首页 > 其他分享 >XCTF-Final Flappy-Bird-Cheat题目复现

XCTF-Final Flappy-Bird-Cheat题目复现

时间:2023-07-11 12:22:54浏览次数:44  
标签:AES 加密 Flappy Cheat int key EVP data XCTF

引言

这是一道有关Magisk模块的题目,虽然一直在用Magisk,但是对其模块作弊机制还不是很了解,之前比赛的时候没做出来(之前没恢复OpenSSL的符号,看起来很难看放弃了),有时间翻出来再看看。难点在于这道题目是采取静态分析的手段看的,暂时没找到什么办法对模块内的so文件进行动调和Hook,之后再研究研究。

解题

  • 将APP和题目给出的zygisk模块安装后打开APP,发现左上角出现一个作弊窗口,但是需要进行校验,这里它读取/data/data/re.ctf.flappybird/file/key.txt进行校验,如果通过才会打开作弊功能。题目中给出了另一个流量包,这个流量包有一个对/auth接口的访问流量。

  • 一般情况下对模块内的so进行分析入口点在zygisk_module_entry,这里off_4B3C08指向几个地址,其中有进行包名匹配的,也有进行Hook的,重点对Hook部分进行分析。

  • Hook部分创建一个线程,内使用DobbyHook将两so中的两个方法Hook到sub_19D0D4sub_19DF40,第二个函数内部大致是一些按键或者图像相关API,而非作弊器校验,因此主要分析19D0D4位置的函数。

  • 19D0D4位置的函数则能够看到在Auth处进行了校验,此处的符号是需要自己猜测恢复的,则主要分析0x19D5C4位置的函数。

  • 分析发现逻辑大概就是打开/data/data/re.ctf.flappybird/file/key.txt读取内容并且计算sha1,拼接为token-sha1(key),附加在流量中Http头部,这里的sha1也是通过恢复符号才能分析,再后面又是很多加密操作

  • 重点是符号的恢复,否则后面很难看,这里可以提取手机中的libcrypto.so或者编译一份arm64架构的共享库,这里直接编译,因为编译出来的符号全一点

首先在github拉一份OpenSSL的源码,题目中so字符串中有指示版本为3.0.5
https://github.com/openssl/openssl
checkout出3.0.5版本
git checkout openssl-3.0.5
然后配置NDK,先从google下一份NDK,这里用的是r25c,配好环境变量
export ANDROID_NDK_ROOT=/root/android-ndk-r25c
export PATH=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin:$ANDROID_NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin:$ANDROID_NDK_ROOT/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin:$PATH
然后编译就行
./Configure android-arm64 -D__ANDROID_API__=21 shared no-tests
make -j4

  • 编译完成后得到libcrypto.so,直接拖入IDA,等IDA处理完成后关闭IDA并pack database。使用bindiff的IDA插件,导入libcrypto.so.i64进行比对,完成后再打开插件选择Import symbol and comments,然后相似度和置信度最小都设置为0.7即可。

  • 恢复后的分析会好很多,后面先是获取了DEVICE_NAME、cmdline、tcp、tcp6 等信息然后作为内容进行加密,加密完成后通过/auth接口发请求

  • 重点分析encypto,主要加密经过几个阶段

  1. rand 随机生成一个AES密钥

  2. 用AES密钥加密数据

  3. 用RSA公钥A加密AES密钥

  4. 拿到sha256(session_key_enc + data_enc)

  5. 用私钥B签名数据

先是通过v4 = time(0LL); srand(v4 & 0xFFFFFFF8);设置种子得到32字节随机数,这32个随机数是作为AES-CBC加密的密钥,

具体是因为在生成随机数后传入0019BBBC位置的函数,该函数是对传入的数据(即包括文件内容和其他信息的内容)进行AES-CBC加密,EVP_EncryptInit声明是这个__owur int EVP_EncryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,const unsigned char *key, const unsigned char *iv);第二个参数包含了一些加密算法的信息,这里的第二个参数指向一个函数sub_328478(),函数则指向一个全局变量

这里导入EVP_CIPHER结构体的部分内容,对该内存进行分析,发现算法就是AES-CBC,也即对32字节的随机数进行了AES加密

struct evp_cipher_st {
    int nid;

