DominicBreuker/pspy

GitHub: DominicBreuker/pspy

pspy 是一个无需 root 权限即可监听 Linux 系统进程和命令执行情况的安全审计工具。

Stars: 6122 | Forks: 568

# pspy - 无特权 Linux 进程监听 [![Go Report Card](https://goreportcard.com/badge/github.com/DominicBreuker/pspy)](https://goreportcard.com/report/github.com/DominicBreuker/pspy) [![Maintainability](https://api.codeclimate.com/v1/badges/23328b2549a76aa11dd5/maintainability)](https://codeclimate.com/github/DominicBreuker/pspy/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/23328b2549a76aa11dd5/test_coverage)](https://codeclimate.com/github/DominicBreuker/pspy/test_coverage) [![CircleCI](https://circleci.com/gh/DominicBreuker/pspy.svg?style=svg)](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 作业: ![动画演示 gif](https://static.pigsec.cn/wp-content/uploads/repos/cas/e6/e6cb9b5836ef8317c7407714e3d286397cbfea7491e9abedc4841cdd977aea49.gif) ## 工作原理 目前有一些工具可以列出 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工具, 日志审计, 权限提升辅助, 网络安全审计, 请求拦截