BLOG main image
분류 전체보기 (224)
Reversing (13)
Pwnable (4)
Linux Kernel (3)
Crypto (2)
Wargames (68)
Programming (18)
Write Up (32)
Project (22)
Web (2)
My Life (52)
Memo (3)
etc (2)
발표자료 (1)
40,483 Visitors up to today!
Today 0 hit, Yesterday 13 hit
daisy rss
tistory 티스토리 가입하기!
'Write Up'에 해당되는 글 32건
2017.08.11 08:32


이번엔 뮤쀼로 참가했다.

Web - 50, 100, 150, 200
Forensic - 50, 100
Reversing - 50, 100, 150, 200
Pwnable - 50, 100, 150, 200
Misc - 50, 100, 150, 200

제 15회 YISF 문제풀이 보고서 이태양(뮤쀼).pdf

리버싱 300 바이너리랑 풀이 코드
https://github.com/5unKn0wn/ctfs/tree/master/yisf2017/reversing300

리버싱 300 가상화 문제라서 오래걸릴 줄 알고 안풀었는데 분석 해보니까 xor만 하는 생각보다 간단한 가상화였다.

'Write Up' 카테고리의 다른 글

YISF 2017 예선 Write-Up  (2) 2017.08.11
ASIS CTF Quals 2017 Reversing Flour  (2) 2017.04.10
YISF 2016 본선 리버싱 문제 풀이  (5) 2016.12.01
2016 Whitehat Contest 예선 Write-Up  (3) 2016.10.13
2016 Layer7 CTF Write-UP  (4) 2016.09.07
YISF 2016 예선 Write-Up  (2) 2016.08.19
| 2018.10.24 18:18 | PERMALINK | EDIT/DEL | REPLY
비밀댓글입니다
5unKn0wn | 2018.11.07 23:40 신고 | PERMALINK | EDIT/DEL
앗 실제로 문제를 풀 때는 웹페이지에서 문제를 풀었습니다.
다만 라이트업을 작성할 때 간결하게 쓰기 위해서 풀이 리퀘스트를 리눅스에서 보내 플래그를 획득한 부분만 캡쳐한 것입니다
Name
Password
Homepage
Secret
2017.04.10 20:39


It was written in Korean


문제들 중에 배점이 두 번째로 낮았는데 푼 사람이 제일 적고 가장 어려웠던 문제입니다ㅠㅠ

파일을 받아보면 일반적인 PE나 ELF같은 포맷이 아닌 

이렇게 알수 없는 형태로 파일이 구성되어 있습니다. 맨 첫줄을 구글에 검색해보니

.hex라는 확장자를 가진 파일이며 아두이노 같은 avr 환경에서 쓰이는 바이너리임을 알았습니다. 다시 검색해보니 

Intel HEX라는 포맷이었습니다. 다시 검색을 통해 objcopy를 이용해서 hex파일을 elf파일로 변환할 수 있다는 것을 알았습니다. (objcopy가 elf32-avr 타겟을 지원해야 합니다.)

"objcopy -I ihex Flour_d550ed0eb751b1da2b2bdfeeb1fe60ae213e77e8.hex -O elf32-avr Flour_d550ed0eb751b1da2b2bdfeeb1fe60ae213e77e8.elf"

이렇게 명령어를 치면 elf파일이 생성되지만 프로세서를 모르기 때문에 이상하게 IDA에서는 디스어셈블링이 되지 않았습니다ㅠㅠ 그래서 objdump를 이용해서 어셈블리를 txt로 뽑아서 소스를 오디팅해 보았습니다. (역시 objdump가 elf32-avr 타겟을 지원해야 합니다.ㅠㅠ)

"objdump -D Flour_d550ed0eb751b1da2b2bdfeeb1fe60ae213e77e8.elf > disassem.txt"

그러면 소스를 추출할 수 있고 소스를 오디팅 하다보면 이런 부분을 찾을 수 있습니다. (###########으로 주석 처리한 부분을 봐주세요.)

r18 = table1[i] ^ table2[i] ^ 0xf3
r19 = input[i]
if (r18 != r19) 
    break;

대충 해석을 해 보면 이럴꺼 같은 느낌이 옵니다. 이 부분이 플래그를 연산해서 비교하는 부분이라 생각했습니다. 여기부터는 어떤 테이블을 쓰는지 정적 분석으로는 한계가 있으므로 avr studio를 이용해서 동적분석 해 보겠습니다. (데이터 영역에서 테이블을 추출할 수도 있지만 대회 당시에는 그럴 생각이 나지 않았습니다.ㅋㅋ)


 avr studio로 elf 파일을 열고 디바이스는 ATMEGA128로 맞춰주고 열어서 디버깅 해보겠습니다.(디바이스는 가장 보편적으로 쓰이는 ATMEGA128로 사용한 것이며, hapsim을 이용해서 바이너리와 입출력 통신을 하려 했으나 안되서 값 입출력은 할 수 없었습니다ㅠㅠ)

열심히 어셈 따라가면서 디버깅 하다 보면 입력을 받는 부분에서 무한 루프가 걸립니다.

값을 입력해주지 않으면 현재 pc가 가리키고 있는 BRNE 명령어가 항상 참이 되어 루프를 탈출 할 수 없습니다. 값을 입력했다 가정하고 pc를 수정해서 좀 더 진행하다 보면

아까 소스를 오디팅 할 때 봤던 소스와 같은 소스가 들어있습니다. 이제 r19레지스터와 r18레지스터에 값을 어떤 테이블에서 가져오는지만 확인하면 됩니다.

먼저 r19에 사용되는 테이블은 데이터 영역의 0x139 주소에 있으며 확인해보면 

이렇게 값이 있습니다. 0x2f만큼 가져오면 C8 CA 9D 4B E3 6B 22 D3 2A 1A 98 BF 5D BB 14 06 08 C0 18 3A 4D 0E 84 CA 12 D8 CA CA BC B8 B8 29 2E 33 2B D9 66 C6 A3 A5 6A EE 0E BE 26 62 8E 이만큼이 첫 번째 테이블 값임을 알 수 있습니다. 

다음으로 r18에 사용되는 테이블인 0x107 주소부터 0x2f 바이트 만큼을 가져오면 

7A 6A 27 EB 6B FD B0 53 80 B6 1F 0D DD 23 B8 97 82 6C 8E A4 DC CE 13 5D 84 4F 66 5D 7C 3D 22 B9 B8 B3 87 43 E6 6A 32 66 EB 74 93 2A EF B8 00 이만큼이 사용됩니다.

이제 이를 이용해서 연산을 하면 

플래그가 나옵니다.

flag : ASIS{easY_tAsk_by_emb3dded_d3vices_is_b0ring:)}

