欢迎光临
我们一直在努力

MOECTF REVERSE [Broken_hash] wp

查壳无壳,CPP写的PE64,丢进IDA分析

请添加图片描述

main函数逻辑,大概就是输入88位的明文去验证,由dword_140005184的数值来判断是否正确,先点进第一个函数sub_1400010C0看看它对我们输入的v8做了些什么操作

请添加图片描述

可以看到这个函数影响了关键的dword_140005184,继续点进sub_1400014F0

请添加图片描述

请添加图片描述

由题目名字(Broken_hash),加上sub_140001400函数可以推断,题目使用了哈希加密,函数sub_140001400正是哈希函数特有的赋初值环节,但是这个初值很奇怪,这里的初值分别是0x39063906,0xEFCDA233,0x74C74C74,0x55555555,0xD33B4700,这四个找不到对应的算法,然后后面四个轮常量也非常奇怪,分别是0xB1ACB1DD,0x23333333,0x66666666,0xCA6272D6也是一样找不到对应的SHA算法,基本上可以确定和题目名字提示的一样,这个哈希算法被魔改了

进入sub_140001B20函数,

请添加图片描述
请添加图片描述

请添加图片描述

填充512bit貌似没什么问题,但是要知道,这里的哈希算法每次只哈希一个字节,sub_140001B20传入的第三个参数是1,也就是长度参数,那么填充函数就永远都装不满64字节

先继续分析下sub_140001610,先是将输入的a2,也就是64字节明文每4字节存进v15中,可以从<<24,<<16,<<8看出来这里是大端序读取
请添加图片描述

请添加图片描述

然后在消息扩展里,看到这里是循环0x50也就是80次,利用了v15存进的前16字进行异或扩展,这里的v15[v3] = (v15[v3] >> 30) | (4 * v15[v3]);很怪,先继续看
请添加图片描述

这下看懂了,4个分轮循环,每轮20次,一共80次,v6v5v7v8v9赋值的也就是之前的5个魔改初值,里面也分别用到了a1[25]a1[26]a1[27]a1[28]四个魔改轮常值,可以确定这是SHA-1魔改,那么前面那个很怪的点,v15[v3] = (v15[v3] >> 30) | (4 * v15[v3]);也就是把SHA-1的循环左移1位改成了循环左移2位了,在结尾处,将得到的最新初值给到原来的初值位置,然后进入下一块继续循环

继续看下一个函数,这里是哈希函数的结尾工作,貌似没有被魔改的痕迹

请添加图片描述

但是在最后计算完的v5,被保存到dword_140005260里,而dword只保存了一位!只保存了前4个字节,后面的内容被丢掉了,也就是说,一个字符明文->20字节哈希->保存前4字节,而且这里非常逆天的是,保存是用小端序的,所以保存的字节是倒过来的,标准的SHA-1是用大端序保存的

请添加图片描述

最后回到main函数,魔改的内容分析的差不多了,验证部分也就是

请添加图片描述

请添加图片描述

要求哈希出来的结果等于dword_140005000里的内容,那么解题思路,哈希是不可逆的,但是这里有个突破点,算法本身每次只加密一个字符,而不是直接把88个字符丢进去,那么就可以直接爆破,写脚本把加密流程给模拟一下,还要写个转小端序和左移2位的修改,建表爆破即可

def rotl(val,bits,max_bits=32):
val&=(1<<max_bits)1
return((val<<bits)|(val>>(max_bitsbits)))&((1<<max_bits)1)

def changed_sha1(char_byte):
h0=0x39063906
h1=0xEFCDA233
h2=0x74C74C74
h3=0x55555555
h4=0xD33B4700
k0=0xB1ACB1DD
k1=0x23333333
k2=0x66666666
k3=0xCA6272D6

block = bytearray(64)
block[0]=char_byte
block[1]=0x80
block[63]=8

w = [0] * 80
for i in range(16):
w[i]=int.from_bytes(block[i*4:i*4+4],'big')

