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
8 use std::process::Command;
12 eprintln!("Error creating folder: {}", err);
16 - // Create HTB config file if not existing
17 - let htb_config = format!("{}/.htb.conf", home);
19 - let file = Path::new(&htb_config);
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");
26 // Initialize Xorg in WSL for secret-tool popup window
27 if is_wsl() && is_display_zero() {
29 let _ = play_machine(&args[2]).await;
33 - if args.len() < 3 || (args[2] != "true" && args[2] != "false") {
34 - println!("Usage: {} -p <true|false>", args[0]);
36 - prompt_setting(&args[2]);
40 reset_machine().await;
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
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;
48 - let mut user_info = PlayingUser::get_playinguser(&appkey).await;
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);
55 - change_shell(&mut machine_info, &mut user_info);
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;
66 // Await the result of the blocking task
67 blocking_task.await.expect("Blocking task failed");
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
75 -pub fn prompt_setting(option: &str) {
76 - let home = env::var("HOME").unwrap_or_default();
77 - let htb_config = format!("{}/.htb.conf", home);
79 - let content = fs::read_to_string(&htb_config)
80 - .expect("Failed to read HTB config file");
82 - let re = Regex::new(r"prompt_change=\w+")
83 - .expect("Failed to create regular expression");
85 - let new_content = re.replace(&content, format!("prompt_change={}", option));
87 - fs::write(&htb_config, new_content.to_string())
88 - .expect("Failed to write updated content to HTB config file");
90 - println!("Prompt setting updated to: {}", option);
93 pub async fn update_machines() -> io::Result<()> {
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
103 use std::io::{self,Write};
105 use serde::Serialize;
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);
113 let mut machine_info = PlayingMachine::get_machine(machine_name, &appkey).await;
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)
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
122 let _ = print_banner();
125 println!("{}Hey! You have already found the Root Flag! Keep it up!{}", BGREEN, RESET);
128 - if htbconfig.promptchange { //If the prompt is set to change during the playing...
129 - change_shell(&mut machine_info, &mut user_info);
132 // Writing /etc/hosts
133 let _ = add_hosts(&machine_info);
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
138 use crate::colors::*;
139 use crate::utils::get_interface_ip;
140 use core::time::Duration;
143 use std::thread::sleep;
151 -pub struct HTBConfig {
152 - pub promptchange: bool,
157 - pub fn get_current_config(htb_config: &str) -> Self {
159 - promptchange: Self::get_prompt_change(htb_config),
163 - fn get_prompt_change(htb_config: &str) -> bool {
164 - let prompt_change = fs::read_to_string(htb_config).expect("Failed to read htconfig.");
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();
171 - // Convert the change_prompt string to a bool
173 - match change_prompt {
177 - // Handle other cases if needed, e.g., return a default value
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
193 use std::net::IpAddr;
195 use tokio::io::{AsyncWriteExt, BufWriter};
196 use tokio::sync::mpsc;
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 = "";
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());
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,
212 - user_info.user.name,
213 - get_interface_ip("tun0").expect("Error on getting tun0 IP address"),
214 - machine_info.machine.points
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());
221 - r#"function fish_prompt
223 - echo -n "βββ[Target:{}ππIP:{}"
225 - echo -n "π₯Attacker:{}π‘IP:{}"
227 - echo "π
Prize:{} points]"
229 - echo -n "ββββΌ[πΎ]"
231 - echo (pwd) '$' (set_color normal)
233 - machine_info.machine.name,
235 - user_info.user.name,
236 - get_interface_ip("tun0").expect("Error on getting tun0 IP address"),
237 - machine_info.machine.points
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());
243 - "PROMPT=\"%F{{46}}βββ[Target:{}ππIP:{}π₯%F{{201}}Attacker:{}π‘IP:{}%F{{46}}π
Prize:{} points]\"$'\\n'\"ββββΌ[πΎ]%F{{44}}%~ $%f \"" ,
244 - machine_info.machine.name,
246 - user_info.user.name,
247 - get_interface_ip("tun0").expect("Error on getting tun0 IP address"),
248 - machine_info.machine.points
250 - prompt_field = "PROMPT=.*";
253 - if !std::path::Path::new(&file_bak).exists() {
254 - std::fs::copy(&file, &file_bak).unwrap_or_default();
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();
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();
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());
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");
288 pub fn display_target_info(machine_info: &PlayingMachine, user_info: &PlayingUser) {
290 println!("{}Our secret agent gathered some information about the target:{}", BYELLOW, RESET);
292 println!("Play Hack The Box machines directly on your system.");
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());
298 println!("Options:");
299 println!("-a Print information about the current active machine.");
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.");