17

老赵说安全系列:破解CISSP-AIO7模拟Exam DB后的反思

 4 years ago
source link: https://www.freebuf.com/articles/database/223865.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

大家好, 我是热爱安全的老赵,喜欢琢磨,不将就,典型的理科男。 但真正全职从事安全岗位,是从2017年才开始的,其实是个嘎嘎新的“老new comer”。 最喜欢和大伙分享自己的学习和心得,期待和也同样热爱安全的朋友们一块交流。 这次的话题是“破解 CISSP-AIO7-模拟Exam DB后的反思”。

一,、前言

相信很多从事安全的朋友们都参加过CISSP的学习和考试, OSG和AIO是2个最重要的学习资料(当然还有CBK), 特别是AIO书后赠送的练习题光盘里,有个 “Total Tester” 软件提供了大量的模拟题供练习, 还包括对每个答案的解释… 不仅极大的丰富了我们对CISSP知识点的理解, 也提高了我们对安全体系的整体认知。 在每天手捧Kindle复习CISSP的日子里, 我一直在想,可不可以把 “Total Tester” 里面的试题导出来呢?(PDF, 或者TXT) 这样在Kindle上学习起来就方便多了。

二、 分析和破解

经过几个小时的努力,终于把全部的模拟题导出成TXT (因为是随书赠送的软件和数据, 此破解并不构成侵权)。 取得CISSP证书也有好长一段时间了,回想这段经历, 还是有值得我们反思的地方, 最大的心得就是无论做安全还是开发, 要不停的锻炼自己像黑客一样去思考,更要多动手, 多尝试。

使用的工具列表:

(1)jd-gui-1.4.0.jar – java app 反编译
(2)Jdk -java 编译
(3)7-zip

步骤1: “Total Tester” 主要界面分析:

ra6F7vJ.jpg!web

图1-启动界面-加载题库

v2iuQ3r.jpg!web

图2-题库加载完毕

nEJBRbj.jpg!web

图3-模拟题练习

yuyAvqN.jpg!web

图4-答案解析

看似简洁的界面,从黑客的角度来看, 这其实已经给我们提供了不少有价值的信息:

(1) 模拟题库的名字:CISSP7E
(2) 题库中, CISSP的8大领域的关键字:
01:Security and Risk Management
02:Asset Security
03:Security Engineering
04:Communications and Network Security
05:Identity and Access Management
06:Security Assessment and Testing
07:Security Operations
08:Software Development Security

步骤2: 分析 “Total Tester” 应用程序文件, 得出判断:

App类型 :Java 应用

数据文件 : /data/cissp7e/cissp7e_exam_1.ser

模拟题辅助参数 : /data/cissp7e/cissp7e.properties

nQb6Rfu.jpg!web

图5-文件分析

步骤3:破解的思路汇总 (打开头脑,发散思维, 罗列所有可行的破解方式方法)

编号 思路 方法 备注 1 直接从 cissp7e_exam_1.ser 导出 假设数据文件可能是sqlite DB, access DB 或者某种可以方便解析的数据文件 经分析, 发现是通过某种方式序列化的二进制文件, 自行写解析代码, 难度较大 2 利用“Total Tester”已有的lib class读取并导出 尝试利用已有的java class,去打开和读取数据文件, 再根据自己的需要开发导出的代码 移花接木, 最省力的方案 3 从App界面导出 看App界面是否有可以支持导出的菜单或功能 经分析, 此路不可行

决定首先从2号方案开始尝试.

步骤4:深入分析Java程序

(1) 常见的java app都是 jar文件, 这个App 只有totaltester.exe

01. totaltester.exe文件大小 516K, 考虑到这个App的并不复杂,猜测它可能是通过某些工具把jar文件转换成exe。

02. 复制 totaltester.exe, 并修改扩展名为totaltester.exe.zip 或者 totaltester.jar, 使用7-zip尝试打开, 果不其然:

Jf6fi27.jpg!web

图6-jar文件分析

03. 查看 \META-INF\MANIFEST.MF 文件, 得到 Main-Class

Main-Class:com。totalsem。totaltester。tt6。totaltestergui。AppMain

(2) 使用 jd-gui-1.4.0.jar 分析 Main-Class, 根据执行逻辑, 逐步分析代码

BbaQf2E.jpg!web

图7-main class 代码

Iz2aM3q.jpg!web

图8-DAOFactory 代码

由此可见, “Total Tester” 确实可以支持不同格式的数据文件,前面步骤3已经初步判定cissp7e_exam_1.ser为序列化的二进制文件, 因此重点分析SerializedFilesExamDAO。 另外,此处getDAOFactory是个 static 静态 public 方法, 这给黑客的“移花接木” 也提供了极大的便利。关键的数据加载方法定义在 SerializedFilesExamDAO 类中:

