Skip to content
KitploitKITPLOIT
उपकरणएक्सप्लॉइटब्लॉग
Log in
जमा करें
उपकरणएक्सप्लॉइटब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
perl_spreadsheet_excel_rce_poc — ParseExcel लाइब्रेरी में RCE भेद्यता के लिए POC, और एक निर्भर लाइब्रेरी के रूप में ParseXLSX भी | Kitploit
उपकरण/GitHubGitHub/haile01/perl_spreadsheet_excel_rce_poc
भेद्यता विश्लेषणकोड विश्लेषणशोषणवेब एप्लिकेशन शोषणपेलोड डेवलपमेंटबाइनरी शोषण
GitHubhaile01/perl_spreadsheet_excel_rce_poc

perl_spreadsheet_excel_rce_poc

ParseExcel लाइब्रेरी में RCE भेद्यता के लिए POC, और एक निर्भर लाइब्रेरी के रूप में ParseXLSX भी

रिपॉजिटरी देखें
18692 साल पहलेअभी तक समीक्षित नहीं

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें

ParseExcel सुरक्षा भेद्यता

TL;DR: फ़ॉर्मेट स्ट्रिंग्स को पार्स करने के लॉजिक से RCE।

एक्सप्लॉइट की संक्षिप्त व्याख्या

एक्सप्लॉइटेशन का मूल कारण Utility.pm में बिना सत्यापित उपयोगकर्ता इनपुट पर eval को कॉल करना है।

https://github.com/jmcnamara/spreadsheet-parseexcel/blob/e33d626d9b9cec91be7520dec1686712313957fb/lib/Spreadsheet/ParseExcel/Utility.pm#L171

# Uitlity.pm
sub ExcelFmt {
	my ( $format_str, $number, $is_1904, $number_type, $want_subformats ) = @_;

	return $number unless $number =~ $qrNUMBER;
	
	my $conditional;
	if ( $format_str =~ /^\[([<>=][^\]]+)\](.*)$/ ) {
		$conditional = $1;
		$format_str  = $2;
	}

	#...

	if ($conditional) {
		# TODO. Replace string eval with a function.
		$section = eval "$number $conditional" ? 0 : 1;
	}
    #...
}

मेरे निरीक्षण के अनुसार, इस प्रवाह के लिए वर्तमान कार्यान्वयन में उचित सत्यापन का अभाव है, जबकि तुलना लॉजिक को संभालने के लिए eval का उपयोग इस मामले में बहुत अधिक ("over kill") है। इस कारण से, ParseExcel::parse और ParseXLSX::parse दोनों (जो Excel फ़ाइलों से डेटा पढ़ने के लिए उपयोग होते हैं) RCE के प्रति संवेदनशील हैं।

$format_str कहाँ है?

ValFmt ही ExcelFmt का सबसे संभावित कॉलर है, इसलिए मैं इस मेथड के बारे में और विस्तार से बताऊँगा https://github.com/jmcnamara/spreadsheet-parseexcel/blob/e33d626d9b9cec91be7520dec1686712313957fb/lib/Spreadsheet/ParseExcel/FmtDefault.pm#L141-L161

sub ValFmt {
    my ( $oThis, $oCell, $oBook ) = @_;

    my ( $Dt, $iFmtIdx, $iNumeric, $Flg1904 );

    if ( $oCell->{Type} eq 'Text' ) {
        $Dt =
          ( ( defined $oCell->{Val} ) && ( $oCell->{Val} ne '' ) )
          ? $oThis->TextFmt( $oCell->{Val}, $oCell->{Code} ) # Perform some encoding logic => doesn't cause RCE
          : '';

        return $Dt;
    }
    else {
        $Dt      = $oCell->{Val};
        $Flg1904 = $oBook->{Flg1904};
        my $sFmtStr = $oThis->FmtString( $oCell, $oBook );

        # where RCE lies => $oCell->{Type} must be either "Date" or "Number"
        return ExcelFmt( $sFmtStr, $Dt, $Flg1904, $oCell->{Type} ); 
    }
}

यदि $oCell->{Type} Date या Number है, तो ExcelFmt को कॉल किया जाएगा।

