ぶちのブログ

競プロとCTFが趣味なWebエンジニアのアウトプットの場

justCTF 2020 writeup

はじめに

1/30 15:00 - 2/1 4:00 (JST)に開催されたjustCTF 2020にチーム「LAIT」として参加しました。 y011d4 との二人チームです。
結果は61st/804チームでした。

f:id:betit0919:20210202215405p:plain

この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にコピペしてバイナリファイルに変換します。
そのバイナリを画像ファイルとして開くと、得られた画像にフラグが書いてあります。

f:id:betit0919:20210202215429j:plain

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

f:id:betit0919:20210202221054p:plain

この画像に「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でしかアクセスさせていなかったため、見つけることができませんでした……。

developer.mozilla.org

no-referrer-when-downgrade (既定値) これはポリシーが指定されていない場合や、与えられた値が無効であった場合の既定の動作です。プロトコルのセキュリティ水準が同一である場合 (HTTP→HTTP, HTTPSHTTPS) または改善される場合 (HTTP→HTTPS) は、 URL のオリジン、パス、クエリ文字列がリファラーとして送信されますが、低下する場合 (HTTPS→HTTP) は、リファラーは送信されません。

自分のサイトにHTTPSでアクセスさせてrefererとして得られるURLにアクセスすると、フラグが直接書かれています。

justCTF{cross_origin_timing_lol}

感想

全体的に難易度が高く「これが海外CTFか」となりました。
兎にも角にも、web問専門のはずなのに全然webが解けていないので、これからも精進していきます。