访问index.php.bak得到index.php的源码
<?php /* PHP Encode by http://Www.PHPJiaMi.Com/ */error_reporting(0);ini_set("display_errors", 0);if(!defined('jnggfmpt')){define('jnggfmpt',__FILE__);if(!function_exists("鯒仅熫")){functi.省略。。。。。。
可以看出这是个phpjiami的加密文件。得解密
这里直接看到了个脚本
https://vsalw.com/wp-content/uploads/phpjiami.zip
将加密文件放入encode目录下。然后访问index.php即可
index.php
<?php
if($_FILES) {
include 'UploadFile.class.php';
$dist = 'upload';
$upload = new UploadFile($dist, 'upfile');
$data = $upload->upload();
}
?>
UploadFile.class.php
<?php
class UploadFile {
public $error = '';
protected $field;
protected $allow_ext;
protected $allow_size;
protected $dist_path;
protected $new_path;
function __construct($dist_path, $field='upfile', $new_name='random', $allow_ext=['gif', 'jpg', 'jpeg', 'png'], $allow_size=102400)
{
$this->field = $field;
$this->allow_ext = $allow_ext;
$this->allow_size = $allow_size;
$this->dist_path = realpath($dist_path);
if ($new_name === 'random') {
$this->new_name = uniqid();
} elseif (is_string($new_name)) {
$this->new_name = $new_name;
} else {
$this->new_name = null;
}
}
protected function codeToMessage($code)
{
switch ($code) {
case UPLOAD_ERR_INI_SIZE:
$message = "The uploaded file exceeds the upload_max_filesize directive in php.ini";
break;
case UPLOAD_ERR_FORM_SIZE:
$message = "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form";
break;
case UPLOAD_ERR_PARTIAL:
$message = "The uploaded file was only partially uploaded";
break;
case UPLOAD_ERR_NO_FILE:
$message = "No file was uploaded";
break;
case UPLOAD_ERR_NO_TMP_DIR:
$message = "Missing a temporary folder";
break;
case UPLOAD_ERR_CANT_WRITE:
$message = "Failed to write file to disk";
break;
case UPLOAD_ERR_EXTENSION:
$message = "File upload stopped by extension";
break;
default:
$message = "Unknown upload error";
break;
}
return $message;
}
protected function error($info)
{
$this->error = $info;
return false;
}
public function upload()
{
if(empty($_FILES[$this->field])) {
return $this->error('上传文件为空');
}
if(is_array($_FILES[$this->field]['error'])) {
return $this->error('一次只能上传一个文件');
}
if($_FILES[$this->field]['error'] != UPLOAD_ERR_OK) {
return $this->error($this->codeToMessage($_FILES[$this->field]['error']));
}
$filename = !empty($_POST[$this->field]) ? $_POST[$this->field] : $_FILES[$this->field]['name'];
if(!is_array($filename)) {
$filename = explode('.', $filename);
}
foreach ($filename as $name) {
if(preg_match('#[<>:"/\\|?*.]#is', $name)) {
return $this->error('文件名中包含非法字符');
}
}
if($_FILES[$this->field]['size'] > $this->allow_size) {
return $this->error('你上传的文件太大');
}
if(!in_array($filename[count($filename)-1], $this->allow_ext)) {
return $this->error('只允许上传图片文件');
}
// 用.分割文件名,只保留首尾两个字符串,防御Apache解析漏洞
$origin_name = current($filename);
$ext = end($filename);
$new_name = ($this->new_name ? $this->new_name : $origin_name) . '.' . $ext;
$target_fullpath = $this->dist_path . DIRECTORY_SEPARATOR . $new_name;
// 创建目录
if(!is_dir($this->dist_path)) {
mkdir($this->dist_path);
}
if(is_uploaded_file($_FILES[$this->field]['tmp_name']) && move_uploaded_file($_FILES[$this->field]['tmp_name'], $target_fullpath)) {
// Success upload
} elseif (rename($_FILES[$this->field]['tmp_name'], $target_fullpath)) {
// Success upload
} else {
return $this->error('写入文件失败,可能是目标目录不可写');
}
return [
'name' => $origin_name,
'filename' => $new_name,
'type' => $ext
];
}
}
关键文件上传后缀名有关的代码就几行。
public function upload()
{
if(empty($_FILES[$this->field])) {
return $this->error('上传文件为空');
}
if(is_array($_FILES[$this->field]['error'])) {
return $this->error('一次只能上传一个文件');
}
if($_FILES[$this->field]['error'] != UPLOAD_ERR_OK) {
return $this->error($this->codeToMessage($_FILES[$this->field]['error']));
}
$filename = !empty($_POST[$this->field]) ? $_POST[$this->field] : $_FILES[$this->field]['name'];
if(!is_array($filename)) {
$filename = explode('.', $filename);
}
foreach ($filename as $name) {
if(preg_match('#[<>:"/\\|?*.]#is', $name)) {
return $this->error('文件名中包含非法字符');
}
}
if($_FILES[$this->field]['size'] > $this->allow_size) {
return $this->error('你上传的文件太大');
}
if(!in_array($filename[count($filename)-1], $this->allow_ext)) {
return $this->error('只允许上传图片文件');
}
// 用.分割文件名,只保留首尾两个字符串,防御Apache解析漏洞
$origin_name = current($filename);
$ext = end($filename);
$new_name = ($this->new_name ? $this->new_name : $origin_name) . '.' . $ext;
$target_fullpath = $this->dist_path . DIRECTORY_SEPARATOR . $new_name;
这里用$_FILES
来判断多文件上传。用$_POST
来进行后缀名操作
将$_POST['upfile']
赋值为$filename
。然后以点号分割。取count(数组)-1。然后取数组最后的一个元素当后缀名。
这里就存在一个差异。
当我post一个数组时。它并不算在$_FILES
里面。只是单纯的作为post数据。那么自然可以绕过多文件上传
然后就是绕过后缀名了。
众所周知。我们可以以数组的方式提交参数。例如a[1]=test
php接受到的是array(1=>'test')
那么我们post一个数字。类似于array(1=>'jpg',2=>'php')
当进行count(数组)-1来判断文件扩展名时
会匹配到数组[1]
。那么就是jpg。绕过判断
然后取数组中的最后一个元素当后缀名。取到的却是php
之后就拿flag了。。