总结下CTF中PHP中遇见的考点

最近碰到的一些php的,比如说弱类型和变量覆盖和一些函数造成的问题,还有序列化反序列化和php伪协议,

https://www.jianshu.com/p/fe158ab25120南京邮电CTF wp设计到挺多

比如弱类型有==的 和md5,array_search .  还有strcmp漏洞(数组绕过),ereg函数%00截断漏洞,变量覆盖的话有$$,extract()函数和parse_str(),

PHP5 intval问题和16进制与数字弱相等、chr对256取模

一叶飘零大佬的PHP黑魔法文章(膜)https://skysec.top/2017/07/22/PHP%E5%87%BD%E6%95%B0%E9%BB%91%E9%AD%94%E6%B3%95%E5%B0%8F%E6%80%BB%E7%BB%93/

 

常见php考点知识

php中有两种比较的符号 == 与 ===

1 <?php
2 $a = $b ;
3 $a===$b ;
4 ?>

=== 在进行比较的时候,会先判断两种字符串的类型是否相等,再比较

== 在进行比较的时候,会先将字符串类型转化成相同,再比较

如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换成数值并且比较按照数值来进行

这里明确了说如果一个数值和字符串进行比较的时候,会将字符串转换成数值

复制代码
1 <?php
2 var_dump("admin"==0);  //true
3 var_dump("1admin"==1); //true
4 var_dump("admin1"==1) //false
5 var_dump("admin1"==0) //true
6 var_dump("0e123456"=="0e4456789"); //true 
7 ?>  //上述代码可自行测试
复制代码
1 观察上述代码,"admin"==0 比较的时候,会将admin转化成数值,强制转化,由于admin是字符串,转化的结果是0自然和0相等
2 "1admin"==1 比较的时候会将1admin转化成数值,结果为1,而“admin1“==1 却等于错误,也就是"admin1"被转化成了0,为什么呢??
3 "0e123456"=="0e456789"相互比较的时候,会将0e这类字符串识别为科学技术法的数字,0的无论多少次方都是零,所以相等

对于上述的问题我查了php手册

当一个字符串欸当作一个数值来取值,其结果和类型如下:如果该字符串没有包含'.','e','E'并且其数值值在整形的范围之内
该字符串被当作int来取值,其他所有情况下都被作为float来取值,该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为0
复制代码
1 <?php
2 $test=1 + "10.5"; // $test=11.5(float)
3 $test=1+"-1.3e3"; //$test=-1299(float)
4 $test=1+"bob-1.3e3";//$test=1(int)
5 $test=1+"2admin";//$test=3(int)
6 $test=1+"admin2";//$test=1(int)
7 ?>
复制代码

所以就解释了"admin1"==1 =>False 的原因

 

md5绕过(Hash比较缺陷)

复制代码
 1 <?php
 2 if (isset($_GET['Username']) && isset($_GET['password'])) {
 3     $logined = true;
 4     $Username = $_GET['Username'];
 5     $password = $_GET['password'];
 6 
 7      if (!ctype_alpha($Username)) {$logined = false;}
 8      if (!is_numeric($password) ) {$logined = false;}
 9      if (md5($Username) != md5($password)) {$logined = false;}
10      if ($logined){
11     echo "successful";
12       }else{
13            echo "login failed!";
14         }
15     }
16 ?>    
复制代码

题目大意是要输入一个字符串和数字类型,并且他们的md5值相等,就可以成功执行下一步语句 

介绍一批md5开头是0e的字符串 上文提到过,0e在比较的时候会将其视作为科学计数法,所以无论0e后面是什么,0的多少次方还是0。md5('240610708') == md5('QNKCDZO') 成功绕过!

复制代码
QNKCDZO
0e830400451993494058024219903391

s878926199a
0e545993274517709034328855841020
  
s155964671a
0e342768416822451524974117254469
  
s214587387a
0e848240448830537924465865611904
  
