Rating:

# A Bowl of Pythons

## Challenge:

A bowl of spaghetti is nice. What about a bowl of pythons?

**chal.py**

https://cdn.discordapp.com/attachments/840060278204006440/840065069894074398/chal.py

## Solution:

We're provided with some obfuscated Python:

```python
#! /usr/bin/env python3
FLAG = 'sdctf{a_v3ry_s3cur3_w4y_t0_st0r3_ur_FLAG}' # lol

a = lambda n: a(n-2) + a(n-1) if n >= 2 else (2 if n == 0 else 1)

b = lambda x: bytes.fromhex(x).decode()

h = eval(b('7072696e74'))

def d():
h(b('496e636f727265637420666c61672120596f75206e65656420746f206861636b206465657065722e2e2e'))
eval(b('5f5f696d706f72745f5f282273797322292e65786974283129'))
h(FLAG)

def e(f):
h("Welcome to SDCTF's the first Reverse Engineering challenge.")
c = input("Input the correct flag: ")
if c[:6].encode().hex() != '{2}3{0}{1}{0}3{2}{1}{0}{0}{2}b'.format(*map(str, [6, 4, 7])):
d()
if c[int(chr(45) + chr(49))] != chr(125):
d()
g = c[6:-1].encode()
if bytes( (g[i] ^ (a(i) & 0xff) for i in range(len(g))) ) != f:
d()
h(b('4e696365206a6f622e20596f7520676f742074686520636f727265637420666c616721'))

if __name__ == "__main__":
e(b't2q}*\x7f&n[5V\xb42a\x7f3\xac\x87\xe6\xb4')
else:
eval(b('5f5f696d706f72745f5f282273797322292e65786974283029'))
```

Sadly, the flag at the beginning is _not_ our flag.

Running `chal.py` confirms that text is being read from somewhere:

```bash
$ python chal.py 126 ↵
Welcome to SDCTF's the first Reverse Engineering challenge.
Input the correct flag: sctf{???}
Incorrect flag! You need to hack deeper...
```

We find that `b` decodes our binary text data and `h` is just `print()`:

```python
>>> b = lambda x: bytes.fromhex(x).decode()
>>> h = eval(b('7072696e74'))
>>> h
<built-in function print>
>>> b('7072696e74')
'print'
>>> b('496e636f727265637420666c61672120596f75206e65656420746f206861636b206465657065722e2e2e')
'Incorrect flag! You need to hack deeper...'
```

There are some additions just to throw us off the scent. The follow makes sure our flag looks like `sdctf{...}`, and sets `g` to everything between the curly braces:

```python
if c[:6].encode().hex() != '{2}3{0}{1}{0}3{2}{1}{0}{0}{2}b'.format(*map(str, [6, 4, 7])):
d()
if c[int(chr(45) + chr(49))] != chr(125):
d()
g = c[6:-1].encode()
```

The main portion is this:

```python
if bytes( (g[i] ^ (a(i) & 0xff) for i in range(len(g))) ) != f:
```

This encodes our input and compares it to the encoded flag in the source:

```python
e(b't2q}*\x7f&n[5V\xb42a\x7f3\xac\x87\xe6\xb4')
```

We can reverse the encoder and get our flag:

```
def solve(answer):
for i in range(20):
print((a(i) & 0xff) ^ answer[i])

if __name__ == "__main__":
solve(b't2q}*\x7f&n[5V\xb42a\x7f3\xac\x87\xe6\xb4')
```

```
$ python modified.py
118
51
114
121
45
116
52
115
116
121
45
115
112
104
52
103
51
116
116
49
```

We can use `chr(...)` to get the characters of the flag, giving us `v3ry-t4sty-sph4g3tt1`.

Now we have our flag: `sdctf{v3ry-t4sty-sph4g3tt1}`.

Original writeup (https://github.com/mcmahoniel/ctf_write-ups/blob/main/2021/sdctf/revenge/a_bowl_of_pythons/README.md).