穿越火线ACE安全团队近期监测到一个代号为「影(Shadow)」的地下外挂组织
正在暗中壮大。经过数周的外围侦察,截获了「影」部署在入口节点上的一套门禁系统「宫殿」。只有通过该系统的验证,才能获取进入「影」内部网络的凭证。
「宫殿」的验证机制并不寻常:系统由用户态控制台和内核驱动组成,驱动内部隐藏着一个加密迷阵,所有操作指令必须由控制台通过驱动接口下发。表面上,系统不会对你的任何操作给出反馈——你无法直接判断每一步操作是成功推进,还是被防线拦截。
但「影」的工程师并不完美。ACE的研究员注意到,系统在运行时似乎并非完全沉默——某些异常现象暗示着隐藏的信息泄露。找到这些线索,你就能感知每一步的结果;发现得越多,破解效率越高。
你的任务:分析这套身份验证系统,发现所有隐藏的信息泄露,突破加密迷阵,
取出通关凭证。ACE 总部在等你的消息。
机制:
R3层应用负责创建隐藏的通信方式,并且与R0层通信,这里主要是打包操作码发出
R0层接收操作包后进行验证,核心验证代码被虚拟化保护了,前五次通信会依次采取五种反馈,五次反馈后或走了回头路,会开始随机反馈
前四种都找到了,但是始终没有找到最后一种,最后的脚本也是只用了四种接收方式

运行截图
R3层简析:

两个疑点,1.汇编层有很多字节都是被跳过的,2.SomeFlowerFunc里面结构不正常可以细看

这里发现两个事件对象创建,并且看名字是和迷宫有关的,应证了前面R0层 加密迷阵,有点像迷宫题?

再往后的两个函数看起来是SMC的作用,那么动调尝试去看

先得到两个信号量对象,后面有点像vmp的虚拟化混淆,这个驱动的通信方式是Io,所以尝试通过IoControl来直接定位

这里DeviceIoControl三种情况 0x8001200C 初始化 0x80012008 未知 0x80012004 位置控制码
然后多次动调分析,得到结论
先前的SomeFlowerFunc的作用1 创建对象, 作用2 创建信号量 但后面虚拟化的代码还没分析

函数尾部代码通过输入来决定push 哪段地址来决定接下来的分支去向

简单更改后可以看源码了


n76存输入,后面可以打印,dx作为操作码,传入通信

还原算法:(uint8_t)((((input ^ 0xFA) << 3) | (input ^ 0x40) >> 5))
v17,也就是高位记录次数大概结构就是
struct packet{ uint32_t opcode, uint32_t time, uint32_t time ^ opcode ^ 0xDEAD1337 };
那么R3层分析完毕
R0层分析
漏洞1、2 Event/Semaphore
简单去个花得到

然后可以搜索 DeviceIoControl(hDevice, 0x80012004``0x80012004 这个宏来查看,alt+b

走迷宫的应该在loc_40305A中,但是里面有类似VMP的虚拟化混淆,所以这里还是尝试通过别的方向入手

这里有先前创建的事件名称

这个函数通过n2决定打开哪个事件 0 2 OK 1 Wall,如此的话看n2参数来判断现在是否撞墙? - 或许可以写一个驱动hook掉这个函数,读参数2?
先双机调试下断点看一下
lmvm ShadowGateSys



看起来应该是可以的
那么这里就有一个想法了,驱动hook一下,然后写个自动化脚本去跑,额不对,那样子太麻烦了,直接看事件情况就好了

这里也有对信号量操作的,写了一个简单监听的程序,一开始还正常,得到地图
1 | #### |
后面再次D之后,会收不到消息,这里windbg给隐藏通信函数下断点,发现断点是没有断住的,断点再往前试试
漏洞3 LastError

疑似又一种通信,这里5080不清晰,动调看一下


是 nt!PsGetThreadTeb:
那前文就是

给teb的0x68结构写值
那么GetLastError就可以获得这里的值了,不过这里是通信进程的GetLastError
结合前面1.事件2.信号量3.错误写了一个,发现还是有接收不到的,应该还有隐匿的,再次寻找
漏洞4 SetInfomationObject

动调发现
这里的函数调用时SetInfomationObject
前文
得到线程teb,那就是R3 teb的+1748处,后面SetInfomation设置的是00 01,是防止关闭,其实有猜测这里是不是根据可不可以关闭决定是否是撞墙
这里才发现,原来题目里面有提示5个通信方式啊,,,
那么我直接并排下断点
这样看就很明显了,第四个就是他,那么去详细的看一下参数,句柄相关信息
进入到SetInfomationObject函数中,进行参数拆解得到
ZwSetInformationObject(0xDC,4,0xfffffb88441ff490,2);
Handle- 一个用于放置信息的手柄。句柄不需要授予任何特定的访问权限。ObjectInformationClass- 要设置的信息类型。- ObjectHandleFlagInformation (4)
控制项处理继承和保护属性。ObjectInformation- 指向包含请求特定数据的缓冲区的指针。ObjectInformationLength- 提供的缓冲区大小(字节单位)。
这里改变的是这个句柄,但是刚好这个句柄是在teb+0x1748里面取出来的,那么也就是说,前文一直探测不到的原因有两个,1.跨进程还得去看teb的句柄,2.同进程我写的通信没有向0x1748中写句柄,那么调试看一下就确定了
通过不同的输入断点最后确定
撞墙 r8 - 00 00,走路 r8 - 00 01
漏洞5
实在没头绪乱翻交叉引用

这里5008,交叉引用

恰好在第五次操作断点断住,并且0FFFFF78000000320这个值有点眼熟,我记得是返回值的随机数用的

这里又有一个R3cookie,有点奇怪
查一下0FFFFF78000000320
https://connormcgarr.github.io/kuser-shared-data-changes-win-11/
这里可能分析有误,后面发现这里是第六次断下的,而且从这个时候开始日志就是随机产生的,所以我猜测这里是随机日志的代码,从第六次开始,漏洞随机
奇怪,之前发现发包的时候忘记带times了,但是如果带了我的第五次始终是漏洞4的成功。
无漏洞5打印地图
前面觉得的奇怪在后面灵验了,测试发现如下规律
- 5步之后,根据KUSER_SHARED_DATA结构.320h位进行随机,这里随机即会进行随机的漏洞输出,也会进行返回值的随机
- 每一步的随机应该是互不干预的,故如进入漏洞5,回退再次进入则可以避免漏洞5(钻了个空子)
- 如果一开始就DDA,那么直接进入随机漏洞,而不继续前五步的固定漏洞
ok,那么可以先编写一个脚本拿地图了
1 |
|
1 | ############### |
最短路径脚本
1 | from collections import deque |

1 | ============================================= |
最终得到flag{SHAD0WNT_HYPERVMX}