前言

GKCTF 2021所以题目均以开源,下面所说的一切思路可以自行通过源码对比IDA进行验证。

Github项目地址:https://github.com/w4nd3r-0/GKCTF2021

出题及解题思路

QQQQT

Enigma Virtual Box打包的QT程序,可以解包其实也可以不解包,因为这里并没有对字符串做隐藏,按钮事件函数可以很块通过flag字符串定位,按根据钮事件的逻辑也十分好猜,base系列加密特征明显,对base系列算法稍有了解的即可识别。若还是无法识别,建议查看一些base系列算法C实现,自行积累一些识别特征的方法。

最终是用了一个base58进行加密,加密字符串也是写脸上,可以直接百度或谷歌在线网站解密即可。

flag: flag{12t4tww3r5e77}

PS:学弟出的这个题目没有对字符串做隐藏,使得选手不用了解QT任何机制就能解出来。

Crash

可根据字符串信息也可根据段gopclntab判别是golang elf程序。符号表可以在IDA7.5中通过IDAGolanHelper(该插件近一个月有更新,可以支持高版本go符号还原)还原符号。

有了符号信息后静态审代码就非常清晰明了,用了3DES CBC, SHA256, SHA512, MD5,对四部分数据进行验证,而对应的密文也都可以简单的提取出来。

3DES CBC的密钥为一个txt文件,利用golang新版特性附加到来了二进制文件中,可以方便的找到,因此直接解密即可。

hash系列函数都是4字节爆破,用python的itertools可以快速爆破。

from Crypto.Cipher import DES3
import base64
import itertools
import string
import hashlib def des3_cbc_decrypt(secret_key, secret_value, iv):
unpad = lambda s: s[0:-ord(s[-1])]
res = DES3.new(secret_key.encode("utf-8"), DES3.MODE_CBC, iv)
base64_decrypted = base64.b64decode(secret_value.encode("utf-8"))
encrypt_text = res.decrypt(base64_decrypted)
result = unpad(encrypt_text.decode())
return result def sha256crash(sha256enc):
code = ''
strlist = itertools.product(string.ascii_letters + string.digits, repeat=4) for i in strlist:
code = i[0] + i[1] + i[2] + i[3]
encinfo = hashlib.sha256(code.encode()).hexdigest()
if encinfo == sha256enc:
return code
break def sha512crash(sha256enc):
code = ''
strlist = itertools.product(string.ascii_letters + string.digits, repeat=4) for i in strlist:
code = i[0] + i[1] + i[2] + i[3]
encinfo = hashlib.sha512(code.encode()).hexdigest()
if encinfo == sha256enc:
return code
break def md5crash(sha256enc):
code = ''
strlist = itertools.product(string.ascii_letters + string.digits, repeat=4) for i in strlist:
code = i[0] + i[1] + i[2] + i[3]
encinfo = hashlib.md5(code.encode()).hexdigest()
if encinfo == sha256enc:
return code
break if __name__ == '__main__':
key = "WelcomeToTheGKCTF2021XXX"
iv = b"1Ssecret"
cipher = "o/aWPjNNxMPZDnJlNp0zK5+NLPC4Tv6kqdJqjkL0XkA=" part1 = des3_cbc_decrypt(key,cipher,iv)
part2 = sha256crash("6e2b55c78937d63490b4b26ab3ac3cb54df4c5ca7d60012c13d2d1234a732b74")
part3 = sha512crash("6500fe72abcab63d87f213d2218b0ee086a1828188439ca485a1a40968fd272865d5ca4d5ef5a651270a52ff952d955c9b757caae1ecce804582ae78f87fa3c9")
part4 = md5crash("ff6e2fd78aca4736037258f0ede4ecf0") flag = "GKCTF{" + part1 + part2 + part3 + part4 + "}"
# GKCTF{87f645e9-b628-412f-9d7a-e402f20af940}
print (flag)

app-debug

这个题目比赛过程中出来一些情况,这里对造成不便的师傅说一声道歉。

安卓逆向题目,主要验证逻辑在native层,因此直接进入native层即可。对输入进行tea加密验证,delta是0x458BCD42,并且有利用TracerPid的反调试,当发现调试器时,会使用假的key,只要没有检测到调试器才会使用真key。

因为key是一个全局变量可以通过引用找到在哪里替换为了真key,再找到比对的密文后即可进行解密函数的编写。

#include <stdio.h>
#include <stdint.h> void TeaDecode(uint32_t* v, uint32_t* k) {
uint32_t delta=0x458BCD42;
uint32_t v0=v[0], v1=v[1], sum=delta*32, i; uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];
for (i=0; i<32; i++) {
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
}
v[0]=v0; v[1]=v1;
} int main()
{
uint32_t enc[]={4121530355,2719511459, 0};
uint32_t key[] = {9, 7, 8, 6}; TeaDecode(enc, key);
puts(enc); //GKcTFg0 return 0;
}

