-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHSS.py
executable file
·266 lines (189 loc) · 8.64 KB
/
HSS.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
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
#!/usr/bin/env python
#HSS.py a tool to generically throw usernames at a login or other form to look for timing attacks
#maybe should implement a spider/scraper to find login forms as well to automate some
#probably a good idea to do more than timing attacks. maybe automate user enum on response data as well (forgot pw link, etc)
#By @arbitrary_code
try:
import argparse, os, requests, signal, ssl, sys, time
from requests.packages.urllib3.exceptions import InsecureRequestWarning
except Exception as e:
print('\n [!] Import(s) failed! ' +str(e))
class Screwdriver():
def __init__(self):
#defaults
self.httpVerbs=['get', 'post', 'put', 'delete']
self.httpVerb = 'post'
self.postData=None
self.cookieInput=None
self.httpProxy = 'http://localhost:8080'
self.httpsProxy = 'https://localhost:8080'
self.userList=[]
self.userPass=None
self.postData=None
self.url=None
self.verbose=False
self.encode=False
self.proxyDict = {
"http" : self.httpProxy,
"https" : self.httpsProxy}
def signal_handler(self, signal, frame):
print('You pressed Ctrl+C! Exiting...')
sys.exit(0)
def cls(self):
os.system('cls' if os.name == 'nt' else 'clear')
def cmdargs(self):
parser = argparse.ArgumentParser()
parser.add_argument('-c', '--cookie', nargs=1, metavar='<cookieInput>', help='Optionally, specify cookie data')
parser.add_argument('-u', '--url', nargs = 1, metavar='http://www.foo.com/login' ,help = 'The URL you want to test.')
parser.add_argument('-p', '--password', nargs = 1, metavar='P@55w0rd!',help = 'The password you want to test, default is null')
parser.add_argument('-d', '--delay', nargs =1, metavar='2',help = 'Optionally set a delay in seconds to rate limit. Default is 2 seconds.')
parser.add_argument('-P', '--postdata', nargs = 1, metavar="User=xux&Password=xpx&Lang=en",help='The POST data string to send, contained in single quotes.\nReplace parameter values with a xux for username and xpx for password.')
#parser.add_argument('-G'. '--getdata', nargs = 1, help = 'Data to use in the GET request')
parser.add_argument('-e', '--encode', help='Optionally URL encode all POST data', action = 'store_true')
parser.add_argument('-v', '--verbose', help='Optionally enable verbosity', action = 'store_true')
parser.add_argument('-V', '--verb', nargs=1, metavar='post',help='HTTP Verb to use')
parser.add_argument('-x', '--proxy', nargs=1, metavar='localhost:8080',help='Optionally specify a proxy')
parser.add_argument('-f', '--postfile', metavar='postdata.txt', help='POST data contained in a file')
args = parser.parse_args()
version='1.0-04202017'
if self.verbose is True:
print(
'''
_ _ _____ _____ ____ ____ _
| | | |_ _|_ _| _ \ / ___| ___ _ __ (_) ___
| |_| | | | | | | |_) | \___ \ / _ \| '_ \| |/ __|
| _ | | | | | | __/ ___) | (_) | | | | | (__
|_| |_| |_| |_| |_| |____/ \___/|_| |_|_|\___|
____ _ _
/ ___| ___ _ __ _____ ____| |_ __(_)_ _____ _ __
\___ \ / __| '__/ _ \ \ /\ / / _` | '__| \ \ / / _ \ '__|
___) | (__| | | __/\ V V / (_| | | | |\ V / __/ |
|____/ \___|_| \___| \_/\_/ \__,_|_| |_| \_/ \___|_|
HSS - A Generic HTTP Timing Attack tool
%s
''' % version)
#print args
print('HSS started at: %s' % (time.strftime("%d/%m/%Y - %H:%M:%S")))
if args.url is None:
print('\n[!] Enter a URL to test\n')
parser.print_help()
sys.exit(0)
if args.verb is None:
print('[i] Verb not specified, using POST')
#check for post data in -P arg or file supplied in -f
#if both are blank
if args.postdata is None and args.postfile is None:
#tell the user and exit
print('\n[-] No POST data entered! Please use -P for inline or -f for a file containing data. Exiting! Use -h for help\n')
sys.exit(0)
#otherwise
else:
#if -P has data
if args.postdata is not None:
#set post data with supplied arg value
self.postData = ''.join(args.postdata)
#if -f has data
if args.postfile is not None:
#open to read as object f
with open(args.postfile,'r') as f:
#read the contents into the userList dictionary
self.postData = ''.join(f.read().splitlines())
if args.verbose is True:print('postdata: \n %s' % self.postData)
if args.password is not None:
self.userPass = ''.join(args.password)
if args.delay is None:
self.delay = float('2')
else:
self.delay = float(str(''.join(args.delay)))
for u in args.url:
self.url = args.url
if self.verbose is True:print ('[i] Url entered is: '.join(self.url)+'\n')
if args.password is None:
self.userPass = ''
if args.password is not None:
self.userPass = ''.join(args.password)
if args.cookie is not None:
self.cookieInput = ''.join(args.cookie)
cookieVal = self.cookieInput.split('=')[0]
cookieData = self.cookieInput.split('=')[1]
self.cookieData = {str(cookieVal):str(cookieData)}
print(self.cookieData.items())
else:
self.cookieData = ''
self.verbose=args.verbose
if args.proxy is not None:
self.httpProxy = args.proxy
self.httpsProxy = args.proxy
else:
self.httpProxy = ''
self.httpProxy = ''
def request(self):
#http://docs.python-requests.org/en/master/user/quickstart/
signal.signal(signal.SIGINT, self.signal_handler)
print('[i] Testing URL: %s ' % ''.join(self.url))
print('[i] Testing post data of: %s ' % self.postData)
print('%-8s %-8s %-s'% ('Response', 'Time(ms)','user:pass'))
#open users.txt to read as object f
with open('users.txt','r') as f:
#read the contents into the userList dictionary
self.userList =f.read().splitlines()
#for each line find its index and value
for i, userID in enumerate(self.userList):
#finx xux in your string
if self.postData.find('xux'):
#replace the string with the user id at the first i value
self.postData=self.postData.replace('xux', str(self.userList[i]))
#find xpx in the string
if self.postData.find('xpx'):
#replace xpx with the the password specified otherwise its blank
self.postData=self.postData.replace('xpx', str(self.userPass))
if self.postData.find(str(self.userList[i-1])):
self.postData=self.postData.replace(str(self.userList[i-1]),str(self.userList[i]))
if self.encode is True:
self.postData = urllib.urlencode(str(self.postData))
#ignore ssl errors
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
#loop through urls as potentially you'd want to test more than 1
for u in self.url:
try:
#set verbosity to print the url
if self.verbose is True:print ('\n[+] ____Testing____ \n %s'% str(u))
#record statt time
startTime=time.time()
#test for verb. this probably could be done better
#uses http://docs.python-requests.org/en/master/api/
if self.httpVerb == 'post':
response = requests.post(u,str(self.postData),cookies=self.cookieData,verify=False)
if self.httpVerb == 'get':
response = requests.get(u) #basic auth needs a header Authorization: Basic
if self.httpVerb == 'put':
response = requests.put(u)
if self.httpVerb == 'delete':
response = requests.delete(u)
#record elapsed time
elapsedTime = str(round((time.time()-startTime)*1000.0))
#if verbose print the response from the server. probabaly better to write to a file?
if self.verbose is True:
print('____SENDING_____\n %s %s \n %s' % (self.httpVerb.upper(),u,str(self.postData)))
print('____RESPONSE HEADERS____')
for k in response.headers.items():
print ('%s : %s' % (k[0], str(k[1].split(';'))+'\n'))
print('________________________')
#print(response.text) #dump all response content html
#return the elapsed time with the user id and password and status code
#print ('HTTP '+str(response.status_code)+' '+"{:<1}".format(str(elapsedTime))+'ms'+' '+str(userID)+':'+str(self.userPass)+' ')
print('HTTP %-3s %-8s %s : %s'% (str(response.status_code), str(elapsedTime), str(userID), str(self.userPass)) )
except requests.exceptions.RequestException as e:
print(e)
sys.exit(1)
#if verbose print the post data too
if self.verbose is True: print('[i] POST data: %s' % str(self.postData))
#throttle based on delay arg
time.sleep(self.delay)
def main():
run = Screwdriver()
run.cls()
run.cmdargs()
run.request()
if __name__ == '__main__':
main()