for i in range(16, 80):
w[i]=rotl(w[i16]^w[i14]^w[i8]^w[i3],2)

a,b,c,d,e=h0,h1,h2,h3,h4

for i in range(80):
if 0 <= i <= 19:
f=(d&~b)^(c&b)
k=k0
elif 20 <= i <= 39:
f=d^c^b
k=k1
elif 40 <= i <= 59:
f=(d&c)^(d&b)^(c&b)
k=k2
elif 60 <= i <= 79:
f=d^c^b
k=k3

temp=(rotl(a,5)+f+e+k+w[i])&0xFFFFFFFF
e=d
d=c
c=rotl(b, 30)
b=a
a=temp

h0=(h0+a)&0xFFFFFFFF

bswap_h0=((h0&0xFF)<<24)|(((h0>>8)&0xFF)<<16)|(((h0>>16)&0xFF)<<8)|((h0>>24)& 0xFF)
return bswap_h0

lookup_table = {}
for char_code in range(256):
res=changed_sha1(char_code)
lookup_table[res]=chr(char_code)

target_dwords = [
0x64744C9A, 0x047C2FF1, 0xA2D74292, 0x85BEF77E, 0x711FCBF7,
0x669E1609, 0x6BBD9DB6, 0x6941C8A4, 0xB16E48B3, 0xDE321186,
0x5251E8C2, 0xFB8F95A7, 0x711FCBF7, 0xCB5C3FAD, 0x36568AF5,
0xFB8F95A7, 0x82ACF96A, 0x75DCD570, 0x7EF00E40, 0xFB8F95A7,
0x4BE9314A, 0xCB5C3FAD, 0xA2D74292, 0xDE321186, 0xFB8F95A7,
0x46927FA8, 0xB16E48B3, 0xD7C1A410, 0x567375C3, 0x711FCBF7,
0xFB8F95A7, 0x9C19F0F3, 0xD035E914, 0xFB8F95A7, 0x6941C8A4,
0x0B7D1395, 0xD7C1A410, 0xC87A7C7E, 0xFB8F95A7, 0xD7C1A410,
0xDE321186, 0x5251E8C2, 0xFB8F95A7, 0xD5380C52, 0xBEA99D3B,
0xCEDB7952, 0xFB8F95A7, 0x73456320, 0xD7C1A410, 0xDE321186,
0xFB8F95A7, 0x581D99E5, 0xA2D74292, 0x711FCBF7, 0xFB8F95A7,
0x06372812, 0xFB8F95A7, 0x73456320, 0xCEDB7952, 0xEF53E254,
0xFB8F95A7, 0x9F12424D, 0x669E1609, 0xFB8F95A7, 0x9C19F0F3,
0xFECF7685, 0x0B7D1395, 0x1833E8B1, 0xFB8F95A7, 0x9F66DD04,
0xA2D74292, 0xD7C1A410, 0xFB8F95A7, 0x6941C8A4, 0x866CAF4F,
0x047C2FF1, 0x64744C9A, 0xFB8F95A7, 0xD5380C52, 0xCEDB7952,
0xDE321186, 0x81453D43, 0xCB5C3FAD, 0xB16E48B3, 0xC578F843,
0xCEDB7952, 0xDE321186, 0xE38C6F07
]

flag=""
for i, dword in enumerate(target_dwords):
if dword in lookup_table:
flag+=lookup_table[dword]

print(f"{flag}")

跑出来是moectf{F1nd_th3_SEH_7hen_B1a5t_My_Fla9_and_Y0u_Can_Get_A_Cup_Of_Milk_Tea_From_YunZh1Jun},丢程序里验证一下

请添加图片描述

没问题,但是不知道为什么平台不给过,一直说我的flag格式有问题
后面去看别人的flag发现一样的,应该是格式问题,直接去分析魔改点还是太麻烦了,花了不少时间,别人wp有更好的解法,动调拿到变换后的表,做map映射可以拿到flag,还是相对来说更简单

赞(0)
未经允许不得转载:171主机测评 » MOECTF REVERSE [Broken_hash] wp
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址