大家好, 我是热爱安全的老赵,喜欢琢磨,不将就,典型的理科男。 但真正全职从事安全岗位,是从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<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)查看导出结果
图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原创奖励计划,未经许可禁止转载
来源:freebuf.com 2020-02-12 08:00:42 by: xiaoguazh
请登录后发表评论
注册