吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2989|回复: 9
收起左侧

[CTF] *CTF2022部分RE_WP

  [复制链接]
zsky 发表于 2022-4-18 13:42
本帖最后由 zsky 于 2022-4-18 13:47 编辑

2022* CTF部分RE题目WP

Simple File System

IDA打开程序进行分析

image-20220417163232398.png

打开instruction.txt,观察运行的指令

# instructions

I implemented a very simple file system and buried my flag in it.

The image file are initiated as follows: 
./simplefs image.flag 500
 simplefs> format
 simplefs> mount
 simplefs> plantflag
 simplefs> exit

And you cold run "help" to explore other commands.

程序逻辑是创建一个磁盘,格式化并挂载,然后将flag文件的内容加密后存储进去,只需要找到对应的加密函数写解密脚本即可

IDA找到plantflag处的代码

image-20220417163339564.png

这里的sub_216A函数的功能其实就是create_inode,v21,v22是2个随机数,而sub_1e16的第二个参数是不同的,进去分析

image-20220417163631438.png

发现sub_21B2才是真正的加密函数,在此函数下断点,把程序运行参数设置为imagetest.flag 500,IDA远程动态调试,运行并执行命令

 simplefs> format
 simplefs> mount
 simplefs> plantflag

image-20220417164027740.png

调试发现V4的值一定是0xDEEDBEEF,观察imagetest.flag文件,发现从偏移0X33000开始存储,每隔0x1000存1个enc_flag,不过这些enc_flag只有1个是真正的通过sub_21b2函数进行加密的,其他的都是sub_2305中生成的随机数,所以不管它,直接把所有enc_flag执行一下解密函数就可以了。

exp为

def ROR(_num, _n):
    return (((_num >> _n) & 0XFF) | ((_num << (8 - _n)) & 0XFF)) & 0XFF
def dec(a):
    for i in range(len(a)):
        a[i] = ROR(a[i], 3)
        a[i] ^= 0xDE
        a[i] = ROR(a[i], 4)
        a[i] ^= 0xED
        a[i] = ROR(a[i], 5)
        a[i] ^= 0xBE
        a[i] = ROR(a[i], 6)
        a[i] ^= 0xEF
        a[i] = ROR(a[i], 7)
    return a

with open('./image.flag', 'rb') as f:
    data = f.read()
data_splitted = [list(data[0x33000 + i * 0x1000: 0x33000 + i * 0x1000 + 32]) for i in range(200)]

for data in data_splitted:
    dec_data = bytes(dec(data))
    if b'*CTF' in dec_data:
        print(dec_data)
        break
b'*CTF{Gwed9VQpM4Lanf0kEj1oFJR6}\n*'

NaCl

IDA打开分析,测试是最终这2段数据进行对比,如果相同的话,flag就是*CTF{input}

image-20220417200540628.png

调试起来,发现了xtea算法

image-20220417200600659.png

最终经过无尽的调试,还原了题目算法

#include <stdio.h>
#include <windows.h>

#define LeftRotate(word, bits) ( (word) << (bits) | (word) >> (32 - (bits)) )

unsigned int dword_80AFB60[44] = {
        0x04050607, 0x00010203, 0x0C0D0E0F, 0x08090A0B, 0xCD3FE81B, 0xD7C45477, 0x9F3E9236, 0x0107F187,
        0xF993CB81, 0xBF74166C, 0xDA198427, 0x1A05ABFF, 0x9307E5E4, 0xCB8B0E45, 0x306DF7F5, 0xAD300197,
        0xAA86B056, 0x449263BA, 0x3FA4401B, 0x1E41F917, 0xC6CB1E7D, 0x18EB0D7A, 0xD4EC4800, 0xB486F92B,
        0x8737F9F3, 0x765E3D25, 0xDB3D3537, 0xEE44552B, 0x11D0C94C, 0x9B605BCB, 0x903B98B3, 0x24C2EEA3,
        0x896E10A2, 0x2247F0C0, 0xB84E5CAA, 0x8D2C04F0, 0x3BC7842C, 0x1A50D606, 0x49A1917C, 0x7E1CB50C,
        0xFC27B826, 0x5FDDDFBC, 0xDE0FC404, 0xB2B30907
};

DWORD xtea_key[4] = { 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C };

