D3CTF_d3rc4

Posted by Humb1e on 2023-05-08
Estimated Reading Time 4 Minutes
Words 972 In Total
Viewed Times

D^3CTF d3rc4

不得不说每次vidar的比赛都能学到很多知识点…

先ida打开

image-20230508211439033

就是一个非常平平无奇的rc4

写一个脚本跑一下才会发现这是什么东西

看了wp才知道,原来还有这种操作

image-20230508211549513

在进入main()函数之前运行了这样一个程序

image-20230508211634262

这里分别异或了三个数组

跑过之后发现其中两个是wrong和right作为最后程序是否正确的输出(这个判断暂时还找不到)

这里估计是出题人故意不想让我们开始直接shift+f12检索字符串找到wrong和right,这样的话藏在_init_array和_fini_array里的函数很容易就会被发现

知道这一点之后就可以直接交叉引用right就能找到一个函数

image-20230508211912477

大概长这样[晕]

里面主要是两个系统调用,一个是pipe()是一个管道函数,之前的博客里刚刚讲过

另一个就是fork,刚好前几天的博客里写过采用fork()和pipe()函数实现类似于strcat操作的方法

这里其实也是类似的

这里是用pipe()和fork()实现了多进程的质数筛选

image-20230508212110870

明白了这些之后分别分析子进程和父进程就完事了

子进程:

image-20230508212204226

这里实现的就是把找到的素数写在aNHFTT…数组的后面

这里还有一个需要注意的是SHIDWORD这一个宏定义,这个在ida里定义的意思是数组的下一位

原来的宏长这样:

1
#define SHIDWORD(x)  (*((int32*)&(x)+1))

附上ida宏定义

父进程:

image-20230508212614108

父进程就是最后对input的处理和最后的比较

解决方案1:

显然可以直接dump出最后byte_4180,byte_4340的值直接z3爆破出input的值的

但是这道题的libc版本太高了,当时想动调dump根本没办法…

解决方法2:

因为题目的逻辑已经知道了,基于rc4生成加密数组的属性,我们完全可以再次模拟一下加密流程,但最终还是要采用爆破的方式得到input(因为同时处理input[i]和input[i+1])

结合wp写的一点脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned char enc[] = { 0xF7, 0x5F, 0xE7, 0xB0, 0x9A, 0xB4, 0xE0, 0xE7, 0x9E, 0x05,
0xFE, 0xD8, 0x35, 0x5C, 0x72, 0xE0, 0x86, 0xDE, 0x73, 0x9F,
0x9A, 0xF6, 0x0D, 0xDC, 0xC8, 0x4F, 0xC2, 0xA4, 0x7A, 0xB5,
0xE3, 0xCD, 0x60, 0x9D, 0x04, 0x1F };
void rc4_init_s(unsigned char* s) {
for (int i = 0; i < 256; i++) {
s[i] = i;
}
}

void rc4_shuffle(unsigned char* s, unsigned char* key, int key_len) {
int j = 0;
for (int i = 0; i < 256; i++) {
j = (j + s[i] + key[i % key_len]) % 256;
int tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
}

void rc4_gen_keystream(unsigned char* s, int len, unsigned char* key_stream) {
int i = 0, j = 0, cnt = -1;
while (len) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;
int tmp = s[i];
s[i] = s[j];
s[j] = tmp;
key_stream[++cnt] = s[(s[i] + s[j]) % 256];
len -= 1;
}
}
int main() {
unsigned char keystream1[50];
unsigned char keystream[50];
unsigned char xbox[256];
unsigned char key[] = { 0x7C, 0x4E, 0x1A, 0x48, 0x1B, 0x46, 0x18, 0x74, 0x5F, 0x1B,
0x74, 0x4F, 0x75, 0x18, 0x48, 0x5F, 0x4D };
for (int i = 0; i < 17; i++) {
key[i] ^= 43;
// printf("%c", key[i]);
}
rc4_init_s(xbox);
rc4_shuffle(xbox,key, 17);
rc4_gen_keystream(xbox, 36, keystream1);
unsigned char primes[] = { 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 };
memcpy(key + 17, primes, 10);
rc4_shuffle(xbox, key, 27);
for (int i = 0; i < 17; i++) { //这里的加密轮数没有找到素数的轮数+1,讲实话确定其他都对的话这个轮数爆破也无所谓的
rc4_gen_keystream(xbox, 36, keystream);
}
for (int i = 0; i < 36; i += 2) {
for (unsigned char a1 = 0; a1 < 0xff; a1++) {
for (unsigned char a2 = 0; a2 < 0xff; a2++) {
unsigned char a10 = a1;
unsigned char a20 = a2;
a1 = a1 ^ keystream1[i];
a2 = a2 ^ keystream1[i + 1];
a1 = (a1 + a2) ^ keystream[i];
a2 = (a1 - a2) ^ keystream[i + 1];
if (a1 == enc[i] && a2 == enc[i + 1]) {
printf("%c%c", a10, a20);
}
a1 = a10;
a2 = a20;
}
}
}
return 0;
}//getting_primes_with_pipes_is_awesome

学到很多


如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !