吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4421|回复: 7
上一主题 下一主题
收起左侧

[CTF] flare-on ctf 2023 第三题mypassion分析

[复制链接]
跳转到指定楼层
楼主
失神我醉了 发表于 2024-5-2 15:43 回帖奖励
本帖最后由 失神我醉了 于 2024-5-2 22:19 编辑

前言

Flare-on每年的ctf都比较有趣,大家可以去试一下,已经办了10届比赛了,官网显示这届最难,因为庆祝比赛10周年。本文就2023的第三题mypassion学习一波逆向,很考验逆向基本功。主要防止忘了,写下来回顾一波。

题目:aHR0cHM6Ly9mbGFyZS1vbi5jb20v


分析


查壳,无壳。



strings.exe .\mypassion.exe 查看一下字符串,发现了有趣的字符串
C:\send\bitcoin\for\symbols\send\bitcoin\for\symbols\send\bitcoin\for\symbols\send\bitcoin\for\sym.pdb


挖矿的?可能根据某恶意软件修改的。运行了一下程序,后无反应,ok。


IDA分析


_start函数没有反调试,直接来到main函数,可以看到程序运行需要带参数,并且参数要满足一些条件,大致用ida看了一下程序执行流程,没有看到特别有用

的信息,不能一步登天。函数会在运行时会从数据段导shellcode执行,所以我打算动静结合,慢慢分析。首先,参数第7个字母影响VirtualAlloc,第一个字母为'0',   第2,3字母得满足x+4y == 0x127, 用py找一下, 我选择9,C

for x in range(0x20,0x7f):
        for y in range(0x20,0x7f):
                if(x+4*y==0x127):
                        print(chr(x),chr(y))




所以得到初步参数09CxxRxxxxxxxxx,   然后用windbg动态调试,windbgx.exe .\passion.exe 09CxxRxxxxxxxxx,最好不要用powershell,后面会出现奇怪的问题?导致程序运行失败。cmd没问题
然后我们在virtualAlloc下断点,程序在这儿退出了,看下原因




用err.exe查看错误值原因,查看相关文档,得到,virtualAlloc最后一个参数得是PAGE_EXECUTE_READWRITE(0x40)。即参数第7个字母得为@



修改参数为09CxxR@xxxxxxxxx,继续往下分析



因为参数13字母会改代码,所以在func1函数入口下个断点,看看这个函数输入是什么,具体代码是干什么的
在偏移1299下断点,可以看到输入参数v39的值是5个'x', 为什么5个,因为v40和v39相邻,v40赋值为'x',高位被清零(汇编代码看会更明白),如图:



然后我们可以明显看到xabort  56h这行汇编有问题,c678f456 (16进制) ,而78正好是'x'的16进制ASCII码,所以这个是受第13字母影响,我们可以猜测c6后面可能是45(试试),因为上面几行都

是,即字母'E'。所以新参数:09CxxR@xxxxxExxx。也可以用CyberChef进行调试汇编(慢慢猜。。),后面也会用到,因为好几个地方会通过参数影响shellcode。



那么这段汇编代码在干嘛呢?它好像对后续没什么影响?直接分析很痛苦,动态分析就很舒服,我们知道输入是5个'x',即参数8-12位置的值,我们直接在ret前f9下断点,看看输出,相关寄存器啥情况,可以发现rsp有东西'brUc3',正好5位,单步分析的话会发现rsp的字符是临时算出来的。猜测可能和这个字符串比较,暂时不知道有什么用,后面相邻的代码也没到它,但是我们可以把x改为这个,反正没影响。



chr((0x74^0x16)) ='b'
chr((0x65^0x17)) ='r'
chr((0x6E^0x3B)) ='U'
chr((0x74^0x17)) ='c'
chr((0x65^0x56)) ='3'


所以新参数:09CxxR@brUc3Exxx


继续往下分析,结合chatgpt和分析,将main函数中后面的函数重命名



接着进入sub_1400013E0继续分析,ida静态分析一波,可以看到,函数会通过'/'来截取参数,所以修改新参数为:09CxxR@brUc3Exxx/test1/test2/ , 大体分析一下,sub_1400013E0会从数据段写入文件从而创建文件,并且会解密数据段的数据,作为代码执行。





sub_1400013E0中间还有个有趣的部分,现在用不到,但后面有影响,即v25变量,v25 = 0x1f + day(系统今天的日期),  v25变量会和数据段进行运算(而这块正属于文件的尾部)。



