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.
```python
# Allowed
1 + 2
[1, 2]
# Not Allowed
len([1, 2])
[1, 2].append(3)
''.__class__
```
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).
Comment
```
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
```python
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
```
[][sys.stdout.write(open('flag').read())]
```
### Note of Flag2
For the second flag, it is really the same thing, but the `attributes` inside the `check` function is more complete.
```python
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'],
}
```