Skip to content

Commit 307ab7f

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 307ab7f

File tree

5 files changed

+299
-0
lines changed

5 files changed

+299
-0
lines changed

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

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
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/graph_responnse_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/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
129+
requires knowledge of Javascript and everyone is not a developer. As I
130+
mentioned earlier, I failed to find the source code of JS-Recon (the tool
131+
written by AndLabs proving possibility of this attack). For those reasons, I
132+
decided to write a tool pioneered on my improvements on an attempt of Andlabs.
133+
Today, I have successfully completed that tool. I have decided to name it
134+
["Chatur"][chatur_pronounciation]. Chatur means intelligent person in Hindi.
135+
Chatur is a free software. Try this tool and share your thoughts with me. This
136+
is not a bulletproofed idea, but it works most of the time you will try.
137+
138+
[andlabs_blogpost]: http://blog.andlabs.org/2010/12/port-scanning-with-html5-and-js-recon.html
139+
[mdn_xhr]: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
140+
[chatur_pronounciation]: https://youtu.be/Tih_dP_Tv2w

Diff for: _posts/draft.md

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

Diff for: _posts/points.md

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
* Mention that knowledge of XML Http Request is expected to understand this blog
2+
post. Dealing with the browser developer console is good to understand this
3+
post.
4+
Exploring method discovered by AndLabs
5+
* Explain the process explained in the blog post.
6+
* Code snippet of sensing time took to open TCP connection for single request
7+
* The code should be copy able
8+
* Put instruction to try this code at the developer console of their
9+
browser.
10+
* Show that this method somehow do not work as claimed by the author
11+
* Prepare a code that floods the port and collects data of the time took to
12+
open the socket for all the requests.
13+
* Prepare this code as the Github gist
14+
* This will help people to identify and try the snippet at the developer
15+
console of their browser.
16+
* Make your conclusion
17+
* May be because of SSD
18+
* Did you tried running this code at HDD? If possible run this script
19+
20+
Exploring method tried by you (inspired from AndLabs)
21+
* Explain the process
22+
* You sent the actual request
23+
* Measures the time when headers are returned from the destination
24+
* Mention that it is not all time effective, but works most of the time
25+
* Share the code snippet just to measure the response time client took to sent
26+
the headers
27+
* Prepare the code which floods the port and measure this time
28+
* Share this code via Github gist
29+
* The reader should be able to copy this code to their browser console
30+
* Introduce Chatur (the tool you wrote on your this hypothesis)
Loading
Loading

0 commit comments

Comments
 (0)