Un1kHacking

Security Classification: 【C-1】 | Publish Time:2024-02-05 | Category:Old Posts | Edit

Expiry Notice: The article was published three months ago. Please independently assess the validity of the technical methods and code mentioned within. :)

AI Summary: 本文介绍了如何开发一款Burp Suite插件,以便快速接入云函数进行代理测试。设计思路是简化现有工具的流量转发机制,利用IHttpListener接口监听HTTP请求,并通过自定义IHttpService修改请求参数,最终将原始请求打包并发送到云函数接口处理。文章详细描述了插件开发的步骤、代码实现及云函数处理逻辑,强调了提升插件灵活性和用户配置的必要性。 --- (From Model:gpt-4o-mini-2024-07-18)

前言

一款为了快速接入云函数代理测试的插件。本文也可给burpsuite开发初学者提供从0到1的开发步骤。

设计思路

由于目前存在的一些云函数代理工具仅仅是做了流量转发,也就是访问网站的时候一股脑儿的把流量全部通过你的vps再转发到你的云函数接口去,以达到通过使用云函数的cdn代理池从而防止被攻击溯源。这样的操作是可行的,但是实际运用是存在许多缺点的。

首先在链路上,流量->vps->云函数,需要通过两层中转,第二是云函数或者是vps的性能、带宽不足,导致访问百度这种速度较快的网站都会加载全部资源导致卡死。所以我们可以简化一下,抽取其中的部分功能给repeater用即可。

编写代码

1.阅读官方SDK与文档

2.了解需求

需要在repeater模块,发送http请求的时候,使用插件发送流量给云函数接口处理,最后返回信息到response即可。而判断在哪个模块,burpsuite api给了通用方法,并且模块可以根据toolflag来判定使用。所以我们需要用到一个监听http请求的模块。

也就是IHttpListener,使用该接口前,需要先通过 IBurpExtenderCallbacks.registerHttpListener() 注册一个 HTTP 监听器,这样所有的HTTP请求和响应都会通知这个监听器,就可以在这个监听器对HTTP数据包进行分析或修改了。

代码如下:

需要注意的是,在最前面需要接口继承IHttpListener:

该接口只提供了一个方法,processHttpMessage。这个方法拥有三个属性:

通过toolflag属性,判断是否为repeater模块 在repeater才生效,代码就可以写

  1. if(toolFlag == 0x00000040) {
  2. // To do here
  3. }

这样第一个要求就轻松解决了,接着就是后面的操作,转发流量到云函数服务接口,并且取消原始请求。这里是开发的最大坑点,这个方法自带一个接口IHttpRequestResponse。我们需要使用这个接口去改变请求和设置响应,他的方法如下:

所以我们一开始需要使用setRequest方法去修改请求,代码如下

虽然请求是被修改了,测试blog.happysec.cn域名下,不管repeater模块的request是什么代码,请求包都是bytes中的请求包,效果是会发送一个get请求/scf.php?body=,从而无视你的包体。

但是测试其他域名就出现问题了,由于setrequest只是修改了request中的报文,但是该请求包的service中的host、port、Protocol,还是原来的a.com,http,8081。当serive中的host与请求包中的host不一致的时候,会发生无法访问的情况。所以我把注意力放在了,setHttpService这个方法上面。如果我们用这个方法,把host、port、protocol改成我们的云函数相关信息,那么就可以解决我们这个问题。但由于HttpService是一个接口,不是对象,需要通过做一个接口实现:

  1. class WSHttpService implements IHttpService

让WSHttpService类实现接口IHttpService中所有的方法,之后定义三个属性,并重载getHost,getPort,getProtocol方法。

  1. private String host;
  2. private int port;
  3. private String protocol;
  4. WSHttpService() {
  5. host = "blog.happysec.cn";
  6. protocol = "https";
  7. port = 443;
  8. }
  9. @Override
  10. public String getHost() {
  11. return host;
  12. }
  13. @Override
  14. public int getPort() {
  15. return port;
  16. }
  17. @Override
  18. public String getProtocol() {
  19. return protocol;
  20. }

在类实例化构造函数中,将三个参数默认定义为云函数的接口地址、端口、协议。之后我们实例化一个类WSHttpService,并用setService方法重新设置messageInfo的service信息。

