# 05.XSS
XSS 攻击全称跨站脚本攻击,是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为 XSS,XSS 是一种在 web 应用中的计算机安全漏洞,它允许恶意 web 用户将代码植入到 web网站里面,供给其它用户访问,当用户访问到有恶意代码的网页就会产生 xss 攻击。
## 1. XSS初体验
我们写一个留言板的网站
### 1.1 创建数据库
```sql
mysql> create database message;
Query OK, 1 row affected (0.00 sec)
mysql> use message
Database changed
```
### 1.2 创建留言板的表
```sql
mysql> create table board(date varchar(200),content varchar(200))DEFAULT CHAR set utf8;
Query OK, 0 rows affected (0.01 sec)
```
### 1.3 网页源码
```php
留言板
英格科技留言板
日期 |
内容 |
{$row['date']} | ".
"{$row['content']} | ".
"";
}
?>
```
### 1.4 测试功能

## 2. XSS原理
在打开的留言板网页中按下F12,我们可以看到网页的前端源码

我们可以看到这部分的代码为
```html
hello world |
```
其中hello world部分为我们自己提交的内容,如果我们提交的内容为``,那么最终的代码就变成
```html
| | |
```
由此可以看出,我们提交的`
```


## 3. XSS种类
### 3.1 存储型xss
存储型xss是将用户提交的xss代码保存到数据库上,当有人访问页面的时候,服务器把数据库里面的xss代码查询出来,插入网页中交给用户,而用户的浏览器会执行其中的代码


存储型xss是持久存储的,每次访问都会被触发
### 3.2 DOM型xss
DOM树

通过JavaScript,可以重构HTML文档,比如我们可以让图片在加载错误的时候,执行我们指定的js脚本,相当于图片的标签就是js的标签
在留言板中提交如下内容,意思是当图片无法加载的时候,就执行后面的代码
```html
```
可以看到图片裂开了,然后就触发了js代码

### 3.3 反射型xss
反射型XSS效果与存储型XSS和DOM型XSS差不多,唯一的差别是反射型XSS直接把GET中的参数显示在网页上,没有经过数据库,而存储型XSS是先存储到服务器上,再回显到网页的。

#### 3.3.1 写一个搜索功能
在上面的留言板后面加上一个搜索功能
```php
""搜索结果
日期 |
内容 |
{$row['date']} | " .
"{$row['content']} | " .
"";
}
?>
```
#### 3.3.2 测试搜索功能

#### 3.3.3 反射型xss原理
在搜索界面按下f12查看源代码

这个双引号中的`12`是我们自己输入的,所以可以对代码进行闭合,由于前面讲过浏览器对于js标签会自动识别执行,所以我们只需要搜索如下内容就能触发反射型xss
```html
```


这个地址栏的地址可以复制给别人点击,这个搜索的内容是不会保存在数据库中
```html
http://localhost:8081/index.php?search=%3Cscript%3Ealert%28%22hello+world%22%29%3C%2Fscript%3E
```
反射型xss需要构造链接,并且让被攻击者自己点击链接,所以需要与社会工程学配合才可以达到最好效果
## 4. XSS的危害
- 盗取各种用户账号
- 窃取用户Cookie资料,冒充用户身份进入网站
- 劫持用户会话,执行任意操作
- 刷流量,执行弹窗广告
- 传播蠕虫病毒
- 攻击者能在一定限度内记录用户的键盘输入
### 4.1 cookie
Cookie技术通过在请求和响应报文中写入cookie信息来控制客户端的状态
- Cookie会根据从服务器端发送的响应报文内的一个叫做Set-Cookie的首部字段信息,通知客户端保存Cookie,客户端下次再向服务器发送请求时,会自动携带cookie信息,一起发送给服务器
- 服务器发现客户端发送过来的cookie后,会去检查是从哪一个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息,这时,就可为客户端继续提供有状态化的服务了。
### 4.2 盗取客户端cookie实战
一个留言板的网站

#### 4.2.1 XSS平台准备
xss平台可以自己搭建,也可以使用别人搭建好的,甚至js学习的不错的,可以不需要xss平台,直接将xss得到的信息发到邮箱
本次案例使用的是xss平台(此平台搭建方法见下一节)
- 在xss平台上创建项目

