XX客户端APP签名分析之bp插件打造篇

  • A+
所属分类:安全文章

前言

本篇主要思路及方法来自于bit4woo和CC11001100两位巨佬的成果。


学习链接https://github.com/bit4woo/burp-api-drops


根据大佬的建议,本次插件使用java进行编写。而且bp插件的编写对于类名也有严格的限制。


主要的调用逻辑如下所示


XX客户端APP签名分析之bp插件打造篇


根据该图,对于插件编写的流程其实也很清楚了,我们只需要先调用这些之前写好的类,然后只需要编写BurpExtender这一个类就好了。


01

热编写流程

首先因为不同网站对应的Key不同,先创建个字典进行存放。


public BurpExtender() {  this.signMap = new ConcurrentHashMap<>();    signMap.put("class.mosaic.cn", "ac6190d7dfaa77df726f0a82244d3eda68675ccd4e95de802f5042e91d15edc7bae3026d8f0fb2a8287446bb289563970264");  signMap.put("bbsapi.mosaic.cn", "Wj8BI3VUZ6BuojAkqzBM3HWHNHv08xdZEtaksbRg6snnuLsvivwa8IvR6PvQ76H0IQQsqkIsa5OKJtg6QcBMfCblMMywgZaA8co");    }


然后是IBurpExtender必须实现的方法registerExtenderCallbacks


