@csvoss:“种子的生成方式非常简单:一个以时钟初始化的常见伪随机数生成器,现在任何人都可以复现它。这大大减少了被钻空子的空间,也让我们确信参数是安全的。”

X AI KOLs Timeline 新闻

摘要

博客讲述了作者在 GitHub Nomic 游戏中试图利用 merge commit 时间戳进行 timing attack 却被 GPG 签名阻止,最终朋友 Chelsea Voss 通过本地生成并推送无签名 merge commit 赢得游戏的故事。

“种子的生成方式非常简单:一个以时钟初始化的常见伪随机数生成器,现在任何人都可以复现它。这大大减少了被钻空子的空间,也让我们确信参数是安全的。” ——我的朋友们,就在我于 2019 年的一局 GitHub Nomic 游戏中击败他们之前所说的。当时我通过暴力搜索各种可能的 merge 时间戳,直到找到一个哈希值令我满意的为止。 https://jefftk.com/p/nomic-game-2-another-conclusion…
查看原文
查看缓存全文

缓存时间: 2026/10/17 17:00

“种子是以一种非常简单的方式生成的:一个从时钟初始化的普通伪随机数生成器,任何人都可以重现。这大大减少了被暗中操纵的空间,我们可以确信参数是安全的。” —— 我的朋友们,在我 2019 年通过暴力搜索假定的合并时间戳直到找到一个哈希值令我满意的,从而在 GitHub Nomic 游戏中击败他们之前 https://jefftk.com/p/nomic-game-2-another-conclusion


Nomic 第二局:又一个结局

来源:https://www.jefftk.com/p/nomic-game-2-another-conclusion

