目前,我正在经历不同的Crackme难题,现在我被困住了。我花了几天的时间来解决它,但我不能。
我们输入登录名和密码。然后,我们在登录时应用算法#1。以及密码的第二算法。在这两种情况下,我们都会得到一个数字。如果两个数字相等,则密码正确。我正在尝试找到一种为任何给定的登录名生成正确密码的方法。
登录算法
登录名至少应包含4个字符。
login = "Vasya_Pupkin"
1)登录后,我们得到前两个字符(“ Va”)和后两个字符(“ in”),并将其ASCII码写入十六进制数:字符串并加总所有ASCII代码:某个数字0xfec0135a:
V = 0x56, a = 0x61, i = 0x69, n = 0x6e
hexVain = 0x5661696e
密码算法
密码应至少为12个字符,并且应仅包含'a'-'f' ,'A'-'F','0'-'9'。
我们输入密码作为字符串。然后将长度除以2。
for (int j = 0; j < login.length(); j++)
asciiSum += login[j];
然后将字符串表示形式转换为十六进制并应用此算法:
我们从左到右遍历每个字节并计算新的魔术值。
hexVain ^ asciiSum ^ 0xfec0135a
magicValueLogin = 0xa8a17eee
该函数的输出如下:
password_str = "011c0d0f090e00";
n = password_str.length() / 2; // n = 7
最终我们得到
Vasya_Pupkin
,它与登录时获得的值相同,因此密码正确。结论那是个坏主意。 #1 楼
当您刚开始使用RE时,请尝试研究SAT解算器。 Z3是一个很棒的工具,它将通过所有主要语言的API来帮助您完成如此简单的任务。这是我在python中尝试的解决方案。password = BitVec("password",64)
magicValuePass = BitVec("magicValuePass",64)
s = Solver()
idx = 7
magicValuePass = (((password&(0xff<<(8*idx)))>>(8*idx))^ (32 * 0xadde + 1) ^ 0xdeadbeef) & 0xffffffff
for i in xrange(6,0,-1):
magicValuePass = (((password&(0xff<<(8*i)))>>(8*i))^ (32 * magicValuePass + 1) ^ 0xdeadbeef) & 0xffffffff
s.add(magicValuePass == magicValueLogin)
if s.check() == sat:
print hex(s.model()[password].as_long())
首先声明
password
为64位变量。然后逐字节迭代计算中间值,最后将magicValuePass
设置为等于magicValueLogin
。如果存在针对此类条件的解决方案,则Z3将运行一段时间并给出打印出来的解决方案。评论
我同意,SAT解算器是数学的出路。但是,您的示例不正确:login:ABCD的幻数为0xbf825114,密码:1171f0902111a00的幻数为0x79660be7。没有比赛!
– Yaspr
17-10-9在10:57
我认为我的假设可能有缺陷,例如采用64位密码并且只能在低56位上运行,但是一旦给出了二进制,我就可以验证我想要并假设的东西。我只是想给他一些尝试的方法,而不是给出一个完整的解决方案。
– sudhackar
17-10-9在11:10
@sudhackar哇,行得通!我已经在crackme拼图中尝试了这两个示例,并且都有效。不幸的是,今天我没有太多时间去看SAT或Z3。因此,到目前为止,我还不了解它是如何工作的。我待会再检查并写回!谢谢您的回答。
– Neilana
17-10-9在18:53
@sudhackar好的,我已经看得更近了,现在我可以完全理解您的脚本中发生了什么。我还在其他一些值上对其进行了测试,并且效果很好。谢谢,不知道现有的SAT解算器,一定会记住这一点。现在,我要解决的难题更难了(还没有看过),我想我也可以在其中应用我的新知识!
– Neilana
17-10-9在21:19
#2 楼
如何通过密码生成许多登录信息?首先,算法1看起来是最弱的链接。算法2是一个单向哈希函数,仅通过知道幻数和密码偏差就无法提取字符。它涉及一些高级数学工作和时间。我将在第二部分中说明破坏算法2的过程。假设:
log_bias = 0xfec0135a
pass_bias = 0xdeadbeef
让我们看一下算法1:
1)log_chunk = 0xlogin(0)login(1)login(n-2)login(n-1);
2)log_checksum = Sum(login,0,n);
3)log_magicnumber = log_chunk ^ log_checksum ^ log_bias;
该算法显示了两个潜在的弱点。一个,如果您采用幻数并用log_bias常数对其进行异或运算,则会得到:
log_chunk ^ log_checksum。
第二,log_chunk是前两个字符和后两个字符的十六进制连接,提供登录框架;因此,我们可以生成自己的字符并为该变量赋值。
消除偏差并为块选择一个值之后,我们可以获取log_checksum的值。
log_checksum =(log_magicnumber ^ log_bias)^ log_chunk;
剩下要做的就是找到一个代表字符的数字序列,它们的总和就是校验和。
如何?
好吧,如果您查看ASCII表,您会看到可打印的字符从33到126。如果我们生成介于33和126之间的随机值b并将其从校验和中减去,我们将获得字符值b,并将校验和值减少b:log_checksum-= b。重复此操作,直到校验和值低于126,并且仅存储diff =(log_checksum-b)大于或等于33的字符。这样,所有字符均可打印。
填写登录字符串的中间后,可以表示为:
登录名= A B b0 b1 b2 ... bj C D
,其中A,B,C,D是我们选择的字符,而bi是从校验和生成的字符。
这种反向工程方法是一种廉价的智能hack,它针对流程中最弱的散列函数,它肯定会起作用并节省您的时间。通过一个密码,您将获得多次登录:这称为哈希冲突。
以下是此代码的示例输出: >如果您稍微更改了密码,请说:“ 011c0d0f090efe”,这就是您得到的:登录魔术数字。
您必须攻击此功能:
log_magicnumber = b ^((log_magicnumber << 5)+ 1)^ pass_bias
如果仔细观察,您会发现当前log_magicnumber是使用先前的log_magicnumber值转换而来的,并与未知字节值和已知偏差进行混合。 > log_magicnumber(i)= b ^((log_magicnumber(i-1)<< 5)+ 1)^ pass_bias
如果我们对pass_magicnumber和pass_bias进行异或运算,则剩下: >
b ^((log_magicnumber << 5)+ 1)
生成所有可能的b值后(0-9和af,总共16种可能性)并为b的每个可能值得出log_magicnumber的对应值,我们对这些幻数值应用相同的步骤以获得另一个值,然后进行8次(密码字符串为64位值= 8个字节,最小长度(共6个字节)。如果设置为零,我们将丢弃最左边的两个字节,并将所有字节打包为密码字符串;然后,我们使用密码魔术数字算法验证密码的魔术数字是否与登录名匹配。
这种方法相当于创建一个8阶段树,其中每个节点有16个子节点。这意味着我们必须生成16到8个字符的幂:16 ^ 8 =(2 ^ 4)^ 8 = 2 ^ 32 = 4.294.967.296字符(4GB)并将它们组合成6到8个字符的字符串检查每个字符串的有效性。编写代码很有趣:)
评论
关于通过密码生成登录名的非常有趣的想法!那绝对有效。我花了很多时间解决这个难题,试图提出能够生成任何有效对登录/通行证的任何算法。但是您提出的建议没有想到。我喜欢:)是的,我想过要实现第二部分中所述的内容,但意识到这是一个非常糟糕的主意:解决了DI标记问题并选择sudhackar的答案作为解决方案,因为它提供了从登录生成通行证的方式(反之亦然)。
– Neilana
17-10-9在21:58
评论
我想不是确定您希望RE能够写某种密钥生成算法的算法,对吧?@PawełŁukasik正是!我们必须找出给定登录名的正确密码。