用php实现php代码的加密解密类分享

 更新时间:2016年11月25日 15:21  点击:2106
php加密,php类,php分享

php 代码加密类,大家可以根据自己的需求进行修改,原类如下,希望能分享给大家。本次在ubuntu下测试没有问题。

    <?php  
    class Encryption{  
        private $c='';//存储密文  
        private $s='',$q1,$q2,$q3,$q4,$q5,$q6;//存储生成的加密后的文件内容  
        //如果不设置一个值,isset会表示不存在;  
        private $file='';//读取文件的路径  
        private $source='',$target='';
        //构造函数,实例化时调用初始化全局变量;  
        public function __construct(){  
            //初始化全局变量  
            $this->initialVar();  
            //echo "hello \n";  
        }  
        /*
        *@input  $property_name,$value
        *@output  
        *   魔法方法,对变量进行设置值;可根据需求进行处理。若直接去除if判断表示可用设置任何属性的值,包括不存在的属性;
        */  
        public function __set($property_name,$value){  
            //定义过的变量;  
            if(isset($this->$property_name)){  
                $this->$property_name = $value;  
            }else{  
                //异常处理,处理未声明的变量赋值;可根据需求进行处理。  
                throw new Exception("property does not exist");  
            }  
        }  
        //魔法方法 取出变量的值;  
        public function __get($property_name){  
            if(isset($this->$property_name)){  
                return $this->$property_name;  
            }else{  
                //throw new Exception("property does not exist");  
                return NULL;  
            }  
        }  
        //取随机排序  
        private function RandAbc($length=""){//随机排序取回  
          $str="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";  
          return str_shuffle($str);  
        }  
        //对明文内容进行加密处理
        private function ciphertext($filename){  
            //$filename='index.php';  
            $T_k1=$this->RandAbc();  
            $T_k2=$this->RandAbc();  
            $vstr=file_get_contents($filename);  
            $v1=base64_encode($vstr);  
            $c=strtr($v1,$T_k1,$T_k2);
            $this->c=$T_k1.$T_k2.$c;  
            return $this;  
        }
        //初始化变量  
        private function initialVar(){  
            $this->q1="O00O0O";//base64_decode  
            $this->q2="O0O000";//$c(原文经过strtr置换后的密文,由 目标字符+替换字符+base64_encode(‘原文内容’)构成)  
            $this->q3="O0OO00";//strtr  
            $this->q4="OO0O00";//substr  
            $this->q5="OO0000";//52  
            $this->q6="O00OO0";//urldecode解析过的字符串(n1zb/ma5\vt0i28-pxuqy*6%6Crkdg9_ehcswo4+f37j)

        }  
        //生成加密后的模板(复杂版本);  
        private function model(){  
            //$c = $this->c;
            //$this->initialVar();  
            $this->s='<?php $'.$this->q6.'=urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");$'.  
            $this->q1.'=$'.$this->q6.'{3}.$'.$this->q6.'{6}.$'.$this->q6.'{33}.$'.$this->q6.'{30};$'.$this->q3.'=$'.$this->q6.'{33}.$'.$this->q6.'{10}.$'  
            .$this->q6.'{24}.$'.$this->q6.'{10}.$'.$this->q6.'{24};$'.$this->q4.'=$'.$this->q3.'{0}.$'.$this->q6.'{18}.$'.$this->q6.'{3}.$'.$this->q3.'{0}  
            .$'.$this->q3.'{1}.$'.$this->q6.'{24};$'.$this->q5.'=$'.$this->q6.'{7}.$'.$this->q6.'{13};$'.$this->q1.'.=$'.$this->q6.'{22}.$'.$this->q6.'{36}  
            .$'.$this->q6.'{29}.$'.$this->q6.'{26}.$'.$this->q6.'{30}.$'.$this->q6.'{32}.$'.$this->q6.'{35}.$'.$this->q6.'{26}.$'.$this->q6.'{30};  
            eval($'.$this->q1.'("'.base64_encode('$'.$this->q2.'="'.$this->c.'";
            eval(\'?>\'.$'.$this->q1.'($'.$this->q3.'($'.$this->q4.'($'.$this->q2.',$'.$this->q5.'*2),$'.$this->q4.'($'.$this->q2.',$'.$this->q5.',$'.$this->q5.'),  
            $'.$this->q4.'($'.$this->q2.',0,$'.$this->q5.'))));').'"));?>';  
            return $this;  
        }
        //创建加密文件  
        private function build($target){
            //$this->encodes("./index.php");  
            //$this->model();  
            $fpp1 = fopen($target,'w');  
            fwrite($fpp1,$this->s) or die('写入是失败!');
            fclose($fpp1);
            return $this;  
        }  
        //加密处理 连贯操作  
        public function encode($file,$target){  
            //$file = "index.php";  
            //连贯操作其实就是利用函数处理完后返回自身  
            $this->ciphertext($file)->model()->build($target);
            echo 'encode------'.$target.'-----ok<br/>';  
        }  
        //解密  
        public function decode($file,$target=''){
            //读取要解密的文件
            $fpp1 = file_get_contents($file);
            $this->decodeMode($fpp1)->build($target);
            echo 'decode------'.$target.'-----ok<br/>';
        }
        //解密模板,得到解密后的文本
        private function decodeMode($fpp1){
            //以eval为标志 截取为数组,前半部分为密文中的替换掉的函数名,后半部分为密文
            $m = explode('eval',$fpp1);
            //对系统函数的替换部分进行执行,得到系统变量
            $varStr = substr($m[0],strpos($m[0],'$'));
            //执行后,后续就可以使用替换后的系统函数名
            eval($varStr);
            //判断是否有密文
            if(!isset($m[1])){
                return $this;
            }

            //对密文进行截取 {$this->q4}  substr
            $star =  strripos($m[1],'(');
            $end = strpos($m[1],')');
            $str = ${$this->q4}($m[1],$star,$end);
            //对密文解密 {$this->q1}  base64_decode
            $str = ${$this->q1}($str);
            //截取出解密后的  核心密文
            $evallen = strpos($str,'eval');
            $str = substr($str,0,$evallen);
            //执行核心密文 使系统变量被赋予值 $O0O000
            eval($str);
            //并不能将如下段封装,因为 ${$this->qn} 并不能在全文中起作用
            $this->s = ${$this->q1}(
                ${$this->q3}(
                    ${$this->q4}(
                        ${$this->q2},${$this->q5}*2
                    ),
                    ${$this->q4}(
                        ${$this->q2},${$this->q5},${$this->q5}
                    ),
                    ${$this->q4}(
                        ${$this->q2},0,${$this->q5}
                    )
                )
            );
            return $this;
        }
        //递归读取并创建目标目录结构
        private function targetDir($target){
            if(!empty($target) )  {
                if(!file_exists($target)){
                    mkdir($target,0777,true);
                }else{
                    chmod($target,0777);
                }

            }
        }

        //递归解密 对指定文件夹下的php文件解密  
        public function decodeDir($source,$target=""){
            if(is_dir($source)){
                $this->targetDir($target);
                $dir = opendir($source);  
                while(false!=$file=readdir($dir))  
                {  
                    //列出所有文件并去掉'.'和'..' 此处用的实例为thinkphp框架,所以默认排除里Thinkphp目录,用户可以按照自己的需求设置
                    if($file!='.' && $file!='..' && $file !='ThinkPHP')
                    {  
                        $path = $target.DIRECTORY_SEPARATOR.$file;  
                        $sourcePath =  $source.DIRECTORY_SEPARATOR.$file;  
                        $this->decodeDir($sourcePath,$path);  
                    }  
                }  
          
            }else if(is_file($source)){  
                $extension=substr($source,strrpos($source,'.')+1);  
                if(strtolower($extension)=='php'){
                    $this->decode($source,$target);  
                }else{  
                    //不是php的文件不处理  
                    copy($source, $target);  
                }  
                //return;  
            }
        }  
        //递归加密 对指定文件夹下的php文件加密  
        public function encodeDir($source,$target){
            if(is_dir($source)){
                $this->targetDir($target);
                $dir = opendir($source);  
                while(false!=$file=readdir($dir))  
                {  
                    //列出所有文件并去掉'.'和'..'
                    if($file!='.' && $file!='..' && $file !='ThinkPHP')
                    {  
                        $path = $target.DIRECTORY_SEPARATOR.$file;  
                        $sourcePath =  $source.DIRECTORY_SEPARATOR.$file;  
                        $this->encodeDir($sourcePath,$path);  
                    }  
                }  

            }else if(is_file($source)){
                $extension=substr($source,strrpos($source,'.')+1);
                if(strtolower($extension)=='php'){
                    $this->encode($source,$target);
                }else{  
                    copy($source, $target);  
                }
            }  
        }
    }  
    $ob = new Encryption();  
    $ob->source = "/var/www/bookReservation";
    $ob->target = "/var/www/jiami/bookReservation";
    //解密指定文件  
    //$ob->decode('D:\\php\\WWW\\workspace\\weixin2\\Application\\Home\\Controller\\IndexController.class.php');  
      
    //$ob->decode('jiami.php');  
    //$ob->decode('dam6.php');  
    //对一个指定的文件目录进行加密  
    $ob->encodeDir($ob->source,$ob->target);
    //对一个指定的文件目录进行解密
    $ob->decodeDir($ob->target,"/var/www/jiami/bookReservationD");

