# 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 测试功能 ![image-20240127093501488](05.XSS/image-20240127093501488.png) ## 2. XSS原理 在打开的留言板网页中按下F12,我们可以看到网页的前端源码 ![image-20240127093505946](05.XSS/image-20240127093505946.png) 我们可以看到这部分的代码为 ```html hello world ``` 其中hello world部分为我们自己提交的内容,如果我们提交的内容为``,那么最终的代码就变成 ```html ``` 由此可以看出,我们提交的` ``` ![image-20240127093521579](05.XSS/image-20240127093521579.png) ![image-20240127093524298](05.XSS/image-20240127093524298.png) ## 3. XSS种类 ### 3.1 存储型xss 存储型xss是将用户提交的xss代码保存到数据库上,当有人访问页面的时候,服务器把数据库里面的xss代码查询出来,插入网页中交给用户,而用户的浏览器会执行其中的代码 ![image-20240127093528737](05.XSS/image-20240127093528737.png) ![image-20240127093533476](05.XSS/image-20240127093533476.png) 存储型xss是持久存储的,每次访问都会被触发 ### 3.2 DOM型xss DOM树 ![image-20240127093536095](05.XSS/image-20240127093536095.png) 通过JavaScript,可以重构HTML文档,比如我们可以让图片在加载错误的时候,执行我们指定的js脚本,相当于图片的标签就是js的标签 在留言板中提交如下内容,意思是当图片无法加载的时候,就执行后面的代码 ```html ``` 可以看到图片裂开了,然后就触发了js代码 ![image-20240127093539788](05.XSS/image-20240127093539788.png) ### 3.3 反射型xss 反射型XSS效果与存储型XSS和DOM型XSS差不多,唯一的差别是反射型XSS直接把GET中的参数显示在网页上,没有经过数据库,而存储型XSS是先存储到服务器上,再回显到网页的。 ![image-20240127093543256](05.XSS/image-20240127093543256.png) #### 3.3.1 写一个搜索功能 在上面的留言板后面加上一个搜索功能 ```php

""搜索结果