publicExamJavaBean_Abstract_v6loadExamSerializedData(String suiteAbbreviation,intexamNumber)

7zYVVzj.jpg!web

图9- SerializedFilesExamDAO 代码

通过检索 cissp7e.properties 文件, 发现参数: suiteAbbreviation和examNumber在 cissp7e.properties 中已有定义, 至此方案2已经万事俱备。

SuiteAbbreviation=cissp7e

NumberOfExams=1

总结所有类和方法的调用逻辑:

AppMain:
    ->JFrame_ApplicationMain:
        initializeUserSession()
            ->Mediator_Main:
                showWelcomeCertSelector()
                setSuitesList()
                    ->UserSession:
                        loadData()
                         ->TotalTesterDataFacade:
                             loadAllSuiteData()
                               ->SuiteDataService:
                                    loadData()
                                      ->DAOFactory:
                                         ->SerializedFilesDAOFactory:
                                             ->SerializedFilesExamDAO:

步骤5: 利用 DAOFactory, SerializedFilesExamDAO 和 ExamJavaBean_Abstract_v6开发数据导出代码:Exam2Text.java

保存在 totaltester\com\totalsem\totaltester\tt6\dataaccessobjects\目录下。

package com.totalsem.totaltester.tt6.dataaccessobjects;

import com.totalsem.totaltester.tt.datajavabeans.ExamJavaBean_Abstract_v3;
import com.totalsem.totaltester.tt.datajavabeans.ExamJavaBean_Abstract_v6;
import com.totalsem.totaltester.tt.datajavabeans.QuestionJavaBean_Abstract_v3;
import java.util.*;
import java.lang.*;
import java.io.*;

/**
Export "CISSP All-in-One Exam Guide 7th Edition" exams to text file
*/

public class Exam2Text
{
    public static String _EXAM_DATABASE = "CISSP All-in-One Exam Guide 7th Edition";

    public static Map<Integer, String> _REFERENCES  = new HashMap<Integer, String>() {{
        put(2146397198, "Chap 01: Security and Risk Management");
        put(2146397199, "Chap 02: Asset Security");
        put(2146397200, "Chap 03: Security Engineering");
        put(2146397201, "Chap 04: Communications and Network Security");
        put(2146397202, "Chap 05: Identity and Access Management");
        put(2146397203, "Chap 06: Security Assessment and Testing");
        put(2146397204, "Chap 07: Security Operations");
        put(2146397205, "Chap 08: Software Development Security");
    }};
    
    public static Map<Integer, String> _OBJECTVIES  = new HashMap<Integer, String>() {{
        put(-1899555586, "01 Security and Risk Management");
        put(-1322155798, "05 Identity and Access Management");
        put(-1084562265, "02 Asset Security");
        put(-939137757, "06 Security Assessment and Testing");
        put(531135497, "08 Software Development Security");
        put(1319549224, "07 Security Operations");
        put(1852249901, "04 Communication and Network Security");
        put(1932016476, "03 Security Engineering");
    }};

    /**
    Convert a Question Object into Text
    */
    public static String convertQuestionToText(QuestionJavaBean_Abstract_v3 q)
    {
        if (null == q)
        {
            return null;
        }
        
        StringBuffer buff = new StringBuffer();
        
        buff.append("[Question ID]: ").append(q.getQuestionID()).append("\n");
        buff.append("[Reference  ]: ").append(_REFERENCES.get(new Integer(q.getReferenceID()))).append("\n");
        buff.append("[Objective  ]: ").append(_OBJECTVIES.get(new Integer(q.getObjectiveID()))).append("\n\n");
        
        buff.append("[Question   ]: ").append(q.getQuestionText().trim()).append("\n\n");
        
        String[] choices = q.getChoicesText();
        for (int i=0; i<choices.length; i++)
        {
            buff.append("  ").append((char)(65+i)).append(". ").append(choices[i].trim()).append("\n");
        }
        
        buff.append("\n");

        boolean[] answers = q.getAnswers();
        
        buff.append("[Answer     ]: ");
        for (int i=0; i<answers.length; i++)
        {
            if (true == answers[i])
            {
                buff.append((char)(65+i)).append(" ");
            }
        }
        
        buff.append("\n\n");

        buff.append("[Explanation]: ").append(q.getExplanation().trim()).append("\n");

        return(buff.toString());
    }

