zoukankan      html  css  js  c++  java
  • Bugku 代码审计

    0x01、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';
    }
    }
    ?>

    GET型传入参数,如果变量shiyan=content,则输出答案

    extract()函数用法:

    extract() 函数从数组中将变量导入到当前的符号表。

    该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。

    该函数返回成功设置的变量数目。

    如果当前符号表中有于数组键值变量名相同的,那么用数组键值的变量覆盖

    trim()函数

    trim() 函数移除字符串两侧的空白字符或其他预定义字符。

    ltrim() - 移除字符串左侧的空白字符或其他预定义字符

    rtrim() - 移除字符串右侧的空白字符或其他预定义字符

    paylaod:?flag=&shiyan=

    为什么必须时空字符???

    0x02、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);
    else
    print 'No';
    }
    ?>

     
    参数 str1第一个字符串。str2第二个字符串。如果 str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0。
    比较两个字符串(区分大小写):
    返回 不同的地方
    strcmp漏洞
    注:这一个漏洞适用与5.3之前版本的php
    可知,传入的期望类型是字符串类型的数据,但是如果我们传入非字符串类型的数据的时候,这个函数将会有怎么样的行为呢?实际上,当这个函数接受到了不符合的类型,这个函数将发生错误,但是在5.3之前的php中,显示了报错的警告信息后,将return 0 !!!! 也就是虽然报了错,但却判定其相等了。这对于使用这个函数来做选择语句中的判断的代码来说简直是一个致命的漏洞,当然,php官方在后面的版本中修复了这个漏洞,使得报错的时候函数不返回任何值。但是我们仍然可以使用这个漏洞对使用老版本php的网站进行渗透测试。    
     
    payload:?a[]=
    传入一个数组

    疑问:是不是get传入的参数,除了字符串和数组没别的了,PHP数据类型有:字符串、整数、浮点数、逻辑、数组、对象、NULL。怎么传入其他类型呢?

    0x03、urldecode二次编码绕过

    <?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]);
    定义和用法
    eregi()函数在一个字符串搜索指定的模式的字符串。搜索不区分大小写。Eregi()可以特别有用的检查有效性字符串,如密码。

    可选的输入参数规则包含一个数组的所有匹配表达式,他们被正则表达式的括号分组。

    返回值
    如果匹配成功返回true,否则,则返回false

     
    url编码
    hackerDJ经过URL编码之后为%68%61%63%6B%65%72%44%4A
    但是id=%68%61%63%6B%65%72%44%4A时,浏览器会自动解码为hackerDJ,则第一个if成立,出不了答案,
    所以讲%68%61%63%6B%65%72%44%4A这一串在经过URL编码一次%2568%2561%2563%256B%2565%2572%2544%254A
    payload:id=%2568%2561%2563%256B%2565%2572%2544%254A
    浏览器自动解码为%68%61%63%6B%65%72%44%4A,之后代码urldecode()在解码一遍得hackerDJ
     

    0x04、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);
    else
    print 'Invalid password';
    }
    ?>

    PHP中md5函数

    (1)在PHP中,MD5是不能处理数组的
    md5(数组)会返回null,所以md5(a[])==null,md5(b[])==null,md5(a[])=md5(b[])=null

    (2)

    0e开头的MD5值,在PHP中被解析为0
     
    s878926199a
    0e545993274517709034328855841020
    s155964671a
    0e342768416822451524974117254469
    s214587387a
    0e848240448830537924465865611904
    s214587387a
    0e848240448830537924465865611904
    s878926199a
    0e545993274517709034328855841020
    s1091221200a
    0e940624217856561557816327384675
    s1885207154a
    0e509367213418206700842008763514
    s1502113478a
    0e861580163291561247404381396064
    s1885207154a
    0e509367213418206700842008763514
    s1836677006a
    0e481036490867661113260034900752
    s155964671a
    0e342768416822451524974117254469
    s1184209335a
    0e072485820392773389523109082030
    s1665632922a
    0e731198061491163073197128363787
    s1502113478a
    0e861580163291561247404381396064
    s1836677006a
    0e481036490867661113260034900752
    s1091221200a
    0e940624217856561557816327384675
    s155964671a
    0e342768416822451524974117254469
    s1502113478a
    0e861580163291561247404381396064
    s155964671a
    0e342768416822451524974117254469
    s1665632922a
    0e731198061491163073197128363787
    s155964671a
    0e342768416822451524974117254469
    s1091221200a
    0e940624217856561557816327384675
    s1836677006a
    0e481036490867661113260034900752
    s1885207154a
    0e509367213418206700842008763514
    s532378020a
    0e220463095855511507588041205815
    s878926199a
    0e545993274517709034328855841020
    s1091221200a
    0e940624217856561557816327384675
    s214587387a
    0e848240448830537924465865611904
    s1502113478a
    0e861580163291561247404381396064
    s1091221200a
    0e940624217856561557816327384675
    s1665632922a
    0e731198061491163073197128363787
    s1885207154a
    0e509367213418206700842008763514
    s1836677006a
    0e481036490867661113260034900752
    s1665632922a
    0e731198061491163073197128363787
    s878926199a
    0e545993274517709034328855841020

    这题payload:?username[]=1&password[]=1

    不知道为什么把username和password赋值成php认为md5值为0的数不可以???

     知道为什么了MD5强碰撞和弱碰撞的区别

    借鉴https://www.jianshu.com/p/2cb9253a0da1

    0x05、数组返回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';
    }
    ?>

    ereg ("^[a-zA-Z0-9]+$", $_GET['password'])这句话的意思是:在password中匹配字母和数字,下面alphanumeric:字母数字

    ^字符串开始的意思,$字符串结束,[a-zA-Z0-9]所有字母数字,+是重复一次或多次

    strpos() 函数查找字符串在另一字符串中第一次出现的位置。

    注释:strpos() 函数对大小写敏感。

    注释:该函数是二进制安全的。

    相关函数:

    stripos() - 查找字符串在另一字符串中第一次出现的位置(不区分大小写)

    strripos() - 查找字符串在另一字符串中最后一次出现的位置(不区分大小写)

    strrpos() - 查找字符串在另一字符串中最后一次出现的位置(区分大小写)

     
    返回值:

    返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。

    注释:字符串位置从 0 开始,不是从 1 开始。

     

    突破点:

    ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE
    1
    字符串对比解析
    在这里如果 $_GET[‘password’]为数组,则返回值为NULL
    如果为123 || asd || 12as || 123%00&&&**,则返回值为true
    其余为false
     
    payload为?password[]=--
     

    0x06、弱类型整数大小比较绕过

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

    ?:    表达式1?表达式2:表达式3 如果表达式1成了,结果为表达式2否则为表达式3

    payload为?password[]=1337

    不知道为什么???

    还有一种:

    is_numeric()判断变量是否为数字或数字字符串

    解题思路:is_numeric()函数对于空字符%00,无论是%00放在前后都可以判断为非数值,而%20空格字符只能放在数值后。所以,查看函数发现该函数对于第一个空格字符会跳过空格字符判断,接着后面的判断

    payload为?password=1337%00

    0x07、sha()函数比较绕过

     源代码:

    <?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!

    ';
    ?>
    代码很简单,目的就是get传入参数name和password,两个参数不能相等但是sha1值要相等
    这里开始随白那猜测了一下应该和MD5()函数漏洞类似,因为都是hash函数
    payload:name[]=1&password[]=2,成功 

    0x08:MD5加密相等绕过

    <?php
    $md51 = md5('QNKCDZO');
    $a = @$_GET['a'];
    $md52 = @md5($a);
    if(isset($a)){
    if ($a != 'QNKCDZO' && $md51 == $md52) {
    echo "flag{*}";
    } else {
    echo "false!!!";
    }}
    else{echo "please input a";}
    ?>
    MD51="0e830400451993494058024219903391"
    php中md5把以0e开头的MD5值看作相等
    240610708、s878926199a、s155964671a、s214587387a、s214587387a这些值MD5后都是以0e开头
    payload:a=s214587387a

    0x09:十六进制与数字比较

    <?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);
    ?> 
    要求是get传入参数password,password要等于“3735929054”,其中的某一位的ascii码值不能[49,57]这个区间内
    payload:password=0xdeadc0de
    PHP在转码时会自动把十六进制转换成十进制

    0x10:变量覆盖

    我做的时候网站好像无法访问了,copy其他人的过程

    payload:?shiyan=&flag

     链接是下一题的http://123.206.87.240:9009/5.php。改成
    http://123.206.87.240:9009/1.php?shiyan=&flag

    0x11:ereg正则%00截断

    <?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

    ';
    }
    }
    ?>
     1)^[a-zA-Z0-9]+$正则表达式
    ^是字符开始的意思;[a-zA-Z0-9]是值数字和字母;+是值前面的数字字母出现重复一次或多次;$是指字符串结束
    条件2:长度小于8,值大于9999999
    条件3:password中必须有“-”
     2)ereg()函数两个漏洞

    ①%00截断及遇到%00则默认为字符串的结束 ②当参数为数组时它的返回值不是FALSE

     3)要大于9999999,用科学计数法1e8=10^8;1e9=10^9
    payload:password=1e9%00*-*

     0x12: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);
    else
    echo '骚年,继续努力吧啊~';
    }
    ?>
     数组-_-
    payloads:ctf[]=1

    0x13:数字验证正则绕过

    <?php
    error_reporting(0);
    $flag = 'flag{test}';
    if ("POST" == $_SERVER['REQUEST_METHOD'])
    {
    $password = $_POST['password'];
    if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password)) //preg_match — 执行一个正则表达式匹配
    {
    echo 'flag';
    exit;
    }
    while (TRUE)
    {
    $reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
    if (6 > preg_match_all($reg, $password, $arr))
    break;
    $c = 0;
    $ps = array('punct', 'digit', 'upper', 'lower'); //[[:punct:]] 任何标点符号 [[:digit:]] 任何数字 [[:upper:]] 任何大写字母 [[:lower:]] 任何小写字母
    foreach ($ps as $pt)
    {
    if (preg_match("/[[:$pt:]]+/", $password))
    $c += 1;
    }
    if ($c < 3) break;
    //>=3,必须包含四种类型三种与三种以上
    if ("42" == $password) echo $flag;
    else echo 'Wrong password';
    exit;
    }
    }
    ?>
    1)[:graph:] 是指可见字符(即除空格、控制字符等外的任何字符)
    2){12,}至少匹配12次
    参数的值位数小于12就可以了,我觉得其他条件也有必要试一下,下面链接整理的很仔细
    不知道为什么这题随便构造payload都能有答案,是题目有问题还是本身就这样没搞懂
    这里借鉴别人的,整理的很仔细
    我觉得这种学习精神我应该好好学习。
    3)知识点:
    ①preg_match:执行一个正则表达式匹配,匹配到就返回1,否则返回0
    preg_match_all:执行一个全局正则表达式匹配,返回成功模式匹配的次数,并将结果存到一个数组中
    ②$reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';

    if (6 > preg_match_all($reg, $password, $arr))
    break;

    这个句子的意思、作用
    reg还是正则表达式,同[:graph:]
    eg:参数a2*8返回

    0x14:简单的waf

    网站无法访问,百度到的

    $a=isset($_GET["a"])?$_GET["a"]:'';
    $b=isset($_GET["b"])?$_GET["b"]:'';
    $c=isset($_GET["c"])?$_GET["c"]:'';
    $d=isset($_GET["d"])?$_GET["d"]:'';
    $e=isset($_GET['e'])?$_GET['e']:'';

    if(preg_match('/php/i', $a)){
    die("This not allow pseudo protocol!");
    }
    if(preg_match('/../', $a)){
    die("This also not allow!");
    }

    if((file_get_contents($a,'r')===$b)&&(file_get_contents($e,'r')==="I'm Administrator!")){
    echo "hello admin!<br>";
    if(preg_match("/flag/",$c)){
    echo "不能现在就给你flag哦";
    exit();
    }else{
    include($c);
    if(preg_match('/base64/', $d)){
    die("No! you can't use it!");
    }
    $d = unserialize($d);
    echo $d;
    }
    }else{
    echo "you are not admin ! <br>";
    }

    首先要求a和b相同,e是I'm Administrator!,因为有两个地方有file_get_contets函数,而且a过滤了php

    所以我现在服务器放个1.txt文件,内容写1,然后这个就能让a和b相等了,e用php://filter伪协议,c也可以用伪协议

    可以看到,现在已经是可以绕过a和b的限制了,但是剩下的后台应该是有点问题,c没有触发waf,却没有回显,无法继续下去了

    ---------------------
    版权声明:本文为CSDN博主「Xi4or0uji」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/xiaorouji/article/details/82292233

    0xff:总结

    2019/8/12暑假无聊,翻看自己的印象笔记和博客园看到博客园里的一篇草稿(就是这篇),哈哈不知道什么时候存的没有发。突然也发现我记录的东西好像没什么用,我自己都觉得没什么营养。以后多记录一点测试流程或者靶场练习(60%);当然比赛记录也要有偏少,尽量实战(40%),这也是我现在的学习侧重点。
    并且要保证笔记质量,有图有文字,漏洞原理、利用方法怎么防御都要有。
  • 相关阅读:
    HDUOJ--4565 So Easy!
    简单的java实验,涉及到 类继承以及接口问题,方法体的重写(区别于重载)
    java 快速求素数
    狄斯奎诺(dijkstra 模板)
    2014 蓝桥杯 阶梯报告(含代码 详细讲解)
    HDUOJ---汉洛塔IX
    小错误系列
    HDUOJ-----4510 小Q系列故事——为什么时光不能倒流
    HDUOJ----4509湫湫系列故事——减肥记II
    HDUOJ-----4506小明系列故事——师兄帮帮忙
  • 原文地址:https://www.cnblogs.com/liqik/p/11148270.html
Copyright © 2011-2022 走看看