diff --git a/doc/tplink-m7350.md b/doc/tplink-m7350.md index b0f7f88..66c3ce6 100644 --- a/doc/tplink-m7350.md +++ b/doc/tplink-m7350.md @@ -7,10 +7,10 @@ The TP-Link M7350 is supported by Rayhunter from 0.3.0 release. TP-Link M7350 su The TP-Link comes in many different *hardware versions*. Support for installation varies: * `1.0`, `2.0`: **Not suported**, probably impossible to obtain anymore (even second-hand), however there is one report that installation is possible on `1.0` (but no reports if it is working or not) -* `3.0`, `3.2`, `5.0`, `5.2`, `7.0`, `8.0`: **Tested, no known issues.** +* `3.0`, `3.2`, `5.0`, `5.2`, `7.0`, `8.0`: **Tested, no known issues since 0.3.0.** * `6.2`: **One user reported it is working** -* `4.0`: **Not working yet** ([issue](https://github.com/EFForg/rayhunter/issues/332)), however [it could be installed manually](https://github.com/m0veax/rayhunter-tplink-m7350/)) -* `9.0`: **Not working yet** ([issue](https://github.com/EFForg/rayhunter/issues/325), however opening/rooting works, Rayhunter could be installed manually, but does not work because of [IOCTL error](#302)) +* `4.0`: **Manual firmware downgrade required** ([issue](https://github.com/EFForg/rayhunter/issues/332)) +* `9.0`: **Working since 0.3.2.** TP-Link versions newer than `3.0` have cyan packaging and a color display. Version `3.0` has a one-bit display and white packaging. @@ -62,6 +62,15 @@ You can change the `port` (default is `8080`) where Rayhunter is listening for i By default the device will go to sleep after N minutes of no devices being connected. In that mode it will also turn off connections to cell phone towers. In order for Rayhunter to record continuously, you have to turn off this sleep mode in TP-Link's admin panel (go to **Advanced** - **Power Saving**) or keep e.g. your phone connectd on the TP-Link's WiFi. +## Port triggers + +On hardware revisions starting with v4.0, the installer will modify settings to +add two port triggers. You can look at `Settings > NAT Settings > Port +Triggers` in TP-Link's admin UI to see them. + +1. One port trigger "rayhunter-root" to launch the telnet shell. This is only needed for installation, and can be removed after upgrade. You can reinstall it using `./installer util tplink-start-telnet`. +2. One port trigger "rayhunter-daemon" to auto-start rayhunter on boot. If you remove this, rayhunter will have to be started manually from shell. + ## Other links For more information on the device and instructions on how to install Rayhunter without an installer (i.e. manually), please see [rayhunter-tplink-m7350](https://github.com/m0veax/rayhunter-tplink-m7350/) diff --git a/doc/uninstalling.md b/doc/uninstalling.md index 0bf9705..4649999 100644 --- a/doc/uninstalling.md +++ b/doc/uninstalling.md @@ -16,4 +16,9 @@ Your device is now Rayhunter-free, and should no longer be in a rooted ADB-enabl ## TPLink -TODO +1. Run `./installer util tplink-start-telnet` +2. Telnet into the device `telnet 192.168.0.1` +3. `rm /data/rayhunter /etc/init.d/rayhunter_daemon` +4. `update-rc.d rayhunter_daemon remove` +5. (hardware revision v4.0+ only) In `Settings > NAT Settings > Port Triggers` in TP-Link's admin UI, remove any leftover port triggers. + diff --git a/installer/src/main.rs b/installer/src/main.rs index e1cc83a..9de31e1 100644 --- a/installer/src/main.rs +++ b/installer/src/main.rs @@ -35,6 +35,17 @@ struct InstallTpLink { /// IP address for TP-Link admin interface, if custom. #[arg(long, default_value = "192.168.0.1")] admin_ip: String, + + /// For advanced users: Specify the path of the SD card to be mounted explicitly. + /// + /// The default (empty string) is to use whichever sdcard path the device would use natively to + /// mount storage on. On most TP-Link this is /media/card, but on hardware versions 9+ this is + /// /media/sdcard + /// + /// Only override this when the installer does not work on your hardware version, as otherwise + /// your custom path may conflict with the builtin storage functionality. + #[arg(long, default_value = "")] + sdcard_path: String, } #[derive(Parser, Debug)] diff --git a/installer/src/tplink.rs b/installer/src/tplink.rs index 6ec2e87..ac6c684 100644 --- a/installer/src/tplink.rs +++ b/installer/src/tplink.rs @@ -27,10 +27,11 @@ pub async fn main_tplink( InstallTpLink { skip_sdcard, admin_ip, + sdcard_path, }: InstallTpLink, ) -> Result<(), Error> { - start_telnet(&admin_ip).await?; - tplink_run_install(skip_sdcard, admin_ip).await + let is_v3 = start_telnet(&admin_ip).await?; + tplink_run_install(skip_sdcard, admin_ip, sdcard_path, is_v3).await } #[derive(Deserialize)] @@ -38,7 +39,7 @@ struct V3RootResponse { result: u64, } -pub async fn start_telnet(admin_ip: &str) -> Result<(), Error> { +pub async fn start_telnet(admin_ip: &str) -> Result { let qcmap_web_cgi_endpoint = format!("http://{admin_ip}/cgi-bin/qcmap_web_cgi"); let client = reqwest::Client::new(); @@ -51,7 +52,9 @@ pub async fn start_telnet(admin_ip: &str) -> Result<(), Error> { .send() .await?; - if response.status() == 404 { + let is_v3 = response.status() != 404; + + if !is_v3 { println!("Got a 404 trying to run exploit for hardware revision v3, trying v5 exploit"); tplink_launch_telnet_v5(admin_ip).await?; } else { @@ -82,20 +85,49 @@ pub async fn start_telnet(admin_ip: &str) -> Result<(), Error> { println!( "Succeeded in rooting the device! Now you can use 'telnet {admin_ip}' to get a root shell. Use './installer util tplink-start-telnet' to root again without installing rayhunter." ); - Ok(()) + Ok(is_v3) } -async fn tplink_run_install(skip_sdcard: bool, admin_ip: String) -> Result<(), Error> { +async fn tplink_run_install( + skip_sdcard: bool, + admin_ip: String, + mut sdcard_path: String, + is_v3: bool, +) -> Result<(), Error> { println!("Connecting via telnet to {admin_ip}"); let addr = SocketAddr::from_str(&format!("{admin_ip}:23")).unwrap(); if !skip_sdcard { - println!("Mounting sdcard"); - if telnet_send_command(addr, "mount | grep -q /media/card", "exit code 0") - .await - .is_err() + if sdcard_path.is_empty() { + if telnet_send_command(addr, "ls /media/card", "exit code 0") + .await + .is_ok() + { + // TP-Link hardware less than v9.0 + sdcard_path = "/media/card".to_owned(); + } else if telnet_send_command(addr, "ls /media/sdcard", "exit code 0") + .await + .is_ok() + { + // TP-Link hardware v9.0 + sdcard_path = "/media/sdcard".to_owned(); + } else { + anyhow::bail!( + "unable to determine sdcard path. this is a bug. please file an issue with your hardware version." + ); + } + } + + println!("Mounting sdcard on {sdcard_path}"); + if telnet_send_command( + addr, + &format!("mount | grep -q {sdcard_path}"), + "exit code 0", + ) + .await + .is_err() { - telnet_send_command(addr, "mount /dev/mmcblk0p1 /media/card", "exit code 0").await.context("Rayhunter needs a FAT-formatted SD card to function for more than a few minutes. Insert one and rerun this installer, or pass --skip-sdcard")?; + telnet_send_command(addr, &format!("mount /dev/mmcblk0p1 {sdcard_path}"), "exit code 0").await.context("Rayhunter needs a FAT-formatted SD card to function for more than a few minutes. Insert one and rerun this installer, or pass --skip-sdcard")?; } else { println!("sdcard already mounted"); } @@ -105,28 +137,38 @@ async fn tplink_run_install(skip_sdcard: bool, admin_ip: String) -> Result<(), E // expects things to be at this location telnet_send_command(addr, "rm -rf /data/rayhunter", "exit code 0").await?; telnet_send_command(addr, "mkdir -p /data", "exit code 0").await?; - telnet_send_command(addr, "ln -sf /media/card /data/rayhunter", "exit code 0").await?; + telnet_send_command( + addr, + &format!("ln -sf {sdcard_path} /data/rayhunter"), + "exit code 0", + ) + .await?; telnet_send_file( addr, - "/media/card/config.toml", + &format!("{sdcard_path}/config.toml"), crate::CONFIG_TOML.as_bytes(), ) .await?; let rayhunter_daemon_bin = include_bytes!(env!("FILE_RAYHUNTER_DAEMON_TPLINK")); - telnet_send_file(addr, "/media/card/rayhunter-daemon", rayhunter_daemon_bin).await?; + telnet_send_file( + addr, + &format!("{sdcard_path}/rayhunter-daemon"), + rayhunter_daemon_bin, + ) + .await?; telnet_send_file( addr, "/etc/init.d/rayhunter_daemon", - get_rayhunter_daemon().as_bytes(), + get_rayhunter_daemon(&sdcard_path).as_bytes(), ) .await?; telnet_send_command( addr, - "chmod ugo+x /media/card/rayhunter-daemon", + &format!("chmod ugo+x {sdcard_path}/rayhunter-daemon"), "exit code 0", ) .await?; @@ -136,7 +178,13 @@ async fn tplink_run_install(skip_sdcard: bool, admin_ip: String) -> Result<(), E "exit code 0", ) .await?; - telnet_send_command(addr, "update-rc.d rayhunter_daemon defaults", "exit code 0").await?; + + // if the device is not v3, the JS-based root exploit already added rayhunter_daemon as a + // startup script. tplink v9 does not have update-rc.d, and it was reported that *sometimes* it + // is unreliable on other hardware revisions too. + if is_v3 { + telnet_send_command(addr, "update-rc.d rayhunter_daemon defaults", "exit code 0").await?; + } println!( "Done. Rebooting device. After it's started up again, check out the web interface at http://{admin_ip}:8080" @@ -278,6 +326,7 @@ async fn handler(state: State, mut req: Request) -> Result { Globals.models.PTModel.add({applicationName: "rayhunter-root", enableState: 1, entryId: 1, openPort: "2300-2400", openProtocol: "TCP", triggerPort: "$(busybox telnetd -l /bin/sh)", triggerProtocol: "TCP"}); + Globals.models.PTModel.add({applicationName: "rayhunter-daemon", enableState: 1, entryId: 2, openPort: "2400-2500", openProtocol: "TCP", triggerPort: "$(/etc/init.d/rayhunter_daemon start)", triggerProtocol: "TCP"}); alert("Success! You can go back to the rayhunter installer."); window.clearInterval(window.rayhunterPoll); }, 1000);"#); @@ -324,7 +373,7 @@ async fn tplink_launch_telnet_v5(admin_ip: &str) -> Result<(), Error> { Ok(()) } -fn get_rayhunter_daemon() -> String { +fn get_rayhunter_daemon(sdcard_path: &str) -> String { // Even though TP-Link eventually auto-mounts the SD card, it sometimes does so too late. And // changing the order in which daemons are started up seems to not work reliably. // @@ -332,12 +381,12 @@ fn get_rayhunter_daemon() -> String { // specific to a particular hardware revision here. crate::RAYHUNTER_DAEMON_INIT.replace( "#RAYHUNTER-PRESTART", - "mount /dev/mmcblk0p1 /media/card || true", + &format!("mount /dev/mmcblk0p1 {sdcard_path} || true"), ) } #[test] fn test_get_rayhunter_daemon() { - let s = get_rayhunter_daemon(); + let s = get_rayhunter_daemon("/media/card"); assert!(s.contains("mount /dev/mmcblk0p1 /media/card")); } diff --git a/lib/src/diag_device.rs b/lib/src/diag_device.rs index 8d4557a..1bec4ba 100644 --- a/lib/src/diag_device.rs +++ b/lib/src/diag_device.rs @@ -251,6 +251,7 @@ impl DiagDevice { // // TPLINK M7350 v5 source code can be downloaded at https://www.tp-link.com/de/support/gpl-code/?app=omada #[repr(C)] +#[derive(Debug, Clone, Copy)] struct diag_logging_mode_param_t { req_mode: u32, peripheral_mask: u32, @@ -261,30 +262,41 @@ struct diag_logging_mode_param_t { fn enable_frame_readwrite(fd: i32, mode: u32) -> DiagResult<()> { unsafe { if libc::ioctl(fd, DIAG_IOCTL_SWITCH_LOGGING, mode, 0, 0, 0) < 0 { - let mut params = if cfg!(feature = "tplink") { + let try_params: &[diag_logging_mode_param_t] = &[ + // tplink M7350 HW revision 3-8 need this mode + #[cfg(feature = "tplink")] diag_logging_mode_param_t { req_mode: mode, peripheral_mask: 0, mode_param: 1, - } - } else { + }, + // tplink M7350 HW revision v9 requires the same parameters as orbic diag_logging_mode_param_t { req_mode: mode, peripheral_mask: u32::MAX, mode_param: 0, - } - }; + }, + ]; + + let mut ret = 0; + + for params in try_params { + let mut params = *params; + ret = libc::ioctl( + fd, + DIAG_IOCTL_SWITCH_LOGGING, + &mut params as *mut diag_logging_mode_param_t, + std::mem::size_of::(), + 0, + 0, + 0, + 0, + ); + if ret == 0 { + break; + } + } - let ret = libc::ioctl( - fd, - DIAG_IOCTL_SWITCH_LOGGING, - &mut params as *mut _, - std::mem::size_of::(), - 0, - 0, - 0, - 0, - ); if ret < 0 { let msg = format!( "DIAG_IOCTL_SWITCH_LOGGING ioctl failed with error code {}",