题目感觉不错,学到很多,开心
分析
64位无壳,elf文件,拖进ida
可以看到这里设置了个异常处理
发现只能在虚拟机中运行。
输入字符串后,进入sub_55AC08D6DF20函数
(注:由于有aslr而且我比较懒(草),所以下面的函数名都是我本地的名字)
sub_55AC08D6DF20函数
sub_55AC08D6DF20函数将我们的输入一个个和一个解密后的字符串拼接后sprintf到v11中
info-set guestinfo.%s %s是解密出的字符串,丢到网上搜索,发现和虚拟机的接口RPCI有关,于是学习了一波RPIC的原理和特点
发现info-set guestinfo.%s %s中的第一个参数对应的是要在宿主机中set的键,第二个参数是值,比如下图就是在宿主机中创建了一个名为b的键,值为2的ascii码。
我们可以通过另一个指令info-get guestinfo.b来获取这个键的值,和python的字典有点像。
然后下方是两个奇怪的函数,这里猜测是send和receive的函数。
发现这里循环26次,将我们的输入作为值,和a到z的键进行了配对。
随后进入下一个函数。
sub_55AC08D6E060函数
第一部分
函数前部分有很多行与下图类似结构的代码,意思大概是把一个固定的字符串中的字符一个个取出,作为键来取出我们刚刚set到宿主机的值(使用info-get guestinfo.%s),然后和当前字符异或,存入内存之中。
第二部分
进行了几轮后,来到了一个判断
这里的v87和ord(‘z’)进行异或后得到的是32,也就是空格。这里应该是用来判断输入是否大于等于26。
然后下面都差不多,直到这个地方
这里是把a到z的所有键对应的值进行了累加。下面的移位会用到。
第三部分
这里是将我们刚刚异或后的保存到内存里的值进行了循环移位后作为参数丢进了这个函数之中。
循环移位的v103就是我们刚刚累加的结果.
然后这个B3C9函数就是把刚刚移位完的结果变成字符串保存在内存中
比较简单,这里不讲了。
然后又是刚刚的套路
从a1到a7set了七个,然后我们看到下图的execve,很容易猜测是用来找到宿主机进行判断的
这个时候我突然发现,不对呀,这个题不需要联网,那宿主机隔哪呢,随后搜索了一下/tem/vm的字符串
发现init里面藏了个这玩意。
elf文件,大小0x48e0.直接dump出来。在dump出来文件的主函数里找到了对比的数
但是只有个这个似乎并不能还原input,因为我们不知道循环移位的位数。于是我们回头寻找
发现a7的第两位是0x455a。然后提取出最后一个对比的数,比较二进制就可以知道移位的位数了。
左移了9位。
然后可以写脚本了。
这里由于懒得写,改了一下官方脚本
def ROL(a,b):
return ((a<<(b%32))|(a>>(32-b%32)))
def d2b(a):
s=[]
for i in range(4):
s.append(a&0xff)
a>>=8
return s[::-1]
p = [(7, 0x23C34040),(3, 0x14380438),(5, 0x6098398),(7, 0xE0E2C3),(9, 0x30585858),(29, 0x81960C),(27, 0xE8AB41C)]
c = list(b'elcvxntymrzoahwujigpqfdsbk\x00\x00')#这里因为不是4的倍数下面会报错所以加俩padding
flag = ""
for s, v in p:
v = ROL(v, 28 + s)
w=d2b(v)
for t in range(4):
flag += chr(w[t] ^ c[0])
c = c[1:]
flag = flag[:-2]#去掉刚刚的padding
c = "elcvxntymrzoahwujigpqfdsbk"
res = [0]*26
for i in range(26):
print(flag[c.find(chr(i + 97))],end="")#输入是按照a到z来输入的,顺序也就是这样决定
得出flag
参考
https://tech.lazyllama.com/2010/06/22/passing-info-from-powercli-into-your-vm-using-guestinfo-variables/
https://zhuanlan.zhihu.com/p/27733895?utm_source=tuicool&utm_medium=referral