//xtea算法
void encipher(unsigned int num_rounds, DWORD v[2], DWORD  key[4]) {
        unsigned int i;
        DWORD v0 = v[0], v1 = v[1], sum = 0, delta = 0x10325476;
        for (i = 0; i < num_rounds; i++) {
                v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
                sum += delta;
                v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
        }
        v[0] = v0; v[1] = v1;
}

void enc11(DWORD* v)
{
        for (int i = 0; i <= 43; i++)
        {
                DWORD tmp = v[0];
                v[0] = (LeftRotate(v[0], 1) & LeftRotate(v[0], 8)) ^ LeftRotate(v[0], 2) ^ v[1] ^ dword_80AFB60[i];
                v[1] = tmp;
        }
        DWORD tmp = v[0];
        v[0] = v[1];
        v[1] = tmp;
}

int main()
{
        // input = "12345678901234561234567890123456"
        DWORD v[] = { 0X31323334 ,0X35363738, 0x39303132, 0x33343536, 0X31323334 ,0X35363738, 0x39303132, 0x33343536};

        DWORD rounds[] = { 2, 4, 8, 16 };
        for (int i = 0; i < 8; i += 2)
        {
                enc11(&v[i]);
                encipher(rounds[i/2], &v[i], xtea_key);
        }

        return 0;
}

接下来的任务就简单了,比着写解密脚本即可

exp为:

#include <stdio.h>
#include <windows.h>

#define LeftRotate(word, bits) ( (word) << (bits) | (word) >> (32 - (bits)) )

unsigned int dword_80AFB60[44] = {
        0x04050607, 0x00010203, 0x0C0D0E0F, 0x08090A0B, 0xCD3FE81B, 0xD7C45477, 0x9F3E9236, 0x0107F187,
        0xF993CB81, 0xBF74166C, 0xDA198427, 0x1A05ABFF, 0x9307E5E4, 0xCB8B0E45, 0x306DF7F5, 0xAD300197,
        0xAA86B056, 0x449263BA, 0x3FA4401B, 0x1E41F917, 0xC6CB1E7D, 0x18EB0D7A, 0xD4EC4800, 0xB486F92B,
        0x8737F9F3, 0x765E3D25, 0xDB3D3537, 0xEE44552B, 0x11D0C94C, 0x9B605BCB, 0x903B98B3, 0x24C2EEA3,
        0x896E10A2, 0x2247F0C0, 0xB84E5CAA, 0x8D2C04F0, 0x3BC7842C, 0x1A50D606, 0x49A1917C, 0x7E1CB50C,
        0xFC27B826, 0x5FDDDFBC, 0xDE0FC404, 0xB2B30907
};

DWORD xtea_key[4] = { 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C };

void decipher(unsigned int num_rounds, DWORD v[2], DWORD key[4]) {
        unsigned int i;
        DWORD v0 = v[0], v1 = v[1], delta = 0x10325476, sum = delta * num_rounds;
        for (i = 0; i < num_rounds; i++) {
                v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
                sum -= delta;
                v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
        }
        v[0] = v0; v[1] = v1;
}

void enc11(DWORD* v)
{
        for (int i = 0; i <= 43; i++)
        {
                DWORD tmp = v[0];
                v[0] = (LeftRotate(v[0], 1) & LeftRotate(v[0], 8)) ^ LeftRotate(v[0], 2) ^ v[1] ^ dword_80AFB60[i];
                v[1] = tmp;
        }
        DWORD tmp = v[0];
        v[0] = v[1];
        v[1] = tmp;
}

void dec11(DWORD* v)
{
        DWORD tmp = v[0];
        v[0] = v[1];
        v[1] = tmp;

        //************************
        for (int i = 0; i <= 43; i++)
        {
                tmp = v[0];
                v[0] = v[1];
                v[1] = (LeftRotate(v[0], 1) & LeftRotate(v[0], 8)) ^ LeftRotate(v[0], 2) ^ tmp ^ dword_80AFB60[43-i];
        }
}

