This page looks best with JavaScript enabled

FreeBSD VNC server

 ·  🎃 kr0m

The best way to provide support to a remote user is through VNC. We could opt for solutions like TeamViewer, but we would be completely trusting that the TeamViewer team is not stealing our data or recording sessions. You know that paranoia is never too much.

This manual is divided into several parts:


VNC Client

Install the VNC server:

pkg install x11vnc

From the session of the user who will receive remote support, generate an access password:

x11vnc -storepasswd

Every time the user needs support, they must execute the following command. This way, the VNC server will start so that they can access it remotely:

x11vnc -usepw -display :0 --loop

NOTE: The loop option will cause the VNC server to restart in case of disconnection by the client. If we do not put this option and the client disconnects, the computer will be inaccessible until the user runs the command again.

On the other hand, the technician will have to access through a VNC client:

pkg install tigervnc-viewer

The connection will be made by indicating the following parameters:

vncviewer IP:5900

VNC Jail

If it is a headless server that we want to access via VNC, we must first start a fake Xorg server that will be displayed by VNC and where we will start our WM.

Install everything you need:

pkg install xorg xorg-vfbserver xfce x11vnc

We start dbus:

sysrc dbus_enable="YES"
service dbus start

We add the user to the video group:

pw groupmod video -m kr0m

We generate an access password from the user:

su kr0m -l
x11vnc -storepasswd

From the user kr0m, we start the fake graphical server:

Xvfb :0

We tell the VNC server to display via network the display :0

x11vnc -usepw -display :0 -noshm --loop

We start the WM on display :0

export DISPLAY=:0 && exec startxfce4

We can now access the VNC server:

vncviewer 192.168.69.56:5900


In both cases, whether connecting to the client or to the jail with xvfb, we will be prompted for a password and once authenticated we will access the system:



VNC SSL

The VNC server supports SSL natively, but in many cases, it causes compatibility problems due to incompatible encryption algorithms between the client and the server. To avoid these types of problems, we will use noVNC . This way, we will only worry about the connection from the browser to the noVNC server being encrypted with an SSL certificate and the noVNC server being in clear text until the final server. In addition, access will be more universal since it will be done through an HTML5 browser without the need for a VNC client.

As of 05/28/2022, if we enable SSL, we get this problem:

28/05/2022 21:03:15 SSL: error:1417A0C1:SSL routines:tls_post_process_client_hello:no shared cipher

Due to this bug .

The steps are the same as in the previous scenario, but we will also start the noVNC server.

We start the graphical server:

/usr/local/bin/Xvfb :0

We start the VNC server:

/usr/local/bin/x11vnc -usepw -rfbport 5901 -display :0 -noshm -forever -shared

Starting the WM:

export DISPLAY=:0 && exec /usr/local/bin/startxfce4

Install git and noVNC:

pkg install novnc git

The noVNC server requires numpy:

pip install numpy

Assign the necessary permissions:

chmod 744 /usr/local/libexec/novnc/utils/novnc_proxy

Check the allowed parameters by the server:

cd /usr/local/libexec/novnc/
./utils/novnc_proxy -h

Usage: novnc_proxy [--listen PORT] [--vnc VNC_HOST:PORT] [--cert CERT] [--ssl-only]

Starts the WebSockets proxy and a mini-webserver and 
provides a cut-and-paste URL to go to.

    --listen PORT         Port for proxy/webserver to listen on
                          Default: 6080
    --vnc VNC_HOST:PORT   VNC server host:port proxy target
                          Default: localhost:5900
    --cert CERT           Path to combined cert/key file, or just
                          the cert file if used with --key
                          Default: self.pem
    --key KEY             Path to key file, when not combined with cert
    --web WEB             Path to web files (e.g. vnc.html)
                          Default: ./
    --ssl-only            Disable non-https connections.
                                    
    --record FILE         Record traffic to FILE.session.js
                                    
    --syslog SERVER       Can be local socket such as /dev/log, or a UDP host:port pair.
                                    
    --heartbeat SEC       send a ping to the client every SEC seconds
    --timeout SEC         after SEC seconds exit when not connected
    --idle-timeout SEC    server exits after SEC seconds if there are no
                          active connections

First, let’s try accessing without SSL. In the following command, we are linking port 5900 with the VNC server started in jail 192.168.69.56:5901:

./utils/novnc_proxy --vnc 192.168.69.56:5901 --listen 5900

It will give us a URL like this:

http://test.alfaexploit.com:5900/vnc.html?host=test.alfaexploit.com&port=5900

If we access this, we will see an authentication window that corresponds to the password assigned to the VNC server:



Next step is to configure the SSL certificate since there is a login and the password could be intercepted.

We issue the certificate request using acme.sh :

pkg install socat
curl https://get.acme.sh | sh -s email=kr0m@alfaexploit.com
acme.sh --issue --standalone -d test.alfaexploit.com

[Sat May 28 18:56:17 CEST 2022] Your cert is in: /root/.acme.sh/test.alfaexploit.com/test.alfaexploit.com.cer
[Sat May 28 18:56:17 CEST 2022] Your cert key is in: /root/.acme.sh/test.alfaexploit.com/test.alfaexploit.com.key
[Sat May 28 18:56:17 CEST 2022] The intermediate CA cert is in: /root/.acme.sh/test.alfaexploit.com/ca.cer
[Sat May 28 18:56:17 CEST 2022] And the full chain certs is there: /root/.acme.sh/test.alfaexploit.com/fullchain.cer

Start the noVNC server with SSL parameters:

cd /usr/local/libexec/novnc/
./utils/novnc_proxy --vnc 192.168.69.56:5901 --cert /root/.acme.sh/test.alfaexploit.com/fullchain.cer --key /root/.acme.sh/test.alfaexploit.com/test.alfaexploit.com.key --listen 5900 --ssl-only

