Week Review 9/29/2023
Continued Work on Battery Holder
While I was waiting for the radios to come in I made the cylindrical battery holder in CAD. Later in the week Ben Wirz cleaned up the model.
The limit for voltage on non-ROV devices in the MATE ROV competition in 12 volts, so we are putting 8 AA batteries in it (8*1.5=12).
Testing Radios
The replacement RFM69HCW radios came in from Adafruit. We bought the 433MHz Spring Antenna with them.
The range was much better with the new radios. This makes me think that the old radios were broken by whoever used them before me.
Writing Arduino Code
I started by taking a closer look at the example code provided by the Radiohead library. When looking at the part of the code that receives data I saw something suspicious.
uint8_t buf[RH_RF69_MAX_MESSAGE_LEN];
Serial.println(RH_RF69_MAX_MESSAGE_LEN);
uint8_t len = sizeof(buf);
if (rf69.waitAvailableTimeout(500)) {
// Should be a reply message for us now
if (rf69.recv(buf, &len)) {
Serial.println(len);
Serial.print("Got a reply: ");
Serial.println((char*)buf);
It is making a buffer with a fixed size and passing a pointer of it into a function that recieves data. Seeing that it also passes a length variable is was a good sign but I thought it would be a good idea to make sure that the rf69.recv()
function protected from buffer overflows.
After looking at the function I saw that it did not. Although it checks if the len
variable was correct, it does not stop the memcpy()
function from running if the buffer it is getting from SPI is larger than the buffer allocated in memory for it. This makes it possible for an attacker to write arbitrary data into the buffer. This is a condition called a buffer overflow.
bool RH_RF69::recv (uint8_t* buf, uint8_t* len)
{
if (!available())
return false;
if (buf && len)
{
ATOMIC_BLOCK_START;
if (*len > _bufLen)
*len = _bufLen;
memcpy (buf, _buf, *len);
ATOMIC_BLOCK_END;
}
_rxBufValid = false; // Got the most recent message
// printBuffer("recv:", buf, *len);
return true;
}
What is a Buffer Overflow
A buffer overflow is a condition where the size of user entered data is not checked before being written to a buffer. When data that is larger than a buffer is being written to it, after the buffer is full the data will be written into whatever memory comes next.
This can be exploited by putting malicious commands into memory. A thorough explanation of how to do this is outside the scope of this blog, but LiveOverflow made a very good youtube video that explains buffer overflow attacks with an example.
Fixing the Vulnerability
Fixing this vulnerability is fairly simple. We just need to code to check if _buf
is bigger than buf
before writing to it. I edited the rf69.recv()
function to make it more secure. The updated version of the function is below.
bool RH_RF69::recv (uint8_t* buf, uint8_t* len)
{
if (!available())
return false;
if (buf && len)
{
ATOMIC_BLOCK_START;
if (*len > _bufLen)
{
*len = _bufLen;
if (buf >= _buf){
memcpy (buf, _buf, *len);
}
}
ATOMIC_BLOCK_END;
}
_rxBufValid = false; // Got the most recent message
// printBuffer("recv:", buf, *len);
return true;
}
I submitted a pull request, but the maintainer has not accepted it yet. The project seems like it might be abandoned so I don’t know if that change will ever made it downstream. If you are using the RF69HCW it might be a good idea to use my fork of the project.
To be clear I did not fix all of the vulnerabilities in this library; I only patched the rf69.recv()
function specifically. Looking at other radios included in this library, the same vulnerability is present. If anyone wants to try their hand at finding binary exploitation vulnerabilities in the wild, I would recommend looking at this library, and more generally Arduino libraries.
“The S in IoT stands for security” -Tin Kadlec
Setting Up A Connection Sequence
We need a predetermined sequence for connecting the float to the topside. In packet radio you have RX and TX. TX is the initial transmitter and TX will send responses. I plan on having the float be TX because it will make the topside silent until there is a connection.
I am going to have the float send out pings until it connects to the station above the water. Once it connects it will start uploading the depth data. When it is done uploading the depth data it will do another profile.