首页
社区
课程
招聘
[原创]第七题 密室逃脱 WriteUp
2018-6-29 12:06 3348

[原创]第七题 密室逃脱 WriteUp

2018-6-29 12:06
3348

注意:此方法很暴力!

这道题,逆向起来逻辑其实很简单,但是,难算……回去要好好学一学算法了……

逆向

程序的逻辑非常简单,程序将输入映射为0-63的数字,按确定的次序去查一个646464的三维数组,类似于M[a0][a1][a2] = b1这样的规律,顺序可以经过动态调试提取出来:

pos = [[0, 1, 2], [3, 4, 0], [5, 6, 0], [5, 7, 1], [4, 6, 1], [8, 2, 3], [9, 2, 4], [7, 10, 3], [8, 0xC, 5], [0xB, 0xD, 6], [0xC, 0xD, 7], [0xB, 0xE, 9], [0xE, 0x8, 0xA], [0xF, 0x9, 0xA], [0xF, 0xB, 0xC], [0xF, 0xD, 0xE]]

查完一轮以后,将这次的结果作为下一轮的输入,这样重复查20轮,最后和一个固定数组进行比较。

计算

三维的表反查是比较困难的,因为每一个数字都出现了64*64次,而且输入中的一字节会和输出的三字节有关,同理输出相对输入也是一样。我首先的想法是暴力搜索,但是64^16的复杂度有点太高了。然后尝试数学拟合那个表的函数,搞了七八个小时都没搞出来……还是尝试搜索,发现可以剪枝,先找每一位出现的最后位置,再生成一个数组,表示确定这一位的搜索范围最多到多少,然后……暴力DFS……

脚本

s = [......]  # 64*64*64的表格

pos = [[0, 1, 2], [3, 4, 0], [5, 6, 0], [5, 7, 1], [4, 6, 1], [8, 2, 3], [9, 2, 4], [7, 10, 3], [8, 0xC, 5], [0xB, 0xD, 6], [0xC, 0xD, 7], [0xB, 0xE, 9], [0xE, 0x8, 0xA], [0xF, 0x9, 0xA], [0xF, 0xB, 0xC], [0xF, 0xD, 0xE]]


correct = [
  0x14, 0x22, 0x1E, 0x10, 0x38, 0x30, 0x18, 0x10, 0x04, 0x1A, 
  0x24, 0x08, 0x02, 0x26, 0x38, 0x2A
]

chars = [
  0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 
  0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 
  0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x2B, 0x2D, 0x41, 0x42, 
  0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 
  0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 
  0x57, 0x58, 0x59, 0x5A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 
  0x36, 0x37, 0x38, 0x39, 0x00
]

def get_xyz(x, y, z):
    return s[64 * 64 * x + 64 * y + z]

current = list(correct)
prev = [0] * 16

search_range = []

for i in xrange(16):
    search_range.append(max(pos[i][0], pos[i][1], pos[i][2]))
    if (i > 1):
        search_range[i] = max(search_range[i], search_range[i-1])

search_pos = [0] * 16

for i in xrange(16):
    search_pos[search_range[i]] = i + 1

for i in xrange(1, 16):
    search_pos[i] = max(search_pos[i], search_pos[i - 1])

print search_range

print search_pos

def dfs(x):
    if (x and search_pos[x-1] != search_pos[x-2]):
        for i in xrange(search_pos[x - 2], search_pos[x - 1]):
            if (get_xyz(prev[pos[i][0]], prev[pos[i][1]], prev[pos[i][2]]) != current[i]):
                return 0
    if (x == 16):
        return 1
    for i in xrange(64):
        prev[x] = i
        if (dfs(x + 1)):
            return 1
    return 0

for i in xrange(19):
    dfs(0)
    print prev
    current = list(prev)
    prev = [0] * 16

在我的机器上大概20分钟算一组出来……
暴力出来最后需要的数字是

17, 43, 33, 5, 63, 1, 37, 11, 57, 19, 51, 9, 63, 57, 53, 37

换算成字符得到Flag

rPFf9bJl3tXj93ZJ

ps

虽然数学方法没有拟合出来,但是我推出了F(0, y, z)=a满足的关系式:

((y) * (16 * (y % 2) + (1 - 4 * a)) + z0 + (32 * ((1+a) % 4 / 2) + 8) * (y % 2)) % 64 == z

而且这些数字中有着非常不自然的等差关系,猜测出题人的预期解是数学方法?


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

最后于 2018-6-29 12:07 被acdxvfsvd编辑 ,原因:
收藏
点赞1
打赏
分享
最新回复 (1)
雪    币: 1020
活跃值: (305)
能力值: ( LV12,RANK:306 )
在线值:
发帖
回帖
粉丝
奈沙夜影 2 2018-6-30 22:20
2
0

const int st[16]={20,34,30,16,56,48,24,16,4,26,36,8,2,38,56,42};
const int u[16][3]={
{0,1,2},
{3,4,0},
{5,6,0},
{5,7,1},
{4,6,1},
{8,2,3},
{9,2,4},
{7,10,3},
{8,12,5},
{11,13,6},
{12,13,7},
{11,14,9},
{14,8,10},
{15,9,10},
{15,11,12},
{15,13,14}
};
const int n=64,m=16,v=3;

char o[64][64][64];
int lst[16],s[16],t[16],l[16],p[16];

inline bool dfs(int x)
{
       //out,"dfs:",x,'\n';
       if(x>1&&p[x-1]!=p[x-2])
       {
               fo(j,p[x-2],p[x-1]-1)
                       if(o[t[u[j][0]]][t[u[j][1]]][t[u[j][2]]]!=s[j])return 0;
       }
       if(x==m)
       {
               out,"ok\n";
               return 1;
       }
       fo0(i,n)
       {
               t[x]=i;
               if(dfs(x+1))return 1;
       }
       return 0;
}

int main()
{
       freopen("in.txt","r",stdin);
       fread(o,1,sizeof(o),stdin);
       fo0(i,n)fo0(j,n)fo0(k,n)assert(o[i][j][k]<n);
       fo0(i,m)s[i]=st[i];
       fo0(i,m)
       {
               l[i]=max(u[i][0],max(u[i][1],u[i][2]));
               if(i)repr(l[i],l[i-1]);
       }
       fo0(i,m)p[l[i]]=i+1;
       fo1(i,m-1)repr(p[i],p[i-1]);
       fo0(i,m)out,p[i],' ';out,'\n';
       //fo0(i,m)t[i]=rand()%64;
       //fo0(j,m)s[j]=o[t[u[j][0]]][t[u[j][1]]][t[u[j][2]]];
       fo0(i,m)out,s[i],' ';out,'\n';
       fo0(i,20)
       {
               out,i,"==========================\n";
               dfs(0);
               fo0(j,m)out,t[j],' ';out,'\n';
               fo0(j,m)assert(s[j]==o[t[u[j][0]]][t[u[j][1]]][t[u[j][2]]]);
               fo0(j,m)s[j]=t[j];
       }
       while(1);
}
游客
登录 | 注册 方可回帖
返回