int main()
{
        DWORD enc[] = { 0xFDF5C266, 0x7A328286, 0xCE944004, 0x5DE08ADC, 0xA6E4BD0A, 0x16CAADDC, 0x13CD6F0C, 0x1A75D936 };

        //input = "1234567890abcdefghijklmn12366666"
        //DWORD enc[] = { 0x4A16D2F5, 0x3995DF74, 0xC0B2BC9A, 0x313495AC, 0x207EAA57, 0x5C46F1CB, 0x9AB2B6D3, 0xF0E536C3 };
        DWORD rounds[] = { 2, 4, 8, 16 };
        for (int i = 0; i < 8; i += 2)
        {
                decipher(rounds[i / 2], &enc[i], xtea_key);
                dec11(&enc[i]);
        }
        char* flag = (char*)enc;

        for (int i = 0; i < 32; i += 4)
        {
                printf("%c", flag[i+3]);
                printf("%c", flag[i + 2]);
                printf("%c", flag[i + 1]);
                printf("%c", flag[i]);
        }
        return 0;
}
// mM7pJIobsCTQPO6R0g-L8kFExhYuivBN

Jump

IDA打开,发现符号都被去除了,用Finger恢复一下符号 https://github.com/aliyunav/Finger ,我只能说这个工具太牛逼了

Finger分析前

image-20220417213946452.png

Finger分析后

image-20220417214325367.png

爽歪歪~~~ 开始分析

程序起名叫Jump,而在调试的过程中,发现确实是Jump,程序从一个地方调到了另一个地方,于是谷歌搜索,找到一篇文章  https://blog.csdn.net/dog250/article/details/89742140  感觉跟题目好像,就是保存线程上下文,然后恢复这个线程上下文来实现跳转

经过分析,找到了save_ctx和restore_ctx函数

image-20220417201238954.png

后面的第一个参数其实就是context, 逆向了下这个save_ctx,发现context结构大致如下

00000000 ctx struc ; (sizeof=0x60, mappedto_18)
00000000 _rbx dq ?
00000008 _enc_rbp dq ?
00000010 _r12 dq ?
00000018 _r13 dq ?
00000020 _r14 dq ?
00000028 _r15 dq ?
00000030 _enc_rsp_8 dq ?                         ; [rsp+8] enc
00000038 _enc_rsp_0 dq ?                         ; [rsp] --> rip
00000040 _rsi dq ?                               ; 当rsi为0的时候,这个位置存rsi寄存器的值
00000048 field_48 dq ?
00000050 field_50 dq ?
00000058 _rax dq ?
00000060 ctx ends

调试找到最终比较的位置

image-20220417201451026.png

密文是[0x03, 0x6A, 0x6D, 0x47, 0x6E, 0x5F, 0x3D, 0x75, 0x61, 0x53, 0x5A, 0x4C, 0x76, 0x4E, 0x34, 0x77, 0x46, 0x78, 0x45, 0x36, 0x52, 0x2B, 0x70, 0x02, 0x44, 0x32, 0x71, 0x56, 0x31, 0x43, 0x42, 0x54, 0x63, 0x6B]

sub_401F62 是关键加密函数,他把这个矩阵每一行,按第一个字符大小进行排序,然后排完序的这个矩阵的最后一列就是密文,现在知道这个矩阵的第一列和最后一列,来求flag

举个例子,假如我们输入的是985236147adgjlqwesxzcvbnmfuiopvx, 程序先将其前加上\x02尾部加上\x03

image-20220417201957613.png

然后一层层循环左移1个字符,循环33次,将循环后的二维数组保存在0000004C9408处,通过下面的IDApython打印出来

addr =[0x00000000004CC0D0, 0x00000000004CC100, 0x00000000004CC130, 0x00000000004CC160, 0x00000000004CC190, 0x00000000004CC1C0, 0x00000000004CC1F0, 0x00000000004CC220, 0x00000000004CC250, 0x00000000004CC280, 0x00000000004CC2B0, 0x00000000004CC2E0, 0x00000000004CC310, 0x00000000004CC340, 0x00000000004CC370, 0x00000000004CC3A0, 0x00000000004CC3D0, 0x00000000004CC400, 0x00000000004CC430, 0x00000000004CC460, 0x00000000004CC490, 0x00000000004CC4C0, 0x00000000004CC4F0, 0x00000000004CC520, 0x00000000004CC550, 0x00000000004CC580, 0x00000000004CC5B0, 0x00000000004CC5E0, 0x00000000004CC610, 0x00000000004CC640, 0x00000000004CC670, 0x00000000004CC6A0, 0x00000000004CC6D0, 0x00000000004CC700] # 0000004C9408处存的34个指针
for i in range(34):
    tmp = b""
    for j in range(34):
        tmp += get_bytes(addr[i]+j, 1)
    print(tmp)
