php函数漏洞原理解析

PHP是世界上最好的语言,是的,php在世界上养活了两类人,一类是编写php代码的人,一类是从事安全×××的这类人,因为在php中存在着有漏洞的函数。
在一定条件作用下,这些函数没有按着函数发明者的意愿去解析。
在ctf的web世界中也算待了几个月了,对学习当中的遇到的有问题的函数略做一下总结。

md5()函数

定义:Md5()函数计算字符串的MD5散列

问题1:经过MD5()函数处理的字符串散列如果出现0e开头的,在被php处理的时候会被认为等于0。
源码:

<?php
    $user=$_GET[‘user‘];
    $pass=$_GET[‘pass‘];
    if($user!=$pass){
        if(md5($user) == md5($pass)){
            echo "this is flag";
        }
        else{
            echo "no no no";
        }
    }else{
        echo "字符串不能相同";
    }

?>

代码功能:判断get方法传入的参数的MD5的hash字符串是否相等,并且是在两参数值不相等的情况下。
测试结果:

原理分析:
当两个字符串被MD5加密的时候,会产生以0e开头的哈希值。Php进行判断的时候0e…会被看成科学计数法,0的n次方都是等于零。所以这两个字符串被md5()加密后都等于零。
var_dump(0 == 0e123456)

问题2:处理数组的时候返回为null
源码:

<?php
    $user=$_GET[‘user‘];
    $pass=$_GET[‘pass‘];
    if($user!=$pass){
        if(md5($user) == md5($pass)){
            echo "this is flag";
        }
        else{
            echo "no no no";
        }
    }else{
        echo "字符串不能相同";
    }

测试:

原理分析:
md5(string,raw)语法:string必须,规定要计算的字符串,raw可选,规定输出格式,TRUE-16字符二进制格式;false-默认,32字符十六进制数。
函数作者规定处理的字符串类型为str字符串型,才能正常输出。传递数组无法处理。造成输出结果为null

问题3:造成sql注入漏洞

某些查询语句,特别是查询密码的时候,往往会使用md5()函数处理后再去数据库查询对比,这样就会造成一些风险。
查询语句:
Select from user where passwd = ‘.md5($password,true)’;
这个地方有一个特殊的字符串可以绕过,在你不知道密码的情况下查询到user表的内容。
字符串:ffifdyop
测试:

可以看到字符串被md5()加密后成为了 ‘ or ‘ 6…,
添加到查询语句中就变成了
Select
from user where password=’’or’6…’(…表示乱码,并不影响查询)
这时候我们将加密后的东西拿去到数据库查询一下。

看可以将数据库中的所有的数据全部查出。
原理分析:
Or语句就不在赘述,只说一下,数据库中的操作,在查询的时候,where 的后面并不一定非要跟上参数才能够查询。

只要where后面的值不等于零,就表示true。等于零为false

并且where后面的值是字符串的时候,但是第一个是一个非零数的时候也能查询所有有内容

所以也解释了,为甚前面乱码依然成立的问题。

***扩展同类函数:sha1()函数。具体用法相同。其哈希值0e开头的有,sha1(‘aaroZmOk‘) sha1(‘aaK1STfY‘) sha1(‘aaO8zKZF‘) sha1(‘aa3OFF9m‘)



ereg()函数

    定义:正则表达式匹配

问题1:可以00截断
源码:
if(isset($_GET[‘num‘])){
if(ereg(‘^[a-zA-Z0-9]+$‘, $_GET[‘num‘]) === FALSE){
echo "请输入符合要求的";
}else{
echo "您输入的符合要求";
}
}
代码分析:只有当输入数字和字母的时候,输入正确,如果输入包含符号的就会提示不正确。
漏洞利用:输入123%00
看字符串中含有符号,应该返回“请输入符合要求的”的提示。但是漏洞就通过00截断产生了

原理解析:
当ereg()函数碰到%00的时候,就会认为字符串结束,并不会继续往下检测。
问题2:碰到参数是数组的返回为null
源码相同,测试结果:

实现原理:因为返回为null,null != FALSE,所以匹配正确

