程序给了一个babydev.ko文件和eatFlag文件,一般来说babydev.ko文件就是存在漏洞的模块,查看init文件,发现将/proc/kallsyms拷贝到/tmp/coresysms.txt中,而且执行了/home/eatFlag文件 结合模拟之后的环境没有flag,但是解压缩文件系统之后是存在flag的,猜测是这个/home/eatFlag程序给flag删除了,这里先不管,先去逆向babydev.ko文件中的dev_ioctl函数: 程序主要有五个分支来处理用户不同的请求0x83170401:返回当前进程的PID0x83170402:获取当前进程名(comm)0x83170403:获取当前缓冲区剩余空间0x83170404:获取当前缓冲区有效长度0x83170405:获取 global_buf 内核地址(用于KASLR 绕过)可以通过下面的exp.c来测试功能: 现的是字符设备的 seek(定位)操作,也就是用户态调用:lseek(fd, offset, SEEK_SET / SEEK_CUR / SEEK_END);他根据 whence(n2)决定新的文件指针:SEEK_SET (0):从头开始,SEEK_CUR (1):从当前偏移开始,SEEK_END (2):从文件末尾开始,最终实现计算当前“文件大小”:实现的是标准的 read() 行为:将数据从内核缓冲区拷贝到用户态:实现向一块 64KB 缓冲区写数据。这里的缓冲区位置有用户设置,但是注意到这里能够实现对global_buf + 0x10008)这里存储的数值的增大,最终相当于实现了global_buf大小虚拟扩大 逆向eatFlag文件得到这个程序会将/flag文件内容读取到自己的堆内存中,之后删除flag文件: 由于一开始 eatFlag 把 /flag 读入过内存,那么在一段时间内,flag 的字节就一定真实存在于某些物理内存页中,结合上面的dev_write能扩大这里的global_buf的空间,所以我们直接爆搜内存去找flag就好,注意这里大概率不存在,得多试几次脚本如下:这道题目给了两个附件 但是proxy直接IDA打开很显然是让人一头雾水,于是丢给了队伍的re手,给程序脱了个壳,脱壳后逆向如图。 这道题目附件的大致用法:用户 → proxy → serverproxy:是一个前端代理/网关,进行流量转发,但在信息的转发过程中可能会有一些加密。server:是一个后端服务,存在漏洞(如栈溢出、堆漏洞等)。所以在连接远程时,用户只能给proxy发送信息,经过proxy的转发才可以和server进行交互。我们要首先弄清楚proxy内部的逻辑!我认为这个函数是关键性函数 这个函数内部的大致框架如下也就是说proxy有四种情况:关键函数中然后发现了程序会从config.txt中读取内容,解析其中的配置参数(n= 和 d=),并将解析出的十六进制数值存储到全局变量中。 其中qword_7240 = strtoull(s1 + 2, 0, 16); // 将后面的字符串转为16进制数qword_7240存储nqword_7248 = strtoull(s1 + 2, 0, 16); // 同样转为16进制数qword_7248存储d接着看到了个感觉像是给信息加密的函数 加密过程中利用了config.txt文件中的n和d,但是,这个config.txt文件在远端,我们不知道n和d,也就是说这个加密过程我们是不可观测的,所以传给server的信息流我们是不可预见的。针对这个问题,有两种方法可以解决:1.泄露远程的config.txt文件,精心对即将发送的信息流进行提前操作,使得发送过去的数据流是可控的。2.覆盖远程的config.txt文件,使得之后每次的信息流加密操作形同虚设。这两种方法我们显然选择后者。所以我们现在要寻找这个程序有没有对config.txt写入什么东西。翻找IDA时很容易看到这个函数: 这里把src的内容放进了config.txt文件中,我们进而可以控制config.txt控制代码:这样运行过后config.txt里的内容就成了 在这个中,RSA解密挑战码,验证是否为"hack"的哈希,通过则返回cookie。相关脚本代码前32字节是cookie,后面是转发数据,需要验证cookie。相关脚本代码关键函数在此 进去看一下 但是我们进入backdoor中没啥用,有栈溢出但是没啥用,我们libcaddr没有。并且很明显看见下面有一个堆的增删改查,所以显然我们要先利用堆来泄露信息。这里还有一个用户名检查 asc_5010是检查标准,但是strcmp会遇到\x00结束,所以我们实际上只需要爆破三个字节的哈希值就可以了!爆破完得到用户名,然后经过一些简单逆向,分析出与server的交互格式 交互格式如下但是,聪明的你也知道,这只是和server的交互格式,中间还需要经过proxy的检查,所以最终发送消息的格式为:接下来就是对于2.31堆的简单泄露heapbase和libcbase,泄露结束之后,可以利用backdoor()中的栈溢出直接打rop链就好了,建议直接orw写出来,因为拿shell实际上是server被打,但咱们是接触不到的。但有一点要注意以下,就是read和write的fd,因为这道题目涉及到许多文件的打开与关闭以及多个终端连接,所以fd并不是寻常值,具体可以通过调试之前的调用过的read、write函数的fd来判断。本地测试 脚本如下:直接进入正题,这个题没开PIE,libc为2.31,可以找到大部分需要的gadget 禁用了execve和execveat 在sub_402D2D函数为一个路由注册结构,扫一眼,主要看setmode就行,里面有sub_402A40函数 发现在切割拷贝输入的内容时能触发栈溢出,“=”前部分会检查是否为setmode,但是后半部分能拷贝覆盖栈。 把客户端 socket fd 存进去,然后开启线程 start_routine 是一个 多线程 HTTP 服务器中处理单个客户端连接的****主函数。内容比较多,只看主要部分:接收并解析 HTTP 请求(方法、路径、Header、Body)路由分发:GET → 静态文件服务;POST → 调用注册的 handler(如 /hello, /setmode) sub_40287D(haystack, "POST"):在路由表中查找匹配的 handler。调用约定:handler(fd, body, body_len)在这里会调用setmode在上面GET方法里面有一个sub_402663函数,这个函数没有限制路径,只需要控制rdi和rsi就可以控制该函数输出我们想要的flag 尝试用一个线程,按照格式输入,覆盖返回地址,利用recv写入/flag字符串和后续rop,利用recv后面leave ret控制执行流到getflag,会发现程序卡死在snprintf里面 vmmap一下,应该是地址不可写 于是修改填入的bss区域(调试发现卡在f栈没对齐,稍微修改即可),得到下面exp由于线程的特点,多个线程共用一个栈和bs
...(已截断)
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-289689.htm
[原创]CISCN-2025-初赛writeup NPUSEC
116 浏览
0 回复
暂无回复,快来抢沙发吧!