KillerAid

程序结构分为两部分,一个C# 前端GUI,用于获取ID和Code,并将ID用Code进行循环异或处理,最后比对ID。需要获得ID的前提必须有正确的Code,因此必须先解出Code。

Code的验证逻辑在一个用C++编写的KillerAid.Core.dll中。Core.dll中主要由两部分组成,一部分是用于反调试的检测代码,一部分是基于AES-CBC的一个简单对称加密体系算法。

反调试检测代码主要有三部分,一部分是利用WIN32 API以及一些Windows下比较常规的反调试技巧;另一部分是通过便于隐藏特征的动态CRC32算法对ntdll、Core.dll、exe的代码段进行冗余码校验;最后一部分是,基于xd4d大佬一篇解析Net内核调试机制的C++代码实现方案,用于切断.net 内核调试线程(即杀死调试线程实例)与dnSpy和IDA这类托管调试器的通信。

调试启动的手段通过C++ 语言机制,用于一个全局委托类进行构造,它会在dll被加载时,十分早的调用委托类的构造函数,而所以反调试手段都是通过调用win32 API创建一个反调试线程进行检测。

这期为了实现这些功能所调用的所有Win 32 api以及一些native api都是定义成为函数指针集成到一个代理类中,调用进行动态函数地址获取,可以比较有效隐藏win32 api的调用以及一部分抗静态分析的效果。

由于反调试比较多,虽然可找到一个反调试的主调用函数,进行文件patch但最简单的方法仍然是将反调试线程挂起。但没有做好的一点是动态crc32的调用时机相对于exe的运行时机来说还是太滞后了,后面想考虑加一个隐蔽的使用文件CRC32进行检测,但由于时间原因并没有加上。

至于加密函数的设计,是一个基于AES-CBC模式设计的简单对称加密体系,具体设计如下图所示:



具体的解密部分并没有写多少,但可以参照AES的解密思路,一个道理,这里不多做赘述。

AES算法的初始key和iv向量都是定义为全局变量,并使用rand函数动态获取。由于iv向量是定位全局变量,dll一加载即有数据了,所以这里即便没过反调试,也可通过实际加载的ImageBase计算偏移获得key和iv向量的地址(PE的知识),提取数据即可。

至于解密函数,可在源码中dllmain.cpp中找到,当然这里也贴出来了。

#ifdef _DEBUG
uint8_t* AES_DecryptPro(uint8_t* encData, size_t sizeofData, uint8_t* key, uint8_t* iv, uint32_t rounds)
{
uint8_t* Ivs = nullptr;
uint8_t* Keys = nullptr; struct AES_ctx ctx; Ivs = new uint8_t[rounds * AES_BLOCKLEN]();
Keys = new uint8_t[rounds * AES_BLOCKLEN](); // 迭代出所有 k 与 iv
for (size_t i = 0; i < rounds; i++)
{
memcpy(Ivs + i * AES_BLOCKLEN, iv, AES_BLOCKLEN);
memcpy(Keys + i * AES_BLOCKLEN, key, AES_BLOCKLEN); // 对 iv 进行 sbox 替代 后 k 用 iv 异或更新
SubBytes((state_t*)iv);
XorWithIv(key, iv);
// 对 k 进行 sbox 替代 后 iv 用 k 异或更新
SubBytes((state_t*)key);
XorWithKey(iv, key);
} // 解密流
for (size_t i = 1; i <= rounds; i++)
{
key = (uint8_t*)(Keys + (rounds - i) * AES_BLOCKLEN);
iv = (uint8_t*)(Ivs + (rounds - i) * AES_BLOCKLEN);
AES_init_ctx_iv(&ctx, key, iv);
AES_CBC_decrypt_buffer(&ctx, encData, sizeofData);
}
delete[] Ivs;
delete[] Keys; return encData;
}
#define DecryptPro(encData, sizeofData, key, iv, rounds) AES_DecryptPro(encData, sizeofData, key, iv, rounds)
#else
#define DecryptPro(encData, sizeofData, key, iv, rounds)
#endif // _DEBUG

SoMuchCode

这个题目的混淆思路十分简单,,即再真实逻辑中插入大量的有引用的垃圾代码,用来将真实的逻辑变得更加复杂难看,其实从CFG图中可以看出,并没有任何复杂分支,基本是一条流程走到底,而具体垃圾代码的插入的实现思路是使用编译器预处理的宏展开机制进行的。

程序的原始逻辑十分简单,获取输入,进行xxtea加密,与密文比较。

本题希望选手能够在大量的垃圾逻辑中抓住关键部分进行逆向,因此xxtea加密函数中进行一部分混淆,但关键特征并没有进行混淆,只要通过长长的程序流程追踪到了加密函数,即可识别出是xxtea加密,后续解题思路也会明了起来。

具体解密函数可参考源码给出的实现。

