JAVA逆向&反混淆-追查Burpsuite的破解原理

wyzsk發表於2020-08-19
作者: lxj616 · 2014/07/30 16:19

0x00 摘要:


本系列文章透過對BurpLoader的幾個版本的逆向分析,分析Burpsuite的破解原理,分析Burpsuite認證體系存在的安全漏洞。

0x01 JD-GUI的用途與缺陷:


JD-GUI是一款從JAVA位元組碼中還原JAVA原始碼的免費工具,一般情況下使用這款工具做JAVA逆向就足夠了,但是由於其原理是從JAVA位元組碼中按照特定結構來還原對應的JAVA原始碼,因此一旦位元組碼結構被打亂(比如說使用混淆器),那麼JD-GUI就會失去它的作用,如圖為使用JD-GUI開啟Burpsuite時的顯示:

enter image description here

顯然,JD-GUI沒能還原JAVA原始碼出來,因為Burpsuite使用了混淆器打亂了位元組碼結構 所以,JD-GUI適用於‘沒有使用混淆器’的JAVA位元組碼,而缺陷是一旦位元組碼結構被打亂,則無法發揮它的作用

0x02 位元組碼分析:


Java的位元組碼並不像普通的二進位制程式碼在計算機中直接執行,它透過JVM引擎在不同的平臺和計算機中執行。

enter image description here

JVM是一個基於棧結構的虛擬計算機,使用的是JVM操作碼(及其助記符),在這一點上和普通二進位制反彙編的過程非常相似。 對Java位元組碼進行反編譯其實非常簡單,JDK內建的Javap工具即可完成這項任務。

示例:對Javar.class進行反編

enter image description here

注意javap的-c引數是顯示詳細程式碼,否則只顯示method,而按照java的老規矩Javar不要加字尾名 同時你也可以使用eclipse的外掛Bytecode Visualizer來反編譯位元組碼

enter image description here

注意右面的流程圖,大家在上程式設計導論課時都畫過吧,現在發現它的用途了吧,一眼就看出是一個if-else結構,前兩句定義i變數,然後取i=2壓棧常數1,比對i和1以後就都java.lang.system.out了,一個輸出wooyun,一個輸出lxj616。

0x03 老版本的BurpLoader分析:


隨著Burpsuite的更新,BurpLoader也在跟著進行更新,我們從老版本的BurpLoader入手,簡要分析一下之前老版本的burpsuite破解原理。 本處選用了1.5.01版本的BurpLoader進行分析 首先試著用JD-GUI載入BurpLoader:

enter image description here

成功還原了BurpLoader原始碼,只可惜由於是對burpsuite的patch,所以burpsuite的混淆在burploader裡仍然可讀性極差,不過可以推斷burploader本身沒有使用混淆工具。

public static void main(String[] args)
  {
    try
    {
      int ret = JOptionPane.showOptionDialog(null, "This program can not be used for commercial purposes!", "BurpLoader by [email protected]", 0, 2, null, new String[] { "I Accept", "I Decline" }, null);
      //顯示選擇對話方塊:這程式是出於學習目的寫的,作者郵箱larry_lau(at)163.com 
      if (ret == 0)  //選擇我同意
      {
        //以下用到的是java反射機制,不懂反射請百度
        for (int i = 0; i < clzzData.length; i++)
        {
          Class clzz = Class.forName(clzzData[i]);
          //是burpsuite的靜態類(名字被混淆過了,也沒必要列出了)
          Field field = clzz.getDeclaredField(fieldData[i]);
         //靜態類中的變數也被混淆過了,也不必列出了
          field.setAccessible(true);
        //訪問private必須先設定這個,不然會報錯

          field.set(null, strData[i]);
        //把變數設定成strData(具體那一長串到底是什麼暫不討論)
        }

        Preferences prefs = Preferences.userNodeForPackage(StartBurp.class);
        //明顯preferences是用來儲存設定資訊的
        for (int i = 0; i < keys.length; i++)
        {
          // key和val能猜出是什麼吧
          String v = prefs.get(keys[i], null);
          if (!vals[i].equals(v))
          {
            prefs.put(keys[i], vals[i]);
          }
        }
        StartBurp.main(args);
      }
    }
    catch (Exception e)
    {
      JOptionPane.showMessageDialog(null, "This program can only run with burpsuite_pro_v1.5.01.jar", "BurpLoader by [email protected]", 
        0);
    }
  }
}