@Overridepublic void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {        this.callbacks = callbacks;        callbacks.setExtensionName("xxsign重放辅助渗透");        helpers = callbacks.getHelpers();        stdout = new PrintWriter(callbacks.getStdout(), true);        callbacks.registerHttpListener(this);//如果不注册,processHttpMessage方法不会生效。    }


接下来就是processHttpMessage方法,首先要确定toolFlag,不同的toolFlag代表不同的burp组件,此处我们只处理repeater发出的消息。


if (toolFlag != burp.IBurpExtenderCallbacks.TOOL_REPEATER) {            return;        }        // 只处理请求,响应则忽略        if (!messageIsRequest) {            return;        }        byte[] request = messageInfo.getRequest();        if (request == null || request.length == 0) {            return;        }
       // 只有特定的两个域名才会生效        final IHttpService httpService = messageInfo.getHttpService();        final String host = httpService.getHost();        if (!signMap.containsKey(host)) {            return;        }


接下来是获取参数,由于上一节中已经分析出了参数组成,key是固定值,noncestr是随机生成。timestamp是当前时间戳,因此实际上参数的获取所产生交互是比较少的。只需要生成这些参数的拼接格式,以及SHA1算法。


long now = System.currentTimeMillis();


private static String randomNoncestr() {        StringBuilder sb = new StringBuilder();        for (int i = 0; i < 8; i++) {            char c = (char) (ThreadLocalRandom.current().nextInt(10) + 48);            sb.append(c);        }        return sb.toString();    }


final String sign = DigestUtils.sha1Hex(sb.toString());


最后每次重放就替换掉参数即可。


final IParameter newTimestampParam = helpers.buildParameter("timestamp", now + "", IParameter.PARAM_URL);        final IParameter newSignParam = helpers.buildParameter("sign", sign, IParameter.PARAM_URL);        final IParameter newNoncestrParam = helpers.buildParameter("noncestr", noncestr, IParameter.PARAM_URL);        request = helpers.updateParameter(request, newTimestampParam);        request = helpers.updateParameter(request, newSignParam);        request = helpers.updateParameter(request, newNoncestrParam);        messageInfo.setRequest(request);        stdout.println("更新了sign: " + sign);        stdout.println("更新了timestamp: " + now);        stdout.println("更新了noncestr: " + noncestr);        stdout.println("本次处理完毕");


所有的关键操作就这样完成了。


02

总结


最终BurpExtender类代码


public class BurpExtender implements IBurpExtender, IHttpListener {
   private IBurpExtenderCallbacks callbacks;    private IExtensionHelpers helpers;    private PrintWriter stdout;
   private ConcurrentHashMap<String, String> signMap;
   public BurpExtender() {        this.signMap = new ConcurrentHashMap<>();        signMap.put("class.mosaic.cn", "ac6190d7dfaa77df726f0a82244d3eda68675ccd4e95de802f5042e91d15edc7bae3026d8f0fb2a8287446bb289563970264");        signMap.put("bbsapi.mosaic.cn", "Wj8BI3VUZ6BuojAkqzBM3HWHNHv08xdZEtaksbRg6snnuLsvivwa8IvR6PvQ76H0IQQsqkIsa5OKJtg6QcBMfCblMMywgZaA8co");    }
   @Override    public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {        this.callbacks = callbacks;        callbacks.setExtensionName("xx客户端sign重放辅助渗透");        helpers = callbacks.getHelpers();        stdout = new PrintWriter(callbacks.getStdout(), true);        callbacks.registerHttpListener(this);    }
   @Override    public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) {        // 只处理repeater发出的消息        if (toolFlag != burp.IBurpExtenderCallbacks.TOOL_REPEATER) {            return;        }        // 只处理请求,响应则忽略        if (!messageIsRequest) {            return;        }        byte[] request = messageInfo.getRequest();        if (request == null || request.length == 0) {            return;        }
       // 只有特定的两个域名才会生效        final IHttpService httpService = messageInfo.getHttpService();        final String host = httpService.getHost();        if (!signMap.containsKey(host)) {            return;        }
       stdout.println("检测到,开始处理...");        final IRequestInfo requestInfo = helpers.analyzeRequest(request);        TreeMap<String, String> signParamsMap = new TreeMap<>();        requestInfo.getParameters().forEach(x -> {            if (IParameter.PARAM_URL != x.getType()) {                return;            }            if ("timestamp".equals(x.getName()) || "sign".equals(x.getName()) || "noncestr".equals(x.getName())) {                return;            }            signParamsMap.put(URLDecoder.decode(x.getName(), UTF_8), URLDecoder.decode(x.getValue(), UTF_8));        });
       String appSignKey = signMap.get(host);        signParamsMap.put("appSignKey", appSignKey);
       long now = System.currentTimeMillis();//        long now = 1626237221383L;        signParamsMap.put("timestamp", now + "");
       String noncestr = randomNoncestr();//        String noncestr = "73699378";        signParamsMap.put("noncestr", noncestr);
       StringBuilder sb = new StringBuilder();        signParamsMap.forEach((key, value) -> {            sb.append(key).append("=").append(value).append("&");        });        if (sb.length() > 0) {            sb.deleteCharAt(sb.length() - 1);        }        stdout.println("用来SHA1加密的字符串: " + sb.toString());        final String sign = DigestUtils.sha1Hex(sb.toString());
       // 替换掉参数        final IParameter newTimestampParam = helpers.buildParameter("timestamp", now + "", IParameter.PARAM_URL);        final IParameter newSignParam = helpers.buildParameter("sign", sign, IParameter.PARAM_URL);        final IParameter newNoncestrParam = helpers.buildParameter("noncestr", noncestr, IParameter.PARAM_URL);        request = helpers.updateParameter(request, newTimestampParam);        request = helpers.updateParameter(request, newSignParam);        request = helpers.updateParameter(request, newNoncestrParam);        messageInfo.setRequest(request);        stdout.println("更新了sign: " + sign);        stdout.println("更新了timestamp: " + now);        stdout.println("更新了noncestr: " + noncestr);        stdout.println("本次处理完毕");



   }
   private static String randomNoncestr() {        StringBuilder sb = new StringBuilder();        for (int i = 0; i < 8; i++) {            char c = (char) (ThreadLocalRandom.current().nextInt(10) + 48);            sb.append(c);        }        return sb.toString();    }
   public static void main(String[] args) {        System.out.println(randomNoncestr());    }
}


XX客户端APP签名分析之bp插件打造篇

【火线短视频精选】



【周度激励】2021.7.26 ~ 2021.8.1公告


XX客户端APP签名分析之bp插件打造篇


【相关精选文章】


火线新手训练之如何使用火器快速查找脆弱资产

车联网安全基础知识之大众集团汽车电子电气架构


火线Zone是[火线安全平台]运营的封闭式社区,社区成员必须在[火线安全平台]提交有效漏洞才能申请免费加入,符合要求的白帽子可联系[火线小助手]加入。


我们不希望出现劣币驱逐良币的结果,我们不希望一个技术社区变成一个水区!


欢迎具备分享精神的白帽子加入火线Zone,共建一个有技术氛围的优质社区!



XX客户端APP签名分析之bp插件打造篇

XX客户端APP签名分析之bp插件打造篇



本文始发于微信公众号(火线Zone):XX客户端APP签名分析之bp插件打造篇

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: