首页 > 技术知识 > 正文

No.1

声明

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测以及文章作者不为此承担任何责任。

雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。

No.2

前言

这节课的来源是在写fastjson rce检测插件时所遇到的问题并解决后的笔记。

我们知道fastjson的数据是json格式的, 那么前面学的buildParameter就不适用该情况了,会导致使用buildParameter重构参数后报错。

这节课学习 buildHttpMessage 重构json数据,并结合前面课程实现fastjson rce检测插件

No.3

getContentType

此方法用于获取消息正文的内容类型,由IRequestInfo对象调用

官方api:https://portswigger.net/burp/extender/api/burp/IRequestInfo.html#getContentType()

Burp Extender Apis 插件开发 (六)

示例代码如下:

reqContentType = analyzedRequest.getContentType()

如果数据是json格式,那么analyzedRequest.getContentType()返回来的值是4。

那么就可以通过reqContentType是否等于4过滤掉不是json格式的数据包,从而使该插件只检测当数据类型是json时才触发。

接下来准备重构数据包。

No.4

stringToBytes()

byte[] stringToBytes(java.lang.String data)

此方法可用于将数据从字符串形式转换为字节数组。该转换不反映任何特定字符集,十六进制表示为0xWXYZ的字符将始终转换为表示形式为0xYZ的字节。它执行与方法相反的转换bytesToString(),并保证使用这两种方法将基于字节的数据转换为String并再次返回,以确保其完整性(反映给定字符集的转换可能不是这种情况)。

官方api:https://portswigger.net/burp/extender/api/burp/IExtensionHelpers.html#stringToBytes(java.lang.String)

Burp Extender Apis 插件开发 (六)1
打开凤凰新闻,查看更多高清图片

官方的解释有点拗口,其实很简单,就是把我们想要提交的字符串内容转换为burp能认识的数据类型。

示例代码如下:将字符串payload转换为burp认识的字节类型,这样newBody的数据类型就变成了byte,就能够在下一个api里使用了。

newBodyPayload = {“age”:25, “name”:”Bob””}

newBody = self._helpers.stringToBytes(newBodyPayload) # 将字符串转换为字节

当构造好payload后,下面准备重构http消息

No.5

buildHttpMessage

byte[] buildHttpMessage(java.util.List headers, byte[] body)

此方法构建包含指定的标头和消息正文的HTTP消息。如果适用,将根据正文的长度添加或更新Content-Length标头。

官方api:https://portswigger.net/burp/extender/api/burp/IExtensionHelpers.html#buildHttpMessage(java.util.List,%20byte[])

Burp Extender Apis 插件开发 (六)2

buildHttpMessage的第一个参数headers是IRequestInfo对象的getHeaders()方法返回值

示例代码如下:如果不知道analyzedIRequestInfo是什么变量,请回顾前几节课。

reqHeaders = analyzedIRequestInfo.getHeaders()

buildHttpMessage的第二个参数body是IExtensionHelpers.stringToBytes(字符串)的返回值

newBody = self._helpers.stringToBytes(newBodyPayload) # 将字符串转换为字节

准备好两个参数后,传递给buildHttpMessage即可重构http消息

newRequest = self._helpers.buildHttpMessage(reqHeaders, newBody) # 重构json格式的数据不能用buildParameter,要用buildHttpMessage替换整个body重构http消息。

然后接下来同样使用makeHttpRequest发送数据并响应即可。

newIHttpRequestResponse = self._callbacks.makeHttpRequest(httpService, newRequest) # 发送数据

fastjson rce检测插件demo

示例代码如下:

# -*-coding:utf-8 -*-

# 被动扫描fastjson rce检测

from burp import IBurpExtender, IScannerCheck, IScanIssue, IMessageEditorTabFactory, IContextMenuFactory

from burp import IScanIssue

import sys

import time

import os

class BurpExtender(IBurpExtender, IMessageEditorTabFactory, IContextMenuFactory, IScannerCheck):

def registerExtenderCallbacks(self, callbacks):

# Required for easier debugging:

sys.stdout = callbacks.getStdout()

# 用于设置当前扩展的显示名称,该名称将显示在Extender工具的用户界面中。参数:name – 扩展名。。

self._callbacks = callbacks

# 用于获取IExtensionHelpers对象,扩展可以使用该对象执行许多有用的任务。返回:包含许多帮助器方法的对象,用于构建和分析HTTP请求等任务。

self._helpers = callbacks.getHelpers()

# 用于设置当前扩展的显示名称,该名称将显示在Extender工具的用户界面中。参数:name – 扩展名。

self._callbacks.setExtensionName(“Passive Fastjson Check”)

# 注册扫描

callbacks.registerScannerCheck(self)

# 获取请求的url

def get_request_url(self, protocol, reqHeaders):

link = reqHeaders[0].split( )[1]

host = reqHeaders[1].split( )[1]

return protocol + :// + host + link

# 获取请求的一些信息:请求头,请求内容,请求方法,请求参数

def get_request_info(self, request):

analyzedIRequestInfo = self._helpers.analyzeRequest(request) # analyzeRequest用于分析HTTP请求,并获取有关它的各种关键详细信息。生成的IRequestInfo对象

reqHeaders = analyzedIRequestInfo.getHeaders() # 用于获取请求中包含的HTTP头。返回:请求中包含的HTTP标头。

reqBodys = request[analyzedIRequestInfo.getBodyOffset():].tostring() # 获取消息正文开始的请求中的偏移量。返回:消息正文开始的请求中的偏移量。

