Apache Guacamole

Apache Guacamole … What is it about? It’s a client-less remote gateway for Telnet, SSH, RDP and VNC. Client-less, because there is no need to install any plugin or additional software for users (clients). The client will use just the browser (also without any plugin). In this tutorial we will create a very simple environment via Vagrant and use Guacamole. Why the tutorial? Because I know a lot of testers for example – who work with Windows, who are not allowed to install any software (eq Putty) but still need access to environments. … Next point are for example public security groups on cloud providers. Here only one port would be needed to support different protocols on different hosts (incl. file transfer).

What we need?

Project preparation

# create project
$ mkdir -p ~/Projects/Guacamole/src

# change directory
$ cd ~/Projects/Guacamole/

# create needed files in root folder
$ touch {Vagrantfile,ShellProvisioner.sh}

# create needed files in root folder
$ touch ./src/{guacamole.properties,server.xml,user-mapping.xml,Xwrapper.config}

# show project (optional)
$ tree ~/Projects/Guacamole/
|____src
| |____guacamole.properties
| |____server.xml
| |____user-mapping.xml
| |____Xwrapper.config
|____ShellProvisioner.sh
|____Vagrantfile

Okay, via your favorite editor you now add the content of all files. All files inside directory “src” are configuration files (installed on Guacamole host).

# Hostname and port of guacamole proxy
guacd-hostname:      localhost
guacd-port:          4822
available-languages: en, de

auth-provider: net.sourceforge.guacamole.net.basic.BasicFileAuthenticationProvider
basic-user-mapping: /etc/guacamole/user-mapping.xml
<?xml version="1.0" encoding="UTF-8"?>
<Server port="-1" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>
  <Service name="Catalina">
    <Connector port="55555" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t "%r" %s %b" />
      </Host>
    </Engine>
  </Service>
</Server>

This file (user-mapping.xml) is the configuration for all your connections.

<user-mapping>

  <authorize username="USERNAME" password="PASSWORD">
    <!--
    <connection name="Debian2: RDP Connection">
      <protocol>rdp</protocol>
      <param name="hostname">localhost</param>
      <param name="port">3389</param>
    </connection>
    -->

    <connection name="Debian2: VNC Connection">
      <protocol>vnc</protocol>
      <param name="hostname">localhost</param>
      <param name="port">5901</param>
      <param name="password">vagrant</param>
    </connection>

    <connection name="Debian2: SSH Connection">
      <protocol>ssh</protocol>
      <param name="hostname">localhost</param>
      <param name="port">22</param>
      <param name="username">vagrant</param>
    </connection>

    <connection name="Debian1: SSH Connection">
      <protocol>ssh</protocol>
      <param name="hostname">192.168.10.5</param>
      <param name="port">22</param>
      <param name="username">vagrant</param>
    </connection>

    <connection name="Debian2: Telnet Connection">
      <protocol>telnet</protocol>
      <param name="hostname">localhost</param>
      <param name="port">23</param>
      <param name="username">vagrant</param>
    </connection>
  </authorize>
</user-mapping>
allowed_users=anybody

The ShellProvisioner.sh includes all installation and configuration for Guacamole All examples are provided but for Debian RDP is currently not working and I commented out.

echo '>>>>Install some default packages<<<<<'
sudo apt update -y -q
sudo apt install -y -q build-essential htop libcairo2-dev libjpeg62-turbo-dev libjpeg-dev libpng-dev libossp-uuid-dev
# install optional guacamole packages eq FFmpeg, SSH
sudo apt install -y -q libavcodec-dev libavutil-dev libswscale-dev libpango1.0-dev libssh2-1-dev libssl-dev libvorbis-dev libwebp-dev

echo '>>>>Install and configure tomcat packages<<<<<'
sudo apt install -y -q tomcat9 tomcat9-admin tomcat9-common tomcat9-user
sudo mkdir -p /usr/share/tomcat9/.guacamole
sudo cp /tmp/guacamole/server.xml /etc/tomcat9/server.xml
sudo chown root:tomcat /etc/tomcat9/server.xml
sudo chmod 0640 /etc/tomcat9/server.xml

echo '>>>>Configure default guacamole directory structure<<<<<'
sudo cp -r /tmp/guacamole /etc/guacamole
sudo mkdir -p /etc/guacamole/{extensions,lib}
sudo chown -R root:root /etc/guacamole
sudo chmod 0640 /etc/guacamole/user-mapping.xml
sudo chown root:tomcat /etc/guacamole/user-mapping.xml
sudo ln -s /etc/guacamole/guacamole.properties /var/lib/tomcat9/.guacamole

