目标
避免在使用工具时被JWT等验证信息给拦截,本文写的是解决JWT的auth校验问题,主要是为大家提供一点思路,相信各位大佬会有更好的方式解决的。
前言
还是先说下遇到的问题和相关细节,上来就说步骤不太好。简单说下问题,使用sqlmap等工具时auth会定时刷新,刷新后之前的校验信息就过期了,如果工具还在跑就坑了。下图是该网站刷新校验信息的接口:
顺便说下获取新auth的认证机制,用当前access_token加上获取该access_token时的refresh_token值获取新token。访问网页时无需refresh_token信息,截图如下:
欧克,从目前的已知信息来看最好的解决方式应该是获取访问token并直接替换auth值。Emm,我最开始也是想这样解决的,但是水平不够在碰到一个又一个的问题时,采用了奇巧*记给避开,直接使用的登录时获取的token替换的auth,所以我使用的技巧有一定的问题,即动态加密的登录方式可能无法使用。咳咳,所以小菜鸡在这希望有大佬提出更好的解决方案来。
正文
Burp宏介绍
宏是一个或多个请求的预定义序列。您可以在会话处理规则中使用宏来执行各种任务。宏的典型用例包括:
提取应用程序的页面(例如用户的主页)以检查当前会话是否仍然有效。
执行登录以获取新的有效会话。
获取令牌或随机数以用作另一个请求中的参数。
在多步骤过程中扫描或模糊处理请求时,请执行必要的先前请求,以使应用程序进入接受目标请求的状态。
在多步骤过程中,在“攻击”请求之后,完成过程的其余步骤,以确认正在执行的操作,或从该过程的结束中获取结果或错误消息。
除了基本的请求顺序之外,每个宏还包括一些重要的配置,这些配置与如何处理顺序中的cookie和参数以及项目之间的任何相互依赖关系有关。
咳咳,这是官方介绍,对于我而言关注的目标仅仅是能不能达到我想要的结果,当然想要准确判断还是离不开对工具的熟悉和实验的。如果想了解更多的信息可以去官网查看,英文水平不够的可以用谷歌翻译链接如下:https://portswigger.net/burp/documentation/desktop/options/sessions
以我遇到的问题为例,新建一个宏并进行配置:
新建一个宏后会弹出历史数据包,使用filter筛选后找到想要的数据包。
选好后,单击ok在选择配置:
点击add进行选择:
配置结果如下:
以上就是新建宏步骤,稍后会运用到该宏。
Burp之cookie存储器和session处理规则
Burp维护一个cookie存储器、其存储了您访问的网站发布的所有cookie。Cookie存储器由Burp的所有工具共享。
您可以配置cookie存储器应监视哪些工具以更新cookie。默认情况下,将根据Proxy和Spider工具的流量更新cookie jar。Burp监视配置的工具收到的响应,并使用设置的任何新cookie更新cookie jar。对于代理服务器,还将检查来自浏览器的传入请求。这在应用程序先前设置了持久性cookie(在您的浏览器中存在)以及正确处理会话所需的持久性cookie时很有用。让Burp根据通过代理的请求更新其cookie存储器意味着即使该应用程序在您当前访问期间未更新此cookie的值,所有必需的cookie都将添加到该cookie存储器中。
您还可以使用“打开cookie存储器”按钮查看cookie存储器的内容并手动编辑cookie。
会话处理规则和宏 可以使用cookie罐来自动更新cookie罐中的cookie的传出请求。
Emm,以上还是属于官方的标准解释。我们需要借用cookie存储器去保存我们在宏中获取到的token,插件代码如下:
# python imports import re import sys # Burp specific imports from burp import IBurpExtender from burp import ISessionHandlingAction from burp import ICookie # For using the debugging tools from # https://github.com/securityMB/burp-exceptions try: from exceptions_fix import FixBurpExceptions except ImportError: pass class Cookie(ICookie): def getDomain(self): return self.cookie_domain def getPath(self): return self.cookie_path def getExpiration(self): return self.cookie_expiration def getName(self): return self.cookie_name def getValue(self): return self.cookie_value def __init__(self, cookie_domain=None, cookie_name=None, cookie_value=None, cookie_path=None, cookie_expiration=None): self.cookie_domain = cookie_domain self.cookie_name = cookie_name self.cookie_value = cookie_value self.cookie_path = cookie_path self.cookie_expiration = cookie_expiration class BurpExtender(IBurpExtender, ISessionHandlingAction): # # Define config and gui variables # cookieName = 'token' cookieDomain = 'XXX.com' # # Define some cookie functions # def deleteCookie(self, domain, name): cookies = self.callbacks.getCookieJarContents() for cookie in cookies: #self.stdout.println("%s = %s" % (cookie.getName(), cookie.getValue())) if cookie.getDomain() == domain and cookie.getName() == name: cookie_to_be_nuked = Cookie(cookie.getDomain(), cookie.getName(), None, cookie.getPath(), cookie.getExpiration()) self.callbacks.updateCookieJar(cookie_to_be_nuked) break def createCookie(self, domain, name, value, path=None, expiration=None): cookie_to_be_created = Cookie(domain, name, value, path, expiration) self.callbacks.updateCookieJar(cookie_to_be_created) def setCookie(self, domain, name, value): cookies = self.callbacks.getCookieJarContents() for cookie in cookies: if cookie.getDomain() == domain and cookie.getName() == name: cookie_to_be_set = Cookie(cookie.getDomain(), cookie.getName(), value, cookie.getPath(), cookie.getExpiration()) self.callbacks.updateCookieJar(cookie_to_be_set) break def getCookieValue(self, domain, name): cookies = self.callbacks.getCookieJarContents() for cookie in cookies: if cookie.getDomain() == domain and cookie.getName() == name: return cookie.getValue() # # implement IBurpExtender # def registerExtenderCallbacks(self, callbacks): # keep a reference to our callbacks object self.callbacks = callbacks # obtain an extension helpers object self.helpers = callbacks.getHelpers() # set our extension name callbacks.setExtensionName("JWT - Store & Set") # register ourselves a Session Handling Action callbacks.registerSessionHandlingAction(self) # Used by the custom debugging tools sys.stdout = callbacks.getStdout() print("DEBUG: JWT - Store & Set - Enabled!") return # # Implement ISessionHandlingAction # def getActionName(self): return "JWT - Store & Set" def performAction(self, current_request, macro_items): if len(macro_items) >= 0: # grab some stuff from the current request req_text = self.helpers.bytesToString(current_request.getRequest()) current_macro = macro_items[0] macro_resp = current_macro.getResponse() macro_resp_info = self.helpers.analyzeResponse(macro_resp) # parse the response & search for jwt if macro_resp: macro_resp_body = macro_resp[macro_resp_info.getBodyOffset():] macro_resp_text = self.helpers.bytesToString(macro_resp_body) search_re = '"%s":"(.*?)"' % self.cookieName search = re.search(search_re, macro_resp_text, re.IGNORECASE) # we have a jwt in the macro response if search: jwt = search.group(1) # set the cookie value in the cookie jar self.createCookie(self.cookieDomain, self.cookieName, jwt) # replace the old token with the stored value header_replace = "%s: %s" % (self.cookieName, jwt) req_text = re.sub(r"\r\n" + self.cookieName + ": .*\r\n", "\r\n" + header_replace + "\r\n" , req_text) # set the current request current_request.setRequest(self.helpers.stringToBytes(req_text)) try: FixBurpExceptions() except: pass
以下代码为设置auth头。这两个脚本之间的唯一区别在于”performAction”函数和代码的burp扩展命名部分。为了简洁起见,以下仅粘贴”performAction”函数部分。
def performAction(self, current_request, macro_items): # grab some stuff from the current request req_text = self.helpers.bytesToString(current_request.getRequest()) # grab jwt from cookie jar token = self.getCookieValue(self.cookieDomain, self.cookieName) # does a value exist yet? if token != None: # replace the old token with the stored value header_replace = "Authorization: Bearer %s" % (token) req_text = re.sub(r"\r\n" + "Authorization" + ": .*\r\n", "\r\n" + header_replace + "\r\n" , req_text) # set the current request current_request.setRequest(self.helpers.stringToBytes(req_text))
对了在此补充下,因使用的是python脚本所以添加扩展时burp需要添加jython:
将脚本添加进扩展后使用session处理规则进行调用。
首先使用扩展脚本更改header
在检测token是否已失效
如果失效运行宏并存储登录后的cookie
最后在建一个更新header头的扩展即可无缝衔接jwt的爆破等功能。
设置规则剩失效的范围和工具等。
效果如下:
总结
思路很重要,该功能的实现本身不需要太高深的技术但之前各种卡思路和找方法饶了很多弯总算是初步达到了想要的结果,但还有许多不足,希望可以见到各位师傅的骚套路!
其实还有不少想法可以尝试的,比如利用文章开头校验刷新出获取token等,但由于时间和水平有限已达到我想要的效果后就不深入了,希望有兴趣的师傅可以踩踩坑并说下方法,嘿嘿。
最后两个小脚本的下载链接:https://github.com/Hack2Web/burp-Obtain-jwt-token
参考链接
https://www.ryanwendel.com/2019/09/07/using-burp-suites-cookie-jar-for-json-web-tokens/——《使用Burp Suite的Cookie Jar获取JSON Web令牌》
https://portswigger.net/burp/documentation/desktop/options/sessions——《brup官方文档》