intval()函数

    定义用法;
    获取变量的整数值,允许以使用特定的进制返回。默认10进制
    注:如果参数为整数,则不做任何处理。

问题:可以构造字符串绕过
测试:

问题解析:
通过上面的实验说明,当取回字符串整数的时候,如果字符串中含有非数字的字符,将会返回第一次出现非数字符的前面的整数。若果没有数字返回0.

unset()函数

定义用法:unset() 销毁指定的变量。

存在问题:可能销毁原有定义的变量,进行绕过

源码:

$abc[‘a‘] = true;

foreach(array(‘_GET‘,‘_POST‘) as $method) {
    foreach($$method as $key=>$value) {
      unset($$key);
    }
}

if ($abc[‘a‘] == false) {
    echo ‘flag {123}‘;
}

?>

测试:

解析:
如果unset变量存在请求参数当中,便会出现销毁变量实现绕过的现象。就如这里,通过$$符号,$key=abc;$$key=$abc;最后unset()函数便会变成unset($abc),将原来定义的$abc[‘a’]=true给销毁。

extract()函数

定义用法:
extract() 函数从数组中将变量导入到当前的符号表。
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
EXTR_OVERWRITE - 默认。如果有冲突,则覆盖已有的变量。
EXTR_SKIP - 如果有冲突,不覆盖已有的变量。
EXTR_PREFIX_SAME - 如果有冲突,在变量名前加上前缀 prefix。
EXTR_PREFIX_ALL - 给所有变量名加上前缀 prefix。
EXTR_PREFIX_INVALID - 仅在不合法或数字变量名前加上前缀 prefix。
EXTR_IF_EXISTS - 仅在当前符号表中已有同名变量时,覆盖它们的值。其它的都不处理。
EXTR_PREFIX_IF_EXISTS - 仅在当前符号表中已有同名变量时,建立附加了前缀的变量名,其它的都不处理。
EXTR_REFS - 将变量作为引用提取。导入的变量仍然引用了数组参数的值。
这个函数的重点就是默认将已经有的变量给覆盖掉

存在问题;将原来的变量覆盖,进行绕过

源码:

    $a = ‘yaun‘;
    extract($_GET);
    if($auth == 1){
        echo "private!";
    } else{
        echo "public!";
    }  

测试:

问题解析:当我传递a=1的时候,extract()函数发现有原来的变量,于是将原来变量的值覆盖掉,变成a=1,在进行if条件语句的判断。

parse_str()函数

定义用法:
parse_str() 函数用于把查询字符串解析到变量中,如果没有array 参数,则由该函数设置的变量将覆盖已存在的同名变量。 极度不建议 在没有 array参数的情况下使用此函数,并且在 PHP 7.2 中将废弃不设置参数的行为。此函数没有返回值。

源码:

  if(empty($_GET[‘id‘])){
    show_source(__FILE__);
    die();
}else{
    include(‘flag.php‘);
    $a = "http://blog.51cto.com/12332766";
    $id = $_GET[‘id‘];
    @parse_str($id);
    if($a[0] == ‘yaun‘){
        echo "yes is flag";
    }else{
        exit(‘其实很简单,其实并不难‘);
    }
}

测试:


问题解析:
当传递参数id=a[]=yaun的时候,经过parse_str()函数的处理将a变成变量。但是原来有同名的变量,于是就将原来的变量覆盖掉,同时覆盖的还有变量的值。

变量覆盖拓展:php中遇到$$的时候也会出现变量覆盖的情况。详情请到:http://blog.51cto.com/12332766/2120800

strcmp()函数

定义用法:
Strcmp(string1,string2)函数比较两个字符串

返回值:
0 - 如果两个字符串相等
<0 - 如果 string1 小于 string2 >0 - 如果 string1 大于 string2

问题:处理数组的时候返回null

源码“


$a="yaun";
$pass=$_GET[‘pass‘];
if(strcmp($a, $pass) == 0){
    echo "成功";
}else{
    echo "失败";
}

测试:


问题解析:
传递数组的时候,函数没有办法比较数组,返回null,php语言本身就是弱类型的语言,null==0 在数值上相等。但是在类型上不等。

