Using client-side JavaScript to build a tool for Portscanning and Host Detection.
While on a holiday in Vienna, me and my buddies noticed a peculiar device on one of the walls of the hotel.
This mystical device turned out to be an iPad, in single-app mode.
The iPad was used to control the lights of the room. Of course that got us thinking,
could we use it in unintended ways?
Devices like these are often called 'single-app kiosk'. Kiosk is described as
'small open-fronted from which items are sold'.
These kiosk- tablets are often restricted to just doing what they're set up as, be it light control, self-checkout, a map of a mall, and so on.
They're made in a restrictive way, with no way to escape, to prevent misuse of the machine.
But if you are a clever individual, you can find a way to open a browser. For example the light-control app allowed us to log in to Spotify with Google. This opens either a browser, or a pseudo browser. And Google of course gives you an option to read their Privacy & Terms. From that page, you can find a link directly to Google search.. and the world is yours to explore!
Whilst we're already progressing away from the restrictions of the kiosk, we're still stuck in the browser. One direction to go to from here would be to move laterally, inside the network, to other machines. For example many routers come with a webpanel, but how do we access it?
This is where my kiosk tooling comes into play. With HTML, and JavaScript it's trivial to make a tool that allows us to redirect our browser to any wanted address. If we know a router is on address 192.168.1.1, and the webpanel is on port 80, we can simply redirect ourselves into http://192.168.1.1:80/
There's a slight problem though. How do we know which hosts exist in the network, what are their addresses, and what ports are open?
Much of my knowledge regarding the following chapter came from this blog. I highly recommend reading it, in it the author Nikolai Tschacher goes deep into the statistics and different methods of scanning open ports.
The extremely basic rundown of the method goes as follows:
We request a resource with JavaScript, for example using Image.src,
and we clock how much time the operation takes. The port 80 will respond to this request likely with an HTTP response 404.
This is fast. But the port 81, when closed, will only produce us an error.This is slow.
It is so much slower infact, that it's easy to tell which ports are open, and which ones are not. If the clocked time is below 100's of milliseconds,
it is likely that the port is open. Or if the timing is above 1000's, we can assume a port is closed.
To be sure, we can use the ratio of known closed ports to the ports we want to test.
I was going to use Image.src and it's .onerror function to map out these timings, but this is asynchronous.
When fired through a for-loop, the timings would increase lineary throughout the ports. All of the timers start simultaniosly, while the errors come one after another.
This means the results were all WHACK. This is illustrated in the image above.
I tried recursion to fix this issue of rising latency, but surprisingly,
It didn't work. Well, somewhat, but not enough.
So instead, we use fetch(), and wait for each function call to finish.
It turned out to be much simpler.
Yeah yeah, ports this and that, but what use is it if we don't know the addresses the of devices?
I gotchu bro, I gotchu.
While writing the Port Scanner, I noticed something interesting. As we need to have one closed port to test the timings against, I started to think, how can we make sure a port is in fact closed? Surely, we can just give an arbitary address to a host we know doesn't exist in the Network, this way it can't hit an open port.
From the image above you can see, that the time it takes for it to error out shot through the roof. The ratio between a host that exists, with a port that is closed, to a host that doesn't exist at all is 10x!
With a closed port the machine drops the request, be it right protocol or not. 'This port is closed, you're not allowed to send anything there.'
This is fast.
But if there is no Computer, no Server, no Router behind the address to receive the connection, it will time out. This is slow.
With this technique, it is possible to do Host Detection in a LAN setting. We can give an IP range, like 192.168.1.0/24, and go through all of the addresses with an arbitary port number. Then we compare the timing again to a known address, for an assumed closed port (localhost:60666). If the ratio is, say, above 8x we determine the address / host to be offline.
I've written simple tooling utilizing these techniques. They can be found from
kiosk.vsim.xyz/
In there we've collected a set of tools to aid in Kiosk-mode pentests. The toolset is expanding, and if you wish to see something in it,
don't hesitate to either hit me up or make a pull request to the repo!
Whilst writing the tooling, a thought came to my mind.
Could we not use these techniques to map out LAN-networks across the globe?
In theory if someone were to make a website, that had these tools built in and trigger at refresh,
they could collect statistical data on the site users network. What hosts are there,
and what ports do they have open? I think in the future this is something that would be cool to demo out.
What do you think? Would this be cool to see?
Thanks for reading, and I hope you learned something!
-Vs1m.