2020 网鼎杯-玄武组 WriteUp
🏛️ 组织架构
支持单位:国家网络与信息安全信息通报中心、深圳市人民政府、广东省公安厅
联合主办:深信服科技股份有限公司、北京永信至诚科技股份有限公司
联合协办:阿里巴巴、百度、腾讯、奇安信、清华大学网络科学与网络空间研究院、中国科学院信息工程研究所等
Reverse
vulcrack(APK 360 加固 + GDA 脱壳)

APKID 识别出 360 加固保以及还开启了 ProGuard 混淆
1 | packer : Jiagu |

解压缩文件查看 assets/cmd.txt,内容是 hfns?qozt<ihxKrhgGkuwyY{eq=jiyLsahUhgttkSugs
将给定的字节串中的每个字节,减去其所在位置索引对 8 取模的值(即 i % 8),生成一个新的字节串,最后以 UTF‑8 编码解码并打印
1 | data = b"hfns?qozt<ihxKrhgGkuwyY{eq=jiyLsahUhgttkSugs" |
得到 help;list;getFlagFirstStep;getFlagSecondStep
这一步非常关键,它告诉你真实代码里大概率有这几个命令
1 | help |
首先,我们按下 Dump 按钮启动程序 GDA Device Dumper,然后点击 Install APK 安装 APK 文件,并按下按钮在设备上运行(需要 root 权限)。之后,右键单击 “刷新” 菜单刷新软件包列表,我们将看到 PID 为 的新软件包 5165
双击进程(软件包名称)即可查看该进程的内存空间分布

接下来,点击单选 REF 按钮显示与进程名称最相关的模块(如下图所示)。oat 文件实际上包含原始应用程序的 DEX(如果您不确定,可以导出所有模块并进行检查,有时原始 DEX 会存在于堆中,我们稍后会讨论这一点)

我们需要完整地导出模块。怎么做呢?例如,导出模块时 classes.oat module,首先用鼠标左键点击模块的第一行 classes.oat,然后拖动到模块的最后一行 classes.oat module,右键单击 Dump Module 并稍等片刻,对话框就会弹出

单击 OK 查看转储文件,如图所示

转储的文件是一个 OAT 文件,解密的 DEX 文件(实际上 DEX 头部的魔法信息被擦除了,GDA 在解析 OAT 时会自动修复它)就在这个文件中

在这里,修改文件后缀并将 .oat 其拖到 GDA 中以反编译解密的 dex 文件(如果要将其转换为 DEX,可以使用菜单工具 > oat2dex 将其转换为 dex)

经过初步检查,我们很快找到了可疑的 Flag 类,它很可能就是答案。该类中有两个关键函数:calcFlagFirstStep() 和 calcFlagSecondStep(),它们似乎通过 Flag.keyFirst 和 Flag.keySecond 来计算 flag
这两个函数(或其返回值)经过 Base64 解码后,会传递给 Flag.comm() 方法。双击 Flag.comm() 查看详情

如果您不想 try-catch 在这里观看,可以右键单击将其禁用,如图所示

此功能由 GDA 的灵活结构化算法实现。尤其是在嵌套结构较多的情况下 try-catch,我们通常不需要处理异常,因此关闭此功能 try-catch 可以大大简化代码的复杂度
这段代码更清晰。首先对两个 flag 进行 Base64 解码,然后进行解密 Flag.comm(),最后连接成我们需要的 flag

在这里,我们使用 GDA Encryption&Decryption 来解码两个标志,然后使用 GDA java plugin 来解密和连接
首先,打开该 GDA Encryption &Decryption 工具 menu>tools>ALG Tool,选择 Base64 快速解码这两个字符串


获取到的两个解码后字符串如下:
第一个解码结果:
fmcj.97;A7G462H;2F/7<I9496EH1,对应的 Base64 编码(方括号内)为:[Zm1jan85NztBN0c0NjJIOzJGLzc8STk0OTZFSDE=]第二个解码结果:
A:HI9E4I1E6<}对应的 Base64 编码为:[QTpISTlFNEkxRTY8fQ==]
下来对 Flag.comm() 的处理步骤:
将
Flag.comm()方法的实现代码直接复制到您的脚本文件中从这里下载 GDA 的 java 插件案例
建议:直接在 GDA 示例目录(example 文件夹)下创建新的 Java 文件,并注意 Java 类名必须与文件名完全相同
完成上述准备后,按照官方提供的调用方式,在脚本中调用
comm()方法即可
1 |
|

最后,点击 Menu>file>Run Java/Class 运行 .java/.class 文件,Flag 将直接打印在 GDA 上,如图所示

java(APK + Base64 + AES + XOR)

jadx 反编译,在 Congratulations 之前调用了 c() 类的 a() 方法

c 类里有两个关键静态字符串以及一个整数数组
1 | public static String a = "aes_check_key!@#"; |
反编译代码中的 android.support.v7.a.a.j.AppCompatTheme_textColorAlertDialogListItem 是 jadx 把某个整数常量显示成了 Android 支持库里的资源常量名

在这里面呢又是调用了 e.a() 方法

查看这个 e 类明显发现是 AES-ECB 加密

再去看这个 d 类,每个字节异或 22,然后每个字节再异或 c[i]

最后返回与 Base64 编码的字符串做比较
1 | return new String(b.a(bArrA)).equals(b); |

同时,APP 启动时会被 App 类修改 key,所以真正的 key 是 aos_chock_koy!@#

1 | import base64 |
得到 flag:flag{67587AAF-C20A-4B6D-991B-A40FD3C2098E}
Forensics
ransom(RDP 溯源)

搜索事件 ID 为 528 的登录成功日志,然后从前往后找 登录类型为 10 的 RDP 登录日志
1 | IP: 192.200.200.40 |
然后运行 rdp.exe 输入上面内容得到 flag:flag{c54a7cb7-80e0-48e6-8251-bdf9dd71af0a}