今早 Chelsea (https://csvoss.com/) 通过一次时序攻击赢得了我们的第二局 Nomic 游戏:

我们的游戏设定用随机数来决定是否有人获胜。实际上,每赚到一分,你就应该获得额外的十万分之一的获胜概率。随机源来自 Python 的 random.random(),这没问题。我之前写了一个 PR (#98) (https://github.com/jeffkaufman/nomic/issues/98),想把随机源改为基于 master 上最近一次合并提交的哈希值来派生。我本来就是打算进行时序攻击:合并提交应该完全可以根据其内容和当前时间来预测。思路是,我可以对每个即将到来的时间戳进行测试,看是否存在某个哈希值能让我获胜。让 git 认为时间在未来的一个非常 hacky 的方法就是把你的本地时钟调快:

CURTIME=$(date +%s) ; sudo date -s '@1549031338' && TZ=America/New_York git merge tmp-branch -m "$MESSAGE" && sudo date -s '@'$CURTIME

不幸的是,当我测试尝试利用这个漏洞时,我发现 GitHub 会对它创建的合并提交进行签名。例如:

$ git cat-file commit 182b57a9b53fc31febd9166fc03f3d91e368b64e
tree 04d5ff9335c297c203f4ee4cb5a14006bfa6abb9
parent 0c08b506c96d42d4ad8fab5c2c1701d557aa3a97
parent 6fc74cf39d7d79e8500ef4c4162decd64b82e8be
author Todd Nelling <1549324096 -0500>
committer GitHub <[email protected]> 1549324096 -0500
gpgsig -----BEGIN PGP SIGNATURE-----
 wsBcBAABCAAQBQJcWM9ACRBK7hj4Ov3rIwAAdHIIAHJ8riEtIRdzPc8lrm6lVFaN
 WvgfntWG2SyokzgiTHmMT1GQvcN6imNMi6TOfo0dWp81OamRqlbg01DXLlVhjIdy
 U23aAtERdYo3UwLNcAss/slRPUFdhQlOd7A2WqapPfjSbVZD3g1SRzjBgDyH1Tfd
 FcuI2X9+nezBRxYd3Un5p//JwdEdu9bBFMIOT7UARMsgbsOmTiQlAUpKc0mrR3yc
 y/8jli7e4sIv29+v3k5w4+DKTwfjL3WHu1WLmEtpkQWz/0Aw/N/oX/CcUgH0foVl
 CDNON4aT+bih4F+saymjJJuM3cdxJAy9MD7BjtPGEDyqHvgpgF4rNyWFgRvF4Ms=
 =2G6+
 -----END PGP SIGNATURE-----

Merge pull request #99 from pavellishin/more_verbose_rule_names

Be more vocal about which rule is being run

这意味着哈希值中包含了一些我无法控制的信息,这个方案行不通了。这时候明智的做法应该是删除这个 PR:如果我知道它有漏洞但自己无法利用它,那我也不应该给别人留下机会!但相反,我想着“应该没事的——能有可复现的随机数也挺好的“,然后就去睡觉了。

第二天早上我看到 Chelsea 赢了,对那个获胜的提交感到惊讶:

$ git cat-file commit 0003490f8179527499e1b0739fec6d1ac22662f3
tree cc61bc798249f7dbf4d12d139f9c9e3134efa87a
parent 182b57a9b53fc31febd9166fc03f3d91e368b64e
parent 1d6c32eea2556acd67c0b4e193bb4e2639bb487b
author Chelsea Voss <1549380160 -0800>
committer Chelsea Voss <1549380160 -0800>

Merge pull request #98 from jeffkaufman/consistent-random

start using reproducible random numbers

没有签名!Chelsea 注意到 GitHub 允许先在本地进行合并,然后再推送上去。你可以通过调整 git 读取的时间戳(或者等到恰好正确的时刻),为一个 PR 生成一个具有适当哈希值的本地合并提交,然后在你准备好时将合并提交推送上去(她的总结 (https://github.com/jeffkaufman/nomic/issues/100#issuecomment-460693725))。于是 Chelsea 准备了一个“易受攻击“的本地提交,用一条调侃的留言 (https://github.com/jeffkaufman/nomic/pull/98#pullrequestreview-200131830) 批准了那个 PR,然后推送了上去。GitHub 接受了合并,Travis 计算出的随机数是 0.00005,正好落在 Chelsea 的获胜区间内,我们就有了赢家!

然而事实证明,从命令行推送的合并提交不会被仔细检查,光凭这一点就足以赢得比赛。例如,我创建了一个 PR (#103) (https://github.com/jeffkaufman/nomic/pull/103),给自己扣了一分,这被允许作为积分转移而无需额外审批即可合并。然后,当 Travis 测试通过后,我从命令行用以下命令进行了合并:

$ git checkout master
$ git merge --no-ff testing-more-local-merges
$ echo 100000 > players/jeffkaufman/bonuses/tons-of-points
$ git add players/jeffkaufman/bonuses/tons-of-points
$ git commit -a --amend
$ git show ae3c5a0
commit ae3c5a01195c351f13d1ae9415e3c7412b92cddb
Merge: 5494d8e 1f73044
Author: Jeff Kaufman <[email protected]>
Date:   Tue Feb 5 17:20:42 2019 +0000

    Merge branch 'testing-more-local-merges'

diff --cc players/jeffkaufman/bonuses/tons-of-points
index 0000000,0000000..f7393e8
new file mode 100644
--- /dev/null
+++ b/players/jeffkaufman/bonuses/tons-of-points
@@@ -1,0 -1,0 +1,1 @@@
++100000

你可以看到这让我在合并提交中夹带了额外的更改,给了我 100,000 分。尽管额外的更改不在 GitHub 运行测试的那个 PR 中,我仍然可以推送这个合并提交:

$ git push
Counting objects: 6, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 497 bytes | 0 bytes/s, done.
Total 6 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
To [email protected]:jeffkaufman/nomic.git
   5494d8e..ae3c5a0  master -> master

这让 Travis 认定我赢了,虽然我实际上没有赢,因为 Chelsea 已经先赢了:

这可能是受保护分支处理方式的一个 bug?(这个 PR 的一个前提是,我之前的 PR (#97) (https://github.com/jeffkaufman/nomic/pull/97) 让我们只调用一次 random() 并给玩家分配了“获胜区间“。那个 PR 也是偷偷摸摸的,一开始会让玩家 #2——也就是我——总是获胜。不过 Pavel 注意到了这一点,我需要做了一些更新 (96d8ba)。)

Steve Weis@sweis·22h: CLAUDE 找到了种子 https://anthropic.com/research/ecdsa-curve-origins

相似文章

我逆向解析了一款桌游

Hacker News Top

作者通过反编译 Hitster 桌游的 Android 应用,破解了其使用 AES-GCM 加密的歌曲数据库,绕过了 Spotify/Apple Music 订阅限制,揭示了该应用极其草率的数据保护措施。

How hackers reverse Math.random()

Lobsters Hottest

本文演示如何逆向常见的伪随机数生成器(如线性同余生成器、XOR shift、Flash的RNG),并通过预测扫雷游戏中的地雷位置展示实际攻击,强调不要将普通随机数用于安全场景。

@BenjaminDEKR:这简直有点天才

X AI KOLs Timeline

一位开发者分享了一个小游戏:让 LLM 守卫一个保险箱,玩家通过聊天、欺骗或直接破解来套出密码,并可扮演机器人或进行 AI 对 AI 实验,支持 Codex 应用和本地模型。

@leaf_sanren: https://x.com/leaf_sanren/status/2073069608437764266

X AI KOLs Timeline

作者详细介绍了如何通过逆向工程破解微信Mac版的加密系统,使用Frida动态插桩捕获系统函数CCKeyDerivationPBKDF生成的密钥,从而解密29个加密数据库,实现了自动获取群聊记录的目标,并计划开源该项目。