Fun with Google Dorks

Google Dorks are a great way to uncover infomation semi-passively. Primarily, it involves special search queries that lead to information that shouldn't be public. In this blog post, I will showcase some useful queries and show the impact these queries have and provide some remediation steps.

Read more…

Fun with GUID's

Recently, Intigrity (https://twitter.com/intigriti) posted a challenge on Twitter. I found this challenge to be pretty interesting, as I had not really heard of any issues regarding GUIDs (Global Unique IDentifier), sometimes also listed as UUID (Universally unique identifier). These are all what I had previously assumed were essentially random and non-predictable. Unfortunately, some versions of the UUID are not so random, at least for UUIDv1.

/images/fun-with-guids/homepage.png

The rest of the post continues after the break.

Read more…

HackTheBox - Search

Introduction

Search is a retired HackTheBox machine which contains several common windows exploits. I completed this box a while ago, but it now that it has retired, I can post my writeup. Some of the tools used to complete this box are: crackmapexec, gmsadumper, bloodhound, smbclient, and rpcclient.

Read more…

Configuring custom headers for OWASP ZAP

I've been trying some bugbounty programs recently. I often alternate between using BurpSuite and ZAP. Many programs want you to add a custom header to your requests so the traffic can be identified, and in some cases, bypass some roadblocks. In this post, I'll show how to configure ZAP to add the custom header.

/images/zap-header/teaser.png

Read more…

Cyber Apocalypse 2022 - Space Pulses

This challenge was part of the hardware category, and was pretty interesting. Here is the challenge description:

One of our enhanced radio telescopes captured some weird fluctuations from a nearby star. It was idle for decades due to the fact that it was fully enclosed by a Dyson Sphere but its patterns began to change drastically leading us to believe that someone is controlling part of the megastructure to release energy and send these pulses directed to us in order to transmit a message. They must have known that our equipment can read even the slightest fluctuations.

There was a downloadable file, which was a saleae logic file. This definitely isn't something easy like serial. It seems like it might have some time dependent information encoded, because the pulse time is not consistent. I started to suspect this might be some sort of pulse width modulation encoding scheme.

/images/space_pulses/initial.png

First, I exported the signal from Logic2 as a CSV so I could work with it. I started by plotting the time each pulse was on vs off. I knew the time was in seconds, so the pulse times would be small.

iimport numpy as np
from matplotlib import pyplot as plt

sig = np.genfromtxt('sp_digital.txt', delimiter=',', skip_header=0)
values = np.diff(sig[:,0])*1000

plt.figure()
plt.plot(values[2:-1])
plt.savefig('signal_plot.png')
plt.close()

That produced the following output:

/images/space_pulses/signal_plot.png

That pretty much confirmed my suspicions that this was PWM. The time delta does not exceed 255 for any pulse, so that seems like it may be an ascii encoded string. Let's convert it.

rounded_values = np.round(values[::2])
floor_values = np.floor(values[::2])
ceil_values = int_values + 1

for v in [rounded_values, floor_values, ceil_values]:
    print(''.join([chr(int(x)) for x in v[1:]]))

I did not know whether my floating point values from the time delta should be rounded, floored, or ceiling-ed, so I did all 3. My script output the following:

Dppsejobuft!.!SB!2:i!69n!33t!}!Efd!,46+!23(!7((!.!Wbmjebujpo!tfdsfu!dpef;!IUC|qv2646`n1ev2582o:`2o`6q5d4"63&~
Coordinates - RA 19h 58m 22s | Dec +35* 12' 6'' - Validation secret code: HTB{pu1535_m0du1471n9_1n_5p4c3!52%}
Dppsejobuft!.!SB!2:i!69n!33t!}!Efd!,46+!23(!7((!.!Wbmjebujpo!tfdsfu!dpef;!IUC|qv2646`n1ev2582o:`2o`6q5d4"63&~

The only one that produced reasonable output was floor. The flag is in the last half of the message.

The full script is below:

import numpy as np
from matplotlib import pyplot as plt

sig = np.genfromtxt('sp_digital.txt', delimiter=',', skip_header=0)
values = np.diff(sig[:,0])*1000

plt.figure()
plt.plot(values[2:-1])
plt.savefig('signal_plot.png')
plt.close()

rounded_values = np.round(values[::2])
int_values = np.floor(values[::2])
ceil_values = int_values + 1

for v in [rounded_values, int_values, ceil_values]:
    print(''.join([chr(int(x)) for x in v[1:]]))

Cyber Apocalypse 2022 - Blinkerfluids

This was the first web challenge I solved in the Cyber Apocalypse 2022 CTF. This challenge had a downloadable portion with a fake flag as well as a web instance with an actual flag. Since the CTF has been over for a while and I didn't capture any of the actual challenge, I am recreating the steps I took here using the docker container.

Read more…

Dumping chrome passwords using pypykatz

I recently competed in the Cyber Apocalypse 2022 CTF on Hackthebox. This was a really fun experience (and my first ever live CTF). I only solved a few challenges (which I'll be writing in subsequent posts), but there was one vexating challenge which I wasn't able to complete. I kinda had the right idea, but I was missing some key pieces of information. The point of this post is to explain what I was missing and how it works (and to document how I would have done it).

This particular challenge was called "Siezed"

The challenge description read

Miyuki is now after a newly formed ransomware division which works for Longhir. This division's goal is to target any critical infrastructure and cause financial losses to their opponents. They never restore the encrypted files, even if the victim pays the ransom. This case is the number one priority for the team at the moment. Miyuki has seized the hard-drive of one of the members and it is believed that inside of which there may be credentials for the Ransomware's Dashboard. Given the AppData folder, can you retrieve the wanted credentials?

A zip file was provided which contained the full AppData from a windows user. Based on the description, I felt like all I needed to do was search for and extract the browser's saved passwords.

Read more…

XSS and SSTI in Flask

Introduction

According to the project's home page,

Flask is a lightweight WSGI web application framework. It is designed to make getting started quick and easy, with the ability to scale up to complex applications. It began as a simple wrapper around Werkzeug and Jinja and has become one of the most popular Python web application frameworks.

Django sits at the other end of the python web service spectrum. Each has their own advantages and disadvantages. If I had to pick a downside for Flask, it is that can be easy to introduce unintentional vulnerabilities. This is not a problem with Flask itself, but is a result of improper sanitizing of user input.

This blog post will explore two vulnerabilities in an intentionally vulnerable flask app.

Read more…

Confusing script kiddies with random default server pages

Anyone who runs a server connected to the internet can tell you that they get hammered all day every day by bots. Sometimes, a human is poking at things looking for vulnerable applications. Quite a while ago, I created a simple php script to randomly pretend to be one of the 3 web servers (Apache, Nginx, IIS).

Due to copyright, I am not sharing the source code from the html page for IIS. They are pretty easy to find without downloading/installing the package. The NGINX source is available on Github I tried to find the one served by Apache2, but could not find the page I wanted. Fortunately, it happened to be available on one of my other servers so I just copied it over from there.

The php script is included below:

Zip Slip (malicious archives)

Recently, I completed a CTF challenge that involved an interesting vulnerability. Since the challenge is active, I won't be providing screenshots, but I've kept things general enough that it shouldn't spoil anything.

The web app

The entire app was provided with a dockerfile, so it could be run offline.

My first step was to investigate the app and see what vulnerabilities might exist. The web app is very simple, and was developed using Flask. It contains a single web page that allows you to upload a tar.gz file. The uploaded file is extracted using the tarfile library. The validation of user uploaded file is insufficient.

First, the file is checked to see if it is indeed a tarfile, with a call to tarfile.is_tarfile(). If this is true, then tarfile.extract_all() is called. There is a warning about this function in the docs.

Warning

Never extract archives from untrusted sources without prior inspection. It is possible that files are created outside of path, e.g. members that have absolute filenames starting with "/" or filenames with two dots "..".

The vulnerability

Some further research reveals that this is quite an old vulnerability. The tar program was discovered to be vulnerable all the way back in 2001, CVE-2001-1267 The core issue is that tar did not validate filenames, so if the archive contained a file named ../../../../etc/passwd, when extracted it would overwrite /etc/passwd by traversing the ../ directives as long the user invoking tar had the appropriate permissions)

The python tarfile module apparently shares a great deal of similar code, because the same issue was identified in the python module in 2007 (6 years after the original tar vulnerability). This was discussed on the python-dev email list https://mail.python.org/pipermail/python-dev/2007-August/074290.html It was again discussed in 2014, https://bugs.python.org/issue21109 Now, 20 years later, there still isn't a resolution.

In the general sense, I see two potential ways of exploiting a vulnerability like this. In modern linux environments, /etc/passwd no longer contains sensitive information like password hashes, so overwriting that file won't allow access to the machine. One potential attack would be to overwrite the users ~/.ssh/authorized_keys file to include your own key. Of course, for that to be exploitable, you would already need access to the file system.

Since python is now popular for developing web apps through Django and Flask, this opens up a new avenue: uploading a malicious archive to overwrite or create files.

Back to the challenge, since the app is flask, it is possible to overwrite the main app handler.

The original file is quite simple

from application.main import app
app.run(host='0.0.0.0', port=1337, debug=True, use_evalex=False)

and the modified code:

from application.main import app
import shutil
import os
try:
    path = '/app/application/static/'
    shutil.copy('flag', os.path.join(path, 'flag'))
    out = subprocess.check_output('id')
    with open(os.path.join(path, 'logfile.txt'), 'w') as f:
        f.write(msg)
except:
    pass
app.run(host='0.0.0.0', port=1337, debug=True, use_evalex=False)

This simply copies the flag from it's location within the app folder to the static files that are served by flask. This could be modified to do the same thing for multiple files, or initiate a reverse shell.

The exploit

I found a tool that had already been created to craft the malicious archive.

https://github.com/ptoomey3/evilarc

That script uses the same vulnerable library to craft the archive. This also appears to work on zip archives as well, but that's something for another time.

Simply running the script python evilarc.py run.py -f evil.tar.gz -o unix -p /app generates the archive.

  • evil.tar.gz is the file that is created

  • run.py is the modified file from earlier

  • -p /app specifies the directory where run.py will be overwritten after traversal

Uploading the resulting file in a browser and then doing curl http://localhost:1337/static/flag outputs the flag.

Further, curl http://localhost:1337/static/logfile.txt reveals this app is running as root 'uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)

Impact

This is a pretty severe vulnerability as it allows full remote code execution. In this particular instance, the flask app is run as root, and directly runs the app.py file in debug mode.

Remediation

The most severe problem with this app is that the contents of the uploaded file are trusted implicitly. To fix this, the user-supplied archive should not be blindly extracted. There currently isn't a fixed version of the tarfile module, so until that is fixed upstream, some crude checks might provide some protection. Ex: refusing to extract files that start with .. The flask app shouldn't be run with debug mode turned on in a production environment. The flask app also shouldn't be running as root.

I'm not sure how applicable this is to real world websites, as this example relies on supervisord detecting the overwritten /app/run.py file and reloading. Having never deployed a flask app to production myself, my understanding is that something like gnuicorn would only do that if debug settings were explicitly enabled. https://docs.gunicorn.org/en/stable/settings.html#debugging

Closing

This was a really fun challenge (and writing this took much longer than getting the flag). It is really interesting that this bug still exists 20 years after first identified in tar. The spread of python based web apps due to the popularity of Django and flask has brought old vulnerabilities that previously required local file system access can now be leveraged to remotely execute code.