Category: Internet of Things
Points: 984
Solves: 10
Description:
We heard a rumor that COVID was leveraging that smart city's 'light' technology for communication. Find out in detail on the technology and what is being transmitted.
We are provided with a .logicdata file for the challenge. A quick google search shows that it is data from a Saleae logic analyser. We download the software from their website to take a look at the file.
We see what looks like a bunch of data packets, one of which looks like this:
This data looks very similar to the NEC IR Protocol
We can find a plugin for the Saleae software for the NEC IR protocol here, but when trying it out, it seems like it is unable to parse the data properly, showing no output, probably because of the 38kHz carrier frequency.
The Saleae software allows us to export the data as a csv file, which we can use to decode the data.
First, we read the csv file
import csv
data = []
with open("raw.csv") as csvFile:
csvReader = csv.reader(csvFile)
lineCount = 0
#loop through csv file
for row in csvReader:
if lineCount == 0:
print(f'Column names are {", ".join(row)}')
lineCount += 1
else:
#append the data to a list if it is not the first row
data.append([float(row[0]),int(row[1])])
lineCount += 1
From the Saleae software, we see that there is a 38kHz carrier signal
We can easily remove this, filtering out pulse shorter than 20 microseconds
for i, dataPoint in enumerate(data):
if i != len(data)-1:
if data[i][1] == 0:
#calculate length that signal is low
timeDiff = data[i+1][0] - data[i][0]
#remove pulse if it is less than 20 microseconds long
if timeDiff < 0.00002:
data[i][1] = 1
The results:
Now we have the demodulated signal, we clean it up by removing consecutive 1
data points:
toPop = []
#generate list of data points to remove
for i, dataPoint in enumerate(data):
if i != 0:
if data[i][1] == 1 and data[i-1][1] == 1:
toPop.append(i)
#remove data points
for i in toPop[-1:0:-1]:
data.pop(i)
Now, we convert the data from absolute time to the length of each pulse:
cleanedData = []
for i, dataPoint in enumerate(data):
if i != len(data)-1:
dataTime = data[i+1][0] - data[i][0]
cleanedData.append([dataTime, data[i][1]])
Finally, we can start decoding the data.
We label the data points based on the NEC ir protocol shown above, giving each data point a range of timings to account for variations in the captured data:
#0: zero width
#1: one width
#2: leading pulse
#3: leading space
for i, dataPoint in enumerate(cleanedData):
dataTime = dataPoint[0]
if dataTime > 0.0087 and dataTime < 0.0092:
cleanedData[i][0] = 2
elif dataTime > 0.004 and dataTime < 0.005:
cleanedData[i][0] = 3
elif dataTime > 0.0005 and dataTime < 0.0006:
cleanedData[i][0] = 0
elif dataTime > 0.0015 and dataTime < 0.0018:
cleanedData[i][0] = 1
else:
cleanedData[i][0] = -1
The data is sent in packets, which we split it into. Then, we remove the first 17 data points, which correspond to the NEC protocol address and leading pulse:
dataPackets = []
#split data into packet
for i, dataPoint in enumerate(cleanedData[:-67]):
if cleanedData[i][0] == 2 and cleanedData[i+1][0] == 3:
dataPacket = []
for j in range(67):
if cleanedData[i+j][1] == 0:
dataPacket.append(cleanedData[i+j][0])
#remove first 17 data points
dataPackets.append(dataPacket[17:])
Now, we have decoded the data in binary and we can easily decode it:
rawData = []
for i in dataPackets:
stringVals = [str(j) for j in i]
stringData = "".join(stringVals)
rawData += chr(int(stringData[0:8],2))
rawData += chr(int(stringData[8:16],2))
print("".join(rawData))
From this, we get the flag:
govtech-csg{CTf_IR_NEC_20@0!_}govtech-csg{CTf_IR_NEC_20@0!_}govtech-csg{CTf_IR_NEC_20@0!_}govtech-csg{CTf_IR_NEC_20@0!_}govtech-csg{CTf_IR_NEC_20@0!_}govtech-csg{CTf_IR_NEC_20@0!_}govtec