shell bypass 403
<?php
/**
* @package RSForm! Pro
* @copyright (C) 2007-2019 www.rsjoomla.com
* @license GPL, http://www.gnu.org/copyleft/gpl.html
*/
defined('_JEXEC') or die;
use Joomla\String\StringHelper;
use Joomla\Archive\Zip;
use Joomla\CMS\Factory;
if (!class_exists('ZipArchive')) {
// Attempt to emulate if ZipArchive does not exist (highly unlikely)
class ZipArchive
{
const CREATE = 1;
protected $filename;
protected $files = array();
public function open($filename, $flag) {
$this->filename = $filename;
return is_writable(dirname($filename));
}
public function addEmptyDir($dir) {}
public function addFile($path, $filename) {
$this->addFromString($filename, file_get_contents($path));
}
public function addFromString($filename, $contents) {
$this->files[] = array(
'name' => $filename,
'data' => $contents
);
}
public function close() {
$zip = new Zip();
$zip->create($this->filename, $this->files);
}
}
}
class RSFormProXLSX
{
protected $cell_formats = array('GENERAL');
// Temporary filename
protected $filename;
// Submissions counter
protected $start;
// Max rows counter
protected $rows;
// Use headers flag
public $useHeaders = false;
// Form name
public $name;
// File pointer
public $fp;
public function open($filename, $mode, $start, $rows = null, $cols = null) {
$this->filename = $filename;
$this->start = $start;
$this->fp = @fopen($filename, $mode);
if (!is_resource($this->fp)) {
throw new Exception("Could not open $filename for writing.");
}
if ($mode == 'w') {
$xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n".
'<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">'."\n".
'<sheetPr filterMode="false">'."\n".
'<pageSetUpPr fitToPage="false"/>'."\n".
'</sheetPr>'."\n".
'<dimension ref="A1:' . $this->getCellName($rows, $cols) . '"/>'."\n".
'<sheetViews>'."\n".
'<sheetView colorId="64" defaultGridColor="true" rightToLeft="false" showFormulas="false" showGridLines="true" showOutlineSymbols="true" showRowColHeaders="true" showZeros="true" tabSelected="true" topLeftCell="A1" view="normal" windowProtection="false" workbookViewId="0" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100">'."\n".
'<selection activeCell="A1" activeCellId="0" pane="topLeft" sqref="A1"/>'."\n".
'</sheetView>'."\n".
'</sheetViews>'."\n".
'<cols>'."\n".
'<col collapsed="false" hidden="false" max="1025" min="1" style="0" width="11.5"/>'."\n".
'</cols>'."\n".
'<sheetData>'."\n";
if (!fwrite($this->fp, $xml)) {
throw new Exception("Could not write sheet XML head data to $filename.");
}
}
}
public function write($data) {
$this->rows = $this->start + count($data);
foreach ($data as $num => $row) {
$this->writeRow($num, $row);
}
}
public function writeHeaders($data) {
$xml = '<row collapsed="false" customFormat="false" customHeight="false" hidden="false" ht="12.1" outlineLevel="0" r="1">'."\n";
$column_number = 0;
foreach ($data as $key => $value) {
$xml .= $this->writeCell(0, $column_number, $value);
$column_number++;
}
$xml .= '</row>'."\n";
fwrite($this->fp, $xml);
}
protected function writeRow($num, $row) {
if ($this->useHeaders) {
// Skip one row since we have headers in that one
$num++;
}
$xml = '<row collapsed="false" customFormat="false" customHeight="false" hidden="false" ht="12.1" outlineLevel="0" r="' . ($this->start + $num + 1) . '">'."\n";
$column_number = 0;
foreach ($row as $key => $value) {
$xml .= $this->writeCell($this->start + $num, $column_number, $value);
$column_number++;
}
$xml .= '</row>'."\n";
fwrite($this->fp, $xml);
}
protected function writeCell($row_number, $column_number, $value)
{
$cell_name = $this->getCellName($row_number, $column_number);
return "\t".'<c r="'.$cell_name.'" s="0" t="inlineStr"><is><t>'.$this->escape($value).'</t></is></c>'."\n";
}
public function close() {
$zip = new ZipArchive();
if (!$zip->open($this->filename.'.zip', ZipArchive::CREATE)) {
throw new Exception("Could not create archive {$this->filename}.zip.");
}
$zip->addEmptyDir("_rels/");
$zip->addEmptyDir("docProps/");
$zip->addEmptyDir("xl/_rels/");
$zip->addEmptyDir("xl/worksheets/");
$zip->addFromString("[Content_Types].xml", $this->buildContentTypesXML());
$zip->addFromString("docProps/app.xml", $this->buildAppXML());
$zip->addFromString("docProps/core.xml", $this->buildCoreXML());
$zip->addFromString("_rels/.rels", $this->buildRelationshipsXML());
$zip->addFromString("xl/_rels/workbook.xml.rels", $this->buildWorkbookRelsXML());
$zip->addFromString("xl/styles.xml", $this->buildStylesXML());
$zip->addFromString("xl/workbook.xml", $this->buildWorkbookXML());
// Finalize sheet
$xml = '</sheetData>'."\n".
'<printOptions headings="false" gridLines="false" gridLinesSet="true" horizontalCentered="false" verticalCentered="false"/>'."\n".
'<pageMargins left="0.5" right="0.5" top="1.0" bottom="1.0" header="0.5" footer="0.5"/>'."\n".
'<pageSetup blackAndWhite="false" cellComments="none" copies="1" draft="false" firstPageNumber="1" fitToHeight="1" fitToWidth="1" horizontalDpi="300" orientation="portrait" pageOrder="downThenOver" paperSize="1" scale="100" useFirstPageNumber="true" usePrinterDefaults="false" verticalDpi="300"/>'."\n".
'<headerFooter differentFirst="false" differentOddEven="false">'."\n".
'<oddHeader>&C&"Times New Roman,Regular"&12&A</oddHeader>'."\n".
'<oddFooter>&C&"Times New Roman,Regular"&12Page &P</oddFooter>'."\n".
'</headerFooter>'."\n".
'</worksheet>';
fwrite($this->fp, $xml);
$zip->addFile($this->filename, "xl/worksheets/sheet1.xml");
$zip->close();
}
protected function buildAppXML()
{
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n".
'<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><TotalTime>0</TotalTime></Properties>';
}
protected function buildCoreXML()
{
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n".
'<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'."\n".
'<dcterms:created xsi:type="dcterms:W3CDTF">'.Factory::getDate()->format("Y-m-d\TH:i:s.00\Z").'</dcterms:created>'."\n".
'<dc:creator>'.$this->escape(Factory::getUser()->name).'</dc:creator>'."\n".
'<cp:revision>0</cp:revision>'."\n".
'</cp:coreProperties>';
}
protected function buildRelationshipsXML()
{
return '<?xml version="1.0" encoding="UTF-8"?>'."\n".
'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'."\n".
'<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>'."\n".
'<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>'."\n".
'<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>'."\n".
'</Relationships>';
}
protected function buildWorkbookXML()
{
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n".
'<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">'."\n".
'<fileVersion appName="Calc"/><workbookPr backupFile="false" showObjects="all" date1904="false"/><workbookProtection/>'."\n".
'<bookViews><workbookView activeTab="0" firstSheet="0" showHorizontalScroll="true" showSheetTabs="true" showVerticalScroll="true" tabRatio="212" windowHeight="8192" windowWidth="16384" xWindow="0" yWindow="0"/></bookViews>'."\n".
'<sheets>'."\n".
'<sheet name="'.$this->escapeSheet($this->name).'" sheetId="1" state="visible" r:id="rId2"/>'."\n".
'</sheets>'."\n".
'<calcPr iterateCount="100" refMode="A1" iterate="false" iterateDelta="0.001"/>'."\n".
'</workbook>';
}
protected function escapeSheet($string)
{
// https://www.accountingweb.com/technology/excel/seven-characters-you-cant-use-in-worksheet-names
$string = str_replace(array('\\', '/', '*', '[', ']', ':', '?'), '', $string);
if (StringHelper::strlen($string) > 31)
{
$string = StringHelper::substr($string, 0, 31);
}
return $this->escape($string);
}
protected function buildWorkbookRelsXML()
{
return '<?xml version="1.0" encoding="UTF-8"?>'."\n".
'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'."\n".
'<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>'."\n".
'<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>'."\n".
'</Relationships>';
}
protected function buildContentTypesXML()
{
return '<?xml version="1.0" encoding="UTF-8"?>'."\n".
'<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'."\n".
'<Override PartName="/_rels/.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>'."\n".
'<Override PartName="/xl/_rels/workbook.xml.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>'."\n".
'<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>'."\n".
'<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>'."\n".
'<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>'."\n".
'<Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>'."\n".
'<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>'."\n".
'</Types>';
}
protected function buildStylesXML()
{
$xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n".
'<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">'."\n".
'<numFmts count="'.count($this->cell_formats).'">'."\n";
foreach ($this->cell_formats as $i => $format) {
$xml .= '<numFmt numFmtId="'.(164 + $i).'" formatCode="'.$this->escape($format).'" />'."\n";
}
$xml .= '</numFmts>'."\n".
'<fonts count="4">'."\n".
'<font><name val="Arial"/><charset val="1"/><family val="2"/><sz val="10"/></font>'."\n".
'<font><name val="Arial"/><family val="0"/><sz val="10"/></font>'."\n".
'<font><name val="Arial"/><family val="0"/><sz val="10"/></font>'."\n".
'<font><name val="Arial"/><family val="0"/><sz val="10"/></font>'."\n".
'</fonts>'."\n".
'<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>'."\n".
'<borders count="1"><border diagonalDown="false" diagonalUp="false"><left/><right/><top/><bottom/><diagonal/></border></borders>'."\n".
'<cellStyleXfs count="20">'."\n".
'<xf applyAlignment="true" applyBorder="true" applyFont="true" applyProtection="true" borderId="0" fillId="0" fontId="0" numFmtId="164">'."\n".
'<alignment horizontal="general" indent="0" shrinkToFit="false" textRotation="0" vertical="bottom" wrapText="false"/>'."\n".
'<protection hidden="false" locked="true"/>'."\n".
'</xf>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="0"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="0"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="2" numFmtId="0"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="2" numFmtId="0"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="43"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="41"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="44"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="42"/>'."\n".
'<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="9"/>'."\n".
'</cellStyleXfs>'."\n";
$xml .= '<cellXfs count="'.count($this->cell_formats).'">'."\n";
foreach ($this->cell_formats as $i => $format)
{
$xml .= '<xf applyAlignment="false" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="'.(164 + $i).'" xfId="0"/>'."\n";
}
$xml .= '</cellXfs>'."\n".
'<cellStyles count="6">'."\n".
'<cellStyle builtinId="0" customBuiltin="false" name="Normal" xfId="0"/>'."\n".
'<cellStyle builtinId="3" customBuiltin="false" name="Comma" xfId="15"/>'."\n".
'<cellStyle builtinId="6" customBuiltin="false" name="Comma [0]" xfId="16"/>'."\n".
'<cellStyle builtinId="4" customBuiltin="false" name="Currency" xfId="17"/>'."\n".
'<cellStyle builtinId="7" customBuiltin="false" name="Currency [0]" xfId="18"/>'."\n".
'<cellStyle builtinId="5" customBuiltin="false" name="Percent" xfId="19"/>'."\n".
'</cellStyles>'."\n".
'</styleSheet>'."\n";
return $xml;
}
public function getCellName($row_number, $column_number)
{
$n = $column_number;
for($r = ""; $n >= 0; $n = intval($n / 26) - 1) {
$r = chr($n%26 + 0x41) . $r;
}
return $r . ($row_number+1);
}
protected function escape($string) {
return htmlspecialchars($string, ENT_QUOTES, 'utf-8');
}
}