added abuseipdb check

This commit is contained in:
theopfr
2023-05-24 23:43:44 +02:00
parent c3b7bf7366
commit 5ac60d480d
6 changed files with 116 additions and 113 deletions

View File

@@ -1,44 +1,48 @@
use std::error::Error;
use reqwest;
use std::{error::Error, env};
use reqwest::{self, Response};
use serde_json::{json, Value};
/// this doesnt work yet
pub fn get_ip_audit() -> Result<(), Box<dyn Error>> {
let url = "https://api.abuseipdb.com/api/v2/check";
pub fn get_ip_audit(remote_ip: &String, verbose: bool) -> Result<Option<i64>, Box<dyn Error>> {
let abuseipdb_api_key: String = match env::var("ABUSEIPDB_API_KEY") {
Ok(val) => val,
Err(_e) => {
if verbose {
println!("Couldn't find AbuseIPDB API key. If you want to use this feature make sure to put the API key into the environment variable 'ABUSEIPDB_API_KEY'.");
}
return Ok(None);
},
};
let client = reqwest::blocking::Client::new();
let ips = vec!["127.0.0.1", "192.168.0.1", "10.0.0.1"];
let params = json!({
"ip": ips,
"maxAgeInDays": 30,
"verbose": true,
});
let response = client.get(url)
.header("Key", "...")
let url = "https://api.abuseipdb.com/api/v2/check";
let params = [
("ipAddress", remote_ip),
("maxAgeInDays", &("40".to_string())),
];
let response: reqwest::blocking::Response = client
.get(url)
.header("Key", abuseipdb_api_key)
.header("Accept", "application/json")
.query(&params)
.send()?;
// check if the request was successful
if response.status().is_success() {
let json_response: Value = response.json()?;
println!("hdfhdfh");
for ip_result in json_response["data"].as_array().unwrap() {
let ip = &ip_result["ipAddress"];
let abuse_confidence_score = &ip_result["abuseConfidenceScore"];
let abuse_confidence_score: Option<i64> = json_response["data"]["abuseConfidenceScore"].as_i64();
println!("IP: {}, Score: {}", ip, abuse_confidence_score);
}
} else {
println!("Request failed with status code: {}", response.status());
return Ok(abuse_confidence_score);
}
else {
println!("AbuseIPDB Request failed with status code: {}", response.status());
return Ok(None);
}
Ok(())
}
@@ -49,7 +53,7 @@ pub fn check_if_known(remote_ip: &str) -> String {
return format!("*{}*", remote_ip.to_string());
}
else if remote_ip == "127.0.0.1" || remote_ip == "[::1]" {
return format!("{} *localhost*", remote_ip.to_string());
return format!("*{} localhost*", remote_ip.to_string());
}
return remote_ip.to_string();
}

View File