मान $format_str एक अन्य मेथड से लौटाया गया मान है: FmtString https://github.com/jmcnamara/spreadsheet-parseexcel/blob/e33d626d9b9cec91be7520dec1686712313957fb/lib/Spreadsheet/ParseExcel/FmtDefault.pm#L101-L136

sub FmtString {
    my ( $oThis, $oCell, $oBook ) = @_;

    my $sFmtStr =
      $oThis->FmtStringDef( $oBook->{Format}[ $oCell->{FormatNo} ]->{FmtIdx},
        $oBook ); # maps to the correct format string
        
    #...

    unless ( defined($sFmtStr) ) {
        # assigns default format string depending on the value, can ignore
        #...
    }
    return $sFmtStr;
}

एक और फ़ंक्शन कॉल किया जा रहा है, इसलिए हम FmtStringDef की भी जाँच करेंगे https://github.com/jmcnamara/spreadsheet-parseexcel/blob/e33d626d9b9cec91be7520dec1686712313957fb/lib/Spreadsheet/ParseExcel/FmtDefault.pm#L87-L96

sub FmtStringDef {
    my ( $oThis, $iFmtIdx, $oBook, $rhFmt ) = @_;
    my $sFmtStr = $oBook->{FormatStr}->{$iFmtIdx}; # does the mapping

    # More with assigning default format string, can ignore
    #...
}

सभी वेरिएबल स्पष्ट हैं, हम अटैक वेक्टर को इस प्रकार निष्कर्षित कर सकते हैं:

  • इंडेक्स $iFmtIdx के साथ दुर्भावनापूर्ण फ़ॉर्मेट स्ट्रिंग इंजेक्ट करें
  • सुनिश्चित करें कि एक सेल फ़ॉर्मेट $oBook->{Format}[$cellFmtIdx] $iFmtIdx से मैप हो
  • सुनिश्चित करें कि एक सेल उस सेल फ़ॉर्मेट से मैप हो ($oCell->{FormatNo} = $cellFmtIdx) ![[flow 1.png]]

नीचे दिए गए अनुभागों में, मैं विस्तार से बताऊँगा कि पेलोड ने शेल कोड को eval कमांड तक कैसे पहुँचाया। ParseExcel का उपयोग करके .xls फ़ाइल को पार्स करने और ParseXLSX का उपयोग करके .xlsx फ़ाइल को पार्स करने के लिए 2 अनुभाग होंगे।

PoC

प्रदर्शन के लिए, नीचे हमारी तैयार की गई दुर्भावनापूर्ण Excel फ़ाइलों (.xls और .xlsx में) का लिंक है, जो whoami चलाती हैं और परिणाम को /tmp/inject.txt फ़ाइल में संग्रहीत करती हैं। https://gist.github.com/haile01/0f4f19e4441895ef33ff27385080478b

XLS फ़ाइल पर एक्सप्लॉइटेशन

नीचे दिए गए जैसा एक सरल Perl प्रोग्राम लें जो xls फ़ाइल को पार्स करता है और ParseExcel::parse का उपयोग करता है। RCE पार्सिंग के दौरान ही हो जाएगा, किसी भी डेटा को प्राप्त करने से पहले ही।

use strict;
use Spreadsheet::ParseExcel;

my $parser = Spreadsheet::ParseExcel->new();
# file.xls is malicious file from end user
my $workbook = $parser->parse("test.xls");

फ़ॉर्मेट स्ट्रिंग इंजेक्ट करना

Excel 97 बाइनरी फ़ाइलें बाइनरी डेटा के खंडों में संरचित होती हैं, जिन्हें BIFF रिकॉर्ड कहा जाता है। प्रत्येक रिकॉर्ड opCode नामक हेडर (little-endian में) से शुरू होता है, फिर रिकॉर्ड की लंबाई और उसका वास्तविक डेटा होता है।

https://github.com/jmcnamara/spreadsheet-parseexcel/blob/19ea68d2ebf640e06df4f6937fcb43d76a5ec96b/lib/Spreadsheet/ParseExcel.pm#L438

