转载

BurpSuite插件开发Tips:请求响应参数的AES加解密

缘由

自己使用burp进行测试的过程中遇到好些接口是有sign的,如果修改了请求参数都需要重新计算sign值,所以有用python实现过一个简单的插件,来自动计算sign值,以达到和普通接口测试一样方便的效果。

后来,好基友在做一个APP的测试的时候,发现有类似的问题,接口的所有参数都有使用AES加密,返回也是一样。他通过逆向获得了加密的算法,我们就通过如下的插件实现了自动加解密的过程。在整个过程中有一点点收获,现分享出来。

具体bug请移步:

Zealer_android客户端安全检测(从脱壳到burp自动加解密插件案例/SQL注入/逻辑漏洞/附AES加解密脚本POC)

代码

闲话少说,上代码,BurpExtender主类代码如下,进行了较为详细的注释。AES算法类的参考链接:

http://www.wenhq.com/article/view_716.html

package burp;   import java.util.ArrayList; import java.util.List; import java.io.PrintWriter; import java.net.URLEncoder;     import burp.AESOperator; //AES加解密算法的实现类 import burp.Util; //unicode解码的实现类     public classBurpExtender implements IBurpExtender, IHttpListener {    privateIBurpExtenderCallbacks callbacks;    privateIExtensionHelpers helpers;    privatePrintWriter stdout;//用于输出,主要用于代码调试        // implement IBurpExtender    @Override    publicvoidregisterExtenderCallbacks(IBurpExtenderCallbacks callbacks)    {       stdout = new PrintWriter(callbacks.getStdout(), true);       //PrintWriter stdout = new PrintWriter(callbacks.getStdout(),true); 这种写法是定义变量和实例化一并进行,会覆盖之前的同名变量。       //stdout.println("testxx");       //System.out.println("test"); 不会输出到burp的         this.callbacks = callbacks;         helpers = callbacks.getHelpers();         callbacks.setExtensionName("AES encrypt Java edition");//插件名称         callbacks.registerHttpListener(this); //如果没有注册,下面的processHttpMessage方法是不会生效的。处理请求和响应包的插件,这是必要的。    }      @Override    publicvoidprocessHttpMessage(int toolFlag,boolean messageIsRequest,IHttpRequestResponsemessageInfo)    {       try{          List<String> paraWhiteList = newArrayList<String>(); //参数白名单,白名单中的参数值不进行加密计算          paraWhiteList.add("android");                    if (toolFlag == 64 || toolFlag == 16 || toolFlag == 32 || toolFlag == 4){ //不同的toolflag代表了不同的burp组件。参考链接https://portswigger.net/burp/extender/api/constant-values.html#burp.IBurpExtenderCallbacks              if (messageIsRequest){ //对请求包进行处理                 IRequestInfoanalyzeRequest= helpers.analyzeRequest(messageInfo); //对消息体进行解析                                 List<String>headers= analyzeRequest.getHeaders();//获取http请求头的信息,返回可以看作是一个python中的列表,java中是叫泛型。                 boolean isFileUploadRequest=false;                 for (String header : headers){                    //stdout.println(header);                    if (header.toLowerCase().indexOf("content-type")!=-1&& header.toLowerCase().indexOf("boundary")!=-1){//通过http头中的内容判断这个请求是否是文件上传的请求。                       isFileUploadRequest= true;                    }                 }                                 if (isFileUploadRequest== false){//对文件上传的请求,对其中的参数不做加密处理                    List<IParameter>paraList= analyzeRequest.getParameters();//获取参数列表,参数分为三种类型,URL中的参数,cookie中的参数,body中的参数。                    byte[] new_Request = messageInfo.getRequest();                    for (IParameter para : paraList){// 循环获取参数,判断类型,进行加密处理后,再构造新的参数,合并到新的请求包中。                       if ((para.getType() == 0 || para.getType() == 1)&& !paraWhiteList.contains(para.getName())){ //getTpe()就是来判断参数是在那个位置的,cookie中的参数是不需要进行加密处理的。还要排除白名单中的参数。                          Stringkey= para.getName();//获取参数的名称                          Stringvalue= para.getValue();//获取参数的值                          //stdout.println(key+":"+value);                          AESOperatoraes= newAESOperator(); //实例化加密的类                          Stringaesvalue;                          aesvalue = aes.encrypt(value); //对value值进行加密                          aesvalue = URLEncoder.encode(aesvalue); //进行URL编码,否则会出现“=”等特殊字符导致参数判断异常                          stdout.println(key+":"+value+":"+aesvalue); //输出到extender的UI窗口,可以让使用者有一些判断                          IParameternewPara= helpers.buildParameter(key, aesvalue, para.getType()); //构造新的参数                          new_Request = helpers.updateParameter(new_Request, newPara); //构造新的请求包                       }                    }                    messageInfo.setRequest(new_Request);//设置最终新的请求包                 }                 /* to verify the updated result                 for(IParameter para : helpers.analyzeRequest(messageInfo).getParameters()){                    stdout.println(para.getValue());                 }                 */              }                           else{                 //处理返回,响应包                 IResponseInfoanalyzedResponse= helpers.analyzeResponse(messageInfo.getResponse()); //getResponse的返回类型是Byte[]                 List<String>header= analyzedResponse.getHeaders();                 short statusCode = analyzedResponse.getStatusCode();                 int bodyOffset = analyzedResponse.getBodyOffset();                 if (statusCode==200){                    try{                       AESOperatoraes= newAESOperator();                       Stringresp= newString(messageInfo.getResponse());//Byte[] to String                           String body = resp.substring(bodyOffset);                           String deBody= aes.decrypt(body);                           deBody = deBody.replace("/"","///"");                           String UnicodeBody = (new Util()).unicodeDecode(deBody);                           //String newBody = body +"/r/n" +UnicodeBody; //将新的解密后的body附到旧的body后面                           String newBody = UnicodeBody;                           byte[] bodybyte = newBody.getBytes();                           messageInfo.setResponse(helpers.buildHttpMessage(header, bodybyte));                    }catch(Exception e){                       stdout.println(e);                    }                 }              }                      }       }       catch(Exception e){          stdout.println(e);       }             } }