代码如下:

  1. WSHttpService iHttpService = new WSHttpService();
  2. messageInfo.setHttpService(iHttpService);
  3. IHttpService iHttpService2 = messageInfo.getHttpService();
  4. this.stdout.println(iHttpService.getHost());
  5. this.stdout.println(iHttpService.getPort());
  6. this.stdout.println(iHttpService.getProtocol());

重新打包插件后我们访问网站测试

发现无论请求包设置的host为啥,都走的是WSHttpService类下的host、port、Protocol。

解决了这个问题,其他的也就是写云函数接口、打包原始请求headers、发送请求包至云函数接口的简单代码即可了。

3.打包原始请求代码编写

我们需要把原始http请求报文打包发送给云函数接口,通过

  1. String body =(helpers.bytesToString(messageInfo.getRequest())); //获取请求数据

这行代码我们可以获取字符串类型的原始请求数据,也就是

这个框里的内容

为了防止编码错误,我们使用base64对string做编码

  1. try {
  2. base64encodedString = Base64.getEncoder().encodeToString(body.getBytes("utf-8"));
  3. } catch (UnsupportedEncodingException e) {
  4. e.printStackTrace();
  5. }

接着我们只需要 重新修改原始请求即可

所以这样能够理解了,前面修改service的目的只是为了防止host不一致导致请求无法传递而已。

然后我们修改body后的参数为我们需要传递的base64代码即可

4.云函数代码编写

此时burp插件已经编写完毕了。

接下来就是云函数对请求包的处理。处理原始请求包提取里面的body、host、uri、method、content-type等重要参数,使用云函数重新请求即可。

这里需要注意的是,由于请求和响应都会被这个监听器捕获,所以我们需要设置条件

默认对获取响应不做处理即可。

我通过

  1. String body = (helpers.bytesToString(messageInfo.getRequest())); //获取请求数据包

再将body进行base64编码,这样就可以发包给云函数接口原请求的http报文。做接口的话选择很多,我这里选择php代码来写。

首先,对原请求重新发包,拿的是http报文。就需要使用socket来write,再重新发包。

这里的坑点也很多,一开始我用的是fsockopen这个函数,但是后面遇到证书错误的问题,于是改用stream_socket_client,并在上下文stream_context_create创建了一个ssl,把verify_peer_name和verify_peer都设置成false,这样就可以忽略证书文件校验了。但是发现上传文件的时候会上传错误,某些接口网站访问空白,并且不是云函数的问题,是代码的问题。

在write的时候发生了什么不可预见错误,我通过反复diff请求包也没有找到问题,接口收到的请求包和原始请求包怎么看都是一个请求包,于是我放弃了这个思路,只能做报文解析了。然后用curl去发包,analyzeRequest给了几个好用的方法,geturl和getHeaders,这样我们可以快速获取url和头部信息,但是需要注意这里的headers的第一个元素是类似POST /api HTTP/1.1的一行,method也可以用getmethod获取,uri在url里,所以我们可以把headers这个list的第一个元素remove,然后都编码base64发给接口。

至此,headers、url、method的问题都可以解决,接下来就是解决body中的文件内容或者请求参数的获取了。对于analyzeRequest,burpsuite api没有给出拿到body内容的接口。但是给了获取body的偏移量getbodyoffset。所以我们可以用以下代码获得请求body:

  1. String sendData = body.substring(reqInfo.getBodyOffset());

也就是把请求包从偏移量开始的地方截取全部,就是body的内容了。后面拿到值然后用curl_setopt即可,就不多写了,效果如下(解决了蛋疼的编码问题)

实际使用还是存在很多需要提升的地方,比如云函数接口是硬编码的,不是动态可变的。导入配置我倒是思考过,但是发现需要绘制ui和使用另外的加载器,比较麻烦,还不如在burpsuite的文件夹下做一个ini的默认载入,不存在就提示用什么命令加载。

mac效果如下:


之后写一个菜单 做监听 假设我修改了配置文件中的接口 那么点击就会重载

对接口代码作修改 在响应内容中加入使用的api host 便于区分

基本上这样就可以投入使用啦~


Comment List

© Copyright: This article is an original work and the copyright belongs to the  Depy's docs  unless marked as Reproduced

Please contact the blogger for authorization to reprint