mirror of
https://github.com/EFForg/rayhunter.git
synced 2026-07-22 07:28:11 -07:00
fix(installer): de-duplicate common wingtech/tmohs
The Tmobile TMOHS1 is clearly based on the Wingtech CT2MHS01, and thus the installation process looks very similar between them.
This commit is contained in:
committed by
Cooper Quintin
parent
b7636386fc
commit
27bf20fbf4
@@ -182,8 +182,8 @@ async fn run() -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
UtilSubCommand::Shell(_) => orbic::shell().await.context("\nFailed to open shell on Orbic RC400L")?,
|
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::TmobileStartTelnet(args) => wingtech::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::TmobileStartAdb(args) => wingtech::start_adb(&args.admin_ip, &args.admin_password).await.context("\nFailed to start adb on the Tmobile TMOHS1")?,
|
||||||
UtilSubCommand::TplinkStartTelnet(options) => {
|
UtilSubCommand::TplinkStartTelnet(options) => {
|
||||||
tplink::start_telnet(&options.admin_ip).await?;
|
tplink::start_telnet(&options.admin_ip).await?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,16 +9,12 @@ use std::net::SocketAddr;
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use aes::Aes128;
|
use anyhow::Result;
|
||||||
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 tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
||||||
use crate::TmobileArgs as Args;
|
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(
|
pub async fn install(
|
||||||
Args {
|
Args {
|
||||||
@@ -29,62 +25,6 @@ pub async fn install(
|
|||||||
run_install(admin_ip, admin_password).await
|
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<String> {
|
|
||||||
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<()> {
|
async fn run_install(admin_ip: String, admin_password: String) -> Result<()> {
|
||||||
echo!("Starting telnet ... ");
|
echo!("Starting telnet ... ");
|
||||||
start_telnet(&admin_ip, &admin_password).await?;
|
start_telnet(&admin_ip, &admin_password).await?;
|
||||||
@@ -154,34 +94,3 @@ async fn run_install(admin_ip: String, admin_password: String) -> Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use std::str::FromStr;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use anyhow::{Context, Result, bail};
|
use anyhow::{Context, Result, bail};
|
||||||
|
use reqwest::Client;
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio::time::{sleep, timeout};
|
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}");
|
println!("Successfully sent {local_path} to {remote_path}");
|
||||||
Ok(())
|
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(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ use serde::Deserialize;
|
|||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
||||||
use crate::WingtechArgs as Args;
|
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)]
|
#[derive(Deserialize)]
|
||||||
struct LoginResponse {
|
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
|
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_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 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(())
|
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]
|
#[test]
|
||||||
fn test_encrypt_password() {
|
fn test_encrypt_password() {
|
||||||
let p = b"80536913";
|
let p = b"80536913";
|
||||||
|
|||||||
Reference in New Issue
Block a user