200점으로 나온 리버싱 문제이다. 새벽에 나와서 별로 풀 의지가 다들 없었던거 같다ㅠㅠ
IDA로 까보면
argv[1]로 플래그를 전달받는다.
그 다음 이 부분을 보자. 먼저 타임스탬프를 가져와서 srand넣어주고 dword_804B060와 xor하는데 dword_804B060를 seed라고 하자.
seed를 타임스탬프와 xor하고 순차적으로 rand()값을 0xffffff, 0xffff, 0xff로 나눈 나머지와 xor 해 주고 그 밑에서 막 쉬프트 연산을 해 준다. 많은 분들이 이 부분에서 아 이게 뭐야 하고 걍 닫았을 거라고 생각하는데 이 부분은 그냥 더미에 불과하다. 이거를 디버깅 해 봤다면 알 수 있었을 텐데 이 구간을 좀 더 간단하게 표현해 보면,
처음 seed값이 0x12345678이라고 하면 seed ^ i를 한 후에 seed값을 0x56781234로 바꾼다. 그러고 다시 (i <<16)과 xor을 한다. 결과적으로는 바뀐 값이 없다. 그 다음에 나오는 쉬프트 연산이 나오는데 이거는 걍
0x56781234 -> 0x56341278 -> 0x56123478 -> 0x12563478 -> 0x12345678 이렇게 1바이트 단위로 서로 자리를 바꿔주면서 교체해 주다가 결국 다시 처음 값으로 돌아간다. 이 행위를 256번 하므로 결국 seed는 반복문을 돌고 나와도 달라진 값이 없게 된다.
그러고 나서 다시 타임스탬프 가져와서 위에서 타임스탬프랑 rand()값으로 xor해 줬던 방식을 그대로 거꾸로 연산을 다시 한다. 즉, 1초가 소요되지 않았다면 타임스탬프가 바뀌지 않고 seed는 처음 상태 그대로 라는 것이다. 디버깅을 하면서 1초라도 소요가 됬다면 seed는 완전히 망가지나 실제 프로그램이 실행될 때는 1초가 소요될 일은 턱없이 없으므로, 이 부분까지 진행이 됐을 때 seed는 결국 처음 값과 같은 값을 가지게 되는 것이다. 그리고 마지막으로
dword_804B060 += (v16 >> 24) ^ (unsigned __int8)((v16 >> 16) ^ v16 ^ BYTE1(v16)); 이 구간이 있는데 여기서 v16은 카나리이다. 카나리가 0x12345600이면 0x12 ^ 0x34 ^ 0x56 ^ 0x00을 한 값을 seed에 더해준다. 그러고 나서 0x100크기의 테이블을 만든다. 그 후에
걍 만들어진 테이블에서 값 두 개 가져와서 xor하고 argv[1]값이랑 바로 비교한다. 최종적으로 우리는 테이블을 연산하는 루틴만 계산하고 그 테이블을 계산하는 루틴에서 seed가 쓰이는데 이 seed는 총 256가지 경우의 수를 가지고 있으므로 테이블도 256가지 경우의 수가 있다. 이거를 코드를 짜던가 angr를 돌려서 위에 비교 구간의 두 값을 xor해서 출력해 보면서 flag가 나오는 경우를 찾으면 된다. 마지막으로 seed의 맨 처음 초기값은 constructor에서
ptrace로 디버깅 중인지를 판단하고 맨 처음에 초기화 해 준다. 디버깅이 아니라면 초기값은 36이 되고, 여기서부터 걍 플래그 찾으면 된다.
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #include <stdio.h> int main(void) { unsigned int seed = 0x24; unsigned char table[0x100]; for (int i = 0; i < 0x100; i++) { seed = 0x24 + i; table[0] = 0x30; for (int j = 1; j < 0x100; j++) { table[j] = seed >> (j % 7); for (int k = 0; k < 0x10; k++) { table[j] = ((table[j] << (k & 2)) ^ (table[j] >> (k & 1))); table[j] = (table[j] ^ table[j - 1] ^ seed); } seed ^= (seed % 0x22); } if (((table[0] ^ table[185]) == 'f') && ((table[0] ^ table[150]) == 'l')) { printf("%c", table[0] ^ table[185]); printf("%c", table[0] ^ table[150]); printf("%c", table[121] ^ table[137]); printf("%c", table[247] ^ table[130]); printf("%c", table[0] ^ table[38]); printf("%c", table[0] ^ table[103]); printf("%c", table[121] ^ table[200]); printf("%c", table[247] ^ table[122]); printf("%c", table[121] ^ table[87]); printf("%c", table[247] ^ table[58]); printf("%c", table[0] ^ table[123]); printf("%c", table[247] ^ table[87]); printf("%c", table[0] ^ table[249]); printf("%c", table[0] ^ table[141]); printf("%c", table[1] ^ table[87]); printf("%c", table[0] ^ table[59]); printf("%c", table[121] ^ table[32]); printf("%c", table[0] ^ table[123]); printf("%c", table[121] ^ table[123]); printf("%c", table[121] ^ table[213]); printf("%c", table[247] ^ table[58]); printf("%c", table[0] ^ table[249]); printf("%c", table[121] ^ table[24]); printf("%c", table[247] ^ table[249]); printf("%c", table[247] ^ table[213]); printf("%c", table[121] ^ table[58]); printf("%c", table[121] ^ table[123]); printf("%c", table[0] ^ table[134]); printf("%c", table[0] ^ table[113]); printf("%c", table[48] ^ table[48]); puts(""); } } } | cs |
브포 소스
실행하면 키 나와요.
key : flag{CPU_15_50_f457_15n7_17?}
'Write Up' 카테고리의 다른 글
2016 Layer7 CTF Write-UP (4) | 2016.09.07 |
---|---|
YISF 2016 예선 Write-Up (2) | 2016.08.19 |
2016 ASIS CTF Quals - firtog (0) | 2016.05.09 |
2016 ASIS CTF Quals - Catch Me! (0) | 2016.05.09 |
2016 CodeGate Final rev (1) | 2016.05.06 |