RS-232 Spy

This is a brief post to describe how to spy on rs232 traffic for the purpose of investigating protocol between two devices that don't provide an interface traffic log. As example, we're examining traffic between a Property Management System (PMS) and a PBX.

The basic concept is very simple - stick a monitoring station between the devices, and echo traffic between the two ports -- when data is received on one port, transmit that out the other port, and vice-versa. With the ports echoing to each other, the only thing left to do is spy on that chatter -- display it somehow.

To perform this monitoring, you need

  • A PC with two serial ports
  • Node.JS

Here's the code:

//npm install serialport
var SerialPort = require("serialport").SerialPort

var portConfig = {
  baudrate: 1200, databits: 7, parity: 'even', stopbits: 1
}
//This was written for linux; change COM ports accordingly.
var hostA = new SerialPort("/dev/ttyUSB0", portConfig)
var hostB = new SerialPort("/dev/ttyUSB1", portConfig)

var aReady, bReady

hostA.open(function () {
  aReady = true
  console.log('host A is open')
  hostA.on('data', function(data){
    if(bReady) hostB.write(data) //THIS IS THE ECHO
    bufferData(data, 'pbx')      //THIS IS THE SPY
  })
  hostA.on('end', function(){
    aReady = false
    console.log('host A is ended')
  })
})
hostB.open(function () {
  bReady = true
  console.log('host B is open')
  hostB.on('data', function(data){
    if(aReady) hostA.write(data) //THIS IS THE ECHO
    bufferData(data, 'pms')      //THIS IS THE SPY
  })
  hostB.on('end', function(){
    bReady = false
    console.log('host B is ended')
  })
})


var _bufferFrom, _buffer="", _bt
function bufferData(data, bufferFrom){
  //buffering the data lets us group it by line
  //rather than logging each character individually.
  clearTimeout(_bt)
  if(!_bufferFrom) _bufferFrom = bufferFrom

  if(_bufferFrom !== bufferFrom) dumpBuffer(bufferFrom)

  _buffer += readable(data)
  _bt = setTimeout(dumpBuffer, 1000)
}
function dumpBuffer(bufferFrom){
  console.log(_bufferFrom + ": " + _buffer)
  _buffer = ""
  _bufferFrom = bufferFrom
}
function readable(data){
  //make buffered ASCII human readable.
  data = data.toString()
  data = data.replace('\x06', '[ACK]')
  data = data.replace('\x00', '[NUL]')
  data = data.replace('\x05', '\n[ENQ]')
  data = data.replace('\x03', '[ETX]')
  data = data.replace('\x02', '[STX]')
  return data
}

Here's a sample output:

pbx: [ENQ]
pms: [ACK]
pbx: [STX]AREYUTHERE[ETX]
pms: [ACK]

pms: [ENQ]
pbx: [ACK]
pms: [STX]CHK1 7224 Phone Tech, Phone Te[NUL][NUL][NUL][NUL][NUL][NUL]w[ETX]
pbx: [ACK]

pms: [ENQ]
pbx: [ACK]
pms: [STX]RST1 7224 [ETX]
pbx: [ACK]

pms: [ENQ]
pbx: [ACK]
pms: [STX]DND0 7224 [ETX]
pbx: [ACK]

pms: [ENQ]
pbx: [ACK]
pms: [STX]MW 0 7224 [ETX]
pbx: [ACK]

pbx: [ENQ]
pms: [ACK]
pbx: [STX]MSG2 7224 0[ETX]
pms: [ACK]

pbx: [ENQ]
pms: [ACK]
pbx: [STX]AREYUTHERE[ETX]
pms: [ACK]
RS-232 Spy
Share this