echo '>>>>Install and configure telnet packages<<<<<'
sudo apt install -y -q telnetd libtelnet-dev

echo '>>>>Install and configure xrdp packages<<<<<'
# actualy broken becauce of freerdp2-dev on debian
# sudo apt install -y -q xrdp freerdp2-dev
# sudo cp /etc/guacamole/Xwrapper.config /etc/X11/Xwrapper.config
# sudo chown root:root /etc/X11/Xwrapper.config
# sudo chmod 0644 /etc/X11/Xwrapper.config
# sudo systemctl enable xrdp.service
# sudo systemctl enable xrdp-sesman.service
# sudo systemctl start xrdp
# sudo systemctl start xrdp-sesman

echo '>>>>Install and configure vnc packages'
sudo apt install -y -q xfce4 xfce4-goodies gnome-icon-theme tightvncserver libvncserver-dev libpulse-dev

echo '>>>>Install guacamole client and restart tomcat<<<<<'
curl -s -O -J -L "http://apache.org/dyn/closer.cgi?action=download&filename=guacamole/1.0.0/binary/guacamole-1.0.0.war"
sudo cp guacamole-1.0.0.war /var/lib/tomcat9/webapps/guacamole.war
sudo chown tomcat:tomcat /var/lib/tomcat9/webapps/guacamole.war
sudo systemctl restart tomcat9

echo '>>>>Install guacamole server<<<<<'
curl -s -O -J -L "http://apache.org/dyn/closer.cgi?action=download&filename=guacamole/1.0.0/source/guacamole-server-1.0.0.tar.gz"
tar xzf guacamole-server-1.0.0.tar.gz
cd guacamole-server-1.0.0/
# space after etc is wrong
sudo ./configure --with-init-dir=/etc /init.d
sudo make
sudo make install
sudo ldconfig
sudo update-rc.d guacd defaults

echo '>>>>Start guacamole server/daemon<<<<<'
sudo systemctl start guacd

echo '>>>>Show open ports<<<<<'
sudo lsof -i -P -n | grep LISTEN

echo '>>>>Start clean-up<<<<<'
sudo rm /etc/guacamole/Xwrapper.config
sudo rm /etc/guacamole/server.xml
sudo rm -fr /tmp/guacamole
sudo rm -fr /home/vagrant/guacamole-server-1.0.0s
sudo rm /home/vagrant/guacamole-server-1.0.0.tar.gz
sudo rm /home/vagrant/guacamole-1.0.0.war
# -*- mode: ruby -*-
# vi: set ft=ruby :

BOX_1_NAME = "debian-1-guacamole"
BOX_2_NAME = "debian-2-guacamole"
BOX_BASE = "generic/debian10"
BOX_RAM_MB = 1024
BOX_CPU_COUNT = 1
BOX_GUI = false
BOX_SYNC_DIR = true

Vagrant.configure("2") do |config|

  config.vm.define BOX_1_NAME do |deb1|
    deb1.vm.box = BOX_BASE
    deb1.vm.synced_folder ".", "/vagrant", disabled: BOX_SYNC_DIR
    deb1.vm.hostname = BOX_1_NAME
    deb1.vm.network "private_network", ip: "192.168.10.5"
    deb1.vm.provider "virtualbox" do |vb1|
      vb1.name = BOX_1_NAME
      vb1.cpus = BOX_CPU_COUNT
      vb1.memory = BOX_RAM_MB
      vb1.gui = BOX_GUI
    end
  end

  config.vm.define BOX_2_NAME do |deb2|
    deb2.vm.box = BOX_BASE
    deb2.vm.synced_folder ".", "/vagrant", disabled: BOX_SYNC_DIR
    deb2.vm.hostname = BOX_2_NAME
    deb2.vm.network "forwarded_port", guest: 55555, host: 55555
    # deb2.vm.network "forwarded_port", guest: 5901, host: 5901
    # deb2.vm.network "forwarded_port", guest: 3389, host: 3389
    # deb2.vm.network "forwarded_port", guest: 23, host: 2323
    deb2.vm.network "private_network", ip: "192.168.10.10"
    deb2.vm.provider "virtualbox" do |vb2|
      vb2.name = BOX_2_NAME
      vb2.cpus = BOX_CPU_COUNT
      vb2.memory = BOX_RAM_MB
      vb2.gui = BOX_GUI
    end
    deb2.vm.provision "file", source: "./src", destination: "/tmp/guacamole"
    deb2.vm.provision "shell", name: "install", path: "./ShellProvisioner.sh"
  end

end

Usage

