惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
Lohrmann on Cybersecurity
Martin Fowler
Martin Fowler
Engineering at Meta
Engineering at Meta
腾讯CDC
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Azure Blog
Microsoft Azure Blog
G
Google Developers Blog
TaoSecurity Blog
TaoSecurity Blog
博客园_首页
Vercel News
Vercel News
Hugging Face - Blog
Hugging Face - Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Last Week in AI
Last Week in AI
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
The Exploit Database - CXSecurity.com
量子位
Project Zero
Project Zero
A
Arctic Wolf
小众软件
小众软件
NISL@THU
NISL@THU
C
CERT Recently Published Vulnerability Notes
有赞技术团队
有赞技术团队
MongoDB | Blog
MongoDB | Blog
博客园 - 聂微东
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
N
News and Events Feed by Topic
宝玉的分享
宝玉的分享
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Troy Hunt's Blog
P
Privacy & Cybersecurity Law Blog
Security Latest
Security Latest
B
Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
D
DataBreaches.Net
Schneier on Security
Schneier on Security
The Hacker News
The Hacker News
K
Kaspersky official blog
C
Check Point Blog
Hacker News: Ask HN
Hacker News: Ask HN
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Webroot Blog
Webroot Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
人人都是产品经理
人人都是产品经理
AI
AI
Cisco Talos Blog
Cisco Talos Blog
MyScale Blog
MyScale Blog
Cloudbric
Cloudbric
B
Blog RSS Feed
S
Schneier on Security
P
Palo Alto Networks Blog

Posts on Changkun's Blog

Why High-Output Systems Are Often the First to Stop Growing Dark Forest Theory: A Formal Derivation Agents (or Humans) in Goal-Directed and Goalless Environments: On Pipelines, Priors, and the Rhythm Between Exploration and Exploitation At the Boundary of Self-Reference: From Stable Structures in Artificial Intelligence to the Self as a Recursive Model in an Open Dissipative System 2023 Reading List 2022 Reading List 2021 Reading List Are PSS/USS and RSS Actually the Same Thing? Performance Differences from Page Faults vs. Prefetching 2020 Year-End Review Migration with Zero Downtime 2020 Reading List The All in Go Stack Pointers Might Not Be Ideal for Parameters Eliminating A Source of Measurement Errors in Benchmarks Setup Wordpress in 10 Minutes 我为什么不再写博客了? 2019 年终总结 2018-2019 读书清单 Ten years of blogging Rethinking the Reflections on Communications and Trusts 2018 年终总结 Go source code study is open source Go source study: unsafe Pattern Go source study: sync.Pool Go runtime programming A Million WebSocket and Go Designing Asynchronous RESTful APIs 分布式杂谈01:CAP 理论的误解 Issues of Human-Bot Interaction 压缩法与深度网络的泛化性 Go in 1 Hour UMSLT04: The Past and Present of SGD UMSLT03: A Gentle Start of Learning Theory UMSLT02: A Breif History of Neural Networks UMSLT01: A Breif History of Regularization 不笑不足以为道 论文笔记:Generalization in Deep Learning 2017 年终总结 2017 读书清单 深度学习的泛化理论简介 删除 GitHub 上已经提交的敏感信息 硕士生涯的第一年就这样告一段落了 人肉计算(10): 系统参与激励 人肉计算(9): 陷阱的解法 别聊,一聊你就暴露 人肉计算(8): 人肉计算与数据科学中的陷阱 人肉计算(7): 社会行为分析 Hexo + GitHub + Travis CI + VPS 自动部署 人肉计算(6): 预测市场 人肉计算(5): 信用风险评级模型 读书与回报 瞎扯: 对现代企业理论与当下IT企业的商业模式和信息产业链的规律性的思考 人肉计算(4): 输入数据聚合与PageRank 又一次打整了一下博客 人肉计算(3): 输入数据聚合与链路预测 人肉计算(2): 意图博弈 GWAPs 人肉计算(1): 众包与群众智慧 对后辈同学在计算机专业上的答疑与解惑 在德国的医疗及住院体验 这可能不是一个技术博客了 实验楼楼赛第3期-Python-题解 迅速更换了 DISQUS Electron 深度实践总结 良好的编码体验的三个方面 2016 年终总结 2016 读书清单 最近在着手写的文章 微信小程序文档极致总结 谈谈过去三个月在实验楼的实习经历 Built a Desktop Client for My Blog Guacamole 源码分析与 VNC 中 RFB 协议的坑 《高速上手 C++11/14》正式发布 Docker 极速入门教程02 - 镜像与容器管理 Docker 极速入门教程01 - 基本概念和操作 阶段性沉默 ELK+Redis 最佳实践 终于全面启用了 HTTPS 苹果开源了LZFSE无损压缩 记一次完整的 Kaldi-TIMIT 示例运行 Kaldi 上的 TIMIT 例子 Kaldi 安装与部署 从科研写作谈起 Swift API 设计指南 有趣的人类 所以其实论文并没有什么鬼用 Githug 通关记录及指南 小结一下这学期的收获 2015 读书清单 2015 年终总结 负能量爆表 转眼就快两个月了 博客迁移记录 大三总结 这个世界,终究不会是我们的。 Linux 内核分析 之六:Linux 内核创建进程的过程 小说「泽缘」 Linux 内核分析 之五:system_call中断处理过程的简要分析 大创项目的标题真是每年都在考验同学们的想象力啊 Linux 内核分析 之四:使用库函数API和嵌入汇编两种方式使用同一个系统调用
Hash 碰撞的一种思路
Changkun Ou · 2016-07-09 · via Posts on Changkun's Blog

Published at发布于:   |   PV/UV: /   |   Reading阅读: 3 min

今天在熊猫 TV 上看乌云白帽子大会,下面有三道互动的题目挺有意思的。