b'\x02985236147adgjlqwesxzcvbnmfuiopvx\x03'
b'985236147adgjlqwesxzcvbnmfuiopvx\x03\x02'
b'85236147adgjlqwesxzcvbnmfuiopvx\x03\x029'
b'5236147adgjlqwesxzcvbnmfuiopvx\x03\x0298'
b'236147adgjlqwesxzcvbnmfuiopvx\x03\x02985'
b'36147adgjlqwesxzcvbnmfuiopvx\x03\x029852'
b'6147adgjlqwesxzcvbnmfuiopvx\x03\x0298523'
b'147adgjlqwesxzcvbnmfuiopvx\x03\x02985236'
b'47adgjlqwesxzcvbnmfuiopvx\x03\x029852361'
b'7adgjlqwesxzcvbnmfuiopvx\x03\x0298523614'
b'adgjlqwesxzcvbnmfuiopvx\x03\x02985236147'
b'dgjlqwesxzcvbnmfuiopvx\x03\x02985236147a'
b'gjlqwesxzcvbnmfuiopvx\x03\x02985236147ad'
b'jlqwesxzcvbnmfuiopvx\x03\x02985236147adg'
b'lqwesxzcvbnmfuiopvx\x03\x02985236147adgj'
b'qwesxzcvbnmfuiopvx\x03\x02985236147adgjl'
b'wesxzcvbnmfuiopvx\x03\x02985236147adgjlq'
b'esxzcvbnmfuiopvx\x03\x02985236147adgjlqw'
b'sxzcvbnmfuiopvx\x03\x02985236147adgjlqwe'
b'xzcvbnmfuiopvx\x03\x02985236147adgjlqwes'
b'zcvbnmfuiopvx\x03\x02985236147adgjlqwesx'
b'cvbnmfuiopvx\x03\x02985236147adgjlqwesxz'
b'vbnmfuiopvx\x03\x02985236147adgjlqwesxzc'
b'bnmfuiopvx\x03\x02985236147adgjlqwesxzcv'
b'nmfuiopvx\x03\x02985236147adgjlqwesxzcvb'
b'mfuiopvx\x03\x02985236147adgjlqwesxzcvbn'
b'fuiopvx\x03\x02985236147adgjlqwesxzcvbnm'
b'uiopvx\x03\x02985236147adgjlqwesxzcvbnmf'
b'iopvx\x03\x02985236147adgjlqwesxzcvbnmfu'
b'opvx\x03\x02985236147adgjlqwesxzcvbnmfui'
b'pvx\x03\x02985236147adgjlqwesxzcvbnmfuio'
b'vx\x03\x02985236147adgjlqwesxzcvbnmfuiop'
b'x\x03\x02985236147adgjlqwesxzcvbnmfuiopv'
b'\x03\x02985236147adgjlqwesxzcvbnmfuiopvx'

然后经过sub_401F62函数,再重新查看0000004C9408处的指针,发现顺序与之前不一样,重新整理IDApython脚本,再打印下

b'\x02985236147adgjlqwesxzcvbnmfuiopvx\x03'
b'\x03\x02985236147adgjlqwesxzcvbnmfuiopvx'
b'147adgjlqwesxzcvbnmfuiopvx\x03\x02985236'
b'236147adgjlqwesxzcvbnmfuiopvx\x03\x02985'
b'36147adgjlqwesxzcvbnmfuiopvx\x03\x029852'
b'47adgjlqwesxzcvbnmfuiopvx\x03\x029852361'
b'5236147adgjlqwesxzcvbnmfuiopvx\x03\x0298'
b'6147adgjlqwesxzcvbnmfuiopvx\x03\x0298523'
b'7adgjlqwesxzcvbnmfuiopvx\x03\x0298523614'
b'85236147adgjlqwesxzcvbnmfuiopvx\x03\x029'
b'985236147adgjlqwesxzcvbnmfuiopvx\x03\x02'
b'adgjlqwesxzcvbnmfuiopvx\x03\x02985236147'
b'bnmfuiopvx\x03\x02985236147adgjlqwesxzcv'
b'cvbnmfuiopvx\x03\x02985236147adgjlqwesxz'
b'dgjlqwesxzcvbnmfuiopvx\x03\x02985236147a'
b'esxzcvbnmfuiopvx\x03\x02985236147adgjlqw'
b'fuiopvx\x03\x02985236147adgjlqwesxzcvbnm'
b'gjlqwesxzcvbnmfuiopvx\x03\x02985236147ad'
b'iopvx\x03\x02985236147adgjlqwesxzcvbnmfu'
b'jlqwesxzcvbnmfuiopvx\x03\x02985236147adg'
b'lqwesxzcvbnmfuiopvx\x03\x02985236147adgj'
b'mfuiopvx\x03\x02985236147adgjlqwesxzcvbn'
b'nmfuiopvx\x03\x02985236147adgjlqwesxzcvb'
b'opvx\x03\x02985236147adgjlqwesxzcvbnmfui'
b'pvx\x03\x02985236147adgjlqwesxzcvbnmfuio'
b'qwesxzcvbnmfuiopvx\x03\x02985236147adgjl'
b'sxzcvbnmfuiopvx\x03\x02985236147adgjlqwe'
b'uiopvx\x03\x02985236147adgjlqwesxzcvbnmf'
b'vbnmfuiopvx\x03\x02985236147adgjlqwesxzc'
b'vx\x03\x02985236147adgjlqwesxzcvbnmfuiop'
b'wesxzcvbnmfuiopvx\x03\x02985236147adgjlq'
b'x\x03\x02985236147adgjlqwesxzcvbnmfuiopv'
b'xzcvbnmfuiopvx\x03\x02985236147adgjlqwes'
b'zcvbnmfuiopvx\x03\x02985236147adgjlqwesx'

