forked from beched/libpywebhack
-
Notifications
You must be signed in to change notification settings - Fork 0
/
common.py
147 lines (137 loc) · 5.74 KB
/
common.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
import httplib
import re
import sys
from time import sleep
from urllib import urlencode
__author__ = 'Beched'
class PyWebHack:
allowed_params = ['host', 'ssl', 'ajax', 'cut', 'sleep', 'verbose', 'output']
verbose = False
log = ''
cnt_reqs = 0
known_urls = {}
known_subs = []
args = {}
current_path = ''
add_headers = {
'Cookie': '',
#'Accept' : 'text/html'
'User-Agent': 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
}
def __init__(self, *args, **kwargs):
"""
The class constructor.
:param host: a host to work with in format hostname[:port]. The only necessary parameter
:param ssl: if True, HTTPS will be used, default value is 0
:param ajax: if True, "X-Requested-With: XMLHttpRequest" header will be added to all HTTP requests
:param cut: if set, all strings matching specified regexp will be removed from all HTTP responses
:param sleep: if set, sleep after each HTTP request for the specified number of seconds, default value is 0
:param verbose: if True, an output will be sent to self.output or to STDOUT, default value is 1
:param output: the file for output, default is None
:return:
"""
for k, v in kwargs.items():
if k in self.allowed_params:
self.args[k] = v
if 'host' not in self.args:
self.help()
return
if 'ajax' in self.args:
self.add_headers['X-Requested-With'] = 'XMLHttpRequest'
self.sleep = float(self.args.get('sleep', 0))
self.cut = self.args.get('cut', '')
self.scheme = 'https' if 'ssl' in self.args else 'http'
self.host = self.args['host']
self.handler = httplib.HTTPSConnection(self.host) if self.scheme == 'https' else httplib.HTTPConnection(
self.host)
self.url = '%s://%s/' % (self.scheme, self.host)
self.verbose = self.args.get('verbose', 1)
self.output = self.args.get('output', None)
def __del__(self):
"""
The class destructor. Outputs the total number of HTTP requests made
"""
self.rep_log('==========\n%s requests made' % self.cnt_reqs)
def rep_log(self, string, delim='\n'):
"""
Logging method. If self.verbose is True, sents output to self.output or to STDOUT
:param string: a log entry
:param delim: a delimiter which is appended to the entry
"""
try:
self.known_urls[self.current_path]['info'] += string + delim
except:
pass
if self.verbose != 0:
if self.output is not None:
open(self.output, 'a+').write('%s%s' % (string, delim))
else:
sys.stdout.write('%s%s' % (string, delim))
def newstructure(self):
"""
Generates a dictionary for holding the information about some path
:return: a dict with all necessary (empty) fields
"""
return {
'args': {'get': [], 'post': [], 'cookie': []},
#'bugs': [],
'info': '',
'html': None,
'code': None,
'hdrs': {}
}
def restructure(self, path):
"""
Sets current path and generates a new structure for it, if path is new
:param path: current path
"""
self.current_path = path
if path not in self.known_urls:
self.known_urls[path] = self.newstructure()
def help(self):
"""
A help method template. Called when invalid input is provided to the constructor
"""
self.rep_log(
'==========\nLibPyWebHack\n==========\nThis is a class constructor and it accepts parameters' +
'%s. See docs for explanation.' % self.allowed_params)
def makereq(self, path, query=None, headers=None, method='GET'):
"""
The core method for sending HTTP requests
:param path: a request URI (if it's directory, it should end with '/')
:param query: a query string
:param headers: a dict with additional request headers
:param method: HTTP request method
:return: a response tuple (str body, int code, dict headers)
"""
sleep(self.sleep)
headers = self.add_headers if headers is None else headers
self.cnt_reqs += 1
if isinstance(query, dict):
query = urlencode(query)
try:
if query is not None:
self.handler.request(method, path, query, headers)
else:
self.handler.request(method, path, headers=headers)
resp = self.handler.getresponse()
return (re.sub(self.cut, '', resp.read()), resp.status, {x: y for (x, y) in resp.getheaders()})
except httplib.HTTPException:
self.handler = httplib.HTTPSConnection(self.host) if self.scheme == 'https' else httplib.HTTPConnection(
self.host)
return ('', None, None)
except:
self.rep_log('Could not connect to %s! Reason: %s' % (path, sys.exc_info()[1]))
return ('', 0, {})
def chkpath(self, paths, comment=None):
"""
Check that the given paths exist. If some path exists, it's added to self.known_urls
:param paths: a list with request URIs
:param comment: a description of what's going on. Will be logged
"""
for path in paths:
self.rep_log('Checking for %s...' % ( '/' + path if comment is None else comment))
r = self.makereq(self.url + path)
if r[1] != 404:
self.rep_log('Possibly (code %s) found at %s%s' % (r[1], self.url, path))
self.known_urls.update({'/' + path: self.newstructure()})