justCTF 2020 writeup
はじめに
1/30 15:00 - 2/1 4:00 (JST)に開催されたjustCTF 2020にチーム「LAIT」として参加しました。 y011d4 との二人チームです。
結果は61st/804チームでした。
このwriteupでは自分が取り組んだ問題についての解法等を書きます。
他の問題についてはチームメイトのwriteupをご覧ください。
フラグを取った問題
[MISC]Sanity Check
『Take That - Rule The World』というタイトルの動画へのリンクが貼られています。
ルールのページに行くと良さそうな気がするので、ルールに書かれていたサンプルのフラグを入力したら通りました。
justCTF{something_h3re!}
[FORE, MISC]PDF is broken, and so is this file
フラグまでの最短経路は以下の通りでした。
binwalk -e challenge
として抽出されるファイルを眺めると、以下のようなテキストファイルが見つかりました。
FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 01 2C 01 2C 00 00 FF DB 00 43 00 08 06 06 07 06 05 08 07 07 07 09 09 08 0A 0C 14 0D 0C 0B 0B 0C 19 12 (以下略)
バイナリのように見え、マジックバイトからjpgだと予想できるため、Hex Fiendにコピペしてバイナリファイルに変換します。
そのバイナリを画像ファイルとして開くと、得られた画像にフラグが書いてあります。
justCTF{BytesAreNotRealWakeUpSheeple}
他にもいくつもの仕掛けがpdfに施されていましたので、自分が把握できたものを書いておきます。
ファイル自体をテキストファイルで開くと以下のようになっていました。
require 'json' require 'cgi' require 'socket' =begin %PDF-1.5 %���� % `file` sometimes lies % and `readelf -p .note` might be useful later 9999 0 obj << /Length 1680 >>stream =end port = 8080 if ARGV.length > 0 then port = ARGV[0].to_i end html=DATA.read().encode('UTF-8', 'binary', :invalid => :replace, :undef => :replace).split(/<\/html>/)[0]+"</html>\n" v=TCPServer.new('',port) print "Server running at http://localhost:#{port}/\nTo listen on a different port, re-run with the desired port as a command-line argument.\n\n" loop do s=v.accept ip = Socket.unpack_sockaddr_in(s.getpeername)[1] print "Got a connection from #{ip}\n" request=s.gets if request != nil then request = request.split(' ') end if request == nil or request.length < 2 or request[0].upcase != "GET" then s.print "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n" s.close next end req_filename = CGI.unescape(request[1].sub(/^\//,"")) print "#{ip} GET /#{req_filename}\n" if req_filename == "favicon.ico" then s.print "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n" s.close next elsif req_filename.downcase.end_with? ".zip" then c="application/zip" d=File.open(__FILE__).read n=File.size(__FILE__) else c="text/html" d=html n=html.length end begin s.print "HTTP/1.1 200 OK\r\nContent-Type: #{c}\r\nContent-Length: #{n}\r\nConnection: close\r\n\r\n"+d s.close rescue Errno::EPIPE print "Connection from #{ip} closed; broken pipe\n" end end __END__ (以下略)
コメントアウトがうまく使われており、rubyのコードとして有効なものになっています。これを実行するとローカルサーバが立ち上がり、zipファイルがダウンロードできました。(binwalkでも同じzipファイルが抽出できます)
zipファイルを開くと、mutoolという実行ファイルのバイナリとMarkdownファイルが手に入り、Markdownに書かれている通りに実行すると、以下の画像が手に入ります。
./mutool draw -r 300 -o rendered.png challenge
この画像に「LMGTFY: 2642 didier "42 bytes" object」とあるため、このキーワードで調べると、こちらのページが見つかります。
また、binwalkで抽出されたファイルの中に、以下のようなテキストファイルも見つかりました。
pip3 install polyfile Also check out the `--html` option! But you'll need to "fix" this PDF first!
[MISC, WEB] Forgotten name
隠されたサブドメインを探す問題です。prefixは与えられていますが、digコマンド等ではサブドメインは探せませんでした。
https://transparencyreport.google.com/https/certificatesというサイトがあるとチームメイトに教えてもらいました。
最初はスコアサーバのサブドメインから探していましたが見つからず、かなり時間が経ってから他のweb問題等のドメインのサブドメインを探すと以下のドメインが見つかりました。
6a7573744354467b633372545f6c34616b735f6f3070737d.web.jctf.pro
このサブドメインを16進のasciiコードとして解釈するとフラグが得られます。
justCTF{c3rT_l4aks_o0ps}
フラグを取りたかった問題
[WEB] Computeration
作題ミスにより、自分の任意のサーバにHTTPSでアクセスさせれば、refererからadminのページが見つかるという問題でした。
しかし、refererの仕様を知らず、HTTPでしかアクセスさせていなかったため、見つけることができませんでした……。
no-referrer-when-downgrade (既定値) これはポリシーが指定されていない場合や、与えられた値が無効であった場合の既定の動作です。プロトコルのセキュリティ水準が同一である場合 (HTTP→HTTP, HTTPS→HTTPS) または改善される場合 (HTTP→HTTPS) は、 URL のオリジン、パス、クエリ文字列がリファラーとして送信されますが、低下する場合 (HTTPS→HTTP) は、リファラーは送信されません。
自分のサイトにHTTPSでアクセスさせてrefererとして得られるURLにアクセスすると、フラグが直接書かれています。
justCTF{cross_origin_timing_lol}
感想
全体的に難易度が高く「これが海外CTFか」となりました。
兎にも角にも、web問専門のはずなのに全然webが解けていないので、これからも精進していきます。