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
cangento generate network traffic, - use
candumpto record network traffic to a file, - use
canreplayto 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-utilshas been installed,ICSimhas been installed to~/ICSim.
Reset Applications
- Close the ICSim and controller applications, if they are running.
- Stop
cansnifferif 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
~/ICSimdirectory.
cd ~/ICSim
- Create the
vcan0network. Thisvcan0network 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
vcan0network 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.shand see a message like, "RTNETLINK answers: File exists," this means that thevcan0network 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
~/ICSimbefore running this command. You will likely have to press theentertwice 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
~/ICSimdirectory.
cd ~/ICSim
- At this point, you should have 3 windows: 1) the ICSim graphical user interface, 2) a terminal with the
~/ICSimworking directory, and 3) another terminal with the~/ICSimworking 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
candumpcommands. 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+cto stop the packet generation. Notice thatcandumpis 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
cangenterminal, presscontrol+cto stop the data generation. - In the
candumpterminal, presscontrol+cto 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
cangenuntil something happens. - Stop capturing.
- Stop the data generation.
- Replay portions of the captured data using
canplayeruntil 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
candumpand presscontrol+cto stop capturing packets. - Next, click on the terminal running
cangenand presscontrol+cto stop generating traffic.
Find the Needle
- Look at how many packets were captured. The
wccommand counts words in files, but adding-ltells 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.txtfile calledneedle.txt.
cp explore.txt needle.txt
- You can split
needle.txtinto 10 separate files using thesplitcommand. 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/10has a lowercaseland 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
canplayerto 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_03toneedle.txtand delete the other files that start withneedle_.
rm needle.txt
mv needle_03 needle.txt
rm needle_*
- The file
needle.txtnow 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.txtinto 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_08toneedle.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
cansendto 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.shhas 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/siftdirectory. 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
candumpcapture. - You should now have two 3 files in the
siftdirectory:sift.sh,noise.txt, andevent.txt. - Run the
siftprogram 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
Yesto 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?