作者个人b站:https://space.bilibili.com/4404257

由于我的挖洞团队『大哥们别挖了孩子要哭惹』,经过上一篇hook前端的文章的影响后,发现其实——只要hook前端的危险生成函数,然后一般而言,危险函数会和过滤函数存在同一个或者相近的作用域下,简单来说:

let filter_data = filter(raw_data)

generate(a)//危险函数

所以用之前想到的hook方法hook住这个generate函数并找到与他同级或者上级的过滤函数这个是很必要的,那么我们要怎么找呢?

我们发现其实js在每个函数作用域下提供一个arguments的变量,而这个变量中的callee.caller则指向了上层函数,但是这里存在一个问题:当使用js内部作用域下使用'use strict'或者"use strict"时,则会导致callee.caller 会触发异常(当然运气不好的话可能是null,为什么出现null是运气不好?因为没异常你也不知道怎么回事,网上解释说是顶层调用才会出现null,而且我第一时间也认为,出异常的话才会是use strict的错(因为我在用油猴脚本hook执行的时候,他会在console.log中红字提示,去掉"use strict"即可),所以忽略了这个问题,导致我和朋友查了一个半小时,最后看了控制台对null输出的解释才知道原来是use strict的原因)

所以回到我们的正题,思前想后为了过滤use strict标签,就想到了用bp来进行拦截修改,这时候就想到bp的插件:

然后通过乌云几篇留下的插件贴和burpsuite 官方上example后就差不多懂内容,关键难的是配置:python环境,因为需要jython,而新版的pycharm不兼容,eclipse也不兼容。 java环境打包runable jar 给bp执行 执行又告诉你缺包,但是拿jadx打开又看到里面已经都被打包进去了,整个过程让我暴躁的不行。(这个流程至少从昨天5点开始到夜里2点,至少6个小时在配置环境!!!!!!!,最后放弃了只能用jython的方式,唯一缺点就是没有语法联想)。

接下来来进入到正题:burpsuite的插件(jython版)

api可以在bp里找(这个api界面是我们要实时切换回来看的)

首先第一步配置环境:


在bp中将python Environment配置为jython的路径

第二部 创建一个入口类(继承,这里应该叫实现IBurpExtenderCallbacks接口):

实现他的接口对应的接口:


实现IBurpExtender

也就是说加载把插件加载进去bp会通过反射来找对应实现了IBurpExtender接口的对象,然后new出实例对象,再调用实例对象的registerExtenderCallback,从而导致我们实现的registerExtenderCallback被触发(也可以直接把他想成是main函数)。

还有关键点就是IBurpExtenderCallbacks这个对象了,可以直接参考api:


IBurpExtenderCallbacks_api

由于篇幅较长,我们这里就简单得将该api中重点(与本篇内容有关的)的api讲解一下:


getHelpers


getStdout


*registerHttpListener


getParameters


getHeaders

(ps:这个api是根据下啦顺序来的,所以可能我们后面的顺序可能不是依赖这个来讲的。)

首先重申我们的需求-》访问网站的js-》bp自动将js中的'use strict'和"use strict"删去-》返回数据给页

所以再这个过程中我们肯定需要监听他的http请求的过程,所以要注册一个HTTP请求的监听事件(registerHttpListener,所以我们也理所应当需要一个IHttpLinstener的实现)


IHttpListener

最简单的方式就是同一个类进行实现

class Somebody(这个是我的hacker名...)Extender(IBurpExtender, IHttpListener):

因为继承(实现了IburpExtender和IHttpListener,所以需要对内部方法registerExtenderCallbacks和processHttpMessage进行实现)

def registerExtenderCallbacks(self, callbacks):

    self._callbacks = callbacks

    self._callbacks.egisterHttpListener(this)#注册监听

def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):

    pass

processHttpMessage三个参数分别是:

toolFlag->来区分插件的一个标号 int

messageIsRequest 是来区分触发该事件的是不是一个Request boolean

messageInfo 则是数据的内容 他的类型是IHttpRequestResponse

接着我们又要去介绍我们的新朋友*IHttpRequestResponse


IHttpRequestResponse

他是一个容器,里面包含一个会话(session)相当于一个request<->response。

但是需要注意的是当触发httplistener的时候如果messageIsRequest==1的话,是仅仅在请求阶段-》那么自然也就get不到Response了。但是在Response阶段你不仅可以getResponse,还能getRequest(会话并不冲突)。

所以我们也可以得到:

def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
   if not messageIsRequest:#非Request时

接着我们需要的是“将js文件中的use strict删除掉”,所以我们要知道请求的是一个js文件,这里我们要用到Request头部的信息,所以要用callbacks中的headers

他返回的是一个String数组,内容就是中的每一段(行)内容。

所以其实只要获取第一行判断内容是不是存在.js就行了

request_headers = self._callbacks.getHeaders(messageInfo.getRequest())

if ".js" in request_header[0]:

接着就是对函数内部的过滤了,上面提到了callbacks方法中getParameters函数,但其实这个函数并不是适合response,一开始我使用的时候很正常,后面发现他会将body中的内容=号去掉(这里你可能就理解了),并且他返回的是string[][]。所以其实他更像是request的方法(而且文档说了是给request使用的)(所以这里就淘汰他,我因为不知道这个规则,后面过滤完之后,发现内容js内容老是执行错误,看了下是少了很多等号,然后排查,才排查出是这个函数的问题)。

所以这里我们要怎么办呢?

这里要用到callbacks中的getHelpers方法他会返回一个IExtensionHelpers对象:

helper = self._callbacks.getHelpers()

这个对象篇幅也比较大,所以我就列举几个关键的函数:


IResponseInfo解析response的内容-》IResponseInfo对象


str->bytes,bytes->str,因为python可能涉及编码的问题,所以最好使用它的api

然后我们就可以通过analyzeResponse方法生成一个分析对象-》

response_info = helper.analyzeResponse(messageInfo.getResponse())

接着我们再看看这个生成的对象的接口:

然后其实就可以看到他有个我们需要的方法getBodyOffset:

他是获取我们body段位置的偏移,那我们怎么利用他呢?很简单

response_raw = messageInfo.getResponse()

response_body = response_raw[response_info.getBodyOffset():]#切片到最后

接着的内容就简单了无非是先将bytes转成string-> 切掉内部的use strict->转成bytes 设置回去

所以这里又用到我们的helper了:

return_js_content=helper.bytesToString(response_body).replace('\'use strict\'', '').replace('"use strict"', '')

还有重要的一点就是当body内容变了的时候在response的header里的Content-Length也要跟着变:

response_header = self._callbacks.getHeaders(messageInfo.getResponse())

header_content = ''

for header in response_headers:
   if "Content-Length:" in header:
       header_content = header_content + 'Content-Length: '+str(len(return_js_content)) +'\n'
   else:
       header_content = header_content + header + "\n"

最后一步(拼接传回):

entire_response = header_content + '\n' +return_js_content

messageInfo.setResponse(entire_response)

回想起来忘了关键的一步其实需要将api中的包导出来和对应的py同级:

还有 关键我的代码比较乱,所以上面内容的代码是我重新打了一遍的。

导包也要导正确..因为我当时用的好像是一个example 所以也没有去掉很多没必要的包,还有就是因为我的pycharm 不兼容jython,所以也没办法正确知道导入啥。

最后测试一下结果:


如今去除use strict的效果

还有一点:
不排除js动态生成的use strict..后期可能还要想个能彻底解除的方法..
最后抱怨一句:
严格模式nmsl

点击收藏 | 1 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