dvwa靶场

登录进入dvwa默认账号密码: 账号–admin,密码–password

Brute Force

Low

随意在登陆框输入,之后打开bp抓包。

放到intrude测试器模块

1.点击清除把所有变量清除
2.分别双击输入的用户名和密码,点击添加,变为有效载荷
3.选择攻击类型,攻击类型有四种,这里出于实际情况,这里选择第四种集束炸弹的模式

Sniper: 单参数爆破,多参数时使用同一个字典按顺序替换各参数,只有一个数据会被替换
Battering ram: 多参数同时爆破,但用的是同一个字典,每个参数数据都是一致的
Pichfork: 多参数同时爆破,但用的是不同的字典,不同字典间数据逐行匹配
Cluster bamb: 多参数做笛卡尔乘积模式爆破

载入字典开始进行爆破

根据爆破里面的长短来判断哪个是正确的账号密码

源码分析:

  1. 首先,它检查是否存在名为"Login"的GET参数,以确定用户是否尝试进行登录。

  2. 如果存在"Login"参数,则获取通过GET方法传递的用户名和密码,并使用md5()函数对密码进行哈希处理。

  3. 接下来,代码构建一个SQL查询语句,使用用户提供的用户名和哈希后的密码来查询数据库中的用户表。

  4. 使用mysqli_query()函数执行查询,并将结果存储在变量$result中。

  5. 如果查询成功且返回的结果集中有且仅有一行数据(即存在匹配的用户名和密码),则表示登录成功。

  6. 在登录成功的情况下,代码从结果集中提取用户的详细信息,包括头像URL,并将其显示在页面上。

  7. 如果登录失败(即没有匹配的用户名和密码),则输出错误消息。

  8. 最后,代码关闭与数据库的连接。

Meduim

Meduim步骤与Low中的相同,但是在Meduim中对登录失败后进行了两秒的休眠。导致延长了爆破时间。

在这个版本中,代码添加了以下改进:

  1. 对用户名和密码进行了SQL注入防护。使用mysqli_real_escape_string()函数对输入的用户名和密码进行转义,以防止恶意输入破坏SQL查询。

  2. 增加了一个延迟2秒的sleep()函数调用。这是为了增加反爬虫功能,防止暴力破解密码的攻击。

High 

在这个版本中,代码添加了以下改进:

  1. 添加了一个checkToken()函数来验证Anti-CSRF令牌。它比较传递的用户令牌和会话令牌,如果不匹配,则可能是CSRF攻击,将重定向到指定的页面。

  2. 使用stripslashes()函数对用户名和密码进行了处理,以防止反斜杠被添加。

  3. 增加了一个随机延迟,使用sleep()函数和rand()函数,使登录失败的情况下的延迟时间在0到3秒之间随机选择,进一步增强了反爬虫功能。

  4. 添加了一个generateSessionToken()函数来生成Anti-CSRF令牌,并将其存储在会话中。

这个前面步骤相同到这里

设置token参数:

跳转到Resource pool选项页面
修改线程为1,大于1可能会有问题,因为token是每次验证完后才会新生成token,所以不能使用多线程进行爆破

之后跳转到options界面:

点击add之后返回到payloads界面

还是根据长度来区分。

impossible

最难的难度增加账户锁定机制,防止爆破

源码:

<?php

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

    // Sanitise username input
    $user = $_POST[ '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 = $_POST[ '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 );

    // Default values
    $total_failed_login = 3;
    $lockout_time       = 15;
    $account_locked     = false;

    // Check the database (Check user information)
    $data = $db->prepare( 'SELECT failed_login, last_login FROM users WHERE user = (:user) LIMIT 1;' );
    $data->bindParam( ':user', $user, PDO::PARAM_STR );
    $data->execute();
    $row = $data->fetch();

    // Check to see if the user has been locked out.
    if( ( $data->rowCount() == 1 ) && ( $row[ 'failed_login' ] >= $total_failed_login ) )  {
        // User locked out.  Note, using this method would allow for user enumeration!
        //echo "<pre><br />This account has been locked due to too many incorrect logins.</pre>";

        // Calculate when the user would be allowed to login again
        $last_login = strtotime( $row[ 'last_login' ] );
        $timeout    = $last_login + ($lockout_time * 60);
        $timenow    = time();

        /*
        print "The last login was: " . date ("h:i:s", $last_login) . "<br />";
        print "The timenow is: " . date ("h:i:s", $timenow) . "<br />";
        print "The timeout is: " . date ("h:i:s", $timeout) . "<br />";
        */

        // Check to see if enough time has passed, if it hasn't locked the account
        if( $timenow < $timeout ) {
            $account_locked = true;
            // print "The account is locked<br />";
        }
    }

    // Check the database (if username matches the password)
    $data = $db->prepare( 'SELECT * FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
    $data->bindParam( ':user', $user, PDO::PARAM_STR);
    $data->bindParam( ':password', $pass, PDO::PARAM_STR );
    $data->execute();
    $row = $data->fetch();

    // If its a valid login...
    if( ( $data->rowCount() == 1 ) && ( $account_locked == false ) ) {
        // Get users details
        $avatar       = $row[ 'avatar' ];
        $failed_login = $row[ 'failed_login' ];
        $last_login   = $row[ 'last_login' ];

        // Login successful
        echo "<p>Welcome to the password protected area <em>{$user}</em></p>";
        echo "<img src=\"{$avatar}\" />";

        // Had the account been locked out since last login?
        if( $failed_login >= $total_failed_login ) {
            echo "<p><em>Warning</em>: Someone might of been brute forcing your account.</p>";
            echo "<p>Number of login attempts: <em>{$failed_login}</em>.<br />Last login attempt was at: <em>{$last_login}</em>.</p>";
        }

        // Reset bad login count
        $data = $db->prepare( 'UPDATE users SET failed_login = "0" WHERE user = (:user) LIMIT 1;' );
        $data->bindParam( ':user', $user, PDO::PARAM_STR );
        $data->execute();
    } else {
        // Login failed
        sleep( rand( 2, 4 ) );

        // Give the user some feedback
        echo "<pre><br />Username and/or password incorrect.<br /><br/>Alternative, the account has been locked because of too many failed logins.<br />If this is the case, <em>please try again in {$lockout_time} minutes</em>.</pre>";

        // Update bad login count
        $data = $db->prepare( 'UPDATE users SET failed_login = (failed_login + 1) WHERE user = (:user) LIMIT 1;' );
        $data->bindParam( ':user', $user, PDO::PARAM_STR );
        $data->execute();
    }

    // Set the last login time
    $data = $db->prepare( 'UPDATE users SET last_login = now() WHERE user = (:user) LIMIT 1;' );
    $data->bindParam( ':user', $user, PDO::PARAM_STR );
    $data->execute();
}