收获和建议

1.能用java就不要用其他

我平常python用得比较多的,之前也用python写过几个简单插件。但是在开发burp插件的时候,发现还是Java更合适。上面的这个插件,最初就是用py实现的,但是,当这个py文件调了python的其他类,如下图。通过Jython去解析执行,遇到pyd文件就无法进行下去了,因为pyd是C写的,Jython是无法使用C写的模块的。burp本事是Java写的,使用Java去开发插件兼容性最高,会少很多莫名其妙的错误。

BurpSuite插件开发Tips:请求响应参数的AES加解密

下面这个链接对此有详细说明:

http://stackoverflow.com/questions/16218183/using-pyd-library-in-jython

BurpSuite插件开发Tips:请求响应参数的AES加解密

2.代码的适当分离

我会分别将插件的代码和AES算法的代码分别写在两个不同文件中。这样可以单独调试算法的代码,也可以让插件代码更简洁不易出错。因为插件的代码每修改一次都需要重新在burp中加载才可以看到效果,不像一般的程序在IDE中就可以调试,所以个人认为这样比较好。

BurpSuite插件开发Tips:请求响应参数的AES加解密

3.插件代码的模式

插件代码的结构基本是固定的。比如,如果想要写一个对http请求和响应进行操作的插件,那么基本上如图的这段代码是可以直接copy使用的,下图标红的几个方法就都是必须的。我想我们大多数时候都是在对http的包进行处理。有了大的框架之后,再进行修改相对会容易很多。所以,如果你想写一个什么样的插件,你完全可以去找一个类似的插件,看他的代码,copy他的代码,改他的代码(比如我的,呵呵)。

BurpSuite插件开发Tips:请求响应参数的AES加解密

你要问怎么样查看已有插件的代码?怎样查API文档?

首先安装一个已有插件。

BurpSuite插件开发Tips:请求响应参数的AES加解密

找到burp所在路径下的bapps目录,里面就是你安装了的插件。

BurpSuite插件开发Tips:请求响应参数的AES加解密

BurpSuite插件开发Tips:请求响应参数的AES加解密

拖到JD-Gui中就可以看代码了,这种一般是不会做混淆的,至少我还没发现~。Py的就更不用说了,直接文件右键打打开。

BurpSuite插件开发Tips:请求响应参数的AES加解密

4.怎样阅读API文档

关于API文档,我是通过溯源的方法,对于0基础的读者比较实用。比如我的目的是加密各个参数,那么首先要获取请求中的参数。我先去API库中搜索关键词parameter,可以找到多个相关方法,通过对比,我确定List<IParameter> getParameters();是我需要的。找到这个方法后,查看它的参数、返回值类型、所属的类这三个关键因素。它属于IRequestInfo类,只有 IRequestInfo类型的对象才可以调用它, 那么,有哪些方法会返回这个类型的对象呢?再去找那些方法可以返回这个类型的方法。依次类推,可以知道需要使用哪些方法,哪些类,就能梳理清除大致的思路了。

BurpSuite插件开发Tips:请求响应参数的AES加解密

参考文档汇总

向先行者致敬,让我们少走弯路。

java 篇:

BurpSuite 扩展开发[1]-API与HelloWold   http://drops.wooyun.org/papers/3962

BurpSuite 插件编写教程(第一篇) http://www.moonsos.com/Article/penetration/107.html

国产BurpSuite插件Assassin V1.0发布   http://www.moonsos.com/tools/webscan/97.html

BurpSuite 插件开发指南之 API 上篇   http://www.evil0x.com/posts/17487.html

BurpSuite插件开发指南之 API 下篇 http://drops.wooyun.org/tools/14685

BurpSuite 插件开发指南之 Java 篇   http://drops.wooyun.org/tools/16056

python 篇:

burpsuite 扩展开发之Python(change unicode to chinese) 我是从这入门的 http://drops.wooyun.org/tools/5751

BurpSuite 插件开发之过狗菜刀  http://www.secpulse.com/archives/44241.html

* 作者:bit4,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)

原文  http://www.freebuf.com/articles/terminal/106673.html
正文到此结束
Loading...