    int block_size;
    /* Default value for variable length ciphers */
    int key_len;
    int iv_len;

    /* Legacy structure members */
    /* Various flags */
    unsigned long flags;
    /* How the EVP_CIPHER was created. */
    int origin;
    /* init key */
    int *init;
    /* encrypt/decrypt data */
    int (*do_cipher);
    /* cleanup ctx */
    int (*cleanup);
    /* how big ctx->cipher_data needs to be */
    int ctx_size;
    /* Populate a ASN1_TYPE with parameters */
    int (*set_asn1_parameters);
    /* Get parameters from a ASN1_TYPE */
    int (*get_asn1_parameters);
    /* Miscellaneous operations */
    int (*ctrl);
    /* Application data */
    void *app_data;

    /* New structure members */
    /* Above comment to be removed when legacy has gone */
    int name_id;
    char *type_name;
    const char *description;
   
} /* EVP_CIPHER */ ;

然后使用公钥加密随机的32字节数据,然后对结果进行了拼接

然后获取sha256摘要,这里的摘要是计算sha256(公钥加密AES_KEY的密文 + AES加密主体内容的密文)

最后使用私钥进行签名,并再次进行拼接,最终的结构就是SessionKey_enc + data_enc + sign

  • 将数据发送出去后收到响应数据,对于响应数据先是用公钥验证签名,然后用AES解密数据,但是这里的AES的密钥不是之前的随机数,而是写死的一个密钥位于byte_515220
    然后就是sub_19CDA4内有一个看起来比较复杂的解密运算,所以参考https://arcovegle.github.io/2023/04/05/XCTF%20Final%20flappy-bird-cheat/给出的方案,伪造一个服务器,直接Patch模块让它自己解包。

  • 到此并未结束,因为在Get FLag按钮被触发后会开始构造flag,在内部先是拿到sha256(DEVICE_NAME)的前16 字节的 hex,然后是服务端返回内容进行解密并且反序列化后sha256的后16字节的 hex,因此需要手动解密第一部分的DEVICE_NAME,这里用官方给出的脚本

import datetime
import ctypes
import struct
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from hashlib import sha256


raw = open("./a.bin", "rb").read() # dump http stream
post_data = raw[raw.index(b"Content-Length: 5696\r\n\r\n")+len(b"Content-Length: 5696\r\n\r\n"):raw.index(b"HTTP/1.1 200 OK\r\nServer: Werkzeug")]
rsp_data = raw[raw.index(b"Connection: close\r\n\r\n") + len(b"Connection: close\r\n\r\n"):]
assert len(post_data) == 5696
assert len(rsp_data) == 672

"28 Aug 2022 18:18:54"
ts = int(datetime.datetime(2022, 8, 28, 19, 3, 14).timestamp()) & 0xFFFFFFF8
libc = ctypes.CDLL("libc.so.6")
libc.srand(ts)
session_key = bytes([libc.rand() & 0xFF for i in range(32)])
print(session_key)

aes = AES.new(session_key, mode=AES.MODE_CBC, iv=b"\x00"*16)
session_key_enc, ciphertext, signature = post_data[0:512], post_data[512:-512], post_data[-512:]
s1 = unpad(aes.decrypt(ciphertext), 16)
print(s1.split(b"======\n")[1].strip())
s1 = sha256(s1.split(b"======\n")[1].strip()).hexdigest()[0:32]
print(s1)
# 941d52d3ca23967191aee16dd541778d
  • 最终Flag就是flag{941d52d3ca23967191aee16dd541778da4f1a8ff674264e8c1e4e404afc1ccdd}

总结

总的来说这题还是很难做的。
主要问题在于单靠静态看很难看,存在大量字符串结构体和一个大的作弊结构体,还是想找个办法动调或者Hook一下。
再者就是符号恢复,不进行符号恢复看破脑袋都解不出来。
然后就是尽管恢复完符号,但是还是存在一些序列化和加密的内容,arm64架构编出来又很难看。

参考

https://arcovegle.github.io/2023/04/05/XCTF Final flappy-bird-cheat/
https://mp.weixin.qq.com/s?__biz=MzI2MDE4MzkzMQ==&mid=2247484521&idx=1&sn=8f5119a0cd930ce5355a6b0c9446e182&chksm=ea6cc67ddd1b4f6bdb0651408a5d03c539c65d84050519c9eb35308833357bb8c55e8c11cfb5#rd