// Generate Anti-CSRF token
generateSessionToken();

?>

  1. 首先,代码检查是否已提交表单($_POST['Login']),以及usernamepassword字段是否设置。如果满足这些条件,登录过程开始执行。

  2. 代码调用checkToken函数来验证防跨站请求伪造(CSRF)令牌。它将表单中提交的令牌($_REQUEST['user_token'])与会话中存储的令牌($_SESSION['session_token'])进行比较。checkToken函数可能执行此比较,并在令牌不匹配时采取适当的措施。

  3. 代码对usernamepassword输入进行了净化处理,使用stripslashesmysqli_real_escape_string函数来防止SQL注入攻击。但需要注意的是,mysqli_real_escape_string函数已被弃用,推荐使用预处理语句或参数化查询来代替。

  4. 代码设定了一些与登录失败和账户锁定相关的默认值。

  5. 代码查询数据库,检查用户是否存在以及账户是否因登录失败次数过多而被锁定。它从数据库中获取指定usernamefailed_loginlast_login值。

  6. 如果用户账户被锁定(即数据库中的failed_login大于等于设定的失败登录次数),代码计算用户下次允许登录的时间。它通过将last_login时间与锁定时间间隔相加来计算。然后,它获取当前时间,并与计算出的时间进行比较。

  7. 代码再次查询数据库,检查usernamepassword是否匹配。它从users表中检索所有列,其中user列匹配提供的usernamepassword列匹配提供的password的MD5哈希值。

  8. 如果登录有效(即查询返回一行)且账户未被锁定,代码获取用户的详细信息,如avatarfailed_loginlast_login。然后,它显示欢迎消息和用户的头像。

  9. 如果账户在上次登录后被锁定,代码显示警告消息、登录尝试次数和上次尝试的时间。

  10. 代码更新数据库中的failed_login列,将失败登录计数重置为0。

  11. 如果登录无效(即查询返回0行)或账户被锁定,代码使用sleep函数引入延迟(2到4秒),以减缓暴力破解尝试。然后,它向用户显示一条包含登录失败原因的消息。

  12. 代码再次更新数据库中的failed_login列,将失败登录计数加1。

  13. 最后,代码更新数据库中的last_login列,将其设置为当前时间,以记录用户的最后登录时间。

  14. 在处理登录表单之前,代码调用generateSessionToken函数生成一个新的会话令牌,并将其存储在$_SESSION['session_token']中。这个令牌用于验证防止跨站请求伪造。

Command Injection 

Low

这里让输入一个ip地址,写127.0.0.1

一片红的乱码,所以要打开靶场里面的dvwaPage.ini.php文件,在文件中ctrl+f,用搜索栏查找utf-8,将UTF-8改为GBK或者GB2312。

源码:

  1. 首先,代码检查是否已提交表单($_POST['Submit'])。只有在提交表单时才会执行后续的代码。

  2. 代码获取用户输入的目标IP地址($_REQUEST['ip'])。

  3. 代码使用php_uname('s')函数确定操作系统类型。如果操作系统是Windows NT,则执行Windows系统的ping命令;否则,执行*nix系统的ping命令。

  4. 代码使用shell_exec函数执行ping命令,并将结果赋给变量$cmdshell_exec函数用于执行系统命令,并返回命令的输出。

  5. 最后,代码将ping命令的结果以预格式化文本的形式输出给用户,使用echo语句和<pre>标签将结果包裹起来。

Medium

  1. 首先,代码检查是否已提交表单($_POST['Submit'])。只有在提交表单时才会执行后续的代码。

  2. 代码获取用户输入的目标IP地址($_REQUEST['ip'])。

  3. 代码定义了一个黑名单数组$substitutions,其中包含一些特殊字符的替代项。这些特殊字符包括&&;,它们通常用于命令注入攻击。

  4. 代码使用str_replace函数将目标IP地址中的黑名单字符替换为空字符串。这样做的目的是移除用户输入中的特殊字符,以减少命令注入的风险。

  5. 代码使用php_uname('s')函数确定操作系统类型。如果操作系统是Windows NT,则执行Windows系统的ping命令;否则,执行*nix系统的ping命令。

  6. 代码使用shell_exec函数执行ping命令,并将结果赋给变量$cmd。这里改进的地方是,在目标IP地址经过过滤后再用于构造命令,减少了命令注入的可能性。

  7. 最后,代码将ping命令的结果以预格式化文本的形式输出给用户,使用echo语句和<pre>标签将结果包裹起来。

这一个使用127.0.0.1&dir即可

High

