-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Description
Description
gnrc_sock_dns
doesn't perform sufficient sanity checks on the DNS response it receives from the configured DNS server.
Here is a non-exhaustive list of issues:
- The
QDCOUNT
contained in the DNS response is not verified. This causes an out-of-bounds buffer access in the_skip_hostname
function ifQDCOUNT
is set to a value larger than the buflen
supplied to_parse_dns_reply
. - The
RDLENGTH
bounds-check for the answer section is incorrect for two reasons: (a)buf + len
is the first invalid address, so>=
needs to be used as a comparison operator (b) The result ofbufpos + addrlen
might cause a pointer overflow (especially due to the fact thataddrlen
is attacker controlled). If pointer overflows wrap around (undefined behaviour) this would allow an attacker to circumvent the bounds-check and exposes a buffer overflow vulnerability since the attacker controlledaddrlen
is later used inmemcpy(addr_out, bufpos, addrlen)
, potentially allowing a code execution. - The size of the caller allocated buffer
addr_out
is not passed to the_parse_dns_reply
function at all. This makes checking whether the attacker controlled address actually fits in the buffer impossible and allows an easy buffer overflow and potential code execution.
All of these are especially critical due to the fact that DNS responses can easily be spoofed, especially since all spoofing protection mechanisms of DNS were not implemented. So an attacker doesn't even need to control the configured DNS server in order to exploit this.
Steps to reproduce the issue
- Flash an unmodified version of
tests/gnrc_sock_dns
to your RIOT node. - Adjust your radvd.conf on your border router and add a RDNSS definition.
Causing a crash
Constantly send a DNS response with an excessive qdcount on the computer associated with the IP-Address you configured in the radvd RDNSS definition. For example
while sleep 1; do
echo AACEAwkmAAAAAAAAKioqKioqKioqKioqKioqKioqKio= | \
base64 -d | \
socat fd:0 udp6-sendto:'[address-of-riot-node]':49152,sourceport=53
done
Remote code execution
This is (obviously) highly platform specific. We did this with BOARD=pba-d-01-kw2x
. We wrote some ARM assembler code which toggles the LED and stored the machine code for it in the RDATA
field of the answer section in the DNS response, thereby overflowing the addr
buffer in the main
stack frame. Our payload exactly fits into the stack frame of the main function and overwrites the return address of that function, jumping to the addr
buffer and executing our payload.
Exploit written by @pyropeter. See: https://github.com/beduino-project/exploit-riot-dns
Versions
RIOT-Version: 5e03f58
Build environment:
Operating System Environment
-----------------------------
Operating System: "Arch Linux"
Kernel: Linux 4.19.4-arch1-1-ARCH x86_64 unknown
Installed compiler toolchains
-----------------------------
native gcc: gcc (GCC) 8.2.1 20181127
arm-none-eabi-gcc: arm-none-eabi-gcc (Arch Repository) 8.2.0
avr-gcc: avr-gcc (GCC) 8.2.0
mips-mti-elf-gcc: missing
msp430-gcc: missing
riscv-none-embed-gcc: missing
clang: clang version 7.0.0 (tags/RELEASE_700/final)
Installed compiler libs
-----------------------
arm-none-eabi-newlib: "3.0.0"
mips-mti-elf-newlib: missing
riscv-none-embed-newlib: missing
avr-libc: "2.0.0" ("20150208")
Installed development tools
---------------------------
cmake: cmake version 3.13.1
cppcheck: missing
doxygen: 1.8.14
flake8: missing
git: git version 2.19.2
make: GNU Make 4.2.1
openocd: Open On-Chip Debugger 0.10.0+dev-00436-g0fdf48f1 (2018-06-18-18:19)
python: Python 3.7.1
python2: Python 2.7.15
python3: Python 3.7.1
coccinelle: missing