依赖注入是对于要求更易维护,更易测试,更加模块化的代码的答案。每个项目都有依赖(外界提供的输入), 项目越复杂,越需要更多的依赖。

PHP程序员如何理解依赖注入容器(dependency injection container)


背景知识

传统的思路是应用程序用到一个Foo类,就会创建Foo类并调用Foo类的方法,假如这个方法内需要一个Bar类,就会创建Bar类并调用Bar类的方法,而这个方法内需要一个Bim类,就会创建Bim类,接着做些其它工作。

<?php
// 代码【1】
class Bim
{
    public function doSomething()
    {
        echo __METHOD__, '|';
    }
}

class Bar
{
    public function doSomething()
    {
        $bim = new Bim();
        $bim->doSomething();
        echo __METHOD__, '|';
    }
}

class Foo
{
    public function doSomething()
    {
        $bar = new Bar();
        $bar->doSomething();
        echo __METHOD__;
    }
}

$foo = new Foo();
$foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething

使用依赖注入的思路是应用程序用到Foo类,Foo类需要Bar类,Bar类需要Bim类,那么先创建Bim类,再创建Bar类并把Bim注入,再创建Foo类,并把Bar类注入,再调用Foo方法,Foo调用Bar方法,接着做些其它工作。

<?php
// 代码【2】
class Bim
{
    public function doSomething()
    {
        echo __METHOD__, '|';
    }
}

