逆向工程实验——pre7(密码学算法:NTLM、Playfair算法破解)

1.阅读

反调试技术总结
https://bbs.pediy.com/thread-225740.htm

https://bbs.pediy.com/thread-212371.htm

2.阅读

https://blog.csdn.net/czc1997/article/details/78167705
http://netsecurity.51cto.com/art/201605/511983.htm

3.(选做)This is one of the hardest ever exercises.

What does this code do?

Hint: the function has been copypasted from the guts of GCC, but in fact, it is present almost in all modern compilers, though, in different forms, but calculating the same value(s). Its function is highly important.

Second hint: f(f(x))=x.

Optimizing GCC 5.4 x86

f:
   mov edx, 31
   mov eax, 1
.L2:
   imul eax, edi
   imul edi, edi
   sub edx, 1
   jne .L2
   ret

这个函数是从GCC的内部复制粘贴过来的,但实际上,它几乎存在于所有现代编译器中,尽管形式不同,但计算的是相同的值。它的功能非常重要。

f:
        mov     edx, 31    //把立即数31送给edx寄存器
        mov     eax, 1		//把立即数1送给eax寄存器
.L2:
        imul    eax, edi		//双操作数的有符号乘,eax=eax*edi,结果存储在eax寄存器
        imul    edi, edi		//双操作数的有符号乘,edi=edi*edi,结果存储在edi寄存器
        sub     edx, 1		//edx寄存器的值减1,edx=edx-1,根据相减的结果置零标志ZF,结果不为0则置1
        jne     .L2			//相减的结果不为0则跳转
        ret

  imul的双操作数格式会按照目的操作数的大小来截取乘积。如果被丢弃的是有效位,则溢出标志位和进位标志位置1。因此,在执行了有两个操作数的IMUL操作后,必须检查这些标志位。
  汇编代码中三个寄存器,edi是输入的参数、edx负责从31递减到1、eax负责保存每次计算的结果。所以函数的功能是:递归调用30次,计算参数edi的edi * edi^2 * edi4 * ······ * edi1^6384的结果,保存在eax中返回。

4. NTLM:CDABE1D16CE42A13B8A9982888F3E3BE

hint:密码长度不超过5,数字和符号组成

Windows下NTLM Hash生成原理:‍‍
  IBM设计的LM Hash算法存在几个弱点,微软在保持向后兼容性的同时提出了自己的挑战响应机制,NTLM Hash便应运而生。
  假设明文口令是”123456″:
  1、首先转换成Unicode字符串,与LM Hash算法不同,这次不需要添加0补足14字节,从ASCII串转换成Unicode串时,使用little-endian序,0x80之前的标准ASCII码转换成Unicode码,就是简单地从0x??变成 0×00??。此类标准ASCII串按little-endian序转换成Unicode串,就是简单地在原有每个字节之后添加0x00。
  2、对所获取的 Unicode串进行标准MD4单向哈希,无论数据源有多少字节,MD4固定产生128-bit的哈希值。
  与LM Hash算法相比,明文口令大小写敏感,无法根据NTLM Hash判断原始明文口令是否小于8字节,摆脱了魔术字符串”KGS!@#$%”。NTLM安全性的关键在于MD4是真正的单向哈希函数,穷举作为数据源出现的明文,难度较大。
  例如:
“123456”先转换成Unicode码“310032003300340035003600”,
然后“310032003300340035003600”进行标准MD4单向哈希就得到了最后的NTLM Hash:32ED87BDB5FDC5E9CBA88547376818D4。

加密的流程就是:
(1)把字符串转成Unicode编码串;
(2)把Unicode编码串用MD4单项哈希算法生成固定128比特的哈希值。

(1)Python代码暴力破解

接下来,我们就根据加密流程来暴力破解,其中密码长度不超过5,数字和符号组成:

# py -3
# -*- coding: utf-8 -*-
# coding:utf-8

from Crypto.Hash import MD4
import string
import hashlib