继续后面,我们通过动态分析,进入sub_1400013E0动态解密的code,看看这块具体干了什么,在1892哪儿下断点,运行调试器后会发现生成了test1的文件,所以参数会影响文件名。
到达断点后,我们直接单步进入动态分析。在函数前下断点,我们只关心输入和输出




根据main函数,可以得到390是retrieve_140002F00,380是strtol_1400071A0,358是ExitProcess,以此类推,最后的3B0是sub_1400018B0函数,所以后面需要分析sub_1400018B0
动态分析后,可以调试得到这段代码在截取test2,并且test2前面得含有数字,并且该数字会转为4为基数的数字,然后与后面数字后面的字符串长度比较,比如这里我选择0x20,转为4为基数为8,所以后面需要8个字符,不然ExitProcess,so修改参数为09CxxR@brUc3Exxx/test1/20testtest/


接着分析sub_1400018B0函数,大体过一遍,该函数会读取之前创建的test1文件,并通过输入参数对该文件进行一些判断。该函数开头和retrieve_140002F00作用一样,在这里它截取第三段,修改参数09CxxR@brUc3Exxx/test1/20testtest/test3/,然后在exitprocess函数下断点,查看一下条件满足





所以第三段得改为'?pizza',加‘?’是因为v8[0]没有被比较,跟踪一下v12,v12的逻辑与之前sub_1400013E0函数中v25 变量一样,所以v8[0] =  0x1f + day(今天30)即字符'='
修改参数为09CxxR@brUc3Exxx/test1/20testtest/=pizza/



接下来我们在下一个exitprocess下断点,可以看到判断逻辑是文件头,所以我们在sub_1400013E0创建文件时忽略了一些东西,我们再去看一下哪里对文件头进行了操作。



回到sub_1400013E0,文件开头第一段进行了操作,从中提取了数字,所以第一段得包含数字,赋值给了v5,而v5会影响文件头,所以修改参数为:09CxxR@brUc3Exxx/1337test1/20testtest/=pizza/



用010editor,可以看见test1开头就是0x11333377。继续sub_1400018B0函数,调试定位下一个exitprocess前面,看看需要什么条件。





调试可以得到,比较的是文件名,需要为pr.ost,  所以修改参数为09CxxR@brUc3Exxx/1337pr.ost/20testtest/=pizza/,成功通过判断。后面函数进入sub_140002170。


sub_140002170里面的逻辑是比较难以理解的,开头的sub_140001DA0,sub_140001F80返回的都是函数指针,然后里面的逻辑也是动态生成的,不能理解。sub_140001F80还受输入参数影响,会改变代码

试试用windbg从内存打印sub_140001DA0函数指针的汇编代码,进行分析,或者动态分析函数输入输出从而了解功能。sub_140001F80后面再分析。





sub_140001DA0的f1.bin丢进ninja可以反汇编为c语言,该函数功能与retrieve_140002F00一样,用'/'截取字符串,也可以通过动态分析根据输入输出知晓功能。



shellcode2暂时理解不了,但他与shellcode3相关。但是我们可以猜想一下,输入的参数是个指针和字符串,输出是指针。那么就有这么几个情况,1.对字符串的处理,字符串对比或者添加什么的。2.看返回

值,shellcode2最后赋值给了*(a1+3C8),在后面的sub_140002910函数中,可以找到它被用做函数,所以返回的是函数指针,可以猜想shellcode2的作用可能是根据字符串查找函数地址,类似GetProcAddress

函数,shellcode2的输入指针还是shellcode3的返回值。理解shellcode2有助于理解shellcode3。先在shellcode3下断点,因为输入参数会影响shellcode3的代码,我们把汇编代码扣出来,慢慢分析。修改参数

为:09CxxR@brUc3Exxx/1337pr.ost/20testtest/=pizza/XXXXXXXXXXXXX/






将shellcode3抠出来的16进制,放到cyberchef,'X'的ASCII码是0x58,找到无效的指令,影响shellcode3代码的输入字符(第四段字符串),依次位置是“12,5,8,9,7,6”,然后仔细分析一下应该用什么代替





在上图,我们慢慢分析,首先第一个58 后面接着的是 “48 8b”,明显像mov指令,所以大概率是mov,那么什么指令后面还能接mov,而且"MOV RAX,QWORD PTR [0000000000000060]",有个60,显而易见
[Asm] 纯文本查看 复制代码
mov rax, qword ptr gs:[0x0000000000000060]
,该指令作用是通过peb获取模块地址,二进制如下:"\x65\x48\x8B\x04\x25\x60\x00\x00\x00\",其实知道了第一个
指令的值,后面就很好知道了,显然shellcode3是通过peb获取指定模块地址,然后shellcode2从指定模块中获取指定函数地址。那么哪个模块有beep函数,谷歌搜一下我们知道Kernel32.dll(分析汇编代码也可知)。所以shellcode3是为了获取Kernel32.dll模块地址。如果不熟悉,可以用搜索x64windows shellcode开发。后面的shellcode2修复也与之相关。修复后,汇编代码如下。



