inctf-noodes

Posted by marginal on 2021-08-16
Estimated Reading Time 10 Minutes
Words 1.9k In Total
Viewed Times

inctf-noodes

这个题算是诈胡出来的

参考链接:

https://linux.die.net/man/7/inotify

https://zh.wikipedia.org/wiki/Inotify

比较的地方

1
2
3
4
5
6
if ( !strcmp(
s1,
"dfxXdf5FcwL\\adsUddPedd}UdflZafn~af9TmflZcwlZafilddKYafM^dfxRmfENcwENddXmdf\\Raff\\df{xddL[adeiadJkdfW5cwiTdd7"
"Ydf^zadkKcw:jadeudfU=dfj~dd[}dfM9cwp7dfhnmfTjcwTjddyQdfftdd5UdfIxddGydfgnddjYdfqZcwqPcwfpdflLddUoaf~vddWqafZJd"
"f=Tcw{Zmf|Fcw|FddnkadUgdfj\\dfr^dd]SdfGJcwwJdfFtcwzFcwXVcwE|cwkPddWMdd]iadu:cwFRad\\IafXrafNxmfElcwElafJvafx9d"
"f4|dd8mmfH~cwH~mfT~cwT~afkFafvpdfj5dd}SafVRmfFpmfP|mfThmfNLmf5ZcwFpcwP|cw\\xcw=7cwyncwG|cwThcwNLcw\\pcwI^cw5ZcwOT") )

s1的生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
v45 = __readfsqword(0x28u);
index = 0;
s_index = 0;
sub_55D31246E16A();
sub_55D31246E1FA();
fd = inotify_init(); //初始化一个 inotify 实例
if ( fd < 0 )
perror("inotify_init");
sub_55D31246E4B7("/tmp/chall/"); //初始化文件
wd = inotify_add_watch(fd, "/tmp/chall/", 0x33Fu); // 将监视添加到初始化的 inotify 实例
pid = fork(); //新建进程
if ( !pid )
sub_55D31246E668("/tmp/chall/"); //用户输入处理,文件变动
if ( waitpid(pid, &stat_loc, 0) == -1 )
{
perror("waitpid failed\n");
goto LABEL_35;
}
v40 = BYTE1(stat_loc);
printf("%d", BYTE1(stat_loc));
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
size = read(fd, buf, 0x8000uLL);
if ( size < 0 )
perror("read");
while ( index < size )
{
byte = &buf[index];
if ( !*((_DWORD *)byte + 3) )
goto LABEL_30;
if ( (*((_DWORD *)byte + 1) & 0x100) != 0 ) // IN_CREATE
{
v3 = s_index;
if ( (*((_DWORD *)byte + 1) & 0x40000000) != 0 )// IN_ISDIR
{
++s_index;
s1[v3] = 'c';
v4 = s_index++;
s1[v4] = 'd';
}
else
{
++s_index;
s1[v3] = 'c';
v5 = s_index++;
s1[v5] = 'f';
}
LABEL_26:
v23 = byte[16] + 4;
v24 = s_index++;
s1[v24] = v23;
v25 = byte[17] + 4;
v26 = s_index++;
s1[v26] = v25;
goto LABEL_30;
}
if ( (*((_DWORD *)byte + 1) & 0x200) != 0 ) // IN_DELETE
{
v6 = s_index;
if ( (*((_DWORD *)byte + 1) & 0x40000000) != 0 )
{
++s_index;
s1[v6] = 'd';
v7 = s_index++;
s1[v7] = 'd';
}
else
{
++s_index;
s1[v6] = 'd';
v8 = s_index++;
s1[v8] = 'f';
}
goto LABEL_26;
}
if ( (*((_DWORD *)byte + 1) & 8) != 0 ) // IN_CLOSE_WRITE
{
v9 = s_index++;
s1[v9] = 'c';
v10 = s_index++;
s1[v10] = 'w';
v11 = byte[16] + 4;
v12 = s_index++;
s1[v12] = v11;
v13 = byte[17] + 4;
v14 = s_index++;
s1[v14] = v13;
goto LABEL_30;
}
if ( (*((_DWORD *)byte + 1) & 1) != 0 ) // IN_ACCESS
{
v15 = s_index++;
s1[v15] = 'a';
v16 = s_index++;
s1[v16] = 'c';
v17 = byte[16] + 4;
v18 = s_index++;
s1[v18] = v17;
v19 = byte[17] + 4;
v20 = s_index++;
s1[v20] = v19;
goto LABEL_30;
}
if ( (*((_DWORD *)byte + 1) & 4) != 0 ) // IN_ATTRIB
{
v21 = s_index;
if ( (*((_DWORD *)byte + 1) & 0x40000000) != 0 )
{
++s_index;
s1[v21] = 'a';
v22 = s_index++;
s1[v22] = 'd';
}
else
{
++s_index;
s1[v21] = 'a';
v27 = s_index++;
s1[v27] = 'f';
}
goto LABEL_26;
}
if ( (*((_DWORD *)byte + 1) & 2) != 0 ) // IN_MODIFY
{
v28 = s_index++;
s1[v28] = 'm';
v29 = s_index++;
s1[v29] = 'f';
v30 = byte[16] + 4;
v31 = s_index++;
s1[v31] = v30;
v32 = byte[17] + 4;
v33 = s_index++;
s1[v33] = v32;
}
LABEL_30:
index += *((_DWORD *)byte + 3) + 16;
}