class Bar
{
    private $bim;

    public function __construct(Bim $bim)
    {
        $this->bim = $bim;
    }

    public function doSomething()
    {
        $this->bim->doSomething();
        echo __METHOD__, '|';
    }
}

class Foo
{
    private $bar;

    public function __construct(Bar $bar)
    {
        $this->bar = $bar;
    }

    public function doSomething()
    {
        $this->bar->doSomething();
        echo __METHOD__;
    }
}

$foo = new Foo(new Bar(new Bim()));
$foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething

这就是控制反转模式。依赖关系的控制反转到调用链的起点。这样你可以完全控制依赖关系,通过调整不同的注入对象,来控制程序的行为。例如Foo类用到了memcache,可以在不修改Foo类代码的情况下,改用redis。

使用依赖注入容器后的思路是应用程序需要到Foo类,就从容器内取得Foo类,容器创建Bim类,再创建Bar类并把Bim注入,再创建Foo类,并把Bar注入,应用程序调用Foo方法,Foo调用Bar方法,接着做些其它工作.

总之容器负责实例化,注入依赖,处理依赖关系等工作。


代码演示 依赖注入容器 (dependency injection container)

通过一个最简单的容器类来解释一下,这段代码来自 Twittee

<?php

class Container
{
    private $s = array();