- 选择需要的功能模块

- 获取xss脚本

```html
```
#### 4.2.2 插入xss代码
在留言板中进行留言,留言的内容中必须包含xss脚本

提交成功之后,我们就可以在留言板界面看到这条留言,可以发现我们夹带在其中的代码已经被执行了

在xss平台上,我们也可以看到这个游客身份的cookie已经被获取

下面等待管理员上线
#### 4.2.3 模拟管理员上线
这个网站的后台是
```
https://d20.s.iproute.cn/index.php?c=adminlogin
```

登录成功后,我们查看到这条留言

此时管理员的cookie已经被提交到xss平台上面,我们已经获取到管理员的cookie以及后台的地址

#### 4.2.4 盗用管理员cookie登录后台
这边使用cookie修改器,强行修改cookie的内容,然后登录后台

修改玩cookie之后,直接发起访问

哪怕直接修改管理员密码都是可以的

### 4.3 xss平台搭建
windows下就可以搭建xss平台,但是xss平台以后工作中使用都是要有公网环境的,而公网服务器大都是Linux系统,所以此处建议熟悉一下Linux下的搭建过程,不要去随意追求省事。
#### 4.3.1 安装nginx
```bash
[root@localhost ~]# vim /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
[root@localhost ~]# yum -y install nginx
```
#### 4.3.2 修改nginx用户
为了方便后面源码文件的权限管理,将nginx和php都设置为www用户
```bash
[root@localhost ~]# groupadd www -g 666
[root@localhost ~]# useradd www -u 666 -g 666 -s /sbin/nologin -M
[root@localhost ~]# sed -i '/^user/c user www;' /etc/nginx/nginx.conf
```
#### 4.3.3 启动nginx并加入开机自启
```bash
# 启动nginx服务
[root@localhost ~]# systemctl start nginx
# 设置nginx开机自启动
[root@localhost ~]# systemctl enable nginx
```
#### 4.3.4 防火墙配置
```bash
# 关闭防火墙(不推荐)
[root@localhost ~]# systemctl stop firewalld
[root@localhost ~]# systemctl disable firewalld
# 防火墙放行指定的协议
[root@localhost ~]# firewall-cmd --add-service=http --permanent
success
[root@localhost ~]# firewall-cmd --reload
success
```
#### 4.3.5 使用第三方扩展源安装php7.1
```bash
[root@localhost ~]# vim /etc/yum.repos.d/php.repo
[php]
name = php Repository
baseurl = http://repo.webtatic.com/yum/el7/x86_64/
gpgcheck = 0
# 安装epel扩展软件仓库
[root@localhost ~]# yum -y install epel-release
[root@localhost ~]# yum -y install php71w php71w-cli php71w-common php71w-devel php71w-embedded php71w-gd php71w-mcrypt php71w-mbstring php71w-pdo php71w-xml php71w-fpm php71w-mysqlnd php71w-opcache php71w-pecl-memcached php71w-pecl-redis php71w-pecl-mongodb
```
#### 4.3.6 修改php-fpm用户为www
```bash
[root@localhost ~]# sed -i '/^user/c user = www' /etc/php-fpm.d/www.conf
[root@localhost ~]# sed -i '/^group/c user = www' /etc/php-fpm.d/www.conf
```
#### 4.3.7 启动php-fpm
```bash
[root@localhost ~]# systemctl start php-fpm
[root@localhost ~]# systemctl enable php-fpm
```
#### 4.3.8 修改nginx配置文件
主要让nginx支持php的fastcgi
```bash
[root@localhost ~]# vim /etc/nginx/conf.d/default.conf
# 将下面这一行从location中移动到server下
root /usr/share/nginx/html;
# 在最后一行的大括号前,加上下面的代码
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# 重启nginx,让配置生效
[root@localhost ~]# systemctl restart nginx
```
测试是否能正常运行php

