ISCTF2023 Reverse方向 WP

2023-12-14 14:13:41

Reverse

crackme

image-20231128235807877

加了UPX壳,可以看到EP Section处UPX标识被修改了

用WinHex修改

image-20231128235912601

之后UPX脱壳

image-20231128235954127

image-20231129000032590

得到flag。


EasyRe

image-20231129000118429

image-20231129002417390

逆向一下,先逆序,再做一些字符的替换,最后异或0x11.

for ( i = v6 - 1; i >= 0; --i )
    v4[v6 - i + 111] = v4[i + 112];

这一部分,实际上就是将数组 v4 中的元素从索引 iv6 - 1 复制到数组 v4 中的索引 v6 - i + 111v6 + 110 的位置

EXP:

enc = ']P_ISRF^PCY[I_YWERYC'
trans_table = str.maketrans('YC', 'BX')
result = enc.translate(trans_table)
re_result = result[::-1]
flag = ''.join([chr(ord(char) ^ 0x11) for char in re_result])

print(flag)
# ISCTFSNXJSIAOWCBXNAL

babyRe

image-20231209082308108

py逆向。用pyinstxtractor解包。

image-20231209082421065

之后找到babyRe.pyc和struct.pyc 拖进WinHex中比较magic number

image-20231209082519282

image-20231209082548264

相同,没有魔改。则直接对babyRe进行反编译,使用uncompyle6 或者 pyc在线反编译

image-20231209082653959

发现是个rsa加密,结合output;已知(p+1)*(q+1)和(p+q);那么根据简单的数学公式,我们可以知道phi 即 (p-1)(q-1) = (p+1)(q+1) - 2(p+q),以及n = p * q = (p+1)(q+1) - (p+q) - 1;

之后根据RSA的计算公式可以解出flag

EXP:

from Crypto.Util.number import long_to_bytes
from gmpy2 import invert

paddq=292884018782106151080211087047278002613718113661882871562870811030932129300110050822187903340426820507419488984883216665816506575312384940488196435920320779296487709207011656728480651848786849994095965852212548311864730225380390740637527033103610408592664948012814290769567441038868614508362013860087396409860
p1xq1=21292789073160227295768319780997976991300923684414991432030077313041762314144710093780468352616448047534339208324518089727210764843655182515955359309813600286949887218916518346391288151954579692912105787780604137276300957046899460796651855983154616583709095921532639371311099659697834887064510351319531902433355833604752638757132129136704458119767279776712516825379722837005380965686817229771252693736534397063201880826010273930761767650438638395019411119979149337260776965247144705915951674697425506236801595477159432369862377378306461809669885764689526096087635635247658396780671976617716801660025870405374520076160
c=5203005542361323780340103662023144468501161788183930759975924790394097999367062944602228590598053194005601497154183700604614648980958953643596732510635460233363517206803267054976506058495592964781868943617992245808463957957161100800155936109928340808755112091651619258385206684038063600864669934451439637410568700470057362554045334836098013308228518175901113235436257998397401389511926288739759268080251377782356779624616546966237213737535252748926042086203600860251557074440685879354169866206490962331203234019516485700964227924668452181975961352914304357731769081382406940750260817547299552705287482926593175925396
n = p1xq1 - paddq - 1
phi = p1xq1 - 2*paddq
e = 65537
d = invert(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))

# ISCTF{kisl-iopa-qdnc-tbfs-ualv}

easy_z3

py文件打开,发现就是一堆约束条件,用python的z3约束求解。

image-20231209162340796

根据源代码,还需要将计算出的整数转换为ascii码的形式。

EXP:

from z3 import *

s = Solver()

l = [Int(f"l_{i}") for i in range(6)]