    public static void main(String args[])
    {
        DAOFactory daoFactory = DAOFactory.getDAOFactory(2); //return SerializedFilesExamDAO
        ExamDAO examDAO = daoFactory.getExamDAO();

        ExamJavaBean_Abstract_v6 examJavaBean = examDAO.loadExamSerializedData("cissp7e",1);

        HashMap all_q = examJavaBean.getQuestionBeans();

        if (all_q.size()==0)
        {
            System.out.println("\nAbort! Exam Database is Empty!\n");
            System.exit(1);
        }

        String txtFile = null; 
        if (args.length > 0)
        {
            txtFile = args[0];
        }
        else
        {
            txtFile = _EXAM_DATABASE+".txt";    //default text file name
        }

        BufferedWriter writer = null;
        try
        {
            writer = new BufferedWriter(new FileWriter(txtFile));
            
            writer.write("===========================================\n");
            writer.write("= " + _EXAM_DATABASE + " =\n");
            writer.write("= " + all_q.size() + " Questions                          =\n");
            writer.write("===========================================\n");
            
            writer.write("\n\n\n");
            
            Iterator iter = all_q.entrySet().iterator();
            while (iter.hasNext())
            {
                Map.Entry entry = (Map.Entry) iter.next();
                //Integer q_Id = (Integer)entry.getKey();
                QuestionJavaBean_Abstract_v3 q = (QuestionJavaBean_Abstract_v3)entry.getValue();

                writer.write(convertQuestionToText(q));
                writer.write("\n\n");
            }
        }
        catch(Exception e)
        {
            System.out.println("\nError! Fail to read Questions!\n");
        }
        finally
        {
            try
            {
                writer.close();
            }
            catch(Exception e)
            {}
        }
    }
}

步骤6:Java编译, 执行

(1)目录结构 (拷贝 data目录, 放在 totaltester 子目录下)

./
  ├─totaltester.jar
  │
  ├─totaltester
  │  │  CISSP All-in-One Exam Guide 7th Edition.txt
  │  │  tt3.properties
  │  │  version.properties
  │  │
  │  ├─com
  │  │  ├─totalsem
  │  │      ├─totaltester
  │  │          ├─tt6
  │  │              ├─dataaccessobjects
  │  │                  ├─Exam2Text.java
  │  ├─data
  │  │  └─cissp7e
  │  │          cissp7e.properties
  │  │          cissp7e_exam_1.ser

(2)  编译 (利用原生的jar来编译导出文件的java)

> javac -cp ".\totaltester.jar" ".\totaltester\com\totalsem\totaltester\tt6\dataaccessobjects\Exam2Text.java"

(3) 执行

> java -cp ".\totaltester.jar;.\totaltester;" com.totalsem.totaltester.tt6.dataaccessobjects.Exam2Text

(4)查看导出结果

vQJjuyq.jpg!web

图10- 导出结果, 上传Kindle

三、反思和预防

作为开发者, 我们该怎样更好的保护软件中的数据不被随意读取, 导出或者其他利用? 从破解“Total Tester”这个例子里能给我们怎样的启示?

“Total Tester”存在的缺陷:

编号 缺陷 备注 1 数据文件未做特别的保护 数据文件缺乏加扰, 加密
通HEX查看器(例如HxD64)很容易分析数据内容 2 数据文件的关键参数暴露在properties文件中 容易在代码中被识别和定位
SuiteAbbreviation=cissp7e
NumberOfExams=1 3 Java代码未做特别保护 Java文件缺乏加扰
反编译后, 容易阅读和分析代码逻辑 4 关键的数据加载为静态公共方法: public static DAOFactory getDAOFactory() 极易被直接利用 5 SerializedFilesExamDAO类中除load()之外还有store()方法 为篡改数据文件提供了便利

预防措施:

编号 方案建议 备注 1 对数据文件压缩并加密 阻止对文件直接分析
增加使用HEX工具直接查看文件的难度 2 对数据文件进行伪装, 例如将扩展名改为jpg/exe/dll等等 减少黑客对数据文件的定位和识别 3 避免暴露数据文件的关键参数 避免黑客在Properties/INI/XML/JSON/YAML等文件中查找关键信息 4 Java代码编译加扰 增加反编译后阅读代码逻辑的难度 5 Jar文件签名, 增加完整性检查 避免jar被恶意篡改和执行 6 对EXE文件加壳处理, 比如压缩壳, 加密壳 阻止黑客使用7-zip/tar等工具直接查看java程序细节 7 避免对关键逻辑使用静态公共方法 降低代码/API被直接利用的可能性 8 减少不必要的数据文件API接口, 例如只读的业务, 应该避免提供修改和保存的API 减少黑客对数据文件的可操作性

小结

我们可能没办法彻底阻止软件中的数据被读取和利用, 但我们可以通过改进我们的设计和采用相关技术让”移花接木”变得更加困难。

要更好的保护我们的软件, 在设计和开发时, 就一定要像黑客一样去思考, 只有这样才能想”黑客”所想, 难”黑客”所难。

*本文原创作者:xiaoguazh,本文属于FreeBuf原创奖励计划,未经许可禁止转载


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK