Mirai Delete yourself

Why delete the executable ?

The Mirai malware uses a technique to remove itself from disk after executing has started. This adds additional complexity of attempting to fingerprint the malware by reducing the footprint of evidence of the attack taking place.

Deleting the executable file during run time does not make it impossible to recover the file, however it does add additionalx complexity while trying to analyse it in action.

Recovering an executable file.

The /proc filesystem will maintain a link to all files opened by an executing process even if the file has been removed from disk.

Each processes open files can be read from /proc/<numeric-pid>/exe

$ sudo ls -l /proc/975301/exe
lrwxrwxrwx. 1 root root 0 Nov  8 22:50 /proc/975301/exe -> /tmp/.malware/init

This is a regular file, and with root user permissions, the file can be copied for later inspection.

$ cat /proc/975301/exec >> ~/captured-executable

If the malware is a scripting language (Mirai is not), the actual executable script will be available in another location in the `/proc/<some-pid>/fd/

$ sudo ls -l /proc/975301/fd/
 total 0
 lr-x------. 1 root root 64 Nov 10 01:08 0 -> /dev/null
 lrwx------. 1 root root 64 Nov 10 01:08 1 -> 'socket:[38592]'
 l-wx------. 1 root root 64 Nov 10 01:08 10 -> /tmp/.malware/script.py

The sample code.

Mirai's self deletion code is simple and unerror checked.

// Delete self
unlink(args[0]);

See it in action here.

The unlink function deletes a file by name from the file system. It has a number of possible error conditions, but it appears that the author did not care about any of them.

Porting to rust.

To implement the same functionality in rust we first need to get the current processes executable file path.

Much like all languages, it is the first arguement in the processes args array.

Once we have the program path, it ss a simple matter of using rusts std::fs remove_file function to delete the file.

The process will continue to run normally and the file will be removed from disk during execution, and the process will continue to run.

use std::fs;

 fn main() {
   //// Delete the executing file to remove incriminating evidence
   let argv0 = std::env::args().next().unwrap(); // this will always exist.
   let _result = delete_file(&argv0);
 }

 fn delete_file(filename: &str) -> std::result::Result<(), std::io::Error> {
  info!("Deleting binary!");
  fs::remove_file(filename)?;
  Ok(())
 }

Having the executable 'missing' would be one of the big alarm bells for an intrustion detection system.

Perhaps a better option to make this harder to detect would be to move a legit binary, rename the malware to the exeutable in place delete the malware then put the original executable back.

This would be much harder to detect, especially if it communicated using the same ports and had the same process name.

I believe this would be similar to herpaderping on windows.

Resources:

Author: Wade mealing

Created: 2020-11-21 Sat 02:16