这里吧源码码一下:
<?php
if (isset ($_GET['password'])) {
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
{
echo '<p>You password must be alphanumeric</p>';
}
else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
{
if (strpos ($_GET['password'], '*-*') !== FALSE)
{
die('Flag: ' . $flag);
}
else
{
echo('<p>*-* have not been found</p>');
}
}
else
{
echo '<p>Invalid password</p>';
}
}
?>
先代码审计,分析一下题目的要求:
- 首先就是password必须是a-zA-Z0-9的字符
- 再者就是pwd的长度要小于8,且内容的值要大于9999999
- pwd要包含
*-*
题目的hint是:ereg()函数有漏洞哩;从小老师就说要用科学的方法来算数
我们先去查询一下ereg()函数的漏洞吧
ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字母的字符是大小写敏感
的。
int ereg(string pattern, string originalstring, [array regs]);
例,
$email_id = "admin@tutorialspoint.com";
$retval = ereg("(\.)(com$)", $email_id);
ereg()限制password的格式,只能是数字或者字母。但ereg()函数存在NULL截断漏洞,可以使用%00绕过验证。
这里ereg有两个漏洞:
%00截断及遇到%00则默认为字符串的结束
//关于00截断我之前的一篇文件上传的博客有介绍
当ntf为数组时它的返回值不是FALSE
以下转自实验吧的wp
第一种方法
长度小于8并且password要大于9999999可以使用科学计数法表示 1e8
password = 1e8%00*-*
%00是一个空字节,占用字节为1
ereg()在匹配字符串的时候遇到%00就只认前面的,而后面的-就会被过滤,进而完成了绕过
这里我又想吐槽了。。。我这第一种方法怎么都不好使。。%00截断总失败。。
第二种方法
既然password为数组时返回null,那我就传入一个数组试试呢
http://ctf5.shiyanbar.com/web/more.php?password=[5]
提示这样做不对
我又想了下,用下面的形式试试呢(原来吧password当数组,后面随便赋一个值)
http://ctf5.shiyanbar.com/web/more.php?password[]=8 没想到flag直接就出来的,哈哈哈
但原理呢?
ereg ("^[a-zA-Z0-9]+$", $_GET['password'])
password为数组,ereg()返回的就是null,
null === false 肯定是false。
三等于号是数值,类型一起做比较的,都匹配对的话为true
所以上面的这句代码就被绕过了
但下面的代码为什么被执行了呢????
strlen($_GET['password']) < 8
不用说了,肯定是满足条件的
$_GET['password'] > 9999999
password是array,在php中array和其他类型比较,总是更大,所以这也满足条件了。
strpos ($_GET['password'], '*-*') !== FALSE)
strpos()官网介绍
password是数组,官网里说strpos()传入数组时会出现意料之外的情况,呵呵,难道说的就是这种情况?这就代码居然也被绕过了。。。。。
最后得到了flag
总结:根据代码审计和提示能容易的想到第一种利用科学记数法的方法,要是像我这样第一种方法怎么都不好使的,就只能传数组了,而且这次记住了传数组的格式以及了解到数组在许多判定中优先级还挺高的