New upstream version 3.4+git20200406
Sophie Brun
4 years ago
16 | 16 | - SSH private key authentication (`-b sshkey`) |
17 | 17 | - VNC key authentication (`-b vpn`) |
18 | 18 | |
19 | ||
20 | 19 | ### Installation |
21 | 20 | |
22 | Install all the dependencies: | |
23 | ||
24 | ``` | |
25 | # apt-get -y install openvpn freerdp-x11 vncviewer | |
21 | **Kali Linux users can do** | |
22 | ||
23 | ``` | |
24 | # sudo apt install -y crowbar | |
25 | ``` | |
26 | ||
27 | Else if you wish to install from source, install all the dependencies: | |
28 | ||
29 | **Debain 9/10+ & Kali Rolling** | |
30 | ||
31 | ``` | |
32 | # apt install -y nmap openvpn freerdp2-x11 tigervnc-viewer | |
33 | ``` | |
34 | ||
35 | **Debain 7/8 & Kali 1/2** | |
36 | ||
37 | ``` | |
38 | # apt-get install -y nmap openvpn freerdp-x11 vncviewer | |
26 | 39 | ``` |
27 | 40 | |
28 | 41 | Then get latest version from GitHub: |
33 | 46 | |
34 | 47 | Note: The RDP client package depends on your OS: |
35 | 48 | |
49 | + Debain 9/10 & Kali Rolling uses `freerdp2-x11` | |
36 | 50 | + Debian 7/8 & Kali 1/2 uses `freerdp-x11` package. |
37 | 51 | + Else you can try `xfreerdp`. |
38 | + Else you may need to compile & tweak `freerdp` by following: http://opentechnotes.blogspot.co.uk/2015/02/compile-headless-freerdp-credential-checking.html | |
39 | ||
40 | _Don't forget to edit the script to point to the new binary_! | |
52 | + The fall back method would be to compile & tweak `freerdp` by following: http://opentechnotes.blogspot.co.uk/2015/02/compile-headless-freerdp-credential-checking.html | |
53 | ||
54 | _Don't forget to patch `./lib/main.py` to point to the new binary_! | |
41 | 55 | |
42 | 56 | ### Usage |
43 | 57 | |
95 | 109 | 2015-03-28 11:04:00 RDP-SUCCESS : 10.68.35.150:3389 - "gokhan alkan@DOMAIN":Aa123456, |
96 | 110 | ``` |
97 | 111 | |
98 | ||
99 | ||
100 | 112 | #### Brute Forcing Remote Desktop Protocol (RDP) |
101 | 113 | |
102 | 114 | Below are a few examples of attacking RDP using Crowbar. |
103 | 115 | |
104 | ||
105 | ||
106 | 116 | RDP brute forcing a single IP address using a single username and a single password: |
107 | 117 | |
108 | 118 | ``` |
111 | 121 | |
112 | 122 | ![](https://raw.githubusercontent.com/galkan/crowbar/master/images/crowbar-rdp.jpg) |
113 | 123 | |
114 | ||
115 | - - - | |
116 | ||
124 | - - - | |
117 | 125 | |
118 | 126 | RDP brute forcing a single IP address using username list file and a single password: |
119 | 127 | |
120 | 128 | ``` |
121 | # ./crowbar.py -b rdp -s 192.168.2.211/32 -U /root/Desktop/userlist -c passw0rd | |
129 | # ./crowbar.py -b rdp -s 192.168.2.211/32 -U ~/Desktop/userlist -c passw0rd | |
122 | 130 | ``` |
123 | 131 | |
124 | 132 | ![](https://raw.githubusercontent.com/galkan/crowbar/master/images/crowvar-rdp-dosya.jpg) |
125 | 133 | |
126 | ||
127 | - - - | |
128 | ||
134 | - - - | |
129 | 135 | |
130 | 136 | RDP brute forcing a single IP address using a single username and a password list: |
131 | 137 | |
132 | 138 | ``` |
133 | # ./crowbar.py -b rdp -s 192.168.2.250/32 -u localuser -C /root/Desktop/passlist | |
139 | # ./crowbar.py -b rdp -s 192.168.2.250/32 -u localuser -C ~/Desktop/passlist | |
134 | 140 | ``` |
135 | 141 | |
136 | 142 | ![](https://raw.githubusercontent.com/galkan/crowbar/master/images/crowvar-rdp-dosya2.jpg) |
137 | 143 | |
138 | ||
139 | - - - | |
140 | ||
144 | - - - | |
141 | 145 | |
142 | 146 | RDP brute forcing a subnet using a username list and a password list in discovery mode: |
143 | 147 | |
144 | 148 | ``` |
145 | # ./crowbar.py -b rdp -s 192.168.2.0/24 -U /root/Desktop/userlist -C /root/Desktop/passlist -d | |
149 | # ./crowbar.py -b rdp -s 192.168.2.0/24 -U ~/Desktop/userlist -C ~/Desktop/passlist -d | |
146 | 150 | ``` |
147 | 151 | |
148 | 152 | ![](https://raw.githubusercontent.com/galkan/crowbar/master/images/crowvar-rdp-kadi-parola-dosya.jpg) |
149 | 153 | |
150 | ||
151 | - - - | |
152 | ||
154 | - - - | |
153 | 155 | |
154 | 156 | #### Brute Forcing SSH Private Keys |
155 | 157 | |
156 | 158 | Below are a few examples which you have using Crowbar. |
157 | 159 | |
158 | ||
159 | ||
160 | 160 | SSH key brute force attempt to a single IP address using a single username and a single private SSH key: |
161 | 161 | |
162 | 162 | ``` |
163 | # ./crowbar.py -b sshkey -s 192.168.2.105/32 -u root -k /root/.ssh/id_rsa | |
163 | # ./crowbar.py -b sshkey -s 192.168.2.105/32 -u root -k ~/.ssh/id_rsa | |
164 | 164 | ``` |
165 | 165 | |
166 | 166 | ![](https://raw.githubusercontent.com/galkan/crowbar/master/images/crowbar-ssh1.jpg) |
167 | 167 | |
168 | ||
169 | - - - | |
170 | ||
168 | - - - | |
171 | 169 | |
172 | 170 | SSH key brute force attempt to a single IP address using a single username and all the SSH keys in a folder: |
173 | 171 | |
174 | 172 | ``` |
175 | # ./crowbar.py -b sshkey -s 192.168.2.105/32 -u root -k /root/.ssh/ | |
173 | # ./crowbar.py -b sshkey -s 192.168.2.105/32 -u root -k ~/.ssh/ | |
176 | 174 | ``` |
177 | 175 | |
178 | 176 | ![](https://raw.githubusercontent.com/galkan/crowbar/master/images/crowbar-ssh2.jpg) |
179 | 177 | |
180 | ||
181 | - - - | |
182 | ||
178 | - - - | |
183 | 179 | |
184 | 180 | SSH key brute force attempt to a subnet using a single username and all the SSH keys in a folder in discovery mode: |
185 | 181 | |
186 | 182 | ``` |
187 | # ./crowbar.py -b sshkey -s 192.168.2.0/24 -u root -k /root/.ssh/ -d | |
183 | # ./crowbar.py -b sshkey -s 192.168.2.0/24 -u root -k ~/.ssh/ -d | |
188 | 184 | ``` |
189 | 185 | |
190 | 186 | ![](https://raw.githubusercontent.com/galkan/crowbar/master/images/crowbar-ssh3.jpg) |
191 | 187 | |
192 | ||
193 | ||
194 | 188 | #### Brute Forcing VNC |
195 | 189 | |
196 | 190 | Below is an example of attacking a VNC service using Crowbar. |
197 | 191 | |
198 | ||
199 | ||
200 | 192 | VNC brute force attempt to a single IP address using a password file with specified port number: |
201 | 193 | |
202 | 194 | ``` |
203 | # ./crowbar.py -b vnckey -s 192.168.2.105/32 -p 5902 -k /root/.vnc/passwd | |
195 | # ./crowbar.py -b vnckey -s 192.168.2.105/32 -p 5902 -k ~/.vnc/passwd | |
204 | 196 | ``` |
205 | 197 | |
206 | 198 | ![](https://raw.githubusercontent.com/galkan/crowbar/master/images/crowbar-vnc.jpg) |
207 | 199 | |
208 | ||
209 | ||
210 | 200 | ### Brute Forcing OpenVPN |
211 | 201 | |
212 | 202 | Below is an example of attacking OpenVPN using Crowbar. |
213 | 203 | |
214 | ||
215 | ||
216 | 204 | OpenVPN brute force attempt to a single IP address using a configuration file, a certificate file, a single username and a single password with specified port number: |
217 | 205 | |
218 | 206 | ``` |
219 | # ./crowbar.py -b openvpn -s 198.7.62.204/32 -p 443 -m /root/Desktop/vpnbook.ovpn -k /root/Desktop/vpnbook_ca.crt -u vpnbook -c cr2hudaF | |
207 | # ./crowbar.py -b openvpn -s 198.7.62.204/32 -p 443 -m ~/Desktop/vpnbook.ovpn -k ~/Desktop/vpnbook_ca.crt -u vpnbook -c cr2hudaF | |
220 | 208 | ``` |
221 | 209 | |
222 | 210 | ![](https://raw.githubusercontent.com/galkan/crowbar/master/images/crowbar-vpn.jpg) |
223 | 211 | |
224 | ||
225 | ||
226 | 212 | - - - |
227 | 213 | |
228 | 214 | ### Logs & Output |
229 | 215 | |
230 | 216 | Once you have executed Crowbar, it generates 2 files for logging and result that are located in your current directory. Default log file name is `crowbar.log` which stores all brute force attempts while execution. If you don't want use default log file, you should use `-l log_path`. The second file is `crowbar.out` which stores successful attempts while execution. If you don't want use default output file, you should use `-o output_path`. After that you can observe Crowbar operations. |
231 | ||
232 | 217 | |
233 | 218 | - - - |
234 | 219 | |
236 | 221 | |
237 | 222 | - Bahtiyar Bircan |
238 | 223 | - Ertuğrul Başaranoğlu |
239 | - G0tmi1k | |
240 | ||
241 | ||
224 | - [g0tmi1k](https://twitter.com/g0tmi1k) | |
242 | 225 | |
243 | 226 | - - - |
244 | 227 |
0 | #!/usr/bin/env python2 | |
0 | #!/usr/bin/env python3 | |
1 | 1 | |
2 | 2 | try: |
3 | 3 | from lib.main import Main |
4 | 4 | from lib.core.exceptions import CrowbarExceptions |
5 | except Exception, err: | |
6 | import sys | |
7 | print >> sys.stderr, err | |
8 | sys.exit(1) | |
5 | except Exception as err: | |
6 | import sys | |
7 | print(err, file=sys.stderr) | |
8 | sys.exit(1) | |
9 | 9 | |
10 | 10 | ## |
11 | 11 | ### Main |
16 | 16 | try: |
17 | 17 | crowbar = Main() |
18 | 18 | crowbar.run(crowbar.args.brute) |
19 | except Exception, err: | |
19 | except Exception as err: | |
20 | 20 | import sys |
21 | print >> sys.stderr, err | |
21 | print(err, file=sys.stderr) | |
22 | 22 | sys.exit(1) |
2 | 2 | import sys |
3 | 3 | import socket |
4 | 4 | import struct |
5 | from functools import reduce | |
5 | 6 | from lib.core.exceptions import CrowbarExceptions |
6 | except Exceptions, err: | |
7 | except Exception as err: | |
7 | 8 | from lib.core.exceptions import CrowbarExceptions |
8 | 9 | |
9 | 10 | raise CrowbarExceptions(str(err)) |
22 | 23 | |
23 | 24 | def ipaddr_to_binary(self, ipaddr): |
24 | 25 | q = ipaddr.split('.') |
25 | return reduce(lambda a, b: long(a) * 256 + long(b), q) | |
26 | return reduce(lambda a, b: int(a) * 256 + int(b), q) | |
26 | 27 | |
27 | 28 | def binary_to_ipaddr(self, ipbinary): |
28 | 29 | return socket.inet_ntoa(struct.pack('!I', ipbinary)) |
65 | 66 | b = b + 1 |
66 | 67 | |
67 | 68 | def cidr_iprange(self, ipaddr, cidrmask): |
68 | mask = (long(2) ** long(32 - long(cidrmask))) - 1 | |
69 | mask = (int(2) ** int(32 - int(cidrmask))) - 1 | |
69 | 70 | b = self.ipaddr_to_binary(ipaddr) |
70 | 71 | e = self.ipaddr_to_binary(ipaddr) |
71 | b = long(b & ~mask) | |
72 | e = long(e | mask) | |
72 | b = int(b & ~mask) | |
73 | e = int(e | mask) | |
73 | 74 | while (b <= e): |
74 | 75 | yield self.binary_to_ipaddr(b) |
75 | 76 | b = b + 1 |
1 | 1 | import logging |
2 | 2 | import os.path |
3 | 3 | from lib.core.exceptions import CrowbarExceptions |
4 | except Exception, err: | |
4 | except Exception as err: | |
5 | 5 | from lib.core.exceptions import CrowbarExceptions |
6 | 6 | |
7 | 7 | raise CrowbarExceptions(str(err)) |
0 | 0 | try: |
1 | 1 | import sys |
2 | from Queue import Queue | |
2 | from queue import Queue | |
3 | 3 | from threading import Thread |
4 | 4 | from lib.core.exceptions import CrowbarExceptions |
5 | except Exception, err: | |
5 | except Exception as err: | |
6 | 6 | from lib.core.exceptions import CrowbarExceptions |
7 | 7 | |
8 | 8 | raise CrowbarExceptions(str(err)) |
13 | 13 | from lib.core.threadpool import ThreadPool |
14 | 14 | from lib.core.exceptions import CrowbarExceptions |
15 | 15 | from lib.core.iprange import IpRange, InvalidIPAddress |
16 | except Exception, err: | |
16 | except Exception as err: | |
17 | 17 | from lib.core.exceptions import CrowbarExceptions |
18 | 18 | |
19 | 19 | raise CrowbarExceptions(str(err)) |
20 | 20 | |
21 | __version__ = '0.3.5-dev' | |
21 | __version__ = '0.3.6-dev' | |
22 | 22 | __banner__ = 'Crowbar v%s' % (__version__) |
23 | 23 | |
24 | 24 | class AddressAction(argparse.Action): |
95 | 95 | |
96 | 96 | self.xfreerdp_path = "/usr/bin/xfreerdp" |
97 | 97 | self.rdp_success = "Authentication only, exit status 0" |
98 | self.rdp_success_ins_priv = "insufficient access privileges" | |
99 | self.rdp_success_account_locked = "alert internal error" | |
98 | 100 | self.rdp_display_error = "Please check that the \$DISPLAY environment variable is properly set." |
99 | 101 | |
100 | 102 | self.vncviewer_path = "/usr/bin/vncviewer" |
130 | 132 | |
131 | 133 | try: |
132 | 134 | self.args = parser.parse_args() |
133 | except Exception, err: | |
135 | except Exception as err: | |
134 | 136 | raise CrowbarExceptions(str(err)) |
135 | 137 | |
136 | 138 | self.ip_list = [] |
213 | 215 | |
214 | 216 | try: |
215 | 217 | pool = ThreadPool(int(self.args.thread)) |
216 | except Exception, err: | |
218 | except Exception as err: | |
217 | 219 | raise CrowbarExceptions(str(err)) |
218 | 220 | |
219 | 221 | for config_line in open(self.args.config, "r"): |
309 | 311 | |
310 | 312 | try: |
311 | 313 | pool = ThreadPool(int(self.args.thread)) |
312 | except Exception, err: | |
314 | except Exception as err: | |
313 | 315 | raise CrowbarExceptions(str(err)) |
314 | 316 | |
315 | 317 | for ip in self.ip_list: |
321 | 323 | def rdplogin(self, ip, user, password, port): |
322 | 324 | rdp_cmd = "%s /v:%s /port:%s /u:%s /p:%s /cert-ignore +auth-only" % ( |
323 | 325 | self.xfreerdp_path, ip, port, user, password) |
326 | ||
324 | 327 | if self.args.verbose == 2: |
325 | 328 | self.logger.output_file("CMD: %s" % rdp_cmd) |
326 | 329 | proc = subprocess.Popen(shlex.split(rdp_cmd), shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
336 | 339 | self.logger.output_file(result) |
337 | 340 | Main.is_success = 1 |
338 | 341 | break |
342 | elif re.search(self.rdp_success_ins_priv, line): | |
343 | result = bcolors.OKGREEN + "RDP-SUCCESS (INSUFFICIENT PRIVILEGES) : " + bcolors.ENDC + bcolors.OKBLUE + ip + ":" + str( | |
344 | port) + " - " + user + ":" + password + bcolors.ENDC | |
345 | self.logger.output_file(result) | |
346 | Main.is_success = 1 | |
347 | break | |
348 | elif re.search(self.rdp_success_account_locked, line): | |
349 | result = bcolors.OKGREEN + "RDP-SUCCESS (ACCOUNT_LOCKED_OR_PASSWORD_EXPIRED) : " + bcolors.ENDC + bcolors.OKBLUE + ip + ":" + str( | |
350 | port) + " - " + user + ":" + password + bcolors.ENDC | |
351 | self.logger.output_file(result) | |
352 | Main.is_success = 1 | |
353 | break | |
339 | 354 | elif re.search(self.rdp_display_error, line): |
340 | 355 | mess = "Please check \$DISPLAY is properly set. See README.md %s" % self.crowbar_readme |
341 | 356 | raise CrowbarExceptions(mess) |
357 | 372 | |
358 | 373 | try: |
359 | 374 | pool = ThreadPool(int(self.args.thread)) |
360 | except Exception, err: | |
375 | except Exception as err: | |
361 | 376 | raise CrowbarExceptions(str(err)) |
362 | 377 | |
363 | 378 | for ip in self.ip_list: |
434 | 449 | |
435 | 450 | try: |
436 | 451 | pool = ThreadPool(self.args.thread) |
437 | except Exception, err: | |
452 | except Exception as err: | |
438 | 453 | raise CrowbarExceptions(str(err)) |
439 | 454 | |
440 | 455 | if not os.path.exists(self.args.key_file): |
457 | 472 | for dirname, dirnames, filenames in os.walk(self.args.key_file): |
458 | 473 | for keyfile in filenames: |
459 | 474 | keyfile_path = self.args.key_file + "/" + keyfile |
460 | if keyfile.endswith('.pub', 4): | |
461 | self.logger.output_file("LOG-SSH: Skipping Public Key - %s" % keyfile_path) | |
462 | continue | |
463 | pool.add_task(self.sshlogin, ip, port, user, keyfile_path, self.args.timeout) | |
475 | if keyfile.endswith('.pub', 4): | |
476 | self.logger.output_file("LOG-SSH: Skipping Public Key - %s" % keyfile_path) | |
477 | continue | |
478 | pool.add_task(self.sshlogin, ip, port, user, keyfile_path, self.args.timeout) | |
464 | 479 | else: |
465 | 480 | pool.add_task(self.sshlogin, ip, port, user, self.args.key_file, self.args.timeout) |
466 | 481 | else: |
4 | 4 | import tempfile |
5 | 5 | import subprocess |
6 | 6 | from lib.core.exceptions import CrowbarExceptions |
7 | except Exception, err: | |
7 | except Exception as err: | |
8 | 8 | from lib.core.exceptions import CrowbarExceptions |
9 | 9 | |
10 | 10 | raise CrowbarExceptions(str(err)) |
19 | 19 | import nmap |
20 | 20 | self.lib = False |
21 | 21 | except ImportError: |
22 | mess = "Please install the python-nmap module (pip install nmap)!" | |
22 | mess = "Please install the python3-nmap module (pip3 install nmap)!" | |
23 | 23 | raise CrowbarExceptions(mess) |
24 | 24 | except: |
25 | 25 | mess = "File: %s doesn't exists!" % self.nmap_path |
33 | 33 | tmpfile = tempfile.NamedTemporaryFile(mode='w+t') |
34 | 34 | tmpfile_name = tmpfile.name |
35 | 35 | |
36 | if os.geteuid() != 0: | |
37 | nmap_scan_type = "-sT" | |
38 | else: | |
39 | nmap_scan_type = "-sS" | |
40 | ||
41 | nmap_scan_option = "-n -Pn -T4 %s --open -p %s --host-timeout=10m --max-rtt-timeout=600ms --initial-rtt-timeout=300ms --min-rtt-timeout=300ms --max-retries=2 --min-rate=150 -oG %s" % ( | |
42 | nmap_scan_type, port, tmpfile_name) | |
43 | ||
36 | 44 | if self.lib: |
37 | nmap_scan_option = "-n -Pn -T4 -sS %s --open -p %s --host-timeout=10m --max-rtt-timeout=600ms --initial-rtt-timeout=300ms --min-rtt-timeout=300ms --max-retries=2 --min-rate=150 -oG %s" % ( | |
38 | ip_list, port, tmpfile_name) | |
45 | nmap_scan_option = "%s %s" % ( | |
46 | ip_list, nmap_scan_option) | |
39 | 47 | run_nmap = "%s %s" % (self.nmap_path, nmap_scan_option) |
40 | 48 | proc = subprocess.Popen([run_nmap], shell=True, stdout=subprocess.PIPE, ) |
41 | 49 | stdout_value = str(proc.communicate()) |
42 | 50 | else: |
43 | 51 | nm = nmap.PortScanner() |
44 | 52 | nm.scan(hosts=ip_list, |
45 | arguments="-n -Pn -T4 -sS --open -p %s --host-timeout=10m --max-rtt-timeout=600ms --initial-rtt-timeout=300ms --min-rtt-timeout=300ms --max-retries=2 --min-rate=150 -oG %s" % ( | |
46 | port, tmpfile_name)) | |
53 | arguments=nmap_scan_option) | |
47 | 54 | |
48 | 55 | try: |
49 | 56 | for line in open(tmpfile_name, "r"): |
51 | 58 | ip = line[:-1].split(" ")[1] |
52 | 59 | result.append(ip) |
53 | 60 | return result |
54 | except Exception, err: | |
61 | except Exception as err: | |
55 | 62 | raise CrowbarExceptions(str(err)) |