1<?php 2// stolen from PEAR2_Pyrus_Developer_Creator_Tar by Greg Beaver, the original author, for use in unit tests 3// this tarmaker makes a malicious tar with a header designed to overflow the buffer 4class danger_tarmaker 5{ 6 /** 7 * Path to archive file 8 * 9 * @var string 10 */ 11 protected $archive; 12 /** 13 * Temporary stream used for creating the archive 14 * 15 * @var stream 16 */ 17 protected $tmp; 18 protected $path; 19 protected $compress; 20 function __construct($path, $compress = 'zlib') 21 { 22 $this->compress = $compress; 23 if ($compress === 'bz2' && !function_exists('bzopen')) { 24 throw new PEAR2_Pyrus_Developer_Creator_Exception( 25 'bzip2 extension not available'); 26 } 27 if ($compress === 'zlib' && !function_exists('gzopen')) { 28 throw new PEAR2_Pyrus_Developer_Creator_Exception( 29 'zlib extension not available'); 30 } 31 $this->path = $path; 32 } 33 34 /** 35 * save a file inside this package 36 * 37 * This code is modified from Vincent Lascaux's File_Archive 38 * package, which is licensed under the LGPL license. 39 * @param string relative path within the package 40 * @param string|resource file contents or open file handle 41 */ 42 function addFile($path, $fileOrStream, $stat = null) 43 { 44 clearstatcache(); 45 if ($stat === null) { 46 if (is_resource($fileOrStream)) { 47 $stat = fstat($fileOrStream); 48 } else { 49 $stat = array( 50 'mode' => 0x8000 + 0644, 51 'uid' => 0, 52 'gid' => 0, 53 'size' => strlen($fileOrStream), 54 'mtime' => time(), 55 ); 56 } 57 } 58 59 $link = null; 60 if ($stat['mode'] & 0x4000) { 61 $type = 5; // Directory 62 } else if ($stat['mode'] & 0x8000) { 63 $type = 0; // Regular 64 } else if ($stat['mode'] & 0xA000) { 65 $type = 1; // Link 66 $link = @readlink($current); 67 } else { 68 $type = 9; // Unknown 69 } 70 71 $filePrefix = ''; 72 if (strlen($path) > 255) { 73 throw new Exception( 74 "$path is too long, must be 255 characters or less" 75 ); 76 } else if (strlen($path) > 100) { 77 $filePrefix = substr($path, 0, strlen($path)-100); 78 $path = substr($path, -100); 79 } 80 81 $block = pack('a100a8a8a8a12A12', 82 $path, 83 '12345678', // have a mode that allows the name to overflow 84 sprintf('%6s ',decoct($stat['uid'])), 85 sprintf('%6s ',decoct($stat['gid'])), 86 sprintf('%11s ',decoct($stat['size'])), 87 sprintf('%11s ',decoct($stat['mtime'])) 88 ); 89 90 $blockend = pack('a1a100a6a2a32a32a8a8a155a12', 91 $type, 92 $link, 93 'ustar', 94 '00', 95 'Pyrus', 96 'Pyrus', 97 '', 98 '', 99 $filePrefix, 100 '123456789abc'); // malicious block 101 102 $checkheader = array_merge(str_split($block), str_split($blockend)); 103 if (!function_exists('_pear2tarchecksum')) { 104 function _pear2tarchecksum($a, $b) {return $a + ord($b);} 105 } 106 $checksum = 256; // 8 * ord(' '); 107 $checksum += array_reduce($checkheader, '_pear2tarchecksum'); 108 109 $checksum = pack('a8', sprintf('%6s ', decoct($checksum))); 110 111 fwrite($this->tmp, (binary)$block . $checksum . $blockend, 512); 112 if (is_resource($fileOrStream)) { 113 stream_copy_to_stream($fileOrStream, $this->tmp); 114 if ($stat['size'] % 512) { 115 fwrite($this->tmp, (binary)str_repeat("\0", 512 - $stat['size'] % 512)); 116 } 117 } else { 118 fwrite($this->tmp, (binary)$fileOrStream); 119 if (strlen($fileOrStream) % 512) { 120 fwrite($this->tmp, (binary)str_repeat("\0", 512 - strlen($fileOrStream) % 512)); 121 } 122 } 123 } 124 125 /** 126 * Initialize the package creator 127 */ 128 function init() 129 { 130 switch ($this->compress) { 131 case 'zlib' : 132 $this->tmp = gzopen($this->path, 'wb'); 133 break; 134 case 'bz2' : 135 $this->tmp = bzopen($this->path, 'w'); 136 break; 137 case 'none' : 138 $this->tmp = fopen($this->path, 'wb'); 139 break; 140 default : 141 throw new Exception( 142 'unknown compression type ' . $this->compress); 143 } 144 } 145 146 /** 147 * Create an internal directory, creating parent directories as needed 148 * 149 * @param string $dir 150 */ 151 function mkdir($dir) 152 { 153 $this->addFile($dir, "", array( 154 'mode' => 0x4000 + 0644, 155 'uid' => 0, 156 'gid' => 0, 157 'size' => 0, 158 'mtime' => time(), 159 )); 160 } 161 162 /** 163 * Finish saving the package 164 */ 165 function close() 166 { 167 fwrite($this->tmp, pack('a1024', '')); 168 fclose($this->tmp); 169 } 170}