    function __set($k, $c)
    {
        $this->s[$k] = $c;
    }

    function __get($k)
    {
        return $this->s[$k]($this);
    }
}

这段代码使用了魔术方法,在给不可访问属性赋值时,__set() 会被调用。读取不可访问属性的值时,__get() 会被调用。

<?php

$c = new Container();

$c->bim = function () {
    return new Bim();
};
$c->bar = function ($c) {
    return new Bar($c->bim);
};
$c->foo = function ($c) {
    return new Foo($c->bar);
};

// 从容器中取得Foo
$foo = $c->foo;
$foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething

这段代码使用了匿名函数

再来一段简单的代码演示一下,容器代码来自simple di container

<?php

class IoC
{
    protected static $registry = [];

    public static function bind($name, Callable $resolver)
    {
        static::$registry[$name] = $resolver;
    }

    public static function make($name)
    {
        if (isset(static::$registry[$name])) {
            $resolver = static::$registry[$name];
            return $resolver();
        }
        throw new Exception('Alias does not exist in the IoC registry.');
    }
}

IoC::bind('bim', function () {
    return new Bim();
});
IoC::bind('bar', function () {
    return new Bar(IoC::make('bim'));
});
IoC::bind('foo', function () {
    return new Foo(IoC::make('bar'));
});


// 从容器中取得Foo
$foo = IoC::make('foo');
$foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething

这段代码使用了后期静态绑定


依赖注入容器 (dependency injection container) 高级功能

真实的dependency injection container会提供更多的特性,如

    自动绑定(Autowiring)或 自动解析(Automatic Resolution)
    注释解析器(Annotations)
    延迟注入(Lazy injection)

下面的代码在Twittee的基础上,实现了Autowiring。

<?php

class Bim
{
    public function doSomething()
    {
        echo __METHOD__, '|';
    }
}

class Bar
{
    private $bim;

    public function __construct(Bim $bim)
    {
        $this->bim = $bim;
    }

    public function doSomething()
    {
        $this->bim->doSomething();
        echo __METHOD__, '|';
    }
}

class Foo
{
    private $bar;

    public function __construct(Bar $bar)
    {
        $this->bar = $bar;
    }

    public function doSomething()
    {
        $this->bar->doSomething();
        echo __METHOD__;
    }
}

class Container
{
    private $s = array();

    public function __set($k, $c)
    {
        $this->s[$k] = $c;
    }

    public function __get($k)
    {
        // return $this->s[$k]($this);
        return $this->build($this->s[$k]);
    }

    /**
     * 自动绑定(Autowiring)自动解析(Automatic Resolution)
     *
     * @param string $className
     * @return object
     * @throws Exception
     */
    public function build($className)
    {
        // 如果是匿名函数(Anonymous functions),也叫闭包函数(closures)
        if ($className instanceof Closure) {
            // 执行闭包函数,并将结果
            return $className($this);
        }

        /** @var ReflectionClass $reflector */
        $reflector = new ReflectionClass($className);

        // 检查类是否可实例化, 排除抽象类abstract和对象接口interface
        if (!$reflector->isInstantiable()) {
            throw new Exception("Can't instantiate this.");
        }

        /** @var ReflectionMethod $constructor 获取类的构造函数 */
        $constructor = $reflector->getConstructor();

        // 若无构造函数,直接实例化并返回
        if (is_null($constructor)) {
            return new $className;
        }

        // 取构造函数参数,通过 ReflectionParameter 数组返回参数列表
        $parameters = $constructor->getParameters();

        // 递归解析构造函数的参数
        $dependencies = $this->getDependencies($parameters);

        // 创建一个类的新实例,给出的参数将传递到类的构造函数。
        return $reflector->newInstanceArgs($dependencies);
    }