is_numeric()函数

定义用法:
is_numeric() 函数用于检测变量是否为数字或数字字符串。
如果指定的变量是数字和数字字符串则返回 TRUE,否则返回 FALSE

问题1:传递十六进制的话,会让检测无效。
源码:

$a=$_GET[‘num‘];
if(is_numeric($a)){
    echo "您输入的是数字";
}else{
    echo "请输入合法字符";
}

测试:
输入一串查询语句转换过得十六进制


成功绕过函数的检测
问题解析:这个函数不仅能够检测十进制,同时还认为十六进制也是合法的。于是就可以构造十六进制的语句进行绕过此函数。

preg_match()函数

定义用法:
Preg_match()函数匹配正则表达式。

返回值:
返回 pattern 的匹配次数。 它的值将是 0 次(不匹配)或 1 次,因为 preg_match() 在第一次匹配后 将会停止搜索。如果发生错误preg_match()返回 FALSE。
问题:如果在进行正则表达式匹配的时候,没有限制字符串的开始和结束(^ 和 $),则可以存在绕过的问题
源码:

$ip=$_GET[‘ip‘];
if(!preg_match("/(\d+)\.(\d+)\.(\d+)\.(\d+)/",$ip)) {
  die(‘error‘);
} else {
   echo "this is flag";
}

测试:
输入一个不符合匹配规则的字符串,依然返回flag

问题解析:
因为这个函数在执行匹配规则的时候没有说明是以什么开头或者结尾,所以只需要在这个字符串中存在规定的字符,其他的字符也可以添加上去进行绕过。

in_array()函数

定义用法:
in_array(search,array) 函数搜索数组中是否存在指定的值。

返回值:
如果给定的值 search 存在于数组 array 中则返回 true。如果没有在数组中找到参数,函数返回 false。

$array=[0,1,2,‘3‘];
var_dump(in_array(‘abc‘, $array));
var_dump(in_array(‘1bc‘, $array));

测试:

问题分析:
可以看到上面的情况返回的都是true,因为’abc’会转换为0,’1bc’转换为1。
在所有php认为是int的地方输入string,都会被强制转换

unserialize()函数
具体使用方法见另一篇博客:http://blog.51cto.com/12332766/2121394

strpos()函数

定义用法:
strpos() 函数查找字符串在另一字符串中第一次出现的位置(区分大小写)。
注释:strpos() 函数是区分大小写的。
注释:该函数是二进制安全的。

语法:
strpos(string,find,start) string 必须,规定被搜索的字符串;find 必须,规定查找的字符串;start 可选,规定开始搜索的位置。
返回值:
返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。注释: 字符串位置从 0 开始,不是从 1 开始
源码:

if(strpos($_GET[‘password‘],‘abc‘) == 0 ){
    echo ‘123‘;
}
else{
    echo ‘456‘;
}

传递一个数组进去测试,使得返回结果是123

可以看到我们输入的并不符合要求,但是还是给了123的输出。
问题解析:
这个函数也是只解析string类型的字符串,给他个数组就不知道如何解析,于是就返回为null。Null==0!

strlen()函数

定义用法:
strlen() 函数返回字符串的长度

语法:
strlen(string) string-必须,规定要检查的字符串。

源码:

if(strlen($_GET[‘password‘]) == 0  ){
    echo ‘1233‘;
}else{

    echo ‘4566‘;
}

测试:
传递一个数组,使得返回为1233

问题分析:
这个函数也是只解析string类型的字符串,给他个数组就不知道如何解析,于是就返回为null。Null==0!

此博客作为个人笔记,若有带来错误之处请谅解!

原文地址:http://blog.51cto.com/12332766/2149184

时间: 2024-07-29 07:24:31

php函数漏洞原理解析的相关文章

文件上传漏洞及解析漏洞总结

