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 |  |
||
| 8 | |||
| 9 | 某チームでSECCON2018に参加しました。 |
||
| 10 | 2問解きました。難しかった、そしてどの問題も重かった。 |
||
| 11 | |||
| 12 | 国内決勝上位12チームに入れるかどうかは、スコアボードに国名でないから何番かわかんないねw |
||
| 13 | 期待しないで全裸で待ってる。 |
||
| 14 | |||
| 15 | # Forengics Unzip 101点 |
||
| 16 | |||
| 17 | zipにはパスワードがかかっている。 |
||
| 18 | |||
| 19 |  |
||
| 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) |