标签:AES,加密,Flappy,Cheat,int,key,EVP,data,XCTF
From: https://www.cnblogs.com/LLeaves/p/17542640.html

相关文章

  • Maven cheat sheet 手抄:从入门到无语
    Mavencheatsheet手抄写给懒人看的概念生命周期由阶段构成:validate,compile,test,package,verify,install,deploy基础基础编译:mvncleanpackage环境变量:MAVEN_HOME,MAVEN_OPTS,MAVEN_ARGS配置打印激活的配置:mvnhelp:active-profiles激活Profile:-Pprofi......
  • WinDbg / SOS Cheat Sheet (zz)
    WinDbg/SOSCheatSheet//z2012-08-3013:54:57IS21344714[T12,L281,R9,V136]HerearetheWinDbg/SOScommandsItalkedaboutatCodeCampNY. ThesearethebasiccommandstogetyougoingwithWinDbg/SOS. Starting,Attaching,ExecutingandExiting St......
  • 饶派杯 XCTF 车联网挑战赛 mqttsvr 复现
    前言IDA和Ghidra对mips64架构的识别貌似不是很友好,赛场上由于反编译实在难看,所以很难静下心来去逆,于是赛后在期末考试前稍微花点时间做了一下复现。准备checksec一下,发现是mips64大端,没开CanaryRELRO,可以溢出,可以覆写got表,这里开了NX和PIE,NX对mips64这种异架构来说好像并不会......
  • git clean cheat sheet
    tags:[git,published]TL;DRgit默认只会非递归地删除当前目录下不被ignore匹配、且不在untracked目录中的untracked文件是否被ignore文件匹配的使用-x删除ignore文件[1]所在目录是否untracked如果是,需要使用-d删除default行为默认会删除当前目录下的......
  • Codeforces 1439E - Cheat and Win
    模拟赛放了道*3500,结果全场都切了,非常恐怖。首先考虑怎么样的树是合法的,打个表发现SG函数值为\(\sum_{d}2^d·(\text{深度为d的点个数}\bmod2)\),换句话说后手必胜当且仅当每种深度的点数都是偶数。于是实际上我们只用建出虚树之后树上差分一下求出每个点被覆盖的情况,进而......
  • xctf_easyphp
    easyphp类型:PHP代码审计1.审查传值2.观看分析条件从上往下看:1.if(isset($a)&&intval($a)>6000000&&strlen($a)<=3)2.if(isset($b)&&'8b184b'===substr(md5($b),-6,6))3.$c=(array)json_decode(@$_GET['c'])4.if(is_a......
  • @Getter cheated me
    下面这段代码,IDE里正常显示。不过,在build时,会报错。interfaceDoable{IntegergetCode();}@lombok.GetterclassDerivedClassimplementsDoable{intcode;}错误信息:Error:(11,5)java:DerivedClass不是抽象的,并且未覆盖Doable中的抽象方法getCode()Err......
  • 一个简单的 rust 项目 使用 bevy 引擎 复刻 Flappy Bird 小游戏
    Rust+Bevy实现的FlappyBird游戏简介一个使用bevy引擎复刻的FlappyBird经典小游戏。通过该项目我们可以学到:bevy的自定义组件,自定义插件,自定义资源,sprite的旋转,sprite的移动,spritesheet动画的定义使用,状态管理,等内容…简单介绍一下包含的内容:游戏状态管理Me......
  • 记首次用Cheat Engine修改游戏内存
    记得第一次见到ce修改器还是因为听闻ce修改器可以修改百度网盘下载速度,但是测试了一下发现确实可行(虽然不知道现在修复了没)。最近想起来得好好研究它的功能。最后我发现了了一片讲的很细的CE修改器教程入门篇,作者用ce自带的一个练习程序详细的讲解了几种修改方式。学习之后为了实......
  • 一个简单的 rust项目 flappy bird
    一个非常简单的小项目。看到了杨旭大佬的教学视频,自己跟着实现了一下,完善了一下游戏逻辑。通过空格键进行控制。游戏中可按P键暂停/恢复游戏项目结构·├──Cargo.lock├──Cargo.toml├──src/│  ├──main.rs│  ├──bird/│  │ ├──......