First start-up the environment (via simple Vagrant command) and next start the VNC inside the box. You can do via vagrant ssh or you start the VNC via Browser (SSH).

# start environment (be patient)
$ vagrant up

# show status (optional)
$ vagrant status

# ssh into 2nd box
$ vagrant ssh debian-2-guacamole

# start VNC server on user vagrant
$ vncserver

# Password: vagrant
# Verify: vagrant
# Would you like to enter a view-only password (y/n)? n

# exit ssh into box
$ exit

# open browser with URL
$ open http://localhost:55555/guacamole

Now login with “USERNAME/PASSWORD” (see src/user-mapping.xml) on http://localhost:55555/guacamole. If everything works it should look like this:

Guacamole on browser

Please have a look here https://guacamole.apache.org/doc/gug/index.html to learn more about configuration and authentication. All files which we used in this tutorial are available via https://github.com/Lupin3000/GuacamoleExample.

Curl via Socks5 proxy on macOS

SSH tunnel in Browsers are easy! What about curl via SSH tunnels? Yeah – it`s easy, too!

Preparation

Check minimal firewall rules and SSH configuration on target host.

# ensure ssh service is enabled
$ firewall-cmd --list-services
...
ssh

# ensure AllowTcpForwarding is allowed
$ sshd -T | grep -i AllowTcpForwarding
...
allowtcpforwarding yes

Create SSH tunnel

Some basics about SSH tunnel…

# create ssh tunnel (foreground process)
$ ssh -ND localhost:9000 <user>@<host>
$ ssh -C4ND localhost:9000 <user>@<host>
$ ssh -C4ND localhost:9000 <user>@<host> -v
$ ssh -C4ND localhost:9000 <user>@<host> -p 22 -v

# create ssh tunnel (background process)
$ ssh -C4ND localhost:9000 <user>@<host> -f
  • C: use compression (level can be set in configuration file)
  • 4: forces ssh to use IPv4 only
  • N: do not execute a remote command
  • D: specifies dynamic application-level port forwarding
  • v: verbose mode
  • f: go to background before command execution
  • p: port to connect to on the remote host

Check SSH tunnel

The following examples will help you to monitor the connection to the target server.

# check ssh tunnel (local)
$ ps aux | grep ssh

# check ssh tunnel via lsof (target)
$ lsof -nPi | grep ssh

# check ssh tunnel via ss (target)
$ ss -4t

Use SSH tunnel

Now we use the tunnel via curl. With the service ipinfo.io we can verify.

# curl for external ip (without tunnel)
$ curl https://ipinfo.io/ip

# curl for external ip
$ curl --socks5 localhost:9000 https://ipinfo.io/ip

# curl for external ip (since curl v7.21.7)
$ curl -x socks5://localhost:9000 https://ipinfo.io/ip

Note: There are two protocol prefixes socks5:// and socks5h://. The 2nd will let the SOCKS server handle DNS-queries.

Kill SSH tunnel

The simplest and hardest way to kill SSH tunnels (on background) is following example. But be careful it kills all ssh connections!

# kill all ssh tunnel
$ sudo killall ssh

SSH jump host example with vagrant

This time shows the tutorial two topics in one. The first topic is: “How an easy to configure SSH host jump”. The 2nd topic is: “Provisioning examples for Vagrant”.

Precondition

  • Vagrant installed
  • VirtualBox installed

File content

---
- name: jump_host
  box: centos/7
  ip: 192.168.100.10
  cpus: 1
  memory: 1024
- name: host_a
  box: centos/7
  ip: 192.168.100.20
  cpus: 1
  memory: 1024
- name: host_b
  box: centos/7
  ip: 192.168.100.30
  cpus: 1
  memory: 1024
Host *
  Compression yes
  AddressFamily inet
  Protocol 2
  ServerAliveInterval 60
  ServerAliveCountMax 30

Host jump_host
  HostName 192.168.x.x
  User testuser

Host host_*
  ProxyCommand ssh jump_host -W %h:%p
  User testuser
# -*- mode: ruby -*-

require 'yaml'

machines = YAML.load_file('machines.yml')
API_VERSION = "2"
KEY_LOCATION = "~/.ssh/id_rsa.pub"

Vagrant.require_version ">= 1.8.1"
Vagrant.configure(API_VERSION) do |config|

  # loop
  machines.each do |machines|
    # vm setup + provisioning
    config.vm.define machines["name"] do |machine|
      machine.vm.box = machines["box"]
      machine.vm.synced_folder ".", "/vagrant", disabled: true
      machine.vm.network "private_network", ip: machines["ip"]

      machine.vm.provider :virtualbox do |vb|
        vb.name = machines["name"]
        vb.cpus = machines["cpus"]
        vb.memory = machines["memory"]
        vb.gui = false
      end

      # provisioning: only jump_host
      if machines["name"] == 'jump_host'
        # prompt for interface
        machine.vm.network "public_network"

        machine.vm.provision "shell", inline: <<-SHELL
          cd /etc && sudo sed -i '/#AllowTcpForwarding yes/c\AllowTcpForwarding yes' ssh/sshd_config
          sudo systemctl restart sshd.service
          cd /etc && sudo grep -q 'host_a' hosts || echo '192.168.100.20  host_a' >> hosts
          cd /etc && sudo grep -q 'host_b' hosts || echo '192.168.100.30  host_b' >> hosts
        SHELL
      end

      # provisioning: all
      machine.vm.provision "file", source: KEY_LOCATION, destination: "/tmp/pub.key"

      machine.vm.provision "shell", inline: <<-SHELL
        sudo useradd testuser
        sudo mkdir /home/testuser/.ssh
        sudo touch /home/testuser/.ssh/authorized_keys
        sudo cat /tmp/pub.key > /home/testuser/.ssh/authorized_keys
        sudo rm -f /tmp/pub.key
        sudo chmod 0700 /home/testuser/.ssh
        sudo chmod 0644 /home/testuser/.ssh/authorized_keys
        sudo chown -R testuser:testuser /home/testuser/.ssh
      SHELL
    end
  end
end

Note: Replace values for HostName “192.168.x.x” by real IP from jump_host and KEY_LOCATION “~/.ssh/id_rsa.pub”!

Steps

# create and goto project
$ mkdir ~/Projects/JumpHostExample && cd ~/Projects/JumpHostExample

# create yaml file
$ vim machines.yml

# create Vagrantfile
$ vim Vagrantfile

# start Vagrant
$ vagrant up

# get IP from jump_host (for config)
$ ssh jump_host -c "ip addr show enp0s9"

# create or edit ssh config
$ vim ~/.ssh/config

# ssh into hosts via jump_host
$ ssh host_a
$ ssh host_b

Extend SSH Sessions on Mac OS

On Mac OS, SSH sessions to remote computers are timing out too quickly! The solution is to set a timeout interval in seconds.

Steps

# create configuration file for SSH
$ touch ~/.ssh/config

# edit the file
$ vim ~/.ssh/config

# add following content and save
ServerAliveInterval 120

Monitor multiple remote log files with MultiTail

With MultiTail you are able to view one or multiple log files (on remote engines). Therefore it creates multiple split-windows on your console. You can configure these! To see all features look here.

Installation

# install on Mac OS via Mac Ports
$ sudo port install multitail

# install on Mac OS via Homebrew
$ sudo brew install multitail

# install on RHEL/CentOS/Fedora
$ yum install -y multitail

# install on Debian/Ubuntu/Mint
$ sudo apt-get install multitail

Examples

# example for two log-files
$ multitail log-file_a log-file_b

# example for two log-files and two columns
$ multitail -s 2 log-file_a log-file_a

# example for two log-files and different colors
$ multitail -ci green log-file_a -ci yellow -I log-file_a

# example for one log file on remote
$ multitail -l "ssh -t <user>@<host> tail -f log-file"

# example for four log files on remote
$ multitail -l "ssh -l <user> <host> tail -f log-file_a" -l "ssh -l <user> <host> tail -f log-file_b" -l "ssh -l <user> <host> tail -f log-file_c" -l "ssh -l <user> <host> tail -f log-file_d"

Note

If you look on multiple files at same time with MultiTail – just hit the “b” key to select the window, with up/down keys you can scroll.

Simple ssh brute-force attack with Hydra

With Hydra you can recover your SSH credentials. Here a tiny tutorial how it works.

Installation

I do install via ports but also different other possibilities are available.

# update macports (optional)
$ sudo port selfupdate

# search port (optional)
$ port search hydra

# check dependencies (optional)
$ port rdeps hydra

# install port
$ sudo port install hydra

Test preparation

Now create two files (or download anywhere)

# create password file
$ vim passwords.txt

# create users file
$ vim users.txt

Create some content (by line) and start the ssh brute-force with Hydra.

Run SSH password recover

# use password.txt only
$ hydra -l root -P passwords.txt <target> ssh

# use user.txt only
$ hydra -L users.txt -p 12345 <target> ssh

# use user and password files
$ hydra -L users.txt -P passwords.txt <target> ssh

If Hydra found something, the message looks like:

[22][ssh] host: <target> login: <user> password: <password>

Note: for legal purposes only!