79624262

Date: 2025-05-15 22:46:30
Score: 0.5
Natty:
Report link

Uhm, actually... ☝️🤓

It is possible to emulate telnet from browser to a port. Working example is in the end of the comment. And I tried it against postgres 5432 port - that should not accept any protocots but psql ones.

I found an article [1] with a direction. Long story short: the 'ERRCONREFUSED' and other meaningfull messages are impossible to catch in js. Browser has it, but js does not. We have to do something but catching.

The only thing we can do - measuring time. In the [1] article author measures image loading time with server url href. His results are not consistent, because image loading engine does not provide enough time difference between open and close ports.

Then I found article [2], that improves this idea: author suggests to use browser caching mechanism. He says, that if the port is closed, and you load iframe with http://host:port - it will not create proper browser cache item, so the next call http://host:port# will be fired again, causing onload event. Hash in the end kinda fools caching mechanism. It's 3 hours of the night, and I have nothing better to do at my 30's but rolling over browser tho. So, anyway. But if the port is open, the http://host:port# will be read from cache like http://host:port and will not cause onload event. So, one event versus two - uwu enough? No.

His idea did not work for me. Maybe something had been fixyd-wixyd in the browser, maybe I wrote a wrong code, but. He uses iframe with server url to check the port. And this loading time works with enough resilience.

If the port is closed, iframe drops immediately. If the port is open, iframe tryes for couple seconds. Cool. But you do not schedule 100500 tasks that telnets to 500100 ports. Do it one by one only, with significant breaks inbetween - otherwise the tab lags like hell and destroys all the magic.

The code below is just an PoC, but I'm fine with it as is. Of course, there are couple details: you may calibrate it by measuring responses from predefined open ports, you may move it to a service worker, but it does not matter.

So. Until iframe gets fixed, it is possible to telnet from browser to host:port.

GNU/GPLv3

[1] https://incolumitas.com/2021/01/10/browser-based-port-scanning/

[2] https://portswigger.net/research/exposing-intranets-with-reliable-browser-based-port-scanning

type PortResponse = Readonly<{
  port: number;
  timeMs: number;
}>;

const measurePortResponse = (host: string, port: number): Promise<PortResponse> => {
  return new Promise((res, rej) => {
    const start = performance.now();
    const iframe = document.createElement('iframe');
    iframe.name = 'probe' + Date.now().toString();
    iframe.src = `http://${host}:${port.toString()}`;
    iframe.onload = () => {
      const end = performance.now();
      iframe.remove();
      res({ port, timeMs: end-start, });
    };
    iframe.onerror = (e) => {
      rej(e as unknown as Error);
    };
    document.body.appendChild(iframe);
  });
};

export const isPortOpen = async (host: string, port: number): Promise<boolean> => {
  const response = await measurePortResponse(host, port);
  const isPortOpen = response.timeMs <= 1000;

  if (!isPortOpen) console.log('hehe', response);

  return isPortOpen;
};
Reasons:
  • Blacklisted phrase (1): did not work
  • Long answer (-1):
  • Has code block (-0.5):
  • Contains question mark (0.5):
  • Low reputation (0.5):
Posted by: homk