ICSim Exploration
- Author: Dr. Jim Marquardson (jimarqua@nmu.edu)
- Updated 2024-06-14
It is possible to monitor and generate CAN traffic using the simulated game controller. But sometimes, you lack a controller to generate codes. Tools exist to generate and replay traffic to see the effects on the controller network. In this exercise, you will use tools to generate CAN network traffic and replay that traffic on the network.
Learning Objectives
In this exercise, you will learn to:
- start ICSim and the controller using a seed,
- use
cangen
to generate network traffic, - use
candump
to record network traffic to a file, - use
canreplay
to replay captured traffic, and - evaluate data using Linux tools.
Prerequisites
This exercise assumes that the following are available:
- Kali Linux VM with a graphical user interface,
can-utils
has been installed,ICSim
has been installed to~/ICSim
.
Reset Applications
- Close the ICSim and controller applications, if they are running.
- Stop
cansniffer
if it is running, usingcontrol+c
. - Close all open terminals.
- There should be no applications running right now.
Setup a CAN Network
- Open a terminal.
- Navigate to the
~/ICSim
directory.
cd ~/ICSim
- Create the
vcan0
network. Thisvcan0
network essentially simulates a physical wire to sensors in a bus topology.
sudo sh setup_vcan.sh
Enter the password (kali
) if prompted.
- You may not see any output. The command likely worked. Check for the
vcan0
network usingifconfig
.
ifconfig
You should see vcan0
in the list of network adapters.
vcan0: flags=193<UP,RUNNING,NOARP> mtu 72
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 1000 (UNSPEC)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
- If you run
sudo sh setup_vcan.sh
and see a message like, "RTNETLINK answers: File exists," this means that thevcan0
network has already been set up. You can ignore this message and continue.
Launch the Simulator
- Run the following command to launch the vehicle simulator. Ensure that your working directory is
~/ICSim
before running this command. You will likely have to press theenter
twice in the terminal to return to the terminal prompt.
./icsim vcan0 &
Note that in this scenario, the controller is not being launched initially. The controller generates a lot of traffic in the background, and we want to minimize that traffic right now.
Window Setup
- Open a second terminal and navigate to the
~/ICSim
directory.
cd ~/ICSim
- At this point, you should have 3 windows: 1) the ICSim graphical user interface, 2) a terminal with the
~/ICSim
working directory, and 3) another terminal with the~/ICSim
working directory.
Generate Traffic
The cangen
tool can generate and send CAN messages on the network. It can be helpful to see the data generated in real-time using candump
.
- Run the following command in one terminal to display the CAN traffic in real-time. Use this terminal for all
candump
commands. The other terminal will be used forcansend
. Keep the following command running.
candump vcan0
- Generate random arbitration IDs and random data. Run this command and see if there are any visual changes on the vehicle simulator.
cangen vcan0
This command might run for a very long time before generating anything interesting in the simulator. Basically, cangen
is throwing monumental amounts of spaghetti at the wall to see what sticks, and very little will stick.
- Click on the terminal running
cangen
, then presscontrol+c
to stop the packet generation. Notice thatcandump
is still running, but no data is showing up on the network. - Generate random data for a specific arbitration ID. This might be helpful if you discovered an interesting arbitration ID, but are not sure how the data needs to be formatted. The following command generates random data but only for the arbitration ID
188
. After running the command, notice how the data is formatted.
cangen vcan0 -I 188
- Generate data for a specific arbitration ID using a fixed length of data. If you know the data needs to be a specific length, you can avoid generating meaningless data. But, you might not know what length you need before doing more exploration.
cangen vcan0 -I 188 -L 8
- In the
cangen
terminal, presscontrol+c
to stop the data generation. - In the
candump
terminal, presscontrol+c
to stop the data capture. Note that none of this data has been saved to a file. Instead, the data was only displayed on the screen.
Workflow for Data Exploration
One issue with cangen
is that it will create a ton of data, and unless you're capturing that data, it is nearly impossible to trace what happened. Therefore, cangen
is most useful when used in combination with candump
to save the traffic to a file. A challenge is finding the useful CAN data in a large candump
file with thousands of unique, random messages. At a high level, the workflow for analyzing data using cangen
is as follows.
- Start capturing data using
candump
. - Generate data using
cangen
until something happens. - Stop capturing.
- Stop the data generation.
- Replay portions of the captured data using
canplayer
until the event is reproduced. - You may need to use the controller to reset the conditions. For example, if you recorded a door unlock event, you may need to use the controller to lock the door before replaying events again.
Build the Haystack (of Data)
- In one terminal, run the following command to start capturing data.
candump vcan0 -l -f explore.txt
- In another terminal, run this command to generate data.
cangen vcan0
- Watch the ICSim window for any changes in the interface. For example, you might see the blinker blink, a door unlock, etc.
- You may need to watch for several minutes.
- When you see an interesting event, click in the terminal with
candump
and presscontrol+c
to stop capturing packets. - Next, click on the terminal running
cangen
and presscontrol+c
to stop generating traffic.
Find the Needle
- Look at how many packets were captured. The
wc
command counts words in files, but adding-l
tells it to count lines instead of individual words.
wc -l explore.txt
You may have tens of thousands of lines representing individual CAN messages.
- Explore the end of the file with
tail
.
tail explore.txt
- Open a third terminal window and start the controller. If you unlocked a door, you will want to re-lock that door before playing packets back. Otherwise, if the door is unlocked and you replace the unlock code, you will not know if it worked.
cd ~/ICSim
./controls vcan0 &
- Make a copy of the
explore.txt
file calledneedle.txt
.
cp explore.txt needle.txt
- You can split
needle.txt
into 10 separate files using thesplit
command. One of the 10 files will have the event that you're looking for. The following command splits the file into 10 files, breaking on lines, and using numbers at the end of the new filenames. Note that the option-n l/10
has a lowercasel
and not the number1
.
split -n l/10 -d needle.txt needle_
- Look at the newly created files using
ls
.
ls
You should see new files like:
needle_00 needle_01 needle_02
needle_03 needle_04 needle_05
needle_06 needle_07 needle_08
needle_09
Together, those files contain all of the data in needle.txt.
- Play each file back until you see the event triggered. You might want to start with the last file. The following command tells
canplayer
to use the input file namedneedle_09
.
canplayer -I needle_09
- Keep replaying the files until you see the event you wanted. You may have to go all the way to
needle_00
.
canplayer -I needle_08
canplayer -I needle_07
- In my case, the event was triggered in
needle_03
. I'll deleteneedle.txt
, renameneedle_03
toneedle.txt
and delete the other files that start withneedle_
.
rm needle.txt
mv needle_03 needle.txt
rm needle_*
- The file
needle.txt
now has 1/10 the data it had previously. So the search space for finding the CAN message that triggered the event is smaller. - Split
needle.txt
into 10 parts again.
split -n l/10 -d needle.txt needle_
- Replay the packets as you did previously. These now contain much less data, so they should replay quicker.
canplayer -I needle_09
canplayer -I needle_08
- In my case, the event was triggered in
needle_08
. I'll repeat the previous process. I'll deleteneedle.txt
, renameneedle_08
toneedle.txt
, and delete the other split files.
rm needle.txt
mv needle_08 needle.txt
rm needle_*
- Repeat this process until you have a manageable file size. You can check how many lines remain in the files using
wc -l
.
wc -l needle_01
In this example, the output shows that needle_01
only has 5 lines.
5 needle_01
- Eventually, the events will be filtered down enough that the
needle_
files have just a few lines. For example, after a few rounds, I had the following data inneedle_05
.
--$ cat needle_05
(1718224638.986934) vcan0 19B#00000E000000
(1718224638.987106) vcan0 244#000000013B
(1718224638.988156) vcan0 095#800007F400000026
(1718224638.991612) vcan0 166#D0320036
(1718224638.992813) vcan0 158#0000000000000037
- Once the list is small enough, you can use
cansend
to test the commands individually.
cansend vcan0 19B#00000E000000
cansend vcan0 244#000000013B
cansend vcan0 095#800007F400000026
cansend vcan0 166#D0320036
cansend vcan0 158#0000000000000037
This is a very iterative process. At its core, it's not a terribly complicated process, but it requires attention to detail. But at this point, you will know the arbitration ID and data that triggered the event.
Scripted Automation
I created a script to automate the process of looking for the "needle" in the "haystack" of events. The script automates the previous process.
- You can download a script to automate this named sift.sh.
- The script
sift.sh
has the following contents.
#!/bin/bash
# This script is used to replay a candump file and find the event that triggered an event.
# Check if the correct number of arguments are provided
if [ "$#" -lt 2 ]; then
echo "This script takes these parameters:"
echo " 1. The filename of the candump file"
echo " 2. The number of parts to split the file into in each iteration"
echo " 3. (optinal) The noise file to replay before the event"
echo "Syntax: $0 filename number_of_splits_per_iteration [noise_file]"
echo "Example: $0 candump.txt 10"
echo "Example: $0 candump.txt 12 noise.txt"
exit 1
fi
filename=$1
num_parts=$2
noise_file=$3
base_temp_name="haystack"
# Check that $num_parts is a number great than 0. Exit if it isn't.
if ! [[ $num_parts =~ ^[0-9]+$ ]] || [ $num_parts -le 0 ]; then
echo "num_parts must be a number greater than 0. Exiting."
exit 1
fi
# Check if the input exists, exit if it doesn't
if [ ! -f $filename ]; then
echo "File $filename does not exist. Please supply a valid file generated using candump. Exiting."
exit 1
fi
# Check if $filename is empty and exit if it is
if [ ! -s $filename ]; then
echo "File $filename is empty. Please supply a valid file generated using candump. Exiting."
exit 1
fi
# Check if $filename is a directory and exit if it is
if [ -d $filename ]; then
echo "$filename is a directory. Please supply a valid file generated using candump. Exiting."
exit 1
fi
# if $base_temp_name.txt exists, generate a new name until it is unique
while [ -f $base_temp_name.txt ]; do
echo "$base_temp_name.txt already exists. Generating a new name..."
base_temp_name="$base_temp_name$(date +%s)"
echo "New name: $base_temp_name.txt"
done
cp $filename $base_temp_name.txt
echo "$filename has been copied to $base_temp_name.txt"
line_count=$(wc -l $base_temp_name.txt | awk '{print $1}')
echo "$base_temp_name.txt has $line_count lines"
# Check if the noise_file parameter was supplied
if [ ! -z $noise_file ]; then
# Check if the noise_file exists, exit if it doesn't
if [ ! -f $noise_file ]; then
echo "File $noise_file does not exist. Please supply a valid file generated using candump. Exiting."
exit 1
fi
# Check if $noise_file is a directory and exit if it is
if [ -d $noise_file ]; then
echo "$noise_file is a directory. Please supply a valid file generated using candump. Exiting."
exit 1
fi
echo "Removing noise from $base_temp_name.txt using $noise_file..."
# Because timestamps in column 1 differ, only columns 2 and 3 are compared
awk 'NR==FNR{a[$2,$3];next} !(($2,$3) in a)' $noise_file $base_temp_name.txt > temp.txt
mv temp.txt $base_temp_name.txt
line_count=$(wc -l $base_temp_name.txt | awk '{print $1}')
echo "$base_temp_name.txt now has $line_count lines"
fi
while true; do
echo -e "\nSplitting $base_temp_name.txt into $num_parts parts...\n"
split -n l/$num_parts -d $base_temp_name.txt $base_temp_name.part.
echo "Ensure the system is in the proper state to begin testing for the event."
read -p "Enter 'c' to continue: " answer
# Loops through the files in reverse order, because its more likely the last one has the event
for file in $(ls -r $base_temp_name.part.*); do
line_count=$(wc -l $file | awk '{print $1}')
echo "Processing $file ($line_count lines)"
# if the line count is less than or equal to 10, print the contents of the file
if [ $line_count -le 10 ]; then
cat $file
fi
echo "Using canplayer to replay $file..."
canplayer -I $file
echo "Done replaying $file"
read -p "Did you see the event? (y/n/x): " answer
if [ "$answer" = "y" ] && [ $line_count -eq 1 ]; then
echo "Here is the event. It will be kept in $base_temp_name.txt:"
cat $file
rm $base_temp_name.txt
mv $file $base_temp_name.txt
rm $base_temp_name.part.*
exit 0
elif [ "$answer" = "y" ]; then
echo "$file will be retained as $base_temp_name.txt. All other $base_temp_name.part files will be deleted."
rm $base_temp_name.txt
mv $file $base_temp_name.txt
rm $base_temp_name.part.*
break # Will continue the outer while loop
elif [ "$answer" = "x" ]; then
echo "Exiting"
exit 0
fi
done
done
- In a Kali terminal, make a new folder.
cd ~
mkdir sift
cd sift
- Download the file to your
/home/kali/sift
directory. You can open Firefox in Kali and open this web page to download the file. - Make the file executable.
chmod +x sift.sh
- Run the program to view the syntax.
./sift.sh
- Optionally, create a new "noise" file.
candump vcan0 -l -f noise.txt
- Stop capturing the noise file after a few seconds or minutes depending on how much noise you want to capture.
- Start a new capture.
candump vcan0 -l -f event.txt
- Trigger an event using either the graphical controller or using
cangen
. - Stop the
candump
capture. - You should now have two 3 files in the
sift
directory:sift.sh
,noise.txt
, andevent.txt
. - Run the
sift
program and follow the prompts. - This first method does not filter out any noise.
./sift.sh event.txt 10
- This second method filters out noise to reduce the search space.
./sift.sh event.txt 5 noise.txt
Challenge
- Go through the process of finding a different event triggered by
cangen
. - You can try splitting the files into different numbers of parts, like 20 instead of 10.
- Can you develop a more efficient way of finding the needle in the haystack?
Shutting Down
- Close the ICSim window. You may have to click
Yes
to confirm closing it. - Close all terminals.
Reflection
- Should the car manufacturers just publish all of the arbitration IDs and data?
- How else might you find the signal in the noise?