s214587387a
0e848240448830537924465865611904
  
s878926199a
0e545993274517709034328855841020
  
s1091221200a
0e940624217856561557816327384675
  
s1885207154a
0e509367213418206700842008763514
复制代码

json绕过

复制代码
<?php
if (isset($_POST['message'])) {
    $message = json_decode($_POST['message']);
    $key ="*********";
    if ($message->key == $key) {
        echo "flag";
    } 
    else {
        echo "fail";
    }
 }
 else{
     echo "~~~~";
 }
?>
复制代码

输入一个json类型的字符串,json_decode函数解密成一个数组,判断数组中key的值是否等于 $key的值,但是$key的值我们不知道,但是可以利用0=="admin"这种形式绕过

最终payload message={"key":0}

array_search is_array绕过

复制代码
 1 <?php
 2 if(!is_array($_GET['test'])){exit();}
 3 $test=$_GET['test'];
 4 for($i=0;$i<count($test);$i++){
 5     if($test[$i]==="admin"){
 6         echo "error";
 7         exit();
 8     }
 9     $test[$i]=intval($test[$i]);
10 }
11 if(array_search("admin",$test)===0){
12     echo "flag";
13 }
14 else{
15     echo "false";
16 }
17 ?>
复制代码

上面是自己写的一个,先判断传入的是不是数组,然后循环遍历数组中的每个值,并且数组中的每个值不能和admin相等,并且将每个值转化为int类型,再判断传入的数组是否有admin,有则返回flag

payload test[]=0可以绕过

下面是官方手册对array_search的介绍

mixed array_search ( mixed $needle , array $haystack [, bool $strict = false ] )

$needle,$haystack必需,$strict可选  函数判断$haystack中的值是存在$needle,存在则返回该值的键值 第三个参数默认为false,如果设置为true则会进行严格过滤

1 <?php
2 $a=array(0,1);
3 var_dump(array_search("admin",$a)); // int(0) => 返回键值0
4 var_dump(array_seach("1admin",$a));  // int(1) ==>返回键值1
5 ?>

array_search函数 类似于== 也就是$a=="admin" 当然是$a=0  当然如果第三个参数为true则就不能绕过

strcmp漏洞绕过 php -v <5.3

复制代码
 1 <?php
 2     $password="***************"
 3      if(isset($_POST['password'])){
 4 
 5         if (strcmp($_POST['password'], $password) == 0) {
 6             echo "Right!!!login success";n
 7             exit();
 8         } else {
 9             echo "Wrong password..";
10         }
11 ?>
复制代码

strcmp是比较两个字符串,如果str1<str2 则返回<0 如果str1大于str2返回>0 如果两者相等 返回0

我们是不知道$password的值的,题目要求strcmp判断的接受的值和$password必需相等,strcmp传入的期望类型是字符串类型,如果传入的是个数组会怎么样呢

我们传入 password[]=xxx 可以绕过 是因为函数接受到了不符合的类型,将发生错误,但是还是判断其相等

payload: password[]=xxx或者传入以一个object

switch绕过

复制代码
 1 <?php
 2 $a="4admin";
 3 switch ($a) {
 4     case 1:
 5         echo "fail1";
 6         break;
 7     case 2:
 8         echo "fail2";
 9         break;
10     case 3:
11         echo "fail3";
12         break;
13     case 4:
14         echo "sucess";  //结果输出success;
15         break;
16     default:
17         echo "failall";
18         break;
19 }
20 ?>
复制代码

PHP %00截断发生在    php 版本<5.3.4

 

 

 

 

 

intval和PHP7中的16进制字符串

PHP5中intval处理不了16进制字符串并会直接返回0,但是数值可以强制转换成十进制,但在PHP7中,intval一样处理不了16进制字符串,返回0,但是16进制的字符串不会在强制转化为10进制数.

这里还有一种绕过就是用科学计数法绕过,$password=2e4,intval('2e4')=2   intval('2e4'+1)=20001(字符串强制转化为数值)   __7.1.28之后PHP,intval('2e4')=20000 

ISCC WEB1,16进制问题适用于PHP5,不存在于PHP7,因为用来表示十六进制的字符串不再被当作数值处理)

