/
snowflake.py
192 lines (148 loc) · 5.2 KB
/
snowflake.py
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
"""
Snowflake framework python API.
Author: George Argyros (argyros.george@gmail.com)
"""
from ctypes import *
CRACKERLIB_PATH = "../release/snowflake.so"
bitMask = 0xffffffff
class MtRand:
N = 624
M = 397
def __init__(self, php = True):
self.php = php
self.twist = self.phpTwist if php else self.mtTwist
self.seeded = False
self.state = []
self.next = self.N
def phpTwist(self, m, u, v):
"""
The invalid twist operation of the PHP generator
"""
return (m ^ (((u) & 0x80000000)|((v) & 0x7fffffff))>>1) ^ \
((-((u) & 0x00000001)) & 0x9908b0df)
def mtTwist(self, m, u, v):
"""
The original mt twist operation
"""
return (m ^ (((u) & 0x80000000)|((v) & 0x7fffffff))>>1) ^ \
((-((v) & 0x00000001)) & 0x9908b0df)
def mtSrand(self, seed):
"""
The default seeding procedure from the original MT code
"""
self.seeded = True
self.next = self.N
self.state = [seed & bitMask]
for i in range(1, self.N):
s = (1812433253 * (self.state[i-1] ^ (self.state[i-1] >> 30))+ i)
self.state.append(s & bitMask)
def setState(self, state):
"""
Replace existing state with another one and considers the
generator initialized
"""
self.next = self.N
self.state = state
self.seeded = True
def reload(self):
"""
Generate the next N words of the internal state
"""
N = self.N
M = self.M
for i in range(N - M):
self.state[i] = self.twist(self.state[M + i], self.state[i],
self.state[i+1])
for i in range(i+1, N-1):
self.state[i] = self.twist(self.state[i+(M-N)], self.state[i],
self.state[i+1])
self.state[N-1] = self.twist(self.state[M-1], self.state[N-1],
self.state[0])
self.next = 0
return
def mtRand(self, min = None, max = None):
"""
Generate a 32 bit integer
"""
if not self.seeded:
self.mtSrand(0xdeadbeef)
if self.next == self.N:
self.reload()
num = self.state[ self.next ]
self.next += 1
num = (num ^ (num >> 11))
num = (num ^ ((num << 7) & 0x9d2c5680))
num = (num ^ ((num << 15) & 0xefc60000))
num = (num ^ (num >> 18))
if not min and not max:
return num
return (min + (num*(max - min + 1)) / (1<<32))
def phpMtRand(self, rmin = None, rmax= None):
"""
as returned by PHP
"""
num = self.mtRand() >> 1
if not rmin and not rmax:
return num
return (rmin + (num*(rmax - rmin + 1)) / (1 <<31))
class Snowflake:
def __init__(self, path=None):
"""
Load the functions from the shared library.
"""
if not path:
path = CRACKERLIB_PATH
crackerLib = cdll.LoadLibrary(path)
self.initialized = False
if not crackerLib:
return
self.searchRainbowTableFunc = crackerLib.searchRainbowTable
self.searchHashOnlineFunc = crackerLib.searchHashOnline
self.initialized = True
def oneWayOrAnother(self, targetHash, tableList=[], hashFuncName=None):
"""
Will try to crack the hash using either rainbow tables or
an online search if the first method fails.
"""
seed = None
if not targetHash or not self.initialized:
return None
for table in tableList:
seed = self.searchRainbowTables(targetHash, tableList)
if seed:
return seed
if hashFuncName:
seed = self.searchHashOnline(targetHash, hashFuncName)
return seed
def searchRainbowTables(self, targetHash, tableList):
"""
Will search all tables in tableList for the targetHash
hash. It will return the seed value or None if its not
found.
"""
if not self.initialized or not (targetHash and tableList):
return None
chash = create_string_buffer(targetHash, len(targetHash))
for t in tableList:
ct = c_char_p(t)
cseed = c_uint()
ret = self.searchRainbowTableFunc(ct, chash, byref(cseed))
if ret > 0:
return cseed.value
return None
def searchHashOnline(self, targetHash, hashFunc):
"""
Do an exhaustive search on all 2^32 possible seeds using the
respective function from the library.
"""
if not self.initialized or not (targetHash and hashFunc):
return None
chash = c_char_p(targetHash)
chashFunc = c_char_p(hashFunc)
cseed = c_uint()
ret = self.searchHashOnlineFunc(chashFunc, chash, byref(cseed))
if ret > 0:
return cseed.value
return None
if __name__ == '__main__':
print 'Snowflake module for attacking PHP PRNGs'