文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力.这种攻击方式是最为直接和有效的,"文件上传"本身没有问题,有问题的是文件上传后,服务器怎么处理.解释文件.如果服务器的处理逻辑做的不够安全,则会导致严重的后果. 文件上传后导致的常见安全问题一般有: 1)上传文件是Web脚本语言,服务器的Web容器解释并执行了用户上传的脚本,导致代码执行. 2)上传文件是Flash的策略文件crossdomain.xml,黑客用以控制Flash在该域下的行为(

CVE2016-8863libupnp缓冲区溢出漏洞原理分析及Poc

1.libupnp问题分析: (1)问题简述: 根据客户给出的报告,通过设备安装的libupnp软件版本来判断,存在缓冲区溢出漏洞:CVE-2016-8863. (2)漏洞原理分析: 该漏洞发生在upnpSDK库中,upnp/src/gena/gena_device.c.文件的create_url_list函数中,由于对输入数据未进行有效检验,造成对缓冲区溢出,可以导致服务器拒绝服务或崩溃:攻击者也可以精心制造一个攻击URL,通过subscribe request的callback header

微软 IIS HTTP.sys漏洞原理学习以及POC

零.MS15-034POC核心部分(参考巡风): 1 socket.setdefaulttimeout(timeout) 2 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 3 s.connect((ip, int(port))) 4 flag = "GET / HTTP/1.0\r\nHost: stuff\r\nRange: bytes=0-18446744073709551615\r\n\r\n" 5 s.send(fl

(转)Apache和Nginx运行原理解析

Apache和Nginx运行原理解析 原文:https://www.server110.com/nginx/201402/6543.html Web服务器 Web服务器也称为WWW(WORLD WIDE WEB)服务器,主要功能是提供网上信息浏览服务. 应用层使用HTTP协议. HTML文档格式. 浏览器统一资源定位器(URL). Web服务器常常以B/S(Browser/Server)方式提供服务.浏览器和服务器的交互方式如下: GET /index.php HTTP/1.1 +-------

游戏外挂原理解析与制作 - [内存数值修改类 篇一]

本章旨在讲解外挂实现原理,未深入涉及至代码层面.希望能与对这方面感兴趣的朋友多多交流,毕竟理论是死的,套路是固定的,只有破解经验是花大量时间和心血积累的. 对于单机游戏而言,游戏中绝大部分的参数(比如血.蓝.能量亦或是金币)都存储在计算机的堆栈中,一些类似剧情进度的则加密后写入本地的自定义配置文件中: 对于页游.网游和手游,虽然服务器保存了大量的重要的参数,但由于客户端不可避免的需要进行大量的计算和资源的加载,本地内存种必定存有部分的临时变量,通过判断这些变量的变化规律和函数的破密寻到利于自身的

JSONP跨域的原理解析

JSONP跨域的原理解析 一种脚本注入行为 在 2011年10月27日 那天写的     已经有 99238 次阅读了 感谢 参考或原文 JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为"Same-Origin Policy"(同源策略).这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容. JavaScript这个安全策略在进

Request 接收参数乱码原理解析二:浏览器端编码原理

上一篇<Request 接收参数乱码原理解析一:服务器端解码原理>,分析了服务器端解码的过程,那么浏览器是根据什么编码的呢? 1. 浏览器解码 浏览器根据服务器页面响应Header中的“Content-Type: text/html; charset=gb2312”解码.修改web.config中“responseEncoding=utf-8”,发现服务器页面响应Header变成了“Content-Type: text/html; charset=utf8”. <system.web&g

游戏外挂原理解析与制作 - [内存数值修改类 篇二]

本章旨在讲解如何利用高级语言根据变量数值寻找内存地址.涉及代码以C#为例. 我用C#写了一个WinForm形式的Demo,界面如下: 源代码: //血量初始值 private int value = 1000; public Form1() { InitializeComponent(); } /// <summary> /// 刷新界面:将最新的血量显示在界面 /// </summary> /// <param name="sender"><

Volley 实现原理解析(转)

Volley 实现原理解析 转自:http://blog.csdn.net/fengqiaoyebo2008/article/details/42963915 1. 功能介绍 1.1. Volley Volley 是 Google 推出的 Android 异步网络请求框架和图片加载框架.在 Google I/O 2013 大会上发布. 名字由来:a burst or emission of many things or a large amount at once发布演讲时候的配图 从名字由来和