    /**
     * @param array $parameters
     * @return array
     * @throws Exception
     */
    public function getDependencies($parameters)
    {
        $dependencies = [];

        /** @var ReflectionParameter $parameter */
        foreach ($parameters as $parameter) {
            /** @var ReflectionClass $dependency */
            $dependency = $parameter->getClass();

            if (is_null($dependency)) {
                // 是变量,有默认值则设置默认值
                $dependencies[] = $this->resolveNonClass($parameter);
            } else {
                // 是一个类,递归解析
                $dependencies[] = $this->build($dependency->name);
            }
        }

        return $dependencies;
    }

    /**
     * @param ReflectionParameter $parameter
     * @return mixed
     * @throws Exception
     */
    public function resolveNonClass($parameter)
    {
        // 有默认值则返回默认值
        if ($parameter->isDefaultValueAvailable()) {
            return $parameter->getDefaultValue();
        }

        throw new Exception('I have no idea what to do here.');
    }
}

// ----
$c = new Container();
$c->bar = 'Bar';
$c->foo = function ($c) {
    return new Foo($c->bar);
};
// 从容器中取得Foo
$foo = $c->foo;
$foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething

// ----
$di = new Container();

$di->foo = 'Foo';

/** @var Foo $foo */
$foo = $di->foo;

var_dump($foo);
/*
Foo#10 (1) {
  private $bar =>
  class Bar#14 (1) {
    private $bim =>
    class Bim#16 (0) {
    }
  }
}
*/

$foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething

以上代码的原理参考PHP官方文档:反射,PHP 5 具有完整的反射 API,添加了对类、接口、函数、方法和扩展进行反向工程的能力。 此外,反射 API 提供了方法来取出函数、类和方法中的文档注释。

exec()、passthru()、system()、shell_exec()在php配置文件中通常是把它给禁止使用了,但有时我们需要用到了,下面就来看看php中exec()、passthru()、system()、shell_exec()函数的用法与禁止方法。

php提供4种方法执行系统外部命令:exec()、passthru()、system()、 shell_exec()。
在开始介绍前,先检查下php配置文件php.ini中是有禁止这是个函数。找到 disable_functions,配置如下:
disable_functions =
如果“disable_functions=”后面有接上面四个函数,将其删除。
默认php.ini配置文件中是不禁止你调用执行外部命令的函数的。

方法一:exec()

function exec(string $command,array[optional] $output,int[optional] $return_value)
php代码:


<?php
        echo exec("ls",$file);
        echo "</br>";
        print_r($file);
?>
执行结果:
test.php
Array( [0] => index.php [1] => test.php)

知识点:

exec 执行系统外部命令时不会输出结果,而是返回结果的最后一行,如果你想得到结果你可以使用第二个参数,让其输出到指定的数组,此数组一个记录代表输出的一行,即如果输出结果有20行,则这个数组就有20条记录,所以如果你需要反复输出调用不同系统外部命令的结果,你最好在输出每一条系统外部命令结果时清空这个数组,以防混乱。第三个参数用来取得命令执行的状态码,通常执行成功都是返回0。

方法二:passthru()

function passthru(string $command,int[optional] $return_value)
代码:


<?php
        passthru("ls");
?>
执行结果:
index.phptest.php
知识点:
passthru与system的区别,passthru直接将结果输出到浏览器,不需要使用 echo 或 return 来查看结果,不返回任何值,且其可以输出二进制,比如图像数据。

方法三:system()

function system(string $command,int[optional] $return_value)
代码:


<?php
        system("ls /");
?>
执行结果:
binbootcgroupdevetchomeliblost+foundmediamntoptprocrootsbinselinuxsrvsystmpusrvar
知识点:
system和exec的区别在于system在执行系统外部命令时,直接将结果输出到浏览器,不需要使用 echo 或 return 来查看结果,如果执行命令成功则返回true,否则返回false。第二个参数与exec第三个参数含义一样。


方法四:反撇号`和shell_exec()

shell_exec() 函数实际上仅是反撇号 (`) 操作符的变体

代码:


<?php
        echo `pwd`;
?>


执行结果:


/var/www/html

CMS为了文章编辑内容,都会在后台集成在线编辑器,如FCKEditor等,但是这种很容易XSS跨站攻击,以下我们来看一下使用 HTML Purifier 如何防止xss跨站攻击

随着html可视即可得编辑器的流行,很多网站使用了这样的编辑器,比如FCKEditor、百度UEditor编辑器等等。

跨站脚本攻击(XSS)已经不是什么新鲜的话题了,甚至很多大公司也为此吃尽苦头。最简单直接的防范方法,就是不允许任何html标签输入,对用户输入进行编码(htmlencode)。

但是如果想用户输入支持一些格式,怎么办?一种办法就是很多论坛采用的BB Code的方法。使用特定的标签代替一些格式。比如:[ B ]表示粗体,等等。但是,BB Code这种形式并不被广泛接受,它的表现力实在太差了,而且并不是标准格式。

为了让用户的输入更具表现力,涌现了大量的Html编辑器控件,著名的有FCKEditor,FreeTextBox,Rich TextBox,Cute Editor,TinyMCE等等。我个人比较喜欢Cute Editor,功能强大,性能不错,而且容易定制。

使用这些Html编辑器控件的潜在危险,是用户可能会输入一些危险字符,注入到网站中,形成XSS攻击。一个最简单的输入就是:

<script>alert('xss')</script>

XSS 输入攻击也可能是 HTML 代码段,譬如:

(1).网页不停地刷新 <meta http-equiv="refresh" content="0;">
(2).嵌入其它网站的链接 <iframe src=http://xxxx width=250 height=250></iframe>

对于PHP开发者来说,如何去防范XSS攻击呢?(php防止xss攻击的函数),这里飘易推荐HTML Purifier工具。

HTML Purifier官网:http://htmlpurifier.org/

HTML Purifier是基于php 5所编写的HTML过滤器,支持自定义过滤规则,还可以把不标准的HTML转换为标准的HTML,是WYSIWYG编辑器的福音。
HTML Purifier,这是一个符合W3C标准的HTML过滤器,可以生成标准的HTML代码,并且有很多的自定义配置,可以过滤掉javascript代码等,有效的防止XSS!

一、使用HTML Purifier的要求

HTML Purifier 只需要PHP 5.0.5以及以上版本,并且不需要其他核心组件的支持。HTML Purifier 不兼容  zend.ze1_compatibility_mode。

以下5个是可选扩展,可以增强HTML Purifier的性能(can enhance the capabilities of HTML Purifier):

    * iconv  : Converts text to and from non-UTF-8 encodings
    * bcmath : Used for unit conversion and imagecrash protection
    * tidy   : Used for pretty-printing HTML
    * CSSTidy : Clean CSS stylesheets using %Core.ExtractStyleBlocks
    * Net_IDNA2 (PEAR) : IRI support using %Core.EnableIDNA

使用前请阅读HTML Purifier详细安装说明:http://htmlpurifier.org/live/INSTALL

二、基本用法

默认下,使用UTF-8编码,和XHTML 1.0 Transitional文档类型.
require_once('HTMLPurifier/library/HTMLPurifier.auto.php');
$config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($config);
 
$dirty_html = <<<EOF 
<h1>Hello 
<script>alert("world");</script> 
EOF; 

$cleanHtml = $purifier->purify($dirty_html); 

输出:

<h1>Hello 
</h1> 

过滤了XSS代码,过滤规则:http://htmlpurifier.org/live/smoketests/xssAttacks.php

自动填充了残缺的标签

三、使用配置

配置主要用于设置规则,使用比较简单

$config = HTMLPurifier_Config::createDefault(); 
// something.... 
$purifier = new HTMLPurifier($config); 

详细的配置规则:http://htmlpurifier.org/live/configdoc/plain.html

无意之中发现特殊的图片上传可以绕过php gd库对图片处理,然后实现php执行,太危险了,下面来看看我是怎么实现的,然后你如何也存在这样的情况,赶快把漏洞补起吧。

