htb-toolkit: init at unstable-2024-01-17

authored by D3vil0p3r and committed by D3vil0p3r 40aee16d 6de92461

+376
+307
pkgs/by-name/ht/htb-toolkit/disable-shell-prompt-change.patch
··· 1 + --- a/src/main.rs 2024-01-17 23:44:21.346253718 +0100 2 + +++ b/src/main.rs 2024-01-17 23:48:54.536921610 +0100 3 + @@ -15,7 +15,6 @@ 4 + use crate::utils::*; 5 + use crate::vpn::*; 6 + use std::fs; 7 + -use std::path::Path; 8 + use std::process::Command; 9 + 10 + #[tokio::main] 11 + @@ -44,16 +43,6 @@ 12 + eprintln!("Error creating folder: {}", err); 13 + } 14 + } 15 + - 16 + - // Create HTB config file if not existing 17 + - let htb_config = format!("{}/.htb.conf", home); 18 + - 19 + - let file = Path::new(&htb_config); 20 + - if !file.exists() { 21 + - let lines = ["# HTB configuration file.\n\n", "# Enable/Disable shell prompt change\n", "prompt_change=true\n"]; 22 + - fs::write(&htb_config, lines.join("")) 23 + - .expect("Failed to create HTB config file"); 24 + - } 25 + 26 + // Initialize Xorg in WSL for secret-tool popup window 27 + if is_wsl() && is_display_zero() { 28 + @@ -104,13 +93,6 @@ 29 + let _ = play_machine(&args[2]).await; 30 + } 31 + } 32 + - "-p" => { 33 + - if args.len() < 3 || (args[2] != "true" && args[2] != "false") { 34 + - println!("Usage: {} -p <true|false>", args[0]); 35 + - } else { 36 + - prompt_setting(&args[2]); 37 + - } 38 + - } 39 + "-r" => { 40 + reset_machine().await; 41 + } 42 + --- a/src/manage.rs 2024-01-17 22:50:22.450368210 +0100 43 + +++ b/src/manage.rs 2024-01-17 23:49:21.143071918 +0100 44 + @@ -77,19 +77,14 @@ 45 + if machine_info.ip.is_empty() { //Starting Point case because SP IP address is assigned only after spawn of the machine 46 + machine_info.ip = active_machine.ip; 47 + } 48 + - let mut user_info = PlayingUser::get_playinguser(&appkey).await; 49 + 50 + // SP Machines change IP address when reset, so need to ask to write /etc/hosts 51 + if machine_info.sp_flag { 52 + let _ = add_hosts(&machine_info); 53 + } 54 + - 55 + - change_shell(&mut machine_info, &mut user_info); 56 + } 57 + 58 + pub async fn stop_machine() { 59 + - let htb_path = format!("{}/.htb.conf", env::var("HOME").unwrap()); 60 + - let htbconfig = HTBConfig::get_current_config(&htb_path); 61 + let appkey = get_appkey(); 62 + let active_machine = ActiveMachine::get_active(&appkey).await; 63 + 64 + @@ -126,31 +121,9 @@ 65 + 66 + // Await the result of the blocking task 67 + blocking_task.await.expect("Blocking task failed"); 68 + - 69 + - if htbconfig.promptchange { //If the prompt is set to change during the playing, when you stop the machine, it should restore the original shell 70 + - restore_shell(); 71 + - } 72 + } 73 + } 74 + 75 + -pub fn prompt_setting(option: &str) { 76 + - let home = env::var("HOME").unwrap_or_default(); 77 + - let htb_config = format!("{}/.htb.conf", home); 78 + - 79 + - let content = fs::read_to_string(&htb_config) 80 + - .expect("Failed to read HTB config file"); 81 + - 82 + - let re = Regex::new(r"prompt_change=\w+") 83 + - .expect("Failed to create regular expression"); 84 + - 85 + - let new_content = re.replace(&content, format!("prompt_change={}", option)); 86 + - 87 + - fs::write(&htb_config, new_content.to_string()) 88 + - .expect("Failed to write updated content to HTB config file"); 89 + - 90 + - println!("Prompt setting updated to: {}", option); 91 + -} 92 + - 93 + pub async fn update_machines() -> io::Result<()> { 94 + 95 + println!("Retrieving updated data from Hack The Box... Gimme some time hackerzzz..."); 96 + --- a/src/play.rs 2024-01-17 22:50:25.709380651 +0100 97 + +++ b/src/play.rs 2024-01-17 23:39:08.715395211 +0100 98 + @@ -4,7 +4,6 @@ 99 + use crate::types::*; 100 + use crate::utils::*; 101 + use crate::vpn::*; 102 + -use std::env; 103 + use std::io::{self,Write}; 104 + use reqwest::Client; 105 + use serde::Serialize; 106 + @@ -29,8 +28,6 @@ 107 + pub async fn play_machine(machine_name: &str) -> Result<(), Box<dyn std::error::Error>> { 108 + let appkey = get_appkey(); 109 + let appkey_clone = appkey.clone(); // Clone the necessary data to avoid borrowed value error 110 + - let htb_path = format!("{}/.htb.conf", env::var("HOME").unwrap()); 111 + - let htbconfig = HTBConfig::get_current_config(&htb_path); 112 + 113 + let mut machine_info = PlayingMachine::get_machine(machine_name, &appkey).await; 114 + 115 + @@ -103,7 +100,7 @@ 116 + 117 + machine_info.ip = get_ip(&appkey_clone).await; // For Starting Point machines and VIP and VIP+ VPNs, if I call the play API two times on the same machine, the old IP address associated to the machine can still live for some seconds providing a wrong IP related to the new same machine. For this reason, it is better to compute always the IP address (no problems for free VPNs because they associate always the same IP address to the same machine) 118 + 119 + - let mut user_info = PlayingUser::get_playinguser(&appkey_clone).await; // Before this it is needed to run HTB VPN to take the Attacker IP address 120 + + let user_info = PlayingUser::get_playinguser(&appkey_clone).await; // Before this it is needed to run HTB VPN to take the Attacker IP address 121 + 122 + let _ = print_banner(); 123 + 124 + @@ -115,10 +112,6 @@ 125 + println!("{}Hey! You have already found the Root Flag! Keep it up!{}", BGREEN, RESET); 126 + } 127 + 128 + - if htbconfig.promptchange { //If the prompt is set to change during the playing... 129 + - change_shell(&mut machine_info, &mut user_info); 130 + - } 131 + - 132 + // Writing /etc/hosts 133 + let _ = add_hosts(&machine_info); 134 + 135 + --- a/src/types.rs 2024-01-17 23:40:14.341769452 +0100 136 + +++ b/src/types.rs 2024-01-17 23:43:14.159871196 +0100 137 + @@ -2,7 +2,6 @@ 138 + use crate::colors::*; 139 + use crate::utils::get_interface_ip; 140 + use core::time::Duration; 141 + -use std::fs; 142 + use std::process; 143 + use std::thread::sleep; 144 + 145 + @@ -485,37 +484,4 @@ 146 + ip: userip, 147 + } 148 + } 149 + -} 150 + - 151 + -pub struct HTBConfig { 152 + - pub promptchange: bool, 153 + -} 154 + - 155 + -impl HTBConfig { 156 + - 157 + - pub fn get_current_config(htb_config: &str) -> Self { 158 + - HTBConfig { 159 + - promptchange: Self::get_prompt_change(htb_config), 160 + - } 161 + - } 162 + - 163 + - fn get_prompt_change(htb_config: &str) -> bool { 164 + - let prompt_change = fs::read_to_string(htb_config).expect("Failed to read htconfig."); 165 + - 166 + - let change_prompt = prompt_change.lines() 167 + - .find(|line| line.starts_with("prompt_change=")) 168 + - .map(|line| line.split('=').nth(1).unwrap_or_default()) 169 + - .unwrap_or_default(); 170 + - 171 + - // Convert the change_prompt string to a bool 172 + - 173 + - match change_prompt { 174 + - "true" => true, 175 + - "false" => false, 176 + - _ => { 177 + - // Handle other cases if needed, e.g., return a default value 178 + - false 179 + - } 180 + - } 181 + - } 182 + } 183 + \ No newline at end of file 184 + --- a/src/utils.rs 2024-01-17 23:29:49.215407440 +0100 185 + +++ b/src/utils.rs 2024-01-17 23:46:20.681009209 +0100 186 + @@ -5,7 +5,6 @@ 187 + use crate::types::*; 188 + use crate::vpn::*; 189 + use pnet::datalink; 190 + -use regex::Regex; 191 + use reqwest::Client; 192 + use std::fs; 193 + use std::net::IpAddr; 194 + @@ -13,96 +12,6 @@ 195 + use tokio::io::{AsyncWriteExt, BufWriter}; 196 + use tokio::sync::mpsc; 197 + 198 + -pub fn change_shell(machine_info: &mut PlayingMachine, user_info: &mut PlayingUser) { 199 + - let result = std::env::var("SHELL").unwrap_or_default(); 200 + - let mut file_bak = String::new(); 201 + - let mut file = String::new(); 202 + - let mut prompt = String::new(); 203 + - let mut prompt_field = ""; 204 + - 205 + - if result.contains("bash") { 206 + - file_bak = format!("{}/.bashrc.htb.bak", std::env::var("HOME").unwrap_or_default()); 207 + - file = format!("{}/.bashrc", std::env::var("HOME").unwrap_or_default()); 208 + - prompt = format!( 209 + - "PS1=\"\\e[32m\\]┌──[Target:{}🚀🌐IP:{}🔥\\e[34m\\]Attacker:{}📡IP:{}\\e[32m\\]🏅Prize:{} points]\\n└──╼[👾]\\\\[\\e[36m\\]\\$(pwd) $ \\[\\e[0m\\]\"", 210 + - machine_info.machine.name, 211 + - machine_info.ip, 212 + - user_info.user.name, 213 + - get_interface_ip("tun0").expect("Error on getting tun0 IP address"), 214 + - machine_info.machine.points 215 + - ); 216 + - prompt_field = "PS1=.*"; 217 + - } else if result.contains("fish") { 218 + - file_bak = format!("{}/.config/fish/functions/fish_prompt.fish.htb.bak", std::env::var("HOME").unwrap_or_default()); 219 + - file = format!("{}/.config/fish/functions/fish_prompt.fish", std::env::var("HOME").unwrap_or_default()); 220 + - prompt = format!( 221 + - r#"function fish_prompt 222 + - set_color 00ff00 223 + - echo -n "┌──[Target:{}🚀🌐IP:{}" 224 + - set_color ff00d7 225 + - echo -n "🔥Attacker:{}📡IP:{}" 226 + - set_color 00ff00 227 + - echo "🏅Prize:{} points]" 228 + - set_color 00ff00 229 + - echo -n "└──╼[👾]" 230 + - set_color 00ffff 231 + - echo (pwd) '$' (set_color normal) 232 + -end"#, 233 + - machine_info.machine.name, 234 + - machine_info.ip, 235 + - user_info.user.name, 236 + - get_interface_ip("tun0").expect("Error on getting tun0 IP address"), 237 + - machine_info.machine.points 238 + - ); 239 + - } else if result.contains("zsh") { 240 + - file_bak = format!("{}/.zshrc.htb.bak", std::env::var("HOME").unwrap_or_default()); 241 + - file = format!("{}/.zshrc", std::env::var("HOME").unwrap_or_default()); 242 + - prompt = format!( 243 + - "PROMPT=\"%F{{46}}┌──[Target:{}🚀🌐IP:{}🔥%F{{201}}Attacker:{}📡IP:{}%F{{46}}🏅Prize:{} points]\"$'\\n'\"└──╼[👾]%F{{44}}%~ $%f \"" , 244 + - machine_info.machine.name, 245 + - machine_info.ip, 246 + - user_info.user.name, 247 + - get_interface_ip("tun0").expect("Error on getting tun0 IP address"), 248 + - machine_info.machine.points 249 + - ); 250 + - prompt_field = "PROMPT=.*"; 251 + - } 252 + - 253 + - if !std::path::Path::new(&file_bak).exists() { 254 + - std::fs::copy(&file, &file_bak).unwrap_or_default(); 255 + - } 256 + - 257 + - if result.contains("bash") || result.contains("zsh") { 258 + - let file_content = std::fs::read_to_string(&file).unwrap_or_default(); 259 + - let regex = Regex::new(prompt_field).unwrap(); 260 + - let new_file_content = regex.replace_all(&file_content, prompt); 261 + - std::fs::write(&file, new_file_content.as_ref()).unwrap_or_default(); 262 + - } else if result.contains("fish") { 263 + - std::fs::write(&file, &prompt).unwrap_or_default(); 264 + - } 265 + -} 266 + - 267 + -pub fn restore_shell() { 268 + - let result = env::var("SHELL").unwrap_or_default(); 269 + - let mut file_bak = String::new(); 270 + - let mut file = String::new(); 271 + - 272 + - if result.contains("bash") { 273 + - file_bak = format!("{}/.bashrc.htb.bak", env::var("HOME").unwrap()); 274 + - file = format!("{}/.bashrc", env::var("HOME").unwrap()); 275 + - } else if result.contains("fish") { 276 + - file_bak = format!("{}/.config/fish/functions/fish_prompt.fish.htb.bak", env::var("HOME").unwrap()); 277 + - file = format!("{}/.config/fish/functions/fish_prompt.fish", env::var("HOME").unwrap()); 278 + - } else if result.contains("zsh") { 279 + - file_bak = format!("{}/.zshrc.htb.bak", env::var("HOME").unwrap()); 280 + - file = format!("{}/.zshrc", env::var("HOME").unwrap()); 281 + - } 282 + - if fs::metadata(&file).is_ok() && std::path::Path::new(&file_bak).exists() { 283 + - //Restore the prompt file from the backup 284 + - fs::copy(&file_bak, &file).expect("Failed to copy file"); 285 + - } 286 + -} 287 + - 288 + pub fn display_target_info(machine_info: &PlayingMachine, user_info: &PlayingUser) { 289 + println!(); 290 + println!("{}Our secret agent gathered some information about the target:{}", BYELLOW, RESET); 291 + @@ -184,7 +93,7 @@ 292 + println!("Play Hack The Box machines directly on your system."); 293 + println!(); 294 + std::thread::sleep(std::time::Duration::from_secs(2)); //Showing the description for some secs before showing the help message 295 + - println!("{} [-h] [-a] [-f] [-k] <set|reset|delete> [-m] <machine-name> [-l] <free|retired|starting> [-p] <true|false> [-r] [-s] [-u] [-v] <vpn-name>", env::args().next().unwrap()); 296 + + println!("{} [-h] [-a] [-f] [-k] <set|reset|delete> [-m] <machine-name> [-l] <free|retired|starting> [-r] [-s] [-u] [-v] <vpn-name>", env::args().next().unwrap()); 297 + println!(); 298 + println!("Options:"); 299 + println!("-a Print information about the current active machine."); 300 + @@ -193,7 +102,6 @@ 301 + println!("-k <set|reset|delete> Set, reset or delete the Hack The Box App Key."); 302 + println!("-m <machine-name> Specify the machine name to play."); 303 + println!("-l <free|retired|starting> List free, retired or starting point machines."); 304 + - println!("-p <true|false> Set if the shell prompt should be changed."); 305 + println!("-r Reset the playing machine."); 306 + println!("-s Stop the playing machine."); 307 + println!("-u Update free machines in the Red Team menu.");
+69
pkgs/by-name/ht/htb-toolkit/package.nix
··· 1 + { lib 2 + , rustPlatform 3 + , fetchFromGitHub 4 + , pkg-config 5 + , openssl 6 + , stdenv 7 + , darwin 8 + , coreutils 9 + , gnome 10 + , libsecret 11 + , bash 12 + , openvpn 13 + , nerdfonts 14 + , gzip 15 + , killall 16 + }: 17 + 18 + rustPlatform.buildRustPackage { 19 + pname = "htb-toolkit"; 20 + version = "unstable-2024-01-17"; 21 + 22 + src = fetchFromGitHub { 23 + owner = "D3vil0p3r"; 24 + repo = "htb-toolkit"; 25 + # https://github.com/D3vil0p3r/htb-toolkit/issues/3 26 + rev = "54e11774ea8746ea540548082d3b25c22306b4fc"; 27 + hash = "sha256-QYUqdqFV9Qn+VbJTnz5hx5I0XV1nrzCoCKtRS7jBLsE="; 28 + }; 29 + 30 + cargoHash = "sha256-XDE6A6EIAUbuzt8Zb/ROfDAPp0ZyN0WQ4D1gWHjRVhg="; 31 + 32 + # Patch to disable prompt change of the shell when a target machine is run. Needed due to Nix declarative nature 33 + patches = [ 34 + ./disable-shell-prompt-change.patch 35 + ]; 36 + 37 + nativeBuildInputs = [ 38 + pkg-config 39 + ]; 40 + 41 + buildInputs = [ 42 + gnome.gnome-keyring 43 + openssl 44 + ] ++ lib.optionals stdenv.isDarwin [ 45 + darwin.apple_sdk.frameworks.Security 46 + ]; 47 + 48 + postPatch = '' 49 + substituteInPlace src/manage.rs \ 50 + --replace /usr/share/htb-toolkit/icons/ $out/share/htb-toolkit/icons/ 51 + substituteInPlace src/utils.rs \ 52 + --replace /usr/bin/bash ${bash} \ 53 + --replace "\"base64\"" "\"${coreutils}/bin/base64\"" \ 54 + --replace "\"gunzip\"" "\"${gzip}/bin/gunzip\"" 55 + substituteInPlace src/appkey.rs \ 56 + --replace secret-tool ${lib.getExe libsecret} 57 + substituteInPlace src/vpn.rs \ 58 + --replace "arg(\"openvpn\")" "arg(\"${openvpn}/bin/openvpn\")" \ 59 + --replace "arg(\"killall\")" "arg(\"${killall}/bin/killall\")" 60 + ''; 61 + 62 + meta = with lib; { 63 + description = "Play Hack The Box directly on your system"; 64 + homepage = "https://github.com/D3vil0p3r/htb-toolkit"; 65 + license = licenses.gpl3Plus; 66 + maintainers = with maintainers; [ d3vil0p3r ]; 67 + mainProgram = "htb-toolkit"; 68 + }; 69 + }