" . " " . ""; } ?>
日期 内容
{$row['date']}{$row['content']}
搜索:
``` #### 3.3.2 测试搜索功能 ![image-20240127093549116](05.XSS/image-20240127093549116.png) #### 3.3.3 反射型xss原理 在搜索界面按下f12查看源代码 ![image-20240127093552312](05.XSS/image-20240127093552312.png) 这个双引号中的`12`是我们自己输入的,所以可以对代码进行闭合,由于前面讲过浏览器对于js标签会自动识别执行,所以我们只需要搜索如下内容就能触发反射型xss ```html ``` ![image-20240127093558392](05.XSS/image-20240127093558392.png) ![image-20240127093602346](05.XSS/image-20240127093602346.png) 这个地址栏的地址可以复制给别人点击,这个搜索的内容是不会保存在数据库中 ```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实战 一个留言板的网站 ![image-20240127093606330](05.XSS/image-20240127093606330.png) #### 4.2.1 XSS平台准备 xss平台可以自己搭建,也可以使用别人搭建好的,甚至js学习的不错的,可以不需要xss平台,直接将xss得到的信息发到邮箱 本次案例使用的是xss平台(此平台搭建方法见下一节) - 在xss平台上创建项目 ![image-20240127093611542](05.XSS/image-20240127093611542.png) - 选择需要的功能模块 ![image-20240127093614133](05.XSS/image-20240127093614133.png) - 获取xss脚本 ![image-20240127093617539](05.XSS/image-20240127093617539.png) ```html ``` #### 4.2.2 插入xss代码 在留言板中进行留言,留言的内容中必须包含xss脚本 ![image-20240127093620397](05.XSS/image-20240127093620397.png) 提交成功之后,我们就可以在留言板界面看到这条留言,可以发现我们夹带在其中的代码已经被执行了 ![image-20240127093623450](05.XSS/image-20240127093623450.png) 在xss平台上,我们也可以看到这个游客身份的cookie已经被获取 ![image-20240127093626130](05.XSS/image-20240127093626130.png) 下面等待管理员上线 #### 4.2.3 模拟管理员上线 这个网站的后台是 ``` https://d20.s.iproute.cn/index.php?c=adminlogin ``` ![image-20240127093629169](05.XSS/image-20240127093629169.png) 登录成功后,我们查看到这条留言 ![image-20240127093631855](05.XSS/image-20240127093631855.png) 此时管理员的cookie已经被提交到xss平台上面,我们已经获取到管理员的cookie以及后台的地址 ![image-20240127093634770](05.XSS/image-20240127093634770.png) #### 4.2.4 盗用管理员cookie登录后台 这边使用cookie修改器,强行修改cookie的内容,然后登录后台 ![image-20240127093637920](05.XSS/image-20240127093637920.png) 修改玩cookie之后,直接发起访问 ![image-20240127093640602](05.XSS/image-20240127093640602.png) 哪怕直接修改管理员密码都是可以的 ![image-20240127093644196](05.XSS/image-20240127093644196.png) ### 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 ![image-20240127093652367](05.XSS/image-20240127093652367.png) #### 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 ``` ![image-20240127093658405](05.XSS/image-20240127093658405.png) ![image-20240127093701535](05.XSS/image-20240127093701535.png) ![image-20240127093704366](05.XSS/image-20240127093704366.png) ![image-20240127093707426](05.XSS/image-20240127093707426.png) ![image-20240127093710325](05.XSS/image-20240127093710325.png) ## 5. XSS防范 ### 5.1 替换双引号 可以添加对提交语句的过滤,比如如果遇到引号,就用html的特殊字符进行替换 | HTML 原代码 | 显示结果 | 描述 | | ----------- | -------- | ---------------------- | | `<` | < | 小于号或显示标记 | | `>` | > | 大于号或显示标记 | | `&` | & | 可用于显示其它特殊字符 | | `"` | “ | 引号 | | `®` | ® | 已注册 | | `©` | © | 版权 | | `™` | ™ | 商标 | | ` ` | | 半个空白位 | | ` ` | | 一个空白位 | | ` ` | | 不断行的空白 | 替换的php代码 ```php $getMessage = str_replace("\"", """,$getMessage); ``` 提交正常的带引号的评论进行测试 ![image-20240127093716616](05.XSS/image-20240127093716616.png) 提交xss弹窗语句,发现双引号已经被替换 ![image-20240127093719410](05.XSS/image-20240127093719410.png) 提交不用双引号的xss代码 ```html ``` ![image-20240127093724159](05.XSS/image-20240127093724159.png) ### 5.2 替换script 替换script,就可以让代码执行不起来了,再加上一个替换语句 ```javascript $getMessage = str_replace("script", "",$getMessage); ``` 再次提交xss代码,发现script代码已经被吞 ![image-20240127093731262](05.XSS/image-20240127093731262.png) 尝试提交下面的代码绕过 ```html ``` 大小写绕过成功 ![image-20240127093734541](05.XSS/image-20240127093734541.png) 假如我们将大小写全部给匹配上,我们依旧可以利用双写法绕过 ```html alert(/hello world/) ``` 不用`` ![image-20240127093744059](05.XSS/image-20240127093744059.png) ![image-20240127093748068](05.XSS/image-20240127093748068.png) ### 6.2 Level-2 在搜索框中输入``,发现没有弹窗弹出,查看网页源码,发现<>都被过滤掉了 ![image-20240127093752389](05.XSS/image-20240127093752389.png) ![image-20240127093755637](05.XSS/image-20240127093755637.png) 但value里面没有过滤掉,闭合value的值,`">`成功弹出窗口 ![image-20240127093758704](05.XSS/image-20240127093758704.png) ### 6.3 Level-3 在搜索框中输入``,发现没有弹窗弹出,查看网页源码,发现<>都被转义了 ![image-20240127093802149](05.XSS/image-20240127093802149.png) ![image-20240127093805672](05.XSS/image-20240127093805672.png) 将``进行编码后尝试 ![image-20240127093809033](05.XSS/image-20240127093809033.png) 发现还是被转译了 ![image-20240127093812087](05.XSS/image-20240127093812087.png) 由于<>都被转义了过滤了,可以利用input标签的其他属性进行窗口弹出 `' onfocus=javascript:alert(1) '` ![image-20240127093815246](05.XSS/image-20240127093815246.png) 在源码里直接修改input标签里的内容,也能实现窗口弹出,这种方法对有input标签的题目都有用。 这种方法在CTF中可以用到,实际的利用会比较困难。 ![image-20240127093818624](05.XSS/image-20240127093818624.png) ### 6.4 Level-4 在搜索框中输入``,查看网页源码,发现<>被转义和过滤掉了。和Level-3一样,可以利用input标签的其他属性进行窗口弹出, `" onfocus=javascript:alert(1) "` ![image-20240127093825766](05.XSS/image-20240127093825766.png) ### 6.5 Level-5 在搜索框中输入``,查看源码,发现script被转义成scr_ipt,on被转义成o_n,但javascript没有被转义。 ![image-20240127093830609](05.XSS/image-20240127093830609.png) 输入`">点我啊` ![image-20240127093834209](05.XSS/image-20240127093834209.png) ### 6.6 Level-6 在搜索框中输入``等代码。发现转义了script、on、href、src等关键词。 ![image-20240127093839237](05.XSS/image-20240127093839237.png) ![image-20240127093844350](05.XSS/image-20240127093844350.png) ![image-20240127093848509](05.XSS/image-20240127093848509.png) 尝试大小写绕过:`" >` ![image-20240127093854134](05.XSS/image-20240127093854134.png) 当然使用万能的修改Input源码也是可以触发的 ### 6.7 Level-7 发现过滤了很多关键词: ``` `,发现输入的内容在a标签的href内。 ![image-20240127094010989](05.XSS/image-20240127094010989.png) 在网址后面加:javascript:alert(1),变成javascr_ipt:alert(1),大小写绕过没用 ![image-20240127094014685](05.XSS/image-20240127094014685.png) 利用属性引号中的内容可以使用空字符、空格、TAB换行、注释、特殊的函数,将代码隔开。如:javas%09cript:alert()、javas%0acript:alert()、javas%0dcript:alert()的特性,成功绕过 前面在SQL注入绕过阶段就讲过空字符绕过,回顾一下 | 编码 | 空格字符 | | ---- | ----------------- | | %09 | TAB键(水平制表符) | | %0a | 新的一行 | | %0c | 新的一页 | | %0d | return功能 | | %0b | TAB键(垂直制表符) | | %a0 | 空格 | ![image-20240127094018810](05.XSS/image-20240127094018810.png) ### 6.9 Level-9 输入javascript:alert(1)查看源码显示“链接不合法”,尝试输入正常的链接:http://127.0.0.1显示正常 ![image-20240127094022169](05.XSS/image-20240127094022169.png) ![image-20240127094025820](05.XSS/image-20240127094025820.png) 疑似检测字符串是否存在http://,所以写一个不是网址的字符串 `hellohttp://world` ![image-20240127094029060](05.XSS/image-20240127094029060.png) 输入`javas%0acript:alert(1) ` 或者`javas%0acript:alert(1) // http:// ` ![image-20240127094032750](05.XSS/image-20240127094032750.png) ### 6.10 Level-10 使用万能的input方法...当然不建议,只是带大家回顾一下(*╯3╰) ![image-20240127094036439](05.XSS/image-20240127094036439.png) 观察源码,发现有个form表单,然后默认是GET提交的方式,里面有三个被隐藏的input,我们尝试一个个的手动提交这些变量名,结果发现t_sort会被携带在value中 ![image-20240127094040014](05.XSS/image-20240127094040014.png) 提交一下t_sort的值 ![image-20240127094042723](05.XSS/image-20240127094042723.png) 发现出现在value中了 ![image-20240127094045938](05.XSS/image-20240127094045938.png) 构建攻击内容 `?t_sort=1" onfocus=alert(1) type=“text”` ![image-20240127094049672](05.XSS/image-20240127094049672.png) 查看一下提交之后的源码 ![image-20240127094054319](05.XSS/image-20240127094054319.png) ### 6.11 Level-11 提交`?t_sort=1" onfocus=alert(1) type=“text”`发现已经讲特殊符号实体化,在前端源码中发现了新线索就是这个t_ref,疑似referer ![image-20240127094057650](05.XSS/image-20240127094057650.png) 尝试使用修改请求中的referer,然后发现填写的内容出现在了value中 ![image-20240127094100639](05.XSS/image-20240127094100639.png) ![image-20240127094105159](05.XSS/image-20240127094105159.png) 构造攻击语句 `?t_sort=1" onfocus=alert(1) type=“text”` ![image-20240127094114390](05.XSS/image-20240127094114390.png) ### 6.12 Level-12 打开源码,发现ua,那就和Level-11的方式一样了 ![image-20240127094117885](05.XSS/image-20240127094117885.png) ![image-20240127094123053](05.XSS/image-20240127094123053.png) ### 6.13 Level-13 与11和12一样 ![image-20240127094125830](05.XSS/image-20240127094125830.png) 查询到cookie的名称为user ![image-20240127094129701](05.XSS/image-20240127094129701.png) 提交攻击语句 ![image-20240127094133742](05.XSS/image-20240127094133742.png) ### 6.14 Level-14 原版第14关是无法正常工作的,这边英格已经将代码补齐了,这关是考察图片的exif信息会导致xss 可以看到会显示照片的作者在网页上 ![image-20240127094141153](05.XSS/image-20240127094141153.png) 找张图片修改作者的信息 ![image-20240127094145144](05.XSS/image-20240127094145144.png) 将图片传上去,就可以触发xss ![image-20240127094148049](05.XSS/image-20240127094148049.png) ### 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) ![image-20240127094151464](05.XSS/image-20240127094151464.png) 我们引入第一关的页面 ![image-20240127094155119](05.XSS/image-20240127094155119.png) 利用第一关的xss ![image-20240127094200168](05.XSS/image-20240127094200168.png) ### 6.16 Level-16 先试试``,发现script被替换为  ![image-20240127094204865](05.XSS/image-20240127094204865.png) 不使用script,换成``,发现空格被替换 ![image-20240127094208462](05.XSS/image-20240127094208462.png) 使用%0a替代空格 `` ![image-20240127094212331](05.XSS/image-20240127094212331.png) ### 6.17 Level-17 尝试修改一下变量值,可以看到会被填到src部分,并且src没有引号,不需要闭合 ![image-20240127094216080](05.XSS/image-20240127094216080.png) 传入``进行测试,不能使用`<`或者`>`符号 ![image-20240127094223833](05.XSS/image-20240127094223833.png) 传入`onclick=alert(1)`进行测试,发现前面没有空格隔开不行 ![image-20240127094227216](05.XSS/image-20240127094227216.png) 传入`%20onclick=alert(1)`,进行测试,但是无法点击触发 ![image-20240127094231343](05.XSS/image-20240127094231343.png) 修改为`%20onmouseover=alert(1)`,鼠标滑过成功触发 ![image-20240127094237311](05.XSS/image-20240127094237311.png) ### 6.18 Level-18 和17关一样 `%20onmouseover=alert(1)` ![image-20240127094240360](05.XSS/image-20240127094240360.png) ### 6.19 Level-19 flash漏洞,鉴于现在flash已经全面淘汰,此漏洞没有研究价值 下图是payload,但是浏览器已经无法加载flash了,所以没有触发,如果以后遇到有flash的页面的话,可以尝试去找找flash的通用漏洞。 ![image-20240127094246275](05.XSS/image-20240127094246275.png) ### 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 # 点击弹窗 # 不需要点击就能弹窗