'Write Up' 카테고리의 다른 글

YISF 2017 예선 Write-Up  (2) 2017.08.11
ASIS CTF Quals 2017 Reversing Flour  (2) 2017.04.10
YISF 2016 본선 리버싱 문제 풀이  (5) 2016.12.01
2016 Whitehat Contest 예선 Write-Up  (3) 2016.10.13
2016 Layer7 CTF Write-UP  (4) 2016.09.07
YISF 2016 예선 Write-Up  (2) 2016.08.19
kirasys | 2017.04.17 02:46 | PERMALINK | EDIT/DEL | REPLY
잘보고갑니다~
| 2017.04.21 08:59 | PERMALINK | EDIT/DEL | REPLY
잘보고 가요! 태양님 블로그는 공부하는데 좋은 자극이 되는 것 같아요~ 항상 좋은 글 올려주셔서 감사합니다:)
Name
Password
Homepage
Secret
2016.12.01 21:36


올해 8월 즈음에 열렸던 순천향대 정보보호 페스티벌 본선에 출제되었던 리버싱 문제를 대회 도중에 풀지 못하여 나중에 풀어야지 생각했다가 풀어서 풀이 올립니다.

분야는 윈도우 드라이버 리버싱이며 정적분석과 windbg로 커널디버깅을 통해 직접 동적분석해서 풀었습니다.

주어진 바이너리는 exe이며 내부 리소스에서 sys파일을 바이너리가 직접 추출해줍니다.

507284b27c265f829adcdc56409200bd.sys라는 파일을 생성하고 서비스를 생성, 시작한 뒤 패스코드를 입력받고 DeviceIoControl로 전달하는 것처럼 보이나

드라이버를 직접 보면 실제로는

드라이버 자체에서 직접 입력을 받고 있습니다. 이 때는 아스키 코드가 아닌 스캔 코드가 반환되므로 문제를 풀 때 유의해야 합니다.

exe를 보면 패스코드를 두 개 입력 받는 것을 볼 수 있고 실제로 드라이버 내에서도 

두 개의 연산 구간이 존재합니다.

두 연산을 간략하게 설명하면 Stage1함수에서는 입력 값을 가지고 12차 연립방정식을 이용하여 비교를 하고 Stage2함수에서는 crc32 알고리즘을 이용해서 비교를 합니다.

먼저 Stage1입니다.

스캔코드는 키보드가 눌렸을 때와 떨어졌을 때 모두 반환하는 값이 있으므로 실질적으로 6개의 글자를 입력했을 때 if문을 통과하여 연산을 진행합니다. 먼저 연립방정식에 사용될 값을 미리 초기화 해 주고

이와 같이 연립방정식을 이용하여 비교합니다. 저는 수학을 잘 하는 편이 아니므로 z3를 이용하여 해결해 주면 됩니다. 키가 맞다면 엔터를 눌러달라고 하네요. 여기서 한 가지 불편했던 점은 여기서 방정식이 틀릴 시 

0으로 초기화 되어있는 clear_stage1변수로 나눗셈 연산을 하기 때문에 DivideByZeroException이 발생하여 블루스크린을 띄웁니다. 생각보다 짜증났습니다ㅠㅠ

쨌든 Stage1을 통과했다면 다음은 crc32입니다. Stage2는

먼저 crc32 table을 연산해서 만들고 들어온 인풋 값이 올바른 스캔코드 범위인지 체크하고 역시 6개의 인풋을 입력했는지 체크 후 다음 연산으로 진행합니다.

다음으로는 앞 12바이트는 스테이지2에서 입력한 값, 뒤 12바이트는 스테이지1에서 입력한 값을 가지고 crc32값을 구할 24바이트의 plaintext를 구성합니다. 여기서 뒤 12바이트는 스테이지1에서 이미 구한 값이므로 crc32 역연산이 가능합니다.

그리고 앞 12바이트에서는 키보드 하나를 누를 때 두 개의 스캔코드가 반환되므로 실질적으로는 6바이트를 브루트포싱 해야 합니다. 스캔코드 범위는 0~85이고 이의 6승인 377149515625가지 경우의 수를 모두 계산하기에는 시간이 너무나도 많이 걸리므로 Meet In The Middle 공격기법을 이용하여 브루트포싱을 하면 됩니다.

이렇게 해서 0xA6C80569의 crc32값을 가지는 평문을 구하면 됩니다. 구했다면 이를 이용해서 플래그를 출력해주는 부분을 볼 수 있습니다.

여기서 해시 충돌이 일어나서 여러개의 평문이 나올 수가 있는데 해당되는 평문 중 위에서 잠깐 언급했던 엔터(\n)로 시작했고 키가 모두 읽을 수 있는 값으로 구성된 평문을 찾으면 됩니다.

분석한 내용을 기반으로 파이썬 소스를 짜서 풀면 됩니다.

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
from z3 import *
import itertools
 
