OWASP TOP10
SQL注入
CSRF
CSRF(Cross-Site Request Forgery)跨站请求伪造。旨在冒用用户身份发起请求。
利用原理
- 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;
- 在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;
- 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;
- 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;
- 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。
防御方式:
- 严格校验referer
- GET转POST,同时添加并校验token
拓展:
token 怎么设计?
- token不宜过长
- token应与当前用户身份绑定,且验证完应立即失效
- token应动态生成,本身应有固定的生命周期,不能长久有效
Referer 是个什么东西?
referer字段用来告诉服务器,用户的来源。referer就是一个URL,有可能是内网的URL,也有可能是功能URL,因此,为了隐私考虑,referer有时候需要发送,有时候不需要发送。
Referer作用:
- 页面统计
- 防盗链
- http请求发给服务器后,如果服务器要求必须是某个地址或者某几个地址才能访问,而你发送的referer不符合他的要求,就会拦截或者跳转到他要求的地址,然后再通过这个地址进行访问
Referer发送的场景:
- 用户点击网页上的链接
- 用户发送表单
- 网页加载静态资源,比如图片、脚本、样式
浏览器会将当前网址作为Referer
字段放在Header
头里发送。
Referer不发送的场景:
-
https跳转到http
-
直接在浏览器中输入URL
-
从收藏夹访问
-
单击「主页」或自定义的地址
-
用js来打开,如:
window.open
、location.href
、location.replace
-
Referer Policy的值
-
no-referer
不发送
referer
。 -
no-referer-when-downgrade
从
https
到http
,不发送referer
,其他情况则发送,这是浏览器的默认行为。 -
same-origin
链接到同源(协议、域名、端口)地址时发送,否则不发送。注意:
https
到http
也属于跨域。 -
origin
referer
字段一律只发送源信息(协议、域名、端口),不管是否跨域。 -
strict-origin
如果从 HTTPS 网址链接到 HTTP 网址,不发送
Referer
字段,其他情况只发送源信息。 -
origin-when-cross-origin
同源时,发送完整的
Referer
字段,跨域时发送源信息。 -
strict-origin-when-cross-origin
同源时,发送完整的
Referer
字段;跨域时,如果 HTTPS 网址链接到 HTTP 网址,不发送Referer
字段,否则发送源信息。 -
unsafe-url
Referer
字段包含源信息、路径和查询字符串,不包含锚点、用户名和密码。
-
-
Referer Policy用法
-
HTTP头信息
1
Referer-Polify: origin
-
<meta>
标签1
<meta name="referer" content="origin">
-
refererpolicy
属性<a>
、<area>
、<img>
、<iframe>
和<link>
标签,可以设置referrerpolicy
属性1
<a href="xxx" refererpolicy="origin" target="_blank">xxx</a>
-
XSS
SSRF
定义
SSRF
,服务端请求伪造(Server-side Request Forge
)的缩写。产生的原因是服务端提供了从其他服务器获取数据的功能,但没有对地址和协议等做过滤与限制。常见的一个场景就是:服务器通过用户输入的 URL 来获取图片。这个功能如果被恶意使用,可以利用存在缺陷的 Web 应用作为跳板来攻击远程和本地的服务器。
分类
ssrf 主要分为:
- 回显型 ssrf
- 无回显型 ssrf
有回显型的 ssrf 就是会将访问到的信息返回给攻击者,而无回显的 ssrf 则不会,但是可以通过带外通道(比如 dnslog)或者 访问开放/未开放的端口导致的延时来判断。
利用方式
伪协议 - gopher://
gopher
协议是一个在http 协议诞生前用来访问Internet 资源的协议可以理解为http 协议的前身或简化版,虽然很古老但现在很多库还支持gopher 协议而且gopher
协议功能很强大。也被称为「万金油」。
它可以实现多个数据包整合发送,然后gopher
服务器将多个数据包捆绑着发送到客户端,这就是它的菜单响应。比如使用一条gopher
协议的curl
命令就能操作mysql 数据库
或完成对redis
的攻击等等。
gopher
协议使用tcp
可靠连接。
协议格式:
1 | gopher://<host>:<port>/<gopher-path> |
默认端口70
如果发起post
请求,回车换行需要使用%0d%0a
,如果多个参数,参数之间的&
也需要进行URL编码
gopher的使用限制:
语言 | 限制 |
---|---|
php | –write-curlwrappers 且 php 版本至少为 5.3 |
Java | < jdk1.7 |
curl | 低版本不支持 |
perl | 支持 |
asp.net | <版本3 |
-
gopher发送get请求
本地使用
nc
测试:两个终端,见图:可以发现,第一个
s
是不会发送过去的,这是gopher
协议的特性,只需要在使用gopher协议时在url后加入一个字符(该字符可随意写)即可。 -
gopher发送post请求
需要注意:
- gopher 协议的默认端口为
70
- 分隔符后面的 TCP/IP 数据就是发出去的数据,数据部分如果有特殊字符必须要进行 url 编码,这样 gopher 协议才能正确解析
- 大部分 PHP 并不会开启 fopen 的 gopher wrapper
- PHP file_get_contents 的 gopher 协议不能 URLencode
- PHP file_get_contents 的 gopher 协议的 302 跳转有 bug,导致利用失败
- PHP 的 curl 默认不跟随 302 跳转
- curl/libcurl v7.43 上 gopher 协议存在
%00
截断,v7.49 可用
利用案例:
可见ssrf + redis
利用方式
伪协议 - dict://
dict协议指词典网络协议,允许客户端在使用过程中访问更多字典。
默认端口2628
协议格式:
1 | dict://serverip:port/命令:参数 |
dict特性:
- 向服务器的端口请求为「命令:参数」,并在末尾自动补上
\r\n
,方便漏洞利用 - 通过
dict
协议,指令需要一条一条执行,而gopher
协议执行一条命令即可
利用案例:
可见ssrf + redis
利用方式
伪协议 - file://
file
协议主要用于访问本地计算机中的文件。格式为:
1 | file://文件路径 |
file 和 http协议的区别?
- file协议主要用于读取服务器本地文件,访问的是
本地的静态资源
- http是访问本地的html文件,相当于把本机当作http服务器,通过http访问服务器,服务器再去访问本地资源。简单来说
file只能静态读取
,http可以动态解析 - http服务器可以开放端口,让他人通过http访问服务器资源,但file不可以
- file对应的类似http的协议是ftp协议(文件传输协议)
- file不能跨域
伪协议 - ldap://
伪协议 - data://
伪协议 - rmi://
常见绕过技巧
- 利用伪协议
- 添加端口可能绕过匹配正则:
http://127.0.0.1/
改为http://127.0.0.1:80/
- 127.0.0.1 与 localhost 在大部分情况下都是等价的
- 利用 IPv6:
http://[::]:80/
相当于http://127.0.0.1
- 利用
@
可能绕过域名限定的正则:http://example.com@127.0.0.1
相当于http://127.0.0.1
- 利用进制:以
127.0.0.1
为例,首先,ip 可以没.
,比如2130706433
(十进制),0x7F000001
(十六进制);也可以有.
,比如0x7F.0x000.0x001
(十六进制)、0177.0000.0001
(八进制),甚至可以混用,比如0x7F.000.0x001
(十六进制 加 十进制);还可以合并,127.0.0.1 == 127.0.1 == 127.1
、127.3.2.1 == 127.3.513 == 127.3.513 == 127.197121
,注意这个合并注意只能从前到后合并,具体的计算方式,可以按照 . 分割,分别先转为 8 位二进制,然后从左到右每段直接拼在一起,最后再转为十进制或者十六进制即可,有一个比较特殊的是0
,0.0.0.0 == 0.0.0 == 0.0 == 0
,即目标服务器监听了0.0.0.0
的服务都可以用此方法访问到。以上这几种方式可以随意组合搭配,而且其实各个进制的补 0 可以填很多个:127.0.0000000000000000000000000000000000.1
。 - 利用跳转:比如,利用短链,
http://dlj.bz/kA47FD
相当于http://127.0.0.1
,本质上是利用 301 跳转,所以完全可以自己打一个 301 跳转,想怎么跳就怎么跳,别忘记同时还可以转换协议:Location: file:///etc/passwd
。状态码可以是 301、302、307 - 利用域名 A 记录:http://localhost.tr0y.wang/, 在域名上设置 A 记录,指向
127.0.0.1
。如果你实在懒,可以用xip.io
/xip.name
,它的子域名前缀就是解析的 ip 地址,比如127.0.0.1.xip.io
的 A 记录就是 127.0.0.1 - 利用 IDN,
ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ
等于example.com
,127。0。0。1
相当于127.0.0.1
- CRLF 头注入:比较经典的就是 Python 的 CVE,由于允许
\r\n
的存在,大大提升了通过 http:// 协议来利用的 ssrf 的杀伤力 - DNS 重绑定攻击:可见:https://www.tr0y.wang/2020/11/02/DNS-3-attack-by-dns/#DNS-重绑定攻击
这个和「域名A记录」很像,但是DNS重绑定的优势是,有些 SSRF 防御策略的第一步是先提取域名,然后解析一下看 ip 是不是内网 ip,但是到最后发起请求的时候依旧用的是域名,第一次不是内网,再次发起请求的时候,就是内网了。可以绕过不规范的SSRF防御策略。
防御方式
明确此类功能的流程:
- 提取 URL 的域名
- 解析 Host 的 ip
- 发出请求
- 如果有跳转,取出 Location URL,回到第 1 步;否则继续下一步
- 发出最终的请求,实现业务逻辑
需要注意:
- 过滤返回的信息/统一错误信息:将有回显变成无回显,提升利用难度(比如 file:// 就直接废掉了)
- 限制请求的 ip 和端口:一般的业务禁掉私有 ip 完全可行;限制端口可有效降低攻击面
- 去除 URL 中的特殊字符:防止因为 url 解析模块造成的问题,往往是 host 提取解析结果存在问题(强烈建议阅读 资料 1)
- 只允许 http 协议,必要时强制使用 https 协议,可以很大程度提升攻击难度,因为 SSL/TLS 握手过程无法完成(骚操作请参考 资料 2)
- 解析/跳转(没必要就别跟随跳转了)后一定要进行检查:防止利用各种形式的 ip、跳转绕过
- 完善正则表达式:这个没啥通用的技巧,根据具体的业务需求定,需要经过完善测试(限制 @ 的使用、防止用子域名前缀绕过等等)
- 最后真正发起请求去获取资源的时候,可以把域名替换成第之前就已经解析的结果,这样来避免重复解析带来的 DNS 重绑定攻击问题。
- 可以考虑建立一个发起请求的代理集群。外网代理集群专门用于业务对外网发起请求;另一个代理集群专门用于业务对内网发起请求。然后在网络层面上保证外网代理集群无法与内网直接互通。
资料:
- SSRF利用新纪元:
- SSRF 遇到 TLS 的利用方式:
- 猪猪侠在乌云大会上关于 ssrf 的分享:
如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !