Seccon 2019 - fileserver

   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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

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

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

Read Flag

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

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