这段代码是在之前改进的基础上进一步增强了安全性的PHP脚本。

  1. 首先,代码检查是否已提交表单($_POST['Submit'])。只有在提交表单时才会执行后续的代码。

  2. 代码获取用户输入的目标IP地址($_REQUEST['ip']),并使用trim函数去除输入字符串的首尾空格。

  3. 代码定义了一个黑名单数组$substitutions,其中包含一些特殊字符的替代项。这些特殊字符包括&;|-、空格、()`||,它们常用于命令注入和其他攻击。

  4. 代码使用str_replace函数将目标IP地址中的黑名单字符替换为空字符串。这样做的目的是移除用户输入中的特殊字符,以进一步减少命令注入的风险。

  5. 代码使用php_uname('s')函数确定操作系统类型。如果操作系统是Windows NT,则执行Windows系统的ping命令;否则,执行*nix系统的ping命令。

  6. 代码使用shell_exec函数执行ping命令,并将结果赋给变量$cmd。这里同样注意到,在目标IP地址经过过滤后再用于构造命令,以减少命令注入的可能性。

  7. 最后,代码将ping命令的结果以预格式化文本的形式输出给用户,使用echo语句和<pre>标签将结果包裹起来。

这个使用127.0.0.1|dir即可。

impossible

这段代码是在之前的基础上进一步增强了安全性的PHP脚本。

  1. 首先,代码检查是否已提交表单($_POST['Submit'])。只有在提交表单时才会执行后续的代码。

  2. 代码调用checkToken函数来验证反跨站请求伪造(Anti-CSRF)令牌。该函数接受三个参数:用户提交的令牌($_REQUEST['user_token'])、会话中的令牌($_SESSION['session_token'])和重定向的页面('index.php')。这样可以确保表单提交是合法的,并防止跨站请求伪造攻击。

  3. 代码获取用户输入的目标IP地址($_REQUEST['ip']),并使用stripslashes函数去除可能的反斜杠转义。

  4. 代码使用explode函数将目标IP地址按照.分割成4个部分(octet)。

  5. 代码使用is_numeric函数检查每个octet是否为数字,并且检查octet的数量是否为4。这样可以验证用户输入的IP地址是否符合预期的格式。

  6. 如果所有4个octet都是数字,并且octet的数量为4,则将IP地址重新组合。

  7. 代码使用php_uname('s')函数确定操作系统类型。如果操作系统是Windows NT,则执行Windows系统的ping命令;否则,执行*nix系统的ping命令。

  8. 代码使用shell_exec函数执行ping命令,并将结果赋给变量$cmd。这里同样注意到,在目标IP地址经过验证后再用于构造命令,以减少命令注入的可能性。

  9. 最后,代码将ping命令的结果以预格式化文本的形式输出给用户,使用echo语句和<pre>标签将结果包裹起来。

  10. 如果用户输入的IP地址不符合预期的格式,代码将输出一个错误提示。

  11. 在代码的末尾,调用generateSessionToken函数生成Anti-CSRF令牌,以便在下次请求时进行验证。

CSRF 

Low

在输入要更改的密码后,有回显更改成功,在url里http://127.0.0.1/DVWA/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change# 可以分析出password_new是输入的密码,password_conf是确认的密码,说明我们在网站上输入的信息是会在url栏这里进行一个传输执行

在url里修改密码确认密码,在新标签页里进行访问http://127.0.0.1/DVWA/vulnerabilities/csrf/?password_new=987654&password_conf=987654&Change=Change#

网站跳转,并且有修改成功之后的回显,说明攻击成功

源码:

  1. 首先,代码检查是否已提交表单($_GET['Change'])。只有在提交表单时才会执行后续的代码。

  2. 代码获取用户输入的新密码($_GET['password_new'])和确认密码($_GET['password_conf'])。

  3. 代码检查新密码和确认密码是否匹配。

  4. 如果新密码和确认密码匹配,代码执行以下操作:

    • 使用mysqli_real_escape_string函数对新密码进行转义,以防止SQL注入攻击。
    • 使用md5函数对新密码进行哈希处理,以增加密码的安全性。
    • 构造一个SQL语句,将新密码更新到数据库中的users表中,使用当前用户(dvwaCurrentUser())作为条件。
    • 执行SQL语句,并将结果赋给变量$result
    • 输出一个成功提示给用户。
  5. 如果新密码和确认密码不匹配,代码输出一个密码不匹配的错误提示给用户。

  6. 在代码的末尾,使用mysqli_close函数关闭数据库连接。

这段代码在处理密码更改时,对新密码进行了一些安全处理,如转义和哈希处理。然而,这段代码仍然存在一些安全风险:

  • 使用md5进行密码哈希处理已经不是最佳实践,推荐使用更安全的哈希算法,如bcrypt或Argon2。
  • 代码中使用了mysqli_real_escape_string对新密码进行转义,但更好的做法是使用参数化查询来处理SQL语句,以避免SQL注入攻击。
  • 代码没有对输入进行验证,如密码长度、复杂度要求等。

Medium 

  1. 首先,代码检查是否已提交表单($_GET['Change'])。只有在提交表单时才会执行后续的代码。

  2. 代码使用stripos函数检查请求的来源是否包含服务器的域名($_SERVER['SERVER_NAME'])。这样可以验证请求是否来自于预期的源,以防止跨站请求伪造(CSRF)攻击。

  3. 如果请求的来源是预期的域名,代码执行以下操作:

    • 获取用户输入的新密码($_GET['password_new'])和确认密码($_GET['password_conf'])。
    • 检查新密码和确认密码是否匹配。
    • 如果新密码和确认密码匹配,代码执行与之前相同的操作。
    • 如果新密码和确认密码不匹配,代码输出一个密码不匹配的错误提示给用户。
  4. 如果请求的来源不是预期的域名,代码输出一个请求不正确的错误提示给用户。

  5. 在代码的末尾,使用mysqli_close函数关闭数据库连接。

源码是通过referrer这个字段的参数进行判断的,通常情况下在增加referrer验证时就是网站本身当前页面的ip地址,通过抓包查看信息

在新的标签页中打开http://127.0.0.1/DVWA/vulnerabilities/csrf/?password_new=987654&password_conf=987654&Change=Change#,并进行抓包,可以发现没有referer,需要进行伪造,Referer: http://127.0.0.1/DVWA/vulnerabilities/csrf/ ,然后放包,即可。

High 

  1. 代码首先初始化一些变量,包括$change(用于标记是否进行密码更改)、$request_type(请求类型,初始为"html")和$return_message(返回的消息,初始为"Request Failed")。

  2. 代码通过检查请求方法($_SERVER['REQUEST_METHOD'])和内容类型($_SERVER['CONTENT_TYPE'])来确定请求的类型。如果请求方法是POST且内容类型是JSON,则将请求类型设置为"json",并解析JSON数据。

  3. 如果是JSON请求类型,并且请求中包含了必要的参数(HTTP_USER_TOKENpassword_newpassword_confChange),则将相关数据赋值给相应的变量。

  4. 如果不是JSON请求类型,代码检查请求中是否包含了必要的参数(user_tokenpassword_newpassword_confChange),如果存在,则将相关数据赋值给相应的变量。

  5. 如果满足进行密码更改的条件,代码执行以下操作:

    • 检查防CSRF令牌的有效性,调用checkToken函数进行验证。
    • 检查新密码和确认密码是否匹配。
    • 如果匹配,对新密码进行转义和哈希处理,然后更新数据库中的密码。
    • 根据请求类型设置返回消息。
    • 关闭数据库连接。
  6. 如果请求类型是JSON,代码生成新的防CSRF令牌,设置响应头的内容类型为JSON,并输出包含返回消息的JSON数据。然后退出程序。

  7. 如果请求类型不是JSON,代码生成新的防CSRF令牌,并以HTML格式输出返回消息。

可以看出high等级的主要区别是增加了一个token值的校验,每次登录都会校验token是否正确,若想要执行更改密码操作必须知道正常用户的token

因为该请求是get请求,所以token验证会被放在请求URL中,随便输入密码验证一下,可以看到,在请求的URL中最末尾加入了token 

进行抓包,使用burpsuite中的从csrf token tracker

有了这个插件之后,每次重放这个数据包都会自动更新user_token

设置对应的参数,返回repeater模块即可修改成功。

impossible

  1. 代码首先检查是否存在$_GET['Change']参数,以确定是否进行密码更改。

  2. 代码调用checkToken函数来验证防CSRF令牌的有效性,使用$_REQUEST['user_token']$_SESSION['session_token']作为参数。

  3. 代码获取输入的当前密码($_GET['password_current'])、新密码($_GET['password_new'])和确认密码($_GET['password_conf'])。

  4. 代码对当前密码进行处理,使用stripslashes函数去除可能存在的反斜杠,然后使用mysqli_real_escape_string函数进行转义,最后使用md5函数进行哈希处理。

  5. 代码使用预处理语句和参数化查询来检查当前密码是否正确,查询数据库中与当前用户和当前密码匹配的记录数。

  6. 如果新密码和确认密码匹配,并且当前密码正确(记录数为1),代码执行以下操作:

    • 对新密码进行处理,使用stripslashes函数去除反斜杠,然后使用mysqli_real_escape_string函数进行转义,最后使用md5函数进行哈希处理。
    • 使用预处理语句和参数化查询更新数据库中的密码。
    • 输出一个密码已更改的消息给用户。
  7. 如果新密码和确认密码不匹配,或者当前密码不正确(记录数不为1),代码输出一个密码不匹配或当前密码不正确的消息给用户。

  8. 在代码的末尾,生成新的防CSRF令牌。

这个要求先知道旧密码才能改动。

File Inclusion

Low

可以直接查看文件

Medium 

  1. 代码首先从$_GET['page']获取要显示的页面。

  2. 代码使用str_replace函数替换输入中的一些字符串,包括将"http://""https://"替换为空字符串,将"../"和"..\\"替换为空字符串。

可以通过输入绝对路径绕过

High

  1. 代码首先从$_GET['page']获取要显示的页面。

  2. 代码使用条件语句进行输入验证。条件语句中使用了fnmatch函数来比较输入的值是否匹配模式"file*",并且输入的值不等于"include.php"

  3. 如果输入的值不匹配模式"file*"且不等于"include.php",代码输出错误消息"ERROR: File not found!",然后使用exit函数终止脚本的执行。

输入?page=file4.php

impossible

  1. 代码首先从$_GET['page']获取要显示的页面。

  2. 代码使用条件语句进行输入验证。条件语句中使用了多个逻辑运算符&&来比较输入的值是否等于"include.php""file1.php""file2.php""file3.php"

  3. 如果输入的值不等于上述任何一个值,代码输出错误消息"ERROR: File not found!",然后使用exit函数终止脚本的执行。

File Upload

Low

没有过滤,可直接上传

Medium

  1. if( isset( $_POST[ 'Upload' ] ) ) { ... }
    这个条件语句检查是否有名为"Upload"的表单字段提交。它用于确定是否有文件上传请求。

  2. $target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
    $target_path变量指定上传文件的目标路径。它使用了一个名为DVWA_WEB_PAGE_TO_ROOT的常量,这个常量可能在其他地方定义了。

  3. $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
    这一行将上传文件的基本名称附加到$target_path变量的末尾,以确定最终的目标文件路径。

  4. $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
    $uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
    $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
    这些变量分别存储上传文件的名称、类型和大小。它们从$_FILES数组中获取,$_FILES是PHP中用于处理文件上传的预定义变量。

  5. if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) && ( $uploaded_size < 100000 ) ) { ... }
    这个条件语句检查上传文件的类型和大小是否满足要求。只有当文件类型为JPEG或PNG,并且文件大小小于100,000字节(约100KB)时,才会执行条件语句块内的代码。

  6. if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) { ... }
    这个条件语句使用move_uploaded_file函数将上传的临时文件移动到目标路径。如果移动文件失败,则会执行条件语句块内的代码。

  7. echo '<pre>Your image was not uploaded.</pre>';
    这行代码在文件上传失败时输出错误消息。

  8. echo "<pre>{$target_path} succesfully uploaded!</pre>";
    这行代码在文件上传成功时输出成功消息,并显示上传后的文件路径。

  9. echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
    这行代码在上传的文件类型不符合要求时输出错误消息。

对文件类型和大小做出了限制   必须是jpeg 或者 png

使用burpsuite抓包进行修改

High

  1. if( isset( $_POST[ 'Upload' ] ) ) { ... }
    这个条件语句检查是否有名为"Upload"的表单字段提交。它用于确定是否有文件上传请求。

  2. $target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
    $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
    这两行代码与之前的代码相同,用于指定上传文件的目标路径和最终的目标文件路径。

  3. $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' ];
    这些变量与之前的代码相同,用于存储上传文件的名称、扩展名、大小和临时文件路径。

  4. if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) && ( $uploaded_size < 100000 ) && getimagesize( $uploaded_tmp ) ) { ... }
    这个条件语句进行了一些改进。它使用strtolower函数将上传文件的扩展名转换为小写,并检查扩展名是否为"jpg"、"jpeg"或"png"。它还检查文件大小是否小于100,000字节,并使用getimagesize函数验证文件是否为有效的图像文件。

  5. if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) { ... }
    这个条件语句与之前的代码相同,用于将上传的临时文件移动到目标路径。

  6. echo '<pre>Your image was not uploaded.</pre>';
    这行代码在文件上传失败时输出错误消息。

  7. echo "<pre>{$target_path} succesfully uploaded!</pre>";
    这行代码在文件上传成功时输出成功消息,并显示上传后的文件路径。

  8. echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
    这行代码在上传的文件类型不符合要求时输出错误消息。

getimagesize(string filename)
函数会通过读取文件头,返回图片的长、宽等信息,如果没有相关的图片文件头,函数会报错。
可以看到,High级别的代码读取文件名中最后一个”.”后的字符串,期望通过文件名来限制文件类型,因此要求上传文件名形式必须是”*.jpg”所以制作图片马,将图片与木马合并为图片

impossible 

  1. checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
    这行代码调用了一个名为checkToken的函数,用于验证Anti-CSRF令牌。它比较了来自请求的user_token和存储在会话中的session_token,以确保请求是合法的。

  2. $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' ];
    这些变量与之前的代码相同,用于存储上传文件的名称、扩展名、大小、类型和临时文件路径。

  3. $target_path = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/';
    $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;
    这些变量用于指定上传文件的目标路径、目标文件名和临时文件路径。目标文件名使用了一个唯一的文件名,以确保文件名的唯一性。

  4. 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 ) ) { ... }
    这个条件语句进行了一些改进。它检查文件的扩展名、大小、类型和是否为有效的图像文件。只有当文件满足这些条件时,才会执行条件语句块内的代码。

  5. if( $uploaded_type == 'image/jpeg' ) { ... } else { ... }
    这个条件语句根据上传文件的类型,使用imagecreatefromjpeg函数或imagecreatefrompng函数创建图像对象,并将图像重新编码为JPEG或PNG格式。这样可以去除图像中的任何元数据,增加安全性。

  6. if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) { ... }
    这个条件语句使用rename函数将临时文件移动到目标路径,并使用唯一的目标文件名。如果移动文件成功,则会执行条件语句块内的代码。

  7. echo "<pre><a href='{$target_path}{$target_file}'>{$target_file}</a> succesfully uploaded!</pre>";
    这行代码在文件上传成功时输出成功消息,并显示上传后的文件链接。

  8. echo '<pre>Your image was not uploaded.</pre>';
    这行代码在文件上传失败时输出错误消息。

  9. if( file_exists( $temp_file ) ) unlink( $temp_file );
    这行代码用于删除临时文件。

  10. generateSessionToken();
    这行代码调用了一个名为generateSessionToken的函数,用于生成Anti-CSRF令牌,并将其存储在会话中。

Impossible级别的代码对上传文件进行了重命名(为md5值,导致%00截断无法绕过过滤规则),加入Anti-CSRF token防护CSRF攻击,同时对文件的内容作了严格的检查,导致攻击者无法上传含有恶意脚本的文件。 

SQL Injection

Low

首先在表单中输入1

输入2.

注入点判断,可知受到单引号闭合影响

直接把SQL语句中后续语句全部注释掉不执行,在判断语句后加#或者--+即可,全部注释掉就可以

语句1’ or 1=1#可以查出所有ID内容

找出注入点以及符号问题,然后判断字段

之后结合union联合查询

1. 获取名为"id"的请求变量的值。
2. 使用switch语句根据$_DVWA['SQLI_DB']的值执行不同的数据库查询操作。

如果$_DVWA['SQLI_DB']的值为MYSQL,它会执行以下操作:
1. 构建一个SQL查询语句,从名为"users"的表中选择"first_name"和"last_name"列,条件是"user_id"等于$id的值。
2. 使用mysqli_query函数执行查询,并将结果存储在$result变量中。
3. 使用mysqli_fetch_assoc函数从$result中获取每一行的结果。
4. 将每一行的"first_name"和"last_name"值存储在$first和$last变量中。
5. 使用echo语句将$id、$first和$last的值以HTML格式输出给用户。

如果$_DVWA['SQLI_DB']的值为SQLITE,它会执行以下操作:
1. 声明一个全局变量$sqlite_db_connection,用于存储SQLite数据库连接。
2. 构建一个SQL查询语句,从名为"users"的表中选择"first_name"和"last_name"列,条件是"user_id"等于$id的值。
3. 使用$sqlite_db_connection->query函数执行查询,并将结果存储在$results变量中。
4. 使用while循环从$results中获取每一行的结果。
5. 将每一行的"first_name"和"last_name"值存储在$first和$last变量中。
6. 使用echo语句将$id、$first和$last的值以HTML格式输出给用户。

Medium

(1)判断注入类型     我们可以看到无法输入数字,所以我们进行抓包在bp中进行SQL注入

输入id=1' and '1'='1看见报错了,输入id=1 and 1=1没有报错。所以为数字类型

(2)判断列数

可知为两列

(3)判断显示位可以知道是2

(4)判断数据库

(5)判断表名

(6)判断列名

输入users之后,发现没有如何反应

通过源代码我们可以知道,发现它对单引号进行了转义,我们采用16进制绕过,得知users的十六进制为 0x75736572

(7)获取数据

相比于low级别首先,它使用了mysqli_real_escape_string函数对$id变量进行了转义,以防止特殊字符对SQL查询造成影响。

接下来,它执行与之前相同的操作来获取用户信息并将其显示给用户。

在代码的最后,它执行了另一个查询来获取用户表中的行数,并将结果存储在$number_of_rows变量中。然后,它关闭了数据库连接。

high

首先判断为字符型注入

之后步骤与前面一样

1. 它使用了$_SESSION['id']来获取用户的ID,而不是之前的$_POST['id']。这意味着用户的ID是通过会话(session)来传递的,可能是在登录过程中设置的。

2. 在SQL查询语句中,添加了LIMIT 1来限制结果只返回一行。这是一个好的做法,可以提高查询效率并减少返回结果的数量。

3. 在关闭数据库连接的代码中,使用了((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res)来关闭连接。这是因为之前的mysqli_close函数可能会返回一个布尔值,而不是void。这个改变没有直接的安全影响,只是一种不同的关闭连接的方式。

Impossible

Impossible级别的代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入,同时只有返回的查询结果数量为一时,才会成功输出,这样就有效预防了“脱裤”,Anti-CSRFtoken机制的加入了进一步提高了安全性。

SQL Injection (Blind)

Low

与一般注入的区别是,一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是否执行都无从得知。

输入1显示存在

输入1 and 1=1 或 1 and 1=2均显示存在

输入1' and 1=1 #显示存在(这三种都显示存在)

输入1' and 1=2 #不存在

说明存在注入

1.查数据库前要先判断数据库的长度
依次输入1' and length(database())=x #(x为大于等于1的整数)
当显示存在时即为数据库长度
发现当x=4时显示存在,故数据库长度为4

2.二分法找数据库名
依次输入1' and ascii(substr(databse(),1,1))>或<字母的ascii值 # 通过比较输入字母的ascii值的显示正常与否来逐个确定库名  

3.找数据库中的表
首先确定数据库中表的数量
1' and (select count (table_name) from information_schema.tables where table_schema=database())=x # (x为大于等于1的整数)
当显示存在时即可判断表的数量
最终当x=2显示存在即表的数量为2

然后确定表的长度
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=x #(x为大于等于1的整数)
当显示存在时即可判断表的长度
当x=9显示存在即表的长度为9

然后同样二分法确定表名
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>或<字母的ascii值 #
通过比较输入字母的ascii值的显示正常与否来逐个确定表名   步骤同第二步
4.找字段名

同上一步  先确定数量  再用二分法确定名称

sqlmap
使用sqlmap,用以下命令进行跑包:

python sqlmap.py -u "http://127.0.0.1/DVWA/vulnerabilities/sqli_blind/?id=1&Submit=Submit" --cookie "PHPSESSID=amv13uu59s3bk067v8fphftos0; security=low" --batch

–batch:在进行命令交互式的时候,默认选择为YES

python sqlmap.py -u "http://127.0.0.1/DVWA/vulnerabilities/sqli_blind/?id=1&Submit=Submit" --cookie "PHPSESSID=amv13uu59s3bk067v8fphftos0; security=low" --batch --technique=B

查询当前数据库 python sqlmap.py -u "http://127.0.0.1/DVWA/vulnerabilities/sqli_blind/?id=1&Submit=Submit" --cookie "PHPSESSID=amv13uu59s3bk067v8fphftos0; security=low" --batch --technique=B --current-db

查询数据库下的表名:

 python sqlmap.py -u "http://127.0.0.1/DVWA/vulnerabilities/sqli_blind/?id=1&Submit=Submit" --cookie "PHPSESSID=amv13uu59s3bk067v8fphftos0; security=low" --batch --technique=B --current-db -D dvwa --tables

查询users表下的字段名

 python sqlmap.py -u "http://127.0.0.1/DVWA/vulnerabilities/sqli_blind/?id=1&Submit=Submit" --cookie "PHPSESSID=amv13uu59s3bk067v8fphftos0; security=low" --batch --technique=B --current-db -D dvwa -T users --columns 

最后查询数据:

python sqlmap.py -u "http://127.0.0.1/DVWA/vulnerabilities/sqli_blind/?id=1&Submit=Submit" --cookie "PHPSESSID=amv13uu59s3bk067v8fphftos0; security=low" --dump -D dvwa -T users --dump -C "users,password"
 

Medium

之前手动注入,我们可以直接在这个里面添加语句进行注入,但这一难度不同。

我们把数据包复制,创建成一个文件,把这个文件放在sqlmap下面

输入语句python.py -r 1.txt --batch(-r 就是读文件)

之后步骤一样

High

还是先抓包,之后把两个页面连接起来,输入命令-second-url“”后面这个地址是第一个页面的地址之后的命令也是跟之前是一样的​​​​​​​

impossible

token校验,防止CSRF攻击

参数校验,确保参数是数字类型才会执行,才会进入sql语句执行的逻辑,sql执行需要经过预编译处理 

Weak Session IDs 

Low

  1. <?php 和 ?> 标记之间的部分是 PHP 代码的起始和结束标记。

  2. $html = ""; 创建了一个名为 $html 的变量,并将其初始化为空字符串。

  3. if ($_SERVER['REQUEST_METHOD'] == "POST") { ... } 是一个条件语句,用于检查当前请求的方法是否为 POST。如果条件成立,将执行条件语句块中的代码。

  4. if (!isset ($_SESSION['last_session_id'])) { ... } 是一个条件语句,用于检查名为 last_session_id 的会话变量是否已设置。如果条件不成立(即 last_session_id 未设置),将执行条件语句块中的代码。

  5. $_SESSION['last_session_id'] = 0; 将会话变量 last_session_id 的值设置为 0。

  6. $_SESSION['last_session_id']++; 将会话变量 last_session_id 的值自增 1。

  7. $cookie_value = $_SESSION['last_session_id']; 将会话变量 last_session_id 的值赋给变量 $cookie_value

  8. setcookie("dvwaSession", $cookie_value); 设置名为 dvwaSession 的 Cookie,其值为 $cookie_value

可以看到每点击一次generate,sessionid+1,并且设置在cookie中

使用burp suite抓包获取cookie

根据上面的数据,用hacker提交cookie

Medium

这个是基于时间戳生成dvwaSesion的,关于时间戳转换,直接查找转换器进行转换即可

High

dvwasession很像md5加密,cookie的值是点击次数的md5加密 ​​​​​​​

impossible

$cookie_value采用随机数+时间戳+固定字符串"Impossible",再进行sha1运算,完全不能猜测到dvwaSession的值 。​​​​​​​

XSS(DOM) 

Low

无任何过滤

所以我们可以构造XSS代码,访问链接:http://127.0.0.1/dvwa1/vulnerabilities/xss_d/?default=<script>alert(666)</script>查看源代码,可以看到,我们的脚本插入到代码中,所以执行了

Medium

以看到,medium级别的代码先检查了default参数是否为空,如果不为空则将default等于获取到的default值。这里还使用了stripos 用于检测default值中是否有 <script  ,如果有的话,则将 default=English 。

很明显,这里过滤了 <script  (不区分大小写),那么我们可以使用:

<img  src=1  οnerrοr=('hack')>

构造Payload:

http://127.0.0.1/dvwa1/vulnerabilities/xss_d/?default=<img src=1 οnerrοr=alert(666)>

此时,并没有弹出任何页面。

       我们查看网页源代码,发现我们的语句被插入到了value值中,但是并没有插入到option标签的值中,所以img标签并没有发起任何作用。

所以我们得先闭合前面的标签,我们构造语句闭合option标签

      构造Payload:

http://127.0.0.1/dvwa1/vulnerabilities/xss_d/?default=></option><img src=1 οnerrοr=alert(666)>

但是我们的语句仍然没有执行,于是我们查看源代码,发现我们的语句中只有 > 被插入到了option标签的值中,因为</option>闭合了option标签,所以img标签并没有插入。

于是我们继续构造语句去闭合select标签,这下我们的img标签就是独立的一条语句了。

构造Payload:

http://127.0.0.1/dvwa1/vulnerabilities/xss_d/?default=>/option></select><img src=1 οnerrοr=alert(666)>

High

以发现使用了白名单的思想,只允许French,English,German以及Spanish,是否存在绕过的可能性呢,答案是肯定的,例如使用如下payload便会触发xss:

http://127.0.0.1/dvwa1/vulnerabilities/xss_d/?default=#</option></select><BODY ONLOAD=alert(document.cookie)>

可以看到我们在English之后添加了#,在url中#后边的内容不会发送到服务端,从而可以实现绕过。

impossible 

服务端没有代码,主要是在客户端处理,看到如下源代码,由于我们在url中输入的任何符号,都会被url编码,以下源代码在渲染我们输入的值的时候,因为没有进行解码,所以即使我们输入了xss注入的攻击代码,也无法被客户端执行。

直接将lang渲染在option中,并没有对lang进行解码,所以无法造成xss注入

XSS(Reflected)

Low

1、随机输入值

​​​​​​​

无论我们输入什么值,在页面中都会显示输入的信息,并且url的name传参值就是我们输入的值

2、对URL中的name传入 xss代码

<script>alert(1)</script>

源码:

  1. header("X-XSS-Protection: 0"); 这行代码设置了一个 HTTP 响应头,即 X-XSS-Protection。将其设置为 0 表示禁用浏览器的内置跨站脚本攻击(XSS)保护机制。请注意,禁用 XSS 保护可能会增加应用程序受到 XSS 攻击的风险,因此需要在代码中进行其他的安全防护措施。

  2. if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { ... } 这是一个条件语句,用于检查是否存在名为 "name" 的 GET 参数,并且该参数的值不为 NULL。如果条件成立,将执行条件语句块中的代码。

  3. echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>'; 这行代码将一个包含用户输入的 <pre> 元素的文本输出到页面上。其中,$_GET[ 'name' ] 表示从 GET 请求中获取名为 "name" 的参数的值,并将其插入到输出字符串中。

Medium​​​​​​​

通过分析源码发现<script>标签被过滤

构造代码<scr<script>ipt>alert(1)</script>或者大小写绕过<sCript>alert(1)</ScRipt>

High

这里使用了正则表达式,使得<script>标签被完全过滤

使用事件型xss代码<img src="#" οnerrοr=alert(1)>

impossible

htmlspecialchars()这个函数的的功能:是把预定义的字符&、"、'、<、>转换为 HTML 实体,防止浏览器将其作为HTML元素。这种做法可以直接避免XSS攻击 。​​​​​​​

XSS(Stored)

Low

储存输入进去的内容,输入xss代码<script>alert(1)</script>​​​​​​​

name处输入的字符受到限制,用F12查看当前元素

最后修改字符的长度。

源码:

  1. if( isset( $_POST[ 'btnSign' ] ) ) { ... } 这是一个条件语句,用于检查是否存在名为 "btnSign" 的 POST 参数。如果条件成立,将执行条件语句块中的代码。通常,这表示用户已经提交了一个名为 "btnSign" 的表单按钮。

  2. $message = trim( $_POST[ 'mtxMessage' ] ); 这行代码从表单中获取名为 "mtxMessage" 的文本输入框的值,并使用 trim() 函数去除首尾的空格,并将其赋值给变量 $message

  3. $name = trim( $_POST[ 'txtName' ] ); 这行代码从表单中获取名为 "txtName" 的文本输入框的值,并使用 trim() 函数去除首尾的空格,并将其赋值给变量 $name

  4. $message = stripslashes( $message ); 这行代码使用 stripslashes() 函数移除 $message 中的反斜杠。这通常用于处理由于转义字符引起的问题,例如在某些情况下,文本中的引号可能会被转义为 \"

  5. $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)) ? "" : "")); 这行代码使用 mysqli_real_escape_string() 函数对 $message 进行转义,以防止 SQL 注入攻击。它会将特殊字符转义为安全的形式,以确保在 SQL 查询中正确处理这些字符。

  6. $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)) ? "" : "")); 这行代码使用 mysqli_real_escape_string() 函数对 $name 进行转义,以防止 SQL 注入攻击。

  7. $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; 这行代码构建了一个 SQL 插入语句,将 $message 和 $name 的值插入到名为 "guestbook" 的数据库表中的 "comment" 和 "name" 列中。

  8. $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>' ); 这行代码执行 SQL 查询,并将结果赋值给变量 $result。如果查询失败,将输出错误消息并终止脚本的执行。

代码对输入的message和name并没有进行XSS过滤,而且数据存储在数据库中,存在比较明显的存储型XSS漏洞 。

Medium

Message处使用了htmlspecialchars()函数,将字符全部转为了HTML实体,因此Message处无法使用XSS形成攻击。可以使用双写绕过<scri<script>pt>alert(1)</script>

High

<script>被过滤

使用事件型 <img src=# οnerrοr=alert(1)>

impossible 

​​​​​​​

impossible 

token校验,防止CSRF攻击

  1. checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); 这行代码调用了一个名为 checkToken() 的函数,用于检查反跨站请求伪造(CSRF)令牌的有效性。它比较了通过 $_REQUEST[ 'user_token' ] 提交的用户令牌和存储在 $_SESSION[ 'session_token' ] 中的会话令牌。如果两个令牌不匹配,将在 'index.php' 页面中触发错误。

  2. $message = htmlspecialchars( $message ); 这行代码使用 htmlspecialchars() 函数对 $message 进行转义,将特殊字符转换为 HTML 实体。这样可以防止用户输入的内容在页面上被解释为 HTML 标签或脚本,从而减少跨站脚本攻击(XSS)的风险。

  3. $name = htmlspecialchars( $name ); 这行代码使用 htmlspecialchars() 函数对 $name 进行转义,以防止特殊字符被解释为 HTML 实体。

  4. $data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' ); 这行代码使用 PDO 准备语句来准备一个 SQL 插入语句。$db 是一个 PDO 连接对象,表示与数据库的连接。

  5. $data->bindParam( ':message', $message, PDO::PARAM_STR ); 和 $data->bindParam( ':name', $name, PDO::PARAM_STR ); 这两行代码将 $message 和 $name 绑定到准备的语句中的命名参数。PDO::PARAM_STR 表示参数是一个字符串类型。

  6. $data->execute(); 这行代码执行准备的语句,将绑定的参数插入到数据库表中。

  7. generateSessionToken(); 这行代码调用了一个名为 generateSessionToken() 的函数,用于生成并存储一个会话令牌。会话令牌用于防止跨站请求伪造(CSRF)攻击,确保表单提交只来自于正确的来源。

 (CSP) Bypass

Low

  1. $headerCSP = "Content-Security-Policy: script-src 'self' https://pastebin.com hastebin.com www.toptal.com example.com code.jquery.com https://ssl.google-analytics.com ;"; 这行代码定义了一个字符串变量 $headerCSP,其中包含了内容安全策略的设置。该策略允许从自身('self')、pastebin.com、hastebin.com、www.toptal.com、example.com、code.jquery.com 和 ssl.google-analytics.com 加载 JavaScript 脚本。

  2. header($headerCSP); 这行代码使用 header() 函数将内容安全策略发送给浏览器。这样浏览器就会按照策略限制页面中 JavaScript 脚本的来源和执行。

  3. if (isset ($_POST['include'])) { ... } 这是一个条件语句,用于检查是否存在名为 "include" 的 POST 参数。如果条件成立,将执行条件语句块中的代码。通常,这表示用户已经提交了一个带有 "include" 参数的表单。

  4. $page[ 'body' ] .= "<script src='" . $_POST['include'] . "'></script>\n"; 这行代码将用户在表单中输入的 URL 作为 JavaScript 脚本的源,将其包含在页面的 <script> 标签中,并将其追加到 $page[ 'body' ] 变量中。这样,页面将加载用户指定的外部脚本。

  5. $page[ 'body' ] .= '...'; 这行代码将一个包含表单的 HTML 代码追加到 $page[ 'body' ] 变量中。这个表单允许用户输入一个 URL,并提交表单来包含指定的外部脚本。

源代码中定义了几个受信任的站点,只能允许这几个站点的脚本才可以运行。

在源代码中也给我们了一个测试站点https://pastebin.com/raw/R570EE00

Medium

这里把其它的安全站点都去掉了,加上了unsafe-inline,如果加上这个参数,就不会阻止内联脚本,如内联< script>元素,javascript:URL,内联事件处理程序(如onclick)和内联元素

<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert(1)</script> 

High

CSP 规则这里十分苛刻,只能引用允许self 的脚本执行,self是指本页面加载的脚本

impossible
构造Poc/DVWA/vulnerabilities/csp/source/jsonp.php?callback=alert(1),触发弹窗

​​​​​​​

impossible

使用HTTP的 Content-Security-Policy头部指定策略
使用meta标签限制表单

JavaScript Attacks

Low

查看源码  发现token由前台生成   并且通过md5进行加密

tr_rot13() 函数对字符串执行 ROT13 编码。
ROT13 编码把每一个字母在字母表中向前移动 13 个字母。数字和非字母字符保持不变。
可以看到只要token等于md5加密success全体移动13个字母后的字母,就能通过。

对应后  结果为结果fhpprff      进行md5加密  然后抓包修改token即可

Medium

在输入框输入 “success” 之后,在控制台中,输入do_elsesomething("XX") 就可以了。

High

s进行解密,解密成功后发现,这里有三个token。token1因为设定原因没有先进行,所以就要先给token1 进行,而后进行token2,最后在进行token3。token3需要点击一下提交键,即可触发。​​​​​​​

impossible

上面显示你永远不能信任来自用户的任何内容,也无法完全阻止他们对其进行篡改,因此不存在绝对的安全级别。所以没有Impossible级别。 

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蛋白质是生物体中普遍存在的一类重要生物大分子,由天然氨基酸通过肽键连接而成。它具有复杂的分子结构和特定的生物功能,是表达生物遗传性状的一类主要物质。 蛋白质的结构可分为四级:一级结构是组成蛋白质多肽链的线性氨基酸序列;二级结构是依靠不同氨基酸之间的C=O和N-H基团间的氢键形成的稳定结构,主要为α螺旋和β折叠;三级结构是通过多个二级结构元素在三维空间的排列所形成的一个蛋白质分子的三维结构;四级结构用于描述由不同多肽链(亚基)间相互作用形成具有功能的蛋白质复合物分子。 蛋白质在生物体内具有多种功能,包括提供能量、维持电解质平衡、信息交流、构成人的身体以及免疫等。例如,蛋白质分解可以为人体提供能量,每克蛋白质能产生4千卡的热能;血液里的蛋白质能帮助维持体内的酸碱平衡和血液的渗透压;蛋白质是组成人体器官组织的重要物质,可以修复受损的器官功能,以及维持细胞的生长和更新;蛋白质也是构成多种生理活性的物质,如免疫球蛋白,具有维持机体正常免疫功能的作用。 蛋白质的合成是指生物按照从脱氧核糖核酸(DNA)转录得到的信使核糖核酸(mRNA)上的遗传信息合成蛋白质的过程。这个过程包括氨基酸的活化、多肽链合成的起始、肽链的延长、肽链的终止和释放以及蛋白质合成后的加工修饰等步骤。 蛋白质降解是指食物中的蛋白质经过蛋白质降解酶的作用降解为多肽和氨基酸然后被人体吸收的过程。这个过程在细胞的生理活动中发挥着极其重要的作用,例如将蛋白质降解后成为小分子的氨基酸,并被循环利用;处理错误折叠的蛋白质以及多余组分,使之降解,以防机体产生错误应答。 总的来说,蛋白质是生物体内不可或缺的一类重要物质,对于维持生物体的正常生理功能具有至关重要的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值