我使用了一个特殊的图片上传技巧,绕过PHP GD库对图片的转换处理,最终成功实现了远程代码执行。

事情是这样的。当时我正在测试该网站上是否存在sql注入漏洞,不经意间我在网站个人页面发现了一个用于上传头像的文件上传表单。开始时我并没指望在上传功能处发现漏洞,但我决定试试。

我上传了一个图片文件,通过截断http数据包,修改jpg图片的文件名后缀为php,然后继续上传。我惊讶的居然上传成功了,我几乎不敢相信这么简单的漏洞居然存在。于是我复制了图片url并且在浏览器上打开。进入我眼帘的是图片的二进制代码,这意味着图片以php解析了,并根据响应包里的 content-type以text/html格式返回。

我现在要做的是在jpg文件中注入php代码以进行远程代码执行,于是我尝试将代码写入图片的EXIF头里,但是悲剧的是再次上传发现php代码没有被执行。

在本机进行了测试,结果仍然无效——代码没有被执行

绕过PHP图片上传转换实现远程代码执行(RCE)危险

在上传到服务器后,EXIF里的代码都被删除了,应用通过imagecreatefromjpeg()函数调用了PHP GD库(GD库,是php处理图形的扩展库),对图片进行了转换。那么如果不将代码注入EXIF头而是注入到图片里呢?

绕过PHP图片上传转换实现远程代码执行(RCE)危险

本机测试通过,但当我上传“1.jpg”到服务器上,返回以下结果:

绕过PHP图片上传转换实现远程代码执行(RCE)危险

报错上写着“文件必须是合法的图片(.gif, .jpg, .jpeg, 或.png)”,我惊叹于应用是怎么判断图片不合法的。我又测试了一些其他jpg文件,结果发现修改任何一个图片字符都会引起php-gd库的错误判断,进而造成上传失败。

接下来我又使用gif图片进行了同样的操作,结果是:图片上传成功了,但是图片中的php代码完全被删除了。

虽然这看起来不可思议,但是我不能放弃,因为现在距离成功利用远程代码执行(RCE)只有一步之遥,我必须绕过imagecreatefromgif()函数。我对图片的处理和php GD库的运行知之甚少,可是这不影响我使用一些传统渗透测试方法。

我想到一个方法:对比两张经过php-gd库转换过的gif图片,如果其中存在相同之处,这就证明这部分图片数据不会经过转换。然后我可以注入代码到这部分图片文件中,最终实现远程代码执行。连我自己都佩服我的机智!

绕过PHP图片上传转换实现远程代码执行(RCE)危险

如图,我用十六进制编辑器打开图片文件,找到了php转换前后仍然保持相同的十六进制串“3b45d00ceade0c1a3f0e18aff1”并修改它为。

绕过PHP图片上传转换实现远程代码执行(RCE)危险

保存图片,上传到服务器:

绕过PHP图片上传转换实现远程代码执行(RCE)危险

我的PHP代码被执行了,我最终成功实现了远程代码执行。

[!--infotagslink--]

