プロジェクト

全般

プロフィール

CTF Writeup SECCON 2018 » 履歴 » バージョン 1

kanata, 2025/04/13 15:28

1 1 kanata
# CTF Writeup SECCON 2018
2
3
{{toc}}
4
5
# 結果&感想
6
7
![score.png](score.png)
8
9
某チームでSECCON2018に参加しました。
10
2問解きました。難しかった、そしてどの問題も重かった。
11
12
国内決勝上位12チームに入れるかどうかは、スコアボードに国名でないから何番かわかんないねw
13
期待しないで全裸で待ってる。
14
15
# Forengics Unzip 101点
16
17
zipにはパスワードがかかっている。
18
19
![Forengics_Unzip.png](Forengics_Unzip.png)
20
21
makefile.sh
22
23
```bash
24
echo 'SECCON{'`cat key`'}' > flag.txt
25
zip -e --password=`perl -e "print time()"` flag.zip flag.txt
26
```
27
28
という訳でUnix通算秒がパスワードになってるはずですね。何時かわからんけど。
29
2018/10/27 0:10 の辺りだろうなと思ったんだけど、とりあえず現在時刻から過去に遡って総当たりしたら終わった。
30
31
```bash
32
33
#!/bin/bash
34
35
C=`date +"%s"`
36
37
while :
38
do
39
  unzip -P $C flag.zip 
40
  if [ $? != 82 ]
41
  then
42
    echo  "-------------------------------------------> $C"
43
    echo $C >> timeline.txt
44
    if cat flag.txt |grep SECCON
45
    then
46
      exit
47
    fi
48
    rm flag.txt
49
  fi
50
  : $((C--))
51
done
52
```
53
54
```
55
Archive:  flag.zip
56
   skipping: flag.txt                incorrect password
57
Archive:  flag.zip
58
   skipping: flag.txt                incorrect password
59
60
61
62
Archive:  flag.zip
63
   skipping: flag.txt                incorrect password
64
Archive:  flag.zip
65
  inflating: flag.txt                
66
-------------------------------------------> 1540566641
67
SECCON{We1c0me_2_SECCONCTF2o18}
68
```
69
70
# Reversing SpecialInstructions 262点
71
72
## 問題
73
74
```
75
Special Instructions
76
77
Execute this file and get the flag.
78
79
References:
80
81
    Assembly samples for many architectures
82
83
http://kozos.jp/books/asm/cross-gcc494-v1.0.zip
84
85
See the assembly samples.
86
87
$ unzip cross-gcc494-v1.0.zip $ cd cross-gcc494/sample $ ls *.d
88
89
See the sample programs running on GDB simulator.
90
91
$ cd cross-gcc494/exec $ ls *.d
92
```
93
94
http://kozos.jp で作問者がわかってしまうw
95
96
## 調査
97
98
実行させるべく、まずはアーキテクチャを調べる。
99
100
```
101
$ file runme
102
runme: ELF 32-bit MSB executable, *unknown arch 0xdf* version 1 (SYSV), statically linked, not stripped
103
```
104
105
0xdf…?こんなアーキあるのかなと思いましたが、チームの方が[moxie](http://www.sco.com/developers/gabi/latest/ch4.eheader.html)であることを教えてくれました。ありがたいです。
106
107
> 10進数になおして、223が Moxie processor family でした http://www.sco.com/developers/gabi/latest/ch4.eheader.html
108
109
さてこれを実行する環境ですが、作問者のお力を借りるのが最短ルートでしょう!
110
111
>クロスコンパイル環境の構築はコンパイルに結構な時間を要します
112
113
[熱血!/大熱血! アセンブラ入門 開発環境のVMイメージ](http://kozos.jp/vmimage/burning-asm.html)からVMイメージをダウンロードします。
114
115
>[SECCON2015](https://raintrees.net/projects/a-painter-and-a-black-cat/wiki/CTF_Writeup_SECCON_2015#Individual-Elebin)にも他種類のCPUアーキテクチャの問題が出ていました。
116
117
ダウンロード後、以下で逆アセできます。
118
119
```
120
$ /usr/local/cross2-gcc494/bin/moxie-elf-objdump -d -M intel ./runme
121
```
122
123
逆アセしたのは、ここに置いておきます。
124
125
attachment:Reversing_SpecialInstructions_asm.txt
126
127
で、これ実行できないんですよね、gdbで実行しようとしても"Illegal instruction."って表示され、終了します
128
129
```
130
$ /usr/local/cross2-gcc494/bin/moxie-elf-gdb ./runme
131
132
(gdb) target sim
133
Connected to the simulator.
134
(gdb) load
135
Loading section .text, size 0x23e lma 0x1400
136
Loading section .rodata, size 0xb0 lma 0x1640
137
Loading section .data, size 0x60 lma 0x1800
138
Start address 0x1400
139
Transfer rate: 6768 bits in <1 sec.
140
(gdb) run
141
Starting program: /home/user/SECCON2018/Reversing_SpecialInstructions/runme 
142
143
Program received signal SIGILL, Illegal instruction.
144
0x0000154a in set_random_seed ()
145
(gdb) 
146
```
147
148
原因は、ここ
149
150
```
151
0000154a <set_random_seed>:
152
    154a:       16 20           bad
153
    154c:       04 00           ret
154
155
0000154e <get_random_value>:
156
    154e:       17 20           bad
157
    1550:       04 00           ret
158
```
159
160
16と17の命令はmoxieに存在しません。
161
この命令をnopとかで潰して実行すると以下が出力されました。
162
163
```
164
This program uses special instructions.
165
SETRSEED: (Opcode:0x16)
166
        RegA -> SEED
167
GETRAND: (Opcode:0x17)
168
        xorshift32(SEED) -> SEED
169
        SEED -> RegA
170
```
171
172
16と17の命令は実装してね(はあと)って事ですね。
173
174
### xorshift32
175
176
実装にあたって、xorshift32 から調べてみます。
177
178
wikipedia:https://ja.wikipedia.org/wiki/Xorshift
179
180
```
181
Xorshiftは疑似乱数列生成法の1つである。George Marsagliaが2003年に提案した。
182
```
183
184
>Googleさんが採用してるやつかな?
185
186
Cの実装例が載っていました。最高です。
187
188
```c
189
uint32_t xor(void) {
190
  static uint32_t y = 2463534242;
191
  y = y ^ (y << 13); y = y ^ (y >> 17);
192
  return y = y ^ (y << 15);
193
}
194
```
195
196
### アセンブラを読む
197
198
わからない命令は[ココ](http://moxielogic.org/blog/pages/architecture.html)で調べながら読みました。
199
200
>解りやすいアーキでよかった。。
201
202
ざっくりこんな感じになっていました。
203
私の理解を#以降に書いています。
204
205
```
206
000015a2 <main>:
207
    15a2:       06 18           push    $sp, $r6
208
    15a4:       91 18           dec     $sp, 0x18
209
    15a6:       01 20 92 d6     ldi.l   $r0, 0x92d68ca2         # set_random_seedに渡す引数(SEED) 0x92d68ca2
210
    15aa:       8c a2 
211
    15ac:       03 00 00 00     jsra    154a <set_random_seed>  # set_random_seed関数呼び出し
212
    15b0:       15 4a 
213
214
    中略
215
216
    160c:       01 20 00 00     ldi.l   $r0, 0x1800    # decode関数に渡す引数1
217
    1610:       18 00 
218
    1612:       01 30 00 00     ldi.l   $r1, 0x1820    # decode関数に渡す引数2
219
    1616:       18 20 
220
    1618:       03 00 00 00     jsra    1552 <decode>  # decode関数呼び出し
221
    161c:       15 52 
222
    161e:       02 32           mov     $r1, $r0
223
    1620:       01 20 00 00     ldi.l   $r0, 0x1
224
    1624:       00 01 
225
    1626:       19 80           jsr     $r6
226
    1628:       01 20 00 00     ldi.l   $r0, 0x1
227
    162c:       00 01 
228
    162e:       01 30 00 00     ldi.l   $r1, 0x167c
229
    1632:       16 7c 
230
    1634:       19 80           jsr     $r6
231
    1636:       2e 22           xor     $r0, $r0
232
    1638:       03 00 00 00     jsra    144a <exit>
233
    163c:       14 4a 
234
```
235
236
```
237
00001552 <decode>:
238
    1552:       06 18           push    $sp, $r6
239
    1554:       06 19           push    $sp, $r7
240
    1556:       06 1a           push    $sp, $r8
241
    1558:       06 1b           push    $sp, $r9
242
    155a:       06 1c           push    $sp, $r10
243
    155c:       06 1d           push    $sp, $r11
244
    155e:       91 18           dec     $sp, 0x18
245
    1560:       02 d2           mov     $r11, $r0           # $r11 = $r1(最初が0x1800)
246
    1562:       1c 42           ld.b    $r2, ($r0)
247
    1564:       2e 22           xor     $r0, $r0
248
    1566:       0e 42           cmp     $r2, $r0			
249
    1568:       c0 12           beq     158e <decode+0x3c> # if $r2 == $r0 then return
250
    156a:       02 a3           mov     $r8, $r1            # $r8  = $r1(最初が0x1820)
251
    156c:       02 9d           mov     $r7, $r11           # $r7  = $r11
252
    156e:       01 c0 00 00     ldi.l   $r10, 0x154e        # $r10 = 0x154e
253
    1572:       15 4e 										
254
    1574:       1c 8a           ld.b    $r6, ($r8)          # $r6  = 0x1820の中身
255
    1576:       2e 22           xor     $r0, $r0            # $r0  = 0
256
    1578:       19 c0           jsr     $r10                # $r0  = 乱数取得32bit
257
    157a:       2e 82           xor     $r6, $r0            # $r6  = $r6 xor $r0
258
    157c:       1c 29           ld.b    $r0, ($r7)          # $r0  = 0x1800の中身
259
    157e:       2e 82           xor     $r6, $r0            # $r6  = $r6 xor $r0
260
    1580:       1e 98           st.b    ($r7), $r6          # 0x1800の中身 = $r6
261
    1582:       89 01           inc     $r7, 0x1            # $r7  = 0x1800++
262
    1584:       8a 01           inc     $r8, 0x1            # $r8  = 0x1820++
263
    1586:       1c 39           ld.b    $r1, ($r7)          # $r1  = 0x1800++の中身
264
    1588:       2e 22           xor     $r0, $r0            # $r0  = 0
265
    158a:       0e 32           cmp     $r1, $r0			
266
    158c:       c7 f3           bne     1574 <decode+0x22>  # if $r1 != NULL then goto 0x1574
267
    158e:       02 2d           mov     $r0, $r11			
268
    1590:       02 e0           mov     $r12, $fp			
269
    1592:       9e 18           dec     $r12, 0x18
270
    1594:       07 ed           pop     $r12, $r11
271
    1596:       07 ec           pop     $r12, $r10
272
    1598:       07 eb           pop     $r12, $r9
273
    159a:       07 ea           pop     $r12, $r8
274
    159c:       07 e9           pop     $r12, $r7
275
    159e:       07 e8           pop     $r12, $r6
276
    15a0:       04 00           ret
277
```
278
279
という事で、以下の動きになっていることがわかりました。
280
281
1. r6 = 0x1820の中身(1byte)
282
2. r0 = 乱数32bit(4byte)
283
3. r6 = r6 ^ r0
284
4. r0 = 0x1800の中身(1byte)
285
5. r6 = r6 ^ r0
286
6. 0x1800と0x1820は1増やして、1の処理に戻る
287
288
0x1800と0x1820あたりに、どんな値が入っているか調べておきます。
289
290
```
291
(gdb) x/100x 0x1800
292
0x1800 <flag>:  0x6d    0x72    0xc3    0xe2    0xcf    0x95    0x54    0x9d
293
0x1808 <flag+8>:        0xb6    0xac    0x03    0x84    0xc3    0xc2    0x35    0x93
294
0x1810 <flag+16>:       0xc3    0xd7    0x7c    0xe2    0xdd    0xd4    0xac    0x5e
295
0x1818 <flag+24>:       0x99    0xc9    0xa5    0x34    0xde    0x06    0x4e    0x00
296
0x1820 <randval>:       0x3d    0x05    0xdc    0x31    0xd1    0x8a    0xaf    0x29
297
0x1828 <randval+8>:     0x96    0xfa    0xcb    0x1b    0x01    0xec    0xe2    0xf7
298
0x1830 <randval+16>:    0x15    0x70    0x6c    0xf4    0x7e    0xa1    0x9e    0x0e
299
0x1838 <randval+24>:    0x01    0xf9    0xc2    0x4c    0xba    0xa0    0xa1    0x08
300
0x1840 <randval+32>:    0x70    0x24    0x85    0x8a    0x4d    0x2d    0x3c    0x02
301
0x1848 <randval+40>:    0xfc    0x6f    0x20    0xf0    0xc7    0xad    0x2f    0x97
302
0x1850 <randval+48>:    0x2b    0xcc    0xa3    0x34    0x23    0x53    0xc9    0xb7
303
0x1858 <randval+56>:    0x0c    0x10    0x6c    0x0e    0xfa    0xf9    0xa1    0x9a
304
0x1860: 0x00    0x00    0x00    0x00
305
```
306
307
xorshift32ですが、乱数といってもシード固定の計算値なので、予め計算しておきます。
308
309
```
310
$ cat xorshift32.c 
311
#include <stdio.h>
312
#include <stdint.h>
313
314
uint32_t xor(void) {
315
  static uint32_t y = 0x92d68ca2;
316
  int i;
317
318
  for(i=0;i<40;i++)
319
  {
320
    y = y ^ (y << 13); y = y ^ (y >> 17);
321
    y = y ^ (y << 15);
322
    printf("%x\n",y);
323
  }
324
  return y;
325
}
326
327
main(void){
328
  xor();
329
}
330
331
$ gcc  xorshift32.c ;./a.out 
332
35c36d03
333
c8fa2132
334
9f72275c
335
3ed1ca90
336
e32b4951
337
1c29ac51
338
e5e39880
339
7f0f53f9
340
89d0b941
341
f5e6563d
342
cbf769ad
343
4ba4dacc
344
49a432b2
345
c557954b
346
40a4eeb4
347
dd74800d
348
ce2e86b7
349
2a1de9cb
350
f6084259
351
70ff1d78
352
b93854d0
353
b5228d01
354
8b22df40
355
8b583725
356
e54151fb
357
e45c5644
358
1e13e10e
359
6a399017
360
f63e5c0a
361
bcd582d5
362
9ec62492
363
7e8849b8
364
ce8cf267
365
4dc3ba07
366
99204746
367
f619cfa2
368
3bc7e854
369
43540b32
370
d727aa2b
371
4fefdb1a
372
```
373
374
## 実装
375
376
ここまで判ったらシェルでシュッてできるんやで
377
378
solv.sh
379
380
```bash
381
#!/bin/bash
382
383
IFS='
384
'
385
386
LIST='
387
35c36d03 6d 3d
388
c8fa2132 72 05
389
9f72275c c3 dc
390
3ed1ca90 e2 31
391
e32b4951 cf d1
392
1c29ac51 95 8a
393
e5e39880 54 af
394
7f0f53f9 9d 29
395
89d0b941 b6 96
396
f5e6563d ac fa
397
cbf769ad 03 cb
398
4ba4dacc 84 1b
399
49a432b2 c3 01
400
c557954b c2 ec
401
40a4eeb4 35 e2
402
dd74800d 93 f7
403
ce2e86b7 c3 15
404
2a1de9cb d7 70
405
f6084259 7c 6c
406
70ff1d78 e2 f4
407
b93854d0 dd 7e
408
b5228d01 d4 a1
409
8b22df40 ac 9e
410
8b583725 5e 0e
411
e54151fb 99 01
412
e45c5644 c9 f9
413
1e13e10e a5 c2
414
6a399017 34 4c
415
f63e5c0a de ba
416
bcd582d5 06 a0
417
9ec62492 4e a1
418
7e8849b8 00 08
419
'
420
421
for LINE in $LIST
422
do
423
  SEED=$(echo $LINE|awk '{print $1}')
424
  x1800=$(echo $LINE|awk '{print $2}')
425
  x1820=$(echo $LINE|awk '{print $3}')
426
  printf %x $(((0x$x1800^0x$SEED)^0x$x1820))|cut -c7-|xxd -p -r
427
done
428
```
429
430
```
431
$ ./solv.sh 
432
SECCON{MakeSpecialInstructions}
433
```
434
435
# おまけ
436
437
Forengics History の問題、タイトルがずっと **Hisotry** だったんだけど、いつの間にかひっそりと修正されていた件。
438
チームで盛り上がった(変に深読みしたw)