PHP是世界上最好的语言,是的,php在世界上养活了两类人,一类是编写php代码的人,一类是从事安全×××的这类人,由于在php中存在着有漏洞的函数。
在必定条件做用下,这些函数没有按着函数发明者的意愿去解析。
在ctf的web世界中也算待了几个月了,对学习当中的遇到的有问题的函数略作一下总结。php
md5()函数web
定义: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字符串是否相等,而且是在两参数值不相等的状况下。
测试结果:sql
原理分析:
当两个字符串被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注入漏洞ide
某些查询语句,特别是查询密码的时候,每每会使用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 = "https://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://www.javashuo.com/article/p-zgqjwlhd-dt.html。
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://www.javashuo.com/article/p-fgdwykvd-ch.html
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!
此博客做为我的笔记,如有带来错误之处请谅解!