老赵说安全系列:破解CISSP-AIO7模拟Exam DB后的反思
大家好, 我是热爱安全的老赵,喜欢琢磨,不将就,典型的理科男。 但真正全职从事安全岗位,是从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” 主要界面分析:
图1-启动界面-加载题库
图2-题库加载完毕
图3-模拟题练习
图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
图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尝试打开, 果不其然:
图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, 根据执行逻辑, 逐步分析代码
图7-main class 代码
图8-DAOFactory 代码
由此可见, “Total Tester” 确实可以支持不同格式的数据文件,前面步骤3已经初步判定cissp7e_exam_1.ser为序列化的二进制文件, 因此重点分析SerializedFilesExamDAO。 另外,此处getDAOFactory是个 static 静态 public 方法, 这给黑客的“移花接木” 也提供了极大的便利。关键的数据加载方法定义在 SerializedFilesExamDAO 类中:
publicExamJavaBean_Abstract_v6loadExamSerializedData(String suiteAbbreviation,intexamNumber)
图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 _REFERENCES = new HashMap() {{ 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 _OBJECTVIES = new HashMap() {{ 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 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)查看导出结果
图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原创奖励计划,未经许可禁止转载