Back to index

php5  5.3.10
make.dangerous.tar.php.inc
Go to the documentation of this file.
00001 <?php
00002 // stolen from PEAR2_Pyrus_Developer_Creator_Tar by Greg Beaver, the original author, for use in unit tests
00003 // this tarmaker makes a malicious tar with a header designed to overflow the buffer
00004 class danger_tarmaker
00005 {
00011     protected $archive;
00017     protected $tmp;
00018     protected $path;
00019     protected $compress;
00020     function __construct($path, $compress = 'zlib')
00021     {
00022         $this->compress = $compress;
00023         if ($compress === 'bz2' && !function_exists('bzopen')) {
00024             throw new PEAR2_Pyrus_Developer_Creator_Exception(
00025                 'bzip2 extension not available');
00026         }
00027         if ($compress === 'zlib' && !function_exists('gzopen')) {
00028             throw new PEAR2_Pyrus_Developer_Creator_Exception(
00029                 'zlib extension not available');
00030         }
00031         $this->path = $path;
00032     }
00033 
00042     function addFile($path, $fileOrStream, $stat = null)
00043     {
00044         clearstatcache();
00045         if ($stat === null) {
00046             if (is_resource($fileOrStream)) {
00047                 $stat = fstat($fileOrStream);
00048             } else {
00049                 $stat = array(
00050                     'mode' => 0x8000 + 0644,
00051                     'uid' => 0,
00052                     'gid' => 0,
00053                     'size' => strlen($fileOrStream),
00054                     'mtime' => time(),
00055                 );
00056             }
00057         }
00058 
00059         $link = null;
00060         if ($stat['mode'] & 0x4000) {
00061             $type = 5;        // Directory
00062         } else if ($stat['mode'] & 0x8000) {
00063             $type = 0;        // Regular
00064         } else if ($stat['mode'] & 0xA000) {
00065             $type = 1;        // Link
00066             $link = @readlink($current);
00067         } else {
00068             $type = 9;        // Unknown
00069         }
00070 
00071         $filePrefix = '';
00072         if (strlen($path) > 255) {
00073             throw new Exception(
00074                 "$path is too long, must be 255 characters or less"
00075             );
00076         } else if (strlen($path) > 100) {
00077             $filePrefix = substr($path, 0, strlen($path)-100);
00078             $path = substr($path, -100);
00079         }
00080 
00081         $block = pack('a100a8a8a8a12A12',
00082                 $path,
00083                 '12345678', // have a mode that allows the name to overflow
00084                 sprintf('%6s ',decoct($stat['uid'])),
00085                 sprintf('%6s ',decoct($stat['gid'])),
00086                 sprintf('%11s ',decoct($stat['size'])),
00087                 sprintf('%11s ',decoct($stat['mtime']))
00088             );
00089 
00090         $blockend = pack('a1a100a6a2a32a32a8a8a155a12',
00091             $type,
00092             $link,
00093             'ustar',
00094             '00',
00095             'Pyrus',
00096             'Pyrus',
00097             '',
00098             '',
00099             $filePrefix,
00100             '123456789abc'); // malicious block
00101 
00102         $checkheader = array_merge(str_split($block), str_split($blockend));
00103         if (!function_exists('_pear2tarchecksum')) {
00104             function _pear2tarchecksum($a, $b) {return $a + ord($b);}
00105         }
00106         $checksum = 256; // 8 * ord(' ');
00107         $checksum += array_reduce($checkheader, '_pear2tarchecksum');
00108 
00109         $checksum = pack('a8', sprintf('%6s ', decoct($checksum)));
00110 
00111         fwrite($this->tmp, (binary)$block . $checksum . $blockend, 512);
00112         if (is_resource($fileOrStream)) {
00113             stream_copy_to_stream($fileOrStream, $this->tmp);
00114             if ($stat['size'] % 512) {
00115                 fwrite($this->tmp, (binary)str_repeat("\0", 512 - $stat['size'] % 512));
00116             }
00117         } else {
00118             fwrite($this->tmp, (binary)$fileOrStream);
00119             if (strlen($fileOrStream) % 512) {
00120                 fwrite($this->tmp, (binary)str_repeat("\0", 512 - strlen($fileOrStream) % 512));
00121             }
00122         }
00123     }
00124 
00128     function init()
00129     {
00130         switch ($this->compress) {
00131             case 'zlib' :
00132                 $this->tmp = gzopen($this->path, 'wb');
00133                 break;
00134             case 'bz2' :
00135                 $this->tmp = bzopen($this->path, 'w');
00136                 break;
00137             case 'none' :
00138                 $this->tmp = fopen($this->path, 'wb');
00139                 break;
00140             default :
00141                 throw new Exception(
00142                     'unknown compression type ' . $this->compress);
00143         }
00144     }
00145 
00151     function mkdir($dir)
00152     {
00153         $this->addFile($dir, "", array(
00154                     'mode' => 0x4000 + 0644,
00155                     'uid' => 0,
00156                     'gid' => 0,
00157                     'size' => 0,
00158                     'mtime' => time(),
00159                 ));
00160     }
00161 
00165     function close()
00166     {
00167         fwrite($this->tmp, pack('a1024', ''));
00168         fclose($this->tmp);
00169     }
00170 }