漏洞根源在于人——知识深度篇
本篇文章,不讲攻击,更多的是去讲“开发人员对知识掌握不够深入”导致产生漏洞。我觉得,只有当我们深谙原理,才能更犀利的去思考攻击:了解开发者可能的弱点、盲区,是安全学习中后期时我们更应具备的一项技能。
本文原创作者:i春秋签约作家——夏之冰雪
人性的万恶是痛苦的本源,人为的疏忽是漏洞的主因。打算写系列文章,主要是想从编程的角度谈谈为什么会存在漏洞。这些漏洞,围绕“人”进行展开,讲讲我自己的看法。 以下这些内容,都是我平时review别人代码时发现的问题,并定期记录下来汇总。虽然没有专门的分类,但是我会尽量设计一个场景,有条理的讲给大家,让大家觉得不陌生。 本篇文章,不讲攻击,更多的是去讲“开发人员对知识掌握不够深入”导致产生漏洞。我觉得,只有当我们深谙原理,才能更犀利的去思考攻击: 了解开发者可能的弱点、盲区,是安全学习中后期时我们更应具备的一项技能。 声明:以下内容均为虚构,用ichunqiu作为场景,更亲切。 1. 网络协议 需求场景:ichunqiu产品提出需求,希望用户可以分享网址,如果这个网址是bbs.ichunqiu.com,则程序自动抓取网站内容,并和网址一起,展现到用户的分享内容中。 需求分析:这是很常见的需求,比如人人网分享、微博分享,为了达到更好的分享效果,一般服务器会抓取分享内容,展现出来。 网址接口:http://bbs.ichunqiu.com/fenxiang.php?url=*** 程序员要考虑防止SSRF漏洞产生,因为如果攻击者输入的是内网网址,就会导致内网信息泄露了,比如: http://bbs.ichunqiu.com/fenxiang.php?url=192.168.0.3 http://bbs.ichunqiu.com/fenxiang.php?url=10.0.0.17 工程师做了一个非常简单的demo,代码fenxiang.php:
<?php $url = $_GET['url']; $info = parse_url($url); if($info['host'] != 'bbs.ichunqiu.com') { #不做抓取网页处理,直接返回url echo $url; exit; } $ch = curl_init(); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_URL, $url); $data = curl_exec($ch); curl_close($ch); echo $url . "<br/>" . $data;如图,如果传递的是bbs.ichunqiu.com的网址,则会在网页输出一行地址,然后再输出网页内容。 如果网址不是bbs.ichunqiu.com,则不会抓取任何内容,只输出网址: 现在,即使传递的网址是: http://bbs.ichunqiu.com/fenxiang.php?url=http://192.168.0.16 也不会产生SSRF漏洞。 但是,这个代码真的没有问题么? 攻击代码如下: http: / / bbs.ichunqiu.com/fenxiang.php?url=file://bbs.ichunqiu.com/etc/passwd 可以看到,已经把服务器的账号文件passwd显示出来了,这属于敏感信息! 攻击原理: 1. parse_url只是负责字符串解析,它不关心协议,即使我们用一个不存在的协议abcdefg也能执行。
$url = 'abcedfg://bbs.ichunqiu.com/test'; $info = parse_url($url); var_dump($info); #结果 array(3) { ["scheme"]=> string(7) "abcedfg" ["host"]=> string(16) "bbs.ichunqiu.com" ["path"]=> string(5) "/test" }2. curl是基于libcurl实现的,支持的协议非常多,官方解释: libcurl supports HTTPS certificates, HTTP POST, HTTP PUT, FTP uploading, Kerberos, SPNEGO, HTTP form based upload, proxies, cookies, user+password authentication, file transfer resume, http proxy tunneling and more 所以,程序员写的代码存在漏洞,程序员误以为parse_url、curl方法都只是支持http和https,实际上file协议被忽视了。而file协议会忽视前面的bbs.ichunqiu.com,因此获取到了服务器敏感信息/etc/passwd,最终导致服务器本地文件泄露的漏洞。 php的curl,linux的curl,是一个东西,在linux上面也会返回相同内容:
[root[url=home.php?mod=space&uid=163960]@localhost[/url] ichunqiu]# curl "file://bbs.ichunqiu.com/etc/passwd" root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown *********** 等等敏感信息 ***********思考: 程序员在编程中,对很多方法、函数并没有完全深入了解,导致漏洞存在。在网络攻击日益猖獗的今天,每个程序员都应该具备更全面网络知识,特别是网络协议。 2. IP的困惑 需求场景:ichunqiu产品提出需求,希望进行推广活动,用户可以把带有自己的id的一个链接分享出去,只要有人点击了,就加1个魔法币。 需求分析:ichunqiu很大方,希望对那些乐于推广的用户进行奖励,但是也要防止有人通过这个进行刷币。所以,可能每天有次数上限,并且同一个人点击只能加1个币。 网址接口:http://bbs.ichunqiu.com/tuiguang.php?id=夏之冰雪 程序员通过ip判断是否为同一用户,每天3次限制,实现预期效果如下。 如果用相同ip,访问这个地址: 第一次,加1分 第二次,以后都不加分 如果每次用不同ip访问: 第一次加1分 第二次加1分 第三次加1分 第四次不加分 工程师做了一个非常简单的demo,代码tuiguang.php:
<?php $id = $_GET['id']; $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; if(check($id, $ip)) { #魔法币++ } //同一id最多加三次 //同一ip最多加一次 function check($id, $ip) { return true or false; }程序员经过自测,满足需求(ABCD为不同IP): A IP访问,魔法币+1 A IP再次访问,魔法币不变 B IP再次访问,魔法币+1 C IP再次访问,魔法币+1 D IP再次访问,魔法币不变 但是,这个代码真的没有问题么? 攻击代码如下: curl ‘http://bbs.ichunqiu.com/tuiguang.php?id=夏之冰雪’ -i -H “X-Forwarded-For: A IP” curl ‘http://bbs.ichunqiu.com/tuiguang.php?id=夏之冰雪’ -i -H “X-Forwarded-For: B IP” curl ‘http://bbs.ichunqiu.com/tuiguang.php?id=夏之冰雪’ -i -H “X-Forwarded-For: C IP” 在相同ip情况下,使用一台机器发送上面3个指令,即可加3个金币。完全不需要多个ip,一个ip就伪造了多个ip。 原理分析: 由于很多企业对自己的网站增加了反向代理,所以服务器没有办法直接获取用户ip,因为服务器前面架设了代理。所以X-Forwarded-For这个字段应运而生,X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址。 但是X-Forwarded-For字段是可以伪造的,客户端可以伪造自己也是代理,这样便欺骗了服务器。 思考: ip这个东西,很多企业都踩过坑。 3. 正则的使用 需求场景:这次不是ichunqiu产品提需求了,而是程序员在看日志的时候,发现有个user-agent叫“HUAIDAN”的浏览器访问,存在恶意攻击。 需求分析:针对恶意攻击,ichunqiu有自己的防火墙,获取到攻击者的ip,将这个攻击者ip加入黑名单封掉即可。 攻击日志: 218.85.134.47 – - [28/Feb/2017:15:54:57 +0800] GET http://bbs.ichunqiu.com/?id=+union+select 1,2,3,4,5,6 HUAIDAN 通过攻击日志可以看到,ip地址是218.85.134.47,攻击的请求主要是利用sql的union注入爆破数据库列数,用的是“1,2,3,4,5,6”这种形式,最后面是浏览器的user-agent,即HUAIDAN。 程序员思考了一下,我们网站网址不可能有“数字加逗号”这种形式,我就用“数字加逗号”以及“HUAIDAN”为依据,在WAF里加一条正则好了。测试demo如下:
import re ichunqiu_log = '218.85.134.47 - - [28/Feb/2017:15:54:57 +0800] GET [url]http://bbs.ichunqiu.com/?id=[/url] union+select+1,2,3,4,5,6 HUAIDAN' re.findall(r'(\d+(,)?)+ HUAIDAN$', ichunqiu_log)但是,第二天程序员来公司,发现HUAIDAN依旧在攻击,为什么WAF不起作用??? 仔细一看,我勒个去!!! WAF竟然挂了!!! 仔细跟踪,发现HUAIDAN猥琐的把WAF沦陷了,攻击语句: 218.85.134.47 – - [28/Feb/2017:15:54:57 +0800] GET http://bbs.ichunqiu.com/?id=union+select+1111,2222,3333,4444,5555,666666666666666666666666666666 NOTHUAIDAN 聪明的读者,你们知道为什么这个语句会让waf崩溃么? 提示如下: 普通的demo,执行时间0.01秒
[root@localhost ichunqiu]# cat demo.py import re re.findall(r'(\d+(,)?)+ HUAIDAN$', '1,2,3,4,5,6 HUAIDAN') [root@localhost ichunqiu]# time python demo.py real 0m0.015s user 0m0.011s sys 0m0.003s增加了数字长度的普通demo,执行时间0.01秒
[root@localhost ichunqiu]# cat demo.py import re re.findall(r'(\d+(,)?)+ HUAIDAN$', '1111,2222,3333,4444,5555,6666 HUAIDAN') [root@localhost ichunqiu]# time python demo.py real 0m0.016s user 0m0.011s sys 0m0.004s伪造UA的demo,执行时间0.3秒
[root@localhost ichunqiu]# cat demo.py import re re.findall(r'(\d+(,)?)+ HUAIDAN$', '1111,2222,3333,4444,5555,6666 NOTHUAIDAN') [root@localhost ichunqiu]# time python demo.py real 0m0.333s user 0m0.324s sys 0m0.006s继续加长数字长度,多加一个数字6,执行时间0.6秒
[root@localhost ichunqiu]# cat demo.py import re re.findall(r'(\d+(,)?)+ HUAIDAN$', '1111,2222,3333,4444,5555,66666 NOTHUAIDAN') [root@localhost ichunqiu]# time python demo.py real 0m0.635s user 0m0.626s sys 0m0.003s继续加长数字长度,再多加一个数字6,执行时间1.2秒
[root@localhost ichunqiu]# cat demo.py import re re.findall(r'(\d+(,)?)+ HUAIDAN$', '1111,2222,3333,4444,5555,666666 NOTHUAIDAN') [root@localhost ichunqiu]# time python demo.py real 0m1.216s user 0m1.205s sys 0m0.003s继续加长数字长度,再多加一个数字6,执行时间2.4秒
[root@localhost ichunqiu]# cat demo.py import re re.findall(r'(\d+(,)?)+ HUAIDAN$', '1111,2222,3333,4444,5555,6666666 NOTHUAIDAN') [root@localhost ichunqiu]# time python demo.py real 0m2.408s user 0m2.386s sys 0m0.003s有没有发现,执行时间,2的指数级增长!!!再来两个6,执行时间会再乘以4!!!
[root@localhost ichunqiu]# cat demo.py import re re.findall(r'(\d+(,)?)+ HUAIDAN$', '1111,2222,3333,4444,5555,666666666 NOTHUAIDAN') [root@localhost ichunqiu]# time python demo.py real 0m9.870s user 0m9.286s sys 0m0.012s而HUAIDAN,用了非常多的6,攻击者太666666666了,最终waf崩溃了。。。 看完如果还不会,自己去补课正则表达式吧~! 这类攻击,一般是让waf崩溃,真实案例“安全狗SQL注入拦截bypass”,测试语句: sql=select%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2a%20from%20manager 思考: 企业安全防护离不开各类正则匹配,而正则表达式的精通与否,决定了防火墙的能力! 希望通过本篇内容,让大家对“深入学习”有帮助,感谢坚持看完~
关注公众号:拾黑(shiheibook)了解更多
[广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
关注网络尖刀微信公众号
随时掌握互联网精彩
随时掌握互联网精彩
赞助链接
排名
热点
搜索指数
- 1 澳门是伟大祖国的一方宝地 7909304
- 2 80岁顶级富豪再婚娶33岁华裔妻子 7912700
- 3 星巴克大罢工 7823286
- 4 2024 向上的中国 7716494
- 5 向佐 我一踢腿就会走光 7600359
- 6 男子钓上一条自带“赎金”的鱼 7583565
- 7 特朗普:马斯克不会成为总统 7414818
- 8 鹿晗录制新综艺 法令纹明显 7309699
- 9 韩国一军方驻地爆炸 3名平民被烧伤 7208528
- 10 大S老公具俊晔站C位跳女团舞 7122596