不一样的 flag

这题表面上是一个输入菜单,实质上是在 5x5 地图上走迷宫。

1. 看题面

ida反编译源码:

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
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
char _11110100001010000101111_[29]; // [esp+17h] [ebp-35h] BYREF
int v4; // [esp+34h] [ebp-18h]
int n4; // [esp+38h] [ebp-14h] BYREF
int i; // [esp+3Ch] [ebp-10h]
_BYTE v7[12]; // [esp+40h] [ebp-Ch] BYREF

__main();
_11110100001010000101111_[26] = 0;
*(_WORD *)&_11110100001010000101111_[27] = 0;
v4 = 0;
strcpy(_11110100001010000101111_, "*11110100001010000101111#");
while ( 1 )
{
puts("you can choose one action to execute");
puts("1 up");
puts("2 down");
puts("3 left");
printf("4 right\n:");
scanf("%d", &n4);
if ( n4 == 2 )
{
++*(_DWORD *)&_11110100001010000101111_[25];
}
else if ( n4 > 2 )
{
if ( n4 == 3 )
{
--v4;
}
else
{
if ( n4 != 4 )
LABEL_13:
exit(1);
++v4;
}
}
else
{
if ( n4 != 1 )
goto LABEL_13;
--*(_DWORD *)&_11110100001010000101111_[25];
}
for ( i = 0; i <= 1; ++i )
{
if ( *(_DWORD *)&_11110100001010000101111_[4 * i + 25] > 4u )
exit(1);
}
if ( v7[5 * *(_DWORD *)&_11110100001010000101111_[25] - 41 + v4] == 49 )
exit(1);
if ( v7[5 * *(_DWORD *)&_11110100001010000101111_[25] - 41 + v4] == 35 )
{
puts("\nok, the order you enter is the flag!");
exit(0);
}
}
}

分析:

程序先把一段字符串写进栈上:

1
strcpy(_11110100001010000101111_, "*11110100001010000101111#");

这串长度刚好是 25,说明它不是普通字符串,更像一张 5x5 的二维地图。

转换后是:

1
2
3
4
5
*1111
01000
01010
00010
1111#

含义很直接:

  • *:起点
  • #:终点
  • 1:墙
  • 0:路

2. 代码怎么还原

菜单部分是:

1
2
3
4
1 up
2 down
3 left
4 right

所以输入数字本质上是在控制坐标移动。

把反编译代码里的变量先改名,会清楚很多:

1
2
3
int x = 0;
int y = 0;
int op;

对应逻辑可以直接还原成:

1
2
3
4
5
6
7
8
9
10
if (op == 1)
y--;
else if (op == 2)
y++;
else if (op == 3)
x--;
else if (op == 4)
x++;
else
exit(1);

然后做边界检查:

1
2
if (x > 4 || y > 4)
exit(1);

再检查当前位置是不是墙,或者是不是终点。

3. 反编译软件产生的干扰

像这种:

1
*(_DWORD *)&_11110100001010000101111_[25]

表面上像在操作字符串,实际上是在把同一块栈空间当成整数坐标用。

所以看到这种代码时,正确姿势不是逐字硬读,而是先问自己:

  • 这个值是不是用户输入控制的?
  • 它是不是在做加一减一?
  • 它最后是不是被拿去当数组下标?

一旦这三件事对上,迷宫题基本就出来了。

4. 具体解法

这张图从左上角 * 到右下角 #,可行路线是:

1
下 下 下 右 右 上 上 右 右 下 下 下

换成输入就是:

1
222441144222

题目提示里说的是:

1
ok, the order you enter is the flag!

5. 这类题怎么练

我现在看这种题,会固定做四步:

  1. 先看字符串长度,判断是不是地图、表、编码串。
  2. scanf 后面的分支改成“人话”。
  3. 找坐标、下标、墙、终点这四个关键词。
  4. 直接把代码重写成自己能看懂的小伪代码。

6. flag

最终路径:222441144222

flag:flag{222441144222}

宇宙级免责声明
重要声明:本文仅供合法授权下的安全研究与教育目的!
  1. 合法授权:本文所述技术仅适用于已获得明确书面授权的目标或自己的靶场内系统。未经授权的渗透测试、漏洞扫描或暴力破解行为均属违法,可能导致法律后果(包括但不限于刑事指控、民事诉讼及巨额赔偿)。
  2. 道德约束:黑客精神的核心是建设而非破坏。请确保你的行为符合道德规范,仅用于提升系统安全性,而非恶意入侵、数据窃取或服务干扰。
  3. 风险自担:使用本文所述工具和技术时,你需自行承担所有风险。作者及发布平台不对任何滥用、误用或由此引发的法律问题负责。
  4. 合规性:确保你的测试符合当地及国际法律法规(如《计算机欺诈与滥用法案》(CFAA)、《通用数据保护条例》(GDPR)等)。必要时,咨询法律顾问。
  5. 最小影响原则:测试过程中应避免对目标系统造成破坏或服务中断。建议在非生产环境或沙箱环境中进行演练。
  6. 数据保护:不得访问、存储或泄露任何未授权的用户数据。如意外获取敏感信息,应立即报告相关方并删除。
  7. 免责范围:作者、平台及关联方明确拒绝承担因读者行为导致的任何直接、间接、附带或惩罚性损害责任。
安全研究的正确姿势:
  • 先授权,再测试
  • 只针对自己拥有或有权测试的系统
  • 发现漏洞后,及时报告并协助修复
  • 尊重隐私,不越界
警告:技术无善恶,人心有黑白。请明智选择你的道路。
声明参考链接:https://blog.csdn.net/2402_84408069/article/details/157263936