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