Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dict return type and updated test. #184

19 changes: 16 additions & 3 deletions docs/_docs/user-guide/eldritch.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,22 @@ The <b>file.write</b> method is very cool, and will be even cooler when Nick doc
The <b>process.kill</b> will kill a process using the KILL signal given its process id.

### process.list
`process.list() -> List<str>`

The <b>process.list</b> method will return a list of JSON strings representing the current process list. Eg. `"{pid:9,ppid:0,status:\"Sleeping\",username:\"root\",path:\"/bin/dash\",command:\"/bin/sh\",cwd:\"/\",environ:\"TERM_PROGRAM_VERSION=1.65.2 USER=root\",name:\"sh\"}"`
`process.list() -> List<Dict>`

The <b>process.list</b> method will return a list of dictionarys that describe each process. The dictionaries follow the schema:
```json
{
"pid": "9812",
"ppid": "1",
"status": "Sleeping",
"name": "golem",
"path": "/usr/bin/golem",
"username": "root",
"command": "/usr/bin/golem -i",
"cwd": "/root/",
"environ": "CARGO_PKG_REPOSITORY= CARGO_PKG_RUST_VERSION= CARGO_PKG_VERSION=0.1.0 CARGO_PKG_VERSION_MAJOR=0",
}
```

### process.name
`process.name(pid: int) -> str`
Expand Down
7 changes: 4 additions & 3 deletions implants/eldritch/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ mod name_impl;
use derive_more::Display;

use starlark::environment::{Methods, MethodsBuilder, MethodsStatic};
use starlark::values::dict::Dict;
use starlark::values::none::NoneType;
use starlark::values::{StarlarkValue, Value, UnpackValue, ValueLike, ProvidesStaticType};
use starlark::values::{StarlarkValue, Value, UnpackValue, ValueLike, ProvidesStaticType, Heap};
use starlark::{starlark_type, starlark_simple_value, starlark_module};

use serde::{Serialize,Serializer};
Expand Down Expand Up @@ -52,9 +53,9 @@ fn methods(builder: &mut MethodsBuilder) {
kill_impl::kill(pid)?;
Ok(NoneType{})
}
fn list(this: ProcessLibrary) -> anyhow::Result<Vec<String>> { //Should we use the JSON starlark type instead of String? Do I implement that here or somewhere else?
fn list<'v>(this: ProcessLibrary, starlark_heap: &'v Heap) -> anyhow::Result<Vec<Dict<'v>>> { //Should we use the JSON starlark type instead of String? Do I implement that here or somewhere else?
if false { println!("Ignore unused this var. _this isn't allowed by starlark. {:?}", this); }
list_impl::list()
list_impl::list(starlark_heap)
}
fn name(this: ProcessLibrary, pid: i32) -> anyhow::Result<String> {
if false { println!("Ignore unused this var. _this isn't allowed by starlark. {:?}", this); }
Expand Down
86 changes: 37 additions & 49 deletions implants/eldritch/src/process/list_impl.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,10 @@
use anyhow::{Result};
use starlark::{values::{dict::Dict, Heap, Value}, collections::SmallMap, const_frozen_string};
use sysinfo::{ProcessExt,System,SystemExt,PidExt};
use std::fmt;
#[cfg(not(target_os = "windows"))]
use sysinfo::{User,UserExt};

pub struct ProcessRes {
pid: u32,
ppid: u32,
status: String,
username: String,
path: String,
command: String,
cwd: String,
environ: String,
name: String,
}

impl fmt::Display for ProcessRes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{{pid:{},ppid:{},status:\"{}\",username:\"{}\",path:\"{}\",\
command:\"{}\",cwd:\"{}\",environ:\"{}\",name:\"{}\"}}",
&self.pid,
&self.ppid,
&self.status,
&self.username,
&self.path,
&self.command,
&self.cwd,
&self.environ,
&self.name,
)
}
}

