Noname's Blog
信息安全专业的小萌新,立志走上更大的舞台
Bugku-代码审计

Bugku-代码审计

刷一下bugku靶场,总结回忆一下最近学习的一些漏洞

extract变量覆盖

<?php
$flag='xxx';
extract($_GET);
if(isset($shiyan))
{
    $content=trim(file_get_contents($flag));//将文件读入一个字符串
    if($shiyan==$content)
    {
        echo'flag{xxx}';
    }else{
        echo'Oh.no';
    }
}
?>

extract()函数

extract(array,extract_rules,prefix)
该函数使用数组键名作为变量名,使用数组键值作为变量值。

针对数组中的每个元素,将在当前符号表中创建对应的一个变量。该函数返回成功设置的变量数目。

array必需。 规定要使用的数组。
extract_rules可选 对不合法和冲突的键名的处理根据该参数决定。
可选值:

EXTR_OVERWRITE - 默认。如果有冲突,则覆盖已有的变量。
EXTR_SKIP - 如果有冲突,不覆盖已有的变量。
EXTR_PREFIX_SAME - 如果有冲突,在变量名前加上前缀 prefix。
EXTR_PREFIX_ALL - 给所有变量名加上前缀 prefix。
EXTR_PREFIX_INVALID -仅在不合法或数字变量名前加上前缀 prefix。
EXTR_IF_EXISTS - 仅在当前符号表中已有同名变量时,覆盖它们的值。其它的都不处理。
EXTR_PREFIX_IF_EXISTS - 仅在当前符号表中已有同名变量时,建立附加了前缀的变量名,其它的都不处理。
EXTR_REFS - 将变量作为引用提取。导入的变量仍然引用了数组参数的值。

思路:使得$shiyan与$content都为空,即可相等,通过extract函数会覆盖的漏洞,将原本的$flag用空值覆盖,payload:

?flag=&shiyan=

strcmp比较字符串

<?php$flag = "flag{xxxxx}";
if (isset($_GET['a']))
{
    if (strcmp($_GET['a'], $flag) == 0) //如果 str1 小于 str2 返回 < 0; 如果 str1大于 str2返回 > 0;如果两者相等,返回 0。
    //比较两个字符串(区分大小写)
        die('Flag: '.$flag);elseprint 'No';
}?>

注释中直接给出了strcmp函数的一些特点
该函数无法比较数组,如果传入的是一个数组,会报错并返回0,最终使得0==0成立
该注释适用于5.3之前的php
payload:

?a[]=1

urldecode二次编码绕过

Bugku: http://123.206.87.240:9009/10.php
urldecode() 解码url字符串,解码已编码字符串中的符号以及中文等被编码的内容
urlencode() 用于编码url字符串,讲字符串编码并将其用于url的请求

<?php
if(eregi("hackerDJ",$_GET[id])) 
{
    echo("not allowed!");
    exit();
}
$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "hackerDJ")
{
    echo "Access granted!";
    echo "flag";
}
?>

eregi()函数
语法
int eregi(string pattern, string string, [array regs]);
在一个字符串不分大小写地搜索指定模式的字符串,匹配成功返回true,否则返回false

思路:
浏览器会先进行一次转码,将%25转成%,而h的url编码是%68
所以%2568--->%68--->h
payload:

?id=%2568ackerDJ

md5()函数


<?php
error_reporting(0);
$flag = 'flag{test}';
if (isset($_GET['username']) and isset($_GET['password']))
{
    if ($_GET['username'] == $_GET['password'])
        print 'Your password can not be your username.';
    else if (md5($_GET['username']) === md5($_GET['password']))
        die('Flag: '.$flag);elseprint 'Invalid password';}?>

md5函数不能正确解析数组
payload:

?username[]=1&password[]=1

数组返回NULL绕过


<?php
$flag = "flag";if (isset ($_GET['password'])) {
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
    echo 'You password must be alphanumeric';
else if (strpos ($_GET['password'], '--') !== FALSE)
    die('Flag: ' . $flag);
else
    echo 'Invalid password';
}
?>

