|  | 
|  | 1 | +--- | 
|  | 2 | +layout: post | 
|  | 3 | +title: "JS-Recon is no more!" | 
|  | 4 | +date: "2019-04-23 17:47:21 +0530" | 
|  | 5 | +tag: | 
|  | 6 | +  - security | 
|  | 7 | +  - attack | 
|  | 8 | +  - vulnerability | 
|  | 9 | +  - javascript | 
|  | 10 | +  - jsrecon | 
|  | 11 | +--- | 
|  | 12 | + | 
|  | 13 | +In 2010, Andlabs discovered an attack to fingerprint open TCP ports at client | 
|  | 14 | +workstation. Here is a blog post from them which is describing this | 
|  | 15 | +vulnerability. JS-Recon was a tool developed by them proving the weakness of | 
|  | 16 | +the browser. Unfortunately JS-Recon is not available on mentioned link for | 
|  | 17 | +unknown reasons. I tried my best to find the source code of that tool, but I | 
|  | 18 | +was ended with no results. Because the source code of the tool is not | 
|  | 19 | +available, the only way to confirm the possibility of this attack was to | 
|  | 20 | +reconstruct it from steps mentioned by the author.rom steps mentioned by the | 
|  | 21 | +author. | 
|  | 22 | + | 
|  | 23 | +In this post I will share my experience of rebuilding this attack. Because this | 
|  | 24 | +attack is from the front-end side, knowledge of basic Javascript API is | 
|  | 25 | +expected from the reader. The original blog post does not include any code | 
|  | 26 | +samples. For the easiness of the reader, I have prepared small code snippets | 
|  | 27 | +and attached them with related sections. I expect you run code samples at the | 
|  | 28 | +developer console of your browser. | 
|  | 29 | + | 
|  | 30 | +### Glossary | 
|  | 31 | + | 
|  | 32 | +* **Empty / Available port**: A port where no service is running. | 
|  | 33 | +* **Non-empty / Occupied port**: A port where some service is running. | 
|  | 34 | +* **XHR**: A short form of [XML Http Request][mdn_xhr]. | 
|  | 35 | +* **Socket**: A TCP/IP raw socket. | 
|  | 36 | + | 
|  | 37 | +According to the author, If I write a Javascript code to open a XHR to | 
|  | 38 | +http://localhost:8084 and host that code at xyz.com then when you visit the | 
|  | 39 | +xyz.com the browser will open that XHR to port 8084 of your workstation, | 
|  | 40 | +because the localhost for your browser is your workstation. This gap invites | 
|  | 41 | +many vulnerabilities for users. One of them is the possibility to fingerprint | 
|  | 42 | +open TCP ports at client workstation. | 
|  | 43 | + | 
|  | 44 | +The author claims that the browser takes recognizably more time to open a XHR | 
|  | 45 | +targeting an occupied port. Comparatively, time took to open a XHR aimed at an | 
|  | 46 | +empty port was short. | 
|  | 47 | + | 
|  | 48 | +```javascript | 
|  | 49 | +//Sample code to measure the time browser took to open the socket. | 
|  | 50 | + | 
|  | 51 | +var requestPort = function(port) { | 
|  | 52 | +  var startTime = null; | 
|  | 53 | +  var xhr = new XMLHttpRequest(); | 
|  | 54 | +  xhr.onreadystatechange = function() { | 
|  | 55 | +    if (xhr.readyState === 1) { | 
|  | 56 | +      var timeTook = Date.now() - startTime; | 
|  | 57 | +      console.log("Browser took : " + timeTook + " microsecounds to open."); | 
|  | 58 | +    } | 
|  | 59 | +  }; | 
|  | 60 | +  startTime = Date.now(); | 
|  | 61 | +  url = "http://localhost:" + port; | 
|  | 62 | +  xhr.open("GET", url, true); | 
|  | 63 | +}; | 
|  | 64 | +``` | 
|  | 65 | + | 
|  | 66 | +You can paste this code at a developer console of your browser. Calling this | 
|  | 67 | +function by writing `requestPort(8084)` at a console will open the XHR for port | 
|  | 68 | +`8084`. The function will print the time browser took to open a socket on that | 
|  | 69 | +port. I request you to call this function with a combination of empty and | 
|  | 70 | +non-empty ports to find response timings. | 
|  | 71 | + | 
|  | 72 | +I tried opening a bunch of requests using `requestPort()` function at suspected | 
|  | 73 | +ports. For me the method was giving unidentifiable pattern in the time browser | 
|  | 74 | +took to open a socket. Below is a histogram of comparing time took to open a | 
|  | 75 | +socket on empty port(8084) and non-empty port(27017). | 
|  | 76 | + | 
|  | 77 | + | 
|  | 78 | + | 
|  | 79 | + | 
|  | 80 | +Above is a graph of 6000 requests done to measure the response time using a | 
|  | 81 | +function I shared earlier. More than 5000 requests has ended in nearly no time. | 
|  | 82 | +There were less than 1000 requests which ended in 1 microseconds. From the | 
|  | 83 | +above results, We can conclude that mentioned method is not giving different | 
|  | 84 | +results for occupied and empty port. We can conclude that mentioned method by | 
|  | 85 | +AndLabs is failing to distinguish an occupied port from a non occupied port. | 
|  | 86 | + | 
|  | 87 | +I tried hard to find any possible cause for the failure of this attack. I | 
|  | 88 | +didn't found any certain evidences. May be our hardware or browser code has | 
|  | 89 | +improved for opening a TCP sockets quicker than what it used to. I will not | 
|  | 90 | +lie, but that abstract blog post by the AndLabs took sometime to understand the | 
|  | 91 | +anatomy of this attack. I wasn't happy with going back from this point. Just | 
|  | 92 | +for my satisfaction, I tried every possible combinations of `xhr.readyState` | 
|  | 93 | +values to find any pattern. From my observation, I recognized that timing for | 
|  | 94 | +returning a header from an occupied port was delayed. Comparatively, this | 
|  | 95 | +response was quick for ports where no service was running. I am comparing the | 
|  | 96 | +time browser took to return a response headers whereas in the previous method | 
|  | 97 | +it was dependent on the time browser took for opening a socket. | 
|  | 98 | + | 
|  | 99 | +```javascript | 
|  | 100 | +var requestPort = function(port) { | 
|  | 101 | +  var startTime = null; | 
|  | 102 | +  var xhr = new XMLHttpRequest(); | 
|  | 103 | +  xhr.onreadystatechange = function() { | 
|  | 104 | +    if (xhr.readyState === 2) { | 
|  | 105 | +      var timeTook = Date.now() - startTime; | 
|  | 106 | +      console.log("Browser took : " + timeTook + " microsecounds to send response headers."); | 
|  | 107 | +    } | 
|  | 108 | +  }; | 
|  | 109 | +  startTime = Date.now(); | 
|  | 110 | +  url = "http://localhost:" + port; | 
|  | 111 | +  xhr.open("GET", url, true); | 
|  | 112 | +  xhr.send(null); | 
|  | 113 | +}; | 
|  | 114 | +``` | 
|  | 115 | + | 
|  | 116 | +Above code will measure the time browser took to receive headers from the | 
|  | 117 | +destination. You should call this function requestPort() with a few | 
|  | 118 | +combinations of empty and non-empty ports. | 
|  | 119 | + | 
|  | 120 | + | 
|  | 121 | + | 
|  | 122 | +This graph is representing header response time of 6000 requests fired at both | 
|  | 123 | +active (27017) and inactive port (8084). The response time of inactive port not | 
|  | 124 | +go beyond 200 microseconds. Comparing this with a header response time of | 
|  | 125 | +occupied ports, we can see that response time of non-empty port is recognizably | 
|  | 126 | +higher than empty port. | 
|  | 127 | + | 
|  | 128 | +Browser is the most common tool used by us. Asserting this venerability requires | 
|  | 129 | +knowledge of Javascript and everyone is not a developer. As I mentioned earlier, | 
|  | 130 | +I failed to find the source code of JS-Recon (the tool written by AndLabs | 
|  | 131 | +proving possibility of this attack). For those reasons, I decided to write a | 
|  | 132 | +tool pioneered on my improvements on an attempt of Andlabs.  Today, I have | 
|  | 133 | +successfully completed that tool. I have decided to name it | 
|  | 134 | +["Chatur"][chatur_pronounciation]. Chatur means intelligent person in Hindi. | 
|  | 135 | +Please find the source code of Chatur [here][chatur_github]. Chatur is a free | 
|  | 136 | +software. Try this tool and share your thoughts with me. This is not a | 
|  | 137 | +bulletproofed idea, but it works most of the time you will try. | 
|  | 138 | + | 
|  | 139 | +[andlabs_blogpost]: http://blog.andlabs.org/2010/12/port-scanning-with-html5-and-js-recon.html | 
|  | 140 | +[mdn_xhr]: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest | 
|  | 141 | +[chatur_pronounciation]: https://youtu.be/Tih_dP_Tv2w | 
|  | 142 | +[chatur_github]: https://github.com/ultimatecoder/chatur | 
0 commit comments