---
# System prepended metadata

title: BSIDES TRANSILVANIA WRITEUP

---

# UVT-CTF @ Bsides Transilvania

# Postmortem
Am mers cu autobuzul

# The Conference
Nu au dat tricouri

# CTF
Fu Okay

## Writeup1 (Tania & Mark)
| title: HashBreaker (I think) | category: Crypto | 275 points | 3 solves | difficulty: medium(?) |

### Introduction
We are provided by the challenge 2 things:
* a hash: "1a061d36422e5a08190009ddfd34d74d603f2f7c384a08b3521c08130d171dcf",
* and the function used to obtain it:
```python
def ultrabrend(message):
    if len(message) < 29:
        message = ((message + " ") * 29)[:29]

    digest = [0]*32

    for i in range(len(message)):
        digest[i % 29] ^= ord(message[i])

    t = digest[0] * digest[28]

    for i in range(28):
        digest[i] = (digest[i] + digest[i+1]) % 256

    digest[28] = t // 256
    digest[29] = t % 256
    digest[30] = 0xff ^ len(message)
    digest = digest[16:] + digest[:16]

    for i in range(32):
        digest[i] ^= digest[(i+1) % 32] ^ i

    return "".join(["{:02x}".format(i) for i in digest])


string = input("Enter a message: ")
print("Hash:", ultrabrend(string))
```
Our goal is to obtain the initial message by reversing the hashing function. 

### First things first, the ending

This is the last operation made on digest[ ], the list returned as hex:
```python
for i in range(32):
    digest[i] ^= digest[(i+1) % 32] ^ i
```

For the theoretical part, let $final[ ]$ be the list we've got, and $initial[ ]$ be the list before being processed by this step.

Now, to break it down:
$final[0] = initial[0] \oplus initial[1] \oplus 0,$
$final[1] = initial[1] \oplus initial[2] \oplus 1,$
$...$
$final[30] = initial[30] \oplus initial[31] \oplus 30$

and for 31, `(i+1) % 32` will take us back to index 0, which has been modified already:
$final[31] = initial[31] \oplus final[0] \oplus 31.$

From here, initial[31] becomes known,
$initial[31] = final[31] \oplus final[0] \oplus 31$

and can be used to find the entire initial list:
$initial[30] = initial[31] \oplus final[30] \oplus 30,$
$...$
$initial[0] = initial[1] \oplus final[0] \oplus 31.$

Now that we understand what it does, we can reverse it:
```python
digest[31] = digest[31] ^ digest[0] ^ 31

for i in range(30, -1, -1):
    digest[i] = digest[i] ^ digest[i + 1] ^ i
```

### Accessories

The next line (bottom-up) performs something like cutting the deck in cards and can easely be undone by repeating the process.
```python
digest = digest[16:] + digest[:16]
```
The "accessories" we receive next are the length of the message and t (because $t = q \cdot 256 + r$, where `q = t//  256` and `r = t % 256`).

```
digest[28] = t // 256
digest[29] = t % 256
digest[30] = 0xff ^ len(message)
```
To find the length, xor again: ```len = digest[30] ^ 255```.

Our new knowns are $t$, $length$ and $final$ (the new final, the current one, before being processed at the step presented above). Remember *length*, it will come in handy later ;).

### A little more math


```
for i in range(28):
    digest[i] = (digest[i] + digest[i+1]) % 256
```

This (+accessories) modifies the digest:


| list | 0 | 1 | ... | 27 | 28 | 29 | 30 | 31 |
| -------- | -------- | -------- | -------- | -------- | -------- |  -------- | -------- |-------- |
| **final** | $x_0+x_1$ | $x_1+x_2$ |  | $x_{27}+x_{28}$ | `t // 256` | `t % 256` | length | 0 |
| **initial** | $x_0$ | $x_1$ |  | $x_{27}$ | $x_{28}$ | 0 | 0 |0 |

Now we can reconstruct $t$ as `final[28] * 256 + final[29]`. This variable was initialized before this for, using the *initial digest*:

`t = digest[0] * digest[28]`,

so we know that $t = x_0 \cdot x_{28}$.

To find a second equation using $x_0$ and $x_{28}$, we use final[ ]:
$final[27] = x_{27} + x_{28}$
$final[26] = x_{26} + x_{27}$
$----------$ $subtraction$
$final[27] -  final[26] = x_{28} - x_{26}$