inotify

这个感觉和git有点点像, 监控文件的变动, 变动会生成事件

1
2
3
4
5
6
7
8
struct inotify_event {
int wd; /* Watch descriptor */
uint32_t mask; /* Mask of events */
uint32_t cookie; /* Unique cookie associating related
events (for rename(2)) */
uint32_t len; /* Size of name field */
char name[]; /* Optional null-terminated name */
};

这里涉及的事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
IN_ACCESS   0x00000001  
文件被访问(读取)(*)。
IN_CLOSE_WRITE 0x00000008
为写入而打开的文件已关闭 (*)。
IN_ATTRIB 0x00000004
权限修改
IN_ISDIR 0x40000000
事件的目标是文件夹
IN_CREATE 0x00000100
有新文件产生(可能是目录)
IN_DELETE 0x00000200
有文件被删除(可能是目录)
IN_MODIFY 0x00000002
修改文件

这里4字节长度刚好对应index += *((_DWORD *)byte + 3) + 16;的加16

处理输入

1
1: stream[v3] = fopen(dest, "a+");
1
2: fclose(stream[--v9]);//生成cw
1
3: fwrite("Wrong", 1uLL, 5uLL, stream[v9 - 1]);//生成mf 
1
4: unlink(dest);//生成df
1
5: chmod(dest, 0x164u);//生成af
1
6: rmdir(dest);//生成dd
1
7: mkdir(dest, 0x1C0u);//生成cd
1
8:exit(0)

除了2,3不能有名称之外都有2字节的名称

分析比较字符串

这里的字符串没有新建操作, 前面的文件初始化已经完成了(监控开启之前)