s.add((593*l[5] + 997*l[0] + 811*l[1] + 258*l[2] + 829*l[3] + 532*l[4]) == 0x54eb02012bed42c08)
s.add((605*l[4] + 686*l[5] + 328*l[0] + 602*l[1] + 695*l[2] + 576*l[3]) == 0x4f039a9f601affc3a)
s.add((373*l[3] + 512*l[4] + 449*l[5] + 756*l[0] + 448*l[1] + 580*l[2]) == 0x442b62c4ad653e7d9)
s.add((560*l[2] + 635*l[3] + 422*l[4] + 971*l[5] + 855*l[0] + 597*l[1]) == 0x588aabb6a4cb26838)
s.add((717*l[1] + 507*l[2] + 388*l[3] + 925*l[4] + 324*l[5] + 524*l[0]) == 0x48f8e42ac70c9af91)
s.add((312*l[0] + 368*l[1] + 884*l[2] + 518*l[3] + 495*l[4] + 414*l[5]) == 0x4656c19578a6b1170)


flag = ''
if s.check() == sat:

    model = s.model()
    for i in range(6):
        hex_model = hex(model[l[i]].as_long())[2:]
        flag += "".join(chr(int(hex_model[j:j+2],16))for j in range(0,len(hex_model),2))
    print(flag)
# ISCTF{N0_One_kn0ws_m@th_B3tter_Th@n_me!!!}

FloweyRSA

image-20231209090613829

ida打开之后全是爆红,找到花指令的地方。

image-20231209090717075

jz到label1中间的内容是混淆的东西,全部nop掉,

image-20231209090759097

之后在main函数处用P 创建函数,根据提示对相应地址的内容进行修复(nop掉再C转化代码)修完之后,回到main处 P 一下,之后反编译就可以了。

image-20231209090936754

得到:

image-20231209091039222

可以知道是一个RSA加密,密文数据在c中,e为 465,n很小,可以分解得到 p 和 q。

EXP:

from Crypto.Util.number import long_to_bytes
from gmpy2 import invert

enc = [0x753C2EC5, 0x8D90C736, 0x81282CB0, 0x7EECC470, 0x944E15D3, 0x2C7AC726, 0x717E8070, 0x30CBE439, 0x0B1D95A9C,
       0x6DB667BB, 0x1240463C, 0x77CBFE64, 0x11D8BE59]
e = 0x1D1
p = 56099
q = 56369
n = p * q
phi = (p - 1) * (q - 1)
d = invert(e, phi)
flag = b''
for key in enc:
    m = pow(key, d, n)
    flag += long_to_bytes(m)
print(flag)

# b'flag{reverse_is_N0T_@lways_jusT_RE_myy_H@bIb1!!!!!!}'

easy_flower_tea

image-20231209160252169

IDA打开后无法加载,地址爆红,看汇编

image-20231209160415934

image-20231209160459378

直接NOP掉,然后P了反编译就好。

image-20231209160534610

要求我们输入number 1 和number 2,对着俩个数进行加密之后进行验证。查看一下加密函数sub_41100A

image-20231209160631080

就是一个简单的TEA加密。

EXP:


#include <stdio.h>
#include <stdint.h>  // 使用uint32_t数据类型需要包含此头文件
#include <string.h>
 #include<iostream>
 using namespace std;
