出题战队:98k
设计思路
1、题目设计思路/背景
2、赛题实现和漏洞
Hmac 伪哈希碰撞:hmac 的 key 是会有预填充以及可能的预哈希操作的,因此题目提供的注册服务可能导致其他用户能够注册得到 admin 的私钥。比如 admin 公钥后面填充若干 0 字节,能够得到 admin 的等价私钥,经过认证即可越权操作
BLS12-381 曲线的子群攻击(Subgroup Attack):blind recovery 服务提供了潜在的 BLS12-381 子群上 DH 的交互。加之 rust 标准实现没有检查子群,因此可以恢复出 PKG 设施的部分私钥。
RSA-LSB-Oracle :可以通过 system reset 功能巧妙转换得到一个类似 RSA 低位解密泄露的 Oracle 场景,进而恢复出更多信息,最终能够通过 BSGS 求解离散对数恢复出完整的 PKG 私钥,从而破解整个系统的安全性。
3、exp 运行截图
cargo run --release
赛题解析
1、Writeup
Hmac 伪哈希碰撞:hmac 的 key 是会有预填充以及可能的预哈希操作的,因此题目提供的注册服务可能导致其他用户能够注册得到 admin 的私钥。比如 admin 公钥后面填充若干 0 字节,能够得到 admin 的等价私钥,经过认证即可越权操作。
BLS12-381 曲线的子群攻击(Subgroup Attack):blind recovery 服务提供了潜在的 BLS12-381 子群上 DH 的交互。加之 rust 标准实现没有检查子群,因此可以恢复出 PKG 设施的部分私钥。
RSA-LSB-Oracle :可以通过 system reset 功能巧妙转换得到一个类似 RSA 低位解密泄露的 Oracle 场景,进而恢复出更多信息,最终能够通过 BSGS 求解离散对数恢复出完整的 PKG 私钥,从而破解整个系统的安全性
2、Identity Based Encrytion
哈希映射:使用了 hmac2g1
,即使用了 hmac 函数,而不是一般的哈希函数。
密钥生成:增加一个 make_key_blind
函数,类似盲分发密钥,限制了只有 admin 才能调用这个函数。
3、HMAC 伪碰撞
pub fn hmac2g1<T>(msg: &str, pk: &T) -> G1Affine
where
T: Hashable,
{
let data = pk.hash();
let mut keyed_hmac = <HmacFunc as Mac>::new_from_slice(msg.as_bytes()).unwrap();
keyed_hmac.update(&data);
let result = keyed_hmac.finalize().into_bytes();
let result = result.as_slice();
let x = BigUint::from_bytes_be(result);
let xr = Fr::from_str(&x.to_string()).unwrap();
G1::one().into_affine().mul(xr).into_affine()
}
hmac2g1(uname, pkg.gs)
,根据注册函数给出的逻辑,这个 uname
是用户可控的任意字符串(邮箱),但是不能多次注册同一个 uname
,以及禁掉了 [email protected]
的注册。用户想要获取 admin 的权限,必须拿到 admin 的私钥。那么是否能够找到两个字符串 a
和 b
使得上述 hmac2g1(a, pk)
与 hmac2g1(b, pk)
得到相同的值,从而生成一样的私钥?uname
作为 hmac
函数的密钥输入,是不安全的。根据 hmac
的一般框架在 K 小于分组长度时:通过用 0 向右填充直至 blocksize,得到 K'
在 K 大于分组长度时,通过先哈希到小于或等于块大小,然后用 0 向右填充。
uname
长度小于分组长度时:形如 uname
和 uname + \x00
形式的字符串是等价密钥。
uname
长度大于分组长度时:形如uname
与 H(uname)
的字符串也会生成等价密钥。
[email protected]
与 [email protected]\x00
会生成相同的私钥,因此只需要注册一个 [email protected]\x00
字符串的账号,就能拿到 [email protected]
的私钥以及 credential (私钥的哈希),从而认证后获得 admin 权限。4、BLS12-381 曲线子群攻击
p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
K = GF(p)
a = K(0x00)
b = K(0x04)
E = EllipticCurve(K, (a, b))
G = E(0x17F1D3A73197D7942695638C4FA9AC0FC3688C4F9774B905A14E3A3F171BAC586C55E83FF97A1AEFFB3AF00ADB22C6BB, 0x08B3F481E3AAA0F1A09E30ED741D8AE4FCF5E095D5D00AF600DB18CB2C04B3EDD03CC744A2888AE40CAA232946C5E7E1)
# E.set_order(0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001 * 0x396C8C005555E1568C00AAAB0000AAAB)
full_order = E.order()
print(factor(full_order))
3 * 11^2 * 10177^2 * 859267^2 * 52437899^2 * 52435875175126190479447740508185965837690552500527637822603658699938581184513
pub fn make_key_blind(&self, x: Fq) -> Option<PrivateKey> {
if let Some(g) = get_point_from_x(x, false) {
Some(PrivateKey::new(self.pk, g.mul(self.x).into_affine()))
} else {
None
}
}
fn blind_recovery(&self, x: Fq) -> Option<Hash> {
// only server_admin can do this
if let Some(sk) = self.pkg.make_key_blind(x) {
Some(sk.gx.hash())
} else {
None
}
}
blind_recovery
函数中,admin 控制输入参数 5、LSB Leak Oracle
fn reset_system(&mut self, mul: &Fr) -> Option<bool> {
// not 1 or 0
if mul == &Fr::from_str("1").unwrap() || mul == &Fr::from_str("0").unwrap() {
return Some(false);
}
let mut super_x = self.pkg.x.clone();
super_x.mul_assign(mul);
let pkg = PKG::new(super_x);
let admin_sk = pkg.make_key(&self.admin);
let user_store: UserStore = Mutex::new(HashMap::new());
{
let mut muser_store = user_store.lock().unwrap();
muser_store.insert(self.admin.clone(), admin_sk.gx.hash());
}
self.pkg = pkg;
self.user_store = user_store;
Some(true)
}
球分享
球点赞
球在看
点击阅读原文查看更多