#### 4.3.9 安装mariadb数据库
```bash
[root@localhost ~]# yum install mariadb-server mariadb -y
[root@localhost ~]# systemctl start mariadb
[root@localhost ~]# systemctl enable mariadb
[root@localhost ~]# mysqladmin password '123456'
[root@localhost ~]# mysql -uroot -p123456
```
#### 4.3.10 创建xssplatform数据库
```sql
MariaDB [(none)]> create database xssplatform;
Query OK, 1 row affected (0.00 sec)
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
| xssplatform |
+--------------------+
5 rows in set (0.00 sec)
```
#### 4.3.11 配置rewrite规则
```bash
[root@localhost ~]# vim /etc/nginx/conf.d/default.conf
# 修改location里面的内容如下
location / {
index index.php index.html index.htm;
rewrite "^/([0-9a-zA-Z]{6})$" /index.php?do=code&urlKey=$1 last;
rewrite "^/do/auth/(\w+?)(/domain/([\w\.]+?))?$" /index.php?do=do&auth=$1&domain=$3 last;
rewrite "^/register/(.*?)$" /index.php?do=register&key=$1 last;
rewrite "^/register-validate/(.*?)$" /index.php?do=register&act=validate&key=$1 last;
}
# 重启nginx,让配置生效
[root@localhost ~]# systemctl restart nginx
```
#### 4.3.12 部署xssplatform
清空`/usr/share/nginx/html`目录下的所有文件
上传xssplatform到`/usr/share/nginx/html`目录下
```bash
[root@localhost ~]# cd /usr/share/nginx/html/
[root@localhost html]# rm -rf *
[root@localhost html]# unzip xssplatform.zip
[root@localhost html]# chown -R www.www /usr/share/nginx/html
[root@localhost html]# setenforce 0
```





## 5. XSS防范
### 5.1 替换双引号
可以添加对提交语句的过滤,比如如果遇到引号,就用html的特殊字符进行替换
| HTML 原代码 | 显示结果 | 描述 |
| ----------- | -------- | ---------------------- |
| `<` | < | 小于号或显示标记 |
| `>` | > | 大于号或显示标记 |
| `&` | & | 可用于显示其它特殊字符 |
| `"` | “ | 引号 |
| `®` | ® | 已注册 |
| `©` | © | 版权 |
| `™` | ™ | 商标 |
| ` ` | | 半个空白位 |
| ` ` | | 一个空白位 |
| ` ` | | 不断行的空白 |
替换的php代码
```php
$getMessage = str_replace("\"", """,$getMessage);
```
提交正常的带引号的评论进行测试

提交xss弹窗语句,发现双引号已经被替换

提交不用双引号的xss代码
```html
```

### 5.2 替换script
替换script,就可以让代码执行不起来了,再加上一个替换语句
```javascript
$getMessage = str_replace("script", "",$getMessage);
```
再次提交xss代码,发现script代码已经被吞

尝试提交下面的代码绕过
```html
```
大小写绕过成功

假如我们将大小写全部给匹配上,我们依旧可以利用双写法绕过
```html
alert(/hello world/)
```
不用``


### 6.2 Level-2
在搜索框中输入``,发现没有弹窗弹出,查看网页源码,发现<>都被过滤掉了


但value里面没有过滤掉,闭合value的值,`">`成功弹出窗口

### 6.3 Level-3
在搜索框中输入``,发现没有弹窗弹出,查看网页源码,发现<>都被转义了


将``进行编码后尝试

发现还是被转译了

由于<>都被转义了过滤了,可以利用input标签的其他属性进行窗口弹出
`' onfocus=javascript:alert(1) '`

在源码里直接修改input标签里的内容,也能实现窗口弹出,这种方法对有input标签的题目都有用。
这种方法在CTF中可以用到,实际的利用会比较困难。

### 6.4 Level-4
在搜索框中输入``,查看网页源码,发现<>被转义和过滤掉了。和Level-3一样,可以利用input标签的其他属性进行窗口弹出,
`" onfocus=javascript:alert(1) "`

### 6.5 Level-5
在搜索框中输入``,查看源码,发现script被转义成scr_ipt,on被转义成o_n,但javascript没有被转义。

输入`">点我啊`

### 6.6 Level-6
在搜索框中输入``等代码。发现转义了script、on、href、src等关键词。



尝试大小写绕过:`" >`