@@ -62,8 +62,6 @@ struct Args {
pub fn cli() -> FlagValues {
let args = Args::parse();
println!("{:?}", args.kill);
let flag_values = FlagValues {
check: args.check,
kill: args.kill,
@@ -81,22 +79,28 @@ pub fn cli() -> FlagValues {
}
//
// kills aprocess by PID
pub fn kill_process(pid: &String) {
let output = process::Command::new("kill")
.arg(pid)
.output()
.expect(&format!("Failed to kill process with PID {}", pid));
if output.status.success() {
println!("Killed process with PID {}.", pid);
}
}
// select option for choosing a process to kill
pub fn interactve_process_kill(connections: &Vec<connections::Connection>) {
let selection: Result<u32, InquireError> = Select::new("Which process to kill (search or type index)?", (1..=connections.len() as u32).collect()).prompt();
match selection {
Ok(choice) => {
let output = process::Command::new("kill")
.arg(&connections[choice as usize - 1].pid)
.output()
.expect(&format!("Failed to kill process with PID {}", choice));
if output.status.success() {
println!("Killed process with PID {}.", choice);
}
let pid: &String = &connections[choice as usize - 1].pid;
kill_process(&pid);
},
Err(_) => println!("Couldn't find process."),
}
}

View File

@@ -1,14 +1,12 @@
use procfs;
use procfs::process::Stat;
use procfs::process::FDTarget;
use std::collections::HashMap;
use crate::string_utils;
use crate::address_checkers;
#[derive(Debug)]
pub struct FilterOptions {
pub by_proto: Option<String>,
pub by_program: Option<String>,
@@ -30,13 +28,12 @@ pub struct Connection {
pub program: String,
pub pid: String,
pub state: String,
pub abuse_score: Option<i64>
}
/// gets all running processes on the system
fn get_processes() -> HashMap<u64, Stat> {
/* gets all running processes on the system */
let all_procs = procfs::process::all_processes().unwrap();
let mut map: HashMap<u64, Stat> = HashMap::new();
@@ -86,7 +83,7 @@ fn filter_out_connection(connection_details: &Connection, filter_options: &Filte
/// gets all open tcp connectections
fn get_tcp_connections(all_processes: &HashMap<u64, Stat>, filter_options: &FilterOptions) -> Vec<Connection> {
fn get_tcp_connections(all_processes: &HashMap<u64, Stat>, filter_options: &FilterOptions, check_malicious: bool) -> Vec<Connection> {
let mut tcp = procfs::net::tcp().unwrap();
if !filter_options.exclude_ipv6 {
tcp.extend(procfs::net::tcp6().unwrap());
@@ -111,20 +108,27 @@ fn get_tcp_connections(all_processes: &HashMap<u64, Stat>, filter_options: &Filt
pid = "-".to_string();
}
let connection: Connection = Connection {
let mut connection: Connection = Connection {
proto: "tcp".to_string(),
local_port: local_port,
remote_address: remote_address,
remote_address: (&remote_address).to_string(),
remote_port: remote_port,
program: program,
pid: pid,
state: state,
abuse_score: None
};
// check if connection should be filtered out
let filter_connection: bool = filter_out_connection(&connection, filter_options);
if filter_connection {
continue;
}
// if malicious-check is activated, get an abuse score from AbuseIPDB.com
if check_malicious {
connection.abuse_score = address_checkers::get_ip_audit(&remote_address, false).unwrap_or(Some(-1i64));
}
all_tcp_connections.push(connection);
}
@@ -134,7 +138,7 @@ fn get_tcp_connections(all_processes: &HashMap<u64, Stat>, filter_options: &Filt
/// gets all open udp connectections
fn get_udp_connections(all_processes: &HashMap<u64, Stat>, filter_options: &FilterOptions) -> Vec<Connection> {
fn get_udp_connections(all_processes: &HashMap<u64, Stat>, filter_options: &FilterOptions, check_malicious: bool) -> Vec<Connection> {
let mut udp = procfs::net::udp().unwrap();
if !filter_options.exclude_ipv6 {
udp.extend(procfs::net::udp6().unwrap());
@@ -159,20 +163,27 @@ fn get_udp_connections(all_processes: &HashMap<u64, Stat>, filter_options: &Filt
pid = "-".to_string();
}
let connection: Connection = Connection {
let mut connection: Connection = Connection {
proto: "udp".to_string(),
local_port: local_port,
remote_address: remote_address,
remote_address: (&remote_address).to_string(),
remote_port: remote_port,
program: program,
pid: pid,
state: state,
abuse_score: None
};
// check if connection should be filtered out
let filter_connection: bool = filter_out_connection(&connection, filter_options);
if filter_connection {
continue;
}
// if malicious-check is activated, get an abuse score from AbuseIPDB.com
if check_malicious {
connection.abuse_score = address_checkers::get_ip_audit(&remote_address, false).unwrap_or(Some(-1i64));
}
all_udp_connections.push(connection);
}
@@ -183,17 +194,17 @@ fn get_udp_connections(all_processes: &HashMap<u64, Stat>, filter_options: &Filt
// gets all tcp and udp connections
pub fn get_all_connections(filter_options: &FilterOptions) -> Vec<Connection> {
pub fn get_all_connections(filter_options: &FilterOptions, check_malicious: bool) -> Vec<Connection> {
let all_processes: HashMap<u64, Stat> = get_processes();
match &filter_options.by_proto {
Some(filter_proto) if filter_proto == "tcp" => return get_tcp_connections(&all_processes, filter_options),
Some(filter_proto) if filter_proto == "udp" => return get_udp_connections(&all_processes, filter_options),
Some(filter_proto) if filter_proto == "tcp" => return get_tcp_connections(&all_processes, filter_options, check_malicious),
Some(filter_proto) if filter_proto == "udp" => return get_udp_connections(&all_processes, filter_options, check_malicious),
_ => { }
}
let mut all_connections = get_tcp_connections(&all_processes, filter_options);
let all_udp_connections = get_udp_connections(&all_processes, filter_options);
let mut all_connections = get_tcp_connections(&all_processes, filter_options, check_malicious);
let all_udp_connections = get_udp_connections(&all_processes, filter_options, check_malicious);
all_connections.extend(all_udp_connections);
return all_connections;

View File

@@ -1,23 +1,13 @@
use termimad::crossterm::style::{Color::*};
use termimad::*;
use reqwest;
use std::error::Error;
mod connections;
mod processes;
mod address_checkers;
mod string_utils;
mod table;
mod interactive;
mod cli;
fn main() {
let args: cli::FlagValues = cli::cli();
let mut args: cli::FlagValues = cli::cli();
// example filter option: Some("tcp".to_string())
let filter_options: connections::FilterOptions = connections::FilterOptions {
@@ -31,8 +21,20 @@ fn main() {
exclude_ipv6: args.exclude_ipv6
};
if args.check {
println!("Checking IPs using AbuseIPDB.com...");
let abuse_result = address_checkers::get_ip_audit(&("127.0.0.1cc".to_string()), true).unwrap();
match abuse_result {
Some(_) => { }
None => {
println!("Cancelling IP abuse check.");
args.check = false;
}
}
}
// get running processes
let all_connections: Vec<connections::Connection> = connections::get_all_connections(&filter_options);
let all_connections: Vec<connections::Connection> = connections::get_all_connections(&filter_options, args.check);
table::get_connections_table(&all_connections, args.check);

View File

@@ -1,24 +0,0 @@
use procfs;
use procfs::process::FDTarget;
use procfs::process::Stat;
use std::collections::HashMap;
pub fn get_processes() -> HashMap<u64, Stat> {
/* gets all running processes on the system */
let all_procs = procfs::process::all_processes().unwrap();
let mut map: HashMap<u64, Stat> = HashMap::new();
for p in all_procs {
let process = p.unwrap();
if let (Ok(stat), Ok(fds)) = (process.stat(), process.fd()) {
for fd in fds {
if let FDTarget::Socket(inode) = fd.unwrap().target {
map.insert(inode, stat.clone());
}
}
}
}
return map;
}

View File

@@ -35,17 +35,21 @@ pub fn get_connections_table(all_connections: &Vec<connections::Connection>, che
// check if the remote IP is a DNS server
let remote_address = &connection.remote_address;
let remote_address_new = &address_checkers::check_if_known(remote_address);
/*if check_malicious_adresses {
// check if the remote IP is malicious using the AbuseIpDb API
let (marked_remote_addess, checked) = address_checkers::check_if_malicious(&remote_address_new);
remote_address_new = &marked_remote_addess;
checked_ip_status = checked;
}*/
let checked_remote_address: String;
if connection.abuse_score >= Some(50) {
checked_remote_address = format!("{} ~~malicious~~", &remote_address_new);
}
else if connection.abuse_score == Some(0) {
checked_remote_address = format!("{} **✓**", &remote_address_new);
}
else {
checked_remote_address = (&remote_address_new).to_string();
}
// add row with connection information
markdown.push_str(&format!("| *{}* | {} | {} | {} | {} | {}*/{}* | {} |\n",
idx + 1, connection.proto, connection.local_port, &remote_address_new, connection.remote_port, connection.program, connection.pid, connection.state
idx + 1, connection.proto, connection.local_port, &checked_remote_address, connection.remote_port, connection.program, connection.pid, connection.state
));
}
@@ -56,19 +60,21 @@ pub fn get_connections_table(all_connections: &Vec<connections::Connection>, che
markdown.push_str(&terminal_filling_row);
markdown.push_str(CENTER_MARKDOWN_ROW);
// print information about checking malicious IPs
markdown.push_str("\n*Info:*");
if checked_ip_status == 1 {
markdown.push_str("\n*Successfully checked remote IPs with the AbuseIpDB API.*\n");
}
else if checked_ip_status == 0 {
markdown.push_str("\n*If you want somo to automatically check for malicious IP addresses in your connections, make an account at `www.abuseipdb.com` and add your API key as an env variable: `ABUSEIPDB_API_KEY={your-api-key}`.*\n");
}
else if checked_ip_status == -1 {
markdown.push_str("\n~~A~~ *Couldn't reach the AbuseIpDB API to check for malicious IP address in your connections.*\n");
markdown.push_str("*Possible problems:*\n");
markdown.push_str("*1. API down or new non-backward compatible changes -> check if there is a new version of somo avaialble *\n");
markdown.push_str("*2. wrong or expired API key stored in the `ABUSEIPDB_API_KEY` env variable *\n");
if check_malicious_adresses {
// print information about checking malicious IPs
markdown.push_str("\n*Info:*");
if checked_ip_status == 1 {
markdown.push_str("\n*Successfully checked remote IPs with the AbuseIpDB API.*\n");
}
else if checked_ip_status == 0 {
markdown.push_str("\n*If you want somo to automatically check for malicious IP addresses in your connections, make an account at `www.abuseipdb.com` and add your API key as an env variable: `ABUSEIPDB_API_KEY={your-api-key}`.*\n");
}
else if checked_ip_status == -1 {
markdown.push_str("\n~~A~~ *Couldn't reach the AbuseIpDB API to check for malicious IP address in your connections.*\n");
markdown.push_str("*Possible problems:*\n");
markdown.push_str("*1. API down or new non-backward compatible changes -> check if there is a new version of somo avaialble *\n");
markdown.push_str("*2. wrong or expired API key stored in the `ABUSEIPDB_API_KEY` env variable *\n");
}
}
println!("{}\n", skin.term_text(&markdown));