注意:df之后不能再打开文件, 否则会出现新建操作,(这里有一处就是这样df之后才mf的, 这里应该再df之前就打开, 我把这个操作放在了最前面, mf之前和cw之前一定要打开文件指针, 打开操作只需要一次, (mf, cw相同的文件只打开一次, 每次mf都会有cw收尾), exit会关闭所有的文件指针(这里也会被记录, 后打开的先关闭)

生成输入脚本: (因为mf操作不多, 我就直接手动删除多余的新建操作, 最后再加个8)

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
#include<iostream>

using namespace std;

int main()
{
char a[437] = {
0x64, 0x66, 0x78, 0x58, 0x64, 0x66, 0x35, 0x46, 0x63, 0x77, 0x4C, 0x5C, 0x61, 0x64, 0x73, 0x55,
0x64, 0x64, 0x50, 0x65, 0x64, 0x64, 0x7D, 0x55, 0x64, 0x66, 0x6C, 0x5A, 0x61, 0x66, 0x6E, 0x7E,
0x61, 0x66, 0x39, 0x54, 0x6D, 0x66, 0x6C, 0x5A, 0x63, 0x77, 0x6C, 0x5A, 0x61, 0x66, 0x69, 0x6C,
0x64, 0x64, 0x4B, 0x59, 0x61, 0x66, 0x4D, 0x5E, 0x64, 0x66, 0x78, 0x52, 0x6D, 0x66, 0x45, 0x4E,
0x63, 0x77, 0x45, 0x4E, 0x64, 0x64, 0x58, 0x6D, 0x64, 0x66, 0x5C, 0x52, 0x61, 0x66, 0x66, 0x5C,
0x64, 0x66, 0x7B, 0x78, 0x64, 0x64, 0x4C, 0x5B, 0x61, 0x64, 0x65, 0x69, 0x61, 0x64, 0x4A, 0x6B,
0x64, 0x66, 0x57, 0x35, 0x63, 0x77, 0x69, 0x54, 0x64, 0x64, 0x37, 0x59, 0x64, 0x66, 0x5E, 0x7A,
0x61, 0x64, 0x6B, 0x4B, 0x63, 0x77, 0x3A, 0x6A, 0x61, 0x64, 0x65, 0x75, 0x64, 0x66, 0x55, 0x3D,
0x64, 0x66, 0x6A, 0x7E, 0x64, 0x64, 0x5B, 0x7D, 0x64, 0x66, 0x4D, 0x39, 0x63, 0x77, 0x70, 0x37,
0x64, 0x66, 0x68, 0x6E, 0x6D, 0x66, 0x54, 0x6A, 0x63, 0x77, 0x54, 0x6A, 0x64, 0x64, 0x79, 0x51,
0x64, 0x66, 0x66, 0x74, 0x64, 0x64, 0x35, 0x55, 0x64, 0x66, 0x49, 0x78, 0x64, 0x64, 0x47, 0x79,
0x64, 0x66, 0x67, 0x6E, 0x64, 0x64, 0x6A, 0x59, 0x64, 0x66, 0x71, 0x5A, 0x63, 0x77, 0x71, 0x50,
0x63, 0x77, 0x66, 0x70, 0x64, 0x66, 0x6C, 0x4C, 0x64, 0x64, 0x55, 0x6F, 0x61, 0x66, 0x7E, 0x76,
0x64, 0x64, 0x57, 0x71, 0x61, 0x66, 0x5A, 0x4A, 0x64, 0x66, 0x3D, 0x54, 0x63, 0x77, 0x7B, 0x5A,
0x6D, 0x66, 0x7C, 0x46, 0x63, 0x77, 0x7C, 0x46, 0x64, 0x64, 0x6E, 0x6B, 0x61, 0x64, 0x55, 0x67,
0x64, 0x66, 0x6A, 0x5C, 0x64, 0x66, 0x72, 0x5E, 0x64, 0x64, 0x5D, 0x53, 0x64, 0x66, 0x47, 0x4A,
0x63, 0x77, 0x77, 0x4A, 0x64, 0x66, 0x46, 0x74, 0x63, 0x77, 0x7A, 0x46, 0x63, 0x77, 0x58, 0x56,
0x63, 0x77, 0x45, 0x7C, 0x63, 0x77, 0x6B, 0x50, 0x64, 0x64, 0x57, 0x4D, 0x64, 0x64, 0x5D, 0x69,
0x61, 0x64, 0x75, 0x3A, 0x63, 0x77, 0x46, 0x52, 0x61, 0x64, 0x5C, 0x49, 0x61, 0x66, 0x58, 0x72,
0x61, 0x66, 0x4E, 0x78, 0x6D, 0x66, 0x45, 0x6C, 0x63, 0x77, 0x45, 0x6C, 0x61, 0x66, 0x4A, 0x76,
0x61, 0x66, 0x78, 0x39, 0x64, 0x66, 0x34, 0x7C, 0x64, 0x64, 0x38, 0x6D, 0x6D, 0x66, 0x48, 0x7E,
0x63, 0x77, 0x48, 0x7E, 0x6D, 0x66, 0x54, 0x7E, 0x63, 0x77, 0x54, 0x7E, 0x61, 0x66, 0x6B, 0x46,
0x61, 0x66, 0x76, 0x70, 0x64, 0x66, 0x6A, 0x35, 0x64, 0x64, 0x7D, 0x53, 0x61, 0x66, 0x56, 0x52,
0x6D, 0x66, 0x46, 0x70, 0x6D, 0x66, 0x50, 0x7C, 0x6D, 0x66, 0x54, 0x68, 0x6D, 0x66, 0x4E, 0x4C,
0x6D, 0x66, 0x35, 0x5A, 0x63, 0x77, 0x46, 0x70, 0x63, 0x77, 0x50, 0x7C, 0x63, 0x77, 0x5C, 0x78,
0x63, 0x77, 0x3D, 0x37, 0x63, 0x77, 0x79, 0x6E, 0x63, 0x77, 0x47, 0x7C, 0x63, 0x77, 0x54, 0x68,
0x63, 0x77, 0x4E, 0x4C, 0x63, 0x77, 0x5C, 0x70, 0x63, 0x77, 0x49, 0x5E, 0x63, 0x77, 0x35, 0x5A,
0x63, 0x77, 0x4F, 0x54, 0x00
};
for (int i = 0; i < 437; i += 4)
{
if (a[i] == 'c' && a[i + 1] == 'f')
cout << "1" << char((a[i + 2] - 4)) << char((a[i + 3] - 4));
else if (a[i] == 'c' && a[i + 1] == 'w')
cout << "1" << char((a[i + 2] - 4)) << char((a[i + 3] - 4)) << "2";
else if (a[i] == 'm' && a[i + 1] == 'f')
cout << "1" << char((a[i + 2] - 4)) << char((a[i + 3] - 4)) << "3";
else if (a[i] == 'd' && a[i + 1] == 'f')
cout << "4" << char((a[i + 2] - 4)) << char((a[i + 3] - 4));
else if (a[i] == 'a' && a[i + 1] == 'f')
cout << "5" << char((a[i + 2] - 4)) << char((a[i + 3] - 4));
else if (a[i] == 'a' && a[i + 1] == 'd')
cout << "5" << char((a[i + 2] - 4)) << char((a[i + 3] - 4));
else if (a[i] == 'd' && a[i + 1] == 'd')
cout << "6" << char((a[i + 2] - 4)) << char((a[i + 3] - 4));
else if (a[i] == 'c' && a[i + 1] == 'd')
cout << "7" << char((a[i + 2] - 4)) << char((a[i + 3] - 4));
}
system("pause");
}

得到1hV4tT41B1HX25oQ6La6yQ4hV5jz55P325eh6GU5IZ4tN1AJ326Ti4XN5bX4wt6HW5ae5Fg4S11eP263U4Zv5gG16f25aq4Q94fz6Wy4I51l324dj1Pf326uM4bp61Q4Et6Cu4cj6fU4mV1mL21bl24hH6Qk5zr6Sm5VF49P1wV21xB326jg5Qc4fX4nZ6YO4CF1sF24Bp1vB21TR21Ax21gL26SI6Ye5q61BN25XE5Tn5Jt1Ah325Fr5t540x64i1Dz321Pz325gB5rl4f16yO5RN1Bl31Lx31Pd31JH311V3221Xt219321uj21Cx2221Xl21EZ221KP28

最后输入发现有错误, 调试之后发现, 从SafVR之后开始, 这里完全倒了过来,

要求的s1:mfFpmfP|mfThmfNLmf5ZcwFpcwP|cw\xcw=7cwyncwG|cwThcwNLcw\pcwI^cw5ZcwOT

生成的s1:mf5Zcw5ZmfNLcwNLcw\xcw=7cwyncwG|mfThcwThmfP|cwP|cw\pcwI^mfFpcwFpcwOT

具体调试了函数之后(前面有一个闹钟记得patch掉), 这里mf之后并没有把字符串写入, 是在fclose文件指针之后把文件修改, 那到底怎么连续修改之后再关闭文件指针呢, 这里我试了一下exit来关闭文件指针,把输入后面改成:

1hV4tT41B1HX25oQ6La6yQ4hV5jz55P325eh6GU5IZ4tN1AJ326Ti4XN5bX4wt6HW5ae5Fg4S11eP263U4Zv5gG16f25aq4Q94fz6Wy4I51l324dj1Pf326uM4bp61Q4Et6Cu4cj6fU4mV1mL21bl24hH6Qk5zr6Sm5VF49P1wV21xB326jg5Qc4fX4nZ6YO4CF1sF24Bp1vB21TR21Ax21gL26SI6Ye5q61BN25XE5Tn5Jt1Ah325Fr5t540x64i1Dz321Pz325gB5rl4f16yO5RN(这里开始修改)

1KP11V31EZ1Xl1JH31Pd31Cx1uj1931Xt1Lx31Bl38, 成功得到flag


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