探索基于http.sys实现权限维持
Posted 零队
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了探索基于http.sys实现权限维持相关的知识,希望对你有一定的参考价值。
前言
在通常WEB应用中,一个应用只能绑定一个端口,若同时绑定一个端口,必然会抛出端口占用异常信息,微软在IIS 5.0以后版本提供了一种机制,Net. Port Sharing,即端口共享。它允许对应用同时使用一个端口只需要各自注册的url前缀不一样即可。
这种机制被封装在http.sys驱动中,驱动监听HTTP流量,然后根据URL注册的情况去分发到当前URL对应的应用。
winrm服务端口复用
实际上,winrm服务就是基于http.sys驱动上注册了wsman后缀,Windows Server 2008默认关闭WinRM服务,Windows Server 2012默认开启
测试环境:192.168.1.201 系统版本:Windows Server 2008 R2
在命令行下开启服务,防火墙会自动添加例外规则,系统默认监听端口5985。
winrm quickconfig –q
此时使用netsh http show servicestate
可以查看到http.sys新注册了一条url前缀:
由于系统原本没有开启5985端口,为了增加后门的隐蔽性,故通过以下命令将winrm服务端口修改至80端口,达到端口复用的效果。
winrm set winrm/config/Listener?Address=*+Transport=HTTP @{Port="80"}
默认客户端连接则会提示Winrs error:WinRM 客户端无法处理该请求。如果身份验证方案与 Kerberos 不同,或者客户端计算机…,因为WinRM只允许当前域用户或者处于本机TrustedHosts列表中的远程主机进行访问,则需在客户端添加一个TrustedHost表,*代表信任远程任意主机:
Set-Item WSMan:localhost\client\trustedhosts -value *
然后使用winrs命令连接远程web服务端口获得交互式SHELL,
使用python实现一款支持NTLM hash的客户端,需要注意的是:
windows 2008是LM-HASH:NTLM-HASH的方式,使用32个0替代。
windows 2012以及之后只能抓到NTLM的Hash,直接使用即可。
https://github.com/c1y2m3/python-tools/blob/master/WinrmAttack.py
HTTP ServerAPI端口复用
微软对外开放了如何调用这种http.sys驱动机制的API接口,也就是HTTP Server API。HTTP Server API 运行在用户模式中,也就是说任意用户都可以调用该API实现一个HttpListener,与 IIS 共享端口,但是前提是你必须拥有管理员权限。
上图整个过程描述如下:
(1)第一步,IIS 或者是自己写的程序(HttpListener)调用API ,向内核的Http.sys注册一个URL前缀,这相当于向路由器添加一条路由规则,Http.sys就是这个路由器。
(2)第二步,Http.sys捕获到一个http请求,它将会根据自身的“路由表”找到该http请求的前缀所对应的应用,然后把请求分发给该应用。
(3)第三步,HttpListener接收到Http.sys转发来的请求,对其进行回应。
1.示例代码测试
微软官方有一个基于HTTP Server API 1.0版本的demo:
https://docs.microsoft.com/zh-cn/windows/win32/http/http-server-sample-application
笔者对其demo进行了简单的修改,进行如下演示:
通过pReq->CookedUrl.pQueryString 能够读取url中的参数,去除参数后的问号对字符串拼接,
获取客户端输入的内容,C++ 代码如下:
*QueryString = new WCHAR[pReq->CookedUrl.QueryStringLength - 1];
wcsncpy_s(QueryString, wcslen(QueryString), pReq->CookedUrl.pQueryString + 5, wcslen(QueryString) - 1);
wprintf(L"[*] QueryStringDecode:%ws\n", QueryString);
后门功能设计
基于该demo进行修改,设计命令执行后门,通过GET请求发送要执行的cmd命令,格式为?,对传来的http请求进行身份验证,验证成功时进行回应,
例如: http://127.0.0.1/a?png=whoami,要执行的命令为whoami,通过处理http请求内容,执行系统命令并通过SendHttpResponse回显到客户端页面。
使用管道读取命令并执行,回传结果,参考代码如下:
https://github.com/3gstudent/Homework-of-C-Language/blob/master/UsePipeToExeCmd.cpp
在测试过程中发现当传入特殊字符时,例如空格,单双,引号等字符会被编码,导致某些命令无法解析执行 ,如图所示:
这里笔者对命令使用了base64解码处理,解决以上问题且可以对流量进行简单加密,以及对回传的结果作格式转换。
并使用#pragma comment( linker, "/subsystem:\"windows\" /entry:\"wmainCRTStartup\"" ),屏蔽控制台应用程序的窗口,修改测试代码如下图:
效果演示
可以看到,未注册/a/前缀时,因为此时只有iis使用了端口共享机制,http.sys把访问/a/的请求交给了iis处理,iis返回了404页面。
随后我们用自己的程序把/a/前缀注册到http.sys,此时访问/a/路径,http.sys于是把请求交了我们的后门程序并回显系统命令。
奇思异想
Windows Server 2008 R2及更高版本的系统默认无法获得明文密码,但是可以利用SSP即 Security Support Provider,通俗理解就是一个用于身份验证的 dll,系统在启动时 SSP 会被加载到 lsass.exe 进程中,由于 lsa 可扩展,导致在系统启动时我们完全可以加载一个自定义的 dll来记录明文账号密码。
mimilib从lsass进程中提取明文凭据的实现代码:
https://github.com/gentilkiwi/mimikatz/blob/master/mimilib/kssp.c
自动武器化实现思路:
1、将动态库或是驱动文件打包进一个可执行文件中,再由需要使用的时候,再临时释放和加载。
2、将释放的dll文件复制到c:\windows\system32下,这里编译的时候需要注意的是程序是32位的,在64位系统下,所有对system32的操作都会被转向syswow64,修改系统注册表Security Packages的值为要加载dll的名称。
3、通过调用 AddSecurityPackage API函数可以使 lsass.exe 进程加载指定的SSP / AP,无需重启,此时管理员输入了新的凭据,将会生成文件kiwissp.log,实战中,可配合上述的HTTP ServerAPI端口复用实时获取凭证,如有需求也可以自行改进。
效果演示:
Reference
http://www.mamicode.com/info-detail-2638519.html
https://www.4hou.com/posts/y6jW
https://blog.csdn.net/ayang1986/article/details/83351842
以上是关于探索基于http.sys实现权限维持的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向Linux 文件权限 ( Linux 权限简介 | 系统权限 | 用户权限 | 匿名用户权限 | 读 | 写 | 执行 | 更改组 | 更改用户 | 粘滞 )(代码片段