Skip to content

Commit 9db350b

Browse files
committed
Adding blog post JS-Recon is no more
JS-Recon was a tool developed by Andlabs proving the vulnerability of fingerprinting active TCP ports at client workstation. Unfortunately that tool is not available. This blog post describes my analysis of success of that method in present condition and share tool developed by me for non-developer mass.
1 parent 3f9901b commit 9db350b

File tree

3 files changed

+142
-0
lines changed

3 files changed

+142
-0
lines changed

Diff for: _posts/2019-04-23-js-recon-is-no-more.md

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
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+
![Graph showing response time to open socket.]({{site.url}}/assets/images/js_recon_is_no_more/graph_response_time_open_socket.png)
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+
![Graph showing header response time.]({{site.url}}/assets/images/js_recon_is_no_more/graph_header_response_time.png)
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
Loading
Loading

0 commit comments

Comments
 (0)