PHP5

 

PHP7

 

 

 

 

 

16进制字符串与数字字符串弱相等在PHP5中(BUGKU 16进制与数字比较,适用于PHP5,不存在于PHP7)

 

<?php
error_reporting(0);
function noother_says_correct($temp)
{
$flag = 'flag{test}';
$one = ord('1'); //ord — 返回字符的 ASCII 码值   49
$nine = ord('9'); //ord — 返回字符的 ASCII 码值  57
$number = '3735929054';
// Check all the input characters!
for ($i = 0; $i < strlen($number); $i++)
{
// Disallow all the digits!
$digit = ord($temp{$i});
if ( ($digit >= $one) && ($digit <= $nine) )
{
// Aha, digit not allowed!
return "flase";
}
}
if($number == $temp)
return $flag;
}
$temp = $_GET['password'];
echo noother_says_correct($temp);
?>

 

在php5中,十进制和对应的十六进制是相等的

 

 

 

 

 

变量覆盖

参考于https://www.freebuf.com/column/150731.html

parse_str()存在url解码的能力

 

PHP反序列化

construct():当一个类被创建时自动调用
destruct():当一个类被销毁时自动调用
invoke():当把一个类当作函数使用时自动调用
tostring():当把一个类当作字符串使用时自动调用
wakeup():当调用unserialize()函数时自动调用
sleep():当调用serialize()函数时自动调用
__call():当要调用的方法不存在或权限不足时自动调用

__get():当要调用的属性不存在或权限不足时自动调用

 

 

 

 

 

 

PHP伪协议

page=php://filter/read=convert.base64-encode/resource=xxx

将1.php压缩成1.zip,改后缀为1.jpg上传指定目录后

/about.php?file=phar://./images/file.jpg/1.php

/about.php?file=zip://./images/file.jpg%231.php

php://input,需要开启allow_url_include。将post请求的数据当作php代码执行。当传入的参数作为文件名打开时,可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容

 

摘自https://www.jianshu.com/p/8057e336514f

 自己测试:http://127.0.0.1/shell1.php?file=phar://1.jpg/testaaa.php (成功)

 

parse_url()绕过

在 5.4.7 之前这会输出路径 "//www.example.com/path"

例如2016asisctf的一道web题

当我们输入http://127.0.0.1/1.php?/home/aaa/ 会被attack detected

但如果输入http://127.0.0.1//1.php?/home/aaa/ 则会被当做相对url,此时的1.php?成了host 而path成了/hone/aaa,导致绕过$data['query']的过滤

3、 ///会被返回false

例如如下代码,如果输入http://localhost/1.php?sql=select会被过

如果输入http://127.0.0.1///1.php?sql=select的话就会成功绕过

Note: parse_url() 是专门用来解析 URL 而不是 URI 的。不过为遵从 PHP 向后兼容的需要有个例外,对 file:// 协议允许三个斜线(file:///...)。其它任何协议都不能这样。

 学习资料:http://www.am0s.com/functions/406.html\

PHP文件上传绕过

文件上传绕过

1.客户端:

javascript的验证

2.服务端:

扩展名绕过:php,php2,php3,php4,php5,phtml

文件类型验证:content-type验证(image/gif)

文件头验证(文件头,gif89a,jeff等,这里就是用图片马,图片马要修改名字)

后缀名黑名单验证1、试验大小写;2、漏网之鱼(jsp:jspx,jspf ; asp:asa,cer,aspx ; php:php2 php3 php4 php5 phtml ; exe:exee)

白名单验证

 

配合文件包含绕过检测后缀为asp/php/jsp是否为木马文件

