Php基础漏洞
Php基础漏洞–30
0x01 前言
Php是世界上最好的语言
危险函数大概有一下:extract、
0x02 中言
extract
extract(array,extract_rules,prefix)
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
如果extract_rules参数未指明,则默认覆盖已有变量。如果array可以人为操作,那么可以控制所有的变量值。想要使用的话多利用extract_rules参数。
绕过过滤的空白字符
主要是一些小tips
- ==弱比较,520==’520lcx’同时转化成数字为True,’+191’==’191′
- 可以引入\f(也就是%0c)在数字前面,因为intval和is_numeric都会忽略这个字符,所以不会影响。
- is_numeric($_REQUEST[‘number’])为假,这个绕过的方法很多使用%00开头也可以再POST一个number参数把GET中的覆盖掉也可以,这个函数会把’+191′,’191’,尽管有引号,还是认为为数字。
Mysql | SqlServer WITH ROLLUP绕过
WITH ROLLUP与group by一起使用,是对group by的信息的再次统计,而分组的条件会逐步返回NULL,如果已知用户名,可以返回用user列表的最后一个username和为空的pwd进行比较,实现绕过
ereg正则%00截断
ereg为正则匹配函数,当遇到目标字符串中的%00后,则认为字符串匹配结束,所以可以在%00后添加一些可以绕过其他判断条件的字符串。同时在php若比较中。如果两边的字符串为数字形式,则会先转换成数字再比较
<?php
echo ('1'==='1e0'); #1
?>
传入其他东西也会返回null
strcmp比较字符串
strcmp(str1, str2)
if(str1 < str2) {
return < 0;
}
else if (str1 > str2) {
return > 0;
}
else {
return 0;
}
利用strcmp传入的是数组时,会直接返回null,弱比较中null认为是0,则认为传入的两个参数相同。所以记得用强比较(tips:该漏洞适用5.3之前。
sha/md5()函数比较绕过
<?php
define('FLAG', 'DrunkCTF{you_bypass_md5!}');
if (($_GET['s1']) != $_GET['s2'] && md5($_GET['s1']) == $_GET['s2']) {
echo "success, flag is :" . FLAG;
}
?>
绕过一
用科学计数法绕过
‘0e123456789’ == ‘0e987654321’ == 0
以下值在md5加密后以0E开头:
- QNKCDZO
- 240610708
- s878926199a
- s155964671a
- s214587387a
- s214587387a
- payload 如下
payload
md5.php?s1=QNKCDZO&s2=240610708
绕过二
通过数组绕过,也叫数组 trick
md5([1,2,3]) == md5([4,5,6]) == NULL
所以我们的 payload:
md5.php?s1[]=1&s2[]=2
SESSION验证绕过
比较session时,可以控制cookie中的东西来控制session获得的值(不知道对不对)
intval函数截断
intval只会提取整数部分,会截断小数点
<?php
if($_GET[id]) {
mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
mysql_select_db(SAE_MYSQL_DB);
$id = intval($_GET[id]);
$query = @mysql_fetch_array(mysql_query("select content from ctf2 where id='$id'"));
if ($_GET[id]==1024) {
echo "<p>no! try again</p>";
}
else{
echo($query[content]);
}
}
?>
绕 preg_match 正则
<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if(preg_match("/[0-9]/", $num)){
die("no no no!");
}
if(intval($num)){
echo $flag;
}
}
?>
0 – 9 都被过滤了,所以要用数组来绕过
绕某个具体数字
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==="4476"){
die("no no no!");
}
if(intval($num,0)===4476){
echo $flag;
}else{
echo intval($num,0);
}
}
这关的话就是要求变量值不能为4476,但用过intval函数后为4476,这里的话我们首先需要知道intval的第二个参数为0时的意思是什么
根据这张图绕过
num=4476e123
//这里就跟上面那个单引号的1e10情况一样,此时只看字母前面的
num=4476.1
//计算int值时,后面有小数点会直接舍去
num=0x117c
//0x表明是十六进制数,117c是4476的十六进制数
num=010574
//0表明是八进制数,10574是4476的八进制数
终极绕过
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==4476){
die("no no no!");
}
if(preg_match("/[a-z]|\./i", $num)){
die("no no no!!");
}
if(!strpos($num, "0")){
die("no no no!!!");
}
if(intval($num,0)===4476){
echo $flag;
}
}
?>
这道题的话看着几乎是防死了,多过滤了.,这就意味着小数点绕过行不通,此时我们看到这个i修饰符,想到那个m修饰符,此时就想起来有个换行符%0a,它对实际输出没影响,它还可以绕过上面的那些函数,因此我们这里构造如下语句,就实现了绕过,由于小数点不能用,这里就用八进制
num=%0a010574
strpos数组trick
找特定字符串的第一个位置。
传入的是数组时,会直接返回null,可以在强比较中和FALSE比较。
0比较绕过
PHP中非数字开头字符串和数字0
比较==
都返回True
implode()
implode(separator,array)
implode() 函数返回一个由数组元素组合成的字符串。
0x03 后言
感谢Drunkbaby师傅的博客支持。