PageRenderTime 55ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/patator.py

https://gitlab.com/simepy/patator
Python | 1415 lines | 1351 code | 4 blank | 60 comment | 2 complexity | 84028051eeed1c86d0ec55f5bd27a628 MD5 | raw file
  1. #!/usr/bin/env python2
  2. # Copyright (C) 2012 Sebastien MACKE
  3. #
  4. # This program is free software; you can redistribute it and/or modify it under
  5. # the terms of the GNU General Public License version 2, as published by the
  6. # Free Software Foundation
  7. #
  8. # This program is distributed in the hope that it will be useful, but WITHOUT
  9. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  10. # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  11. # details (http://www.gnu.org/licenses/gpl.txt).
  12. __author__ = 'Sebastien Macke'
  13. __email__ = 'patator@hsc.fr'
  14. __url__ = 'http://www.hsc.fr/ressources/outils/patator/'
  15. __git__ = 'https://github.com/lanjelot/patator'
  16. __twitter__ = 'http://twitter.com/lanjelot'
  17. __version__ = '0.7-beta'
  18. __license__ = 'GPLv2'
  19. __banner__ = 'Patator v%s (%s)' % (__version__, __git__)
  20. # README {{{
  21. '''
  22. INTRODUCTION
  23. ------------
  24. * What ?
  25. Patator is a multi-purpose brute-forcer, with a modular design and a flexible usage.
  26. Currently it supports the following modules:
  27. + ftp_login : Brute-force FTP
  28. + ssh_login : Brute-force SSH
  29. + telnet_login : Brute-force Telnet
  30. + smtp_login : Brute-force SMTP
  31. + smtp_vrfy : Enumerate valid users using SMTP VRFY
  32. + smtp_rcpt : Enumerate valid users using SMTP RCPT TO
  33. + finger_lookup : Enumerate valid users using Finger
  34. + http_fuzz : Brute-force HTTP
  35. + pop_login : Brute-force POP3
  36. + pop_passd : Brute-force poppassd (http://netwinsite.com/poppassd/)
  37. + imap_login : Brute-force IMAP4
  38. + ldap_login : Brute-force LDAP
  39. + smb_login : Brute-force SMB
  40. + smb_lookupsid : Brute-force SMB SID-lookup
  41. + rlogin_login : Brute-force rlogin
  42. + vmauthd_login : Brute-force VMware Authentication Daemon
  43. + mssql_login : Brute-force MSSQL
  44. + oracle_login : Brute-force Oracle
  45. + mysql_login : Brute-force MySQL
  46. + mysql_query : Brute-force MySQL queries
  47. * rdp_login : Brute-force RDP (NLA)
  48. + pgsql_login : Brute-force PostgreSQL
  49. + vnc_login : Brute-force VNC
  50. + dns_forward : Forward DNS lookup
  51. + dns_reverse : Reverse DNS lookup
  52. + snmp_login : Brute-force SNMP v1/2/3
  53. + ike_enum : Enumerate IKE transforms
  54. + unzip_pass : Brute-force the password of encrypted ZIP files
  55. + keystore_pass : Brute-force the password of Java keystore files
  56. + umbraco_crack : Crack Umbraco HMAC-SHA1 password hashes
  57. + tcp_fuzz : Fuzz TCP services
  58. + dummy_test : Testing module
  59. Future modules to be implemented:
  60. - rdp_login w/no NLA
  61. The name "Patator" comes from http://www.youtube.com/watch?v=xoBkBvnTTjo
  62. * Why ?
  63. Basically, I got tired of using Medusa, Hydra, Ncrack, Metasploit auxiliary modules, Nmap NSE scripts and the like because:
  64. - they either do not work or are not reliable (got me false negatives several times in the past)
  65. - they are not flexible enough (how to iterate over all wordlists, fuzz any module parameter)
  66. - they lack useful features (display progress or pause during execution)
  67. FEATURES
  68. --------
  69. * No false negatives, as it is the user that decides what results to ignore based on:
  70. + status code of response
  71. + size of response
  72. + matching string or regex in response data
  73. + ... see --help
  74. * Modular design
  75. + not limited to network modules (eg. the unzip_pass module)
  76. + not limited to brute-forcing (eg. remote exploit testing, or vulnerable version probing)
  77. * Interactive runtime
  78. + show progress during execution (press Enter)
  79. + pause/unpause execution (press p)
  80. + increase/decrease verbosity
  81. + add new actions & conditions during runtime (eg. to exclude more types of response from showing)
  82. + ... press h to see all available interactive commands
  83. * Use persistent connections (ie. will test several passwords until the server disconnects)
  84. * Multi-threaded
  85. * Flexible user input
  86. - Any module parameter can be fuzzed:
  87. + use the FILE keyword to iterate over a file
  88. + use the COMBO keyword to iterate over a combo file
  89. + use the NET keyword to iterate over every hosts of a network subnet
  90. + use the RANGE keyword to iterate over hexadecimal, decimal or alphabetical ranges
  91. + use the PROG keyword to iterate over the output of an external program
  92. - Iteration over the joined wordlists can be done in any order
  93. * Save every response (along with request) to seperate log files for later reviewing
  94. INSTALL
  95. -------
  96. * Dependencies (best tested versions)
  97. | Required for | URL | Version |
  98. --------------------------------------------------------------------------------------------------
  99. paramiko | SSH | http://www.lag.net/paramiko/ | 1.7.7.1 |
  100. --------------------------------------------------------------------------------------------------
  101. pycurl | HTTP | http://pycurl.sourceforge.net/ | 7.19.0 |
  102. --------------------------------------------------------------------------------------------------
  103. openldap | LDAP | http://www.openldap.org/ | 2.4.24 |
  104. --------------------------------------------------------------------------------------------------
  105. impacket | SMB | https://github.com/CoreSecurity/impacket | 0.9.12 |
  106. --------------------------------------------------------------------------------------------------
  107. cx_Oracle | Oracle | http://cx-oracle.sourceforge.net/ | 5.1.1 |
  108. --------------------------------------------------------------------------------------------------
  109. mysql-python | MySQL | http://sourceforge.net/projects/mysql-python/ | 1.2.3 |
  110. --------------------------------------------------------------------------------------------------
  111. xfreerdp | RDP (NLA) | https://github.com/FreeRDP/FreeRDP/ | 1.2.0 |
  112. --------------------------------------------------------------------------------------------------
  113. psycopg | PostgreSQL | http://initd.org/psycopg/ | 2.4.5 |
  114. --------------------------------------------------------------------------------------------------
  115. pycrypto | VNC | http://www.dlitz.net/software/pycrypto/ | 2.3 |
  116. --------------------------------------------------------------------------------------------------
  117. dnspython | DNS | http://www.dnspython.org/ | 1.10.0 |
  118. --------------------------------------------------------------------------------------------------
  119. IPy | NET keyword | https://github.com/haypo/python-ipy | 0.75 |
  120. --------------------------------------------------------------------------------------------------
  121. pysnmp | SNMP | http://pysnmp.sourceforge.net/ | 4.2.1 |
  122. --------------------------------------------------------------------------------------------------
  123. pyasn1 | SNMP | http://sourceforge.net/projects/pyasn1/ | 0.1.2 |
  124. --------------------------------------------------------------------------------------------------
  125. ike-scan | IKE | http://www.nta-monitor.com/tools-resources/ | 1.9 |
  126. --------------------------------------------------------------------------------------------------
  127. unzip | ZIP passwords | http://www.info-zip.org/ | 6.0 |
  128. --------------------------------------------------------------------------------------------------
  129. Java | keystore files | http://www.oracle.com/technetwork/java/javase/ | 6 |
  130. --------------------------------------------------------------------------------------------------
  131. python | | http://www.python.org/ | 2.7 |
  132. --------------------------------------------------------------------------------------------------
  133. * Shortcuts (optional)
  134. ln -s path/to/patator.py /usr/bin/ftp_login
  135. ln -s path/to/patator.py /usr/bin/http_fuzz
  136. so on ...
  137. USAGE
  138. -----
  139. $ python patator.py <module> -h
  140. or
  141. $ <module> -h (if you created the shortcuts)
  142. There are global options and module options:
  143. - all global options start with - or --
  144. - all module options are of the form option=value
  145. All module options are fuzzable:
  146. ---------
  147. ./module host=FILE0 port=FILE1 foobar=FILE2.google.FILE3 0=hosts.txt 1=ports.txt 2=foo.txt 3=bar.txt
  148. The keywords (FILE, COMBO, NET, ...) act as place-holders. They indicate the type of wordlist
  149. and where to replace themselves with the actual words to test.
  150. Each keyword is numbered in order to:
  151. - match the corresponding wordlist
  152. - and indicate in what order to iterate over all the wordlists
  153. For example, this would be the classic order:
  154. ---------
  155. $ ./module host=FILE0 user=FILE1 password=FILE2 0=hosts.txt 1=logins.txt 2=passwords.txt
  156. 10.0.0.1 root password
  157. 10.0.0.1 root 123456
  158. 10.0.0.1 root qsdfghj
  159. ... (trying all passwords before testing next login)
  160. 10.0.0.1 admin password
  161. 10.0.0.1 admin 123456
  162. 10.0.0.1 admin qsdfghj
  163. ... (trying all logins before testing next host)
  164. 10.0.0.2 root password
  165. ...
  166. While a smarter way might be:
  167. ---------
  168. $ ./module host=FILE2 user=FILE1 password=FILE0 2=hosts.txt 1=logins.txt 0=passwords.txt
  169. 10.0.0.1 root password
  170. 10.0.0.2 root password
  171. 10.0.0.1 admin password
  172. 10.0.0.2 admin password
  173. 10.0.0.1 root 123456
  174. 10.0.0.2 root 123456
  175. 10.0.0.1 admin 123456
  176. ...
  177. * Keywords
  178. Brute-force a list of hosts with a file containing combo entries (each line => login:password).
  179. ---------
  180. ./module host=FILE0 user=COMBO10 password=COMBO11 0=hosts.txt 1=combos.txt
  181. Scan subnets to just grab version banners.
  182. ---------
  183. ./module host=NET0 0=10.0.1.0/24,10.0.2.0/24,10.0.3.128-10.0.3.255
  184. Fuzzing a parameter by iterating over a range of values.
  185. ---------
  186. ./module param=RANGE0 0=hex:0x00-0xffff
  187. ./module param=RANGE0 0=int:0-500
  188. ./module param=RANGE0 0=lower:a-zzz
  189. Fuzzing a parameter by iterating over the output of an external program.
  190. ---------
  191. ./module param=PROG0 0='john -stdout -i'
  192. ./module param=PROG0 0='mp64.bin ?l?l?l',$(mp64.bin --combination ?l?l?l) # http://hashcat.net/wiki/doku.php?id=maskprocessor
  193. * Actions & Conditions
  194. Use the -x option to do specific actions upon receiving expected results. For example:
  195. To ignore responses with status code 200 *AND* a size within a specific range.
  196. ---------
  197. ./module host=10.0.0.1 user=FILE0 -x ignore:code=200,size=57-74
  198. To ignore responses with status code 500 *OR* containing "Internal error".
  199. ---------
  200. ./module host=10.0.0.1 user=FILE0 -x ignore:code=500 -x ignore:fgrep='Internal error'
  201. Remember that conditions are ANDed within the same -x option, use multiple -x options to
  202. specify ORed conditions.
  203. * Failures
  204. During execution, failures may happen, such as a TCP connect timeout for
  205. example. By definition a failure is an exception that the module does not expect,
  206. and as a result the exception is caught upstream by the controller.
  207. Such exceptions, or failures, are not immediately reported to the user, the
  208. controller will retry 4 more times (see --max-retries) before reporting the
  209. failed payload to the user with the logging level "FAIL".
  210. * Read carefully the following examples to get a good understanding of how patator works.
  211. {{{ FTP
  212. * Brute-force authentication. Do not report wrong passwords.
  213. ---------
  214. ftp_login host=10.0.0.1 user=FILE0 password=FILE1 0=logins.txt 1=passwords.txt -x ignore:mesg='Login incorrect.'
  215. NB0. If you get errors like "500 OOPS: priv_sock_get_cmd", use -x ignore,reset,retry:code=500
  216. in order to retry the last login/password using a new TCP connection. Odd servers like vsftpd
  217. return this when they shut down the TCP connection (ie. max login attempts reached).
  218. NB1. If you get errors like "too many connections from your IP address", try decreasing the number of
  219. threads, the server may be enforcing a maximum number of concurrent connections.
  220. * Same as before, but stop testing a user after his password is found.
  221. ---------
  222. ftp_login ... -x free=user:code=0
  223. * Find anonymous FTP servers on a subnet.
  224. ---------
  225. ftp_login host=NET0 user=anonymous password=test@example.com 0=10.0.0.0/24
  226. }}}
  227. {{{ SSH
  228. * Brute-force authentication with password same as login (aka single mode). Do not report wrong passwords.
  229. ---------
  230. ssh_login host=10.0.0.1 user=FILE0 password=FILE0 0=logins.txt -x ignore:mesg='Authentication failed.'
  231. NB. If you get errors like "Error reading SSH protocol banner ... Connection reset by peer",
  232. try decreasing the number of threads, the server may be enforcing a maximum
  233. number of concurrent connections (eg. MaxStartups in OpenSSH).
  234. * Brute-force several hosts and stop testing a host after a valid password is found.
  235. ---------
  236. ssh_login host=FILE0 user=FILE1 password=FILE2 0=hosts.txt 1=logins.txt 2=passwords.txt -x free=host:code=0
  237. * Same as previous, but stop testing a user on a host after his password is found.
  238. ---------
  239. ssh_login host=FILE0 user=FILE1 password=FILE2 0=hosts.txt 1=logins.txt 2=passwords.txt -x free=host+user:code=0
  240. }}}
  241. {{{ Telnet
  242. * Brute-force authentication.
  243. (a) Enter login after first prompt is detected, enter password after second prompt.
  244. (b) The regex to detect the login and password prompts.
  245. (c) Reconnect when we get no login prompt back (max number of tries reached or successful login).
  246. ------------ (a)
  247. telnet_login host=10.0.0.1 inputs='FILE0\nFILE1' 0=logins.txt 1=passwords.txt
  248. prompt_re='tux login:|Password:' -x reset:egrep!='Login incorrect.+tux login:'
  249. (b) (c)
  250. NB. If you get errors like "telnet connection closed", try decreasing the number of threads,
  251. the server may be enforcing a maximum number of concurrent connections.
  252. }}}
  253. {{{ SMTP
  254. * Enumerate valid users using the VRFY command.
  255. (a) Do not report invalid recipients.
  256. (b) Do not report when the server shuts us down with "421 too many errors",
  257. reconnect and resume testing.
  258. --------- (a)
  259. smtp_vrfy host=10.0.0.1 user=FILE0 0=logins.txt -x ignore:fgrep='User unknown in local
  260. recipient table' -x ignore,reset,retry:code=421
  261. (b)
  262. * Use the RCPT TO command in case the VRFY command is not available.
  263. ---------
  264. smtp_rcpt host=10.0.0.1 user=FILE0@localhost 0=logins.txt helo='ehlo mx.fb.com' mail_from=root
  265. * Brute-force authentication.
  266. (a) Send a fake hostname (by default your host fqdn is sent)
  267. ------------ (a)
  268. smtp_login host=10.0.0.1 helo='ehlo its.me.com' user=FILE0@dom.com password=FILE1 0=logins.txt 1=passwords.txt
  269. }}}
  270. {{{ HTTP
  271. * Find hidden web resources.
  272. (a) Use a specific header.
  273. (b) Follow redirects.
  274. (c) Do not report 404 errors.
  275. (d) Retry on 500 errors.
  276. --------- (a)
  277. http_fuzz url=http://localhost/FILE0 0=words.txt header='Cookie: SESSID=A2FD8B2DA4'
  278. follow=1 -x ignore:code=404 -x ignore,retry:code=500
  279. (b) (c) (d)
  280. NB. You may be able to go 10 times faster using webef (http://www.hsc.fr/ressources/outils/webef/).
  281. It is the fastest HTTP brute-forcer I know, yet at the moment it still lacks useful features
  282. that will prevent you from performing the following attacks.
  283. * Brute-force phpMyAdmin logon.
  284. (a) Use POST requests.
  285. (b) Follow redirects using cookies sent by server.
  286. (c) Ignore failed authentications.
  287. --------- (a) (b) (b)
  288. http_fuzz url=http://10.0.0.1/phpmyadmin/index.php method=POST follow=1 accept_cookie=1
  289. body='pma_username=root&pma_password=FILE0&server=1&lang=en' 0=passwords.txt
  290. -x ignore:fgrep='Cannot log in to the MySQL server'
  291. (c)
  292. * Scan subnet for directory listings.
  293. (a) Ignore not matching reponses.
  294. (b) Save matching responses into directory.
  295. ---------
  296. http_fuzz url=http://NET0/FILE1 0=10.0.0.0/24 1=dirs.txt -x ignore:fgrep!='Index of'
  297. -l /tmp/directory_listings (a)
  298. (b)
  299. * Brute-force Basic authentication.
  300. (a) Single mode (login == password).
  301. (b) Do not report failed login attempts.
  302. ---------
  303. http_fuzz url=http://10.0.0.1/manager/html user_pass=FILE0:FILE0 0=logins.txt -x ignore:code=401
  304. (a) (b)
  305. * Find hidden virtual hosts.
  306. (a) Read template from file.
  307. (b) Fuzz both the Host and User-Agent headers.
  308. ---------
  309. echo -e 'Host: FILE0\nUser-Agent: FILE1' > headers.txt
  310. http_fuzz url=http://10.0.0.1/ header=@headers.txt 0=vhosts.txt 1=agents.txt
  311. (a) (b)
  312. * Brute-force logon using GET requests.
  313. (a) Encode everything surrounded by the two tags _@@_ in hexadecimal.
  314. (b) Ignore HTTP 200 responses with a content size (header+body) within given range
  315. and that also contain the given string.
  316. (c) Use a different delimiter string because the comma cannot be escaped.
  317. --------- (a) (a)
  318. http_fuzz url='http://10.0.0.1/login?username=admin&password=_@@_FILE0_@@_' -e _@@_:hex
  319. 0=words.txt -x ignore:'code=200|size=1500-|fgrep=Welcome, unauthenticated user' -X '|'
  320. (b) (c)
  321. * Brute-force logon that enforces two random nonces to be submitted along every POST.
  322. (a) First, request the page that provides the nonces as hidden input fields.
  323. (b) Use regular expressions to extract the nonces that are to be submitted along the main request.
  324. ---------
  325. http_fuzz url=http://10.0.0.1/login method=POST body='user=admin&pass=FILE0&nonce1=_N1_&nonce2=_N2_' 0=passwords.txt accept_cookie=1
  326. before_urls=http://10.0.0.1/index before_egrep='_N1_:<input type="hidden" name="nonce1" value="(\w+)"|_N2_:name="nonce2" value="(\w+)"'
  327. (a) (b)
  328. * Test the OPTIONS method against a list of URLs.
  329. (a) Ignore URLs that only allow the HEAD and GET methods.
  330. (b) Header end of line is '\r\n'.
  331. (c) Use a different delimiter string because the comma cannot be escaped.
  332. ---------
  333. http_fuzz url=FILE0 0=urls.txt method=OPTIONS -x ignore:egrep='^Allow: HEAD, GET\r$' -X '|'
  334. (a) (b) (c)
  335. }}}
  336. {{{ LDAP
  337. * Brute-force authentication.
  338. (a) Do not report wrong passwords.
  339. (b) Talk SSL/TLS to port 636.
  340. ---------
  341. ldap_login host=10.0.0.1 binddn='cn=FILE0,dc=example,dc=com' 0=logins.txt bindpw=FILE1 1=passwords.txt
  342. -x ignore:mesg='ldap_bind: Invalid credentials (49)' ssl=1 port=636
  343. (a) (b)
  344. }}}
  345. {{{ SMB
  346. * Brute-force authentication.
  347. ---------
  348. smb_login host=10.0.0.1 user=FILE0 password=FILE1 0=logins.txt 1=passwords.txt -x ignore:fgrep=STATUS_LOGON_FAILURE
  349. NB. If you suddenly get STATUS_ACCOUNT_LOCKED_OUT errors for an account
  350. although it is not the first password you test on this account, then you must
  351. have locked it.
  352. * Pass-the-hash.
  353. (a) Test a list of hosts.
  354. (b) Test every user (each line := login:rid:LM hash:NT hash).
  355. ---------
  356. smb_login host=FILE0 0=hosts.txt user=COMBO10 password_hash=COMBO12:COMBO13 1=pwdump.txt -x ...
  357. (a) (b)
  358. }}}
  359. {{{ rlogin
  360. * Brute-force usernames that root might be allowed to login as with no password (eg. a ~/.rhosts file with the line "+ root").
  361. rlogin_login host=10.0.0.1 luser=root user=FILE0 0=logins.txt persistent=0 -x ignore:fgrep=Password:
  362. * Brute-force usernames that might be allowed to login as root with no password (eg. a /root/.rhosts file with the line "+ john").
  363. rlogin_login host=10.0.0.1 user=root luser=FILE0 0=logins.txt persistent=0 -x ignore:fgrep=Password:
  364. }}}
  365. {{{ MSSQL
  366. * Brute-force authentication.
  367. -----------
  368. mssql_login host=10.0.0.1 user=sa password=FILE0 0=passwords.txt -x ignore:fgrep='Login failed for user'
  369. }}}
  370. {{{ Oracle
  371. Beware, by default in Oracle, accounts are permanently locked out after 10 wrong passwords,
  372. except for the SYS account.
  373. * Brute-force authentication.
  374. ------------
  375. oracle_login host=10.0.0.1 user=SYS password=FILE0 0=passwords.txt sid=ORCL -x ignore:code=ORA-01017
  376. NB0. With Oracle 10g XE (Express Edition), you do not need to pass a SID.
  377. NB1. If you get ORA-12516 errors, it may be because you reached the limit of
  378. concurrent connections or db processes, try using "--rate-limit 0.5 -t 2" to be
  379. more polite. Also you can run "alter system set processes=150 scope=spfile;"
  380. and restart your database to get rid of this.
  381. * Brute-force SID.
  382. ------------
  383. oracle_login host=10.0.0.1 sid=FILE0 0=sids.txt -x ignore:code=ORA-12505
  384. NB. Against Oracle9, it may crash (Segmentation fault) as soon as a valid SID is
  385. found (cx_Oracle bug). Sometimes, the SID gets printed out before the crash,
  386. so try running the same command again if it did not.
  387. }}}
  388. {{{ MySQL
  389. * Brute-force authentication.
  390. -----------
  391. mysql_login host=10.0.0.1 user=FILE0 password=FILE0 0=logins.txt -x ignore:fgrep='Access denied for user'
  392. }}}
  393. {{{ PostgresSQL
  394. * Brute-force authentication.
  395. -----------
  396. pgsql_login host=10.0.0.1 user=postgres password=FILE0 0=passwords.txt -x ignore:fgrep='password authentication failed'
  397. }}}
  398. {{{ VNC
  399. Some VNC servers have built-in anti-bruteforce functionnality that temporarily
  400. blacklists the attacker IP address after too many wrong passwords.
  401. - RealVNC-4.1.3 or TightVNC-1.3.10 for example, allow 5 failed attempts and
  402. then enforce a 10 second delay. For each subsequent failed attempt that
  403. delay is doubled.
  404. - RealVNC-3.3.7 or UltraVNC allow 6 failed attempts and then enforce a 10
  405. second delay between each following attempt.
  406. * Brute-force authentication.
  407. (a) No need to use more than one thread.
  408. (b) Keep retrying the same password when we are blacklisted by the server.
  409. (c) Exit execution as soon as a valid password is found.
  410. --------- (a)
  411. vnc_login host=10.0.0.1 password=FILE0 0=passwords.txt --threads 1
  412. -x retry:fgrep!='Authentication failure' --max-retries -1 -x quit:code=0
  413. (b) (b) (c)
  414. }}}
  415. {{{ DNS
  416. * Brute-force subdomains.
  417. (a) Ignore NXDOMAIN responses (rcode 3).
  418. -----------
  419. dns_forward name=FILE0.google.com 0=names.txt -x ignore:code=3
  420. (a)
  421. * Brute-force domain with every possible TLDs.
  422. -----------
  423. dns_forward name=google.MOD0 0=TLD -x ignore:code=3
  424. * Brute-force SRV records.
  425. -----------
  426. dns_forward name=MOD0.microsoft.com 0=SRV qtype=SRV -x ignore:code=3
  427. * Grab the version of several hosts.
  428. -----------
  429. dns_forward server=FILE0 0=hosts.txt name=version.bind qtype=txt qclass=ch
  430. * Reverse lookup several networks.
  431. (a) Ignore names that do not contain 'google.com'.
  432. (b) Ignore generic PTR records.
  433. -----------
  434. dns_reverse host=NET0 0=216.239.32.0-216.239.47.255,8.8.8.0/24 -x ignore:code=3 -x ignore:fgrep!=google.com -x ignore:fgrep=216-239-
  435. (a) (b)
  436. }}}
  437. {{{ SNMP
  438. * SNMPv1/2 : Find valid community names.
  439. ----------
  440. snmp_login host=10.0.0.1 community=FILE0 0=names.txt -x ignore:mesg='No SNMP response received before timeout'
  441. * SNMPv3 : Find valid usernames.
  442. ----------
  443. snmp_login host=10.0.0.1 version=3 user=FILE0 0=logins.txt -x ignore:mesg=unknownUserName
  444. * SNMPv3 : Find valid passwords.
  445. ----------
  446. snmp_login host=10.0.0.1 version=3 user=myuser auth_key=FILE0 0=passwords.txt -x ignore:mesg=wrongDigest
  447. NB0. If you get "notInTimeWindow" error messages, increase the retries option.
  448. NB1. SNMPv3 requires passphrases to be at least 8 characters long.
  449. }}}
  450. {{{ Unzip
  451. * Brute-force the ZIP file password (cracking older pkzip encryption used to be not supported in JtR).
  452. ----------
  453. unzip_pass zipfile=path/to/file.zip password=FILE0 0=passwords.txt -x ignore:code!=0
  454. }}}
  455. CHANGELOG
  456. ---------
  457. * v0.6 2014/08/25
  458. - added CSV and XML output formats
  459. - added module execution time column
  460. - improved RANGE keyword
  461. - new modules: rlogin_login, umbrack_crack
  462. - minor bug fixes/improvements in http_fuzz and smb_login
  463. - added more TLDs to dns_forward
  464. * v0.5 2013/07/05
  465. - new modules: mysql_query, tcp_fuzz
  466. - new RANGE and PROG keywords (supersedes the reading from stdin feature)
  467. - switched to impacket for mssql_login
  468. - output more intuitive
  469. - fixed connection cache
  470. - minor bug fixes
  471. * v0.4 2012/11/02
  472. - new modules: smb_lookupsid, finger_lookup, pop_login, imap_login, vmauthd_login
  473. - improved connection cache
  474. - improved usage, user can now act upon specific reponses (eg. stop brute-forcing host if down, or stop testing login if password found)
  475. - improved dns brute-forcing presentation
  476. - switched to dnspython which is not limited to the IN class (eg. can now scan for {hostname,version}.bind)
  477. - rewrote itertools.product to avoid memory over-consumption when using large wordlists
  478. - can now read wordlist from stdin
  479. - added timeout option to most of the network brute-forcing modules
  480. - added SSL and/or TLS support to a few modules
  481. - before_egrep now allows more than one expression (ie. useful when more than one random nonce needs to be submitted)
  482. - fixed numerous bugs
  483. * v0.3 2011/12/16
  484. - minor bugs fixed in http_fuzz
  485. - option -e better implemented
  486. - better warnings about missing dependencies
  487. * v0.2 2011/12/01
  488. - new smtp_login module
  489. - several bugs fixed
  490. * v0.1 2011/11/25 : Public release
  491. TODO
  492. ----
  493. * new option -e ns like in Medusa (not likely to be implemented due to design)
  494. * replace dnspython|paramiko|IPy with a better module (scapy|libssh2|netaddr... ?) // https://netaddr.readthedocs.org/en/latest/tutorial_01.html
  495. * use impacket/enum_lookupsids to automatically get the sid
  496. '''
  497. # }}}
  498. # logging {{{
  499. class Logger:
  500. def __init__(self, pipe):
  501. self.pipe = pipe
  502. self.name = multiprocessing.current_process().name
  503. # neat but wont work on windows
  504. # def __getattr__(self, action):
  505. # def send(*args):
  506. # self.pipe.send((self.name, action, args))
  507. # return send
  508. def send(self, action, *args):
  509. self.pipe.send((self.name, action, args))
  510. def quit(self):
  511. self.send('quit')
  512. def headers(self):
  513. self.send('headers')
  514. def result(self, *args):
  515. self.send('result', *args)
  516. def save(self, *args):
  517. self.send('save', *args)
  518. def setLevel(self, level):
  519. self.send('setLevel', level)
  520. def warn(self, msg):
  521. self.send('warn', msg)
  522. def info(self, msg):
  523. self.send('info', msg)
  524. def debug(self, msg):
  525. self.send('debug', msg)
  526. import logging
  527. class TXTFormatter(logging.Formatter):
  528. def __init__(self, indicatorsfmt):
  529. self.resultfmt = '%(asctime)s %(name)-7s %(levelname)7s - ' + ' '.join('%%(%s)%ss' % (k, v) for k, v in indicatorsfmt) + ' | %(candidate)-34s | %(num)5s | %(mesg)s'
  530. logging.Formatter.__init__(self, datefmt='%H:%M:%S')
  531. def format(self, record):
  532. if not record.msg or record.msg == 'headers':
  533. self._fmt = self.resultfmt
  534. if not all(True if 0x20 <= ord(c) < 0x7f else False for c in record.candidate):
  535. record.candidate = repr(record.candidate)
  536. else:
  537. if record.levelno == logging.DEBUG:
  538. self._fmt = '%(asctime)s %(name)-7s %(levelname)7s [%(pname)s] %(message)s'
  539. else:
  540. self._fmt = '%(asctime)s %(name)-7s %(levelname)7s - %(message)s'
  541. return logging.Formatter.format(self, record)
  542. class CSVFormatter(logging.Formatter):
  543. def __init__(self, indicatorsfmt):
  544. fmt = '%(asctime)s,%(levelname)s,'+','.join('%%(%s)s' % name for name, _ in indicatorsfmt)+',%(candidate)s,%(num)s,%(mesg)s'
  545. logging.Formatter.__init__(self, fmt, datefmt='%H:%M:%S')
  546. def format(self, record):
  547. for k in ['candidate', 'mesg']:
  548. record.__dict__[k] = '"%s"' % record.__dict__[k].replace('"', '""')
  549. return logging.Formatter.format(self, record)
  550. class XMLFormatter(logging.Formatter):
  551. def __init__(self, indicatorsfmt):
  552. fmt = '''<result time="%(asctime)s" level="%(levelname)s">
  553. ''' + '\n'.join(' <{0}>%({1})s</{0}>'.format(name.replace(':', '_'), name) for name, _ in indicatorsfmt) + '''
  554. <candidate>%(candidate)s</candidate>
  555. <num>%(num)s</num>
  556. <mesg>%(mesg)s</mesg>
  557. <target %(target)s/>
  558. </result>'''
  559. logging.Formatter.__init__(self, fmt, datefmt='%H:%M:%S')
  560. def format(self, record):
  561. for k, v in record.__dict__.iteritems():
  562. if isinstance(v, basestring):
  563. record.__dict__[k] = xmlescape(v)
  564. return super(XMLFormatter, self).format(record)
  565. class MsgFilter(logging.Filter):
  566. def filter(self, record):
  567. if record.msg:
  568. return 0
  569. else:
  570. return 1
  571. def process_logs(pipe, indicatorsfmt, argv, log_dir):
  572. ignore_ctrlc()
  573. try:
  574. # python3
  575. logging._levelToName[logging.ERROR] = 'FAIL'
  576. except:
  577. # python2
  578. logging._levelNames[logging.ERROR] = 'FAIL'
  579. handler_out = logging.StreamHandler()
  580. handler_out.setFormatter(TXTFormatter(indicatorsfmt))
  581. logger = logging.getLogger('patator')
  582. logger.setLevel(logging.DEBUG)
  583. logger.addHandler(handler_out)
  584. names = [name for name, _ in indicatorsfmt] + ['candidate', 'num', 'mesg']
  585. if log_dir:
  586. runtime_log = os.path.join(log_dir, 'RUNTIME.log')
  587. results_csv = os.path.join(log_dir, 'RESULTS.csv')
  588. results_xml = os.path.join(log_dir, 'RESULTS.xml')
  589. with open(runtime_log, 'a') as f:
  590. f.write('$ %s\n' % ' '.join(argv))
  591. if not os.path.exists(results_csv):
  592. with open(results_csv, 'w') as f:
  593. f.write('time,level,%s\n' % ','.join(names))
  594. if not os.path.exists(results_xml):
  595. with open(results_xml, 'w') as f:
  596. f.write('<?xml version="1.0" encoding="UTF-8"?>\n<root>\n')
  597. f.write('<start utc=%s local=%s/>\n' % (xmlquoteattr(strfutctime()), xmlquoteattr(strflocaltime())))
  598. f.write('<cmdline>%s</cmdline>\n' % xmlescape(' '.join(argv)))
  599. f.write('<module>%s</module>\n' % xmlescape(argv[0]))
  600. f.write('<options>\n')
  601. i = 0
  602. del argv[0]
  603. while i < len(argv):
  604. arg = argv[i]
  605. if arg[0] == '-':
  606. if arg in ('-d', '--debug'):
  607. f.write(' <option type="global" name=%s/>\n' % xmlquoteattr(arg))
  608. else:
  609. if not arg.startswith('--') and len(arg) > 2:
  610. name, value = arg[:2], arg[2:]
  611. elif '=' in arg:
  612. name, value = arg.split('=', 1)
  613. else:
  614. name, value = arg, argv[i+1]
  615. i += 1
  616. f.write(' <option type="global" name=%s>%s</option>\n' % (xmlquoteattr(name), xmlescape(value)))
  617. else:
  618. name, value = arg.split('=', 1)
  619. f.write(' <option type="module" name=%s>%s</option>\n' % (xmlquoteattr(name), xmlescape(value)))
  620. i += 1
  621. f.write('</options>\n')
  622. f.write('<results>\n')
  623. else: # remove "</results>...</root>"
  624. with open(results_xml, 'r+') as f:
  625. f.seek(f.read().find('</results>'))
  626. f.truncate(f.tell())
  627. handler_log = logging.FileHandler(runtime_log)
  628. handler_csv = logging.FileHandler(results_csv)
  629. handler_xml = logging.FileHandler(results_xml)
  630. handler_csv.addFilter(MsgFilter())
  631. handler_xml.addFilter(MsgFilter())
  632. handler_log.setFormatter(TXTFormatter(indicatorsfmt))
  633. handler_csv.setFormatter(CSVFormatter(indicatorsfmt))
  634. handler_xml.setFormatter(XMLFormatter(indicatorsfmt))
  635. logger.addHandler(handler_log)
  636. logger.addHandler(handler_csv)
  637. logger.addHandler(handler_xml)
  638. while True:
  639. pname, action, args = pipe.recv()
  640. if action == 'quit':
  641. if log_dir:
  642. with open(os.path.join(log_dir, 'RESULTS.xml'), 'a') as f:
  643. f.write('</results>\n<stop utc=%s local=%s/>\n</root>\n' % (xmlquoteattr(strfutctime()), xmlquoteattr(strflocaltime())))
  644. break
  645. elif action == 'headers':
  646. logger.info(' '*77)
  647. logger.info('headers', extra=dict((n, n) for n in names))
  648. logger.info('-'*77)
  649. elif action == 'result':
  650. typ, resp, candidate, num = args
  651. results = [(name, value) for (name, _), value in zip(indicatorsfmt, resp.indicators())]
  652. results += [('candidate', candidate), ('num', num), ('mesg', str(resp)), ('target', resp.str_target())]
  653. if typ == 'fail':
  654. logger.error(None, extra=dict(results))
  655. else:
  656. logger.info(None, extra=dict(results))
  657. elif action == 'save':
  658. resp, num = args
  659. if log_dir:
  660. filename = '%d_%s' % (num, '-'.join(map(str, resp.indicators())))
  661. with open('%s.txt' % os.path.join(log_dir, filename), 'w') as f:
  662. f.write(resp.dump())
  663. elif action == 'setLevel':
  664. logger.setLevel(args[0])
  665. else: # 'warn', 'info', 'debug'
  666. getattr(logger, action)(args[0], extra={'pname': pname})
  667. # }}}
  668. # imports {{{
  669. import re
  670. import os
  671. import sys
  672. from time import localtime, gmtime, strftime, sleep, time
  673. from platform import system
  674. from functools import reduce
  675. from select import select
  676. from itertools import islice
  677. import string
  678. import random
  679. from base64 import b64encode
  680. from datetime import timedelta, datetime
  681. from struct import unpack
  682. import socket
  683. import subprocess
  684. import hashlib
  685. from collections import defaultdict
  686. import multiprocessing
  687. import signal
  688. import ctypes
  689. from xml.sax.saxutils import escape as xmlescape, quoteattr as xmlquoteattr
  690. try:
  691. # python3+
  692. from queue import Empty, Full
  693. from urllib.parse import quote, urlencode, urlparse, urlunparse, parse_qsl, quote_plus
  694. from io import StringIO
  695. from sys import maxsize as maxint
  696. except ImportError:
  697. # python2.6+
  698. from Queue import Empty, Full
  699. from urllib import quote, urlencode, quote_plus
  700. from urlparse import urlparse, urlunparse, parse_qsl
  701. from cStringIO import StringIO
  702. from sys import maxint
  703. notfound = []
  704. try:
  705. from IPy import IP
  706. has_ipy = True
  707. except ImportError:
  708. has_ipy = False
  709. notfound.append('IPy')
  710. import multiprocessing.forking
  711. class _Popen(multiprocessing.forking.Popen):
  712. def __init__(self, *args, **kw):
  713. if hasattr(sys, 'frozen'):
  714. # We have to set original _MEIPASS2 value from sys._MEIPASS
  715. # to get --onefile mode working.
  716. os.putenv('_MEIPASS2', sys._MEIPASS)
  717. try:
  718. super(_Popen, self).__init__(*args, **kw)
  719. finally:
  720. if hasattr(sys, 'frozen'):
  721. # On some platforms (e.g. AIX) 'os.unsetenv()' is not
  722. # available. In those cases we cannot delete the variable
  723. # but only set it to the empty string. The bootloader
  724. # can handle this case.
  725. if hasattr(os, 'unsetenv'):
  726. os.unsetenv('_MEIPASS2')
  727. else:
  728. os.putenv('_MEIPASS2', '')
  729. class Process(multiprocessing.Process):
  730. _Popen = _Popen
  731. # So BaseManager.start() uses this new Process class
  732. multiprocessing.Process = Process
  733. from multiprocessing.managers import SyncManager
  734. # imports }}}
  735. # utils {{{
  736. def strfutctime():
  737. return strftime("%Y-%m-%d %H:%M:%S", gmtime())
  738. def strflocaltime():
  739. return strftime("%Y-%m-%d %H:%M:%S %Z", localtime())
  740. def which(program):
  741. def is_exe(fpath):
  742. return os.path.exists(fpath) and os.access(fpath, os.X_OK)
  743. fpath, fname = os.path.split(program)
  744. if on_windows() and fname[-4:] != '.exe' :
  745. fname += '.exe'
  746. if fpath:
  747. if is_exe(program):
  748. return program
  749. else:
  750. for path in os.environ["PATH"].split(os.pathsep):
  751. exe_file = os.path.join(path, fname)
  752. if is_exe(exe_file):
  753. return exe_file
  754. return None
  755. def build_logdir(opt_dir, opt_auto):
  756. if opt_auto:
  757. return create_time_dir(opt_dir or '/tmp/patator', opt_auto)
  758. elif opt_dir:
  759. return create_dir(opt_dir)
  760. else:
  761. return None
  762. def create_dir(top_path):
  763. top_path = os.path.abspath(top_path)
  764. if os.path.isdir(top_path):
  765. files = os.listdir(top_path)
  766. if files:
  767. if raw_input("Directory '%s' is not empty, do you want to wipe it ? [Y/n]: " % top_path) != 'n':
  768. for root, dirs, files in os.walk(top_path):
  769. if dirs:
  770. print("Directory '%s' contains sub-directories, safely aborting..." % root)
  771. sys.exit(0)
  772. for f in files:
  773. os.unlink(os.path.join(root, f))
  774. break
  775. else:
  776. os.mkdir(top_path)
  777. return top_path
  778. def create_time_dir(top_path, desc):
  779. now = localtime()
  780. date, time = strftime('%Y-%m-%d', now), strftime('%H%M%S', now)
  781. top_path = os.path.abspath(top_path)
  782. date_path = os.path.join(top_path, date)
  783. time_path = os.path.join(top_path, date, time + '_' + desc)
  784. if not os.path.isdir(top_path):
  785. os.makedirs(top_path)
  786. if not os.path.isdir(date_path):
  787. os.mkdir(date_path)
  788. if not os.path.isdir(time_path):
  789. os.mkdir(time_path)
  790. return time_path
  791. def pprint_seconds(seconds, fmt):
  792. return fmt % reduce(lambda x,y: divmod(x[0], y) + x[1:], [(seconds,),60,60])
  793. def md5hex(plain):
  794. return hashlib.md5(plain).hexdigest()
  795. def sha1hex(plain):
  796. return hashlib.sha1(plain).hexdigest()
  797. # I rewrote itertools.product to avoid memory over-consumption when using large wordlists
  798. def product(xs, *rest):
  799. if len(rest) == 0:
  800. for x in xs():
  801. yield [x]
  802. else:
  803. for head in xs():
  804. for tail in product(*rest):
  805. yield [head] + tail
  806. def chain(*iterables):
  807. def xs():
  808. for iterable in iterables:
  809. for element in iterable:
  810. yield element
  811. return xs
  812. class FileIter:
  813. def __init__(self, filename):
  814. self.filename = filename
  815. def __iter__(self):
  816. return open(self.filename)
  817. def padhex(d):
  818. x = '%x' % d
  819. return '0' * (len(x) % 2) + x
  820. # These are examples. You can easily write your own iterator to fit your needs.
  821. # Or using the PROG keyword, you can call an external program such as:
  822. # - seq(1) from coreutils
  823. # - http://hashcat.net/wiki/doku.php?id=maskprocessor
  824. # - john -stdout -i
  825. # For example:
  826. # $ ./dummy_test data=PROG0 0='seq 1 80'
  827. # $ ./dummy_test data=PROG0 0='mp64.bin ?l?l?l',$(mp64.bin --combination ?l?l?l)
  828. class RangeIter:
  829. def __init__(self, typ, rng, random=None):
  830. if typ in ('hex', 'int', 'float'):
  831. m = re.match(r'(-?.+?)-(-?.+)$', rng) # 5-50 or -5-50 or 5--50 or -5--50
  832. if not m:
  833. raise NotImplementedError("Unsupported range '%s'" % rng)
  834. mn = m.group(1)
  835. mx = m.group(2)
  836. if typ in ('hex', 'int'):
  837. mn = int(mn, 16 if '0x' in mn else 10)
  838. mx = int(mx, 16 if '0x' in mx else 10)
  839. if typ == 'hex':
  840. fmt = padhex
  841. elif typ == 'int':
  842. fmt = '%d'
  843. elif typ == 'float':
  844. from decimal import Decimal
  845. mn = Decimal(mn)
  846. mx = Decimal(mx)
  847. if mn > mx:
  848. step = -1
  849. else:
  850. step = 1
  851. elif typ == 'letters':
  852. charset = [c for c in string.letters]
  853. elif typ in ('lower', 'lowercase'):
  854. charset = [c for c in string.lowercase]
  855. elif typ in ('upper', 'uppercase'):
  856. charset = [c for c in string.uppercase]
  857. else:
  858. raise NotImplementedError("Incorrect type '%s'" % typ)
  859. def zrange(start, stop, step, fmt):
  860. x = start
  861. while x != stop+step:
  862. if callable(fmt):
  863. yield fmt(x)
  864. else:
  865. yield fmt % x
  866. x += step
  867. def letterrange(first, last, charset):
  868. for k in range(len(last)):
  869. for x in product(*[chain(charset)]*(k+1)):
  870. result = ''.join(x)
  871. if first:
  872. if first != result:
  873. continue
  874. else:
  875. first = None
  876. yield result
  877. if result == last:
  878. return
  879. if typ == 'float':
  880. precision = max(len(str(x).partition('.')[-1]) for x in (mn, mx))
  881. fmt = '%%.%df' % precision
  882. exp = 10**precision
  883. step *= Decimal(1) / exp
  884. self.generator = zrange, (mn, mx, step, fmt)
  885. self.size = int(abs(mx-mn) * exp) + 1
  886. def random_generator():
  887. while True:
  888. yield fmt % (Decimal(random.randint(mn*exp, mx*exp)) / exp)
  889. elif typ in ('hex', 'int'):
  890. self.generator = zrange, (mn, mx, step, fmt)
  891. self.size = abs(mx-mn) + 1
  892. def random_generator():
  893. while True:
  894. yield fmt % random.randint(mn, mx)
  895. else: # letters, lower, upper
  896. def count(f):
  897. total = 0
  898. i = 0
  899. for c in f[::-1]:
  900. z = charset.index(c) + 1
  901. total += (len(charset)**i)*z
  902. i += 1
  903. return total + 1
  904. first, last = rng.split('-')
  905. self.generator = letterrange, (first, last, charset)
  906. self.size = count(last) - count(first) + 1
  907. if random:
  908. self.generator = random_generator, ()
  909. self.size = maxint
  910. def __iter__(self):
  911. fn, args = self.generator
  912. return fn(*args)
  913. def __len__(self):
  914. return self.size
  915. class ProgIter:
  916. def __init__(self, prog):
  917. self.prog = prog
  918. def __iter__(self):
  919. p = subprocess.Popen(self.prog.split(' '), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  920. return p.stdout
  921. class Progress:
  922. def __init__(self):
  923. self.current = ''
  924. self.done_count = 0
  925. self.hits_count = 0
  926. self.skip_count = 0
  927. self.fail_count = 0
  928. self.seconds = [1]*25 # avoid division by zero early bug condition
  929. class TimeoutError(Exception):
  930. pass
  931. def on_windows():
  932. return 'Win' in system()
  933. def ignore_ctrlc():
  934. if on_windows():
  935. ctypes.windll.kernel32.SetConsoleCtrlHandler(0, 1)
  936. else:
  937. signal.signal(signal.SIGINT, signal.SIG_IGN)
  938. def handle_alarm():
  939. if not on_windows():
  940. signal.signal(signal.SIGALRM, raise_timeout)
  941. def raise_timeout(signum, frame):
  942. if signum == signal.SIGALRM:
  943. raise TimeoutError('timed out')
  944. def enable_alarm(timeout):
  945. if not on_windows():
  946. signal.alarm(timeout)
  947. def disable_alarm():
  948. if not on_windows():
  949. signal.alarm(0)
  950. # SyncManager.start(initializer) only available since python2.7
  951. class MyManager(SyncManager):
  952. @classmethod
  953. def _run_server(cls, registry, address, authkey, serializer, writer, initializer=None, initargs=()):
  954. ignore_ctrlc()
  955. super(MyManager, cls)._run_server(registry, address, authkey, serializer, writer)
  956. # }}}
  957. # Controller {{{
  958. class Controller:
  959. builtin_actions = (
  960. ('ignore', 'do not report'),
  961. ('retry', 'try payload again'),
  962. ('free', 'dismiss future similar payloads'),
  963. ('quit', 'terminate execution now'),
  964. )
  965. available_encodings = {
  966. 'hex': (lambda s: s.encode('hex'), 'encode in hexadecimal'),
  967. 'unhex': (lambda s: s.decode('hex'), 'decode from hexadecimal'),
  968. 'b64': (b64encode, 'encode in base64'),
  969. 'md5': (md5hex, 'hash in md5'),
  970. 'sha1': (sha1hex, 'hash in sha1'),
  971. 'url': (quote_plus, 'url encode'),
  972. }
  973. def expand_key(self, arg):
  974. yield arg.split('=', 1)
  975. def find_file_keys(self, value):
  976. return map(int, re.findall(r'FILE(\d)', value))
  977. def find_net_keys(self, value):
  978. return map(int, re.findall(r'NET(\d)', value))
  979. def find_combo_keys(self, value):
  980. return [map(int, t) for t in re.findall(r'COMBO(\d)(\d)', value)]
  981. def find_module_keys(self, value):
  982. return map(int, re.findall(r'MOD(\d)', value))
  983. def find_range_keys(self, value):
  984. return map(int, re.findall(r'RANGE(\d)', value))
  985. def find_prog_keys(self, value):
  986. return map(int, re.findall(r'PROG(\d)', value))
  987. def usage_parser(self, name):
  988. from optparse import OptionParser
  989. from optparse import OptionGroup
  990. from optparse import IndentedHelpFormatter
  991. class MyHelpFormatter(IndentedHelpFormatter):
  992. def format_epilog(self, epilog):
  993. return epilog
  994. def format_heading(self, heading):
  995. if self.current_indent == 0 and heading == 'Options':
  996. heading = 'Global options'
  997. return "%*s%s:\n" % (self.current_indent, "", heading)
  998. def format_usage(self, usage):
  999. return '%s\nUsage: %s\n' % (__banner__, usage)
  1000. available_actions = self.builtin_actions + self.module.available_actions
  1001. available_conditions = self.module.Response.available_conditions
  1002. usage = '''%%prog <module-options ...> [global-options ...]
  1003. Examples:
  1004. %s''' % '\n '.join(self.module.usage_hints)
  1005. usage += '''
  1006. Module options:
  1007. %s ''' % ('\n'.join(' %-14s: %s' % (k, v) for k, v in self.module.available_options))
  1008. epilog = '''
  1009. Syntax:
  1010. -x actions:conditions
  1011. actions := action[,action]*
  1012. action := "%s"
  1013. conditions := condition=value[,condition=value]*
  1014. condition := "%s"
  1015. ''' % ('" | "'.join(k for k, v in available_actions),
  1016. '" | "'.join(k for k, v in available_conditions))
  1017. epilog += '''
  1018. %s
  1019. %s
  1020. ''' % ('\n'.join(' %-12s: %s' % (k, v) for k, v in available_actions),
  1021. '\n'.join(' %-12s: %s' % (k, v) for k, v in available_conditions))
  1022. epilog += '''
  1023. For example, to ignore all redirects to the home page:
  1024. ... -x ignore:code=302,fgrep='Location: /home.html'
  1025. -e tag:encoding
  1026. tag := any unique string (eg. T@G or _@@_ or ...)
  1027. encoding := "%s"
  1028. %s''' % ('" | "'.join(k for k in self.available_encodings),
  1029. '\n'.join(' %-12s: %s' % (k, v) for k, (f, v) in self.available_encodings.items()))
  1030. epilog += '''
  1031. For example, to encode every password in base64:
  1032. ... host=10.0.0.1 user=admin password=_@@_FILE0_@@_ -e _@@_:b64
  1033. Please read the README inside for more examples and usage information.
  1034. '''
  1035. parser = OptionParser(usage=usage, prog=name, epilog=epilog, version=__banner__, formatter=MyHelpFormatter())
  1036. exe_grp = OptionGroup(parser, 'Execution')
  1037. exe_grp.add_option('-x', dest='actions', action='append', default=[], metavar='arg', help='actions and conditions, see Syntax below')
  1038. exe_grp.add_option('--start', dest='start', type='int', default=0, metavar='N', help='start from offset N in the wordlist product')
  1039. exe_grp.add_option('--stop', dest='stop', type='int', default=None, metavar='N', help='stop at offset N')
  1040. exe_grp.add_option('--resume', dest='resume', metavar='r1[,rN]*', help='resume previous run')
  1041. exe_grp.add_option('-e', dest='encodings', action='append', default=[], metavar='arg', help='encode everything between two tags, see Syntax below')
  1042. exe_grp.add_option('-C', dest='combo_delim', default=':', metavar='str', help="delimiter string in combo files (default is ':')")
  1043. exe_grp.add_option('-X', dest='condition_delim', default=',', metavar='str', help="delimiter string in conditions (default is ',')")
  1044. exe_grp.add_option('--allow-ignore-failures', action='store_true', default=False, dest='allow_ignore_failures', help="failures cannot be ignored with -x (this is by design to avoid false negatives) this option overrides this behavior")
  1045. opt_grp = OptionGroup(parser, 'Optimization')
  1046. opt_grp.add_option('--rate-limit', dest='rate_limit', type='float', default=0, metavar='N', help='wait N seconds between each test (default is 0)')
  1047. opt_grp.add_option('--timeout', dest='timeout', type='int', default=0, metavar='N', help='wait N seconds for a response before retrying payload (default is 0)')
  1048. opt_grp.add_option('--max-retries', dest='max_retries', type='int', default=4, metavar='N', help='skip payload after N retries (default is 4) (-1 for unlimited)')
  1049. opt_grp.add_option('-t', '--threads', dest='num_threads', type='int', default=10, metavar='N', help='number of threads (default is 10)')
  1050. log_grp = OptionGroup(parser, 'Logging')
  1051. log_grp.add_option('-l', dest='log_dir', metavar='DIR', help="save output and response data into DIR ")
  1052. log_grp.add_option('-L', dest='auto_log', metavar='SFX', help="automatically save into DIR/yyyy-mm-dd/hh:mm:ss_SFX (DIR defaults to '/tmp/patator')")
  1053. dbg_grp = OptionGroup(parser, 'Debugging')
  1054. dbg_grp.add_option('-d', '--debug', dest='debug', action='store_true', default=False, help='enable debug messages')
  1055. parser.option_groups.extend([exe_grp, opt_grp, log_grp, dbg_grp])
  1056. return parser
  1057. def parse_usage(self, argv):
  1058. parser = self.usage_parser(argv[0])
  1059. opts, args = parser.parse_args(argv[1:])
  1060. if not len(args) > 0:
  1061. parser.print_usage()
  1062. print('ERROR: wrong usage. Please read the README inside for more information.')
  1063. sys.exit(2)
  1064. return opts, args
  1065. def __init__(self, module, argv):
  1066. self.thread_report = []
  1067. self.thread_progress = []
  1068. self.payload = {}
  1069. self.iter_keys = {}
  1070. self.enc_keys = []
  1071. self.module = module
  1072. opts, args = self.parse_usage(argv)
  1073. self.combo_delim = opts.combo_delim
  1074. self.condition_delim = opts.condition_delim
  1075. self.rate_limit = opts.rate_limit
  1076. self.timeout = opts.timeout
  1077. self.max_retries = opts.max_retries
  1078. self.num_threads = opts.num_threads
  1079. self.start, self.stop = opts.start, opts.stop
  1080. self.allow_ignore_failures = opts.allow_ignore_failures
  1081. self.resume = [int(i) for i in opts.resume.split(',')] if opts.resume else None
  1082. manager = MyManager()
  1083. manager.start()
  1084. self.ns = manager.Namespace()
  1085. self.ns.actions = {}
  1086. self.ns.free_list = []
  1087. self.ns.paused = False
  1088. self.ns.quit_now = False
  1089. self.ns.start_time = 0
  1090. self.ns.total_size = 1
  1091. pipe = multiprocessing.Pipe(duplex=False)
  1092. logsvc = Process(name='LogSvc', target=process_logs, args=(pipe[0], module.Response.indicatorsfmt, argv, build_logdir(opts.log_dir, opts.auto_log)))
  1093. logsvc.daemon = True
  1094. logsvc.start()
  1095. global logger
  1096. logger = Logger(pipe[1])
  1097. if opts.debug:
  1098. logger.setLevel(logging.DEBUG)
  1099. else:
  1100. logger.setLevel(logging.INFO)
  1101. wlists = {}
  1102. kargs = []
  1103. for arg in args: # ('host=NET0', '0=10.0.0.0/24', 'user=COMBO10', 'password=COMBO11', '1=combos.txt', 'name=google.MOD2', '2=TLD')
  1104. for k, v in self.expand_key(arg):
  1105. logger.debug('k: %s, v: %s' % (k, v))
  1106. if k.isdigit():