频道栏目
首页 > 资讯 > 加密解密 > 正文

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

16-06-22        来源:[db:作者]  
收藏   我要投稿

自己使用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 paraWhiteList = newArrayList(); //参数白名单,白名单中的参数值不进行加密计算
         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); //对消息体进行解析
              
                Listheaders= 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){//对文件上传的请求,对其中的参数不做加密处理

                   ListparaList= 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[]
                Listheader= 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去开发插件兼容性最高,会少很多莫名其妙的错误。

下面这个链接对此有详细说明:
http://stackoverflow.com/questions/16218183/using-pyd-library-in-jython

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

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

 


你要问怎么样查看已有插件的代码?怎样查API文档?
首先安装一个已有插件。

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


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

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

 

 

相关TAG标签
上一篇:什么是“移动端应用协作”(MAC)攻击?
下一篇:测试Web应用程序中的竞争条件
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站