基于python的RPC Fuzz寻找可提权函数

Fay 2022-07-27 09:43:00

简介

本文主要涉及有SeImpersonatePrivilege时通过pipe管道复制客户端权限的rpc提权漏洞挖掘。

先说rpc,rpc是Remote Procedure Call,windows中许多服务都会提供的rpc接口,例如uac的授权认证RaiLaunchAdminProcess,又如SvcMoveFileInheritSecurity以system权限移动文件,有不少可以被利用于bypass uac,提权,远程下载等等操作。这些函数被隐藏了起来,可通过rpcview或者ntapidotnet等反编译接口为IDL文件,获取某个rpc服务的唯一uuid,版本,和提供的接口函数以及对应的参数。

所以如果想寻找其中可以利用的函数,首先得获取idl文件,再在其中寻找可能存在漏洞的函数,寻找的方法也可以总结为

  1. 寻找危险函数名

如上文提到过的uac认证中的admin,任意文件移动中的security,从windows SDK中下载symbol,再在rpcview中引入后反编译,就能解析出函数的名字。或是powershell遍历注册表中的clsid,去获取对应的函数名,再寻找危险的函数

  1. 寻找可能存在漏洞的dll

例如用于验证身份的appinfo.dll,rpc提供的函数只有函数名,需要的参数,并不提供执行过程,所以一些逻辑错误还是需要深入dll逆向。

  1. fuzz参数

对所有参数尝试一些可能触发漏洞的数据,如一些溢出呀,或是一些格式化字符串漏洞呀,命令注入之类的。

本文提权原理

原理是发起pipe的服务端如果具有SeImpersonatePrivilege权限,则可以模拟连接pipe的客户端的权限,再用连接上的高权限用户生成进程,达到提权的目的。

这里涉及对文件的访问,所以我们把目标放在一些可能存在文件操作的函数上。于是我计划将获取到的函数的string参数用\\\\localhost\\pipe\\testpipe代替,fuzz出所有访问过该路径的参数。

fuzz参考了rpc-forge,原理也就是通过数据类型,生成对应的用于fuzz的参数,编码为ndr结构,再传给函数进行反复调用。由于rpc-forge需要特定python文件的格式进行输入,而并未给生成文件的代码,秉着造轮子的心态自己写了fuzz

流程

  1. 解析idl生成的cs文件,使其变为可供python使用的函数集,含有uuid,版本,结构体和结构体内参数,方法和参数

用ntapidotnet遍历出可供c#调用的idl文件

https://github.com/tyranid/WindowsRpcClients中有对应的导出方法,或直接引用他提供的

但是在c#中调用函数需要using引入,这样就没法遍历所有文件自动fuzz,得引入全部文件,所以我选择用python中的pythonforwindows来调用rpc函数,这样就需要在python中获取cs文件中rpc服务对应的uuid,版本号

https://hakril.github.io/PythonForWindows/build/html/rpc.html为pythonforwindows的官方文档,供使用参考。

  1. 获取uuid,版本并尝试连接

c#的整体结构还是相对好解析,非常规整,完全可以通过{ } ;( ) ,分别解析类和函数,再删除不必要的# //行,可以大致将所有类,结构体,union,接口和接口中的参数进行分类,再返回一个列表,方便后面获取值。

  1. 根据对应类型生成参数

c#生成的idl文件中也将参数用ntapidotnet中的对应函数进行了包装,例如用WriteTerminatedString包装String,用WriteInt32包装int,WriteReferent将里面的类型转为UniquePTR,或是自定一个Write_xx处理一些数组、结构体或union之类的东西。通过c#中的函数得到参数对应的包装方式,再记录为pythonforwindows中对应的类型如NdrWStringNdrLong,NdrByte之类的,会比从函数参数中直接翻译更加准确

还有一些参数嵌套了好几层结构体,写个解析函数在碰到结构体的时候回调解析就行。最后返回一个列表包含了所有参数的类型。

值得注意的是pythonforwindows并没有将所有类型完全解析,不能将c#所有包装函数完全对应上pythonforwindows中的类型,比如union的包装方式就没有在pythonforwindows中提供(可以看ntapidotnet中的源码,union的包装方式是将int类型的selector用NdrLong包装,再拼接上selector对应的参数包装),但作为fuzz,其实我们也不需要对所有类型完全进行处理,遇到不能处理的类型直接用byte数组代替就好。

参数生成可以直接套用rpc-forge中的generator,根据对应参数类型生成对应参数,再将参数用对应类型包装拼接,就是可供函数使用的传参了。

  1. 循环调用函数

写一个最大循环限制将fuzz方法拿进去循环跑就好。

  1. 获取结果

rpc返回的结果由out关键字指定的参数接收,其编码格式和我们发送参数的编码格式一样,通过获取out参数返回的结果进行解码可以得到调用rpc接口所返回的结果。

由于我们需要做的只是fuzz出对unc路径有访问行为的函数,所以更简单的办法是直接用procmon过滤出访问了我们指定路径的进程,一旦有CreateFile记录,就说明函数触发了参数中的unc路径。

结果

参数生成不是很到位,会有一部分函数报传输数据不符合格式,但是不影响我们寻找这种函数。

开着procmon监视触发了testpipe目录的行为,很快就找到了目标,例如tellib.dll中的UtcApi_SnapCustomTrace触发了读取目录的行为(这个有师傅已经找到过了),又比如appxdeploymentserver.dll中的AppXApplyTrustLabelToFolder_59,接受两个字符串参数作为输入,第一个参数可触发unc路径

这一系列rpc服务大多都是svchost调用dll,拥有system权限

找到后用c#创建一个pipe管道,再写一个rpc函数调用,然后复制权限创建进程,就得到了一个system权限的客户端

留下fuzzer链接(由于自用仅供参考)>>https://github.com/0xFay/python_RPC_Fuzzer

评论

Fay

这个人很懒,没有留下任何介绍

twitter weibo github wechat

随机分类

软件安全 文章:17 篇
Android 文章:89 篇
Java安全 文章:34 篇
CTF 文章:62 篇
Python安全 文章:13 篇

扫码关注公众号

WeChat Offical Account QRCode

最新评论

Article_kelp

因为这里的静态目录访功能应该理解为绑定在static路径下的内置路由,你需要用s

N

Nas

师傅您好!_static_url_path那 flag在当前目录下 通过原型链污

Z

zhangy

你好,为什么我也是用windows2016和win10,但是流量是smb3,加密

K

k0uaz

foniw师傅提到的setfge当在类的字段名成是age时不会自动调用。因为获取

Yukong

🐮皮

目录