Source[12] = 0x65 = e
Source[5]   = 0x60 = `
Source[8]   = 0x2e = .
Source[9]   = 0x43 = C
Source[7]   = 0x52 = R
Source[6]   = 0x30 = 0
MOV RAX,QWORD PTR GS:[0000000000000060] ;PEB基址
MOV RCX,QWORD PTR [RAX+18]  ;PEB中PEB_LDR_DATA 结构

; 获取 PEB_LDR_DATA 中的 InMemoryOrderModuleList 的地址
MOV RDX,QWORD PTR [RCX+20]

;获取LDR_DATA_TABLE_ENTRY 结构
SUB RDX,0000000000000010

; 判断模块名称
MOV RAX,QWORD PTR [RDX+60]
CMP WORD PTR [RAX+10],002E   ;'.'
JNE 000000000000004E
CMP WORD PTR [RAX+0E],0032   ;'2'
JNE 000000000000004E
CMP WORD PTR [RAX+0C],0033   ;'3'
JNE 000000000000004E
CMP WORD PTR [RAX+0A],004C   ;'L'
JE 000000000000003C
JS 0000000000000041
INS BYTE PTR [RDI],DX
JNE 000000000000004E
MOVZX EAX,WORD PTR [RAX+08]   ;'E'
MOV ECX,0000FFDF
SUB AX,0045   ;0x45='E'
TEST CX,AX
JE 0000000000000060
;循环 InMemoryOrderModuleList 的地址链表
MOV RAX,QWORD PTR [RDX+10]
;获取LDR_DATA_TABLE_ENTRY 结构
SUB RDX,0000000000000010
;判断DllBase是否为空
CMP QWORD PTR [RDX+30],0000000000000000
JNE 0000000000000015
XOR EAX,EAX
RET
;返回DllBase模块基址
MOV RAX,QWORD PTR [RDX+30]
RET


修改参数为:09CxxR@brUc3Exxx/1337pr.ost/20testtest/=pizza/XXXXX`0R.CXXeXXXX/。接着我们修复shellcode2,它也被输入参数影响。一样的,导入cyberchef,慢慢分析。





shellcode2功能与GetProcAddress一样,一顿操作猛如虎后,可以得到输入参数满足以下时,shellcode2可以运行。修改参数为:09CxxR@brUc3Exxx/1337pr.ost/20testtest/=pizza/AMu$E`0R.CAZeXXXX/

Source[1]   = 0x4d = M
Source[11] = 0x5a = Z
Source[4]   = 0x45 = E
Source[2]   = 0x75 = u
Source[3]   = 0x24 = $
Source[0]   = Source [10] = 0x41 = A


1.转到PE头(偏移量0x3c)
2.转到导出表(偏移量0x88)
3.转到名称表(偏移量0x20)
4.获取函数名称
5.比较名称
6.转到序数表(偏移量0x24)
7.获取功能号码
8.转到地址表(偏移量0x1c)
9.获取功能地址

MOV QWORD PTR [RSP+08],RBX
MOV QWORD PTR [RSP+18],RDI
MOV QWORD PTR [RSP+10],RDX ;'beep'
MOV R8,RCX
TEST RCX,RCX
JE 000000000000007A
MOV EAX,00005A4D   ;'ZM'   PE头
CMP WORD PTR [RCX],AX
JNE 000000000000007A
MOVSXD RAX,DWORD PTR [RCX+3C]
CMP DWORD PTR [RAX+RCX],00004550  ;'PE' magic
JNE 000000000000007A
MOV R9D,DWORD PTR [RAX+RCX+00000088]
ADD R9,RCX
MOV R11D,DWORD PTR [R9+20]
ADD R11,RCX
XOR ECX,ECX
CMP DWORD PTR [R9+18],ECX
JBE 000000000000007A
MOV EAX,DWORD PTR [R11+RCX*4]
MOV RBX,QWORD PTR [RSP+10]
ADD RAX,R8
SUB RBX,RAX
MOV EDI,ECX
MOVZX EDX,BYTE PTR [RAX]
MOVZX R10D,BYTE PTR [RAX+RBX]
SUB EDX,R10D
JNE 000000000000006E
INC RAX
TEST R10D,R10D
JNE 0000000000000059
TEST EDX,EDX
JE 0000000000000087
INC ECX
CMP ECX,DWORD PTR [R9+18]
JB 0000000000000048
XOR EAX,EAX
MOV RBX,QWORD PTR [RSP+08]
MOV RDI,QWORD PTR [RSP+18]
RET
MOV ECX,DWORD PTR [R9+24]
ADD RCX,R8
MOVZX EDX,WORD PTR [RCX+RDI*2]
MOV ECX,DWORD PTR [R9+1C]
ADD RCX,R8
MOV EAX,DWORD PTR [RCX+RDX*4]
ADD RAX,R8
JMP 000000000000007C




又完成一个套娃,继续下一个sub_140002910。又多了一段,在memcmp下断点,看看比较的啥





输入全是'X'  ,输出全是'E',  得与RUECKWAERTSINGENIEURWESEN相等,应该存在某种对应关系,将A~F作为输入看看,修改参数为:09CxxR@brUc3Exxx/1337pr.ost/20testtest/=pizza/AMu$E`0R.CAZeXXXX/ABCDEFGHIJKLMNOPQRSTUVWXYZ/