因此,BurpLoader的原理就是偽造有效的Key來透過檢測,Key的輸入是透過preference來注入的,而我猜測它為了固定Key的計算方法,透過反射把一些環境變數固定成常量了

0x04 新版本的BurpLoader分析:


以下用1.6beta版的BurpLoader進行分析: 首先用JD-GUI嘗試開啟BurpLoader:

enter image description here

看來這個版本的BurpLoader對位元組碼使用了混淆,這條路走不通了 於是直接讀位元組碼吧!

enter image description here

大家可以看到這裡的字串都是混淆過的,每一個都jsr到151去解密

enter image description here

這段解密程式碼特點非常明顯,一個switch走5條路,給221傳不同的解密key,這不就是Zelix KlassMaster的演算法嗎? 簡單的異或而已,輕鬆寫出解密機:

public class Verify {
    private static String decrypt(String str) {
        char key[] = new char[] {73,25,85,1,29};
        char arr[] = str.toCharArray();
        for (int i = 0; i < arr.length; i++) {
            arr[i] ^= key[i % 5];
        }
        return new String(arr);
    }

    public static void main (String args[]) {
        System.out.println(decrypt("%x'sdgu4t3#x#`egj\"hs.7%m|/7;hp+l&/S t7tn\5v:j\'}_dx%"));
    }
}

裡面的5個金鑰就是上圖bipush的傳參,別忘了iconst_1的那個1 解密出來是:larry.lau.javax.swing.plaf.nimbus.NimbusLook:4

其實這裡解密出字串沒有什麼用處,因為我們已經拿到老版本的原始碼了,不過在別的軟體逆向分析中可能會非常有用

0x05 總結&POC


以下為我修改後的BurpLoader,其中的惡意程式碼我已經去除,並將修改前的原值輸出,大家可以在新增burpsuite jar包後編譯執行這段程式碼

package stratburp;

import burp.StartBurp; 
import java.lang.reflect.Field; 
import java.util.prefs.Preferences; 
import javax.swing.JOptionPane; 

public class startburp 
{ 

  private static final String[] clzzData = { "burp.ecc", "burp.voc", "burp.jfc",  
    "burp.gtc", "burp.zi", "burp.q4c", "burp.pid", "burp.y0b" }; 

  private static final String[] fieldData = { "b", "b", "c", "c", "c", "b", "c", "c" }; 
  private static final String errortip = "This program can only run with burpsuite_pro_v1.5.01.jar"; 
  private static final String[] keys = { "license1", "uG4NTkffOhFN/on7RT1nbw==" }; 

  public static void main(String[] args) 
  { 
    try 
    { 
        for (int i = 0; i < clzzData.length; i++) 
        { 
          Class clzz = Class.forName(clzzData[i]); 
          Field field = clzz.getDeclaredField(fieldData[i]); 
          field.setAccessible(true); 

          //field.set(null, strData[i]); 
          System.out.println(field.get(null));
        } 

        Preferences prefs = Preferences.userNodeForPackage(StartBurp.class); 
        for (int i = 0; i < keys.length; i++) 
        { 
          String v = prefs.get(keys[i], null); 
          System.out.println(prefs.get(keys[i], null));
        } 
        StartBurp.main(args); 
    } 
    catch (Exception e) 
    { 
      JOptionPane.showMessageDialog(null, "This program can only run with burpsuite_pro_v1.5.01.jar", "Notice",0); 
    } 
  } 
}

其效果如截圖所示

enter image description here

其中前8行輸出為之前BurpLoader惡意修改的目標原值(對我的計算機而言),同一臺裝置執行多少遍都是不變的,後面的key由於我之前執行過BurpLoader因此是惡意修改後的值(但是由於前8行沒有修改因此不能透過Burpsuite驗證),可見BurpLoader其實是使用了同一個金鑰來註冊所有不同計算機的,只不過修改並固定了某些參與金鑰計算的環境變數而已,這大概就是Burpsuite破解的主要思路了,至於最初能用的license是怎麼計算出來的,我們以後再研究

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章