Skip to content

Commit

Permalink
feat: version 0.7.2 (#108)
Browse files Browse the repository at this point in the history
* feat: display of unlinked clients when no ap is selected
* feat: use of xterm as decryption terminal
* feat: popover menu when right-clicking on aps and clients list to copy rows
* fix: keep original first time seen values
* fix: error management
* fix: buttons sensitivity management

Signed-off-by: Martin Olivier <[email protected]>
  • Loading branch information
martin-olivier authored Apr 13, 2024
1 parent d7b4698 commit f9ba508
Show file tree
Hide file tree
Showing 21 changed files with 642 additions and 397 deletions.
3 changes: 2 additions & 1 deletion .fpm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-s dir ./target/release/airgorah ./icons/app_icon.png package README.md LICENSE
--name airgorah
--license MIT
--version 0.7.1
--version 0.7.2
--description "A WiFi auditing software that can perform deauth attacks and passwords cracking"
--url "https://github.com/martin-olivier/airgorah"
--maintainer "Martin Olivier <[email protected]>"
Expand All @@ -10,6 +10,7 @@
--conflicts airgorah

--depends bash
--depends xterm
--depends iw
--depends macchanger
--depends aircrack-ng
Expand Down
Binary file modified .github/assets/illustration.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[package]
name = "airgorah"
version = "0.7.1"
version = "0.7.2"
edition = "2021"
license = "MIT"
description = "A WiFi auditing software that can perform deauth attacks and passwords cracking"
description = "A WiFi security auditing software mainly based on aircrack-ng tools suite"
authors = ["Martin Olivier <[email protected]>"]
homepage = "https://github.com/martin-olivier/airgorah"
repository = "https://github.com/martin-olivier/airgorah"
Expand All @@ -29,6 +29,7 @@ nix = { version = "0.28", features = ["signal"] }
ureq = { version = "2.9", features = ["json"] }
log = "0.4"
env_logger = "0.11"
thiserror = "1"

[build-dependencies]
serde = { version = "1", features = ["derive"] }
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Airgorah</h1>

<p align="center">
<span>A WiFi auditing software that can perform deauth attacks and passwords cracking</span>
<span>A WiFi security auditing software mainly based on <a href="https://github.com/aircrack-ng/aircrack-ng">aircrack-ng</a> tools suite</span>
</p>

<p align="center">
Expand All @@ -20,9 +20,9 @@ Airgorah</h1>
[![aur](https://img.shields.io/aur/version/airgorah)](https://aur.archlinux.org/packages/airgorah)
[![ci](https://github.com/martin-olivier/airgorah/actions/workflows/CI.yml/badge.svg)](https://github.com/martin-olivier/airgorah/actions/workflows/CI.yml)

`Airgorah` is a WiFi auditing software that can discover the clients connected to an access point, perform deauthentication attacks against specific clients, capture WPA handshakes, and crack the password of the access point.
`Airgorah` is a WiFi security auditing software that can capture nearby WiFi traffic, discover clients connected to access points, perform deauthentication attacks, capture handshakes, and crack the password of access points.

It is written in Rust and uses [GTK4](https://github.com/gtk-rs/gtk4-rs) for the graphical part. The software is mainly based on [aircrack-ng](https://github.com/aircrack-ng/aircrack-ng) tools suite.
It is written in Rust and uses [GTK4](https://github.com/gtk-rs/gtk4-rs) for the graphical part.

`⭐ Don't forget to put a star if you like the project!`

Expand Down
30 changes: 19 additions & 11 deletions src/backend/app.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
use super::*;
use crate::error::Error;
use crate::globals::*;

/// Check if the user is root, and if all the dependencies are installed
pub fn app_setup() -> Result<(), Error> {
#[derive(thiserror::Error, Debug)]
pub enum AppError {
#[error("Could not setup Ctrl-C (SIGINT) handler: {0}")]
SigintHandler(#[from] ctrlc::Error),

#[error("Airgorah need root privilege to run")]
NotRoot,

#[error("Missing required dependency: {0}")]
MissingDependency(String),
}

/// Check if the user is root, load settings, and check if all the required dependencies are installed
pub fn app_setup() -> Result<(), AppError> {
app_cleanup();

ctrlc::set_handler(move || {
app_cleanup();
std::process::exit(1);
})
.expect("Error setting Ctrl-C handler");
})?;

if sudo::check() != sudo::RunningAs::Root {
return Err(Error::new("Airgorah need root privilege to run"));
return Err(AppError::NotRoot);
}

load_settings();
Expand All @@ -23,6 +33,7 @@ pub fn app_setup() -> Result<(), Error> {
"ip",
"iw",
"awk",
"xterm",
"airmon-ng",
"airodump-ng",
"aireplay-ng",
Expand Down Expand Up @@ -53,13 +64,10 @@ pub fn has_dependency(dep: &str) -> bool {
}

/// Check if all the required dependencies are installed
pub fn check_required_dependencies(deps: &[&str]) -> Result<(), Error> {
pub fn check_required_dependencies(deps: &[&str]) -> Result<(), AppError> {
for dep in deps {
if !has_dependency(dep) {
return Err(Error::new(&format!(
"Missing required dependency: \"{}\"",
dep,
)));
return Err(AppError::MissingDependency(dep.to_string()));
}
}
Ok(())
Expand Down
54 changes: 49 additions & 5 deletions src/backend/capture.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
use super::*;
use crate::error::Error;
use crate::globals::*;
use crate::types::*;

use regex::Regex;
use serde::Serialize;
use std::fs::File;
use std::io::Write;
use std::process::Command;

#[derive(Debug, Serialize)]
struct Report {
pub access_points: Vec<AP>,
pub unlinked_clients: Vec<Client>,
}

#[derive(thiserror::Error, Debug)]
pub enum CapError {
#[error("Input/Output error: {0}")]
IoError(#[from] std::io::Error),

#[error("Regex error: {0}")]
BadRegex(#[from] regex::Error),

#[error("Json error: {0}")]
JsonError(#[from] serde_json::Error),
}

/// Update the handshake capture status of all APs
pub fn update_handshakes() -> Result<(), Error> {
pub fn update_handshakes() -> Result<(), CapError> {
let handshakes = get_handshakes([
&(LIVE_SCAN_PATH.to_string() + "-01.cap"),
&(OLD_SCAN_PATH.to_string() + "-01.cap"),
Expand All @@ -26,7 +47,7 @@ pub fn update_handshakes() -> Result<(), Error> {
}

/// Get the access points infos of the handshakes contained in the capture file
pub fn get_handshakes<I, S>(args: I) -> Result<Vec<(String, String)>, Error>
pub fn get_handshakes<I, S>(args: I) -> Result<Vec<(String, String)>, CapError>
where
I: IntoIterator<Item = S>,
S: AsRef<std::ffi::OsStr>,
Expand Down Expand Up @@ -64,10 +85,33 @@ where
}

/// Save the current capture to a file
pub fn save_capture(path: &str) -> Result<(), Error> {
pub fn save_capture(path: &str) -> Result<(), CapError> {
std::fs::copy(OLD_SCAN_PATH.to_string() + "-01.cap", path)?;

log::info!("capture saved to \"{}\"", path);
log::info!("capture saved to '{}'", path);

Ok(())
}

/// Save the capture report to a file
pub fn save_report(path: &str) -> Result<(), CapError> {
let access_points = get_aps().values().cloned().collect::<Vec<AP>>();
let unlinked_clients = get_unlinked_clients()
.values()
.cloned()
.collect::<Vec<Client>>();

let report = Report {
access_points,
unlinked_clients,
};

let json_data = serde_json::to_string::<Report>(&report)?;

let mut file = File::create(path)?;
file.write_all(json_data.as_bytes())?;

log::info!("report saved to '{}'", path);

Ok(())
}
9 changes: 7 additions & 2 deletions src/backend/deauth.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
use crate::error::Error;
use crate::globals::*;
use crate::types::*;
use std::process::{Command, Stdio};
use std::sync::MutexGuard;

#[derive(thiserror::Error, Debug)]
pub enum DeathError {
#[error("Input/Output error: {0}")]
IoError(#[from] std::io::Error),
}

/// Launch a deauth attack on a specific AP
pub fn launch_deauth_attack(
iface: &str,
ap: AP,
specific_clients: Option<Vec<String>>,
software: AttackSoftware,
) -> Result<(), Error> {
) -> Result<(), DeathError> {
let mut attack_pool = get_attack_pool();

let attack_targets = match specific_clients {
Expand Down
92 changes: 25 additions & 67 deletions src/backend/decrypt.rs
Original file line number Diff line number Diff line change
@@ -1,61 +1,14 @@
use super::*;
use crate::error::Error;
use std::process::{Command, Stdio};

const CRUNCH_LOWERCASE: &str = "abcdefghijklmnopqrstuvwxyz";
const CRUNCH_UPPERCASE: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const CRUNCH_NUMBERS: &str = "0123456789";
const CRUNCH_SYMBOLS: &str = " @!#$%^&*()-_+=~`[]{}|:;<>,.?/\\";

/// Get the terminal emulator
pub fn build_terminal(title: String, command: String) -> Result<Command, Error> {
let err_msg = Error::new("No supported terminal found, please install one of the following:\nxfce4-terminal, gnome-terminal, konsole");

if has_dependency("xfce4-terminal") {
let mut process = Command::new("xfce4-terminal");
process.stdin(Stdio::piped());
process.args([
"--hide-menubar",
"--hide-toolbar",
"--hide-scrollbar",
"--hold",
"-T",
&title,
"-e",
&format!("sh -c \"{}\"", command),
]);
Ok(process)
} else if has_dependency("gnome-terminal") {
let mut process = Command::new("gnome-terminal");
process.stdin(Stdio::piped());
process.args([
"--hide-menubar",
"--title",
&title,
"--",
"sh",
"-c",
&format!("{} ; exec sh", command),
]);
Ok(process)
} else if has_dependency("konsole") {
let mut process = Command::new("konsole");
process.stdin(Stdio::piped());
process.args([
"--hide-menubar",
"--hide-tabbar",
"--hold",
"-p",
&format!("title={}", title),
"-e",
"sh",
"-c",
&command,
]);
Ok(process)
} else {
Err(err_msg)
}
#[derive(thiserror::Error, Debug)]
pub enum DecryptError {
#[error("Input/Output error: {0}")]
IoError(#[from] std::io::Error),
}

/// Launch a new terminal window to run aircrack-ng to decrypt a handshake with the specified wordlist
Expand All @@ -64,18 +17,24 @@ pub fn run_decrypt_wordlist_process(
bssid: &str,
essid: &str,
wordlist: &str,
) -> Result<(), Error> {
) -> Result<(), DecryptError> {
let title = format!("Handshake Decryption ({})", essid);
let cmd = format!(
"aircrack-ng '{}' -b '{}' -w '{}'",
handshake, bssid, wordlist
);

let mut process = build_terminal(title, cmd)?;

std::thread::spawn(move || {
process.output().unwrap();
});
Command::new("xterm")
.stdin(Stdio::null())
.args([
"-hold",
"-T",
&title,
"-e",
"aircrack-ng",
handshake,
"-b",
bssid,
"-w",
wordlist,
])
.spawn()?;

Ok(())
}
Expand All @@ -89,7 +48,7 @@ pub fn run_decrypt_bruteforce_process(
up: bool,
num: bool,
sym: bool,
) -> Result<(), Error> {
) -> Result<(), DecryptError> {
let charset = format!(
"{}{}{}{}",
match low {
Expand All @@ -115,11 +74,10 @@ pub fn run_decrypt_bruteforce_process(
charset, bssid, handshake
);

let mut process = build_terminal(title, cmd)?;

std::thread::spawn(move || {
process.output().unwrap();
});
Command::new("xterm")
.stdin(Stdio::null())
.args(["-hold", "-T", &title, "-e", "sh", "-c", &cmd])
.spawn()?;

Ok(())
}
Loading

0 comments on commit f9ba508

Please sign in to comment.