Tags: morse python statistics 

Rating:

# Noisy
1. Intro
2. Understand the script
3. Get the flag

## Intro
![](https://imgur.com/Dwk2KCD.png)

28800 lines with random floats.

*Nice*

## Understanding the script

```python
import numpy as np
from random import gauss
morse = REDACTED
repeats = REDACTED
pointed = []
for c in morse:
if c == ".":
pointed.extend([1 for x in range(10)])
if c == "-":
pointed.extend([1 for x in range(20)])
if c == " ":
pointed.extend([0 for x in range(20)])
pointed.extend([0 for x in range(10)])

with open("points.txt", "w") as f:
for _ in range(repeats):
signal = pointed
output = []
for x, bit in enumerate(signal):
output.append(bit + gauss(0,2))

signal = list(np.array(output) - .5)
f.write('\n'.join([str(x) for x in signal])+"\n")
f.close()
```

There is 2 things we don't know here : morse, which is the flag, and repeats, the number of times the flag is repeated.

The first ```for``` is used to translate the morse code into 0 and 1.
We can see after each character, ten 0 are printed.

For example, ```".-"``` -> 11111111110000000000111111111111111111110000000000

The entire message is stored in ```pointed```.

```
with open("points.txt", "w") as f:
```
open the file to write the message inside, with a ```for``` loop to repeat the message [repeats] times.

```python
for x, bit in enumerate(signal):
output.append(bit + gauss(0,2))

signal = list(np.array(output) - .5)
f.write('\n'.join([str(x) for x in signal])+"\n")
```

This block of code a every bit of pointed in the file, adding to it ```gauss(0, 2)```.

Gauss is a function which return a random number chosen like this :

![](https://imgur.com/9VqacO7.png)

with here μ = 0 and σ = 2

Finally, we can see here ```signal = list(np.array(output) - .5)``` that we substract 0.5 to this number.

I don't really know the reason, except to make me lose 30min... :cry:

### Recap :

- As the message is random-based, we need to do an average to get the real character, this is why there is 10 character each time and why we repeat the message
- We have to find either the length of the message or the number of repetition.

## Get the flag
First we have to find the possible sizes for the flag. It can be easily done with this python script :
```
possibleSize = []
a = 0
for i in range(1, 2880)):
if 2880%i == 0:
a += 1
possibleSize.append(i)
print(possibleSize)
```

For every int between 1 and 2880 (2880 = 28800/10, because every character in the message is repeated 10 times), we will see if 2880 mod i (were i is a possible message length) is equal to 0, because there is only entire message repetion. We have repeats\*messageLength = 2880.

The result is ```[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 30, 32, 36, 40, 45, 48, 60, 64, 72, 80, 90, 96, 120, 144, 160, 180, 192, 240, 288, 320, 360, 480, 576, 720, 960, 1440]```

I don't think the message is less than 10 morse character long, so let's remove some values :

```python
possibleSize = [15, 16, 18, 20, 24, 30, 32, 36, 40, 45, 48, 60, 64, 72, 80, 90, 96, 120, 144, 160, 180, 192, 240, 288, 320, 360, 480, 576, 720, 960, 1440]
```

Now we have everything we need to write the solver script

```python
possibleSize = [15, 16, 18, 20, 24, 30, 32, 36, 40, 45, 48, 60, 64, 72, 80, 90, 96, 120, 144, 160, 180, 192, 240, 288, 320, 360, 480, 576, 720, 960, 1440]
filename = r"F:\CTF\angstromCTF\misc\Noisy\4ea.txt"
```

and we read the file

``` python
with open(filename) as f:
content = f.readlines()
content = [float(x.strip())+0.5 for x in content] #don't forget to add 0.5 to the value read
```
content contain every lines of the file in an array. Let's sum every group of ten values :
```python
ten = 10
tenAdded = 0
allAddedG10 = []
for i in range(2880):
tenAdded = 0
for j in range(ten):
tenAdded += content[i*ten+j] #we add the values of the nth group of ten
allAddedG10.append(tenAdded)
```

allAddedG10 now contain every group of ten.

NOW LET'S HAVE FUN

Now everything will be inside a for loop, to test every possible sizes :
```python
for size in possibleSize:
```

And, before anything else, I need to show your how I will process the data
Let's take an example :
```
allAddedG10 = [12, 15, 3, 9, 16, 5, 10, 8, 10, 9, 9, -4] #len(allAddedG10) = 12
possibleSizes = [1, 2, 3, 4, 6, 12] #every divisor of 12
```

![](https://imgur.com/Delh86K.png)

Depending on the size, we put the set in defferent array. With a size of 4, there is 4 column, etc...

Then, we can do the average ? of the column. If this average is greater than 5, the character of the message is a 1, else, it's a 0.

And we just have to check every array, to se if the output is valid :

![](https://imgur.com/yAxtBvk.png)

We find a valid output with size = 3, and the output is "-"

Let's do the same on the challenge.

```python
nbRepeat = int((len(allAddedG10))/size) #because repeats*messageLength = len(allAddedG10) <=> repeats = len(allAddedG10) / messageLength

arrayPart = []
arrayG10 = []

for i in range(nbRepeat):
arrayPart = []
for j in range(size):
arrayPart.append(allAddedG10[i*size+j])
arrayG10.append(arrayPart)
```

We now have an array with every groups of 10, and do the average of the columns will give us the character of the message, if we use the right size.

Let's calculate the total of every column :
```python
columnTotal = [0 for x in range(size)]

for i in range(nbRepeat): #i stand for the number of the row

for j in range(size): #j stand for the number of the column
columnTotal[j] += arrayG10[i][j]

```

![](https://imgur.com/OfYF4kG.png)

Now, in columnTotal, we have the total of each column.

Calculation of the average and the final value:

```python
definitivValues = []
for i in range(size):
average = columnTotal[i]/(nbRepeat*ten)
if average < 0.5:
average = 0
else:
average = 1
definitivValues.append(average)
```

Now we want to avoid every incoherent values, for example those which don't start with a 1 and end with a 0 :

```python
if definitivValues[0] == 1 and definitivValues[-1] == 0:
print(size)
print(definitivValues)
```

Final script :
```python
possibleSize = [15, 16, 18, 20, 24, 30, 32, 36, 40, 45, 48, 60, 64, 72, 80, 90, 96, 120, 144, 160, 180, 192, 240, 288, 320, 360, 480, 576, 720, 960, 1440]
filename = r"F:\CTF\angstromCTF\misc\Noisy\4ea.txt"

with open(filename) as f:
content = f.readlines()
content = [float(x.strip())+0.5 for x in content] #don't forget to add 0.5 to the value read

ten = 10
tenAdded = 0
allAddedG10 = []
for i in range(2880):
tenAdded = 0
for j in range(ten):
tenAdded += content[i*ten+j] #we add the values of the nth group of ten
allAddedG10.append(tenAdded)

for size in possibleSize:
print("------------------------------")
nbRepeat = int((len(allAddedG10))/size) #because repeats\*messageLength = len(allAddedG10) <=> repeats = len(allAddedG10) / messageLength

arrayPart = []
arrayG10 = []

for i in range(nbRepeat):
arrayPart = []
for j in range(size):
arrayPart.append(allAddedG10[i*size+j])
arrayG10.append(arrayPart)
columnTotal = [0 for x in range(size)]

for i in range(nbRepeat): #i stand for the number of the row

for j in range(size): #j stand for the number of the column
columnTotal[j] += arrayG10[i][j]

definitivValues = []
for i in range(size):
average = columnTotal[i]/(nbRepeat*ten)
if average < 0.5:
average = 0
else:
average = 1
definitivValues.append(average)
if definitivValues[0] == 1 and definitivValues[-1] == 0:
print(size)
print(definitivValues)
```

We can see that 16, 24, 72, 90, 96,... are valid values

Now forget every values with incoherent values, like three 0, three 1, more than four 0, etc...

The first value working is for size = 96 : `.- -. --- .. ... -.-- -. --- .. ... .`

Translated, it gives us : `ANOISYNOISE`

`Flag : ANOISYNOISE`

-----

*If you have any questions, you can dm me on Discord, nhy47paulo#3590*