diff --git a/installer/src/main.rs b/installer/src/main.rs index 39debf9..7bd8ada 100644 --- a/installer/src/main.rs +++ b/installer/src/main.rs @@ -182,8 +182,8 @@ async fn run() -> Result<(), Error> { } } UtilSubCommand::Shell(_) => orbic::shell().await.context("\nFailed to open shell on Orbic RC400L")?, - UtilSubCommand::TmobileStartTelnet(args) => tmobile::start_telnet(&args.admin_ip, &args.admin_password).await.context("\nFailed to start telnet on the Tmobile TMOHS1")?, - UtilSubCommand::TmobileStartAdb(args) => tmobile::start_adb(&args.admin_ip, &args.admin_password).await.context("\nFailed to start adb on the Tmobile TMOHS1")?, + UtilSubCommand::TmobileStartTelnet(args) => wingtech::start_telnet(&args.admin_ip, &args.admin_password).await.context("\nFailed to start telnet on the Tmobile TMOHS1")?, + UtilSubCommand::TmobileStartAdb(args) => wingtech::start_adb(&args.admin_ip, &args.admin_password).await.context("\nFailed to start adb on the Tmobile TMOHS1")?, UtilSubCommand::TplinkStartTelnet(options) => { tplink::start_telnet(&options.admin_ip).await?; } diff --git a/installer/src/tmobile.rs b/installer/src/tmobile.rs index ee8bcae..210c3c3 100644 --- a/installer/src/tmobile.rs +++ b/installer/src/tmobile.rs @@ -9,16 +9,12 @@ use std::net::SocketAddr; use std::str::FromStr; use std::time::Duration; -use aes::Aes128; -use aes::cipher::{BlockEncrypt, KeyInit, generic_array::GenericArray}; -use anyhow::{Result, bail}; -use base64_light::base64_encode_bytes; -use block_padding::{Padding, Pkcs7}; -use reqwest::Client; +use anyhow::Result; use tokio::time::sleep; use crate::TmobileArgs as Args; -use crate::util::{echo, telnet_send_command, telnet_send_file}; +use crate::util::{echo, http_ok_every, telnet_send_command, telnet_send_file}; +use crate::wingtech::start_telnet; pub async fn install( Args { @@ -29,62 +25,6 @@ pub async fn install( run_install(admin_ip, admin_password).await } -const KEY: &[u8] = b"abcdefghijklmn12"; - -/// Returns password encrypted in AES128 ECB mode with the key b"abcdefghijklmn12", -/// with Pkcs7 padding, encoded in base64. -fn encrypt_password(password: &[u8]) -> Result { - let c = Aes128::new_from_slice(KEY)?; - let mut b = GenericArray::from([0u8; 16]); - b[..password.len()].copy_from_slice(password); - Pkcs7::pad(&mut b, password.len()); - c.encrypt_block(&mut b); - Ok(base64_encode_bytes(&b)) -} - -pub async fn start_telnet(admin_ip: &str, admin_password: &str) -> Result<()> { - run_command(admin_ip, admin_password, "busybox telnetd -l /bin/sh").await -} - -pub async fn start_adb(admin_ip: &str, admin_password: &str) -> Result<()> { - run_command(admin_ip, admin_password, "/sbin/usb/compositions/9025").await -} - -async fn run_command(admin_ip: &str, admin_password: &str, cmd: &str) -> Result<()> { - let qcmap_auth_endpoint = format!("http://{admin_ip}/cgi-bin/qcmap_auth"); - let qcmap_web_cgi_endpoint = format!("http://{admin_ip}/cgi-bin/qcmap_web_cgi"); - - let encrypted_pw = encrypt_password(admin_password.as_bytes()).ok().unwrap(); - - let client = Client::new(); - let login = client - .post(&qcmap_auth_endpoint) - .body(format!( - "type=login&pwd={encrypted_pw}&timeout=60000&user=admin" - )) - .send() - .await? - .text() - .await?; - let token = match login.find("token") { - Some(n) => &login[n + 8..n + 8 + 16], - None => bail!("login did not return a token in response: {}", login), - }; - - let telnet = client.post(&qcmap_web_cgi_endpoint) - .body(format!("page=setFWMacFilter&cmd=add&mode=0&mac=50:5A:CA:B5:05||{cmd}&key=50:5A:CA:B5:05:AC&token={token}")) - .send() - .await?; - if telnet.status() != 200 { - bail!( - "starting telnet failed with status code: {:?}", - telnet.status() - ); - } - - Ok(()) -} - async fn run_install(admin_ip: String, admin_password: String) -> Result<()> { echo!("Starting telnet ... "); start_telnet(&admin_ip, &admin_password).await?; @@ -154,34 +94,3 @@ async fn run_install(admin_ip: String, admin_password: String) -> Result<()> { Ok(()) } - -async fn http_ok_every(rayhunter_url: String, interval: Duration, max_failures: u32) -> Result<()> { - let client = Client::new(); - let mut failures = 0; - loop { - match client.get(&rayhunter_url).send().await { - Ok(test) => match test.status().is_success() { - true => break, - false => bail!( - "request for url ({rayhunter_url}) failed with status code: {:?}", - test.status() - ), - }, - Err(e) => match failures > max_failures { - true => return Err(e.into()), - false => failures += 1, - }, - } - sleep(interval).await; - } - - Ok(()) -} - -#[test] -fn test_encrypt_password() { - let p = b"80536913"; - let s = encrypt_password(p).ok(); - let expected = Some("5brvd8xl732cSoFTAy67ig==".to_string()); - assert_eq!(s, expected); -} diff --git a/installer/src/util.rs b/installer/src/util.rs index 64e45ba..27a8026 100644 --- a/installer/src/util.rs +++ b/installer/src/util.rs @@ -4,6 +4,7 @@ use std::str::FromStr; use std::time::Duration; use anyhow::{Context, Result, bail}; +use reqwest::Client; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::TcpStream; use tokio::time::{sleep, timeout}; @@ -105,3 +106,25 @@ pub async fn send_file(admin_ip: &str, local_path: &str, remote_path: &str) -> R println!("Successfully sent {local_path} to {remote_path}"); Ok(()) } + +pub async fn http_ok_every(rayhunter_url: String, interval: Duration, max_failures: u32) -> Result<()> { + let client = Client::new(); + let mut failures = 0; + loop { + match client.get(&rayhunter_url).send().await { + Ok(test) => match test.status().is_success() { + true => break, + false => bail!( + "request for url ({rayhunter_url}) failed with status code: {:?}", + test.status() + ), + }, + Err(e) => match failures > max_failures { + true => return Err(e.into()), + false => failures += 1, + }, + } + sleep(interval).await; + } + Ok(()) +} diff --git a/installer/src/wingtech.rs b/installer/src/wingtech.rs index 3ec7bc7..77c92a9 100644 --- a/installer/src/wingtech.rs +++ b/installer/src/wingtech.rs @@ -19,7 +19,7 @@ use serde::Deserialize; use tokio::time::sleep; use crate::WingtechArgs as Args; -use crate::util::{echo, telnet_send_command, telnet_send_file}; +use crate::util::{echo, http_ok_every, telnet_send_command, telnet_send_file}; #[derive(Deserialize)] struct LoginResponse { @@ -56,7 +56,7 @@ pub async fn start_adb(admin_ip: &str, admin_password: &str) -> Result<()> { run_command(admin_ip, admin_password, "/sbin/usb/compositions/9025").await } -async fn run_command(admin_ip: &str, admin_password: &str, cmd: &str) -> Result<()> { +pub async fn run_command(admin_ip: &str, admin_password: &str, cmd: &str) -> Result<()> { let qcmap_auth_endpoint = format!("http://{admin_ip}/cgi-bin/qcmap_auth"); let qcmap_web_cgi_endpoint = format!("http://{admin_ip}/cgi-bin/qcmap_web_cgi"); @@ -150,29 +150,6 @@ async fn wingtech_run_install(admin_ip: String, admin_password: String) -> Resul Ok(()) } -async fn http_ok_every(rayhunter_url: String, interval: Duration, max_failures: u32) -> Result<()> { - let client = Client::new(); - let mut failures = 0; - loop { - match client.get(&rayhunter_url).send().await { - Ok(test) => match test.status().is_success() { - true => break, - false => bail!( - "request for url ({rayhunter_url}) failed with status code: {:?}", - test.status() - ), - }, - Err(e) => match failures > max_failures { - true => return Err(e.into()), - false => failures += 1, - }, - } - sleep(interval).await; - } - - Ok(()) -} - #[test] fn test_encrypt_password() { let p = b"80536913";