每一行是按照第一个字符从小到大排序,而拍完序的最后一列,正好是000004C9420 存储的加密后的flag

现在已知密文是\x03jmGn_=uaSZLvN4wFxE6R+p\x02D2qV1CBTck,将其排序后为\x02\x03+1246=BCDEFGLNRSTVZ_acjkmnpquvwx

知道这个二位数组的第一列的每个字符和最后一列的每个字符,因为每一行的第一个字符和最后一个字符在原始字符串中肯定是挨着了,这样就可以慢慢推出原始字符串来了,写脚本解一下即可

lie1 = list(b'\x02\x03+1246=BCDEFGLNRSTVZ_acjkmnpquvwx')
lie34 = list(b'\x03jmGn_=uaSZLvN4wFxE6R+p\x02D2qV1CBTck')

flag = [2] + [0] * 33

map_ = [[lie1[i], lie34[i]] for i in range(34)]
# print(map_)

for i in range(33):
    tmp = lie34.index(flag[i])
    flag[i+1] = lie1[tmp]

print(flag)
print(bytes(flag))
# \x02cwNG1paBu=6Vn2kxSCqm+_4LETvFRZDj\x03

免费评分

参与人数 2威望 +1 吾爱币 +21 热心值 +2 收起 理由
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
muyilin + 1 + 1 受教了

查看全部评分

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

 楼主| zsky 发表于 2022-4-20 10:00
iloveasdl 发表于 2022-4-20 09:54
如何发现是XTEA算法

那个移位的特征啊,很明显的
muyilin 发表于 2022-4-18 15:33
想问一下师傅第一道 simple file system 的从偏移0X33000开始存储,师傅是怎么得到0x33000这个位置的呢?
 楼主| zsky 发表于 2022-4-18 16:04
muyilin 发表于 2022-4-18 15:33
想问一下师傅第一道 simple file system 的从偏移0X33000开始存储,师傅是怎么得到0x33000这个位置的呢?

我是自己重新模拟了一遍,然后用010editor 对比前后文件得到的
muyilin 发表于 2022-4-18 16:07
zsky 发表于 2022-4-18 16:04
我是自己重新模拟了一遍,然后用010editor 对比前后文件得到的

非常感谢
iloveasdl 发表于 2022-4-20 09:54
如何发现是XTEA算法
Jasonmusic 发表于 2022-4-20 10:20



O1dYu4n 发表于 2022-4-20 19:41
想知道为啥finger恢复符号全部失败
Y1rannn 发表于 2022-4-22 15:40
师傅, Jump那道题可以通过FLIRT直接恢复libc的符号表, longjump是libc函数
我们队两点分析出来, 推原文推到了凌晨六点, hh
 楼主| zsky 发表于 2022-4-22 16:53
Y1rannn 发表于 2022-4-22 15:40
师傅, Jump那道题可以通过FLIRT直接恢复libc的符号表, longjump是libc函数
我们队两点分析出来, 推原文推 ...

感谢,我去试试
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-24 17:26

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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