Burp session模块之获取JWT令牌 – 作者:fenghua

目标

避免在使用工具时被JWT等验证信息给拦截,本文写的是解决JWT的auth校验问题,主要是为大家提供一点思路,相信各位大佬会有更好的方式解决的。

前言

还是先说下遇到的问题和相关细节,上来就说步骤不太好。简单说下问题,使用sqlmap等工具时auth会定时刷新,刷新后之前的校验信息就过期了,如果工具还在跑就坑了。下图是该网站刷新校验信息的接口:1613808293_6030c2a58ca92db8df4db.png!small?1613808293830

1613808300_6030c2ac02e325d75a496.png!small?1613808300303

顺便说下获取新auth的认证机制,用当前access_token加上获取该access_token时的refresh_token值获取新token。访问网页时无需refresh_token信息,截图如下:1613808311_6030c2b7435f21b20dda5.png!small?1613808311504

欧克,从目前的已知信息来看最好的解决方式应该是获取访问token并直接替换auth值。Emm,我最开始也是想这样解决的,但是水平不够在碰到一个又一个的问题时,采用了奇巧*记给避开,直接使用的登录时获取的token替换的auth,所以我使用的技巧有一定的问题,即动态加密的登录方式可能无法使用。咳咳,所以小菜鸡在这希望有大佬提出更好的解决方案来。

正文

Burp宏介绍

宏是一个或多个请求的预定义序列。您可以在会话处理规则中使用宏来执行各种任务。宏的典型用例包括:

提取应用程序的页面(例如用户的主页)以检查当前会话是否仍然有效。

执行登录以获取新的有效会话。

获取令牌或随机数以用作另一个请求中的参数。

在多步骤过程中扫描或模糊处理请求时,请执行必要的先前请求,以使应用程序进入接受目标请求的状态。

在多步骤过程中,在“攻击”请求之后,完成过程的其余步骤,以确认正在执行的操作,或从该过程的结束中获取结果或错误消息。

除了基本的请求顺序之外,每个宏还包括一些重要的配置,这些配置与如何处理顺序中的cookie和参数以及项目之间的任何相互依赖关系有关。

咳咳,这是官方介绍,对于我而言关注的目标仅仅是能不能达到我想要的结果,当然想要准确判断还是离不开对工具的熟悉和实验的。如果想了解更多的信息可以去官网查看,英文水平不够的可以用谷歌翻译链接如下:https://portswigger.net/burp/documentation/desktop/options/sessions

以我遇到的问题为例,新建一个宏并进行配置:1613808324_6030c2c4385277e6667d3.png!small?1613808324639

新建一个宏后会弹出历史数据包,使用filter筛选后找到想要的数据包。1613808333_6030c2cd2675190af4f51.png!small?16138083334761613808344_6030c2d8031c987ee0b48.png!small?16138083445161613808354_6030c2e27670c79a1584c.png!small?1613808354798

选好后,单击ok在选择配置:1613808384_6030c30027e156111280b.png!small?1613808384426

点击add进行选择:1613808392_6030c3080b38f5b9d1c83.png!small?1613808392782

配置结果如下:1613808398_6030c30eee1bb9080031a.png!small?1613808399348

以上就是新建宏步骤,稍后会运用到该宏。

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:1613808423_6030c327aa82fe49a1c87.png!small?1613808424069

将脚本添加进扩展后使用session处理规则进行调用。1613808430_6030c32ebaaa6445f230f.png!small?1613808431151

首先使用扩展脚本更改header1613808438_6030c33625c81d331fa67.png!small?1613808438403

在检测token是否已失效

1613808446_6030c33e899ae8c21107e.png!small?16138084468661613808455_6030c3471f21549de6850.png!small?1613808455449

如果失效运行宏并存储登录后的cookie1613808465_6030c351cb398fb52705a.png!small?1613808466323

最后在建一个更新header头的扩展即可无缝衔接jwt的爆破等功能。1613808476_6030c35c1cef13008ddcc.png!small?1613808476422

设置规则剩失效的范围和工具等。1613808494_6030c36eb7084407bae23.png!small?1613808495070

效果如下:1613808521_6030c389b4ca58a9f4a5a.png!small?1613808522033

总结

思路很重要,该功能的实现本身不需要太高深的技术但之前各种卡思路和找方法饶了很多弯总算是初步达到了想要的结果,但还有许多不足,希望可以见到各位师傅的骚套路!

其实还有不少想法可以尝试的,比如利用文章开头校验刷新出获取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官方文档》

来源:freebuf.com 2021-02-20 16:12:29 by: fenghua

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论