当然使用万能的修改Input源码也是可以触发的
### 6.7 Level-7
发现过滤了很多关键词:
```
`,发现输入的内容在a标签的href内。

在网址后面加:javascript:alert(1),变成javascr_ipt:alert(1),大小写绕过没用

利用属性引号中的内容可以使用空字符、空格、TAB换行、注释、特殊的函数,将代码隔开。如:javas%09cript:alert()、javas%0acript:alert()、javas%0dcript:alert()的特性,成功绕过
前面在SQL注入绕过阶段就讲过空字符绕过,回顾一下
| 编码 | 空格字符 |
| ---- | ----------------- |
| %09 | TAB键(水平制表符) |
| %0a | 新的一行 |
| %0c | 新的一页 |
| %0d | return功能 |
| %0b | TAB键(垂直制表符) |
| %a0 | 空格 |

### 6.9 Level-9
输入javascript:alert(1)查看源码显示“链接不合法”,尝试输入正常的链接:http://127.0.0.1显示正常


疑似检测字符串是否存在http://,所以写一个不是网址的字符串
`hellohttp://world`

输入`javas%0acript:alert(1) `
或者`javas%0acript:alert(1) // http:// `

### 6.10 Level-10
使用万能的input方法...当然不建议,只是带大家回顾一下(*╯3╰)

观察源码,发现有个form表单,然后默认是GET提交的方式,里面有三个被隐藏的input,我们尝试一个个的手动提交这些变量名,结果发现t_sort会被携带在value中

提交一下t_sort的值

发现出现在value中了

构建攻击内容
`?t_sort=1" onfocus=alert(1) type=“text”`

查看一下提交之后的源码

### 6.11 Level-11
提交`?t_sort=1" onfocus=alert(1) type=“text”`发现已经讲特殊符号实体化,在前端源码中发现了新线索就是这个t_ref,疑似referer

尝试使用修改请求中的referer,然后发现填写的内容出现在了value中


构造攻击语句
`?t_sort=1" onfocus=alert(1) type=“text”`

### 6.12 Level-12
打开源码,发现ua,那就和Level-11的方式一样了


### 6.13 Level-13
与11和12一样

查询到cookie的名称为user

提交攻击语句

### 6.14 Level-14
原版第14关是无法正常工作的,这边英格已经将代码补齐了,这关是考察图片的exif信息会导致xss
可以看到会显示照片的作者在网页上

找张图片修改作者的信息

将图片传上去,就可以触发xss

### 6.15 Level-15
这关考察的是AngularJS的ng-include指令,可以在源码中看到引入了angularjs,并且页面中存在ng-include
关于ng-include的指令可以参考[https://www.runoob.com/angularjs/ng-ng-include.html](https://www.runoob.com/angularjs/ng-ng-include.html)

我们引入第一关的页面

利用第一关的xss

### 6.16 Level-16
先试试``,发现script被替换为 

不使用script,换成`
`,发现空格被替换

使用%0a替代空格
`
`

### 6.17 Level-17
尝试修改一下变量值,可以看到会被填到src部分,并且src没有引号,不需要闭合

传入``进行测试,不能使用`<`或者`>`符号

传入`onclick=alert(1)`进行测试,发现前面没有空格隔开不行

传入`%20onclick=alert(1)`,进行测试,但是无法点击触发

修改为`%20onmouseover=alert(1)`,鼠标滑过成功触发

### 6.18 Level-18
和17关一样
`%20onmouseover=alert(1)`

### 6.19 Level-19
flash漏洞,鉴于现在flash已经全面淘汰,此漏洞没有研究价值
下图是payload,但是浏览器已经无法加载flash了,所以没有触发,如果以后遇到有flash的页面的话,可以尝试去找找flash的通用漏洞。

### 6.20 Level-20
同Level-19,漏洞已过时
## 7. XSS绕过
### 7.1 a标签
```html
#javascript协议
点我啊
# data协议
点我
# url编码的data协议
# 另两种方式实现
```
### 7.2 script标签
```html
# 直接弹窗
# javascript协议编码
# 如果输出是在setTimeout里,我们依然可以直接执行alert(1)
```
### 7.3 button标签
```html
# 点击弹窗
# 不需要点击就能弹窗