前回 は、C言語とアセンブラでシェルを起動するプログラムを機械語に直して動かしてみました。
今回は、「入門セキュリティコンテストーーCTFを解きながら学ぶ実戦技術」を読みました。CTF の各ジャンルごとに、練習問題の解き方を丁寧に説明された本で、とてもオススメできる内容でした。単なる解法だけではなく、そこで使われている技術についても丁寧な解説がされていました。
また、この本では、CTF で、よく使われているとされるツールが、たくさん紹介されていたので、今回は、そのツールを調べたり、実際に使ってみたりしたいと思います。
それでは、やっていきます。
参考文献
はじめに
「セキュリティ」の記事一覧です。良かったら参考にしてください。
セキュリティの記事一覧
それでは、やっていきます。
入門セキュリティコンテストの概要
約220ページの本で、CTF に初めて挑戦する人向けの内容でした。私も初心者なので、とても参考になる内容でした。
国内の著名な CTF として、以下が紹介されていました。
また、著名なオンライン常設型の CTF として、以下が紹介されていました。
他にも、初心者向けとして、picoCTF、CSAW CTF の writeup が参考になると書かれていました。
問題のジャンル別の解説
以降は、問題のジャンル別に、過去の問題を実際に解いていく過程を解説されています。
リバースエンジニアリング問題:IDA Pro
逆アセンブラのツールとして、「IDA Pro」の無償版の「IDA Freeware」が紹介されています。
以下が公式サイトです。ここから無償版としては、「IDA Free」と「IDA Demo」がダウンロードできそうです。機能一覧を見たところ、無償版は、どちらも、x86 と x64 のみ対応で、ARM には対応してなさそうでした。
hex-rays.com
暗号問題:PkCrack
ここでは、パスワード付きの ZIPファイルが問題の対象でした。
パスワードは分からない状況でも、ZIPファイルの中身以外の情報(ZIPファイルに格納されているファイル名、ファイルサイズなど)を取得するのに、zipinfoコマンドを使用されていました。
問題の対象ファイル(unzipというファイル名)をダウンロードしてきて、実際に、zipinfoコマンドを使ってみます。3つのファイルが圧縮されたことが分かります。Windows の 7-zip という圧縮解凍ツールでも、圧縮ファイルを 7-zip で開くと、同じような情報は得られます。
$ zipinfo unzip
Archive: unzip
Zip file size: 21710 bytes, number of entries: 3
-rw-r----- 3.0 unx 14182 TX defN 15-Nov-30 16:23 backnumber08.txt
-rw-r----- 3.0 unx 12064 TX defN 15-Nov-30 16:22 backnumber09.txt
-rw------- 3.0 unx 22560 BX defN 15-Dec-01 15:21 flag
3 files, 48806 bytes uncompressed, 21148 bytes compressed: 56.7%
パスワード付きZIPファイルのパスワードをクラックするツールとして、PkCrack が使われていました。
www.unix-ag.uni-kl.de
ソースファイルへのリンクがあるので、ダウンロードして、ビルドする必要があります。ビルドが完了すると、pkcrack という実行ファイルが得られます。
$ tar zxvf pkcrack-1.2.3.tar.gz
$ cd pkcrack-1.2.3/
$ cd src/
$ make
では、実際に、パスワードをクラックしてみます。
なぜ、パスワード付きZIPファイルのパスワードがクラックできるかと言うと、デフォルトでパスワード付きZIPファイルを作成する場合、Traditional PKWARE Encryption という暗号方式が使われるそうで、これは、既に簡単にクラックされてしまう方式だそうです(書籍には、丁寧な解説があります)。
ただし、パスワード付きZIPファイルに格納されたファイル(今回の場合は3ファイル)のうち、暗号化されてないファイルが、1ファイルは手元にあることが条件です。今回のように、3つのファイルのうち、2つのファイルの backnumber08.txt と backnumber09.txt は、Web を検索すると、すぐに入手することが出来ます。ここでは、backnumber08.txt を使います。
あと、準備として、事前に、同じ圧縮率で ZIPファイルに格納されている平文ファイルを、普通に ZIP圧縮したファイルが必要です。では、やってみます。約2分半でクラックできたようです。指定したファイル「unzip_decrypted.zip」は、パスワードが無い ZIPファイルです。
$ zip backnumber08.zip backnumber08.txt
$ ../../pkcrack-1.2.3/src/pkcrack -C unzip -c backnumber08.txt -p backnumber08.txt -P backnumber08.zip -d unzip_decrypted.zip
Files read. Starting stage 1 on Sun Sep 1 22:55:09 2024
Generating 1st generation of possible key2_5299 values...done.
Found 4194304 possible key2-values.
Now we're trying to reduce these...
Lowest number: 984 values at offset 970
Lowest number: 932 values at offset 969
Lowest number: 931 values at offset 967
Lowest number: 911 values at offset 966
Lowest number: 906 values at offset 965
Lowest number: 904 values at offset 959
Lowest number: 896 values at offset 955
Lowest number: 826 values at offset 954
Lowest number: 784 values at offset 606
Lowest number: 753 values at offset 206
Done. Left with 753 possible Values. bestOffset is 206.
Stage 1 completed. Starting stage 2 on Sun Sep 1 22:55:51 2024
Ta-daaaaa! key0=270293cd, key1=b1496a17, key2=8fd0945a
Probabilistic test succeeded for 5098 bytes.
Ta-daaaaa! key0=270293cd, key1=b1496a17, key2=8fd0945a
Probabilistic test succeeded for 5098 bytes.
Stage 2 completed. Starting zipdecrypt on Sun Sep 1 22:57:35 2024
Decrypting backnumber08.txt (5315a01322ab296c211eecba)... OK!
Decrypting backnumber09.txt (83e6640cbec32aeaf10ed1ba)... OK!
Decrypting flag (34e4d2ab7fe1e2421808bab2)... OK!
Finished on Sun Sep 1 22:57:35 2024
パスワード付きZIPファイルを使うときは、暗号化方式をデフォルトのまま使ってはいけない、という知見が得られました。
フォレンジック問題:usnparser
ここでは、Windows 上で、ファイルやフォルダに対する変更処理を記録したログファイルである、USN(Updated Sequence Number)ジャーナルが解析対象となっています(初めて知りました)。このログファイルをパースするのに、usnparser というツール(Pythonパッケージ)が紹介されています。
pypi.org
事前知識がないと、絶対にたどり着けないですね。
あと、解説の途中で、stringsコマンドで、2byte文字を扱ってるところがありましたのでメモしておきます。
実際に使われていたのは、「$ strings -e l J
」で、J というファイル名に対して使われていました。
-e オプションで、「s、S、b、l、B、L」を指定することが出来ます。ParrotOS で stringsコマンドを manコマンドで見た結果を表にしておきます。
オプション |
内容 |
s |
single-7-bit-byte characters (default) |
S |
single-8-bit-byte characters |
b |
16-bit bigendian |
l |
16-bit littleendian |
B |
32-bit bigendian |
L |
32-bit littleendian |
あと、Useful for finding wide character strings. (l and b apply to, for example, Unicode UTF-16/UCS-2 encodings).
とあるように、マルチバイト文字の場合、l と b が適用できるとあります。
Webセキュリティ問題:うさみみハリケーン
ここでは、SECCON 令和CTF で出題された「reiwaVote」という問題を扱っています。読み進めると、なかなかユーモアのある問題です。
ここでは、ツールではないですが、定番の SQLインジェクションの手段が解説されています。' or 1=1 --
です。
SQLインジェクションでフラグは獲得できてしまうのですが、なぜ、この SQLインジェクションでフラグが獲得できたかを丁寧に解説されています。
問題となっている Webアプリケーションについて、以下のツールを使って解析しています。
www.vector.co.jp
このツールを使うと、実行中のプロセスのメモリを参照、編集することが出来るようです。これにより、実行されている SQL文や、Webアプリケーションのソースコードを抽出できるようです。
次回の Webアプリケーションの問題をやるときに使ってみたいと思います。
また、Webアプリケーションのセキュリティを学ぶ書籍として、以下がオススメされていました。確かに、Webセキュリティのバイブルだと思います。
ネットワーク問題:Scapy、PingTunnel
pcapファイルを解析する問題を扱っています。今回の問題では、141個のパケットが格納されており、その全てが ICMP のパケットというものでした。
ICMP の pcapファイルに埋め込まれた画像ファイル(PNGファイル)を抽出するのに、Python の Scapy を使っています。
ICMP に、任意のデータを埋め込む手法(ICMP Tunnel)ことが出来ることが解説されています。また、そのためのツールとして、PingTunnel が紹介されています。
PingTunnel の公式サイトは以下です。
www.cs.uit.no
今回は、直接、解法にこのツールを使うわけではないため、サイトの紹介だけとしたいと思います。世の中には、いろんなツール、手法があるんだなと感じました。
Pwnable問題
ここでは、baby_stack という SECCON 2017 のオンライン予選で出題された問題を取り扱っています。
ここでも、バイナリの逆アセンブルは、IDA PRo が使われています。
baby_stack には、スタックバッファオーバーフローの脆弱性があるようです。そこにシェルを起動するプログラムを埋め込んで侵入し、フラグを取得する流れになっています。
「機械語でシェルを起動するプログラムを作る(ARM64) - 土日の勉強ノート」の私の記事で、シェルを起動するプログラムを手動で作りましたが、mprotect を使って、無理やり、実行させました。ここでは、ROP(Return Oriented Programming)という手法で、実行できない領域でも、シェルを起動する方法を取り扱っています。
ROP とは、既にプログラム内に存在する命令の断片をつなぎ合わせて、任意の動作を行えるようにする手法です。
socatコマンド
CTF の大会終了後、サーバは非公開になりますが、同じ環境を再現するために「socatコマンド」を使う方法が紹介されています。
socatコマンドとは、netcatコマンドの高機能版のようなツールらしく、baby_stack の環境を再現させる方法をメモしておきます。
問題ファイルと flag.txt を同じディレクトリに配置後、以下を実行することで、環境を再現できるそうです。
$ socat tcp-listen:15285,reuseaddr,form,EXEC:"./baby_stack"
脆弱性緩和技術のチェックツール:checksec
前回のシェルを起動するプログラムのときに、苦労した内容を簡単に調べることが出来るツールのようです。前回は、シェルを起動するプログラムが、dataセクションに配置されていて、実行が出来ない状況でした。そういう制約を調べることが出来るツールのようです。
github.com
シェルスクリプト版としては、2.7.x(現在は、2.7.1)が最終リリースで、以降の 3.x からは、Go言語による実装に代わるそうです。
では、Release から 2.7.1 をダウンロードして、早速前回の環境で使ってみます。
シェルを起動する機械語を埋め込んだプログラムで試します。何も対策をしていない状態だと以下のようになるようです。NX は、No Execute のことで、スタックなどのデータ領域に置かれているデータを、命令として解釈して実行することは禁止されている状態とのことです。
$ ../../checksec.sh-2.7.1/checksec --file=./execve_str.out
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
Partial RELRO No canary found NX enabled No PIE N/A N/A 3153 Symbols N/A 0 22 ./execve_str_fixed.out
Pwnable の問題のときは、まず、このチェックツール「checksec」を実行する方がいいようです。
ROPガジェットを探すツール:rp++
上で説明したように、スタックバッファオーバーフローで、任意のコードを配置できても、実行できない領域の場合に、ROP という手法でシェルを起動していく方法が説明されています。
既にプログラム内にある命令の断片を探すツールが、「rp++」です。
以下は、rp++ の GitHub です。
github.com
このツールについては、前回の記事の続きとして、シェルを起動するプログラムを発展させていくときに使ってみたいと思います(今の私のレベルでは難しいというのが理由になります)。
ここでは、侵入からシェルの起動までを、Exploitコードとして、Pythonスクリプトで実装されています。その実装に便利な Python ライブラリが「pwntools」です。
こちらも、今回は、公式サイトの紹介だけとします。
github.com
Exploitコードの実装を学ぶには、以下の書籍がオススメされていました。564ページと、結構なボリュームがありますが、私も読んでみようと思います。
Misc問題:Sandstorm
今回は、与えられた画像から、隠されたデータを見つける問題でした。
問題の画像は、インターレース画像(通常のように、上から順に画像を描画していくのではなく、全体を徐々に描画していく方式)で、Adam7 という方式が使われていました。
画像の解析は、Pythonスクリプトで、OpenCV のライブラリを使用されていました。また、Adam7 のインターレースを実現するのに、ImageMagic というツールが使われていました。
画像や音声ファイルなどに、任意の別のデータを隠す技術を、情報ハイディング技術と呼ぶそうです。CTF のジャンルとしては、今回は、Misc(分類でできない)問題とされてましたが、Steganography の問題と言ってもいいようです。
まず、情報ハイディング技術の解説として、以下の電子情報通信学会の記事が紹介されていました。
https://www.ieice-hbkb.org/files/01/01gun_03hen_13.pdf
また、Steganography で隠ぺいされたデータがないかを解析するツールとして、「stegsolve」、「stegdetect」が紹介されていました。
Misc問題:Mail Address Validator
今回は、脆弱性のある正規表現に対して、どういう入力をすれば、その脆弱性を発現させるか、という問題でした。脆弱性のある正規表現は、ReDoS(Regular expression Denial of Service)と呼ばれるそうです。
正規表現エンジンは、有限オートマトンで実現されており、書籍では、有限オートマトンについての丁寧な解説がされていました。
有限オートマトンについてのオススメの書籍として、以下が紹介されていました。
ReDos の詳しい説明や事例について、以下が紹介されていました(英語でした)。
owasp.org
おわりに
今回は、「入門セキュリティコンテストーーCTFを解きながら学ぶ実戦技術」に沿って、書籍で紹介されているツールについて調べてみました。知らないことばかりで、大変参考になる本でした。
この書籍の最後で、さらに勉強したい人向けに、以下の CTF の書籍が紹介されていました。
一冊目は、私も少し読んだことがありました。難易度的には、今回の書籍「入門セキュリティコンテストーーCTFを解きながら学ぶ実戦技術」と近い印象です。
二冊目は、これから読もうと思っていた本です。難易度は少し上がると思います。
2冊とも、よく聞く本だと思います。今回は以上です。
最後になりましたが、エンジニアグループのランキングに参加中です。
気楽にポチッとよろしくお願いいたします🙇
今回は以上です!
最後までお読みいただき、ありがとうございました。