# 数据字典:密码由数字和符号组成
dataDictionary = string.digits + string.punctuation
# 密码长度不超过5
for a in range(len(dataDictionary)):
    for b in range(len(dataDictionary)):
        for c in range(len(dataDictionary)):
            for d in range(len(dataDictionary)):
                for e in range(len(dataDictionary)):
                    password1 = dataDictionary[a]+"\0"+dataDictionary[b]+"\0"+dataDictionary[c]+"\0"+dataDictionary[d]+"\0"+dataDictionary[e]+"\0"
                    # print(password)
	       # 以指定的utf-8编码格式编码字符串,返回bytes 对象
                    password2 = password1.encode('utf-8')
                    # print(password)

                    # Crypto.Hash模块的MD4算法
                    # result = MD4.new()
                    # result.update(password2)
                    # if "CDABE1D16CE42A13B8A9982888F3E3BE" == str.upper(result.hexdigest()):
                    
                    # hashlib的md4算法,但是生成的明文都是小写,但是题目给的是大写,所以用str的upper函数把明文转化成大写
                    if 'CDABE1D16CE42A13B8A9982888F3E3BE' == str.upper(hashlib.new('md4',password2).hexdigest()):
                        print("CDABE1D16CE42A13B8A9982888F3E3BE对应的密码是: " + password1)
                        exit()

运行结果:
在这里插入图片描述
得到CDABE1D16CE42A13B8A9982888F3E3BE解密后的结果为:1+2=3。

(2)hashcat工具破解

因为老师提示了密码长度不超过5,数字和符号组成,直接生成攻击字典:
在这里插入图片描述
在这里插入图片描述

在cmd下运行hashcat:hashcat32.exe -m 1000 -a 0 CDABE1D16CE42A13B8A9982888F3E3BE mutou.txt
在这里插入图片描述

28秒找到了结果:
在这里插入图片描述

打开hashcat.potfile查看结果,CDABE1D16CE42A13B8A9982888F3E3BE解密后的结果为:1+2=3。
在这里插入图片描述

5.(选做)Playfair Encryption

原题目链接:https://www.mysterytwisterc3.org/en/challenges/level-i/playfair-encryption
更新后的题目链接:https://www.mysterytwisterc3.org/en/challenges/level-1/playfair-encryption

The Playfair encryption is a relatively simple monoalphabetic and
digraph substitution, which means there is only one ciphertext
alphabet but it encrypts pairs of letters. The cipher was invented by
Sir Charles Wheatstone.This kind of encryption was promoted by Lord
Lyon Playfair and was used by the British forces in the Crimean War
and in World War I, among others. Your challenge is to decrypt the
ciphertext on the following pages. Hints: The plaintext is English and
the used key is relatively short. The wanted solution is the
(fictitious) author of the plaintext and must be typed in with capital
letters.
Playfair加密是一种相对简单的单字母和有向替换,这意味着只有一个密文字母表,但它加密成对的字母。密码是查尔斯·惠斯通爵士发明的。这种加密技术是由里昂·普莱费尔勋爵(Lord
Lyon Playfair)推广的,英国军队在克里米亚战争和第一次世界大战中使用了这种加密技术。 你的挑战是解密以下页面上的密文。
提示:明文为英文,使用的密钥相对较短。希望的解决方案是(虚构的)明文的作者必须用大写字母输入。

刚开始尝试了暴力破解的方式:即一个密钥从a到z,产生的明文从25条:
在这里插入图片描述