scancodeTable = ["KEY_NONE""KEY_ESC""1""2""3""4""5""6""7""8""9""0""-""=""KEY_BACKSPACE""KEY_TAB""q""w""e""r""t""y""u""i""o""p""[""]""\n""KEY_CTRL""a""s""d""f""g""h""j""k""l"";""\"""`""KEY_LSHIFT""\\""z""x""c""v""b""n""m"","".""/""KEY_RSHIFT""*""KEY_LALT""'""KEY_CAPSLOCK""KEY_F1""KEY_F2""KEY_F3""KEY_F4""KEY_F5""KEY_F6""KEY_F7""KEY_F8""KEY_F9""KEY_F10""KEY_NUMLOCK""KEY_SCROLLLOCK""KEY_HOME""KEY_UP""KEY_PAGEUP""-""KEY_LEFT""KEY_CENTER""KEY_RIGHT""+""KEY_END""KEY_DOWN""KEY_PAGEDOWN""KEY_INS""KEY_DEL""KEY_NONE""KEY_NONE""KEY_NONE""KEY_F11""KEY_F12"]
################### Stage1 ###################
= Solver()
input = [BitVec("input[%d]" % i, 8for i in range(12)]
Stage1 = ''
 
dword_13940 = 43123;
dword_13940 >>= 2 + 2 * 2;
dword_13944 = 23446;
dword_13944 ^= 2 * 3;
dword_13948 = 46562;
#dword_13948 >>= 32;
dword_1394C = 23123;
dword_1394C ^= 1 + 2 * 3;
dword_13950 = 55005;
dword_13950 >>= 11;
dword_13954 = 84672 >> 1;
dword_13958 = 2 ^ 0xCF7D;
dword_1395C = 58126;
dword_13960 = 67232;
dword_13964 = 7313;
dword_13968 = 0;
dword_1396C = 2212;
dword_13970 = 54761;
dword_13974 = 54671 >> 3;
dword_13978 = 4 ^ 0x1857;
dword_1397C = 45672;
dword_13980 = 2 ^ 0x3039;
dword_13984 = 56221;
dword_13988 = 65123;
dword_1398C = 2 ^ 0x14709;
dword_13990 = 12353 >> 3;
dword_13994 = 84123;
dword_13998 = 34593;
dword_1399C = 12333;
dword_139A0 = 95783;
dword_139A4 = 26614;
dword_139A8 = 4 ^ 0x854B;
dword_139AC = 1 ^ 0x19D9E;
dword_139B0 = 34123;
dword_139B4 = 2 ^ 0x691B;
dword_139B8 = 23123;
dword_139BC = 56223 >> 4;
dword_139C0 = 74821;
dword_139C4 = 23154;
dword_139C8 = 17702;
dword_139CC = 23812;
dword_139D0 = 56745;
dword_139D4 = 0;
dword_139D8 = 12354;
dword_139DC = 76622 >> 3;
dword_139E0 = 12353;
dword_139E4 = 1 ^ 0x15592;
dword_139E8 = 2 ^ 0x17270;
dword_139EC = (3 + 1 * 2) ^ 0xB484;
dword_139F0 = 1 + 32337 * 2;
dword_139F4 = (2 + 2 * 2) ^ 0xA664;
dword_139F8 = 12367;
dword_139FC = 98382 >> 2;
dword_13A00 = 0;
dword_13A04 = 76445 >> 1 * 1;
dword_13A08 = 2 * 1 ^ 0x5B9D;
dword_13A0C = 59322;
dword_13A10 = 21357;
dword_13A14 = 94872;
dword_13A18 = 23347;
dword_13A1C = 23921;
dword_13A20 = 55652;
dword_13A24 = 6140 >> 2;
dword_13A28 = 23523;
dword_13A2C = 671663;
dword_13A30 = 82828 >> 6;
dword_13A34 = 23512;
dword_13A38 = 2 ^ 0xD973;
dword_13A3C = 55321;
dword_13A40 = 23521 >> 1;
dword_13A44 = 2 * 2 ^ 0x9BDD;
dword_13A48 = 32312;
dword_13A4C = 64042 << 2;
dword_13A50 = 23412;
dword_13A54 = 3 ^ 0x1E106;
dword_13A58 = 23225;
dword_13A5C = 39583 * 2 >> 2;
dword_13A60 = 55212;
dword_13A64 = 12827;
dword_13A68 = 38912 >> 2;
dword_13A6C = 36632;
dword_13A70 = 10450;
dword_13A74 = 23821;
dword_13A78 = 94382 >> 3;
dword_13A7C = 2 ^ 0x79FF;
dword_13A80 = 23112;
dword_13A84 = 55312;
dword_13A88 = 49320;
dword_13A8C = 78244;
dword_13A90 = 34123;
dword_13A94 = 38923;
dword_13A98 = 2 ^ 0x5EC4;
dword_13A9C = 23153;
dword_13AA0 = 3 ^ 0xAEE4;
dword_13AA4 = 11312 << 2;
dword_13AA8 = 12352;
dword_13AAC = 77331;
dword_13AB0 = 23121;
dword_13AB4 = 18820;
dword_13AB8 = 11257 >> 2;
dword_13ABC = 33221;
dword_13AC0 = 1 ^ 18470 * 2;
dword_13AC4 = 22115;
dword_13AC8 = 66442;
dword_13ACC = 22332;
dword_13AD0 = 67753;
dword_13AD4 = 1 * 2 ^ 0xB93D;
dword_13AD8 = 41178 >> 3;
dword_13ADC = 23664;
dword_13AE0 = 88553;
dword_13AE4 = 43502;
dword_13AE8 = 2 ^ 0x132C5;
dword_13AEC = 86731;
dword_13AF0 = 2 ^ 0x1E240;
dword_13AF4 = 58551;
dword_13AF8 = 34364;
dword_13AFC = 88665 >> 2;
dword_13B00 = 11946;
dword_13B04 = 23156 >> 3;
dword_13B08 = 23553;
dword_13B0C = 774423;
dword_13B10 = 18231;
dword_13B14 = 22233;
dword_13B18 = 55443;
dword_13B1C = 11234;
dword_13B20 = 667745;
dword_13B24 = 5 ^ 0x21A4;
dword_13B28 = 26574;
dword_13B2C = 47043;
dword_13B30 = 3 ^ 0xA57B;
dword_13B34 = 23532;
dword_13B38 = 23553;
dword_13B3C = 65634;
dword_13B40 = 55332;
dword_13B44 = 3 ^ 0x5C00;
dword_13B48 = 2 ^ 0xD82F;
dword_13B4C = 51549;
dword_13B50 = 88992;
dword_13B54 = 1 ^ 0x2776;
dword_13B58 = 22316;
dword_13B5C = 63732;
dword_13B60 = 23212;
dword_13B64 = 55332 << 1;
dword_13B68 = 23321;
dword_13B6C = 2 * 1 ^ 0xB0AA;
dword_13B70 = 55332;
dword_13B74 = 44232;
dword_13B78 = 33221;
dword_13B7C = 44221;
 
s.add( dword_1394C * input[3+ dword_13948 * input[2+ dword_13944 * input[1+ dword_13940 * input[0- dword_13950 * input[4- dword_13954 * input[5- dword_13958 * input[6- dword_1395C * input[7- dword_13960 * input[8- dword_13964 * input[9- dword_1396C * input[11== 0x33DE90 )
s.add( dword_1397C * input[3+ dword_13978 * input[2+ dword_13974 * input[1+ dword_13970 * input[0- dword_13980 * input[4- dword_13984 * input[5- dword_13988 * input[6- dword_1398C * input[7- dword_13990 * input[8- dword_13994 * input[9- dword_13998 * input[10- dword_1399C * input[11== 0xE845D0 )
s.add( dword_139AC * input[3+ dword_139A8 * input[2+ dword_139A4 * input[1+ dword_139A0 * input[0- dword_139B0 * input[4- dword_139B4 * input[5- dword_139B8 * input[6- dword_139BC * input[7- dword_139C0 * input[8- dword_139C4 * input[9- dword_139C8 * input[10- dword_139CC * input[11== 0xFF4F826B )
s.add( dword_139DC * input[3+ dword_139D8 * input[2+ dword_139D4 * input[1+ dword_139D0 * input[0- dword_139E0 * input[4- dword_139E4 * input[5- dword_139E8 * input[6- dword_139EC * input[7- dword_139F0 * input[8- dword_139F4 * input[9- dword_139F8 * input[10- dword_139FC * input[11== 0xE3FF26 )
s.add( dword_13A0C * input[3+ dword_13A08 * input[2+ dword_13A04 * input[1+ dword_13A00 * input[0- dword_13A10 * input[4- dword_13A14 * input[5- dword_13A18 * input[6- dword_13A1C * input[7- dword_13A20 * input[8- dword_13A24 * input[9- dword_13A28 * input[10- dword_13A2C * input[11== 0x38BE903 )
s.add( dword_13A3C * input[3+ dword_13A38 * input[2+ dword_13A34 * input[1+ dword_13A30 * input[0- dword_13A40 * input[4- dword_13A44 * input[5- dword_13A48 * input[6- dword_13A4C * input[7- dword_13A50 * input[8- dword_13A54 * input[9- dword_13A58 * input[10- dword_13A5C * input[11== 0x219FCF5 )
s.add( dword_13A6C * input[3+ dword_13A68 * input[2+ dword_13A64 * input[1+ dword_13A60 * input[0- dword_13A70 * input[4- dword_13A74 * input[5- dword_13A78 * input[6- dword_13A7C * input[7- dword_13A80 * input[8- dword_13A84 * input[9- dword_13A88 * input[10- dword_13A8C * input[11== 0xA69FCA )
s.add( dword_13A9C * input[3+ dword_13A98 * input[2+ dword_13A94 * input[1+ dword_13A90 * input[0- dword_13AA0 * input[4- dword_13AA4 * input[5- dword_13AA8 * input[6- dword_13AAC * input[7- dword_13AB0 * input[8- dword_13AB4 * input[9- dword_13AB8 * input[10- dword_13ABC * input[11== 0x6C079F )
s.add( dword_13ACC * input[3+ dword_13AC8 * input[2+ dword_13AC4 * input[1+ dword_13AC0 * input[0- dword_13AD0 * input[4- dword_13AD4 * input[5- dword_13AD8 * input[6- dword_13ADC * input[7- dword_13AE0 * input[8- dword_13AE4 * input[9- dword_13AE8 * input[10- dword_13AEC * input[11== 0x7E7EB7 )
s.add( dword_13AFC * input[3+ dword_13AF8 * input[2+ dword_13AF4 * input[1+ dword_13AF0 * input[0- dword_13B00 * input[4- dword_13B04 * input[5- dword_13B08 * input[6- dword_13B0C * input[7- dword_13B10 * input[8- dword_13B14 * input[9- dword_13B18 * input[10- dword_13B1C * input[11== 0x455B88E )
s.add( dword_13B2C * input[3+ dword_13B28 * input[2+ dword_13B24 * input[1+ dword_13B20 * input[0- dword_13B30 * input[4- dword_13B34 * input[5- dword_13B38 * input[6- dword_13B3C * input[7- dword_13B40 * input[8- dword_13B44 * input[9- dword_13B48 * input[10- dword_13B4C * input[11== 0x6BFF55 )
s.add( dword_13B5C * input[3+ dword_13B58 * input[2+ dword_13B54 * input[1+ dword_13B50 * input[0- dword_13B60 * input[4- dword_13B64 * input[5- dword_13B68 * input[6- dword_13B6C * input[7- dword_13B70 * input[8- dword_13B74 * input[9- dword_13B78 * input[10- dword_13B7C * input[11== 0xAEA158 )
 
s.check()
= s.model()
Stage1 += scancodeTable[int(str(m[input[0]]))] + scancodeTable[int(str(m[input[2]]))] + scancodeTable[int(str(m[input[4]]))] + scancodeTable[int(str(m[input[6]]))] + scancodeTable[int(str(m[input[8]]))] + scancodeTable[int(str(m[input[10]]))]
print "[*] Stage1 passcode :", Stage1, "\n"
 
################### Stage2 ###################
Stage2 = ''
CRC32 = 0xA6C80569
table = [0x000x000x000x000x000x000x000x000x000x000x000x000x030x830x040x840x2f0xaf0x170x970x060x860x210xa1]
 
CRC32Table_Index = []
CRC32Table = []
CRC32Brute_f = []
CRC32Brute_b = []
 
for i in range(256):
    k = i << 24
    for j in range(8):
        bit = k >> 31
        k <<= 1
        if bit:
            k ^= 0x4C11DB7
        k &= 0xffffffff
    CRC32Table.append(k)
    CRC32Table_Index.append(k >> 24)
 
for i in table[-1:-(len(table) / 2 + 1):-1]:
    idx = CRC32Table_Index.index(CRC32 >> 24)
    CRC32 = ((CRC32Table[idx] ^ CRC32) << 8+ (idx ^ i)
print "[*] Finding Middle CRC Finish"
 
for i in itertools.product(''.join(chr(i) for i in range(0x55)), repeat=3):
    CRC32_f = 0
    plain = i[0+ chr(ord(i[0]) + 0x80+ i[1+ chr(ord(i[1]) + 0x80+ i[2+ chr(ord(i[2]) + 0x80)
    for j in plain:
        CRC32_f = ((CRC32_f >> 8) ^ CRC32Table[(CRC32_f ^ ord(j)) & 0xff])
    CRC32Brute_f.append([CRC32_f, i])
print "[*] Forward Calculation Finish"
 
for i in itertools.product(''.join(chr(i) for i in range(0x55)), repeat=3): 
    CRC32_b = CRC32
    plain = chr(ord(i[2]) + 0x80+ i[2+ chr(ord(i[1]) + 0x80+ i[1+ chr(ord(i[0]) + 0x80+ i[0]
    for j in plain:
        idx = CRC32Table_Index.index(CRC32_b >> 24)
        CRC32_b = ((CRC32Table[idx] ^ CRC32_b) << 8+ (idx ^ ord(j))
    CRC32Brute_b.append([CRC32_b, i])
print "[*] Reverse Calculation Finish"
 
CRC32Brute_f.sort()
CRC32Brute_b.sort()
 
count = 85 ** 3
cnt1 = 0
cnt2 = 0
while cnt1 < count and cnt2 < count:
    if CRC32Brute_f[cnt1][0== CRC32Brute_b[cnt2][0]:
        if CRC32Brute_f[cnt1][1][0== chr(scancodeTable.index('\n')):    # Stage2 Starts With Enter
            Stage2 = scancodeTable[ord(CRC32Brute_f[cnt1][1][0])] + scancodeTable[ord(CRC32Brute_f[cnt1][1][1])] + scancodeTable[ord(CRC32Brute_f[cnt1][1][2])]
            Stage2 += scancodeTable[ord(CRC32Brute_b[cnt2][1][0])] + scancodeTable[ord(CRC32Brute_b[cnt2][1][1])] + scancodeTable[ord(CRC32Brute_b[cnt2][1][2])]
            print "\n[*] Stage2 passcode :",Stage2[1:]    # Ignore Enter
            break
        cnt1 += 1
    elif CRC32Brute_f[cnt1][0> CRC32Brute_b[cnt2][0]:
        cnt2 += 1
    elif CRC32Brute_f[cnt1][0< CRC32Brute_b[cnt2][0]:
        cnt1 += 1
 
scancode_flag = ''.join(chr(scancodeTable.index(i)) + chr(scancodeTable.index(i) + 0x80for i in Stage2)
scancode_flag += ''.join(chr(scancodeTable.index(i)) + chr(scancodeTable.index(i) + 0x80for i in Stage1)
flag = ''
 
flag += chr(ord(scancode_flag[0]) + 0x4d)
flag += chr(ord(scancode_flag[1]) - 0x6b)
flag += chr(ord(scancode_flag[2]) + 0x55)
flag += chr(ord(scancode_flag[3]) - 0x63)
flag += chr(ord(scancode_flag[4]) + 0x2e)
flag += chr(ord(scancode_flag[5]) - 0x46)
flag += chr(ord(scancode_flag[6]) + 0x3e)
flag += chr(ord(scancode_flag[7]) - 0x14)
flag += chr(ord(scancode_flag[8]) + 0x5e)
flag += chr(ord(scancode_flag[9]) - 0x31)
flag += chr(ord(scancode_flag[10]) + 0x60)
flag += chr(ord(scancode_flag[11]) - 0x54)
flag += chr(ord(scancode_flag[12]) + 0x2d)
flag += chr(ord(scancode_flag[13]) - 0x14)
flag += chr(ord(scancode_flag[14]) + 0x45)
flag += chr(ord(scancode_flag[15]) - 0x4d)
flag += chr(ord(scancode_flag[16]) + 0x8)
flag += chr(ord(scancode_flag[17]) - 0x6f)
flag += chr(ord(scancode_flag[18]) + 0xa)
flag += chr(ord(scancode_flag[19]) - 0x4e)
flag += chr(ord(scancode_flag[20]) + 0x59)
flag += chr(ord(scancode_flag[21]) - 0x20)
flag += chr(ord(scancode_flag[22]) + 0x10)
flag += chr(ord(scancode_flag[23]) - 0x33)
 
print "\n[*] flag :", flag
cs


flag : i1i1_k@nn_d00oI77@!I_f1n

'Write Up' 카테고리의 다른 글

YISF 2017 예선 Write-Up  (2) 2017.08.11
ASIS CTF Quals 2017 Reversing Flour  (2) 2017.04.10
YISF 2016 본선 리버싱 문제 풀이  (5) 2016.12.01
2016 Whitehat Contest 예선 Write-Up  (3) 2016.10.13
2016 Layer7 CTF Write-UP  (4) 2016.09.07
YISF 2016 예선 Write-Up  (2) 2016.08.19
맸보이 | 2016.12.02 12:17 | PERMALINK | EDIT/DEL | REPLY
리버싱고수 sun.lee님;
5unKn0wn | 2016.12.02 17:19 신고 | PERMALINK | EDIT/DEL
호고곡;
hanel | 2016.12.02 18:32 | PERMALINK | EDIT/DEL | REPLY
갓갓..
2301 | 2016.12.04 20:33 | PERMALINK | EDIT/DEL | REPLY
대단해요!!
태양님팬 | 2017.01.08 16:06 | PERMALINK | EDIT/DEL | REPLY
갓태양님 블로그 잘보고있습니다
너무 멋져요 ㅎㅎㅎ
Name
Password
Homepage
Secret
2016.10.13 20:33


2016 Whitehat Contest 예선 NYAN언더바CAT Write-Up입니다.


2016 WHITEHAT CONTEST 예선_NYAN언더바CAT.pdf

'Write Up' 카테고리의 다른 글

ASIS CTF Quals 2017 Reversing Flour  (2) 2017.04.10
YISF 2016 본선 리버싱 문제 풀이  (5) 2016.12.01
2016 Whitehat Contest 예선 Write-Up  (3) 2016.10.13
2016 Layer7 CTF Write-UP  (4) 2016.09.07
YISF 2016 예선 Write-Up  (2) 2016.08.19
2016 KDMHS-CTF times  (0) 2016.05.15
청소년부 | 2016.11.02 00:01 | PERMALINK | EDIT/DEL | REPLY
오늘 whitehat contest 에서 보았습니다. NYAN언더바CAT 청소년부 1등 수상하신거 축하드립니다!~~
5unKn0wn | 2016.11.02 06:45 신고 | PERMALINK | EDIT/DEL
앗 감사합니다~~
| 2017.11.08 13:24 | PERMALINK | EDIT/DEL | REPLY
비밀댓글입니다
Name
Password
Homepage
Secret
2016.09.07 20:39


라업입니다. 닉네임은 "양파가 송송" 사용했습니다.

2016 Layer7 CTF Writeup_이태양.pdf


'Write Up' 카테고리의 다른 글

YISF 2016 본선 리버싱 문제 풀이  (5) 2016.12.01
2016 Whitehat Contest 예선 Write-Up  (3) 2016.10.13
2016 Layer7 CTF Write-UP  (4) 2016.09.07
YISF 2016 예선 Write-Up  (2) 2016.08.19
2016 KDMHS-CTF times  (0) 2016.05.15
2016 ASIS CTF Quals - firtog  (0) 2016.05.09
| 2016.09.09 20:49 | PERMALINK | EDIT/DEL | REPLY
비밀댓글입니다
5unKn0wn | 2016.09.09 21:07 신고 | PERMALINK | EDIT/DEL
제 환경의 스택과 비교하여 알아냈습니다. 버퍼에서부터 카나리, 그리고 리턴 주소(__libc_start_main) 까지의 오프셋은 모든 환경에서 동일하게 적용되므로 이를 이용하면 알 수 있습니다.
| 2016.11.06 19:21 | PERMALINK | EDIT/DEL | REPLY
비밀댓글입니다
5unKn0wn | 2016.11.15 22:15 신고 | PERMALINK | EDIT/DEL
위 질문과 동일한 질문이네요! 카나리와 라이브러리 주소는 제 환경의 스택과 비교해서 알아냈습니다. 버퍼에서부터 카나리와 리턴주소(라이브러리 주소 - __libc_start_main)의 오프셋은 모든 환경에서 동일하게 적용하기 때문에 제 환경에서의 오프셋을 가지고 적용 시킨 값이 실제 리모트 환경에서도 동일하게 적용됩니다. easy_fsb도 위와 같은 방법으로 오프셋을 구했습니당
Name
Password
Homepage
Secret
2016.08.19 21:03


Algorithm - 50, 100, 200
Crypto - 50
Forensic - 50
Misc - 50
Pwnable - 50, 100
Reversing - 50, 100


2016_YISF_문제풀이보고서_이태양.pdf


'Write Up' 카테고리의 다른 글

2016 Whitehat Contest 예선 Write-Up  (3) 2016.10.13
2016 Layer7 CTF Write-UP  (4) 2016.09.07
YISF 2016 예선 Write-Up  (2) 2016.08.19
2016 KDMHS-CTF times  (0) 2016.05.15
2016 ASIS CTF Quals - firtog  (0) 2016.05.09
2016 ASIS CTF Quals - Catch Me!  (0) 2016.05.09
김민석 | 2016.09.07 16:07 | PERMALINK | EDIT/DEL | REPLY
안녕하세요 궁금한 점이 있어서 댓글로 남깁니다.
리버싱 50점 문제 푸실 때 IDA로 hexray 쓰신거 같은데 저는 IDA로 button.exe파일 열어봐도 hexray 버튼이 없습니다. 어떻게 여신건지 알려주실 수 있으신가요?
5unKn0wn | 2016.09.07 20:37 신고 | PERMALINK | EDIT/DEL
헥스레이는 해당 IDA에 헥스레이 플러그인이 깔려 있어야 합니다. 단축키는 F5이고 만약 F5를 눌러도 디컴파일이 되지 않는다면 헥스레이 플러그인을 구매하거나 잘 구하셔서 사용하시면 됩니다.
Name
Password
Homepage
Secret
2016.05.15 15:04


200점으로 나온 리버싱 문제이다. 새벽에 나와서 별로 풀 의지가 다들 없었던거 같다ㅠㅠ

IDA로 까보면

argv[1]로 플래그를 전달받는다.

그 다음 이 부분을 보자. 먼저 타임스탬프를 가져와서 srand넣어주고 dword_804B060xor하는데 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 KDMHS-CTF times  (0) 2016.05.15
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
Name
Password
Homepage
Secret
2016.05.09 22:39


포렌식 문제이다. 맨 처음 나온 리버싱이 너무 안풀려서 잡아본 문제이다. 파일은 패킷 파일이 주어진다. 네트워크 같은거 잘 몰라서 내부에 어떤 파일들이 있나 봤더니 zlib 파일들이 많이 있었다. 그래서 다 추출해 보았다. 

1
2
3
4
5
6
file = open('firtog.pcap''rb').read().split('\x78\x9c')
 
data = ''
for i in range(1len(file)):
    data += ('\x78\x9c' + file[i]).decode('zlib')
open('decypted''wb').write(data)
cs

이렇게 파이썬 소스를 짜서 추출하면 된다.

추출된거 보면 막 이상한 것들이 많다. 페이크 플래그도 있고 막 파이썬 소스도 있고 했는데 추출된 데이터의 밑쪽을 보니까 

1
2
3
4
5
6
7
8
9
10
11
12
from os import urandom
from hashlib import md5
 
= 128
rd = urandom(l)
= md5(rd).hexdigest()
flag = 'ASIS{' + h + '}'
= open('flag.txt''r').read()
flag = ''
for c in f:
    flag += hex(pow(ord(c), 65537143))[2:]
print flag
cs

이런 소스가 있었다. 처음에 나오는 flag는 말도 안되는 값이고, 8번째 줄부터 보니까 flag.txt를 열어서 암호화 하는 것 같았다. 그리고 복호화된 데이터 맨 밑을 보면 41608a606a63201245f1020d205f1612147463d85d125c1416635c854c74d172010105c14f8555d125c3c 이런 값이 있었다. 

그래서 복호화 했다. 

1
2
3
4
5
6
7
8
9
10
11
12
flag_enc = '41608a606a63201245f1020d205f1612147463d85d125c1416635c854c74d172010105c14f8555d125c3c'
flag = ''
table = 'ASIS{}abcdef0123456789'
tmp = ''
 
while tmp != flag_enc:
    for i in table:
        if flag_enc.startswith(tmp + hex(pow(ord(i), 65537143))[2:]):
            flag += i
            tmp += hex(pow(ord(i), 65537143))[2:]
            break
print flag
cs

돌리면 키 나와요.


key : ASIS{c691a0646e79f3c4d495f7c5db3486005fad2495}

'Write Up' 카테고리의 다른 글

YISF 2016 예선 Write-Up  (2) 2016.08.19
2016 KDMHS-CTF times  (0) 2016.05.15
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
2016 CodeGate Final GMPQZ  (0) 2016.05.04
Name
Password
Homepage
Secret
2016.05.09 21:09


대회 전체적으로 리버싱이 상당히 어렵게 나왔다.. 5문제 나왔는데 최종적으로는 이 문제 하나밖에 못풀었다. 아무래도 리버싱 문제를 풀 때 인내심이 약간 떨어진 것 같다. 본선 올라갔으니까 본선 문제는 빡세게 제대로 잡고 다 분석하겠다는 마음으로 풀어봐야겠다. 

이 문제는 x64 elf 바이너리이고 xmm 레지스터를 이용한 연산을 많이 한다. 

main함수의 코드는 이게 다이다.  sub_400820의 함수 리턴값은 항상 0xB11924E1로 같으므로 크게 신경쓸 것은 없다. 그 후에 이 값들을 이용해서 0x6012A8부터 네 바이트 값을 만들어 내고 ASIS와 CTF 환경변수의 값들을 가져와서 CTF 환경변수의 값과 0xB11924E1 이 값을 xor했을 때의 값이 0xFEEBFEEB이면 ASIS 환경변수에 있는 값을 0x6012AC부터 4바이트만큼 넣어준다. 이 부분은 동적 디버깅을 하면서 직접 넣어줄 수 있는 부분이라서 걍 환경변수는 무시하고 풀었다. 그 후에 haystack값과 0x6012A8에 있는 값을 한 글자씩 계속 xor해 나간 후에 막 xmm레지스터 연산들을 한다. 근데 저 부분이 엄청 어려워 보이는데 사실은 걍 xor해서 나온 플래그 값의 각 자리수 아스키 합이다. 즉, 걍 xor해서 합이 2388인 값을 찾으면 되는 것이다. 동적디버깅 해 보면 플래그 중 600d...._y0u...._637...._574.... 이 부분은 확실한 플래그 부분임을 알 수 있고, xor했을 때 나머지 값을 만족할 수 있는 4바이트를 찾아야 하는데 그 힌트로 글자수 합 2388이 주어졌는데 걍 게싱으로 풀었다. 

먼저 경우의 수를 최대한 줄이기 위해서 원래 haystack에 세팅되어 있는 값과 어떤 값을 xor했을 때 정상적인 문자가 나오는지를 찾아보았다. 

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
#include <stdio.h>
 
char asciitable[] = "0123456789ABCDEFGHIJKLMNOPQRSTVWXYZabcdefghijklmnopqrstuvwxyz!@():-_";
bool isascii(char);
int main(void) {
    unsigned char table[4][4= { { 0x550xB00xC20x2D }, { 0x550xEE0x800x7C }, 
                            { 0x3D0xEB0x9C0x79 }, { 0x780xED0xC10x2B } };
 
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 0x100; j++) {
            if (isascii(table[0][i] ^ j) && isascii(table[1][i] ^ j) && isascii(table[2][i] ^ j) && isascii(table[3][i] ^ j))
                printf("%c  %c  %c  %c  %x \n", table[0][i] ^ j, table[1][i] ^ j, table[2][i] ^ j, table[3][i] ^ j, j);
        }
        printf("---------------------------------------------------------\n");
    }
}
 
bool isascii(char tmp) {
    if (tmp == NULLreturn false;
    for (int i = 0; i < sizeof(asciitable); i++) {
        if (tmp == asciitable[i])
            return true;
    }
    return false;
}
cs

이렇게 코딩하고 나온 값들을 선별하여 가장 플래그 스러운 문자열을 만들면 된다. 적당히 나온 값들을 선별해서 뽑아보면 

_  _  7  r  a 

Y  Y  1  t  c 

X  X  0  u  d 

Z  Z  2  w  f 

---------------------

0  n  k  m  80 

1  o  j  l  81 

2  l  i  o  82 

3  m  h  n  83 

4  j  o  i  84 

5  k  n  h  85 

6  h  m  k  86 

7  i  l  j  87 

8  f  c  e  88 

9  g  b  d  89 

:  d  a  g  8a 

h  6  3  5  d8 

i  7  2  4  d9 

j  4  1  7  da 

k  5  0  6  db 

l  2  7  1  dc 

m  3  6  0  dd 

n  0  5  3  de 

o  1  4  2  df 

---------------------

o  -  1  l  ad 

s  1  -  p  b1 

2  p  l  1  f0 

3  q  m  0  f1 

0  r  n  3  f2 

1  s  o  2  f3 

6  t  h  5  f4 

7  u  i  4  f5 

4  v  j  7  f6 

5  w  k  6  f7 

---------------------

5  d  a  3  18 

7  f  c  1  1a 

6  g  b  0  1b 

0  a  d  6  1d 

3  b  g  5  1e 

2  c  f  4  1f 

e  4  1  c  48 

d  5  0  b  49 

g  6  3  a  4a 

a  0  5  g  4c 

c  2  7  e  4e 

b  3  6  d  4f 

--------------------

이렇게 나온다. 먼저 여러 값을 넣어본 결과 각 자리 중 맨 앞은 _  _  7  r 이 들어가서 플래그가 600d_..._y0u_..._6377..._574r... 이렇게 이어나가는게 가장 자연스러울 것 같아서 이렇게 설정했고, 이제부터는 위 플래그를 평문으로 바꿔보았을 때
Good ___ you ___ gett___ star___ 이렇게 나오고 적당한 게싱을 통해 Good 뒤에는 job이 온다던가 you 뒤에는 are 이 온다는 것을 추측해 내어 적당히 게싱해 주면 된다. 나는 you 뒤에 are이 온다고 가정했고 (매쓰보이 하드캐리) 위에서 이를 만족할 수 있는 값들을 찾아 보았더니 4r3 이 만들어 질 수 있는 셋을 발견했고 이를 이용해서 
j  4  1  7,  0  r  n  3,  b  3  6  d 이런 값들을 발견했다. 이를 모두 플래그에 적용시켜보면 최종적으로 600d_j0b_y0u_4r3_63771n6_574r73d 라는 플래그를 만들 수 있다. 그래서 ASIS{600d_j0b_y0u_4r3_63771n6_574r73d} 이렇게 인증했더니 풀렸다..

key : ASIS{600d_j0b_y0u_4r3_63771n6_574r73d}


'Write Up' 카테고리의 다른 글

2016 KDMHS-CTF times  (0) 2016.05.15
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
2016 CodeGate Final GMPQZ  (0) 2016.05.04
2016 CodeGate Final BMP  (0) 2016.05.04
Name
Password
Homepage
Secret
2016.05.06 20:42



두 명 푼 250점 리버싱 문제입니다. 64비트 ELF이고 Go언어로 작성된 프로그램 입니다. 일단 실행시켜 보겠습니다.

막 good good wrong wrong 출력하고 끝납니다. 모두 good이 나오는 키를 찾으면 될 것 같습니다.

먼저 IDA로 까 보겠습니다. Go는 언어 특성상 헥스레이가 안되기 때문에 순 어셈만 보고 분석했습니다.

먼저 입력을 받고 

길이 체크 후에 메인 체크 루틴으로 넘어갑니다.

길이는 15글자 이상이어야 합니다. 후에 메인 체크 루틴으로 넘어가면 

그래프뷰 보고 쫄았지만 디버깅 하면서 분석하니까 크게 힘들지는 않았습니다.

먼저 

스트링의 첫 번째 글자와 마지막 글자를 가져와서 비교합니다. 만약 같다면 wrong을 출력합니다. 그 다음으로 


첫 글자와 끝 글자가 숫자/알파벳 범위에 없고 합이 0xf8이어야 하는 것으로 보아 시작과 끝 글자가 '{', '}'로 정해져 있다는 것을 알 수 있습니다. 이를 만족하지 않으면 wrong을 출력합니다. 

다음은 

{ }사이에 있는 값이 문자로 0~9, A~F 사이에 있는지 확인합니다. 그러고 난 후에 사이에 없다면 wrong을 출력합니다. 

그 다음 입력 값에서 { }사이의 값들의 합을 구합니다. 여기서 모든 글자의 합을 구하는 것이 아니라 전체 길이의 앞 절반의 합만 구해야 합니다. 그 길이가 0x38f이어야 하고 만족하지 않을 시 wrong을 출력합니다. 임시적으로 입력값을 {BBBBBBBBBBBBB5BBBBBBBBBBBBB5} 이렇게 넣고 하면 됩니다. 그 다음에 sum값이 올바른지 한 번 더 확인을 하고 다음으로 넘어갑니다. 

그 다음은 입력 값 첫 번째 글자와 두 번째 글자를 정수형으로 가져와서 차가 2이고 합이 14인지를 확인합니다. 차가 2면서 합이 14이며 두 번째 글자가 더 커야 하므로 첫 번째 글자는 6, 두 번째 글자는 8이어야 합니다. 

그 다음은 단순 비교입니다. 처음부터 전체 길이의 절반 만큼을 오른쪽 하단에서 입력값과 실제 키 값과 한 글자씩 비교합니다. 여기까지 했을 때 현재까지의 시리얼은 {681D62F73B520ABBBBBBBBBBBBB5} 입니다. 

그 후부터도 인덱스 순서만 바꿔가면서 한 바이트씩 비교하니까 그냥 인내심만 가지고 디버깅 하면서 어떤 값이랑 비교하는지만 확인하면서 키 값을 만들어 주면 됩니다. 

key : 681D62F73B520A4F6063B7128FF0D645

'Write Up' 카테고리의 다른 글

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
2016 CodeGate Final GMPQZ  (0) 2016.05.04
2016 CodeGate Final BMP  (0) 2016.05.04
2015 Christmas CTF vsnoted  (0) 2016.04.30
장선웅 | 2016.05.07 01:59 | PERMALINK | EDIT/DEL | REPLY
잘 봤어~
Name
Password
Homepage
Secret