[writeup]Based - Points: 200 (picoCTF 2019)
今日のお昼にCTFもくもく会でpicoCTF2019の「Based - Points: 200」を解いたのでそのメモ。
$ nc 2019shell1.picoctf.com xxxx
みたいにするとこんな感じで問題文が表示される。
$ nc 2019shell1.picoctf.com xxxx
Let us see how data is stored
street
Please give the 01110011 01110100 01110010 01100101 01100101 01110100 as a word.
...
you have 45 seconds.....
Input:
問題名からもわかる通りこの01110011 01110100 01110010 01100101 01100101 01110100
みたいなのを文字列に直して答えるという問題。
2進数のあとは8進数・16進数と続く。
最初はこんな感じで手でコピペして答えを出力するのを続けてフラグをゲットした。
input = '01100011 01101111 01101100 01101111 01110010 01100001 01100100 01101111'
puts input.split.map {|e| e.to_i(2).chr}.join
これだとあんまスマートじゃない感じがするので完全に自動で解くスクリプトを書いてみたのがこちら。
require 'socket'
TCPSocket.open("2019shell1.picoctf.com", xxxx) do |socket|
input = ''
loop do
loop do
data = socket.gets
break if data.nil?
return if data.include? 'picoCTF' # 終わり
if data.start_with? "Please give"
m = data.match /Please give( me)? the (?<input>.*) as a word./
input = m[:input]
unless input.include? ' '
input = input.chars.each_slice(2).map {|a| a.join}.join(' ')
end
end
puts data
break if data.start_with? 'Input:' # 入力待ち
end
[2, 8, 16].each do |base|
begin
out = input.split.map {|e| e.to_i(base).chr}.join
rescue => error
next
end
if out.downcase.chars.all? {|c| [*'a'..'z'].include? c}
puts out
socket.puts out
end
end
end
end
n進数を文字に直す部分はe.to_i(base).chr
の部分。
問題の仕様を知ってる前提の処理が多いのがなぁって感じになってしまった…ある程度は仕方ないけど。
とはいえ、[2, 8, 16].each
みたいにして基数を試す部分も、2, 8, 16
が来るとわかってる前提で処理してるにもかかわらず、謎に変換を試みてそれっぽいものになってるか=変換後が英字だけで構成されるかを検証してるのがどっちつかずで微妙な感じがする。
本当はちゃんと判定できたらいいんだけど、1e
みたいなのは可能としても01
は2, 8, 16のどれかわからないし、結論プレフィックスがないから無理な気がしてる。
それとnc
コマンドの役割でTCPSocket
を使っているけど、対話的に処理する部分がいけてない。特定の文字の出力があること前提で入力と出力を制御してる。IO.select
とか使ってちゃんとできるのかなぁーって感じだったけどよくわからなかった。
こんな感じで妥協の産物になってしまったけど問題は解けたからまぁヨシ!