18 | 18 |
|
19 | 19 |
raise CrowbarExceptions(str(err))
|
20 | 20 |
|
21 | |
__version__ = '0.3.6-dev'
|
|
21 |
__version__ = '0.4.1'
|
22 | 22 |
__banner__ = 'Crowbar v%s' % (__version__)
|
|
23 |
|
23 | 24 |
|
24 | 25 |
class AddressAction(argparse.Action):
|
25 | 26 |
def __call__(self, parser, args, values, option=None):
|
|
80 | 81 |
mess = """ Usage: use --help for further information\ncrowbar.py: error: argument -c/--passwd or -C/--passwdfile expected one argument """
|
81 | 82 |
raise CrowbarExceptions(mess)
|
82 | 83 |
|
|
84 |
|
83 | 85 |
class Main:
|
84 | 86 |
is_success = 0
|
85 | 87 |
|
|
92 | 94 |
self.vpn_success = re.compile("Initialization Sequence Completed")
|
93 | 95 |
self.vpn_remote_regex = re.compile("^\s+remote\s[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\s[0-9]{1,3}")
|
94 | 96 |
self.vpn_warning = "Warning! Both \"remote\" options were used at the same time. But command line \"remote\" options will be used!"
|
|
97 |
self.vpn_error_in_use = "Address already in use (errno=98)"
|
95 | 98 |
|
96 | 99 |
self.xfreerdp_path = "/usr/bin/xfreerdp"
|
97 | 100 |
self.rdp_success = "Authentication only, exit status 0"
|
98 | 101 |
self.rdp_success_ins_priv = "insufficient access privileges"
|
99 | 102 |
self.rdp_success_account_locked = "alert internal error"
|
100 | |
self.rdp_display_error = "Please check that the \$DISPLAY environment variable is properly set."
|
|
103 |
self.rdp_error_host_down = "ERRCONNECT_CONNECT_FAILED" # [0x00020006] [0x00020014]
|
|
104 |
self.rdp_error_display = "Please check that the \$DISPLAY environment variable is properly set."
|
101 | 105 |
|
102 | 106 |
self.vncviewer_path = "/usr/bin/vncviewer"
|
103 | 107 |
self.vnc_success = "Authentication successful"
|
|
109 | 113 |
parser.add_argument('-b', '--brute', dest='brute', help='Target service', choices=self.services.keys(),
|
110 | 114 |
required=True)
|
111 | 115 |
parser.add_argument('-s', '--server', dest='server', action='store', help='Static target')
|
112 | |
parser.add_argument('-S', '--serverfile', dest='server_file', action='store', help='Multiple targets stored in a file')
|
113 | |
parser.add_argument('-u', '--username', dest='username', action='store', nargs='+', help='Static name to login with')
|
114 | |
parser.add_argument('-U', '--usernamefile', dest='username_file', action='store', help='Multiple names to login with, stored in a file')
|
115 | |
parser.add_argument('-n', '--number', dest='thread', action='store', help='Number of threads to be active at once', default=5, type=int)
|
116 | |
parser.add_argument('-l', '--log', dest='log_file', action='store', help='Log file (only write attempts)', metavar='FILE',
|
|
116 |
parser.add_argument('-S', '--serverfile', dest='server_file', action='store',
|
|
117 |
help='Multiple targets stored in a file')
|
|
118 |
parser.add_argument('-u', '--username', dest='username', action='store', nargs='+',
|
|
119 |
help='Static name to login with')
|
|
120 |
parser.add_argument('-U', '--usernamefile', dest='username_file', action='store',
|
|
121 |
help='Multiple names to login with, stored in a file')
|
|
122 |
parser.add_argument('-n', '--number', dest='thread', action='store',
|
|
123 |
help='Number of threads to be active at once', default=5, type=int)
|
|
124 |
parser.add_argument('-l', '--log', dest='log_file', action='store', help='Log file (only write attempts)',
|
|
125 |
metavar='FILE',
|
117 | 126 |
default="crowbar.log")
|
118 | |
parser.add_argument('-o', '--output', dest='output', action='store', help='Output file (write everything else)', metavar='FILE',
|
|
127 |
parser.add_argument('-o', '--output', dest='output', action='store', help='Output file (write everything else)',
|
|
128 |
metavar='FILE',
|
119 | 129 |
default="crowbar.out")
|
120 | 130 |
parser.add_argument('-c', '--passwd', dest='passwd', action='store', help='Static password to login with')
|
121 | |
parser.add_argument('-C', '--passwdfile', dest='passwd_file', action='store', help='Multiple passwords to login with, stored in a file',
|
|
131 |
parser.add_argument('-C', '--passwdfile', dest='passwd_file', action='store',
|
|
132 |
help='Multiple passwords to login with, stored in a file',
|
122 | 133 |
metavar='FILE')
|
123 | |
parser.add_argument('-t', '--timeout', dest='timeout', action='store', help='[SSH] How long to wait for each thread (seconds)', default=10, type=int)
|
124 | |
parser.add_argument('-p', '--port', dest='port', action='store', help='Alter the port if the service is not using the default value', type=int)
|
125 | |
parser.add_argument('-k', '--keyfile', dest='key_file', action='store', help='[SSH/VNC] (Private) Key file or folder containing multiple files')
|
|
134 |
parser.add_argument('-t', '--timeout', dest='timeout', action='store',
|
|
135 |
help='[SSH] How long to wait for each thread (seconds)', default=10, type=int)
|
|
136 |
parser.add_argument('-p', '--port', dest='port', action='store',
|
|
137 |
help='Alter the port if the service is not using the default value', type=int)
|
|
138 |
parser.add_argument('-k', '--keyfile', dest='key_file', action='store',
|
|
139 |
help='[SSH/VNC] (Private) Key file or folder containing multiple files')
|
126 | 140 |
parser.add_argument('-m', '--config', dest='config', action='store', help='[OpenVPN] Configuration file ')
|
127 | |
parser.add_argument('-d', '--discover', dest='discover', action='store_true', help='Port scan before attacking open ports', default=False)
|
128 | |
parser.add_argument('-v', '--verbose', dest='verbose', action="count", help='Enable verbose output (-vv for more)', default=False)
|
|
141 |
parser.add_argument('-d', '--discover', dest='discover', action='store_true',
|
|
142 |
help='Port scan before attacking open ports', default=False)
|
|
143 |
parser.add_argument('-v', '--verbose', dest='verbose', action="count",
|
|
144 |
help='Enable verbose output (-vv for more)', default=False)
|
129 | 145 |
parser.add_argument('-D', '--debug', dest='debug', action='store_true', help='Enable debug mode', default=False)
|
130 | |
parser.add_argument('-q', '--quiet', dest='quiet', action='store_true', help='Only display successful logins', default=False)
|
|
146 |
parser.add_argument('-q', '--quiet', dest='quiet', action='store_true', help='Only display successful logins',
|
|
147 |
default=False)
|
131 | 148 |
parser.add_argument('options', nargs='*', action=AddressAction)
|
132 | 149 |
|
133 | 150 |
try:
|
|
182 | 199 |
|
183 | 200 |
openvpn_cmd = "%s --remote %s %s --auth-user-pass %s --tls-exit --connect-retry-max 0 --config %s" % (
|
184 | 201 |
self.openvpn_path, ip, port, brute_file_name, self.args.config)
|
|
202 |
|
185 | 203 |
if self.args.verbose == 2:
|
186 | 204 |
self.logger.output_file("CMD: %s" % openvpn_cmd)
|
187 | |
proc = subprocess.Popen(shlex.split(openvpn_cmd), shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
205 |
|
|
206 |
proc = subprocess.Popen(shlex.split(openvpn_cmd), shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
188 | 207 |
|
189 | 208 |
brute = "LOG-OPENVPN: " + ip + ":" + str(port) + " - " + username + ":" + password + " - " + brute_file_name
|
190 | 209 |
self.logger.log_file(brute)
|
191 | |
for line in iter(proc.stdout.readline, ''):
|
|
210 |
|
|
211 |
# For every line out
|
|
212 |
for line in proc.stdout:
|
|
213 |
# Is debug enabled
|
192 | 214 |
if self.args.debug:
|
193 | |
self.logger.output_file(line.rstrip())
|
194 | |
if re.search(self.vpn_success, line):
|
195 | |
result = bcolors.OKGREEN + "OPENVPN-SUCCESS: " + bcolors.ENDC + bcolors.OKBLUE + ip + ":" + str(port) + " - " + username + ":" + password + bcolors.ENDC
|
|
215 |
self.logger.output_file(line.decode("utf-8").rstrip())
|
|
216 |
|
|
217 |
# Success
|
|
218 |
if re.search(self.vpn_success, str(line)):
|
|
219 |
result = bcolors.OKGREEN + "OPENVPN-SUCCESS: " + bcolors.ENDC + bcolors.OKBLUE + ip + ":" + str(
|
|
220 |
port) + " - " + username + ":" + password + bcolors.ENDC
|
196 | 221 |
self.logger.output_file(result)
|
197 | 222 |
Main.is_success = 1
|
198 | 223 |
os.kill(proc.pid, signal.SIGQUIT)
|
|
224 |
# Errors
|
|
225 |
elif re.search(self.vpn_error_in_use, str(line)):
|
|
226 |
mess = "Already connected to a VPN"
|
|
227 |
raise CrowbarExceptions(mess)
|
199 | 228 |
brute_file.close()
|
200 | 229 |
|
201 | 230 |
def openvpn(self):
|
202 | |
port = 443 #TCP 443, TCP 943, UDP 1194
|
|
231 |
port = 443 # TCP 443, TCP 943, UDP 1194
|
|
232 |
|
|
233 |
if not 'SUDO_UID' in os.environ.keys():
|
|
234 |
mess = "OpenVPN requires super user privileges"
|
|
235 |
raise CrowbarExceptions(mess)
|
203 | 236 |
|
204 | 237 |
if not os.path.exists(self.openvpn_path):
|
205 | 238 |
mess = "openvpn: %s path doesn't exists on the system!" % os.path.abspath(self.openvpn_path)
|
|
273 | 306 |
|
274 | 307 |
def vnclogin(self, ip, port, keyfile):
|
275 | 308 |
vnc_cmd = "%s -passwd %s %s:%s" % (self.vncviewer_path, keyfile, ip, port)
|
|
309 |
|
276 | 310 |
if self.args.verbose == 2:
|
277 | 311 |
self.logger.output_file("CMD: %s" % vnc_cmd)
|
278 | |
proc = subprocess.Popen(shlex.split(vnc_cmd), shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
312 |
|
|
313 |
proc = subprocess.Popen(shlex.split(vnc_cmd), shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
279 | 314 |
|
280 | 315 |
brute = "LOG-VNC: " + ip + ":" + str(port) + " - " + keyfile
|
281 | 316 |
self.logger.log_file(brute)
|
282 | |
for line in iter(proc.stderr.readline, ''):
|
|
317 |
|
|
318 |
# For every line out
|
|
319 |
for line in proc.stdout:
|
|
320 |
# Is debug enabled
|
283 | 321 |
if self.args.debug:
|
284 | |
self.logger.output_file(line.rstrip())
|
285 | |
if re.search(self.vnc_success, line):
|
|
322 |
self.logger.output_file(line.decode("utf-8").rstrip())
|
|
323 |
|
|
324 |
if re.search(self.vnc_success, str(line)):
|
286 | 325 |
os.kill(proc.pid, signal.SIGQUIT)
|
287 | 326 |
result = bcolors.OKGREEN + "VNC-SUCCESS: " + bcolors.ENDC + bcolors.OKBLUE + ip + ":" + str(
|
288 | 327 |
port) + " - " + keyfile + bcolors.ENDC
|
|
326 | 365 |
|
327 | 366 |
if self.args.verbose == 2:
|
328 | 367 |
self.logger.output_file("CMD: %s" % rdp_cmd)
|
329 | |
proc = subprocess.Popen(shlex.split(rdp_cmd), shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
368 |
|
|
369 |
# stderr to stdout
|
|
370 |
proc = subprocess.Popen(shlex.split(rdp_cmd), shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
330 | 371 |
|
331 | 372 |
brute = "LOG-RDP: " + ip + ":" + str(port) + " - " + user + ":" + password
|
332 | 373 |
self.logger.log_file(brute)
|
333 | |
for line in iter(proc.stderr.readline, ''):
|
|
374 |
|
|
375 |
# For every line out
|
|
376 |
for line in proc.stdout:
|
|
377 |
# Is debug enabled
|
334 | 378 |
if self.args.debug:
|
335 | |
self.logger.output_file(line.rstrip())
|
336 | |
if re.search(self.rdp_success, line):
|
|
379 |
self.logger.output_file(line.decode("utf-8").rstrip())
|
|
380 |
|
|
381 |
# Success
|
|
382 |
if re.search(self.rdp_success, str(line)):
|
337 | 383 |
result = bcolors.OKGREEN + "RDP-SUCCESS : " + bcolors.ENDC + bcolors.OKBLUE + ip + ":" + str(
|
338 | 384 |
port) + " - " + user + ":" + password + bcolors.ENDC
|
339 | 385 |
self.logger.output_file(result)
|
340 | 386 |
Main.is_success = 1
|
341 | 387 |
break
|
342 | |
elif re.search(self.rdp_success_ins_priv, line):
|
|
388 |
elif re.search(self.rdp_success_ins_priv, str(line)):
|
343 | 389 |
result = bcolors.OKGREEN + "RDP-SUCCESS (INSUFFICIENT PRIVILEGES) : " + bcolors.ENDC + bcolors.OKBLUE + ip + ":" + str(
|
344 | 390 |
port) + " - " + user + ":" + password + bcolors.ENDC
|
345 | 391 |
self.logger.output_file(result)
|
346 | 392 |
Main.is_success = 1
|
347 | 393 |
break
|
348 | |
elif re.search(self.rdp_success_account_locked, line):
|
|
394 |
elif re.search(self.rdp_success_account_locked, str(line)):
|
349 | 395 |
result = bcolors.OKGREEN + "RDP-SUCCESS (ACCOUNT_LOCKED_OR_PASSWORD_EXPIRED) : " + bcolors.ENDC + bcolors.OKBLUE + ip + ":" + str(
|
350 | 396 |
port) + " - " + user + ":" + password + bcolors.ENDC
|
351 | 397 |
self.logger.output_file(result)
|
352 | 398 |
Main.is_success = 1
|
353 | 399 |
break
|
354 | |
elif re.search(self.rdp_display_error, line):
|
|
400 |
# Errors
|
|
401 |
elif re.search(self.rdp_error_display, str(line)):
|
355 | 402 |
mess = "Please check \$DISPLAY is properly set. See README.md %s" % self.crowbar_readme
|
|
403 |
raise CrowbarExceptions(mess)
|
|
404 |
elif re.search(self.rdp_error_host_down, str(line)):
|
|
405 |
mess = "Host isn't up"
|
356 | 406 |
raise CrowbarExceptions(mess)
|
357 | 407 |
|
358 | 408 |
def rdp(self):
|
|
505 | 555 |
self.logger.output_file("No results found...")
|
506 | 556 |
|
507 | 557 |
def signal_handler(self, signal, frame):
|
508 | |
raise CrowbarExceptions("Exiting...")
|
|
558 |
raise CrowbarExceptions("\nExiting...")
|