// 定义加密函数
// 定义加密函数
void tea_decrypt(uint32_t *v, uint32_t *k) {
    uint32_t v0 = v[0], v1 = v[1], i;  // 根据TEA算法,解密轮次的计算需要初始化sum
    uint32_t delta = 0x61C88647;
    uint32_t sum = -(delta*32);
 
    for (i = 0; i < 32; i++) {
        v1 -= ((v0 * 16) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
        v0 -= ((v1 * 16) + k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + k[1]);
        sum += delta;
    }
 
    v[0] = v0;
    v[1] = v1;
}
 
int main() {
    uint32_t enc[2]={1115126522,2014982346};
    uint32_t key[]={12,34,56,78};
    tea_decrypt(enc,key);
    cout<<enc[0]<<endl;
    cout<<enc[1];
    return 0;
}

mfx_re

UPX魔改壳,使用WinHex将MFX都改成UPX,mfx改成upx就好了。之后用UPX脱壳

image-20231209162759835

只有处–s[i],逆向一下就是 +1

EXP:

enc = 'HRBSEz51e1a81c,78b3,34d`,84`4,6acce2c776a0|'
print("".join(chr(ord(enc[i])+1)for i in range(len(enc))))
# ISCTF{62f2b92d-89c4-45ea-95a5-7bddf3d887b1}

z3_revenge

image-20231209163202351

image-20231209163235461

一样的用python的z3约束求解。

实际上v4可以看做v0,之后SBYTE1(v4)就是v1,SBYTE2(v4) 为v2;以此类推

z3可以解出

solution_values = [
    73, 83, 67, 84, 70, 123, 53, 53, 54, 52, 48, 48, 53, 102, 45, 50, 100, 100,
    56, 45, 52, 100, 57, 53, 45, 57, 100, 50, 55, 45, 48, 100, 98, 102, 52, 48,
    48, 49, 57, 54, 49, 57, 125
]
flag = []
for i in range(len(solution_values)):
    flag.append(chr(solution_values[i]))
print(''.join(flag))
# ISCTF{5564005f-2dd8-4d95-9d27-0dbf40019619}

WHERE

image-20231214080514798

IDA打开

image-20231214082750499

程序开始23行处设置了一个异常处理函数

  • 使用了 NtCurrentTeb() 函数来获取当前线程的TEB
  • 访问 NtTib 结构,从中获取 ExceptionList 成员的值。
  • 在Windows中,ExceptionList 是 TEB 的一部分,用于指向当前线程的异常链表的头部。
  • 异常链表用于管理当前线程的异常处理信息,当线程执行发生异常时,系统会根据这个链表找到对应的异常处理程序。

之后往下看,

image-20231214083436214

GetModuleHandleA函数 获取 kernel32.dll 动态链接库中的 AddVectoredExceptionHandler 函数的地址,而AddVectoredExceptionHandler 函数用于向进程中添加一个矢量化的异常处理程序。所以这里也是关于异常处理的操作。

接着,

image-20231214083622518

又一次通过 NtCurrentTeb() 函数来获取当前线程的TEB,这一次是通过访问TEB的 ProcessEnvironmentBlock 成员,最终获取了一个叫做 BeingDebugged 的成员的值。在Windows中, BeingDebugged 是用于指示当前进程是否被调试的,如果当前值为非零,表示进程正在被调试。

image-20231214083853664

接上面,如果进程没有被调试,则这里会进入401520中,

image-20231214083954918

这里看一下,似乎都是对调试器的操作,阻止动态分析。

还有一处loc_401660,点进去看看

image-20231214084425601

发现一小段花指令,去除后发现是一个TEA加密,但是目前不清楚是哪里的。

image-20231214084511856

再次返回主函数的时候,发现不见了。不知道是什么情况了,看了wp好像是 VEH异常处理还是SEH异常处理,不太懂(待学)

image-20231214084556145

往下看。

image-20231214084111919

第一部分flag的地方,可以用z3解出来。

再往下,

image-20231214084727331

先验证了 Str 长度为32,爆红的不知道什么,好像是什么空指针异常,想起上面讲的异常处理函数,

image-20231214085941647

点进去看,

image-20231214090000890

发现是一个魔改了一点的RC4

image-20231214090023692

接着看到 sub_401660,这里不就是1我们刚刚 修复的花指令处,虽然不懂具体的过程,但是这里应该就是 TEA加密。

再看下面。

image-20231214085158466

这里拿 刚刚 TEA加密后的密文,先是异或,将得到的数据作为一个二维数组的索引,把当前位置的值设置为1,最后比较返回0。

其实到这里就分析完了。好像也不是很难,但是当初纠结了好久。

逆向一下就好了。

但是其实现在也还有点疑惑,为什么TEA加密的时候的明文和key是相同的,解密的时候密文和key也可以相同,当时就是这里纠结不出来。o(╥﹏╥)o、

具体的EXP就不再写了,分析完了。主要是这个拖了好久了,今天补一下。可以去找官方wp。有EXP。

文章来源:https://blog.csdn.net/Sciurdae/article/details/134986964
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。