Rating: 5.0

# Tokyo Western 2018: pysandbox

__Tags:__ `misc`

This sandbox uses python's `ast` module to parse the input string to its corresponding _abstract syntax tree_. This is what python uses to represent scripts during runtime.

A quick reading of the server scripts shows that when check encounters a `Call` or `Attribute` in the expression, it will be considered invalid.

# Allowed
1 + 2
[1, 2]

# Not Allowed
len([1, 2])
[1, 2].append(3)

The incorrect way to approach this problem is to look for ways to be able to do this __without__ `Call`. Instead, we should look for areas in the tree __not seen by `check`__.

The task was nice enough to put a comment that can be found from python's `ast` [module documentation](https://docs.python.org/2/library/ast.html).

expr = BoolOp(boolop op, expr* values)
| BinOp(expr left, operator op, expr right)
| UnaryOp(unaryop op, expr operand)
| Lambda(arguments args, expr body)
| IfExp(expr test, expr body, expr orelse)

Implemented Checks
attributes = {
'BoolOp': ['values'],
'BinOp': ['left', 'right'],
'UnaryOp': ['operand'],
'Lambda': ['body'],
'IfExp': ['test', 'body', 'orelse']

These list down the different components of a particular expression, and the `attributes` dictionary shows the parts that `check` traverses. We compare the two and identify several parts that are not checked.

Here are some examples:

| Original | Implemented Checks | Unchecked parts |
| Lambda(arguments args, expr body) | 'Lambda': ['body'] | args |
| ListComp(expr elt, comprehension* generators) | 'ListComp': ['elt'] | generators |
| Subscript(expr value, slice slice, expr_context ctx) | Subscript': ['value'] | slice, ctx |


Based on this we can infer that any `Call` in those parts will not be checked.

All of the unchecked parts can be used to hide calls. Here are two ways of getting the flags based on the findings above:

### Using List Comprehensions

[e for e in list(open('flag'))]

### Using Subscript


### Note of Flag2

For the second flag, it is really the same thing, but the `attributes` inside the `check` function is more complete.

attributes = {
'BoolOp': ['values'],
'BinOp': ['left', 'right'],
'UnaryOp': ['operand'],
'Lambda': ['body'],
'IfExp': ['test', 'body', 'orelse'],
'Dict': ['keys', 'values'],
'Set': ['elts'],
'ListComp': ['elt', 'generators'],
'SetComp': ['elt', 'generators'],
'DictComp': ['key', 'value', 'generators'],
'GeneratorExp': ['elt', 'generators'],
'Yield': ['value'],
'Compare': ['left', 'comparators'],
'Call': False, # call is not permitted
'Repr': ['value'],
'Num': True,
'Str': True,
'Attribute': False, # attribute is also not permitted
'Subscript': ['value'],
'Name': True,
'List': ['elts'],
'Tuple': ['elts'],
'Expr': ['value'], # root node
'comprehension': ['target', 'iter', 'ifs'],


Original writeup (https://github.com/pberba/ctf-solutions/tree/master/20180901_tokyo_western/pysandbox).