首先来一道虚拟机镜像的题目 源于上学期校内开的一个会议 让我一直好奇虚拟机镜像自己需要怎么制作虽然看完题目也不知道怎么做
2021 Virtual Love_Revenge(2.0)
搜了好久题目附件找不到了 只能按照wp梳理思路
密钥爆破
解压完题目文件 之后可以得到一个加密的含有flag的压缩包还有一个wm虚拟机的文件夹 双击打开文件夹中的vmx文件 发现虚拟机被加密
那么我们首先需要破解密码 要使用以下的项目文件
https://github.com/axcheron/pyvmx-cracker
usage: pyvmx-cracker.py [-h] [-v VMX] [-d DICT]
这里的DICT项目中有 但是无法用来爆破密码 所以需要我们使用自定义密码
接下来寻找自定义密码
进行下一步前我们要先来了解一下虚拟机文件
- vmx
VMware虚拟机配置,它是虚拟机系统文件,通常通过打开这个虚拟机文件以启动系统。
- vmdk
VMware虚拟磁盘文件。这个是虚拟机存放文件的虚拟磁盘。也就是说,虚拟机内的系统和所有文件都在这个文件中,它就相当于我们电脑主机中的硬盘。
- .vmx.lck
这个文件叫做磁盘锁文件。因为.vmdk虚拟磁盘文件有一个保护机制。为了防止多台虚拟机同时访问一个.vmdk虚拟磁盘文件带来的数据丢失和性能下降。
- .vmware.log
这种log文件会有很多,vmware-0.log、vmware-1.log等等,用来记录vmware工作日志。
- .vmxf
英文全称为VMware team member,VMware组成员。该文件为虚拟机组team中的虚拟机的辅助配置文件。一般无需改动。
- .vmsd
VMware快照元素。VM快照和相关联的vmdk的字典文件。一般无需改动。
- .nvram
VMware虚拟机非易变RAM。虚拟机的BIOS信息。
参考文章
https://blog.csdn.net/qq_38145502/article/details/103629709
正常导出加密虚拟机时 导出的文件不会含有log文件 这里的log文件很明显时出题人后来加上去的 在log文件中藏有隐写 这里我们用sublime打开
可以看到<200c><200d>对其进行01转化
<200c>->1 <200d>->0
提取隐写的信息,即可得到一份字典,顺便还原出没有经过隐写的log
使用提取出的字典替代上述爆破项目的DICT 就可以得到密码kx4s3a
用密钥移除加密后,即可打开虚拟机
配置修复
打开虚拟机后 发现提示客户文件未指定虚拟机操作系统
在vmxf文件中可以找到一句话
You hurt my heart deeply! So I will revenge, I will destroy everything you have!
上面这句话暗示了文件损坏 需要我们去进行修复
我们需要先找到虚拟机的操作系统,在镜像文件中一定会有记录,打开iso文件,可以看到CentOS 7 64 位得到操作系统版本 修改一下
再次打开虚拟机 又出现报错Operating System not found
搜索一下发现是CD/DVD指定目录的问题 查看虚拟机的配置与正常虚拟机对比发现少了很多选项设置
因为.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文件对比或者参考官方文献我一般会选择前面的方法
下面是可以参考的官方文献
http://sanbarrow.com/vmx.html
https://cdn.ttgtmedia.com/searchVMware/downloads/RULE_CH09.pdf
https://blog.csdn.net/shuideyidi/article/details/40688369
在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"
...(中间略)...
usb:0.parent = "-1"
保存后 再次打开虚拟机出现新的报错:指定的文件不是虚拟磁盘
在vmx文件已经修复好的情况下,出现这种报错,那就是虚拟磁盘文件,即vmdk文件出现了问题,所以接下来需要修复vmdk
参考这一文献
https://github.com/libyal/libvmdk/blob/main/documentation/VMWare%20Virtual%20Disk%20Format%20(VMDK).asciidoc
使用010editorvmdk打开发现缺少文件头4B 44 4D 56 01 00 00 00还有文件尾
0A 20 0D 0A保存后依旧报错
用notpead++打开 观察vmdk文件结构
结构大体由三部分组成
# Disk DescriptorFile
# Extent description
# The Disk Data Base
#DDB
对比正确的vmdk,或者参考文献[](https://cdn.ttgtmedia.com/searchVMware/downloads/RULE_CH09.pdf)可以发现第一部分缺少了version、parentCID和磁盘文件的编号
version的值默认为1,本题虚拟机并没有快照,所以parentCID=ffffffff,再按顺序补充编号s001~s006,修改后保存,即可正常打开虚拟机
绕过密码
使用题目所给的用户进行登录 只能得到错误的flag 查看history log文件
得到提示Try to enter root!
我们需要进入root文件夹,但guest用户没有权限进入
CentOS存在单用户模式,我们可以利用单用户模式来修改root的密码
接下来具体按照文档指示操作即可https://edu.51cto.com/article/note/16777.html
重启系统后即可用刚刚修改过的密码登录root,这样就可以进入root文件夹
上述多次提及参照正常的xxx文件 所以这里有非预期就是直接与正常文件替换然后再进行root密码修改
参考文章https://cloud.tencent.com/developer/article/2272859
接下来来三道D^3CTF出现过的网络题 因为题目的环境无法打开所以这里也是梳理思路
2024 O!!!SPF!!!!!! Enhanced
很抱歉藏宝图丢失了一部分。幸运的是,我们有办法找回它。2a13:b487:11aa::d3:c7f:2f 会告诉你钥匙的路径。但要找到它似乎并不容易?地牢和里面的旗帜正在等着你。
参考https://baimeow.cn/posts/ctf/ospf/
修复VPN配置
题目给了个损坏的OpenVPN配置文件 文件里缺了静态密钥导致VPN连不上
题目给了个IPv6地址2a13:b487:11aa::d3:c7f:2f需要我们使用 tracert 命令去连接 需要把TTL改大一点不然是 trace 不到的
发现每个路由器节点都用32位十六进制字符串命名 最后一个节点正好是题目提示的 aaf26d2a066ce6356487ead9551fda4c
得到的OpenVPN TLS Static Key位于2a13:b487:11aa::d3:c7f:20 和 2a13:b487:11aa::d3:c7f:2f 之间
把他写到附件的配置文件里预留的地方就可以了
-----BEGIN OpenVPN Static key V1-----
bd23ff4fb2b7f8e49200c3801151663d
0dcc848e1b075bd4dcb4fd32712559de
...(中间省略)...
aaf26d2a066ce6356487ead9551fda4c
-----END OpenVPN Static key V1-----
nmap扫网段,注意到100.64.11.2 开了 18080 端口鉴定为 flagServer
修改服务器地址为 100.64.11.2:18080
成功连上VPN
破解验证程序
用nmap扫描找到目标服务:100.64.11.2:18080并用nc命令连接目标服务器
连接到之后要进行身份验证 这里不管给出的saltedhash是否正确都会输出flag
要先发32字节任意数据到服务器 然后服务器会用HMAC-SHA256计算一个签名返回 这就类似于一个临时通行证 接下来开始交互
服务器随机发送多条消息
要求你对每条消息计算saltedhash并返回但是这里程序根本没检查你的返回值对不对
持续发送大量数据(比如一直发"Y")塞满服务器的缓冲区
之后服务器会问:"要flag吗?(Y/N)"
回复"Y"就能拿到flag 一下引用别人的脚本
func handleConn(c net.Conn) {
defer c.Close()
// convince the client that we are the real server
var challenge [32]byte
_, err := io.ReadFull(c, challenge[:])
if err != nil {
log.Println(err)
return
}
authSigner := hmac.New(sha256.New, []byte(AuthKey))
authSigner.Write(challenge[:])
if _, err := c.Write(append(authSigner.Sum(nil))); err != nil {
log.Println(err)
return
}
// game start message
_, err = c.Write([]byte("I will send you messages, please reply me the salted hash for confirming.
To Players: You are not supposed guess the salt.\n"))
if err != nil {
log.Println(err)
return
}
// game loop
for _, msg := range RandOrder(msgs) {
_, err = c.Write([]byte(msg + "\n"))
if err != nil {
log.Println(err)
return
}
var rec [32]byte
_, err := io.ReadFull(c, rec[:])
if err != nil {
log.Println(err)
return
}
if slices.Compare(rec[:], Sign([]byte(msg))) != 0 {
_, err = c.Write([]byte("Wrong Hash\n"))
if err != nil {
log.Println(err)
return
}
}
}
// game end message
_, err = c.Write([]byte{'\n'})
if err != nil {
log.Println(err)
}
// game reward
_, err = c.Write([]byte("Would you like to have a flag?(Y/N)\n"))
if err != nil {
log.Println(err)
return
}
var getFlag [1]byte
_, err = io.ReadFull(c, getFlag[:])
if err != nil {
if err != io.EOF {
log.Println(err)
}
return
}
if getFlag[0] == 'Y' {
_, err = c.Write([]byte(os.Getenv("flag")))
if err != nil {
log.Println(err)
return
}
}
}
2025d3RPKI
比赛的时候直接伪造路由但是t1配置了启用了 ROA(资源公钥基础设施起源验证),直接伪造路由会受到限制 所以当时监听Flag没成功
网络拓扑:
- t1:连接 nw0、nw1、nw2 和 subnet1,ASN 为 4211110001,运行 RPKI 服务器。
- t2-1:连接 nw0 和 subnet2,ASN 为 4211110002,可通过 SSH(端口 2233)访问。
- t2-2:连接 nw1 和 subnet3,ASN 为 4211110003,发送 FLAG 到 10.4.0.5:1234。
- t2-3:连接 nw2 和 subnet4,ASN 为 4211110004,负责 10.4.0.0/24。
FLAG发送机制
t2-2容器每10秒会执行 echo $FLAG | nc 10.4.0.5 1234
目标IP 10.4.0.5 原本属于t2-3管理的子网(10.4.0.0/24)
路由劫持机会
- BGP协议默认优先选择最具体的路由(比如/32比/24更优先)
- 我们可以在t2-1上宣告 10.4.0.5/32 的虚假路由
- 通过操纵AS路径,让路由看起来是从合法ASN(4211110004)发出的
绕过安全防护
- t1启用了ROA验证(检查路由是否合法)
- 通过伪造AS路径的最后一跳为4211110004(10.4.0.0/16的合法ASN)
- 使伪造的10.4.0.5/32能通过ROA验证
解题步骤
修改t2-1的bird.conf文件
伪造/32路由 制造更优先的路由条目
添加合法ASN 绕过ROA安全验证
protocol static {
...
route 10.2.0.0/24 reject;
+ route 10.4.0.5/32 reject {
+ bgp_path.prepend(4211110004); // 关键!伪造AS路径
+ };
}
template bgp BGP_peers {
export filter {
+ if net = 10.4.0.5/32 then {
+ accept; // 放行伪造路由
+ }
if source ~ [RTS_STATIC, RTS_BGP] then accept;
reject;
};
}
绑定假IP到网卡 让系统认为10.4.0.5是本机IP,数据包会被本地接收
ip addr add 10.4.0.5/32 dev lo
重启BIRD服务
service bird restart
启动监听程序 持续监听1234端口,等待FLAG数据包到达 nc -l -p 1234 -k