pub fn list() -> Result<Vec<String>> {
pub fn list(starlark_heap: &Heap) -> Result<Vec<Dict>> {
if !System::IS_SUPPORTED {
return Err(anyhow::anyhow!("This OS isn't supported for process functions.
Pleases see sysinfo docs for a full list of supported systems.
Expand All @@ -42,7 +13,7 @@ pub fn list() -> Result<Vec<String>> {
#[cfg(target_os = "windows")]
const UNKNOWN_USER: &str = "???";

let mut res : Vec<String> = Vec::new();
let mut final_res: Vec<Dict> = Vec::new();
let mut sys = System::new();
sys.refresh_processes();
sys.refresh_users_list();
Expand All @@ -60,20 +31,29 @@ pub fn list() -> Result<Vec<String>> {
#[cfg(not(target_os = "windows"))]
let tmp_username = uid_to_username(process.uid, user_list);

let tmprow = ProcessRes{
pid: pid.as_u32(),
ppid: tmp_ppid,
status: process.status().to_string(),
username: tmp_username,
path: String::from(process.exe().to_str().unwrap()),
command: String::from(process.cmd().join(" ")),
cwd: String::from(process.cwd().to_str().unwrap()),
environ: String::from(process.environ().join(" ")),
name: String::from(process.name())
};
res.push(tmprow.to_string());
let res: SmallMap<Value, Value> = SmallMap::new();
// Create Dict type.
let mut tmp_res = Dict::new(res);

tmp_res.insert_hashed(const_frozen_string!("pid").to_value().get_hashed().unwrap(), Value::new_int(match pid.as_u32().try_into() {
Ok(local_int) => local_int,
Err(_) => -1,
}));
tmp_res.insert_hashed(const_frozen_string!("ppid").to_value().get_hashed().unwrap(), Value::new_int(match tmp_ppid.try_into() {
Ok(local_int) => local_int,
Err(_) => -1,
}));
tmp_res.insert_hashed(const_frozen_string!("status").to_value().get_hashed().unwrap(), starlark_heap.alloc_str(&process.status().to_string()).to_value());
tmp_res.insert_hashed(const_frozen_string!("username").to_value().get_hashed().unwrap(), starlark_heap.alloc_str(&tmp_username).to_value());
tmp_res.insert_hashed(const_frozen_string!("path").to_value().get_hashed().unwrap(), starlark_heap.alloc_str(&String::from(process.exe().to_str().unwrap())).to_value());
tmp_res.insert_hashed(const_frozen_string!("command").to_value().get_hashed().unwrap(), starlark_heap.alloc_str(&String::from(process.cmd().join(" "))).to_value());
tmp_res.insert_hashed(const_frozen_string!("cwd").to_value().get_hashed().unwrap(), starlark_heap.alloc_str(&String::from(process.cwd().to_str().unwrap())).to_value());
tmp_res.insert_hashed(const_frozen_string!("environ").to_value().get_hashed().unwrap(), starlark_heap.alloc_str(&String::from(process.environ().join(" "))).to_value());
tmp_res.insert_hashed(const_frozen_string!("name").to_value().get_hashed().unwrap(), starlark_heap.alloc_str(&String::from(process.name())).to_value());

final_res.push(tmp_res);
}
Ok(res)
Ok(final_res)
}

#[cfg(not(target_os = "windows"))]
Expand All @@ -98,18 +78,26 @@ mod tests {
#[cfg(target_os = "windows")]
let sleep_str = "timeout";

let child = Command::new(sleep_str)
println!("Starting sleep process");
hulto marked this conversation as resolved.
Show resolved Hide resolved
let mut child = Command::new(sleep_str)
.arg("5")
.spawn()?;

let res = list()?;
let searchstring = String::from(format!("pid:{}", child.id()));
println!("Testing command");
hulto marked this conversation as resolved.
Show resolved Hide resolved
let binding = Heap::new();
let res = list(&binding)?;
for proc in res{
if proc.as_str().contains(&searchstring) {
let cur_pid = match proc.get(const_frozen_string!("pid").to_value())? {
Some(local_cur_pid) => local_cur_pid.to_int()?,
None => return Err(anyhow::anyhow!("pid couldn't be unwrapped")),
};
if cur_pid as u32 == child.id() {
println!("Killing child PID {}", child.id());
hulto marked this conversation as resolved.
Show resolved Hide resolved
assert_eq!(true, true);
return Ok(())
}
}
println!("Nothing found failing");
hulto marked this conversation as resolved.
Show resolved Hide resolved
assert_eq!(true, false);
hulto marked this conversation as resolved.
Show resolved Hide resolved
return Ok(())
}
Expand Down