From 3bf2f94b0dfaf41858985c033aca13bcd683123a Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Mon, 21 Oct 2019 19:40:16 +0200 Subject: [PATCH] Add seccon19 writeup (theguy) --- writeups/theguy/seccon19.md | 81 +++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 writeups/theguy/seccon19.md diff --git a/writeups/theguy/seccon19.md b/writeups/theguy/seccon19.md new file mode 100644 index 0000000..d3cc2ae --- /dev/null +++ b/writeups/theguy/seccon19.md @@ -0,0 +1,81 @@ +# SECCON 2019 + +## Conclusion +Sadly I could only participate a few hours on saturday, but the challenges were fun to work on. I didn't really have time to dig into any challenge quite deep. But the writeups that were published afterwards are interesting and I learnt some new things from them like JSONP and some stuff about Shell Globbing. + +## Challenges I worked on + +### Option-Cmd-U + +The intended purpose of the site is to show the source code of the websites you input. The URLs have to start with `http`. + +First thing was of course a bit of information gathering. +The server runs PHP version 7.2.0 (X-Powered-By header field from the response). +The source code hinted towards the source code at `/index.php?action=source` and pointed out that the flag is located at `flag.php` and that the server is running *php-fm* and *nginx* and where the *docker-compose* file is located. + +So I downloaded the source code and the *docker-compose.yml* file. + +The source code shows that the `url` GET-parameter is filtered using the PHP function `filter_input` given no parameter. The documentation says that the default behaviour is to do nothing. So the function call is useless and can be ignored. + +The url then gets parsed using `parse_url` which splits the url into its different parts. It returns an associative array with `scheme`, `host`, `path`, `port` and so on. + +Then the `scheme` is checked to be `http`. + +After that it is checked that the hostname of the url is not equal to `gethostbyname('nginx')`. If it wasn't then there was a call to `file_get_contents` and the url was read and displayed on the webpage. + +The check for `nginx` was kinda strange and I thought it might be part of the challenge or just part of some strange edge case. Either way I first tried to see if just using the same domain as used by the challenge worked, but it just returned `Forbidden. Your IP: 172.25.0.1`. So I tried `http://172.25.0.1:10000/flag.php` but that yielded the same result. + +So it seemed to really only worked if url was pointing to a local target. + +So I tried: `http://127.0.0.1:10000/flag.php` but that just resulted in nothing. +So I set up the PHP code on my local system. + +I tried `http://127.0.0.1:10000/flag.php` and noticed that the problem was the function `file_get_contents` timing out. To verify that I removed the `timeout` parameter and then it took it 30 seconds instead of 2 to abort. + +I still don't know why, but I've read something about php file opening functions trying to see a given path/url are local files and then instead of opening them like usual do something weird. I guess that's the reason, but I'm not entirely sure. + +Then I found a presentation of Orange Tsai called "A New Era of SSRF". It was about problems in URL parsers and filter bypassing. +One such idea was to use a DNS A record entry that points to 127.0.0.1 to bypass filters for `localhost` and `127.0.0.1`. + +So I set up an DNS entry on my own domain (and @lavish gladly did the same on his domain). But that didn't work either. + +After that I was kinda stuck and wandered off to another challenge. + +### Web Search + +The website consisted of only one input field and a submit button. +The requests are sent to the path `/` using a GET request. The query is sent using the `q` parameter. +The site can be used to search for RFCs. + +The first thing I've tried of course is a SQL injection. +Basics first: `' or 1=1--` -> Error and the query in the input field got modified. +The query was modified to `'1=1--`. So I immediately thought of sanitization and luckily for use they showed you the query after it got sanitized. You could bypass the filtering of `or` or any other potentially filtered keyword by just putting another `or` into the word, like `OorR`. +The space filtering can be easily bypassed using `/**/` (thanks Introsec UE ;) ) (From this point on I will only write the queries without the sanitization bypassing to better show what the intention was). + +The next thing I tried is bypassing the sanitization with `' or 1=1--` -> still Error, so I tried `' or 1=1#` instead. That worked! + +When scrolling down you could see +``` +FLAG + The flag is "SECCON{Yeah_Sqli_Success_" ... well, the rest of flag is in "flag" table. Try more! +``` +So the next thing I thought was to use Blind SQLi, so I tried to find out if the table actually existed using `' or exists(select * from flag limit 1)` -> Worked! +So the table actually exists and it is not just trying to throw you off. + +Next thing is to check if the information schema tables are available and readable. +The query I used for that was `' or exists(select * from information_schema.table where table_name='flag')#` (here `information_schema` would also be written as `infoorrmation_schema`). Luckily `'`s where not filtered, else you could have used MySQL hex notation for strings. (Not that bad, but a bit more annoying). + +Next step I would have done is finding the column name (which is not needed in hindsight, but that's what I thought to do) using `' or (select substr(column_name from {place} for 1) from information_schema.columns where table_name='flag')='{guess}'#`. + +After finding the column I would have extracted the value of the column using `' of (select substr({column_name} from {place} for 1) from flag)='{guess}'#`. But I didn't even get to this point, since I had to leave. + +So I also don't have an exploit script. What it was essentially like the challenge from IntroSec UE course. + +### Fileserver +I also very briefly looked over this challenge. + +I found the source code and I found the possibilty to do a bit of path traversal by just removing the `/public/index.html` part of the url. But since I'm not really at all comfortable in *Ruby* I didn't find anything useful. + +I looked for *Ruby* or *webrick* CVEs and found some, but none that would help here. + +I just noticed that you would have to either have a full path traversal bug or to pop a shell, since the flag is stored in a tmp file with a random name. \ No newline at end of file -- 2.43.0