相关文章

  • 图解PHP使用Zend Guard 6.0加密方法教程

    有时为了网站安全和版权问题,会对自己写的php源码进行加密,在php加密技术上最常用的是zend公司的zend guard 加密软件,现在我们来图文讲解一下。 下面就简单说说如何...2016-11-25
  • vue接口请求加密实例

    这篇文章主要介绍了vue接口请求加密实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-12
  • AES加密解密的例子小结

    关于AES加密的算法我们就不说了,这里主要给各位演示了三个关于AES算法实现的加密例子,希望本文章能给你带来帮助。 话不多说,先放上代码,一共有两个文件:AES.php(aes算...2016-11-25
  • node.JS md5加密中文与php结果不一致怎么办

    这次文章要给大家介绍的是node.JS md5加密中文与php结果不一致怎么办,不知道具体解决办法的下面跟小编一起来看看。 因项目需要,需要Node.js与PHP做接口调用,发现nod...2017-07-06
  • PHP加密解密函数详解

    分享一个PHP加密解密的函数,此函数实现了对部分变量值的加密的功能。 加密代码如下: /* *功能:对字符串进行加密处理 *参数一:需要加密的内容 *参数二:密钥 */ function passport_encrypt($str,$key){ //加密函数 srand(...2015-10-30
  • php威盾解密的例子分享

    下面来给大家分享两个关于php威盾解密的例子,一个是批量解密一个是超级算法的解密都非常的好,大家有举的进入参考。 例子,批量解密 代码如下 复制代码 ...2016-11-25
  • NODE.JS加密模块CRYPTO常用方法介绍

    使用require('crypto')调用加密模块。加密模块需要底层系统提供OpenSSL的支持。它提供了一种安全凭证的封装方式,可以用于HTTPS安全网络以及普通HTTP连接。该模块还提供了一套针对OpenSSL的hash(哈希),hmac(密钥哈希),cipher...2014-06-07
  • C#连接加密的Sqlite数据库的方法

    对数据加密分两种,一种是对数据库本身进行加密,另一种是对数据表中的数据进行加密,下面通过本文给大家介绍C#连接加密的Sqlite数据库的方法,感兴趣的朋友一起看看吧...2020-06-25
  • C# 获取硬盘号,CPU信息,加密解密技术的步骤

    这篇文章主要介绍了C# 获取硬盘号,CPU信息,加密解密技术的步骤,帮助大家更好的理解和学习c#,感兴趣的朋友可以了解下...2021-01-16
  • C#实现对文件进行加密解密的方法

    这篇文章主要介绍了C#实现对文件进行加密解密的方法,涉及C#加密与解密的技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • php使用异或实现的加解密的方法

    若a=b ^ c;则b=a ^ c (^是异或的意思),php在处理异或的字符时先把字符转化为二进制的ascii值,对这些值进行异或,获取结果后在将ascii值转化为字符...2013-09-26
  • 一组PHP加密解密函数分享

    复制代码 代码如下:<?php/***功能:对字符串进行加密处理*参数一:需要加密的内容*参数二:密钥*/function passport_encrypt($str,$key){ //加密函数srand((double)microtime() * 1000000);$encrypt_key=md5(rand(0, 32000...2014-06-07
  • go语言使用RC4加密的方法

    这篇文章主要介绍了go语言使用RC4加密的方法,实例分析了RC4加密的技巧与实现方法,具有一定参考借鉴价值,需要的朋友可以参考下...2020-05-07
  • C#为配置文件加密的实现方法

    这篇文章主要介绍了C#为配置文件加密的实现方法,可实现对配置文件中的敏感信息进行加密,非常具有实用价值,需要的朋友可以参考下...2020-06-25
  • c#实现md5加密示例

    这篇文章主要介绍了md5加密,加密结果可以为32位、48位、64位,只要修改一下参数就可以实现...2020-06-25
  • C#编写的Base64加密和解密类

    本文给大家汇总介绍了几种C#编写的Base64加密和解密类的代码,从简单到复杂,都能够实现功能,有需要的小伙伴根据自己的项目需求参考下吧。...2020-06-25
  • 微信小程序 MD5加密登录密码详解及实例代码

    这篇文章主要介绍了微信小程序 MD5加密登录密码详解及实例代码的相关资料,这里附有实例代码,需要的朋友可以参考下...2017-01-16
  • C#实现的MD5加密功能与用法示例

    这篇文章主要介绍了C#实现的MD5加密功能与用法,结合实例形式分析了C# MD5加密类的定义与使用方法,需要的朋友可以参考下...2020-06-25
  • C#实现对AES加密和解密的方法

    C#实现对AES加密和解密的方法,需要的朋友可以参考一下...2020-06-25
  • Android使用RSA加密实现接口调用时的校验功能

    这篇文章主要介绍了Android+Java使用RSA加密实现接口调用时的校验功能,帮助大家更好的利用Android进行开发,感兴趣的朋友可以了解下...2020-12-24