아이디어가 굉장히 참신해서 재밌던 문제였다. curl 라이브러리를 바탕으로 그대로 가져와서 중간에 --pctfkey 인자를 추가해서 키를 입력할 수 있게 하였다.
실제 curl 라이브러리에는 저런 인자가 없다. IDA로 열어서 저 인자로 주었을 때의 동작을 봤더니
스택 자체를 아예 바꿔버리고 리턴을 해버린다. 즉, 연산 루틴 과정을 코드가 아니라 ROP처럼 리턴으로 이루어진 연산을 하게 된다. 여기서부터 이 문제는 아이디어가 되게 좋다고 생각했다. 진행을 해 보면 리턴을 하다가
strlen함수로 가서 입력한 키 값의 글자를 구한다. 그리고 몇 번의 리턴 후에 pop edx 명령어를 수행한다.
위 레지스터에서 ebx가 strlen으로 구한 값이고, edx가 스택에서 pop 한 값이다.
그리고 sub 연산을 한 후에
그 후에 cmovnz 명령어로 ZF가 세팅되어 있지 않다면 eax에 ebx를 넣는다. sub 명령어는 ZF를 건드리고 그 이후로 건들지 않으므로 이 명령어들이 하나의 비교를 하는 행위인 것이다.
그리고 eax의 값을 edi로 옮긴 후에 esp에 더한다. 만약 글자 수가 0x35글자가 아니라면 스택에 아무 값도 더해지지 않고, 0x35글자 였다면
edi에 0x94가 들어가 있다. 만약 스택에 0x94가 더해지지 않는다면
wrong이라는 문자열을 write하고, exit한다. 즉, 이것으로 문자열의 길이가 0x35글자가 아니라면 종료됨을 알 수 있다. 종료되지 않았다면 다음으로 넘어간다.
그 후에는 역시 조금 더 리턴을 몇 번 하다가 다시
add [edx], ecx 명령어로 입력한 값의 각 글자를 맨 첫 번째 글자만 빼고 모두 더한다. 플래그 형식이 PCTF{}이므로 맨 앞의 P만 빼고 더한 값을 구한다.
그리고 하위 1바이트만 ror 0x5f를 한후에
다시 전체 값을 rol 1한다.
그 후 xor을 몇 번 한다.
sum ^ 0x01F9933D ^ 0xC7FFFFFA을 한다. 그리고 나서
md5 해시를 구한다. 그리고 구한 값의 앞 4바이트를 dword형으로 가져와서 다시 0x86F4FA3F와 xor 하고 난 후에
0x5BFFFFFF와 비교한다. 즉, 플래그의 총 길이를 구해야 함을 알 수 있다. md5는 간단한 파이썬 브루트 포싱으로 구했다.
1 2 3 4 5 6 7 8 9 10 11 | from SunKn0wn import * for i in range(100000): sum = i sum = sum ^ 0x01F9933D ^ 0xC7FFFFFA sum = md5(p32(sum))[:8] if sum == "c0050bdd": # little endian(0x5BFFFFFF ^ 0x86F4FA3F) i = ROR(i, 1) i = i - (i & 0xff) + (ROL(i & 0xff, 0x5f) & 0xff) print "[*]Flag num is " + str(i) break | cs |
이렇게 넣고 돌려주면 나온다. 이제 나온 값에 맞게 다시 글자 합을 맞게 임시적으로 PCTF{NBCDEFGHIjKLmnopqrstuvwxyzabcdefghijklmnopqrstl} 이렇게 넣고 디버깅 해봤다. 몇 번 리턴을 하다가
이렇게 0x10크기 만큼의 바이트의 테이블에서 한 바이트를 가져온다.
그리고 edx안의 값과 xor 한다. 그렇게 쭉쭉 연산하고
dword형으로 eax로 가져온다. 그리고 다시
스택에 있는 테이블 값을 pop ecx를 통해 ecx로 가져온 뒤에
빼서 cmovnz로 또 비교한다. 이제 xor테이블을 알고 있으므로 역연산을 할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <stdio.h> int main(void) { char table[] = { 0xc0, 0x05, 0x0b, 0xdd, 0x74, 0x77, 0x21, 0x64, 0x6f, 0x14, 0xff, 0x00,0x8C, 0x69, 0x78, 0xB9 }; unsigned char flag[] = { 0x90, 0x46, 0x5f, 0x9b, 0x0f, 0x1d, 0x54, 0x17, 0x1b, 0x4b, 0x9e, 0x5f, 0xe0, 0x58, 0x0c, 0xcd, 0xac, 0x60, 0x54, 0xa9, 0x1c, 0x1e, 0x4f, 0x03, 0x30, 0x25, 0xa0, 0x6c, 0xbd, 0x02, 0x1d, 0xe6, 0xb4, 0x35, 0x54, 0xbe, 0x15, 0x1b, 0x4d, 0x3b, 0x1d, 0x7b, 0x8f, 0x66, 0xf9, 0x1a, 0x1b, 0xd8, 0xb4, 0x6c, 0x64, 0xb3, 0x09 }; for (int i = 0; i < sizeof(flag); i++) { printf("%c", flag[i] ^ table[i % 0x10]); } } | cs |
짠 역연산 소스!
짠 플래그!
짠 브렉쓰루 3등!
flag : PCTF{just_a_l1ttle_thing_1_l1ke_t0_call_ropfuscation}
'Write Up' 카테고리의 다른 글
2016 CodeGate Final BMP (0) | 2016.05.04 |
---|---|
2015 Christmas CTF vsnoted (0) | 2016.04.30 |
PlaidCTF 2016 quick - 175pt (0) | 2016.04.18 |
2016 CodeGate watermelon exploit (1) | 2016.04.01 |
2016 CodeGate bugbug exploit (1) | 2016.04.01 |