It will give us a URL like this:

https://test.alfaexploit.com:5900/vnc.html?host=test.alfaexploit.com&port=5900

The content of the web will be the same but this time the traffic will be encrypted:


VNC SSL Daemon

To make all of this start automatically, we will create an RC script:

vi /usr/local/etc/rc.d/vnc

#! /bin/sh
#
# $FreeBSD$
#

# PROVIDE: vnc
# REQUIRE: DAEMON
# KEYWORD: shutdown 

. /etc/rc.subr

name="vnc"
extra_commands="status"
username="kr0m"

start_cmd="${name}_start"
stop_cmd="${name}_stop"
status_cmd="${name}_status"

vnc_start(){
    PID=$(ps -U ${username}|grep Xvfb|grep -v grep|awk '{print$1}')
    if [ -z $PID ]; then
        echo "Starting service: Xvfb"
        /bin/rm /tmp/.X*-lock 2>/dev/null
        /usr/bin/su -l ${username} -c '/usr/bin/nohup /usr/local/bin/Xvfb :0 > /dev/null 2>&1 &' 1>/dev/null
    else
        echo "Service: Xvfb already started"
    fi

    PID=$(ps -U ${username}|grep x11vnc|grep -v grep|awk '{print$1}')
    if [ -z $PID ]; then
        echo "Starting service: X11vnc"
        /usr/bin/su -l ${username} -c '/usr/bin/nohup /usr/local/bin/x11vnc -usepw -rfbport 5901 -display :0 -noshm -forever -shared > /dev/null 2>&1 &' 1>/dev/null
    else
        echo "Service: x11vnc already started"
    fi

    PID=$(ps -U ${username}|grep xfce4-session|grep -v grep|awk '{print$1}'|sort|head -n 1)
    if [ -z $PID ]; then
        echo "Starting service: XFCE"
        /usr/bin/su -l ${username} -c 'export DISPLAY=:0 && /usr/bin/nohup /usr/local/bin/startxfce4 > /dev/null 2>&1 &' 1>/dev/null
    else
        echo "Service: x11vnc already started"
    fi

    # WEBSOCKIFY launches more than one thread in that way we have to check the number of running threads
    WEBSOCKIFY_N=$(ps -U root|grep websockify|grep -v grep|wc -l|awk '{print$1}')
    if [ $WEBSOCKIFY_N -eq 0 ]; then
        echo "Starting service: Websockify"
        PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin
        /usr/bin/nohup /usr/local/bin/bash /usr/local/libexec/novnc/utils/novnc_proxy --vnc 192.168.69.56:5901 --cert /root/.acme.sh/test.alfaexploit.com/fullchain.cer --key /root/.acme.sh/test.alfaexploit.com/test.alfaexploit.com.key --listen 5900 --ssl-only > /dev/null 2>&1 & 1>/dev/null
    else
        echo "Service: Websockify already started"
    fi
    
    /bin/rm /home/${username}/nohup.out 2>/dev/null
    /bin/rm /root/nohup.out 2>/dev/null
}

vnc_stop(){
    PID=$(ps -U ${username}|grep Xvfb|grep -v grep|awk '{print$1}')
    if [ -z $PID ]; then
        echo "It appears Xvfb is not running."
    else
        echo "Stopping service: Xvfb/X11vnc/XFCE"
        kill -s INT $PID
        sleep 3
    fi

    # WEBSOCKIFY launches more than one thread in that way we have to check the number of running threads
    WEBSOCKIFY_N=$(ps -U root|grep websockify|grep -v grep|wc -l|awk '{print$1}')
    if [ $WEBSOCKIFY_N -eq 0 ]; then
        echo "It appears Websockify is not running."
    else
        echo "Stopping service: Websockify"
        for PID in $(ps -U root|grep websockify|grep -v grep|awk '{print$1}'); do
                kill -s INT $PID
        done
        sleep 3
    fi
}

vnc_status(){
    PID=$(ps -U ${username}|grep Xvfb|grep -v grep|awk '{print$1}')
    if [ -z $PID ]; then
        echo "Xvfb is not running."
    else
        echo "Xvfb running with PID: $PID"
    fi

    PID=$(ps -U ${username}|grep x11vnc|grep -v grep|awk '{print$1}')
    if [ -z $PID ]; then
        echo "x11vnc is not running."
    else
        echo "X11vnc running with PID: $PID"
    fi

    PID=$(ps -U ${username}|grep xfce4-session|grep -v grep|awk '{print$1}'|sort|head -n 1)
    if [ -z $PID ]; then
        echo "XFCE is not running."
    else
        echo "XFCE running with PID: $PID"
    fi

    # WEBSOCKIFY launches more than one thread in that way we have to check the number of running threads
    WEBSOCKIFY_N=$(ps -U root|grep websockify|grep -v grep|wc -l|awk '{print$1}')
    if [ $WEBSOCKIFY_N -eq 0 ]; then
        echo "Websockify is not running."
    else
        echo "Websockify running with PIDS:"
        for PID in $(ps -U root|grep websockify|grep -v grep|awk '{print$1}'); do
                echo "PID: $PID"
        done
        sleep 3
    fi
}

load_rc_config ${name}
run_rc_command "$1"

Assign the necessary permissions:

chmod 555 /usr/local/etc/rc.d/vnc
chown root:wheel /usr/local/etc/rc.d/vnc

Enable and start the service:

sysrc vnc_enable=“YES”
service vnc start

With this script, all processes will start automatically on each reboot.

If you liked the article, you can treat me to a RedBull here