Skip to content

Commit 7625ede

Browse files
author
Matěj Smyčka
committed
Merge branch 'master' into 'publish'
Daubner writeups See merge request csirt-mu-mgmt/threat-management/writeups!6
2 parents 825b0bf + 83226fa commit 7625ede

69 files changed

Lines changed: 11579 additions & 19 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
authors:
3+
- Lukas Daubner
4+
date: 16-01-2024
5+
---
6+
7+
# Crypto - RLotto
8+
9+
After accessing the app using browser, you can see a lot of gibberish. So, let's try it in telnet. `telnet 167.99.82.136 30363` And it's way better.
10+
11+
Apparently, the goal is to gues the next 5 random numbers, given the 5 previous random numbers. OK, let's check the code. I am specifically looking how the random works and how it is seeded.
12+
13+
* The random is simple `import random`
14+
* It is initialised with seed `random.seed(seed)`
15+
* The seed is time `seed = int(time.time())`
16+
17+
## Experiments
18+
19+
According to the docs the used time function is just seconds from epoch https://docs.python.org/3/library/time.html#time.time So, let's run the following few times and see how it is changing.
20+
21+
```
22+
python3 -c "import time; print(int(time.time()))"
23+
```
24+
25+
And it is really seconds.
26+
27+
For the second experiment, let's run the app in localhost. When started, it creates a new seed, and prints the expected solution. Like this:
28+
29+
```
30+
[+] EXTRACTION: 12 90 31 79 20
31+
[+] SOLUTION: 35 58 89 51 38
32+
```
33+
34+
But the important part that a **new seed** is generated. According to the time.
35+
36+
Thus, if we could know the seed, we can simulate the pseudorandom generation on localhost. It would give us the solution we need. Only if we could...
37+
38+
## Matching the seed
39+
40+
We actually can. By running
41+
42+
```
43+
python3 -c "import time; print(int(time.time()))"; telnet 167.99.82.136 30363
44+
```
45+
46+
We get the time (the seed), -/+ off-by-one miss, if the timing is bad.
47+
48+
Anyway, we run the command. Supplement the seed to the code and run it on localhost. Compare the first 5 numbers. If they do not match, we run it again. If they match, we write the solution and get the flag.
49+
50+
```
51+
# Seed: 1705075719
52+
# Localhost
53+
[+] EXTRACTION: 12 90 31 79 20
54+
[+] SOLUTION: 35 58 89 51 38
55+
# Remote
56+
[+] EXTRACTION: 12 90 31 79 20
57+
[?] Guess the next extraction!!!
58+
[?] Put here the next 5 numbers: 35 58 89 51 38
59+
Good Job!
60+
HTB{........}
61+
```
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
authors:
3+
- Lukas Daubner
4+
date: 16-01-2024
5+
---
6+
7+
# Crypto - The Last Dance
8+
9+
This challange was for the stream cyphers.
10+
11+
In the `soruce.py` there are multiple points to look for:
12+
13+
14+
1. ChaCha20 is used for encryption
15+
2. key is reused
16+
3. IV (nonce) is reused
17+
18+
Since ChaCha20 is a stream cypher based on XOR, this gives a rather straighhtforward hits what to do. The key is in this equation: `ciphertext1 XOR ciphertext2 = plaintext1 XOR plaintext2` See https://cryptosmith.com/2008/05/31/stream-reuse/ for details
19+
20+
And in fact you got two cyphertext (message and flag) and one plaintext (message).
21+
22+
So, you have to try one-by-one, comparing the equation.
23+
24+
```
25+
c1 = bytes.fromhex("7aa34395a258f5893e3db1822139b8c1f04cfab9d757b9b9cca57e1df33d093f07c7f06e06bb6293676f9060a838ea138b6bc9")
26+
c2 = bytes.fromhex("7d8273ceb459e4d4386df4e32e1aecc1aa7aaafda50cb982f6c62623cf6b29693d86b15457aa76ac7e2eef6cf814ae3a8d39c7")
27+
28+
# Just the part of a message for a length
29+
p1 = b"Our counter agencies have intercepted your messages"
30+
31+
def byte_xor(x1 , x2):
32+
return bytes(a ^ b for a, b in zip(x1, x2))
33+
34+
p2 = b""
35+
36+
for i in range(1,len(c2)+1):
37+
# Compute the pattern for processed range
38+
pattern = byte_xor(c1[:i], c2[:i])
39+
# Loop the relevant ascii codes
40+
for ch in range(32, 127):
41+
current = ch.to_bytes()
42+
test_pattern = byte_xor(p1[:i], p2+current)
43+
if pattern == test_pattern:
44+
# Match found, saving byte and moving on...
45+
p2 = p2+current
46+
break
47+
48+
print(p2)
49+
```
50+
51+
And thats it
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
authors:
3+
- Lukas Daubner
4+
date: 16-01-2024
5+
---
6+
7+
# Misc - Canvas
8+
9+
The source code contains obfuscated javascript
10+
11+
We can use online tool to deopfuscate it (e.g., https://deobfuscate.io/)
12+
13+
But that will still give us bunch of gibberish. But if we look closely, the flag is right there! `var res = String.fromCharCode(72, 84, 66, 123, 87, 51, 76, 99, 48, 109, 51, 95, 55, 48, 95, 74, 52, 86, 52, 53, 67, 82, 49, 112, 55, 95, 100, 51, 48, 98, 70, 117, 53, 67, 52, 55, 49, 48, 78, 125, 10);`
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
---
2+
authors:
3+
- Lukas Daubner
4+
date: 16-01-2024
5+
---
6+
7+
# Misc - Deterministic
8+
9+
The challange is presented with a text file containing 3-tuples, and a note saying some important details.
10+
11+
* State 0: 69420
12+
* State N: 999
13+
* Flag ends at state N
14+
* Each character of the password is XORed with a very super secret key
15+
16+
## 3-tuples
17+
18+
So now you must figure out what does the 3-tuples mean. You can notice form the "fake" flag that it is always a number, followed by a label, followed by another number. Then the next line is the same as the 3rd number from previous line.
19+
20+
So maybe the 3rd number is a reference to the next one.
21+
22+
You can test out the hypothesis using the known numbers (69420 and 999)
23+
24+
* Really, you can follow the numbers
25+
* There is no line with "69420" as 3rd number
26+
* There is no line with "999" as 1st number
27+
* The lines repeat a lot, but it seems that the refrences are deterministic (lol)
28+
29+
So, this all looks like an Automata (which hints towards the "Deterministic" name) Let's name the tuple (state, value, next).
30+
31+
Now about the password...
32+
33+
## Values
34+
35+
Now you know that the 2nd number is a value. But it is XORed somehow, so it is gibberish. However, you know something extra:
36+
37+
* The last value (20) XOR key is "}" (125).
38+
* The key is reused for all characters (one-time pad fail)
39+
40+
That allows to reverse the XOR operation to determine the key https://cyberchef.org/#recipe=XOR(%7B'option':'Binary','string':'01101001'%7D,'Standard',false)To_Decimal('Space',false)&input=fQ
41+
42+
So key is: 01101001 (binary) You can try it out on other values if it produces something that makes sense. Especially, locate "HTB{". And it is there! "H" starts at state "0".
43+
44+
## Putting it all together
45+
46+
```
47+
from dataclasses import dataclass
48+
49+
@dataclass
50+
class StateData:
51+
value: int
52+
next : int
53+
state : int
54+
55+
states = {}
56+
# Fill the sctruct
57+
with open("deterministic.txt") as input:
58+
# The lines with text
59+
next(input)
60+
next(input)
61+
for line in input:
62+
split = line.split()
63+
# Filter out the fake flag
64+
if split[1].isnumeric():
65+
state = int(split[0])
66+
value = int(split[1])
67+
next = int(split[2])
68+
# Filter out duplicities
69+
# I need to go from the end (to avoid cycles)
70+
if next not in states.keys():
71+
states[next] = StateData(value, next, state)
72+
73+
result = []
74+
key = 0b01101001
75+
# Traverse states from the back
76+
# State "N-1"
77+
next = 999
78+
# Until state which I know that got value "H"
79+
while next != 0:
80+
state = states[next]
81+
decrypted = chr(state.value ^ key)
82+
result.append(decrypted)
83+
next = state.state
84+
85+
result.reverse()
86+
print(*result, sep="")
87+
```
88+
89+
And there is the flag!
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
authors:
3+
- Lukas Daubner
4+
date: 16-01-2024
5+
---
6+
7+
# Misc - Man in the middle
8+
9+
First by simply reading the data we can see the textual header teling us that this is a `btsnoop` file. That can be analysed using `btmon` or `Wireshark`. While the prior can give some statistical information, we need to use Wireshark.
10+
11+
Now the hard part is to figure out what are the packets sayng. We try to decode them using different **bluetoth device profiles** and look closely if there is a mathch. It matches on a MOUSE and KEYBOARD. The packets are mouse movements and key events (shorter packets). The longer packets are the keyboardevents.
12+
13+
If we mimic the keyboard (key presses, shift presses, etc), we get the flag.

0 commit comments

Comments
 (0)