reqMethod = analyzedIRequestInfo.getMethod() # 获取请求方法

reqParameters = analyzedIRequestInfo.getParameters()

return analyzedIRequestInfo, reqHeaders, reqBodys, reqMethod, reqParameters

# 获取响应的一些信息:响应头,响应内容,响应状态码

def get_response_info(self, response):

analyzedIResponseInfo = self._helpers.analyzeRequest(response) # analyzeResponse方法可用于分析HTTP响应,并获取有关它的各种关键详细信息。返回:IResponseInfo可以查询的对象以获取有关响应的详细信息。

resHeaders = analyzedIResponseInfo.getHeaders() # getHeaders方法用于获取响应中包含的HTTP标头。返回:响应中包含的HTTP标头。

resBodys = response[analyzedIResponseInfo.getBodyOffset():].tostring() # getBodyOffset方法用于获取消息正文开始的响应中的偏移量。返回:消息正文开始的响应中的偏移量。response[analyzedResponse.getBodyOffset():]获取正文内容

# resStatusCode = analyzedIResponseInfo.getStatusCode() # getStatusCode获取响应中包含的HTTP状态代码。返回:响应中包含的HTTP状态代码。

return resHeaders, resBodys

# 获取服务端的信息,主机地址,端口,协议

def get_server_info(self, httpService):

host = httpService.getHost()

port = httpService.getPort()

protocol = httpService.getProtocol()

ishttps = False

if protocol == https:

ishttps = True

return host, port, protocol, ishttps

# 获取请求的参数名、参数值、参数类型(get、post、cookie->用来构造参数时使用)

def get_parameter_Name_Value_Type(self, parameter):

parameterName = parameter.getName()

parameterValue = parameter.getValue()

parameterType = parameter.getType()

return parameterName, parameterValue, parameterType

# 开始检测

def start_run(self, baseRequestResponse):

self.baseRequestResponse = baseRequestResponse

# 获取请求包的数据

request = self.baseRequestResponse.getRequest()

analyzedRequest, reqHeaders, reqBodys, reqMethod, reqParameters = self.get_request_info(request)

reqContentType = analyzedRequest.getContentType() # 获取请求格式,例如json

if reqContentType == 4: # json格式数据

# 获取服务信息

httpService = self.baseRequestResponse.getHttpService()

newBodyPayload = {“age”:25, “name”:”Bob””}

newBody = self._helpers.stringToBytes(newBodyPayload) # 将字符串转换为字节 https://portswigger.net/burp/extender/api/burp/IExtensionHelpers.html#stringToBytes(java.lang.String)

newRequest = self._helpers.buildHttpMessage(reqHeaders, newBody) # 重构json格式的数据不能用buildParameter,要用buildHttpMessage替换整个body重构http消息。https://portswigger.net/burp/extender/api/burp/IExtensionHelpers.html#buildHttpMessage(java.util.List,%20byte[])

newIHttpRequestResponse = self._callbacks.makeHttpRequest(httpService, newRequest) # 发送数据

response = newIHttpRequestResponse.getResponse() # 获取响应包

analyzedIResponseInfo = self._helpers.analyzeRequest(response) # analyzeResponse方法可用于分析HTTP响应,并获取有关它的各种关键详细信息。返回:IResponseInfo可以查询的对象以获取有关响应的详细信息。

resBodys = response[analyzedIResponseInfo.getBodyOffset():].tostring()

newUrl = self._helpers.analyzeRequest(newIHttpRequestResponse).getUrl()

print resBodys

if fastjson in resBodys:

print [+] {}.format(newUrl)

self.save(newUrl)

self.issues.append(CustomScanIssue(

newIHttpRequestResponse.getHttpService(),

newUrl,

[newIHttpRequestResponse],

“FastJson RCE”,

“fastjson”,

“High”))

else:

print [-] {}.format(newUrl)

def doPassiveScan(self, baseRequestResponse):

:param baseRequestResponse: IHttpRequestResponse

:return:

self.issues = []

self.start_run(baseRequestResponse)

return self.issues

def consolidateDuplicateIssues(self, existingIssue, newIssue):

相同的数据包,只报告一份报告

:param existingIssue:

:param newIssue:

:return:

if existingIssue.getIssueDetail() == newIssue.getIssueDetail():

return -1

return 0

class CustomScanIssue(IScanIssue):

def __init__(self, httpService, url, httpMessages, name, detail, severity):

:param httpService: HTTP服务

:param url: 漏洞url

:param httpMessages: HTTP消息

:param name: 漏洞名

:param detail: 漏洞细节

:param severity: 漏洞等级

self._httpService = httpService

self._url = url

self._httpMessages = httpMessages

self._name = name

self._detail = detail

self._severity = severity

def getUrl(self):

return self._url

def getIssueName(self):

return self._name

def getIssueType(self):

return 0

def getSeverity(self):

return self._severity

def getConfidence(self):

return “Certain”

def getIssueBackground(self):

pass

def getRemediationBackground(self):

pass

def getIssueDetail(self):

return self._detail

def getRemediationDetail(self):

pass

def getHttpMessages(self):

return self._httpMessages

def getHttpService(self):

return self._httpService

效果如下:

当正常发送数据包时,响应包没报错

Burp Extender Apis 插件开发 (六)3

再来看看插件的情况,可以看到响应包里出现了fastjon字符串,说明payload检测出了该漏洞

Burp Extender Apis 插件开发 (六)3

这里demo用的是写死的payload,自己写的时候根据自己的需求将payload请求的地址改为dnslog的地址。

猜你喜欢