前面两题都很简单,第一题是解一个莫斯电码、第二题答案很简单,但是要提交答案需要在网页源码上懂点手脚。

第三题是重头戏,不过难度也不高,题目如下:

第三题每个人的答案都不一样,图片里被我划掉的这部分是我的用户名(手机号) K。

红色部分的一串数字就是经过上面的 DEKHash 算出的结果,所以题意就很明显了,找到 K' 使得 DEKHash(K') == DEKHash(K)

题目中给出的是 Java 代码,我作为 Java 黑,显然是不能忍受的,所以弄成了 C++的版本:

1
2
3
4
5
6
7
long DEKHash(string str) {
    long hash = str.length();
    for(int i = 0; i < str.length(); i++) {
        hash = ((hash<<5)^(hash>>27))^str.at(i);
    }
    return hash;
}

下面来看我是怎么寻找这样的 K'

思路

本科的时候对安全相关的技术很有兴趣,但是由于各种忙从来没接触过,今天刚好又是周六看起了直播,所以也算是第一次尝试。

首先,这个 DEKHash 的计算方法显然是跟字符串的长度有关的,所以我们寻找的碰撞 K' 的长度应该和我们原来的 K 的长度相同。

验证纯数字

因为用户名是手机号码,所以一开始我会想要穷举11位的所有手机号是否有重复的 Hash:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
void find() {
    long i = 15900000000;
    while(true) {
        string str = to_string(i);
        long value = DEKHash(str);
        if(value == 379207836497504850) {
            cout << "find:" << i << endl;
            break;
        }
        cout << "current: " << i << " value: " << value << endl;
        i++;
    }
}

不过跑了一段一小会儿就放弃了,但是从观察到的输出来看,发现了一个规律:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
current: 15900270751 value: 379033047429333661
current: 15900270752 value: 379033047429333662
current: 15900270753 value: 379033047429333663
current: 15900270754 value: 379033047429333656
current: 15900270755 value: 379033047429333657
current: 15900270756 value: 379033047429333658
current: 15900270757 value: 379033047429333659
current: 15900270758 value: 379033047429333652
current: 15900270759 value: 379033047429333653

current: 15900270760 value: 379033047429333756
current: 15900270761 value: 379033047429333757
current: 15900270762 value: 379033047429333758
current: 15900270763 value: 379033047429333759
current: 15900270764 value: 379033047429333752
current: 15900270765 value: 379033047429333753
current: 15900270766 value: 379033047429333754
current: 15900270767 value: 379033047429333755
current: 15900270768 value: 379033047429333748
current: 15900270769 value: 379033047429333749

在这个结果下,只有末尾号码发生变化,最后算出来的值只有最后两位才会发生变化。

所以很明显,如果只是纯数字的号码,找到Hash 值相同的 K' 只能够在最后一位不同的情况下寻找,一共才十个号码,很容易验证没有这样的 K'

所以纯数字的结果马上就可以放弃了。

随机搜索

最开始的时候我们已经分析过K'的串场要与K相同,既然纯数字不可能,那么只能从字符串中搜索了。

下面这个函数是一个生成长度为 len 的随机字符串,字符串会包含数字、大小写字母。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
void gen_random(char *s, const int len) {
    static const char alphanum[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";
    for (int i = 0; i < len; ++i) {
        s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
    }
    s[len] = 0;
}

这样的话,我们重新编写搜索函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void random_find() {
    while(true) {
        int search_length = 5;
        
        char *str = new char[search_length];
        str[search_length-1] = '\0';
        gen_random(str, search_length-1);
        
        string first = "3x63qqR";

        string sec(str);
        
        string real = first+sec;
        long value = DEKHash(real);
        if(value == 379207836497504850) {
             cout << "find:" << real << endl;
             break;
        }
        cout << "current: " << real << " value: " << value << endl;
        delete [] str;
    }
}

这样的话,跑一跑马上就能找到了:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
current: 3x63qqRzvgF value: 379207836495569058
current: 3x63qqRFa6M value: 379207836493854345
current: 3x63qqRrPWN value: 379207836495281834
current: 3x63qqRQBTF value: 379207836494313154
current: 3x63qqRQor5 value: 379207836494268017
current: 3x63qqR4sVH value: 379207836497605260
current: 3x63qqRtJzX value: 379207836495450908
current: 3x63qqRgQUH value: 379207836494920428
current: 3x63qqRoSaC value: 379207836495180903
current: 3x63qqR217I value: 379207836497475245
current: 3x63qqRE7KR value: 379207836493832502
current: 3x63qqRz5Ts value: 379207836495637239
current: 3x63qqRFLPJ value: 379207836493811278
find:3x63qqR7ts6

你可能会问,string first = "3x63qqR" 这段是怎么来的?

首先这段字符串并不知道,是一步步迭代来的。

string first 首先应该设置为 "",而 search_length 的值设置为 12(留一个单元保存 \0),然后开始跑结果,当然不太可能马上就能获得结果,但是我们至少能够获得一部分结果,然后在输出的结果中用我们已知的 hash 值的一部分在 value 中搜索以 379207836497504850 前面几位开头的值,查找有没有匹配的结果,如果有,反复人肉,就能够一步步得到所需的串头了。

自动碰撞程序

人肉方案做出来显然有点低效率,我们不如编写一个自动化搜索的函数,这稍微需要一点精力,思路是,可以先随机跑出来一定大小的样本,然后在样本中进行搜索,确定一小部分串头,如此反复。

但是从另一方面看,其实我是第一个解出这道题的人,用的就是人肉的方法,如果还要花精力编写一个自动碰撞的程序,可能就不会是第一个解出的人了。

所以,既然思路已经有了,这个程序就留给有意者写吧。