$final[27] -  final[26] = x_{28} - x_{26}$
$final[25] = x_{25} + x_{26}$
$----------$ $addition$
$final[27] -  final[26] + final[25] = x_{28} + x_{25}$

$...$

By subtracting and adding repeatedly, we should obtain  $x_{28} - x_0 = (result)$, therefore $x_{28}$ with regards to $x_0$:
$x_{28} = (result) + x_0$,
replace $x_{28}$ in our first equation,
$t = x_0 \cdot ((result) + x_0)$
and obtain a quadratic equation:
$x_0^2 + x_0(result) - t = 0$.

Here on out, the job is simple, as $x_0$ will probably take a positive value (take a peak above and notice it's just xor'ed ASCII from the message). From $x_0$ and $final[0] = x_0 + x_1$ we find $x_1$ and repeat for all $x_i$.

### Lastly, the beginning

For the last step, there is a message formatting:
```
if len(message) < 29:
    message = ((message + " ") * 29)[:29]
```
which transforms the message to be *at least* of length 29, and then the XOR overlay.
```
digest = [0]*32

for i in range(len(message)):
    digest[i % 29] ^= ord(message[i])
```
The digest (initialized with 0) gets xor'ed with the first 29 characters from the message. Since a ^ 0 = a, this is equivalent to initializing digest with message[ :29] in ASCII.
Afterwards, the digest index moves back to 0 and it continues to xor it with the rest of the message.

| digest | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... | 26 | 27 | 28 |
| -------- | -------- | -------- | -------- | -------- | -------- |  -------- | -------- |-------- | -------- | -------- |-------- | -------- | -------- |-------- |
|  | m | e | s | s | a | g | e | _ | m | e | ... | e | s |  s |
|  | a | g | e |  |  |  |  |  |  |  |  | |  |

It would be impossible to deduce two random characters which xor'ed are equal to digest[i] and also make sense in the message.
However, since the message should be the flag, we can safely presume it starts with "**MetaCTF{**". And because ```a ^ b = c <=> a = c ^ b```, we can check this presumption by xoring digest[ :8] with "MetaCTF{". 

The result was "**ashabyss**", so totally not a coincidence :).

Remember *length*?

Length was smaller than $2 \cdot 29$, which means there are *some* letters at the end of digest which were not xored, and $len - 29$ tells us exactly *where* the raw piece starts.

Here we got "**lags_deep_int0_the_h**", which matches "**ashabyss**" perfectly. As a cherry on top, "f" from "flags" and "}" xor'ed give digest[8], confirming the flag:

```MetaCTF{flags_deep_int0_the_hashabyss}```


**** 

# Writeup2 (Paul)

### Title: smartexfil 
### Category: forensics 
### Points: 375 points 
### Solves: 2
### Difficulty: hard 
### Flag: `MetaCTF{bright_blinking_bulb_breaches}`

## Introduction

We are given a pcap and a elf executable binary `logs.pcap` and `nothing_to_see_here`

