前言: 由于本鶸出题设计的太不严谨,考虑不够周全,导致比赛中多次出现非预期,因此不得不在比赛过程中对附件进行多次修改,再加上题目附件过大(
根本压缩不动),多次下载浪费了做题师傅许多的时间和空间,带来了不便和不好的做题体验,我对此表示诚挚的歉意,还请各位师傅多多包涵谅解!
I'm coming for revenge again.
You say you love me, but you don't know me at all! Your love...Your love is all virtual!(Login User: guest)
解压题目文件,可以发现一个装有flag的加密压缩包和一个完整的用于vmware的虚拟机,双击vmx文件,打开发现虚拟机被加密,所以首先要破解加密
在github上可以找到一个项目:https://github.com/axcheron/pyvmx-cracker
使用这个脚本可以进行爆破,但是用其自带的字典爆破无法得到密钥,所以接下来我们要寻找字典
观察文件夹中的文件,我们需要先了解一下这些文件的用途,可参考文章
我们依次观察这些文件,可以发现在 .vmxf 文件中有这样一句话
You hurt my heart deeply! So I will revenge, I will destroy everything you have!
正常的vmxf文件是不会有这样一句话的,很明显是出题人故意修改过的,用来暗示文件被破坏,需要进行修复
附件中有三个log文件,单纯查看并不能发现什么,但是如果用十六进制编辑器或者vim查看,就可以发现在最大的log文件中存在一些不可见字符
这些不可见字符仅由\xe2\x80\x8d
和\xe2\x80\x8c
组成(<200d>
和<200c>
),想到转换成01序列
import libnum
f = open('vmware-1.log', 'rb')
ff = open('vmware-1.log', 'rb')
fi = open('dic.txt', 'w')
fj = open('log.txt', 'w')
fj.write(ff.read().replace('\xe2\x80\x8d', '').replace('\xe2\x80\x8c', ''))
fj.close()
while 1:
a = f.readline().replace('\xe2\x80', '')
out = ''
if a:
for i in a:
if i == '\x8d':
out += '0'
elif i == '\x8c':
out += '1'
else:
break
fi.write(libnum.b2s(out) + '\n')
else:
break
fi.close()
提取隐写的信息,即可得到一份字典,顺便还原出没有经过隐写的log
其实这里也有一个快速确定log文件的方法:正常导出加密虚拟机时,导出的文件并不会含有log文件,而这里的log文件很明显就是出题人后加进去的
通过使用提取出来的字典,利用刚刚提到的脚本进行爆破,即可得到密钥:kx4s3a
用密钥移除加密后,打开虚拟机,发现提示客户文件未指定虚拟机操作系统
所以我们需要先找到虚拟机的操作系统,在镜像文件中一定会有记录,打开iso文件,大概翻一翻就可以看到CentOS
,如果用010的话直接打开加载模板也能看到
修改操作系统为Linux CentOS 7 64 位,再次尝试打开虚拟机,发现提示Operating System not found
,百度一下报错可以大概了解到是CD/DVD指定目录的问题,但是我们再观察一下这个虚拟机再vmware中显示的配置,和其他的虚拟机相对照,可以发现有很多设置都缺少了
有关虚拟机配置的信息,我们上文已经提到了在 .vmx 文件中,用文本编辑器打开vmx文件,可以看到如下的信息
.encoding = "GBK"
displayName = "VirtualLove"
config.version = "8"
virtualHW.version = "16"
usb.vbluetooth.startConnected = "XXX"
nvram = "VirtualLove.nvram"
virtualHW.productCompatibility = "hosted"
powerType.powerOff = "soft"
powerType.powerOn = "soft"
powerType.suspend = "soft"
powerType.reset = "soft"
tools.syncTime = "XXX"
numvcpus = "2"
cpuid.coresPerSocket = "2"
vcpu.hotadd = "XXX"
...
如果打开不是这样的话,先把虚拟机的加密移除,就可以看到了
有关vmx文件中的这些配置选项的含义,可以参考:
当然也可以参考自己其他虚拟机的vmx文件,无论是查看相关文章,还是自己对比其他的虚拟机,都可以发现配置选项中是没有XXX
这一选项的,所以很明显vmx文件已经损坏,需要进行修复,修复方法可参考此文章,需要用到log文件,在log中寻找如下两行信息
2021-02-20T11:50:10.598+08:00| vmx| I125: DICT --- CONFIGURATION
......
2021-02-20T11:50:10.598+08:00| vmx| I125: DICT --- USER DEFAULTS
将这两行中间的信息复制到vmx文件中,移除前面多余的时间信息和结尾用于隐写的空白字符,保留如下格式,调整为左对齐
config.version = "8"
virtualHW.version = "16"
pciBridge0.present = "TRUE"
pciBridge4.present = "TRUE"
...(中间略)...
usb:0.present = "TRUE"
usb:0.deviceType = "hid"
usb:0.port = "0"
usb:0.parent = "-1"
修改后保存即可,再次尝试打开虚拟机,出现了新的报错:指定的文件不是虚拟磁盘
在vmx文件已经修复好的情况下,出现这种报错,那就是虚拟磁盘文件,即vmdk文件出现了问题,所以接下来需要修复vmdk,有关vmdk的结构详解可参考:
本题的虚拟机共有7个vmdk,一个很小的和六个分别编号1~6的较大的,其中较小的文件可以用文本编辑器打开,且内容可读,结构大体由三部分组成
# Disk DescriptorFile
# Extent description
# The Disk Data Base
#DDB
参考文档,对比正确的vmdk,可以发现第一部分缺少了version
、parentCID
和磁盘文件的编号,文档中也有写
version
的值默认为1,本题虚拟机并没有快照,所以parentCID=ffffffff
,再按顺序补充编号s001~s006,修改后保存,再次打开发现仍然报错,继续检查其余的vmdk文件,编号1~6的vmdk文件有固定的文件头,大小为512字节,具体组成如下表:
Offset | Size | Value | Description |
---|---|---|---|
0 | 4 | "KDMV" | Signature |
4 | 4 | 1, 2 or 3 | Version |
8 | 4 | Flags See section: Flags.asciidoc#vmdk_extent_file_flags) | |
12 | 8 | Maximum data number of sectors (capacity) | |
20 | 8 | Grain number of sectors The value must be a power of 2 and > 8 | |
28 | 8 | Descriptor sector number The sector number of the embedded descriptor file. The value is relative from the start of the file or 0 if not set. | |
36 | 8 | Descriptor number of sectors The number of sectors of the embedded descriptor in the extent data file. | |
44 | 4 | 512 | The number of grains table entries |
48 | 8 | Secondary (redundant) grain directory sector number The value is relative from the start of the file or 0 if not set. | |
56 | 8 | Grain directory sector number The value is relative from the start of the file or 0 if not set. Note that the value can be -1 see below for more information. | |
64 | 8 | Metadata (overhead) number of sectors | |
72 | 1 | Is dirty Value to determine if the extent data file was cleanly closed. | |
73 | 1 | 'n' | Single end of line character |
74 | 1 | ' ' | Non end of line character |
75 | 1 | 'r' | First double end of line character |
76 | 1 | 'n' | Second double end of line character |
77 | 2 | Compression method | |
79 | 433 | 0 | Padding |
*The end of line characters are used to detect corruption due to file transfers that alter line end characters.
我们用十六进制编辑器打开vmdk,可以发现这些文件缺少了Signature和version(默认为1)共8字节的内容,补上4B 44 4D 56 01 00 00 00
,继续查看,还可以发现第73~76位用于校验文件传输是否发生损坏的行结束符也没有,查ascii表或者对照正常的vmdk,都可以得到对应的16进制字符串0A 20 0D 0A
,修改后保存,再次尝试即可正常打开虚拟机
用题目所给的guest用户登录,发现在当前目录就有一个假的flag,提示flag不在这里,查看history,发现其中提示
Try to enter root!
我们需要进入root文件夹,但guest用户没有权限进入,查看sudo的版本可以发现是最新版,所以也并不存在提权漏洞,需要换一种思路
CentOS存在单用户模式,我们可以利用单用户模式来修改root的密码:
首先重启虚拟机,在如下界面按e
找到linux16
开头的那一段,将ro
修改为rw init=/sysroot/bin/sh
,按ctrl+x进入单用户模式
依次执行以下几条命令:
chroot /sysroot
LANG=en
passwd root
touch /.autorelabel
reboot -f
重启系统后即可用刚刚修改过的密码登录root,在root文件夹下得到压缩包密码
Revenge:f5`FU2)I$F0Oc'qL@pP)S
Revenge2.0:2F!,O<DJ+@<*K0@<6L(Df-
在当前目录下还可以看到一个 7@rget-f1le,取小写md5即是2.0的最后一部分flag
解压即可得到真正的flag
Revenge:d3ctf{Vmw@RE_1s_5oooo_C0mpl3x_ec4bb60e58}
Revenge2.0:d3ctf{Vmw@RE_1s_5ooo_C0mpl3x_8cf8463b34caa8ac871a52d5dd7ad1ef}
我看也有许多队伍的师傅是采用替换vmx,修改vmdk配置文件的方式对虚拟机进行修复,这也是一种很好的方法,而且比我设计的预期解题方式要简单一些。其实我设计这道题的目的,就是想让大家更多了解虚拟机各个配置文件的用途,了解并学习虚拟机损坏时的修复方式和当root密码忘记如何获得root权限等知识点,私认为和实际生活的联系还是比较大的,也希望各位做题的师傅能通过本题学到新的知识 :)