所以ABCDEFGHIJKLMNOPQRSTUVWXYZ对应着VPWLCJSFTXKHINGUBYZDOMQERA,用py推一下,修改参数为:09CxxR@brUc3Exxx/1337pr.ost/20testtest/=pizza/AMu$E`0R.CAZeXXXX/YPXEKCZXYIGMNOXNMXPYCXGXN/

table = str.maketrans("VPWLCJSFTXKHINGUBYZDOMQERA", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
key = "RUECKWAERTSINGENIEURWESEN"
output = key.translate(table)
print(output) # YPXEKCZXYIGMNOXNMXPYCXGXN



继续程序运行到sub_140002670,又多了一段字符串。。修改参数为:09CxxR@brUc3Exxx/1337pr.ost/20testtest/=pizza/AMu$E`0R.CAZeXXXX/YPXEKCZXYIGMNOXNMXPYCXGXN/XXXXXXXXXXX/



在0x26e1 有三个比较,动态调试,看看比较了什么。





0x6335626f转为字符就是'ob5c',改一下参数,继续调试下一个比较, 0x7255 对应 'Ur',其实它比较的就是第0段未使用的5个字符'brUc3'

改参,调试下一个,只有一个33对应字符'3' , 修改参数:09CxxR@brUc3Exxx/1337pr.ost/20testtest/=pizza/AMu$E`0R.CAZeXXXX/YPXEKCZXYIGMNOXNMXPYCXGXN/ob5cUr3/



如果之前'0x1f+day' 即字符'=' 那个地方没注意,偏移0x27ff会判断失败程序退出,当然一个字符我们也可以爆破。如果第0段的'brUc3'不知道的话,就推不出ob5cUr3,那么byte_140049420就会解密错误的指令,影响后面指令的执行。运行到sub_140002670函数的最后,偏移0x290A,进入指令,看看干了啥,看到了call    qword ptr [rcx+390h],还有参数8,明显又套了一层娃,修改参数:09CxxR@brUc3E/1337pr.ost/20testtest/=pizza/AMu$E`0R.CAZe/YPXEKCZXYIGMNOXNMXPYCXGXN/ob5cUr3/XXXXXX/ ,将之前多余的X都去掉(影响程序运行)






调试一下就可以得到最后的答案了,最终参数为09CxxR@brUc3E/1337pr.ost/20testtest/=pizza/AMu$E`0R.CAZe/YPXEKCZXYIGMNOXNMXPYCXGXN/ob5cUr3/fin/





总结

该程序通过命令行参数,控制文件的生成,并对文件进行修改,还会校验文件内容,并且通过参数控制shellcode的执行。
这才第三题,对于我这种小白,不敢想象后面是啥。。。


参考链接



免费评分

参与人数 4吾爱币 +5 热心值 +4 收起 理由
笙若 + 1 + 1 谢谢@Thanks!
52bit + 1 + 1 谢谢@Thanks!
fengbolee + 2 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
Daoxin + 1 + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
csl丶龙 发表于 2024-5-2 21:44
牛逼得很
3#
Cleaf007 发表于 2024-5-4 08:42
4#
zhaijing521 发表于 2024-5-9 11:06
5#
Satifer 发表于 2024-5-10 07:57
感谢分享,收获颇丰
6#
15022387787 发表于 2024-5-14 13:42
感谢分享,研究看看
7#
wisoft 发表于 2024-5-21 23:14
这得做多久哦,太厉害了
8#
wdb364778978 发表于 2024-9-25 09:04
硬通干货,谢谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-21 19:29

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表