两个密钥ab到zy,但是明文数到达了625条:
在这里插入图片描述

  随着密钥长度的增加,解密的明文条数会呈几何倍数增长,如果每一条都肉眼去看解密的明文正确与否显然是不现实的,所以这种暴力破解的方式是不可取的。
  之后我查阅资料,在找到了基于“模拟退火”(SA)算法来寻找最接近于正确密钥的随机密钥,遗传算法好像也是一个可以尝试的方向:该算法模仿自然选择的过程。每次SA算法过后都会评估随机密钥的适应性,并修改随机密钥以增大接近正确的密钥的概率。
  算法的原理可以自行搜索相关的期刊文献,最后是总能找到一个密钥长度15位的随机密钥,它被算法认为是最接近于正确密钥的一个解,用这个解得到的明文再经过分词之后,跟最后搜索找到的原文相比大概相似度有90%左右,还是很有效果的。
  明文是两首上世纪的歌,第一首是一首短的完整的摇篮曲,第二首是截取的歌曲的一部分,两首歌都是都是以同一口吻写的,最后的答案就是这个虚构的人名。
在这里插入图片描述

不敢相信这是一道level-1的题目,也可能是我没有找到更简单合适的方法,方法有点太麻烦了,就没有放具体的代码和答案了,有什么更好的建议可以在评论区评论告诉我。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
暴力破解NTLM加密算法需要对于每个可能的密码进行哈希计算,并将其与目标哈希进行比较。C++可以使用Windows API中的Cryptographic Service Provider (CSP)来实现NTLM哈希计算。以下是一个使用CSP进行NTLM哈希计算的示例代码: ```c++ #include <windows.h> #include <wincrypt.h> #include <iostream> #include <string> bool CrackNTLMHash(const std::string& hash, const std::string& charset, int length, std::string& password) { // Open a handle to the Microsoft Base Cryptographic Provider HCRYPTPROV hProv; if (!CryptAcquireContext(&hProv, nullptr, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { std::cerr << "Failed to acquire cryptographic context\n"; return false; } // Convert the hex-encoded hash to binary std::string hashBytes; for (size_t i = 0; i < hash.length(); i += 2) { hashBytes += static_cast<char>(std::stoi(hash.substr(i, 2), nullptr, 16)); } // Allocate a buffer for the hash object HCRYPTHASH hHash; if (!CryptCreateHash(hProv, CALG_MD4, 0, 0, &hHash)) { std::cerr << "Failed to create hash object\n"; CryptReleaseContext(hProv, 0); return false; } // Iterate over all possible passwords std::string passwordHash; for (int i = 0; i < length; ++i) { std::string password(length, charset[0]); do { // Hash the password if (!CryptHashData(hHash, reinterpret_cast<const BYTE*>(password.data()), length, 0)) { std::cerr << "Failed to hash data\n"; CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); return false; } // Get the hash value DWORD hashLength = 16; BYTE hashValue[16]; if (!CryptGetHashParam(hHash, HP_HASHVAL, hashValue, &hashLength, 0)) { std::cerr << "Failed to get hash value\n"; CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); return false; } // Compare the hash value to the target hash passwordHash.assign(reinterpret_cast<const char*>(hashValue), hashLength); if (passwordHash == hashBytes) { password = password.substr(0, i) + password[i] + password.substr(i + 1); break; } // Reset the hash object if (!CryptDestroyHash(hHash) || !CryptCreateHash(hProv, CALG_MD4, 0, 0, &hHash)) { std::cerr << "Failed to reset hash object\n"; CryptReleaseContext(hProv, 0); return false; } } while (std::next_permutation(password.begin(), password.end(), [&charset](char a, char b) { return charset.find(a) < charset.find(b); })); } // Release resources CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); // Check if the password was found if (passwordHash == hashBytes) { password = password.substr(0, length); return true; } else { return false; } } ``` 该代码将目标哈希作为十六进制字符串传递,因此您需要将其从NTLM哈希格式转换为十六进制字符串。此外,您需要为字符集和密码长度指定值。代码将在字符集中迭代所有可能的密码,并使用Cryptographic Service Provider计算NTLM哈希。如果找到密码,则将其保存在传递的字符串参数中并返回true,否则返回false。注意,这是一种非常低效的方法,因为它需要尝试所有可能的密码。在现实世界中,密码长度和复杂度通常足以使暴力破解成为不切实际的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值