CyberRebeatCTF というものに参加しました*1。
どうやらIT系同人サークルの人たちが主催しているっぽい。
これの協力をしている会社Aqutras はその昔アルバイトでお世話になっていた会社で、ActiveDefense研究所については、社長?所長? の方の講演を聞いたりしたこともありFacebookでつながっており、参加してねポストが流れてきたので、興味もあり参加しました。
最終順位は63 /148でした。
以下writeupや所感など
writeup (とけたやつ)
Misc
Readme
image.jpgをダウンロードするとなんか変なものが書かれた画像ファイルが取得できる。
なんか コム? ソロ? ?モムワ?
としか読めない…
というわけではなくて、ちょっと前に流行った日本人には読めないフォントで書かれているだけ。
一番下の行さえ読めばいい。
CRCTF{YOUCANPLAYCYBERREBEATINBOTHLANGUAGES}
Trivia
Crossword
何も考えずにCrosswordを解いていけばいい。
CRCTF{submarine}
Web
White Page
問題文にURLとログイン情報は書かれている。
しかし、URL先にアクセスすると、ログインボタンしか表示されていない。
Inspectorを起動すると style="visibility:hidden"
が指定されているので、これを消したらフォームが出てくる。
でログインしたらOK
CRCTF{All I typed were four letters.}
Let's tweet
ツイートしてそのURL貼ったら終わり。
(何かを仕込めそうな気もするけど諦めた)
(そしてflagをメモり忘れた)
Programming
Calculation
指定されたコマンドを打つと、単純な加減算の問題が出てくる。 でそれに答えるとまた次の問題が…、というもの。
(*'-') < nc 59.106.212.75 8080 39 - 62 + 4 - 5 - 28 -52 55 - 19 - 68 - 94 + 51
めんどくさいのでスクリプトにさせましょう
require 'socket' ADDR = ARGV[0] PORT = ARGV[1] socket = TCPSocket.open(ADDR, PORT) while true response = socket.gets.chomp! puts response ans = eval(response) break unless response socket.write(ans.to_s + "\n") end
CRCTF{She calls herself a human calculator}
Prime Factor
上と同様に指定されたアドレスにncすると、ある数字が送られる。
その数字を素因数分解して、最大の素数を答える、というもの。
これも同様にスクリプトでやりましょう。
Rubyには Prime.prime_division
という便利なメソッドが生えていました。
require 'socket' require 'prime' ADDR = ARGV[0] PORT = ARGV[1] socket = TCPSocket.open(ADDR, PORT) while true response = socket.gets.chomp! break unless response ans = response.gsub!(/\W/,'') prime_max = Prime.prime_division(response.to_i).last.first puts prime_max socket.write(prime_max.to_s + "\n") end
CRCTF{I'm a calculating type by nature.}
あと少しのとこまでやったもの
Programming
Visual Novels
あるユーザーは"Reading Power"を持っている。これはVisualNovelを月にどのくらい読めるかを示している。 彼がたくさんのVisualNovelを持っているとき、彼はどの組み合わせでプレイすればその月の満足度を最大にできるか。 最大の満足度を答えよ。
実際にアクセスすると、こんなかんじ。 ちなみに1問目の場合、30以下のサイズで最も満足できるのは28の本なので3と入力すると、次の問題が表示されます。
(*;-;)? < nc 59.106.212.75 8082 Reading Power = 30 Games([size, satisfaction]) = [28, 3], [27, 1], [25, 2], Answer = ? 3 Reading Power = 100 Games([size, satisfaction]) = [60, 3], [68, 3], [38, 4], [95, 10], [81, 2], Answer = ?
どう見てもナップサック問題じゃん! と思ったけど、プログラミング力がないので泣きながら再帰を書いた…
require 'socket' require 'open3' ADDR = ARGV[0] PORT = ARGV[1] socket = TCPSocket.open(ADDR, PORT) reading_flag = false def rec(i, max, list, memo) res = 0; if memo[i][max] >= 0 memo[i][max] end return res if i == list.length if max < list[i][:size] res = rec(i + 1, max, list, memo) else res = [ rec(i+1, max, list, memo), rec(i+1, max - list[i][:size], list, memo) + list[i][:satisfaction] ].max end memo[i][max] = res end while true response = socket.gets puts response response.gsub!(/[^\w\s]/,'')&.chomp! case response when /Reading/ reading_flag = true @uplimit = response.split(' ')[2].to_i @list = [] ] when /Games/ next when /^\d/ response = response.split(' ') @list << {size: response[0].to_i, satisfaction: response[1].to_i} when /Answer/ next else next unless reading_flag res = rec(0, @uplimit, @list, Array.new(@uplimit + 1, Array.new(@uplimit+1, -1))) socket.write(res.to_s + "\n") reading_flag = false end end
最初メモ化もせずに書いてタイムアウトし、メモ化してもタイムアウトするので調べてDP使って泣きながら書き直した…
require 'socket' require 'open3' ADDR = ARGV[0] PORT = ARGV[1] socket = TCPSocket.open(ADDR, PORT) reading_flag = false def dp(max, list) max_cost = 0 table = Hash.new table[0] = 0 list.length.times do |ind| tmp = table.clone table.each do |k, v| total_w = k + list[ind][:size] total_v = v + list[ind][:satisfaction] unless tmp.has_key?(total_w) tmp[total_w] = total_v end if max >= total_w && total_v > max_cost max_cost = total_v end end table = tmp.clone end return max_cost end while true response = socket.gets puts response response.gsub!(/[^\w\s]/,'')&.chomp! case response when /Reading/ reading_flag = true @uplimit = response.split(' ')[2].to_i @list = [] when /Games/ next when /^\d/ response = response.split(' ') @list << {size: response[0].to_i, satisfaction: response[1].to_i} when /Answer/ next else next unless reading_flag res = dp(@uplimit, @list) socket.write(res.to_s + "\n") reading_flag = false end end
しかしこれだと30要素の答えが合わず…断念。
Web
Uploader
指定されたURLにアクセスするとファイルの一覧が。
ファイル検索っぽい窓があるので、そこに1発 ' OR '1'='1'; --
打ち込んであげれば秘密のファイルが見れます。
で、秘密のファイルを開こうとしたところパスワードが掛かっており、断念です*2…
感想
久しぶりのCTFでした。
100点と200点問題で構成されていましたが、200点問題が解けなかったのが悔しい…!
ただ、簡単かもしれないけどプログラミング問題に挑戦してとけたのは個人的には嬉しいです。
バイナリ系は全く無理なので今後頑張りたい。
そういえば社内CTFあるらしいので勉強しようと思います。