0x00 摘要:
本系列文章通過對BurpLoader的幾個版本的逆向分析,分析Burpsuite的破解原理,分析Burpsuite認證體系存在的安全漏洞。
0x01 JD-GUI的用途與缺陷:
JD-GUI是一款從JAVA字節碼中還原JAVA源代碼的免費工具,一般情況下使用這款工具做JAVA逆向就足夠了,但是由於其原理是從JAVA字節碼中按照特定結構來還原對應的JAVA源代碼,因此一旦字節碼結構被打亂(比如說使用混淆器),那么JD-GUI就會失去它的作用,如圖為使用JD-GUI打開Burpsuite時的顯示:
顯然,JD-GUI沒能還原JAVA源代碼出來,因為Burpsuite使用了混淆器打亂了字節碼結構 所以,JD-GUI適用於‘沒有使用混淆器’的JAVA字節碼,而缺陷是一旦字節碼結構被打亂,則無法發揮它的作用
0x02 字節碼分析:
Java的字節碼並不像普通的二進制代碼在計算機中直接執行,它通過JVM引擎在不同的平台和計算機中運行。
JVM是一個基於棧結構的虛擬計算機,使用的是JVM操作碼(及其助記符),在這一點上和普通二進制反匯編的過程非常相似。 對Java字節碼進行反編譯其實非常簡單,JDK內置的Javap工具即可完成這項任務。
示例:對Javar.class進行反編
注意javap的-c參數是顯示詳細代碼,否則只顯示method,而按照java的老規矩Javar不要加后綴名 同時你也可以使用eclipse的插件Bytecode Visualizer來反編譯字節碼
注意右面的流程圖,大家在上程序設計導論課時都畫過吧,現在發現它的用途了吧,一眼就看出是一個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:
成功還原了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 larry_lau@163.com", 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 larry_lau@163.com", 0); } } }
因此,BurpLoader的原理就是偽造有效的Key來通過檢測,Key的輸入是通過preference來注入的,而我猜測它為了固定Key的計算方法,通過反射把一些環境變量固定成常量了
0x04 新版本的BurpLoader分析:
以下用1.6beta版的BurpLoader進行分析: 首先用JD-GUI嘗試打開BurpLoader:
看來這個版本的BurpLoader對字節碼使用了混淆,這條路走不通了 於是直接讀字節碼吧!
大家可以看到這里的字符串都是混淆過的,每一個都jsr到151去解密
這段解密代碼特點非常明顯,一個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); } } }
其效果如截圖所示
其中前8行輸出為之前BurpLoader惡意修改的目標原值(對我的計算機而言),同一台設備運行多少遍都是不變的,后面的key由於我之前運行過BurpLoader因此是惡意修改后的值(但是由於前8行沒有修改因此不能通過Burpsuite驗證),可見BurpLoader其實是使用了同一個密鑰來注冊所有不同計算機的,只不過修改並固定了某些參與密鑰計算的環境變量而已,這大概就是Burpsuite破解的主要思路了,至於最初能用的license是怎么計算出來的,我們以后再研究
http://drops.wooyun.org/tips/2689