payload:

?username[]=1

弱类型整数大小比较绕过

$temp = $_GET['password'];
is_numeric($temp)?die("no numeric"):NULL;if($temp>1336){
echo $flag;

payload:

?password=1366a

sha()函数比较绕过 md5加密相等绕过


<?php
$flag = "flag";
if (isset($_GET['name']) and isset($_GET['password']))
{
var_dump($_GET['name']);
echo "
";
var_dump($_GET['password']);
var_dump(sha1($_GET['name']));
var_dump(sha1($_GET['password']));
if ($_GET['name'] == $_GET['password'])
echo 'Your password can not be your name!';
else if (sha1($_GET['name']) === sha1($_GET['password']))
die('Flag: '.$flag);
else echo 'Invalid password.';
}
else echo 'Login first!';
?>

md5源码不贴了
就是简单的碰撞
记录一些常用值:
md5加密后以0E开头(科学计数法,得0)

QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
s214587387a

sha1加密后以0E开头

aaroZmOk
aaK1STfY
aaO8zKZF
aa3OFF9m

十六进制与数字比较


<?php
    error_reporting(0);
    function noother_says_correct($temp){
    $flag = 'flag{test}';
    $one = ord('1'); //ord — 返回字符的 ASCII 码值
    $nine = ord('9'); //ord — 返回字符的 ASCII 码值
    $number = '3735929054';// Check all the input characters!
    for ($i = 0; $i < strlen($number); $i++){// Disallow all the digits!
        $digit = ord($temp{$i});
        if ( ($digit >= $one) && ($digit <= $nine) )
        {
            // Aha, digit not allowed!
            return "flase";
        }
    }
    if($number == $temp)
    return $flag;}
    $temp = $_GET['password'];
    echo noother_says_correct($temp);
?>

代码要求传入的参数不能为大于等于1,小于等于9的数字,但是
payload:

?password=0xdeadc0de

ereg正则%00截断

Bugku:http://123.206.87.240:9009/5.php

<?php
$flag = "xxx";
if (isset ($_GET['password']))
{
    if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
    {
        echo 'You password must be alphanumeric';
    }else if(strlen($_GET['password']) < 8 && $_GET['password'] > 9999999){
    if (strpos ($_GET['password'], '-') !== FALSE) //strpos — 查找字符串首次出现的位置
    {
        die('Flag: ' . $flag);
    }else{
        echo('- have not been found');
    }
    }else{
        echo 'Invalid password';}
    }
?>

int ereg(string pattern, string originalstring, [array regs]);
用指定的模式搜索一个字符中指定的字符串,如果成功返回true,否则返回false,对搜索字母的字符大小写敏感

漏洞:当%00截断及遇到%00则默认为字符串的结束

分析题中拿到flag的条件:
1.password必须数字或字母
2.长度小于8
3.要大于9999999
4.必须含有-
利用%00截断除了字母以外的内容
利用科学计数法使得数字足够大
1e8=100000000
1e9=1000000000

payload:

?password=1e8%00- //提示*-*未被找到
?password=1e8%00*-*

strpos数组绕过


<?php
$flag = "flag";
if (isset ($_GET['ctf'])) {if (@ereg ("^[1-9]+$", $_GET['ctf']) === FALSE)echo '必须输入数字才行';else if (strpos ($_GET['ctf'], '#biubiubiu') !== FALSE)die('Flag: '.$flag);elseecho '骚年,继续努力吧啊~';}?>

int strpos ( string $haystack , mixed $needle [, int $offset = 0 ] )
查找字符在字符串中首次出现的位置

strpos函数返回查找到的子字符串的下标。如果字符串开头就是我们要搜索的目标,则返回下标 0 ;如果搜索不到,则返回false。

若传入一个数组,则返回null,与false也不匹配

但是其实根据题目的提示,也就知道该传一个数组
payload:

?ctf[]=1
?ctf[]