GKCTF 2021 Reverse Writeup的更多相关文章

  1. BUGKU-逆向(reverse)-writeup

    目录 入门逆向 Easy_vb Easy_Re 游戏过关 Timer(阿里CTF) 逆向入门 love LoopAndLoop(阿里CTF) easy-100(LCTF) SafeBox(NJCTF) ...

  2. BUU [GKCTF 2021]签到

    BUU [GKCTF 2021]签到 1.题目概述 2.解题过程 追踪HTTP流 在下面发现了一串可疑字符 Base16转base64 放到010里看看 复制下来,去转字符 好像不是,再回去找找其他的 ...

  3. NEEPU-CTF 2021公开赛 writeup

    没打这场比赛,但是题目质量挺高的.赛后赶紧学习一波. RUSH B Linux入门 考linux指令的. cat hint.txt 提示让访问根目录. ls / 发现flag cat flag 提示说 ...

  4. 2021 羊城杯WriteUP

    比赛感受 题目质量挺不错的,不知道题目会不会上buu有机会复现一下,躺了个三等奖,发下队伍的wp Team BinX from GZHU web Checkin_Go 源码下载下来发现是go语言写的 ...

  5. (未完成)catalyst-system WriteUp(2019暑假CTF第一周reverse)

    目录 预备学习--Linux实践:ELF文件格式分析 一.概述 二.分析ELF文件头(ELF header) 三.通过文件头找到section header table,理解其内容 四.通过secti ...

  6. ISCC2018 Reverse & Pwn writeup

    Reference:L1B0 Re RSA256 春秋欢乐赛原题..flag都不变的 给了三个加密文件和公钥证书public.key,可以使用openssl进行处理 $openssl rsa -pub ...

  7. 2021广东省强网杯WriteUp

    个人赛 网络诈骗 参考 https://github.com/Heyxk/notes/issues/1 先把EnMicroMsg.db提出来 CompatibleInfo.cfg是0kb,用第一种方法 ...

  8. 2021 数字四川创新大赛WriteUp

    数字四川初赛+复赛wp Web easyphp http://111.9.220.114:50006/.index.php.swp 备份文件泄漏 <?php #error_reporting(0 ...

  9. 虎符2021线下赛pwn writeup

    jdt 一个图书管理系统,但并不是常规的堆题.edit和show函数可以越界.edit函数和show函数相互配合泄露libc基地址,将main函数的返回地址覆盖成onegadgets拿shell. f ...

随机推荐

  1. 【java虚拟机】分代垃圾回收策略的基础概念

    作者:平凡希 原文地址:https://www.cnblogs.com/xiaoxi/p/6602166.html 一.为什么要分代 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一 ...

  2. jQuery中的效果(九):hide()、show()、slideUp()、slideDown()、slideToggle()、fadeOut()、fadeIn()、fadeTo()、animate等

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...

  3. 初识apache DBCP连接池

    连接案例: 首先:我们使用的是mysql数据库,所以要有一个mysql和java的JDBCjar包: 然后是DBCP中的两个jar包,DBCP使用的话,需要两个包: dbcp.jar和pool.jar ...

  4. Git配置多账户

    一般情况下,公司代码company_repos/会存放在公司内部的gitlab上,个人代码privacy_repos/会放在github上.因此我们会有两个git账户:公司账号zioyi@campan ...

  5. CNN的Pytorch实现(LeNet)

    CNN的Pytorch实现(LeNet)   上次写了一篇CNN的详解,可是累坏了老僧我.写完后拿给朋友看,朋友说你这Pytorch的实现方式对于新人来讲会很不友好,然后反问我说里面所有的细节你都明白 ...

  6. git推送文件到gitee

    注册gitee账号 设置姓名.个人空间地址 点击头像旁边的加号,新建仓库 安装git # 设置姓名和邮箱,姓名是注册gitee时设置的姓名,邮箱是注册gitee的邮箱 git config --glo ...

  7. JS_DOM操作之常用事件

    1 - onload 事件:加载完成后立即执行 <!DOCTYPE html> <html lang="en"> <head> <meta ...

  8. C# 爬虫框架实现 流程_爬虫结构/原理

    目录链接:C# 爬虫框架实现 概述 首先需要讲的是,爬虫的原理.其实在我看来,爬虫只是用来解决以下四个问题的工具: 提取哪些网页 提取网页上的哪些内容 存储到哪里(推荐数据库/开源类/Console) ...

  9. 细谈布隆过滤器及Redis实现

    ​ 何为布隆过滤器? 本质上是一种数据结构,是1970年由布隆提出的.它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希函数).可以用于检索一个元素是否在一个集合中. 数据结构: 布隆过 ...

  10. C语言学习笔记---2.C语言数据类型

    1.C语言基本数据类型 1.1 int类型 int类型是有符号整型,即int类型的值必须是整数,可以是正整数.负整数或零.其取值范围依计算机系统而异.一般而言,储存一个int要占用一个机器字长. 声明 ...