The Pritunl Client contacted the configured VPN server for specific configuration data before initiating the VPN connection. This data was signed using HMAC SHA-512, however, the signature was never verified by the client. A man-in-the-middle attacker could hijack the connection and supply their own configuration data, causing the Pritunl VPN client to connect to an attacker controlled server and send all traffic through the attacker’s VPN.
Patch:
commit c91229ab7ec49834b64d7635faa65dd4a25b8958
Author: Zachary Huff <[email protected]>
Date: Sat Oct 1 18:05:21 2016 -0400
Validate server signature in conf sync
diff --git a/client/www/js/profile.js b/client/www/js/profile.js
index 78ef4fdbd450..85a29a2e59c9 100644
--- a/client/www/js/profile.js
+++ b/client/www/js/profile.js
@@ -649,6 +649,32 @@ Profile.prototype.sync = function(syncHosts, callback) {
utils.authRequest('get', host, pth, this.syncToken, this.syncSecret, null,
function(err, resp, body) {
+ try {
+ var data = JSON.parse(body);
+ } catch (_) {
+ if (callback) {
+ callback();
+ }
+ return;
+ }
+
+ if (!data.signature || !data.conf) {
+ if (callback) {
+ callback();
+ }
+ return;
+ }
+
+ var confSignature = crypto.createHmac('sha512', this.syncSecret).update(
+ data.conf).digest('base64');
+
+ if (confSignature !== data.signature) {
+ if (callback) {
+ callback();
+ }
+ return;
+ }
+
if (err) {
if (!syncHosts.length) {
if (resp) {
@@ -670,7 +696,7 @@ Profile.prototype.sync = function(syncHosts, callback) {
logger.warning('profile: Failed to sync conf, ' +
'authentication error');
} else if (resp.statusCode === 200 && body) {
- this.updateSync(body);
+ this.updateSync(data.conf);
} else if (resp.statusCode !== 200) {
logger.warning('profile: Failed to sync conf, unknown error (' +
resp.statusCode + ')');
diff --git a/client/www/js/utils.js b/client/www/js/utils.js
index 56cdb9e0e8fb..ec377ff75e37 100644
--- a/client/www/js/utils.js
+++ b/client/www/js/utils.js
@@ -32,7 +32,7 @@ var authRequest = function(method, host, path, token, secret, jsonData,
authString = authString.join('&');
- var authSignature = crypto.createHmac('sha256', secret).update(
+ var authSignature = crypto.createHmac('sha512', secret).update(
authString).digest('base64');
var headers = {