type
status
date
slug
summary
tags
category
icon
password
internal_system 挺有意思的,复现完学到了刷多 (
签到题
考点:PHP供应链攻击
php 近期爆的漏洞,一开始就看到了,
喔?你说这个我可就不困了,(我是个爱看新闻的好孩子 逃
但是,,User-Agentt 看成了 User-Agent,,没成,然后被另一个地方吸住了眼球,在搞 guestbook.php 草。。
直到官方放出提示,我不信邪在看了一遍
unsetme
考点:CVE-2020-5203 补丁绕过
源码
也是有故事
开开心心本地分析了一波弄出来了,线上一打,啥返回都没= =,,我在想..
你这不是考察 CVE-2020-5203 根据 3.7.2的代码修改记录 https://github.com/bcosca/fatfree-core/commit/dae95a0baf3963a9ef87c17cee52f78f77e21829 来写 3.7.1 的exp么?
你不是。。3.7.2 吧?晕,于是想办法找,找到了 changlog 来确定版本
草,慢慢分析吧,其实漏洞触发点是类似的
由上两图,
$f3
是 Base
实例,这个类重载了 __unset
魔术方法,然后这个 $key
参数是可控的也就是说,调用
unset($f3->$a);
会触发该魔术方法,跟进 $this->offsetunset
方法,调用 $this->clear
方法继续跟进,
刚刚说到,这个
$key
参数是可控的,也就是说,这个 eval
里的 $val
是可控的问题是,3.7.2 版本打过补丁,
$this->compile
方法和之前的不同,如果用 3.7.1 版本的exp 打,断点调试,会发现最终 $val
构造出来是类似于 "['xxx;eval_code']"
,无论怎样都会被包括在引号里的。先传入
/?a=s
右边红框框住的部分和原本有点不一样,就是把写在一起的提取出来,赋值到变量里方便查看变化
经过
$this->compile
预处理值 $pre
为 $hive['s']
,要后被
eval
的部分 $pinjie
为 "unset($this->hive['s']);"
。到这里我们明白了大概的数据流,即设法构造
$_GET['a']
使我们的恶意代码可以被 eval
这里绕过有两个点
- 数组闭合
- 注释闭合多余部分
继续尝试构造传入
a=s[]);
可以看到
$pre
部分已经成功被闭合了,但是有个问题,$pinjie
部分拼接不正常unset($this->hive['s']['']);
这部分正常,但多了 );
至于为什么我这么熟练,直接用数组给闭合了,,因为一开始,,在分析 3.7.1 时,把代码流,包括$this->compile
部分给整明白了,然后 3.7.2 重构了$this->compile
很类似,有兴趣可以去看看,就是正则有点多和复杂。。。看的头皮发麻
尝试传入
a=s[]);phpinfo();//
这样,反正后面多了的 );
会被注释掉(好像和我新年出的 CTF 有点像,要闭合加注释),断点看看呗然后线上环境 cat 一下就好了
"慢慢做" 管理系统
没做出来,写思路,后续补上
提示
第一步登录的sql语句是"SELECT * FROM users WHERE password = '".md5($password,true)."' limit 0,1";
元老级
md5($password,true)
绕过,以前实验吧刷过,可以看以下链接但是。。黑人问号.jpg
好,你说题目描述重要
这个sql吧,有点ssrf的样子,首页是一个很普通的sql注入,没有什么花样,但是我的admin.php是一个内网的管理系统,只要你用“真-admin”的密码登录了,就可以拿到flag,反正慢慢做就对了,不要急躁,静下心。
完全不知道 ssrf 的点在哪,一共就发现 index.php admin.php 和 flag.php 三个文件,好了,没思路了。(还是太菜了
emm,看来别人的wp,发现原来,,除了 ffifdyop 还有其他的,晕....
坐等 buu 出复现 (
5月6更
buu 群问了下,说不会出复现环境了,参考其他师傅的题解吧~
internal_system
没做出来,但是感觉接近了
admin/admin 一把梭,
密码竟然是错的,不过有提示
访问
/source
获取源码查看
login
方法,也就是要满足以下条件和
其中我们传入的为
然后见代码 13 和 15行
也就是说,用户名和密码都要是 admin 但是,,他们长度和内容不一样 = =,好,非常好,还好 js 有的特性和 PHP 有点类似,
username
用数组即可绕过登录成功后,我们要想办法访问
/flag
接口,不过必须为内网 ip代码里提供
/proxy
接口可以代理访问,然后这个接口是本机访问的,所以可以跳过这个限制绕过点1
你传入的要是ip,,不能是域名,而且,ip必须是公网ip,其实这个好办,整个公网服务器,然后
写入代码重定向即可
至于为啥在这里写
/flag
是因为内部代理请求不会触发这个waf 机制绕过点2
构造一下
即可得到提示,
大概意思是他们在内网部署了 netflix conductor 服务器,让我们 SSRF 一下,这里熟悉 docker 的 果果 同学跟我说题目都是 docker 搭建的,会不会,,这个 netflix 服务也是 docker 来的呢?
膜拜.jpg ,至于为什么知道是 8080 端口,搜一下 netflix 官方部署文档,就 8080 和 5000 两个端口。
当然,这里还有小差曲,我一开始暴力破解,,内网ip 和 端口,直接把它给弄宕机了。。。
源码有点长,提取关键部分
访问这个 json 文件
然后到这就卡住了
网上搜了一下 CVE, https://xz.aliyun.com/t/7889 毕竟 SSRF 常见都是和 Redis 之类的的,一般都是公开漏洞,然后接口好像也可以正常访问
正打算看看能不能 CRLF 啥的,看看能不能发送 POST 请求过去利用 CVE,但突然就访问不了了,,,
不知道思路是不是跑偏了,然后被举办方给看到了 ,就直接卡了,然后就没啥时间了,也没来得及试其他的,坐等 wp,我很好奇.jpg
4月22日更
好了,原来思路没有跑偏,我们继续(刚肝完论文
不过在 buu 的复现环境里直接给出了netflix 的内网ip,不用我们猜docker网段然后爆破,我们直接fuzz下图3个网段 8080端口即可
最近刷了一些SSRF题,发现还可以用 0.0.0.0 的方式去绕过 IP 限制,访问 0.0.0.0 默认是解析到本机上的,然后恰好 nodejs 的
IP.isPublic(host)
函数会把他视为公网IP。注意fuzz线程不能太高,不然服务容易崩,最终发现netflix在 10.0.219.14:8080
现在网上搜了一下,发现有多个的漏洞,所以先确认一下 netflix 的版本,
先请求一下根路径发现源码有中暴露的api路径
请求一下会返回json格式内容
复制json 格式化一下发现 admin config 就在第一处,,
请求一下
发现 netflix 版本为 2.26.0,网上查了下,只发现 2.25.3 版本的漏洞
看了一下 commit 记录,发现这个版本已经修了的
看了一下大佬的复现,发现思路是对了,CRLF POST 利用 netflix 的 CVE
经过这次比赛,发现,有时候版本不对就先试试临近版本,看看能不能死马当活马医 (
首先要复现 CVE-2020-9296,先保证在本地能正常利用。
CVE-2020-9296 复现
漏洞分析
先搭建一下环境,复现一下
回到上面的 https://xz.aliyun.com/t/7889 链接
Netflix Conductor uses Java Bean Validation (JSR 380) custom constraint validators. When building custom constraint violation error messages, different types of interpolation are supported, including Java EL expressions. If an attacker can inject arbitrary data in the error message template being passed to ConstraintValidatorContext.buildConstraintViolationWithTemplate() argument, they will be able to run arbitrary Java code.本次漏洞成因在于自定义约束冲突时的错误信息支持了 Java EL 表达式。如果攻击者可以控制ConstraintValidatorContext.buildConstraintViolationWithTemplate() 函数的参数,那么可以通过注入 Java EL 表达式进行任意代码执行。
全局搜一下
buildConstraintViolationWithTemplate(
发现多处有用到,并且参数利用 String.format(0)
生成的格式化字符串,格式化过程中存在用户可控的变量 taskDef.getName()
至于怎么发现的 TaskTimeoutConstraint.java
文件存在可利用点,可能排查起来就需要些时间和耐心了,这里跟着来先。下一步继续关注
TaskTimeoutConstraint.java
在哪被使用,定位到 common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskDef.java
文件,其实也有多处引用,。找漏洞利用点的大佬辛苦了~可以看到
TaskTimeoutConstraint
注解到了 TaskDef
类上,那么下一步进行看 TaskDef
类会在哪里被使用,继续搜索全局引用,可以看到 jersey/src/main/java/com/netflix/conductor/server/resources/MetadataResource.java
会
把该类和路由 /api/metadata/taskdefs
绑定,即我们通过请求该路由,即可获得 TaskDef
对象。官方给出的访问 API 稍微修改后如下
所以漏洞最终的利用逻辑如下:
- 通过 POST 请求访问 URL
/api/metadata/taskdefs
创建TaskDef
对象
- 根据官方API给出的demo稍微修改后,参数中的
timeoutSeconds
和responseTimeoutSeconds
满足了taskDef.getTimeoutSeconds() > 0
以及taskDef.getResponseTimeoutSeconds() > taskDef.getTimeoutSeconds()
这两个条件,TaskTimeoutValidator
校验失败,TaskDef
的name
属性作为错误信息的一部分通过buildConstraintViolationWithTemplate(0)
输出
- 由于
name
是我们构造好的 Java EL 表达式,所以最后该表达式会被执行,进而成功触发远程代码执行
漏洞利用
还自带 docker-compose.yaml 也太贴心了吧 (
由于刚刚下载的就是2.25.0版本,所以直接切到 docker 目录,在 up 一下就好
如果期间有下载错误啥的,可以尝试代理或者 up 多几下。
注意事项
无论下面是自己写 BCEL 还是 直接用现有的工具,都要注意 Java的版本,我本地用的是 1.8.0_144 版本。
这里还篇有趣的文章,BCEL ClassLoader去哪了 ,我感觉和这个有关,2333
据网上看,好像保证 Java 版本 < Java 8u261 即可。
自己写一个,熟悉一下BCEL
依赖下载地址:
Main.java
Exp.java
这个POC我在本机可以打成功,但是通过 curl 打实际docker环境 shell 就反弹不回来,然后也试了各种方法 sh 反弹方法,毕竟是 docker最简环境嘛,一般里面除了 sh 能用其他基本没啥了。
然后突然想起之前看到这篇酒仙桥的文章,他遇到的情形和我一样。然后通过 java 编写 socket 的思路来反弹shell,这样可以不依赖于具体的系统环境。
真 Exp.java
当然可以不反弹shell,可以通过 wget 之类的方式下载到本地在加载,
不过就是想复现一下,万一以后遇到了 HTTP 不出网呢 (
结构如下
BCEL编码后的恶意代码
直接用现有工具
也是先写好 exp,然后
BCEL编码后的恶意代码
构造POC
得到编码后构造 POC ,主要是替换 name 部分为 EL表达式,内容为
com.sun.org.apache.bcel.internal.util.ClassLoader
加载器加载BCEL编码后的恶意代码成功反弹shell
根据漏洞相关的 pull requests:https://github.com/Netflix/conductor/pull/1543 可以定位对该漏洞的修复开发者将org.hibernate:hibernate-validator
替换为了org.apache.bval:bval-jsr
,而后者在最新版本下不会解析 Java EL 表达式,所以也不会有 RCE 的危险。
好,本地复现成功,把这个 POC 直接打线上,估计问题不大
回到题目中
现在漏洞是可以尝试去利用了,问题是,题目只提供 GET 的代理,无法发送 POST 请求。
继续沿着一开始的思路走,CRLF SSRF
guguru了一下,nodejs CRLF 漏洞,发现还真有2333
这篇写的比较详细,跟着复现一下
然后看了别人的复现,发现有一个比较隐秘的提示。。
中间藏了个 8,, nodejs8 is best,2333 不过不伤大雅,眼睛不好网上搜一下也可以知道 nodejs HTTP库包含了阻止CRLF的措施,普通 CRLF不管用,但可以通过 nodejs 的设计不严谨问题来绕过。当然这个问题在 nodejs10 被修复了,如果请求路径包含非Ascii字符,则会抛出错误。
nodejs < 9版本 CRLF注入
对于 Node.js v8 或更低版本,如果有下列情况,任何发出HTTP请求的服务器都可能受到通过请求拆实现的SSRF的攻击:
- 接受来自用户输入的Unicode数据
- 并将其包含在HTTP请求的路径中
- 且请求具有一个0长度的主体(比如一个
GET
或者DELETE
)
由于本机是 node10+,所以docker拉个镜像,
进入容器的node环境,然后试试普通的 CRLF
返回包
nodejs Unicode 字符损失原理
当 Node.js v8 或更低版本对URL发出的
GET
请求进行处理时,它不会进行编码转义,因为它们不是HTTP控制字符,但HTTP请求返回的结果中会被编码为 latin1
编码写入路径,但 latin1 编码为单字节编码(编码范围为 0x00
- 0xFF
,其中 0x00
- 0x7F
之间完全和ASCII一致,0x80
- 0x9F
之间是控制字符,0xA0
- 0xFF之间是文字符号 ),如果此时我们用单字节 8位 Unicode 编码,那么高 4 位会被截断。构造请求
返回包
观察
\u{220D}
和 \u{330A}
,其中 22
和 33
随意,什么都行,因为最终高 4 位都会被截断,然后 0D
和 0A
分别为 \r
和 \n
的 ASCII码,然后Latin1是向下兼容ASCII码的,所以返回包被 \r\n
截断了, tari
变在第二行可见,可以通过构造 Unicode字符,在 nodejs 实现 CRLF注入。
在实际使用时,因为 CRLF + SSRF 点 在 HTTP 状态行,所以要注意闭合原有的状态行中的
HTTP/1.1
,即保证注入后有正常的 HTTP 状态行,先举个例子,假设目标主机存在SSRF,需要我们在目标主机本地上传文件。我们需要尝试构造如下这个文件上传的完整 POST 请求:
为了方便,我们将这个POST请求里面的所有的字符包括控制符全部用上述的高编号Unicode码表示:
构造请求:
返回包
在SSRF中我们经常使用 Gopher 协议去攻击内网应用,比如Redis、MySQL、FTP等。但是当 Gopher 协议被过滤了之后,我们还可以通过HTTP协议并配合CRLF漏洞进行攻击,达到与 Gopher 协议一样的效果。
至此,完成了 nodejs CRLF 注入复现
再次回到题目中
现在我们可以通过 题目的
GET
代理发送 POST
请求(假如题目中的 node 版本是 < 9),现在尝试利用漏洞,看看是否能利用成功。构造 POC,node 或 F12 控制运行
这里的 encodeURI 编码 1 次是防止传输过程中特殊字符被干掉 。
console.log(poc)
输出的东西替换 HTTP 包第一行即可。成功反弹
这个题目流程有点多,做个小总结
- nodejs 数组绕过管理员登录
isPublic
绕过,通过 /proxy 获取 /flag 得到提示
- 通过 docker 默认网段,或者题目给的提示 fuzz 内网网段的8080端口
- 构造 CVE-2020-9296 Netflix Post POC 反弹 shell
- 利用 nodejs < 9 进行 CRLF注入,发送 CVE-2020-9296 Netflix Post POC
- 最终通过 cat /flag 获取 flag