ぶちのブログ

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

BCACTF write up (後半)

前半はこちら

1+1=window

ふたつの16進数をそれぞれ足し算して、アスキーコードから逆変換するとフラグが得られる。

a="0x23 0x49 0x16 0x46 0x45 0x16 0x3c 0x3c 0x45 0x64 0x16 0x37 0x3c 0x3c 0x3c 0x16 0x46 0x45 0x37 0x1e 0x49 0x16 0x46 0x49 0x16 0x1e 0x16 0x32 0x32 0x3c 0x32 0x49 0x3c 0x64 0x1e 0x32 0x3c 0x18 0x64 0x32 0x32 0x50 0x14 0x64 0x32 0x5a 0x45 0x32 0x32 0x55 0x50 0x49 0x3c 0x14 0x3c 0x5f"
b="0x26 0x2b 0x0a 0x23 0x2e 0x0a 0x29 0x25 0x2e 0x15 0x0a 0x37 0x25 0x25 0x2c 0x0a 0x23 0x2e 0x37 0x09 0x2b 0x0a 0x23 0x2b 0x0a 0x21 0x0a 0x30 0x31 0x25 0x31 0x2b 0x2a 0x17 0x13 0x2d 0x2c 0x18 0x0c 0x01 0x2d 0x29 0x1c 0x11 0x2d 0x1b 0x2e 0x01 0x2d 0x1b 0x29 0x2b 0x2c 0x1c 0x32 0x1e"
a.split.zip(b.split).map{|ab|(ab[0].to_i(16)+ab[1].to_i(16)).chr}.join

bca-store

やるだけ。すごく雑なコードが残っていたので一応貼る。

ans = []
7.times do
  cnta,cntb,cntc,cntd=0,0,0,0
  s=gets.split
  yen=s.pop.to_i
  tmp=0.0
  s.each do |t|
    if t=='A'
      cnta+=1
      tmp+=45
    elsif t=='B'
      cntb+=1
      tmp += cntb%2==0 ? 52*0.9 : 52
    elsif t=='C'
      cntc+=1
      tmp+=cntc%2==0 ? 67*0.5 : 67
    else
      cntd+=1
      tmp+=75 if cntd%3!=0
    end
  end
  if(yen-tmp>=0)
    ans<<format("%.2f",yen-tmp)
  else
    ans<< -1
  end
end
puts ans.join(" ")

instructions

やるだけ。コードはこんな感じになった。

nums = gets.split.map(&:to_i)

i=0
while true
  line=gets.chomp
  next if line.length%3!=0
  next if line.include?("&")

  print(line[nums[i]-1])
  i+=1
  break if i>=nums.length
end

public-library

Javaのclassファイルが渡される。インターフェースを作成して実行したりするのが本線っぽいけれど、stringsで覗けばそれで解けてしまう。

manner-of-thpeaking

LISPの構文らしい。aの数が要素の番号を表しているっぽい。最初がbcactfであることからメタ読みして、コードに落とすと以下のようになった。

printables = [[*' '..'/'],[*'0'..'9'],[*':'..'@'],[*'A'..'Z'],[*'['..'`'],[*'a'..'z'],[*'{'..'~']]
instructions = "cadadddddr, caddadddddr, caadddddr, caddadddddr, cadddddddddddddddddddadddddr, cadddddadddddr, caaddddddr, cadddddddddddadddr, cadadr, cadddddadr, cadddddddadr, caddddaddddr, caddddddddadr, caddddadr, cadddddadr, cadddadr, cadddadddddr, caddddaddddr, cadddddddddddddddadddddr, cadddddddddddddddddadddr, caadr, caddddddadddddr, cadddddddddddddddddadddr, caddddadr, caddddddddddddadddr, caddddddddddddadddddr, cadadr, cadddddddddddddadddddr, caddddddadddr, caddddaddddr, cadadr, cadddddadr, caddddaddddr, caddddadr, caddddddddddddddddddddddadddddr, cadddadr, caddddddddddddddddddadddr, caadr, caddddddddddddadddr, caddddadddddr, cadar, caddaddddddr"
instructions.split(", ").map{|s|printables[s.split("a")[2].length-1][s.split("a")[1].length]}.join

free-real-estate

意味がわからないけれど、Bを選んだら減点された。

copypasta

discardからflagを拾ってくる。

you-wanted-it

1を出力するコードを書けばいい。何となく雰囲気がpythonっぽかったので、3系の構文で書いたら通った。

def main():
    print(1)

main()

for-the-night-is-dark-1

bmp画像の各ピクセルのRの値を上から順に並べる。数字をasciiコードから逆変換するとURLになるので、アクセスするとflagが得られる。Rubyだとbitmapの操作が少し辛いのでこういう感じになった。(headerのバイト数は適当です)

str = File.open("starmap.bmp") do |f|
  f.seek(120)
  f.read.unpack('H*')
end
str[0].split(/0+/).reverse.map{|hex| (hex.length==1 ? hex+'0' : hex).to_i(16).chr}.join[0..-2]

for-the-night-is-dark-2

1で得られるURLにアクセスする。JSのフォームがぽつんとあり、ソースコードは以下。

$("#target").submit(function( event ) {
  var hash = md5($("#secret").val())
  if (hash == "3758002ab24653af8d550c0c50473098") {
    var encode = "ÐßϽ榠ÐÞÙ֩û¤× ÃºªîÈ©¼×ÐÖËÕ§£¢Íç«ÖÉ̱ÈÕÒßÊÕÅ"
    var newstr = ""
    var key = $("#secret").val()
    for (var i = 0; i < encode.length; i++) {
        newstr += String.fromCharCode(encode.charCodeAt(i) - key.charCodeAt(i%key.length))
    }
    window.location = "/f" + newstr
  }

  $("#secret").val("")
  event.preventDefault();
});

MD5ハッシュ値3758002ab24653af8d550c0c50473098になるものを適当に検索するとdarknightが出てくるので入力する。

for-the-night-is-dark-3

2をクリアした後のページの英語を読むと、そのページにflagがあって、現在は削除されていることが書かれている。webarchiveで探すとflagが残ったバージョンのサイトが見つかる。

basic-pass-1

stringsで覗けばflagが丸見えだった。

scratch-that

これ好き。以下のように書き換える。

f:id:betit0919:20190616182757p:plain

basic-pass-2

stringsで覗けばflagが丸見えだった。

basic-pass-3

パスワードが合っている部分にはビットが立つ。1文字ずつ総当たりするスクリプトを書く。

require 'socket'

def main
  sockin = TCPSocket.open('challenges.ctfd.io', '30133')
  sockout = sockin

  response = sockin.gets
  ans="bcactf{"
  while true do
    (33..200).each do |t|
      sockin.write("#{ans+(t.chr)}\n")
      response1 = sockin.gets
      response2 = sockin.gets
      if response2[ans.length]=='1'
        ans+=t.chr
        break
      end
    end
    puts ans
  end
end

main if $PROGRAM_NAME == __FILE__

f:id:betit0919:20190616184217p:plain

この待ってる時間好き。

the-inspector

検証ツールで探すとflagがある。

wite-out

ドラッグするとflagが隠れているとわかる。

dig-dug

与えられたhostのTXTレコードを見る。

dig -t txt hole.sketchy.dev

cookie-clicker

クッキーを書き換えてflagを購入する。

おわりに

お疲れ様でした!(最後の方の解説が雑になってごめんなさい)
公式でも解答を出すそうなので、解けなかった問題はしっかり復習します。