劫持LD_PRELOAD
0x00 前言
LD_PRELOAD是Linux系统中的一个环境变量,作用是在程序在运行链接之前优先加载LD_PRELOAD中的链接库,因此通过指定LD_PRELOAD变量我们可以实现二进制程序的链接库劫持,覆盖重写原来的系统调用。
0x01 劫持系统命令
1 |
|
以ls命令为例使用readelf -Ws /usr/bin/ls
查看ls命令调用的库函数
1 |
|
选择strncmp进行劫持,重新定义strncmp的函数体,注意参数列表必须保持不变,记得unsetenv。
1 |
|
然后编译并设置环境变量
1 |
|
最后执行ls
1 |
|
0x02 绕过 Disable_Functions
在拿到php环境下的webshell时常常遇到Disable_Functions禁用系统命令执行的情况,使用LD_PRELOAD也可以实现bypass。
根据上述LD_PRELOAD劫持的特点,欲将其用于bypass Disable_Functions需要满足以下几个条件:
- 由于LD_PRELOAD是在程序链接之前起作用,因此我们无法在现有php进程中实现劫持,必须要寻找能够创建新进程的函数。
- 环境变量需要可控,例如可以使用putenv()函数。
mail()
mail()函数是php内置用于发送邮件的函数,在底层是调用Linux中的sendmail函数。
1 |
|
执行并使用strace跟踪系统调用
1 |
|
结果如下:
1 |
|
明显是调用了/usr/sbin/sendmail
,同时execve启用了新进程,因此劫持sendmail()即可劫持mail()。
下一步查看sendmail()的库函数
1 |
|
(我的vps里没有sendmail拓展,不过问题不大后续可以解决这个问题)
挑选getuid函数进行劫持:
1 |
|
然后在脚本中设置环境变量:
1 |
|
执行即可实现劫持。
error_log()
error_log()和mail()一样也会调用sendmail,劫持的过程没有差别不再赘述
1 |
|
能创建新进程的函数含有很多,有时候要根据主机所安装的拓展因地制宜。
0x03 __attribute__((constructor))
上面提到在我的vps中没有sendmail拓展,因此事实上我们无法实现劫持,因此我们需要一个通用的解决方案,那就是C语言的一个拓展修饰符__attribute__((constructor))
,由它所修饰的函数将在程序main()函数之前执行,如果它存在于动态链接库中,那么它将会在动态链接库被系统加载之前执行。这样就可以实现对于链接的劫持,而不是局限于特定的系统调用。
1 |
|
reference
https://www.anquanke.com/post/id/254388