From 9db350b5b41724c6e3724a25c77ecdad12d79e50 Mon Sep 17 00:00:00 2001 From: ultimatecoder Date: Thu, 18 Apr 2019 17:02:23 +0530 Subject: [PATCH 1/8] 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. --- _posts/2019-04-23-js-recon-is-no-more.md | 142 ++++++++++++++++++ .../graph_header_response_time.png | Bin 0 -> 14483 bytes .../graph_response_time_open_socket.png | Bin 0 -> 6785 bytes 3 files changed, 142 insertions(+) create mode 100644 _posts/2019-04-23-js-recon-is-no-more.md create mode 100644 assets/images/js_recon_is_no_more/graph_header_response_time.png create mode 100644 assets/images/js_recon_is_no_more/graph_response_time_open_socket.png diff --git a/_posts/2019-04-23-js-recon-is-no-more.md b/_posts/2019-04-23-js-recon-is-no-more.md new file mode 100644 index 0000000..47a8f5a --- /dev/null +++ b/_posts/2019-04-23-js-recon-is-no-more.md @@ -0,0 +1,142 @@ +--- +layout: post +title: "JS-Recon is no more!" +date: "2019-04-23 17:47:21 +0530" +tag: + - security + - attack + - vulnerability + - javascript + - jsrecon +--- + +In 2010, Andlabs discovered an attack to fingerprint open TCP ports at client +workstation. Here is a blog post from them which is describing this +vulnerability. JS-Recon was a tool developed by them proving the weakness of +the browser. Unfortunately JS-Recon is not available on mentioned link for +unknown reasons. I tried my best to find the source code of that tool, but I +was ended with no results. Because the source code of the tool is not +available, the only way to confirm the possibility of this attack was to +reconstruct it from steps mentioned by the author.rom steps mentioned by the +author. + +In this post I will share my experience of rebuilding this attack. Because this +attack is from the front-end side, knowledge of basic Javascript API is +expected from the reader. The original blog post does not include any code +samples. For the easiness of the reader, I have prepared small code snippets +and attached them with related sections. I expect you run code samples at the +developer console of your browser. + +### Glossary + +* **Empty / Available port**: A port where no service is running. +* **Non-empty / Occupied port**: A port where some service is running. +* **XHR**: A short form of [XML Http Request][mdn_xhr]. +* **Socket**: A TCP/IP raw socket. + +According to the author, If I write a Javascript code to open a XHR to +http://localhost:8084 and host that code at xyz.com then when you visit the +xyz.com the browser will open that XHR to port 8084 of your workstation, +because the localhost for your browser is your workstation. This gap invites +many vulnerabilities for users. One of them is the possibility to fingerprint +open TCP ports at client workstation. + +The author claims that the browser takes recognizably more time to open a XHR +targeting an occupied port. Comparatively, time took to open a XHR aimed at an +empty port was short. + +```javascript +//Sample code to measure the time browser took to open the socket. + +var requestPort = function(port) { + var startTime = null; + var xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function() { + if (xhr.readyState === 1) { + var timeTook = Date.now() - startTime; + console.log("Browser took : " + timeTook + " microsecounds to open."); + } + }; + startTime = Date.now(); + url = "http://localhost:" + port; + xhr.open("GET", url, true); +}; +``` + +You can paste this code at a developer console of your browser. Calling this +function by writing `requestPort(8084)` at a console will open the XHR for port +`8084`. The function will print the time browser took to open a socket on that +port. I request you to call this function with a combination of empty and +non-empty ports to find response timings. + +I tried opening a bunch of requests using `requestPort()` function at suspected +ports. For me the method was giving unidentifiable pattern in the time browser +took to open a socket. Below is a histogram of comparing time took to open a +socket on empty port(8084) and non-empty port(27017). + +![Graph showing response time to open socket.]({{site.url}}/assets/images/js_recon_is_no_more/graph_response_time_open_socket.png) + + +Above is a graph of 6000 requests done to measure the response time using a +function I shared earlier. More than 5000 requests has ended in nearly no time. +There were less than 1000 requests which ended in 1 microseconds. From the +above results, We can conclude that mentioned method is not giving different +results for occupied and empty port. We can conclude that mentioned method by +AndLabs is failing to distinguish an occupied port from a non occupied port. + +I tried hard to find any possible cause for the failure of this attack. I +didn't found any certain evidences. May be our hardware or browser code has +improved for opening a TCP sockets quicker than what it used to. I will not +lie, but that abstract blog post by the AndLabs took sometime to understand the +anatomy of this attack. I wasn't happy with going back from this point. Just +for my satisfaction, I tried every possible combinations of `xhr.readyState` +values to find any pattern. From my observation, I recognized that timing for +returning a header from an occupied port was delayed. Comparatively, this +response was quick for ports where no service was running. I am comparing the +time browser took to return a response headers whereas in the previous method +it was dependent on the time browser took for opening a socket. + +```javascript +var requestPort = function(port) { + var startTime = null; + var xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function() { + if (xhr.readyState === 2) { + var timeTook = Date.now() - startTime; + console.log("Browser took : " + timeTook + " microsecounds to send response headers."); + } + }; + startTime = Date.now(); + url = "http://localhost:" + port; + xhr.open("GET", url, true); + xhr.send(null); +}; +``` + +Above code will measure the time browser took to receive headers from the +destination. You should call this function requestPort() with a few +combinations of empty and non-empty ports. + +![Graph showing header response time.]({{site.url}}/assets/images/js_recon_is_no_more/graph_header_response_time.png) + +This graph is representing header response time of 6000 requests fired at both +active (27017) and inactive port (8084). The response time of inactive port not +go beyond 200 microseconds. Comparing this with a header response time of +occupied ports, we can see that response time of non-empty port is recognizably +higher than empty port. + +Browser is the most common tool used by us. Asserting this venerability requires +knowledge of Javascript and everyone is not a developer. As I mentioned earlier, +I failed to find the source code of JS-Recon (the tool written by AndLabs +proving possibility of this attack). For those reasons, I decided to write a +tool pioneered on my improvements on an attempt of Andlabs. Today, I have +successfully completed that tool. I have decided to name it +["Chatur"][chatur_pronounciation]. Chatur means intelligent person in Hindi. +Please find the source code of Chatur [here][chatur_github]. Chatur is a free +software. Try this tool and share your thoughts with me. This is not a +bulletproofed idea, but it works most of the time you will try. + +[andlabs_blogpost]: http://blog.andlabs.org/2010/12/port-scanning-with-html5-and-js-recon.html +[mdn_xhr]: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest +[chatur_pronounciation]: https://youtu.be/Tih_dP_Tv2w +[chatur_github]: https://github.com/ultimatecoder/chatur diff --git a/assets/images/js_recon_is_no_more/graph_header_response_time.png b/assets/images/js_recon_is_no_more/graph_header_response_time.png new file mode 100644 index 0000000000000000000000000000000000000000..75531b894cd077d8217490603f40fd37c83b60f3 GIT binary patch literal 14483 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 literal 0 HcmV?d00001 diff --git a/assets/images/js_recon_is_no_more/graph_response_time_open_socket.png b/assets/images/js_recon_is_no_more/graph_response_time_open_socket.png new file mode 100644 index 0000000000000000000000000000000000000000..d9344fc1dc0db3ba784b8b4442bdbed7ab962c83 GIT binary patch literal 6785 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 literal 0 HcmV?d00001 From 73dda15755612a5f96c5361ce99a13d5b9f6e731 Mon Sep 17 00:00:00 2001 From: ultimatecoder Date: Wed, 24 Apr 2019 11:35:18 +0530 Subject: [PATCH 2/8] Improving blog post according to comments by TWB --- _posts/2019-04-23-js-recon-is-no-more.md | 69 ++++++++++++------------ 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/_posts/2019-04-23-js-recon-is-no-more.md b/_posts/2019-04-23-js-recon-is-no-more.md index 47a8f5a..0c6db8a 100644 --- a/_posts/2019-04-23-js-recon-is-no-more.md +++ b/_posts/2019-04-23-js-recon-is-no-more.md @@ -11,14 +11,13 @@ tag: --- In 2010, Andlabs discovered an attack to fingerprint open TCP ports at client -workstation. Here is a blog post from them which is describing this -vulnerability. JS-Recon was a tool developed by them proving the weakness of -the browser. Unfortunately JS-Recon is not available on mentioned link for -unknown reasons. I tried my best to find the source code of that tool, but I -was ended with no results. Because the source code of the tool is not -available, the only way to confirm the possibility of this attack was to -reconstruct it from steps mentioned by the author.rom steps mentioned by the -author. +workstation. You can read [this blog post][andlabs_blogpost] which is describing +details of this method. JS-Recon was a tool implementing this attack on its +client to prove the danger of this vulnerability. Unfortunately, JS-Recon is not +available on mentioned link for unknown reasons. I tried my best to find the +source code of that tool, but I was ended with no results. Because the source +code of the tool is not available, the only way to confirm the possibility of +this attack was to reconstruct it from steps mentioned at that blog post. In this post I will share my experience of rebuilding this attack. Because this attack is from the front-end side, knowledge of basic Javascript API is @@ -34,12 +33,12 @@ developer console of your browser. * **XHR**: A short form of [XML Http Request][mdn_xhr]. * **Socket**: A TCP/IP raw socket. -According to the author, If I write a Javascript code to open a XHR to -http://localhost:8084 and host that code at xyz.com then when you visit the -xyz.com the browser will open that XHR to port 8084 of your workstation, -because the localhost for your browser is your workstation. This gap invites -many vulnerabilities for users. One of them is the possibility to fingerprint -open TCP ports at client workstation. +According to that blog post, If I write a Javascript code to open a XHR to +`http://localhost:8084` and host that code at example.com then when you visit +the example.com the browser will open that XHR to port `8084` of your +workstation, because the localhost for your browser is your workstation. This +gap invites many vulnerabilities for users. One of them is the possibility to +fingerprint open TCP ports at client workstation. The author claims that the browser takes recognizably more time to open a XHR targeting an occupied port. Comparatively, time took to open a XHR aimed at an @@ -54,7 +53,7 @@ var requestPort = function(port) { xhr.onreadystatechange = function() { if (xhr.readyState === 1) { var timeTook = Date.now() - startTime; - console.log("Browser took : " + timeTook + " microsecounds to open."); + console.log("Browser took : " + timeTook + " microseconds to open."); } }; startTime = Date.now(); @@ -84,17 +83,17 @@ above results, We can conclude that mentioned method is not giving different results for occupied and empty port. We can conclude that mentioned method by AndLabs is failing to distinguish an occupied port from a non occupied port. -I tried hard to find any possible cause for the failure of this attack. I -didn't found any certain evidences. May be our hardware or browser code has -improved for opening a TCP sockets quicker than what it used to. I will not -lie, but that abstract blog post by the AndLabs took sometime to understand the -anatomy of this attack. I wasn't happy with going back from this point. Just -for my satisfaction, I tried every possible combinations of `xhr.readyState` -values to find any pattern. From my observation, I recognized that timing for -returning a header from an occupied port was delayed. Comparatively, this -response was quick for ports where no service was running. I am comparing the -time browser took to return a response headers whereas in the previous method -it was dependent on the time browser took for opening a socket. +I tried hard to find any possible cause for the failure of this attack. I didn't +found any conclusive evidences. May be our hardware or browser code has improved +for opening a TCP sockets quicker than what it used to. I will not lie, but that +abstract blog post by the AndLabs took sometime to understand the anatomy of +this attack. I wasn't happy with going back from this point. Just for my +satisfaction, I tried every possible combinations of `xhr.readyState` values to +find any pattern. From my observation, I recognized that timing for returning a +header from an occupied port was delayed. Comparatively, this response was quick +for ports where no service was running. I am comparing the time browser took to +return a response headers whereas in the previous method it was dependent on the +time browser took for opening a socket. ```javascript var requestPort = function(port) { @@ -103,7 +102,7 @@ var requestPort = function(port) { xhr.onreadystatechange = function() { if (xhr.readyState === 2) { var timeTook = Date.now() - startTime; - console.log("Browser took : " + timeTook + " microsecounds to send response headers."); + console.log("Browser took : " + timeTook + " microseconds to send response headers."); } }; startTime = Date.now(); @@ -125,15 +124,15 @@ go beyond 200 microseconds. Comparing this with a header response time of occupied ports, we can see that response time of non-empty port is recognizably higher than empty port. -Browser is the most common tool used by us. Asserting this venerability requires -knowledge of Javascript and everyone is not a developer. As I mentioned earlier, -I failed to find the source code of JS-Recon (the tool written by AndLabs -proving possibility of this attack). For those reasons, I decided to write a -tool pioneered on my improvements on an attempt of Andlabs. Today, I have -successfully completed that tool. I have decided to name it +Browser is the most common tool used by us. Asserting this vulnerability +requires knowledge of Javascript and everyone is not a developer. As I mentioned +earlier, I failed to find the source code of JS-Recon (the tool written by +AndLabs proving possibility of this attack). For those reasons, I decided to +write a tool pioneered on my improvements on an attempt of Andlabs. Today, I +have successfully completed that tool. I have decided to name it ["Chatur"][chatur_pronounciation]. Chatur means intelligent person in Hindi. -Please find the source code of Chatur [here][chatur_github]. Chatur is a free -software. Try this tool and share your thoughts with me. This is not a +Please find the source code of Chatur [on Github][chatur_github]. Chatur is a +free software. Try this tool and share your thoughts with me. This is not a bulletproofed idea, but it works most of the time you will try. [andlabs_blogpost]: http://blog.andlabs.org/2010/12/port-scanning-with-html5-and-js-recon.html From 36e8229888b11519657ad5ea2871736374c7085e Mon Sep 17 00:00:00 2001 From: ultimatecoder Date: Wed, 24 Apr 2019 11:37:23 +0530 Subject: [PATCH 3/8] Adding twb as a proofreaders of the blog post --- _posts/2019-04-23-js-recon-is-no-more.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/_posts/2019-04-23-js-recon-is-no-more.md b/_posts/2019-04-23-js-recon-is-no-more.md index 0c6db8a..534cdd5 100644 --- a/_posts/2019-04-23-js-recon-is-no-more.md +++ b/_posts/2019-04-23-js-recon-is-no-more.md @@ -135,6 +135,8 @@ Please find the source code of Chatur [on Github][chatur_github]. Chatur is a free software. Try this tool and share your thoughts with me. This is not a bulletproofed idea, but it works most of the time you will try. +###### Proofreaders: [twb](https://www.emacswiki.org/emacs/TrentBuck#twb) + [andlabs_blogpost]: http://blog.andlabs.org/2010/12/port-scanning-with-html5-and-js-recon.html [mdn_xhr]: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest [chatur_pronounciation]: https://youtu.be/Tih_dP_Tv2w From 8bf0f8a33bd643894892c4d93dea22e709def2cb Mon Sep 17 00:00:00 2001 From: ultimatecoder Date: Wed, 24 Apr 2019 11:44:31 +0530 Subject: [PATCH 4/8] Updating information of twb --- _posts/2019-04-23-js-recon-is-no-more.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2019-04-23-js-recon-is-no-more.md b/_posts/2019-04-23-js-recon-is-no-more.md index 534cdd5..3b3ba52 100644 --- a/_posts/2019-04-23-js-recon-is-no-more.md +++ b/_posts/2019-04-23-js-recon-is-no-more.md @@ -135,7 +135,7 @@ Please find the source code of Chatur [on Github][chatur_github]. Chatur is a free software. Try this tool and share your thoughts with me. This is not a bulletproofed idea, but it works most of the time you will try. -###### Proofreaders: [twb](https://www.emacswiki.org/emacs/TrentBuck#twb) +###### Proofreaders: Trent W. Buck [andlabs_blogpost]: http://blog.andlabs.org/2010/12/port-scanning-with-html5-and-js-recon.html [mdn_xhr]: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest From 460b95222995ae783ca9521ec6baafd8d789db92 Mon Sep 17 00:00:00 2001 From: ultimatecoder Date: Wed, 24 Apr 2019 12:55:51 +0530 Subject: [PATCH 5/8] Improving the blogpost according to the suggestions by quakerquickoats. Adding him as a proofreader of this blog post. --- _posts/2019-04-23-js-recon-is-no-more.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/_posts/2019-04-23-js-recon-is-no-more.md b/_posts/2019-04-23-js-recon-is-no-more.md index 3b3ba52..1fb8079 100644 --- a/_posts/2019-04-23-js-recon-is-no-more.md +++ b/_posts/2019-04-23-js-recon-is-no-more.md @@ -11,20 +11,20 @@ tag: --- In 2010, Andlabs discovered an attack to fingerprint open TCP ports at client -workstation. You can read [this blog post][andlabs_blogpost] which is describing -details of this method. JS-Recon was a tool implementing this attack on its +workstations. You can read [this blog post][andlabs_blogpost] which describes +the details of this method. JS-Recon was a tool implementing this attack on its client to prove the danger of this vulnerability. Unfortunately, JS-Recon is not -available on mentioned link for unknown reasons. I tried my best to find the -source code of that tool, but I was ended with no results. Because the source -code of the tool is not available, the only way to confirm the possibility of -this attack was to reconstruct it from steps mentioned at that blog post. +available on the mentioned link for unknown reasons. I tried my best to find the +source code of that tool, but I found no results. Because the source code of the +tool is not available, the only way to confirm the possibility of this attack +was to reconstruct it from the steps mentioned at that blog post. In this post I will share my experience of rebuilding this attack. Because this -attack is from the front-end side, knowledge of basic Javascript API is -expected from the reader. The original blog post does not include any code -samples. For the easiness of the reader, I have prepared small code snippets -and attached them with related sections. I expect you run code samples at the -developer console of your browser. +attack is from the front-end side, knowledge of basic Javascript API is expected +from the reader. The original blog post does not include any code samples. For +the benefit of the reader, I have prepared small code snippets and attached them +with related sections. I expect you run code samples at the developer console of +your browser. ### Glossary @@ -135,7 +135,7 @@ Please find the source code of Chatur [on Github][chatur_github]. Chatur is a free software. Try this tool and share your thoughts with me. This is not a bulletproofed idea, but it works most of the time you will try. -###### Proofreaders: Trent W. Buck +###### Proofreaders: Trent W. Buck, [quakerquickoats via #emacs at Freenode](mailto:quakerquickoats@gmail.com) [andlabs_blogpost]: http://blog.andlabs.org/2010/12/port-scanning-with-html5-and-js-recon.html [mdn_xhr]: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest From 97b49dd94f475e8155cc632f4f52c4228d5f6a7b Mon Sep 17 00:00:00 2001 From: ultimatecoder Date: Wed, 24 Apr 2019 13:40:20 +0530 Subject: [PATCH 6/8] Improving the code by suggestions from quakerquickoats --- _posts/2019-04-23-js-recon-is-no-more.md | 108 ++++++++++++----------- 1 file changed, 56 insertions(+), 52 deletions(-) diff --git a/_posts/2019-04-23-js-recon-is-no-more.md b/_posts/2019-04-23-js-recon-is-no-more.md index 1fb8079..8ee4a22 100644 --- a/_posts/2019-04-23-js-recon-is-no-more.md +++ b/_posts/2019-04-23-js-recon-is-no-more.md @@ -10,20 +10,21 @@ tag: - jsrecon --- -In 2010, Andlabs discovered an attack to fingerprint open TCP ports at client -workstations. You can read [this blog post][andlabs_blogpost] which describes -the details of this method. JS-Recon was a tool implementing this attack on its -client to prove the danger of this vulnerability. Unfortunately, JS-Recon is not -available on the mentioned link for unknown reasons. I tried my best to find the -source code of that tool, but I found no results. Because the source code of the -tool is not available, the only way to confirm the possibility of this attack -was to reconstruct it from the steps mentioned at that blog post. +In 2010, Andlabs discovered an attack which fingerprints open TCP ports in +client workstations. You can read [this blog post][andlabs_blogpost] which +describes the details of this method. JS-Recon was a tool implementing this +attack on its clients to prove the danger of this vulnerability. Unfortunately, +JS-Recon is no longer available on the aforementioned link for unknown reasons. +I tried my best to find the source code of this tool, but I finished with no +results. Because the source code of the tool is not available, the only way to +confirm the possibility of this attack was to reconstruct it from the steps +mentioned in that blog post. In this post I will share my experience of rebuilding this attack. Because this attack is from the front-end side, knowledge of basic Javascript API is expected from the reader. The original blog post does not include any code samples. For the benefit of the reader, I have prepared small code snippets and attached them -with related sections. I expect you run code samples at the developer console of +with related sections. I expect you run code samples in the developer console of your browser. ### Glossary @@ -33,16 +34,16 @@ your browser. * **XHR**: A short form of [XML Http Request][mdn_xhr]. * **Socket**: A TCP/IP raw socket. -According to that blog post, If I write a Javascript code to open a XHR to +According to that blog post, If I write a Javascript code to open an XHR to `http://localhost:8084` and host that code at example.com then when you visit -the example.com the browser will open that XHR to port `8084` of your -workstation, because the localhost for your browser is your workstation. This +the `example.com` the browser will open that XHR to port `8084` of your +workstation, because the `localhost` for your browser is your workstation. This gap invites many vulnerabilities for users. One of them is the possibility to -fingerprint open TCP ports at client workstation. +fingerprint open TCP ports at the client workstation. -The author claims that the browser takes recognizably more time to open a XHR -targeting an occupied port. Comparatively, time took to open a XHR aimed at an -empty port was short. +That post further claims that the browser takes recognizably more time to open +an XHR targeting an occupied port. Comparatively, time took to open an XHR aimed +at an empty port was short. ```javascript //Sample code to measure the time browser took to open the socket. @@ -62,38 +63,39 @@ var requestPort = function(port) { }; ``` -You can paste this code at a developer console of your browser. Calling this -function by writing `requestPort(8084)` at a console will open the XHR for port -`8084`. The function will print the time browser took to open a socket on that -port. I request you to call this function with a combination of empty and -non-empty ports to find response timings. +You can paste this code at the developer console of your browser. Calling this +function by writing `requestPort(8084)` at the console will open an XHR for port +`8084`. The function will print how long the browser took to open a socket on +that port. I invite you to call this function with a combination of empty and +non-empty ports to observe various response timings. I tried opening a bunch of requests using `requestPort()` function at suspected -ports. For me the method was giving unidentifiable pattern in the time browser -took to open a socket. Below is a histogram of comparing time took to open a -socket on empty port(8084) and non-empty port(27017). +ports. For me the method was giving unidentifiable patterns in the time the +browser took to open a socket. Below is a histogram of comparing times taken to +open a socket on empty port(8084) and non-empty port(27017). ![Graph showing response time to open socket.]({{site.url}}/assets/images/js_recon_is_no_more/graph_response_time_open_socket.png) -Above is a graph of 6000 requests done to measure the response time using a -function I shared earlier. More than 5000 requests has ended in nearly no time. -There were less than 1000 requests which ended in 1 microseconds. From the -above results, We can conclude that mentioned method is not giving different -results for occupied and empty port. We can conclude that mentioned method by -AndLabs is failing to distinguish an occupied port from a non occupied port. - -I tried hard to find any possible cause for the failure of this attack. I didn't -found any conclusive evidences. May be our hardware or browser code has improved -for opening a TCP sockets quicker than what it used to. I will not lie, but that -abstract blog post by the AndLabs took sometime to understand the anatomy of -this attack. I wasn't happy with going back from this point. Just for my -satisfaction, I tried every possible combinations of `xhr.readyState` values to -find any pattern. From my observation, I recognized that timing for returning a -header from an occupied port was delayed. Comparatively, this response was quick -for ports where no service was running. I am comparing the time browser took to -return a response headers whereas in the previous method it was dependent on the -time browser took for opening a socket. +Above is a graph of 6000 requests done to measure the response times using the +function I shared earlier. More than 5000 requests have ended in nearly no time. +There were less than 1000 requests which ended in 1 microseconds. From the above +results, We can conclude that mentioned method is not giving different results +for occupied and empty port. We can conclude that mentioned method by AndLabs is +failing to distinguish occupied ports from nonoccupied ports. + +I tried hard to find possible causes for the failure of this attack. I didn't +find any conclusive evidence. Perhaps our hardware or browser code has improved +for opening a TCP sockets quicker than what it used to. I will be honest, but it +took sometime to understand the anatomy of this attack from that abstract blog +post by Andlabs. However I was not about to give up and turn back from this +point. Just for my satisfaction, I tried every possible combinations of +`xhr.readyState` values to find any pattern. From my observation, I recognized +that timings for returning a header from an occupied port was delayed. +Comparatively, this response was quick for ports where no service was running. I +am comparing the time in which the browser returned a response headers whereas +in the previous method it was dependent on the time browser took for opening a +socket. ```javascript var requestPort = function(port) { @@ -112,28 +114,29 @@ var requestPort = function(port) { }; ``` -Above code will measure the time browser took to receive headers from the -destination. You should call this function requestPort() with a few +The above code will measure times the browser has taken to receive headers from +the destination. You should call the function requestPort() with several combinations of empty and non-empty ports. ![Graph showing header response time.]({{site.url}}/assets/images/js_recon_is_no_more/graph_header_response_time.png) -This graph is representing header response time of 6000 requests fired at both -active (27017) and inactive port (8084). The response time of inactive port not -go beyond 200 microseconds. Comparing this with a header response time of +This graph is representing header response times of 6000 requests fired at both +active (27017) and inactive port (8084). The response times of inactive ports do +not go beyond 200 microseconds. Comparing this with a header response time of occupied ports, we can see that response time of non-empty port is recognizably higher than empty port. -Browser is the most common tool used by us. Asserting this vulnerability +The web browser is the most common tool we use. Asserting this vulnerability requires knowledge of Javascript and everyone is not a developer. As I mentioned earlier, I failed to find the source code of JS-Recon (the tool written by AndLabs proving possibility of this attack). For those reasons, I decided to write a tool pioneered on my improvements on an attempt of Andlabs. Today, I have successfully completed that tool. I have decided to name it -["Chatur"][chatur_pronounciation]. Chatur means intelligent person in Hindi. -Please find the source code of Chatur [on Github][chatur_github]. Chatur is a -free software. Try this tool and share your thoughts with me. This is not a -bulletproofed idea, but it works most of the time you will try. +["Chatur"][chatur_pronounciation]. Chatur means intelligent person in +[Hindi][hindi]. Please find the source code of Chatur [on +Github][chatur_github]. Chatur is a free software. Please try out this tool and +share your thoughts on my tool with me. This is not a bulletproofed idea, but it +works most of the time you will try. ###### Proofreaders: Trent W. Buck, [quakerquickoats via #emacs at Freenode](mailto:quakerquickoats@gmail.com) @@ -141,3 +144,4 @@ bulletproofed idea, but it works most of the time you will try. [mdn_xhr]: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest [chatur_pronounciation]: https://youtu.be/Tih_dP_Tv2w [chatur_github]: https://github.com/ultimatecoder/chatur +[hindi]: https://en.wikipedia.org/wiki/Hindi From 42223d5809f46af9dba5b201fa94c737e88f4b16 Mon Sep 17 00:00:00 2001 From: ultimatecoder Date: Wed, 24 Apr 2019 16:38:25 +0530 Subject: [PATCH 7/8] Improving the post according to suggestions by wasamasa --- _posts/2019-04-23-js-recon-is-no-more.md | 36 +++++++++++------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/_posts/2019-04-23-js-recon-is-no-more.md b/_posts/2019-04-23-js-recon-is-no-more.md index 8ee4a22..22e5913 100644 --- a/_posts/2019-04-23-js-recon-is-no-more.md +++ b/_posts/2019-04-23-js-recon-is-no-more.md @@ -16,16 +16,15 @@ describes the details of this method. JS-Recon was a tool implementing this attack on its clients to prove the danger of this vulnerability. Unfortunately, JS-Recon is no longer available on the aforementioned link for unknown reasons. I tried my best to find the source code of this tool, but I finished with no -results. Because the source code of the tool is not available, the only way to -confirm the possibility of this attack was to reconstruct it from the steps -mentioned in that blog post. +results. For this reason, the only way to confirm the possibility of this +attack was to reconstruct it from the steps mentioned in that blog post. -In this post I will share my experience of rebuilding this attack. Because this -attack is from the front-end side, knowledge of basic Javascript API is expected -from the reader. The original blog post does not include any code samples. For -the benefit of the reader, I have prepared small code snippets and attached them -with related sections. I expect you run code samples in the developer console of -your browser. +In this post I will share my experience of rebuilding this attack. As this +attack is from the front-end side, knowledge of basic Javascript and [XML Http +Request API][mdn_xmr] are expected from the reader. The original blog post did +not include any code samples. For the benefit of the reader, I have prepared +small code snippets and attached them with related sections. I expect you run +code samples in the developer console of your browser. ### Glossary @@ -115,7 +114,7 @@ var requestPort = function(port) { ``` The above code will measure times the browser has taken to receive headers from -the destination. You should call the function requestPort() with several +the destination. You should try calling the `requestPort` function with several combinations of empty and non-empty ports. ![Graph showing header response time.]({{site.url}}/assets/images/js_recon_is_no_more/graph_header_response_time.png) @@ -129,19 +128,16 @@ higher than empty port. The web browser is the most common tool we use. Asserting this vulnerability requires knowledge of Javascript and everyone is not a developer. As I mentioned earlier, I failed to find the source code of JS-Recon (the tool written by -AndLabs proving possibility of this attack). For those reasons, I decided to -write a tool pioneered on my improvements on an attempt of Andlabs. Today, I -have successfully completed that tool. I have decided to name it -["Chatur"][chatur_pronounciation]. Chatur means intelligent person in -[Hindi][hindi]. Please find the source code of Chatur [on -Github][chatur_github]. Chatur is a free software. Please try out this tool and -share your thoughts on my tool with me. This is not a bulletproofed idea, but it -works most of the time you will try. +AndLabs proving possibility of this attack). For these reasons I have decided to +write a tool based on my improvements on an attempt of Andlabs. Today, I have +successfully completed that tool. I have decided to name it +["Chatur"][chatur_pronounciation]. You can find its source code [on +Github][chatur_github]. Chatur is a free software. Please try it out and share +your thoughts on it with me. -###### Proofreaders: Trent W. Buck, [quakerquickoats via #emacs at Freenode](mailto:quakerquickoats@gmail.com) +###### Proofreaders: Trent W. Buck, [quakerquickoats via #emacs at Freenode](mailto:quakerquickoats@gmail.com), [Vasilij Schneidermann](https://github.com/wasamasa) [andlabs_blogpost]: http://blog.andlabs.org/2010/12/port-scanning-with-html5-and-js-recon.html [mdn_xhr]: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest [chatur_pronounciation]: https://youtu.be/Tih_dP_Tv2w [chatur_github]: https://github.com/ultimatecoder/chatur -[hindi]: https://en.wikipedia.org/wiki/Hindi From f214e5db9424e1bf5dca59217fc2f7abfcd757a2 Mon Sep 17 00:00:00 2001 From: ultimatecoder Date: Wed, 24 Apr 2019 16:58:06 +0530 Subject: [PATCH 8/8] Improving blog post according to corrections done by Wasamasa --- _posts/2019-04-23-js-recon-is-no-more.md | 36 +++++++++++------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/_posts/2019-04-23-js-recon-is-no-more.md b/_posts/2019-04-23-js-recon-is-no-more.md index 22e5913..9a9f26c 100644 --- a/_posts/2019-04-23-js-recon-is-no-more.md +++ b/_posts/2019-04-23-js-recon-is-no-more.md @@ -31,13 +31,13 @@ code samples in the developer console of your browser. * **Empty / Available port**: A port where no service is running. * **Non-empty / Occupied port**: A port where some service is running. * **XHR**: A short form of [XML Http Request][mdn_xhr]. -* **Socket**: A TCP/IP raw socket. +* **Socket**: A raw TCP/IP socket. According to that blog post, If I write a Javascript code to open an XHR to -`http://localhost:8084` and host that code at example.com then when you visit +`http://localhost:8084` and host that code at `example.com` then when you visit the `example.com` the browser will open that XHR to port `8084` of your workstation, because the `localhost` for your browser is your workstation. This -gap invites many vulnerabilities for users. One of them is the possibility to +gap lead to many vulnerabilities for users. One of them is the possibility to fingerprint open TCP ports at the client workstation. That post further claims that the browser takes recognizably more time to open @@ -62,11 +62,11 @@ var requestPort = function(port) { }; ``` -You can paste this code at the developer console of your browser. Calling this +You can paste this code into the developer console of your browser. Calling this function by writing `requestPort(8084)` at the console will open an XHR for port `8084`. The function will print how long the browser took to open a socket on -that port. I invite you to call this function with a combination of empty and -non-empty ports to observe various response timings. +that port. I recommended you to call this function with a combination of empty +and non-empty ports to observe the difference in response timings. I tried opening a bunch of requests using `requestPort()` function at suspected ports. For me the method was giving unidentifiable patterns in the time the @@ -79,22 +79,20 @@ open a socket on empty port(8084) and non-empty port(27017). Above is a graph of 6000 requests done to measure the response times using the function I shared earlier. More than 5000 requests have ended in nearly no time. There were less than 1000 requests which ended in 1 microseconds. From the above -results, We can conclude that mentioned method is not giving different results +results, we can conclude that mentioned method is not giving different results for occupied and empty port. We can conclude that mentioned method by AndLabs is failing to distinguish occupied ports from nonoccupied ports. I tried hard to find possible causes for the failure of this attack. I didn't -find any conclusive evidence. Perhaps our hardware or browser code has improved -for opening a TCP sockets quicker than what it used to. I will be honest, but it -took sometime to understand the anatomy of this attack from that abstract blog -post by Andlabs. However I was not about to give up and turn back from this -point. Just for my satisfaction, I tried every possible combinations of -`xhr.readyState` values to find any pattern. From my observation, I recognized -that timings for returning a header from an occupied port was delayed. -Comparatively, this response was quick for ports where no service was running. I -am comparing the time in which the browser returned a response headers whereas -in the previous method it was dependent on the time browser took for opening a -socket. +find any conclusive evidence. I will be honest, but it took sometime to +understand the anatomy of this attack from that abstract blog post by Andlabs. +However I was not about to give up and turn back from this point. To satisfy my +curiosity, I tried every possible combinations of `xhr.readyState` values to +find any pattern. From my observation, I recognized the timings for returning a +header from an occupied port were delayed. Comparatively, this response was +quick for ports where no service was running. I am comparing the time in which +the browser returned a response headers whereas in the previous method it was +dependent on the time browser took for opening a socket. ```javascript var requestPort = function(port) { @@ -113,7 +111,7 @@ var requestPort = function(port) { }; ``` -The above code will measure times the browser has taken to receive headers from +The above code will measure the time browser has taken to receive headers from the destination. You should try calling the `requestPort` function with several combinations of empty and non-empty ports.