请注意,本文编写于 1677 天前,最后修改于 1677 天前,其中某些信息可能已经过时。
题目二进制文件,靶机已经关闭
这道题比赛的时候,直接就把我劝退了。先百度一下Rubik,哦,是一个建筑学家,还是魔方之父(这点当时我可没反应上来)。拖入IDA,能找到main函数与一些关键的字符串,但是我压根就没看懂他到底在干嘛,有些函数套在一起,相互间一直调用,而且没找到什么关键信息。然后就没有然后了。。。。
直到昨天认真再看大佬的题解的时候,才慢慢对这道题进行了摸索。大佬指出这是一道拼魔方的题目,Rubik提示魔方的方向。其次,可以使用gdb调试一下,看起来比IDA舒服一些。直到这里,我才看见这道题的真实面目。
题目会给你串长度为9个字节的十六进制数,然后获取你的一个输入。
整道题目的交互很简单,而且在IDA中也没留下很明显的逻辑代码。每次启动GDB,都会获得一串不同的16进制数字,初步猜测这串数字应该是随机生成的。结合题目所给提示,猜测整道题应该需要你输入一些东西,进入程序,完成某些功能,最终给你返回一个flag(逆向题目给了靶机,说明flag应该存储在靶机上,需要你触发某个开关,才可以返回flag)。搜寻IDA发现一组字符。
RUF是一组魔方中经常使用的几个符号,都是英语单词的缩写,意思分别为:
分析一波,魔方一般来说是有六个面,而计算机存储也一定不是拿颜色存储的,所以只需要给它6个可分辨的标志位,就可以让他区分6种不同的颜色。设想一下,如果是你在编程最简单的一定是使用编号0-5进行每一个面的代替,用三位二进制数表示6种状态(最多8种)。而十六进制与二进制进行转化是十分方便的,先做一下尝试,直接转换为二进制,每三位为一组,一眼望过去,用很多000,明显不是这样构成魔方的。继续思考,我们拿到的是九个字节的数据每个字节对应8位二进制数字,98/3=24,24/6=4。所以我们拿到的应该是一个22得魔方,这次使用每位对应四位二进制数展开,三三分组。转换标号正好得到了如下数据:
如倒数后三行所示,正好6种数字,每种占4个。说明我们的分析是没有问题的。
于是我们遇到了第二个问题,以何种方式将每种颜色填入我们得魔方当中。这个地方可谓是相当的艰辛,Gdb逐句调试分析逻辑,但是奈何我动态分析真的能力有限,这里就不赘述了。主要还是结合了一下学长给的WP里面的脚本才勉勉强强写出来一个逻辑。
这个地方属实没有太搞清楚,在后面我会贴上学长的脚本。
#coding=utf-8
class Block():
def __init__(self, bits):
self.bits = bits
self.color = self.bits_to_num(bits)
def bits_to_num(self, bits):
a = 0
for i in range(3):
a *= 2
a += bits[2 - i]
return a
def __str__(self):
ret = ''
if self.color == 6:
ret = 'g'
elif self.color == 5:
ret = 'w'
elif self.color == 4:
ret = 'o'
elif self.color == 2:
ret = 'y'
elif self.color == 1:
ret = 'b'
elif self.color == 0:
ret = 'r'
return ret
def __eq__(self, a):
if self.color == a.color:
return True
else:
return False
def __ne__(self, a):
if self.color == a.color:
return False
else:
return True
class Rubic():
def __init__(self, blocks):
self.blocks = blocks
self.b1 = blocks[0:4]
self.b2 = blocks[4:8]
self.b3 = blocks[8:12]
self.b4 = blocks[12:16]
self.b5 = blocks[16:20]
self.b6 = blocks[20:24]
def get_num(self):
n = 0
for i in range(len(self.blocks)):
for j in range(len(self.blocks[i].bits)):
n *= 2
n += self.blocks[i].bits[j]
return n
def F(self):
tmp = self.b6[3]
for i in range(3):
self.b6[-1 + i] = self.b6[i]
self.b6[2] = tmp
tmp1 = self.b5[1]
tmp2 = self.b5[2]
self.b5[1] = self.b4[0]
self.b5[2] = self.b4[1]
self.b4[0] = self.b2[0]
self.b4[1] = self.b2[1]
self.b2[1] = self.b1[2]
self.b2[0] = self.b1[1]
self.b1[2] = tmp2
self.b1[1] = tmp1
def U(self):
tmp = self.b4[3]
for i in range(3):
self.b4[-1 + i] = self.b4[i]
self.b4[2] = tmp
tmp1 = self.b5[0]
tmp2 = self.b5[1]
self.b5[1] = self.b3[1]
self.b5[0] = self.b3[0]
self.b3[1] = self.b2[2]
self.b3[0] = self.b2[1]
self.b2[2] = self.b6[2]
self.b2[1] = self.b6[1]
self.b6[2] = tmp2
self.b6[1] = tmp1
def R(self):
tmp = self.b5[3]
for i in range(4):
self.b5[-1 + i] = self.b5[i]
self.b5[2] = tmp
tmp1 = self.b6[0]
tmp2 = self.b6[1]
self.b6[1] = self.b1[1]
self.b6[0] = self.b1[0]
self.b1[1] = self.b3[2]
self.b1[0] = self.b3[1]
self.b3[2] = self.b4[2]
self.b3[1] = self.b4[1]
self.b4[2] = tmp2
self.b4[1] = tmp1
def __str__(self):
ret = ''
ret += ' '
ret += self.b4[3].__str__() + self.b4[2].__str__() + '\n'
ret += ' '
ret += self.b4[0].__str__() + self.b4[1].__str__() + '\n'
ret += ' '
ret += self.b2[2].__str__() + self.b2[1].__str__() + ' '
ret += self.b6[2].__str__() + self.b6[1].__str__() + ' '
ret += self.b5[1].__str__() + self.b5[0].__str__() + ' '
ret += self.b3[1].__str__() + self.b3[0].__str__() + '\n'
ret += ' '
ret += self.b2[3].__str__() + self.b2[0].__str__() + ' '
ret += self.b6[3].__str__() + self.b6[0].__str__() + ' '
ret += self.b5[2].__str__() + self.b5[3].__str__() + ' '
ret += self.b3[2].__str__() + self.b3[3].__str__() + '\n'
ret += ' '
ret += self.b1[2].__str__() + self.b1[1].__str__() + '\n'
ret += ' '
ret += self.b1[3].__str__() + self.b1[0].__str__() + '\n'
return ret
if __name__ == '__main__':
x = int(input(), 16)
b = [0 for _ in range(72)]
idx = 0
while x != 0:
b[71 - idx] = x & 1
idx += 1
x >>= 1
blocks = []
bit = []
for i in range(len(b)):
if i % 3 == 0 and i != 0:
blocks.append(Block(bit))
bit = []
bit.append(b[i])
blocks.append(Block(bit))
r = Rubic(blocks)
print(r)
这个地方先留做疑惑,等一波其他大佬的解释,到时候深度学习一下,如何将这个还原逻辑从汇编中找出来。只要找到这个逻辑,这道题就已经结束了。附上一个在线解密魔方的网站,输入解密完成。将代码串check一下,得到flag。
打开GDB,获取随机16进制字符串(靶机已经关闭了),分析字符串,构成魔方
在线运行,返回GDB输入答案,cat在文件中我自己创建的假flag。
总体来说,这次的魔方题算是一次开眼界吧。让我知道在逆向里除了代码分析脱壳以外还有这种题型。这里的汇编还是我的一大障碍,还是要多读,多练。还有就是大佬写的题解是真的简略QAQ,再等一等,要是之后有大佬把中间分析过程写出来,我在好好学习一下,到时候再继续完善这篇博客。
全部评论 (暂无评论)
info 还没有任何评论,你来说两句呐!