DominicBreuker/pspy
GitHub: DominicBreuker/pspy
pspy 是一个无需 root 权限即可监听 Linux 系统进程和命令执行情况的安全审计工具。
Stars: 6122 | Forks: 568

# pspy - 无特权 Linux 进程监听
[](https://goreportcard.com/report/github.com/DominicBreuker/pspy)
[](https://codeclimate.com/github/DominicBreuker/pspy/maintainability)
[](https://codeclimate.com/github/DominicBreuker/pspy/test_coverage)
[](https://circleci.com/gh/DominicBreuker/pspy)
pspy 是一个命令行工具,旨在无需 root 权限的情况下监听进程。
它允许你在其他用户执行的命令、cron 作业等运行时查看它们。
非常适合在 CTF 中对 Linux 系统进行枚举。
同时也非常适合向你的同事演示,为什么在命令行中传递机密信息是个糟糕的主意。
该工具通过扫描 procfs 来收集信息。
在文件系统的选定部分设置的 Inotify 监视器会触发这些扫描,从而捕获短时进程。
## 快速开始
### 下载
将该工具获取到你要检查的 Linux 机器上。
首先获取二进制文件。在此处下载已发布的二进制文件:
- 32 位大体积静态版本:`pspy32` [下载](https://github.com/DominicBreuker/pspy/releases/download/v1.2.1/pspy32)
- 64 位大体积静态版本:`pspy64` [下载](https://github.com/DominicBreuker/pspy/releases/download/v1.2.1/pspy64)
- 32 位小体积版本:`pspy32s` [下载](https://github.com/DominicBreuker/pspy/releases/download/v1.2.1/pspy32s)
- 64 位小体积版本:`pspy64s` [下载](https://github.com/DominicBreuker/pspy/releases/download/v1.2.1/pspy64s)
静态编译的文件应该可以在任何 Linux 系统上运行,但体积非常大(约 4MB)。
如果体积是个问题,可以尝试较小体积的版本,它们依赖 libc 并使用 UPX 进行了压缩(约 1MB)。
### 构建
你可以使用系统上安装的 Go,或者运行用于创建发布版本的基于 Docker 的构建过程。
对于后者,请确保已安装 Docker,然后运行 `make build-build-image` 构建 Docker 镜像,接着运行 `make build` 使用该镜像构建二进制文件。
你可以运行 `pspy --help` 来了解各个参数及其含义。
简要说明如下:
- -p:启用将命令打印到标准输出(默认启用)
- -f:启用将文件系统事件打印到标准输出(默认禁用)
- -r:使用 Inotify 监视的目录列表。pspy 将递归监视所有子目录(默认监视 /usr、/tmp、/etc、/home、/var 和 /opt)。
- -d:使用 Inotify 监视的目录列表。pspy 将仅监视这些目录,而不包括子目录(默认为空)。
- -i:procfs 扫描之间的间隔(以毫秒为单位)。无论是否有 Inotify 事件,pspy 都会定期扫描新进程,以防漏掉某些事件。
- -c:以不同颜色打印命令。文件系统事件不再着色,命令会根据进程 UID 显示不同颜色。
- --debug:打印详细的错误消息,否则这些消息将被隐藏。
对于大多数应用场景,默认设置应该就足够了。
监视 `/usr` 中的文件最为重要,因为许多工具会访问其中的库。
一些更复杂的示例:
```
# 同时打印 commands 和 file system events 并每 1000 毫秒(=1秒)扫描一次 procfs
./pspy64 -pf -i 1000
# 在两个目录中递归放置 watchers,并在第三个目录中非递归放置
./pspy64 -r /path/to/first/recursive/dir -r /path/to/second/recursive/dir -d /path/to/the/non-recursive/dir
# 禁用打印发现的 commands 但启用 file system events
./pspy64 -p=false -f
```
### 示例
### Cron 作业监视
要查看工具的实际运行情况,只需克隆代码仓库并运行 `make example`(需要 Docker)。
众所周知,将密码作为命令行参数传递是不安全的,此示例可用于演示这一点。
该命令启动一个 Debian 容器,其中有一个由 root 运行的机密 cron 作业,每分钟更改一次用户密码。
pspy 将以前台方式、以用户 myuser 的身份运行,并扫描进程。
你应该会看到类似以下的输出:
```
~/pspy (master) $ make example
[...]
docker run -it --rm local/pspy-example:latest
[+] cron started
[+] Running as user uid=1000(myuser) gid=1000(myuser) groups=1000(myuser),27(sudo)
[+] Starting pspy now...
Watching recursively : [/usr /tmp /etc /home /var /opt] (6)
Watching non-recursively: [] (0)
Printing: processes=true file-system events=false
2018/02/18 21:00:03 Inotify watcher limit: 524288 (/proc/sys/fs/inotify/max_user_watches)
2018/02/18 21:00:03 Inotify watchers set up: Watching 1030 directories - watching now
2018/02/18 21:00:03 CMD: UID=0 PID=9 | cron -f
2018/02/18 21:00:03 CMD: UID=0 PID=7 | sudo cron -f
2018/02/18 21:00:03 CMD: UID=1000 PID=14 | pspy
2018/02/18 21:00:03 CMD: UID=1000 PID=1 | /bin/bash /entrypoint.sh
2018/02/18 21:01:01 CMD: UID=0 PID=20 | CRON -f
2018/02/18 21:01:01 CMD: UID=0 PID=21 | CRON -f
2018/02/18 21:01:01 CMD: UID=0 PID=22 | python3 /root/scripts/password_reset.py
2018/02/18 21:01:01 CMD: UID=0 PID=25 |
2018/02/18 21:01:01 CMD: UID=??? PID=24 | ???
2018/02/18 21:01:01 CMD: UID=0 PID=23 | /bin/sh -c /bin/echo -e "KI5PZQ2ZPWQXJKEL\nKI5PZQ2ZPWQXJKEL" | passwd myuser
2018/02/18 21:01:01 CMD: UID=0 PID=26 | /usr/sbin/sendmail -i -FCronDaemon -B8BITMIME -oem root
2018/02/18 21:01:01 CMD: UID=101 PID=27 |
2018/02/18 21:01:01 CMD: UID=8 PID=28 | /usr/sbin/exim4 -Mc 1enW4z-00000Q-Mk
```
首先,pspy 会打印出所有当前正在运行的进程,每个进程都附带其 PID、UID 和命令行。
当 pspy 检测到新进程时,它会在日志中添加一行。
在这个示例中,你可以找到一个 PID 为 23 的进程,它似乎正在更改 myuser 的密码。
这是 root 的私有 crontab `/var/spool/cron/crontabs/root` 中的一个 Python 脚本执行该 shell 命令的结果(查看 [crontab](docker/var/spool/cron/crontabs/root) 和 [脚本](docker/root/scripts/password_reset.py))。
请注意,myuser 既无法查看 crontab,也无法查看 Python 脚本。
但有了 pspy,它依然可以看到执行的命令。
### 来自 Hack The Box 的 CTF 示例
以下是一个来自 [Hack The Box](https://www.hackthebox.eu/) 中 Shrek 机器的示例。
在这个 CTF 挑战中,任务是利用一个隐藏的 cron 作业,该作业会更改文件夹中所有文件的所有权。
漏洞在于不安全地将通配符与 chmod 结合使用(感兴趣的读者可查看[详情](https://www.defensecode.com/public/DefenseCode_Unix_WildCards_Gone_Wild.txt))。
要找到并利用它需要进行大量的猜测。
但有了 pspy,就可以轻松地找到并分析该 cron 作业:

## 工作原理
目前有一些工具可以列出 Linux 系统上执行的所有进程,包括已经执行完毕的进程。
例如 [forkstat](http://smackerelofopinion.blogspot.de/2014/03/forkstat-new-tool-to-trace-process.html)。
它接收来自内核的关于进程相关事件(如 fork 和 exec)的通知。
这些工具需要 root 权限,但这不应让你产生虚假的安全感。
其实没有什么能阻止你监听 Linux 系统上运行的进程。
只要进程在运行,procfs 中就会显示大量信息。
唯一的问题是,你必须在短时进程存活的极短时间窗口内捕捉到它们。
在一个无限循环中扫描 `/proc` 目录以查找新 PID 可以解决问题,但这会消耗大量 CPU。
一种更隐蔽的方法是使用以下技巧。
进程往往会访问诸如 `/usr` 中的库、`/tmp` 中的临时文件、`/var` 中的日志文件等...
使用 [inotify](http://man7.org/linux/man-pages/man7/inotify.7.html) API,只要这些文件被创建、修改、删除、访问等,你就可以收到通知。
Linux 不对该 API 要求特权用户,因为许多无害的应用程序都需要使用它(例如文本编辑器向你展示最新的文件资源管理器)。
因此,尽管非 root 用户无法直接监视进程,但他们可以监视进程在文件系统上产生的影响。
我们可以利用文件系统事件作为触发器来扫描 `/proc`,希望我们能足够快地执行扫描以捕获进程。
这就是 pspy 所做的工作。
虽然不能保证你一个都不会漏掉,但在我的实验中,捕获的几率似乎很高。
通常,进程运行的时间越长,捕获它们的几率就越大。
# 其他
Logo:“By Creative Tail [CC BY 4.0 (http://creativecommons.org/licenses/by/4.0)], via Wikimedia Commons” ([链接](https://commons.wikimedia.org/wiki/File%3ACreative-Tail-People-spy.svg))
标签:EVTX分析, Go, procfs, Ruby工具, 日志审计, 权限提升辅助, 网络安全审计, 请求拦截