![image](https://hackmd.io/_uploads/ry_MAB7JR.png)

Opening `logs.pcap` in wireshark, we see a lot of traffic: `dns, http, tcp, ping`

![image](https://hackmd.io/_uploads/ryZ7JI710.png)

So, we thought that maybe the exfiltration happend using the dns requests, there are multiple tehniques: 

- using subdomains to exfiltrate small ammount of data with each dns request
- time based, ascii could be exfiltrated by noticing the time difference between the requests
- using checksum (it will be shown as unverified)

but none of these gave us anything useful.
Finally we notice a custom protocol, made for iot devices like light bulbs:

![image](https://hackmd.io/_uploads/S1jGeUmJ0.png)

we can see that the requests info contain the commands sent to the light bulb

![image](https://hackmd.io/_uploads/H1zueI7J0.png)

we used tshark to get the message informations from the packets, here the brightness field caught my eye because it was either 0 or 100, no other value in between

![image](https://hackmd.io/_uploads/BJCzbUQyC.png)

got all these values using tshark:

```bash
tshark -r logs.pcap -Y "tcp.dstport == 9999"  -T fields -e tplink_smarthome.msg | awk -F " " '{print $10}' | tr -d ","
```


```
-Y <display filter> : Apply a display filter.
-T <format>         : Set the format of the output when viewing decoded packet data. Common formats include `text`, `json`, `psml`, etc.
fields              : This option allows you to specify which fields of the packet you want to display. It's often used with `-e` to extract specific fields.
-e <field>          : Specify a field to print. Used with `-T fields` to extract specific fields from the packet data.


awk -F " "    -> we specify that space char is the delimiter, it will split the output into words
'{print $10}' -> we print the 10th element of the line, it means the 10th

tr -d ","     -> get rid of commas ','
```

after this , we got rid of the `00`, replaced them with nothing, then made it into a binary string

```
00101101001011010111010101101110011000010110110101100101001011010010110101111000100111001111001111001001110011000010101110101101010100001100100001001101001011010100100101001100110010101010111101010000001100001101001100110011110100100011001111010000001101010011011011010010010011010100111111001101010010110010110111001010010011000101011001010000001101100011011010101010001100110000001010001010100110011110100000011001111010101000011000100110100101011110011010010101100101000010101000000100111110110000011000101000000001000000010010111001101110101111101000000110100001001100010010111011010001001111101000111001111110100111101000111010001010111011100000010101011001010010101000111000100101101010011000101011000110000101101000101000000110000001101001011000100110010001100001011000000110010001101000101011100001001000011000111000001010110001100000101001010101000101100010011000110001011001101110011001101000000101000111101110011111101010000111111010001111100010000010001011101110010000000000111101100100110010001110001111001011010010110101100101011011010111000001101100011011110111100101100101011001010101111101100101011110000111000001101111011100100111010000101110011000110111001101110110001011010010110101111000100111000101010110010001110011010110111011011011001100000001000010000100111011110111100100001010110000101001011101011110100101101000001001001000111111011001000010111100110110010111010101100011101000001010110111011101000000101000100110000001000101101011110100001000001010111001100110010101100110000101000010100100010000011100100101110000111011011010001011101111010111100100101010111001010001000011011100001110000001111101100001101111011101101001011010100111101010010010100000000101001111001111011000111101110000100000000111000011011010001001110010111110100000111000111000101010111010011101011110011101111111101000001111010110100011000011101000110001000111101000011010001011000110111011101001101000010011101001011001010100111010110001101101110110110111100010011110001101111011111000000100101001010010010110010101001110110010110010110000010111101100000110001000111100001000110000011100111100010110110100110110011110010001110010000011001111111001110110000001011100111110111101101101101000011110110000001011110010011110010100111101001010001011101101001001111100000001010000111101000101110010010101100101100100011011101000001001000001111110001111111011100001010010010001101101101011011011111000000001010001001001010111111011000001011111001111101100001010101100111001111111110011011101011101101110100011101100010011001100110011111001110010100100010101001001011000110101110011001000100101001110010101000110010111100111010010101001111010101111110111001001111011001001110111100100011000101010001110111011000000001010111010110001100000110010001101000001111011001011011101000100001001010110110011001101000101101111000001010000011000111110111000001111011110111011111110110101101100000110110100110111010101100011010101110101101011100011010111100110001010111110101010001011111011011010101110111010101010000010110001111010011111010011110000111011110100000110110000010000101110011000011100101111100110000011110011001110100111100000000111000111111000001110111111001110100111100001111001010100110100100110111101000010001111100001010010010011110110011010001011101111010000111011101111000110100010100100110010010001101010010110100010101100100010110000100100101011001010010011001000110010010000111110110100111011100011001010010010101011010000100101000000001111101010000110110101001110000000000000111001111111100010010010100010111000000010100110001011011101011100100001000010101100010100110011000010101101101011001101011110110000110010111111010011110001110110100100111101001110100110100000100110100111011101110000010111110000001110011001011110010011010011011100011010010001101101001100101100111010101100100010101000010100100011010000000110100011110111010101110000010101100010100001110010110100000111100011110010110101111011100110001110001000111111011001100111000001001011001011011011100100110010110000101011010100110001111001111001010010100010101011001001001110000011110010001110010111011010010001111100011010110010111100110111111011010100000001001111001000100111000100001011100110001001101110101101011010101011011010100100011111001011111110100000001011001010100110010000100101000000100110010001010001110101111010010001010010111011001011110101001110001000110001101000111001111010101101101111010111001101001111111001100000001010110110001110110011111010111101000100101010010110001001011110111100100011111101011101101010001100001001110010
```

After decoding, we see that there's some text which are `uname` and `employee_export.csv`

![image](https://hackmd.io/_uploads/BJR0GUQkA.png)


At this step we were stuck at the ctf, didn't figure out that those are the commands, and the stuff after them the zlib flated contents.
We can save the output from binary as a file, and run binwalk on it:

![image](https://hackmd.io/_uploads/Bk6AmUQJA.png)