sub QueryNext {
    my ( $q ) = @_;


    if ( $q->{streamPos} + 4 >= $q->{streamLen} ) {
        return 0;
    }

    my $data = substr( $q->{stream}, $q->{streamPos}, 4 );

    ( $q->{opcode}, $q->{length} ) = unpack( 'v2', $data );

    # No biff record should be larger than around 20,000.
    if ( $q->{length} >= 20000 ) {
        return 0;
    }

    if ( $q->{length} > 0 ) {
        $q->{data} = substr( $q->{stream}, $q->{streamPos} + 4, $q->{length} );
    }
    else {
        $q->{data}                     = undef;
        $q->{dont_decrypt_next_record} = 1;
    }

    if ( $q->{encryption} == MS_BIFF_CRYPTO_RC4 ) {
        # Handles with decryption
    }
    elsif ( $q->{encryption} == MS_BIFF_CRYPTO_XOR ) {
        # not implemented
        return 0;
    }
    elsif ( $q->{encryption} == MS_BIFF_CRYPTO_NONE ) {

    }

    $q->{streamPos} += 4 + $q->{length};

    return 1;
}

उसके बाद, उस BIFF रिकॉर्ड डेटा को निकालने के लिए रिकॉर्ड प्रकार का एक संगत हैंडलर उपयोग किया जाता है। https://github.com/jmcnamara/spreadsheet-parseexcel/blob/19ea68d2ebf640e06df4f6937fcb43d76a5ec96b/lib/Spreadsheet/ParseExcel.pm#L576-L580

if ( defined $self->{FuncTbl}->{$record} && !$workbook->{_skip_chart} )
{
		$self->{FuncTbl}->{$record}
			->( $workbook, $record, $record_length, $record_header );
}

फ़ॉर्मेट स्ट्रिंग को _subFormat द्वारा संभाला जाता है, जिसमें opCode = 0x41E होता है। https://github.com/jmcnamara/spreadsheet-parseexcel/blob/19ea68d2ebf640e06df4f6937fcb43d76a5ec96b/lib/Spreadsheet/ParseExcel.pm#L1563-L1585

sub _subFormat {

    my ( $oBook, $bOp, $bLen, $sWk ) = @_;
    my $sFmt;

    if ( $oBook->{BIFFVersion} <= verBIFF5 ) {
        $sFmt = substr( $sWk, 3, unpack( 'c', substr( $sWk, 2, 1 ) ) );
        $sFmt = $oBook->{FmtClass}->TextFmt( $sFmt, '_native_' );
    }
    else {
        $sFmt = _convBIFF8String( $oBook, substr( $sWk, 2 ) );
    }

    my $format_index = unpack( 'v', substr( $sWk, 0, 2 ) );

    # Excel 4 and earlier used an index of 0 to indicate that a built-in format
    # that was stored implicitly.
    if ( $oBook->{BIFFVersion} <= verBIFF4 && $format_index == 0 ) {
        $format_index = keys %{ $oBook->{FormatStr} };
    }

    $oBook->{FormatStr}->{$format_index} = $sFmt;
}

मुझे यकीन नहीं था कि मेरी .xls फ़ाइल में कौन सा BIFF संस्करण उपयोग हो रहा है, लेकिन बाइनरी फ़ाइल के डेटा के अनुसार, यह else केस (> verBIFF5) से मेल खाना चाहिए।

नए BIFF संस्करणों में फ़ॉर्मेट स्ट्रिंग रिकॉर्ड की संरचना इस प्रकार होनी चाहिए 1E 04 [रिकॉर्ड लंबाई - 2 बाइट्स] [फ़ॉर्मेट स्ट्रिंग इंडेक्स - 2 बाइट्स] [फ़ॉर्मेट स्ट्रिंग लंबाई - 1 बाइट] [स्ट्रिंग फ़्लैग्स - 2 बाइट्स] [फ़ॉर्मेट स्ट्रिंग सामग्री]

सही संरचना का पालन करके, मैं .xls फ़ाइल में कोई भी फ़ॉर्मेट स्ट्रिंग इंजेक्ट कर सकता हूँ।

टूल डाउनलोड करें