通过先上传一个.txt文件,然后在上传一个include('.txt')去包含。

<?php Include("上传的txt文件路径");?> 

 

配合解析漏洞绕过文件包含,iis,apache,nginx解析漏洞

(一)IIS5.x-6.x解析漏洞
使用iis5.x-6.x版本的服务器,大多为windows server 2003,网站比较古老,开发语句一般为asp;该解析漏洞也只能解析asp文件,而不能解析aspx文件。
目录解析(6.0)
形式:www.xxx.com/xx.asp/xx.jpg
原理: 服务器默认会把.asp,.asp目录下的文件都解析成asp文件。(传个图片马)
文件解析
形式:www.xxx.com/xx.asp;.jpg(文件名)
原理:服务器默认不解析;号后面的内容,因此xx.asp;.jpg便被解析成asp文件了。
解析文件类型
IIS6.0 默认的可执行文件除了asp还包含这三种 :
/test.asa
/test.cer
/test.cdx
(二)apache解析漏洞
漏洞原理
Apache 解析文件的规则是从右到左开始判断解析,如果后缀名为不可识别文件解析,就再往左判断。比如test.php.qwe.asd “.qwe”和”.asd” 这两种后缀是apache不可识别解析,apache就会把wooyun.php.qwe.asd解析成php。
漏洞形式
www.xxxx.xxx.com/test.php.php123
其余配置问题导致漏洞
(1)如果在 Apache 的 conf 里有这样一行配置 AddHandler php5-script .php 这时只要文件名里包含.php 即使文件名是 test2.php.jpg 也会以 php 来执行。
(2)如果在 Apache 的 conf 里有这样一行配置 AddType application/x-httpd-php .jpg 即使扩展名是 jpg,一样能以php 方式执行。(htaccess文件上传解析漏洞,可以将这段代码写到.htaccess中,再上传写有php一句话代码的jpg文件中)

(三)nginx解析漏洞
漏洞原理
Nginx默认是以CGI的方式支持PHP解析的,普遍的做法是在Nginx配置文件中通过正则匹配设置SCRIPT_FILENAME。当 访问www.xx.com/phpinfo.jpg/1.php这个URL时,$fastcgi_script_name会被设置为 “phpinfo.jpg/1.php”,然后构造成SCRIPT_FILENAME传递给PHP CGI,但是PHP为什么会接受这样的参数,并将phpinfo.jpg作为PHP文件解析呢?这就要说到fix_pathinfo这个选项了。 如果开启了这个选项,那么就会触发在PHP中的如下逻辑:
PHP会认为SCRIPT_FILENAME是phpinfo.jpg,而1.php是PATH_INFO,所以就会将phpinfo.jpg作为PHP文件来解析了
漏洞形式
www.xxxx.com/UploadFiles/image/1.jpg/1.php
www.xxxx.com/UploadFiles/image/1.jpg%00.php
www.xxxx.com/UploadFiles/image/1.jpg/%20\0.php
另外一种手法:上传一个名字为test.jpg,然后访问test.jpg/.php,在这个目录下就会生成一句话木马shell.php。
(四)IIS7.5解析漏洞
IIS7.5的漏洞与nginx的类似,都是由于php配置文件中,开启了cgi.fix_pathinfo,而这并不是nginx或者iis7.5本身的漏洞。
5.配合操作系统文件命令规则
(1)上传不符合windows文件命名规则的文件名
test.asp.
test.asp(空格)
test.php:1.jpg
test.php:: $DATA
会被windows系统自动去掉不符合规则符号后面的内容

 

 

如果遇到上传一个php文件上传后自动修改成为gif或者其他格式的后缀,则可以考虑使用双重后缀,即为1.pphphp

 学习资料:https://www.cnblogs.com/lgf01010/p/9516445.html

转载于:https://www.cnblogs.com/BOHB-yunying/p/10847273.html

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值