Skip to content

Commit

Permalink
sys.get_user() (#257)
Browse files Browse the repository at this point in the history
* Linux-Side Get User

* Fix Windows Implementation

* Add Test

* Fixup Windows Tests

---------

Co-authored-by: Hulto <[email protected]>
  • Loading branch information
jabbate19 and hulto authored Aug 14, 2023
1 parent 268b091 commit 9d2a792
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 2 deletions.
27 changes: 27 additions & 0 deletions docs/_docs/user-guide/eldritch.md
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,33 @@ An example is below:
"distro": "Debian GNU/Linux 10 (buster)",
"platform": "Linux"
}
```

### sys.get_user
`sys.get_user() -> Dict`

The <b>sys.get_user</b> method returns a dictionary that describes the current process's running user.
On *Nix, will return UID, EUID, GID, EGID, and detailed user info for the UID and EUID mappings.
For users, will return name and groups of user.

```json
{
"uid": {
"uid": 0,
"name": "root",
"gid": 0,
"groups": ["root"]
},
"euid": {
"uid": 0,
"name": "root",
"gid": 0,
"groups": ["root"]
},
"gid": 0,
"egid": 0
}
```

### sys.is_linux
`sys.is_linux() -> bool`
Expand Down
2 changes: 1 addition & 1 deletion implants/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ starlark = { git = "https://github.com/facebookexperimental/starlark-rust", rev
starlark_derive = { git = "https://github.com/facebookexperimental/starlark-rust", rev = "1109aaf9b700d7cdd7ba48986aa650221b70a22f" }
structopt = "0.3.23"
sys-info = "0.9.1"
sysinfo = "0.28.4"
sysinfo = "0.29.7"
tar = "0.4.38"
tavern = { path = "./lib/tavern" }
tempfile = "3.3.0"
Expand Down
2 changes: 1 addition & 1 deletion implants/lib/eldritch/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ mod tests {
r#"
dir(file) == ["append", "compress", "copy", "download", "exists", "hash", "is_dir", "is_file", "list", "mkdir", "read", "remove", "rename", "replace", "replace_all", "template", "timestomp", "write"]
dir(process) == ["kill", "list", "name"]
dir(sys) == ["dll_inject", "exec", "get_ip", "get_os", "is_linux", "is_macos", "is_windows", "shell"]
dir(sys) == ["dll_inject", "exec", "get_ip", "get_os", "get_user", "is_linux", "is_macos", "is_windows", "shell"]
dir(pivot) == ["arp_scan", "bind_proxy", "ncat", "port_forward", "port_scan", "smb_exec", "ssh_exec", "ssh_password_spray"]
dir(assets) == ["copy","list","read","read_binary"]
"#,
Expand Down
10 changes: 10 additions & 0 deletions implants/lib/eldritch/src/sys.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod exec_impl;
mod get_ip_impl;
mod get_os_impl;
mod get_user_impl;
mod is_linux_impl;
mod is_windows_impl;
mod is_macos_impl;
Expand Down Expand Up @@ -77,6 +78,15 @@ fn methods(builder: &mut MethodsBuilder) {
if false { println!("Ignore unused this var. _this isn't allowed by starlark. {:?}", this); }
get_ip_impl::get_ip(starlark_heap)
}
fn get_user<'v>(this: SysLibrary, starlark_heap: &'v Heap) -> anyhow::Result<Dict<'v>> {
if false {
println!(
"Ignore unused this var. _this isn't allowed by starlark. {:?}",
this
);
}
get_user_impl::get_user(starlark_heap)
}
fn is_linux(this: SysLibrary) -> anyhow::Result<bool> {
if false { println!("Ignore unused this var. _this isn't allowed by starlark. {:?}", this); }
is_linux_impl::is_linux()
Expand Down
186 changes: 186 additions & 0 deletions implants/lib/eldritch/src/sys/get_user_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
use anyhow::Result;
use starlark::collections::SmallMap;
use starlark::values::dict::Dict;
use starlark::values::Heap;
use starlark::{const_frozen_string, values::ValueLike};
use std::process;
use sysinfo::{Pid, ProcessExt, System, SystemExt, UserExt};

pub fn get_user(starlark_heap: &Heap) -> Result<Dict> {
let res = SmallMap::new();
let mut dict_res = Dict::new(res);
let user = SmallMap::new();
let mut dict_user = Dict::new(user);


let sys = System::new_all();
let pid = process::id() as usize;
if let Some(process) = sys.process(Pid::from(pid)) {
let uid = match process.user_id() {
Some(uid) => uid,
None => return Err(anyhow::anyhow!("Failed to get uid")),
};
#[cfg(target_os="windows")]
let uid_value = starlark_heap.alloc(uid.to_string());
#[cfg(not(target_os="windows"))]
let uid_value = starlark_heap.alloc(**uid);
dict_user.insert_hashed(
match const_frozen_string!("uid").to_value().get_hashed() {
Ok(val) => val,
Err(e) => return Err(anyhow::anyhow!("Failed to alloc uid information: {}", e)),
},
uid_value.to_value(),
);
let user = match sys.get_user_by_id(uid) {
Some(user) => user,
None => return Err(anyhow::anyhow!("Failed to get user")),
};
let user_name_value = starlark_heap.alloc_str(user.name());
dict_user.insert_hashed(
match const_frozen_string!("name").to_value().get_hashed() {
Ok(val) => val,
Err(e) => return Err(anyhow::anyhow!("Failed to alloc name information: {}", e)),
},
user_name_value.to_value(),
);
let user_gid_value = starlark_heap.alloc(*user.group_id());
dict_user.insert_hashed(
match const_frozen_string!("gid").to_value().get_hashed() {
Ok(val) => val,
Err(e) => return Err(anyhow::anyhow!("Failed to alloc gid information: {}", e)),
},
user_gid_value.to_value(),
);
let user_groups_value = starlark_heap.alloc(Vec::from(user.groups()));
dict_user.insert_hashed(
match const_frozen_string!("groups").to_value().get_hashed() {
Ok(val) => val,
Err(e) => return Err(anyhow::anyhow!("Failed to alloc groups information: {}", e)),
},
user_groups_value.to_value(),
);
#[cfg(not(target_os="windows"))]
{
let euser = SmallMap::new();
let mut dict_euser = Dict::new(euser);
let euid = match process.effective_user_id() {
Some(euid) => euid,
None => return Err(anyhow::anyhow!("Failed to get euid")),
};
let euid_value = starlark_heap.alloc(**euid);
dict_euser.insert_hashed(
match const_frozen_string!("uid").to_value().get_hashed() {
Ok(val) => val,
Err(e) => return Err(anyhow::anyhow!("Failed to alloc uid information: {}", e)),
},
euid_value.to_value(),
);
let euser = match sys.get_user_by_id(euid) {
Some(euser) => euser,
None => return Err(anyhow::anyhow!("Failed to get euser")),
};
let euser_name_value = starlark_heap.alloc_str(euser.name());
dict_euser.insert_hashed(
match const_frozen_string!("name").to_value().get_hashed() {
Ok(val) => val,
Err(e) => return Err(anyhow::anyhow!("Failed to alloc name information: {}", e)),
},
euser_name_value.to_value(),
);
let euser_gid_value = starlark_heap.alloc(*euser.group_id());
dict_euser.insert_hashed(
match const_frozen_string!("gid").to_value().get_hashed() {
Ok(val) => val,
Err(e) => return Err(anyhow::anyhow!("Failed to alloc gid information: {}", e)),
},
euser_gid_value.to_value(),
);
let euser_groups_value = starlark_heap.alloc(Vec::from(euser.groups()));
dict_euser.insert_hashed(
match const_frozen_string!("groups").to_value().get_hashed() {
Ok(val) => val,
Err(e) => return Err(anyhow::anyhow!("Failed to alloc groups information: {}", e)),
},
euser_groups_value.to_value(),
);
let dict_euser_value = starlark_heap.alloc(dict_euser);
dict_res.insert_hashed(
match const_frozen_string!("euid").to_value().get_hashed() {
Ok(val) => val,
Err(e) => return Err(anyhow::anyhow!("Failed to alloc euid information: {}", e)),
},
dict_euser_value,
);
let gid = match process.group_id() {
Some(gid) => gid,
None => return Err(anyhow::anyhow!("Failed to get gid")),
};
let gid_value = starlark_heap.alloc(*gid);
let egid = match process.effective_group_id() {
Some(egid) => egid,
None => return Err(anyhow::anyhow!("Failed to get egid")),
};
let egid_value = starlark_heap.alloc(*egid);
dict_res.insert_hashed(
match const_frozen_string!("gid").to_value().get_hashed() {
Ok(val) => val,
Err(e) => return Err(anyhow::anyhow!("Failed to alloc gid information: {}", e)),
},
gid_value.to_value(),
);
dict_res.insert_hashed(
match const_frozen_string!("egid").to_value().get_hashed() {
Ok(val) => val,
Err(e) => return Err(anyhow::anyhow!("Failed to alloc egid information: {}", e)),
},
egid_value.to_value(),
);
}
let dict_user_value = starlark_heap.alloc(dict_user);
dict_res.insert_hashed(
match const_frozen_string!("uid").to_value().get_hashed() {
Ok(val) => val,
Err(e) => return Err(anyhow::anyhow!("Failed to alloc uid information: {}", e)),
},
dict_user_value,
);
return Ok(dict_res);
}
Err(anyhow::anyhow!("Failed to obtain process information"))
}

#[cfg(test)]
mod tests {
use starlark::values::{UnpackValue, Value};
use super::*;

#[test]
fn test_sys_get_user() -> anyhow::Result<()>{
let test_heap = Heap::new();
let res = get_user(&test_heap)?;
let keys: Vec<&str> = res.keys().map(|key| key.unpack_str().unwrap()).collect();
assert!(keys.contains(&"uid"));
if !cfg!(target_os="windows") {
assert!(keys.contains(&"euid"));
assert!(keys.contains(&"egid"));
assert!(keys.contains(&"gid"));
}
let uid_data: Value<'_> = res.get(const_frozen_string!("uid").to_value())?.unwrap();
let uid_data_map: SmallMap<String, Value<'_>> = SmallMap::unpack_value(uid_data).unwrap();
let uid_data_keys: Vec<&str> = uid_data_map.keys().map(|key| &key[..]).collect();
assert!(uid_data_keys.contains(&"uid"));
assert!(uid_data_keys.contains(&"name"));
assert!(uid_data_keys.contains(&"gid"));
assert!(uid_data_keys.contains(&"groups"));
if !cfg!(target_os="windows") {
let euid_data: Value<'_> = res.get(const_frozen_string!("euid").to_value())?.unwrap();
let euid_data_map: SmallMap<String, Value<'_>> = SmallMap::unpack_value(euid_data).unwrap();
let euid_data_keys: Vec<&str> = euid_data_map.keys().map(|key| &key[..]).collect();
assert!(euid_data_keys.contains(&"uid"));
assert!(euid_data_keys.contains(&"name"));
assert!(euid_data_keys.contains(&"gid"));
assert!(euid_data_keys.contains(&"groups"));
}
Ok(())
}
}

0 comments on commit 9d2a792

Please sign in to comment.