emp3r0r: Linux下的进程注入与伪装 | xxxemp3r0r: Linux下的进程注入与伪装 – xxx
菜单

emp3r0r: Linux下的进程注入与伪装

二月 27, 2022 - FreeBuf

背景

距离《emp3r0r:Linux用户打造的Linux后渗透框架》已经过了一年,本人继续发扬年初做更新(然后鸽一年)的优良传统,水一篇关于Linux进程注入的文章。

本文和我去年在安全客发表的Linux进程注入可能略有重合,但和上次不同的是,emp3r0r加入了一个用户态ELF加载器,将其编译为shared library,并定义了__attribute__((constructor))以便被dlopen直接执行。不要问我为啥会执行,那是一个固定特性,而且你只能在使用dl家族的open时才会被ld.so加载执行,所以你如果要自己写个dlopen的话,你还得写个ELF加载器(等会儿,这个shared library是干啥的来着?)

好接着讲,这个ELF加载器(就叫它loader.so吧)自然首先要被dlopen加载才行,然后我们的emp3r0r agent就可以被加载到它所在的进程里执行了,对于procfs来说,这个被注入的进程还是原样,你用psss这样的工具看到的所有活动也都是被注入的进程发出的。

先上个图吧,这是我刚写的新界面,各位大黑阔可以试用下。

emp3r0r: Linux下的进程注入与伪装

技术流程

怎么调用dlopen

上面说过了,我们不会去自己实现一个dlopen,那么就只能调用现成的了。众所周知,dlopenlibdl.so的一个导出函数,那么为了调用它,我们注入的目标进程必须是链接了libdl.so的,也就是说它得事先给我们准备好了。

但如果你看一下就会发现,很多进程是没有加载libdl.so的,毕竟谁闲着没事总跟外部so文件互动呢?好在我们还有其他选择,要知道libc.so是几乎每个Linux进程都会加载的,哪怕它自己静态链接了其他libc.so,道理也是一样的,那么libc.so怎么会有一个dlopen呢?严格来说它并没有,这个函数不是libc导出函数,而是它内部的一个函数,叫做__libc_dlopen_mode,属于是Glibc的一个dlopen实现。

道理懂了,那么我们怎么在目标进程的地址空间里找到__libc_dlopen_mode呢?首先它通常不会位于一个固定的地址,其次ASLR只是把base随机化,但offset是固定的,也就是说我们只要找到libc.so的base,就可以根据offset算出__libc_dlopen_mode的地址。

鉴于我们是直接在emp3r0r agent里实现的,所以这个问题就很容易解决,直接读取procfs里的/proc/pid/maps文件就可以获取一切我们需要的东西。

emp3r0r: Linux下的进程注入与伪装

这就是我们要找的东西,从左到位依次是:起止地址(address),权限(permission),偏移量(offset),inode(不知道中文是啥,可以理解成文件系统的操作单位),长度,文件路径。

这里面我们需要关注的就是起始地址,offset,以及路径。

起始地址不必多说,就是我们要的base。权限呢必须带有x也就是执行权限,offset则是在当前base的基础上加上一个值,当计算__libc_dlopen_mode地址的时候,需要在考虑ELF镜像offset的基础上减去这个值。

怎么注入

GDB就可以直接调用进程里的任意函数,你可以在GDB里执行print __libc_dlopen("loader.so", 2),然后GDB直接就会按照你的参数来调用。

但作为一个后渗透工具,不能指望别人还安装一个GDB吧?所以我就把这个部分自己实现了。

思路的话上面也说了,现在我们有了__libc_dlopen_mode的地址,剩下的工作就是shellcode了。

如果你还有疑问,没关系,emp3r0r已经实现了这部分,直接去看代码吧。另外我实现的是动态shellcode,支持可变参数。

注入的思路很简单,就是和上次我在安全客发过的方法一样,使用ptrace把shellcode扔到$rip的位置,执行完了再把原先的register恢复了,当然你也可以不恢复,在我这里的话loader.so会在子进程里执行ELF,如果你不在乎原进程死活的话也可以在当前进程执行ELF。

这里主要讲讲shellcode,这个shellcode只需要做一件事:设置好__libc_dlopen_mode的参数,并按照给定的地址call进去。这个shellcode管杀不管埋,所以可能执行完不能干净的返回,不过没关系,哪怕挂了,我们也可以wait接住,然后ptrace恢复原先的registers(虽然也不干净),具体的cleanup工作我后续有空了再说吧。

emp3r0r: Linux下的进程注入与伪装

这里需要注意的是stack alignment,push的字节数必须是16的整数倍,不足的话后面执行会挂。

由于文件路径和__libc_dlopen_mode地址都是动态的,我们需要把shellcode也弄成动态生成的。

首先把shellcode用nasm汇编器汇编成机器码,然后把字节dump出来。我有个脚本,调用rasm2实现。

emp3r0r: Linux下的进程注入与伪装

然后你就可以做一个shellcode模板,具体请参考emp3r0r的源码

emp3r0r: Linux下的进程注入与伪装

另外如果需要调试shellcode的话,你可以使用GDB的restore功能,把shellcode二进制文件恢复到$rip下面,然后就可以很方便地观察执行情况。

执行restore shellcode.bin binary $rip然后继续执行即可。

emp3r0r: Linux下的进程注入与伪装

其他

上述技术细节虽然不够详细,但鉴于已经开源,我就不废那么多话了。效果图就是开头的那个截图,不难看到,emp3r0r的代码已经在/sbin/init里运行了,loader.so伪装成了libpam.so注入了systemd的进程。从进程角度来看,整个emp3r0r的活动都是systemd发出的。这个注入目前还不太稳定,需要进一步优化。

另外不知道你注意到没有,我用tmux实现了一个简单的终端分屏界面,这样emp3r0r的一些输出可以从主界面剥离,放到副窗口中,这样的副窗口还包括了一个内置的bashshell,会随着你选择的agent来变化。

“内置的bashshell”是啥呢?就是我把一个完整的纯静态bash可执行文件压缩并base64编码之后塞进emp3r0r,运行时自动释放。

另外我也编译了纯静态的bettercap,效果见Github首页视频

关于前些天挺火的CVE-2021-4034 PwnKit,我也写了个武器化exploit,纯Go零依赖零BS(实名diss下那些说”如果目标环境没有gcc“的人,目标环境直接给你root得了,提权干什么)。已经集成进emp3r0r,以后会武器化更多的提权漏洞,敬请期待。

谢谢大家。

本文作者:, 转载请注明来自FreeBuf.COM

# 内网渗透 # 木马 # linux安全 # linux pwn

Notice: Undefined variable: canUpdate in /var/www/html/wordpress/wp-content/plugins/wp-autopost-pro/wp-autopost-function.php on line 51