Some of the practices described in this HOWTO are considered to be illegal as they often break internal corporate policies. Anything you do, you do at your own risk.
This HOWTO will show how to make running most of the tools used in a corporate environment under Linux. This HOWTO assumes that the company is using Windows as their main operating system and Cisco-based infrastructure (WiFi, VPN, communication tools).
Just to name few reasons:
- No license fees
- Stability, security and privacy
- No need to run antivirus software
- Better package management
- Better automation of tasks
- Better window management
- Freedom
Big corporations are either not supporting Linux desktops at all or are thinking to support the same Linux distribution for their production servers as well as for desktop. The second option is definitely more optimistic although still not very good. The Linux distribution used on servers is usually either RedHat Enterprise Linux or one of its derivatives (CentOS, Oracle Linux, ...). Those are good choice for servers but definitely not for desktop. More suitable distribution for desktop are Ubuntu, Fedora, Arch Linux or any other cutting edge distribution.
Almost every corporation is using Microsoft Windows as their main desktop operating system. Windows desktops are usually secured with an user-specific certificate. This certificate is usually not possible to export and the only access to the certificate is usually provided only through a Public Key Infrastructure (e.g. Cisco PKI client) which normally doesn't support Linux. This is the root of all problems to run Linux desktop in the corporate environment. In order to make things working on Linux, we must get the user's certificate from Windows.
For this we can use Mimikatz.
Mimikatz allows to
extract
user's certificate directly from the Windows memory. In order to run
Mimikatz, the Windows firewall/antivirus must be disabled (ask some
friendly desktop support guy to help you with that). As Mimikatz extracts
all certificates by default, we need to identify which of them is
actually the user's certificate. Once the certificates are exported, you
can delete all the installed certificates (run certmgt.msc
command on
Windows). Then import certificates one by one and try to connect to the
corporate WiFi (and/or VPN). Once the connection is established, you
found the user's certificate.
Mimikatz secures all the exported certificates with a default password so it's recommended to change it:
$ openssl pkcs12 -des3 -in CURRENT_USER_My_1_<username>.pfx -out user_cert.pfx
Now we can delete the original certificate:
$ rm -f ./CURRENT_USER_My_1_<username>.pfx
The user's certificate has two parts - the public certificate and the
private key. You can extract each of them from the .pfx
file like
this:
$ openssl pkcs12 -in user_cert.pfx -nodes -nocerts -out Key.pem
$ openssl pkcs12 -in user_cert.pfx -nodes -nokeys -clcerts -out ClientCert.pem
And set password on the private key:
$ openssl rsa -aes256 -in Key.pem -out KeyP.pem
Now we can delete the unsecured key:
$ rm -f ./Key.pem
Although we can secure the private key and with a password, it is still
not very secure as anybody who get access to our PC can steal them. We
can extend the security by encrypting the filesystem (eg. ecryptfs
,
dm-crypt
) and allow to decrypt it only when we login.
This is still not very secure as the private key is still available as a file. But if we use Yubikey NEO, we can upload the public certificate and the private key on it and nobody, including us, can ever extract the private key from it. That makes it a very secure solution. That's possible only thanks to the NEO's Privilege and Identification Card (PIV) interface used to provide a platform-independent API to cryptographic tokens via PKCS#11 standard. That makes the Yubikey to work like a smart card. Access to the PIV interface is secured by a PIN - only person who knows the password can use the Yubikey to authenticate.
To load the user's certificate on the Yubikey, we can either use
GUI or
CLI. Go
ahead and use the GUI to set the PIN/PUK and import the user's
certificate (user_cert.pfx
) into the Authenticate slot (9a). I will
show here how to do it with the CLI as it allow us to do more things
(e.g. change the number of PIN/PUK attempts).
First we block the PIN and PUK to be able to reset the PIV application (both must be blocked before we can reset the application). Bear in mind that this action will destroy all keys stored in PIV application:
$ for N in $(seq 3); do yubico-piv-tool -a verify-pin -P wrongpin; yubico-piv-tool -a change-puk -P wrongpuk -N wrongpuk; done
$ yubico-piv-tool -a reset
First we generate and set a new Management KEY (24 bits in hex):
$ dd if=/dev/random bs=1 count=24 2>/dev/null | hexdump -v -e '/1 "%02X"' | gpg -c -a -o MgmtKey.gpg
$ KEY=$(gpg -d MgmtKey.gpg 2>/dev/null)
$ yubico-piv-tool -a set-mgm-key -n $KEY
Keep the MgmtKey.gpg
file secure for later use. Then we set PIN (4-8
chars) and PUK (4-8 chars):
$ read -s -p "Type your new PIN: " PIN
$ read -s -p "Type your new PUK: " PUK
$ yubico-piv-tool -a change-pin -P 123456 -N $PIN
$ yubico-piv-tool -a change-puk -P 12345678 -N $PUK
Upload the user's certificate onto the Yubikey:
$ read -s -p "Type the user's certificate password: " PASS
$ yubico-piv-tool -s 9a -a import-key -a import-cert -a set-chuid -i user_cert.pfx -K PKCS12 -p $PASS -k $KEY
Verify that the user's certificate is installed:
$ yubico-piv-tool -a status
Clean the KEY, PIN, PUK and PASS from the environment (or simply exit the shell):
$ unset KEY PIN PUK PASS
The following commands are showing other potentially useful tasks. If we by accident block the PIN (3 unsuccessful attempts), we can unblock it with the PUK:
$ yubico-piv-tool -a unblock-pin -N $PIN --pin $PUK
If the PUK is blocked (3 unsuccessful attempts), the PIV applet will be blocked and we need to reset it (see above).
We can change the number of attempts for PIN/PUK:
$ yubico-piv-tool -a pin-retries --pin-retries=10 --puk-retries=5 -k $KEY
We can change the PIN/PUK:
$ yubico-piv-tool -a change-pin -P $PIN -N $NEW_PIN
$ yubico-piv-tool -a change-puk -P $PUK -N $NEW_PUK
We can extract the public certificate (not the private key) from the Yubikey:
$ yubico-piv-tool -a read-certificate -s 9a > ClientCert.pem
In order to connect to the WiFi from Linux, we need to have the user's
certificate (see above how to get it). Then we can use either the .pfx
file directly (not recomended):
# Path to the control interface
ctrl_interface=/var/run/wpa_supplicant
# Allow users from the group wheel to connect to the control interface
ctrl_interface_group=wheel
# Some more params
eapol_version=1
ap_scan=1
fast_reauth=1
update_config=1
# Using the .pfx file (not recomended)
network={
ssid="CORPORATE"
key_mgmt=WPA-EAP
eap=TLS
identity="none"
# Cert and key from the .pfx file
private_key="/path/to/your/user_cert.pfx"
# Run wpa_gui or wpa_cli to be asked for the password
#private_key_passwd="password"
}
Or we can use the user's certificate stored on the Yubikey (change the
value of disabled=1
to 0
for the relevant block):
# Path to the control interface
ctrl_interface=/var/run/wpa_supplicant
# Allow users of the group wheel to connect to the interface
ctrl_interface_group=wheel
# Some more params
eapol_version=1
ap_scan=1
fast_reauth=1
update_config=1
# Make the pkcs11 engine available (requires engine_pkcs11 > v0.1.8 and libp11 > v2.8)
pkcs11_engine_path=/usr/lib/engines/engine_pkcs11.so
# Configure the path to the pkcs11 module required by the pkcs11 engine
pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
# Using Yubikey - for wpa_supplicant < v2.4
network={
disabled=1
ssid="CORPORATE"
key_mgmt=WPA-EAP
eap=TLS
identity="none"
# Use yubico-piv-tool to read the certificate
client_cert="/path/to/your/ClientCert.pem"
# Select the right engine
engine=1
engine_id="pkcs11"
# Use "pkcs11-tool -L" to get the slot number
# Use "pkcs11-tool -O" or "pkcs15-tool --list-keys" to get the ID
key_id="slot_1-id_01"
# Run wpa_gui or wpa_cli to be asked for the PIN - requires patch
#pin="password"
}
# Using Yubikey - for wpa_supplicant >= v2.4
network={
disabled=1
ssid="CORPORATE"
key_mgmt=WPA-EAP
eap=TLS
identity="none"
# Use "p11tool --list-tokens | grep =piv" to get the value
client_cert="pkcs11:manufacturer=piv_II;id=%01"
private_key="pkcs11:manufacturer=piv_II;id=%01"
# There is no password so define is as an empty string
private_key_passwd=""
# Run wpa_gui or wpa_cli to be asked for the PIN - requires patch
#pin="password"
}
It's recommended to keep running wpa_gui
or wpa_cli
in order to be
asked for the password or PIN interactively. It's more secure than keep
the password or PIN written in the wpa_supplicant.conf
file.
In the case of using Yubikey, it's necessary to apply the following patch
and re-build the wpa_supplicant
:
diff -u -r a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
--- a/src/eap_peer/eap_tls_common.c 2015-03-15 18:30:39.000000000 +0100
+++ b/src/eap_peer/eap_tls_common.c 2015-08-17 14:29:52.000000000 +0200
@@ -204,6 +204,11 @@
*/
os_free(config->pin);
config->pin = NULL;
+ eap_sm_request_pin(sm);
+ sm->ignore = TRUE;
+ tls_connection_deinit(data->ssl_ctx, data->conn);
+ data->conn = NULL;
+ return -1;
} else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
wpa_printf(MSG_INFO, "TLS: Failed to load private key");
/*
That will make sure that the PIN is requested via wpa_gui
or wpa_cli
.
VPN is normally used to secure connection to the corporate network. Corporat solution for that are usually supported only for Windows desktops. The only tolerated solution for Linux desktop is by using virtualized Windows guest and tunnel the VPN connection to Linux host. Such solution is usually slow, impractical and mainly huge waste of resources. Therefore it's desirable to have native Linux client.
Connection to Cisco AnyConnect VPN is possible with
OpenConnect client. The best way
how to connect to this device is to use
OpenConnect client. The
connection is usually secured by an user's certificate and the Cisco
Secure Desktop (CSD) policy. CSD is a program which is stored on the VPN
device and runs before every connection to verify certain facts about the
client device. Full list of parameters sent by the CSD check back to the
server can be found on Windows in the AnyConnect client log file
(C:\Users\<username>\AppData\Local\Cisco\Cisco HostScan\log\cscan.log
).
Just for information, the proprietary CSD for Linux is stored on the VPN device and can be downloaded like this:
# Change i386 to x64 for 64-bit binaries
$ for N in $(wget -q -O - https://vpn.company.com/CACHE/sdesktop/hostscan/linux_i386/manifest | sed -r 's/.*\(//;s/\).*//'); do wget -q https://vpn.company.com/CACHE/sdesktop/hostscan/linux_i386/$N; done
CSD policy can be configured to deny connections from Linux clients. This can be verified in the policy file:
$ wget -q -O - https://vpn.company.com/CACHE/sdesktop/data.xml | grep -A1 'os_check.*linux' | grep denied 1>/dev/null && echo "Linux is denied" || echo "Linux is enabled"
If the Linux connection is denied, OpenConnect allows to fake CSD output with a script so the VPN server thinks that the connection was established from a client which is trusted:
$ cat <<SCRIPT > /path/to/the/csd-wrapper.sh
#!/bin/bash
function run_curl {
curl \\
--insecure \\
--user-agent "AnyConnect Windows \$ver" \\
--header "X-Transcend-Version: 1" \\
--header "X-Aggregate-Auth: 1" \\
--header "X-AnyConnect-Platform: \$plat" \\
--cookie "sdesktop=\$token" \\
"\$@"
}
set -e
host=https://\$CSD_HOSTNAME
plat=win
ver=3.1.02043
token=\$CSD_TOKEN
###
# Here goes the list of parameters which should be sent back to the server.
# By default, only the endpoint.policy.location parameter is required.
###
# Get the value of the <policy_location> on Windows from the cscan.log file
# OR
# get it from the policy file:
# wget -O - -q https://vpn.company.com/CACHE/sdesktop/data.xml | grep 'location name='
###
run_curl --data-ascii @- "\$host/+CSCOE+/sdesktop/scan.xml?reusebrowser=1" <<-END
endpoint.policy.location="<policy_location>";
END
exit 0
SCRIPT
Make it executable:
$ chmod +x /path/to/the/csd-wrapper.sh
The CSD script can be used either on the command line or in the configuration file:
$ cat <<END > /path/to/the/openconnect.conf
# Silence the output
quiet
# Prevent error message in the syslog
no-dtls
# Run the process on background after connection is established
background
# Send all logs to syslog after the connection is established
syslog
# Where to store the process ID
pid-file=/var/run/openconnect.pid
# User's certificate
certificate=/path/to/your/ClientCert.pem
# Users's private key
sslkey=/path/to/your/Key.pem
# CSD wrapper used to fake the output of the desktop check script
csd-wrapper=/path/to/the/csd-wrapper.sh
# User's name
user=<username>
# User's password (will be prompted on the command line if commented out)
#password=<password>
END
The connection can then be established with this command:
$ openconnect --config=/path/to/the/openconnect.conf vpn.company.com
And the connection can be closed by this command:
$ pkill -F /var/run/openconnect.pid
OpenConnect supports PKCS#11 which makes it possible to use user's
certificate stored on the Yubikey NEO. To make it working only requires
replace the certificate
and sslkey
parameters in the configuration
file with the following like:
# Search for both the cert and the key on the Yubikey NEO
# (http://www.infradead.org/openconnect/pkcs11.html)
certificate=pkcs11:manufacturer=piv_II;id=%01
Use vpnc
to connect to Nortel VPN. It requires special
branch of
vpnc
which supports Nortel devices. The vpnc
configuration (e.g.
/etc/vpnc/company.conf
) is then like the following:
IPSec gateway <CompanyVpnServer>
IPSec ID <CompanyVpnID>
IPSec secret <CompanyVpnSecret>
Xauth username <username>
#Xauth password <password>
Vendor nortel
Nortel Client ID V07_01
Then use the following command to connect to the VPN:
$ vpnc company
Juniper VPN requires proprietary client (ncsvc
) which is stored on the
device itself. There is many scripts which automate download of the
proprietary client and establishment of the connection but probably the
best one is jvpn. The installation
and configuration of jvpn
is straightforward.
There is certain support support for Juniper VPN in OpenConnect. If the Juniper VPN requires user's certificate, then this is probably preffered solution as OpenConnect supports PKCS#11 interface used by Yubikey NEO.
TODO
Use Webmail or Davmail.
The WebEx plugin is a Java Application which only works in web browsers which support NPAPI. Google Chrome removed this support in the version 42. Fortunately Firefox still supports it. Other problem is that WebEx is 32-bit application which requires 32-bin Oracle Java (JRE) which must run in 32-bit Firefox.
Screen sharing, chat and computer audio works just fine. Just make sure no other application (e.g web browser) is using the soundcard while trying to use the computer audio in WebEx.
If the company is using Microsoft Communicator, then Pidgin with SIPE plugin should work.
If the company is using Cisco Jabber, then alternative Jabber client (e.g. Pidgin) should work. There is also Cisco WebEx Web IM which works from any web browser. If run from the 32-bit Firefox then even the WebEx meeting integration works. If the company is using some sort of Single Sign ON (SSO) system, then alternative Jabber clients probably won't work.
Pidgin (libpurple
) doesn't understand the authentication method
WEBEX-TOKEN
(run pidgin -d
):
jabber: Sending (ssl) (anonymous@company.com): <stream:stream to='company.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>
jabber: Recv (ssl)(183): <stream:stream xmlns='jabber:client' xml:lang='en-US.UTF-8' xmlns:stream='http://etherx.jabber.org/streams' from='company.com' id='lsh4avD9N5Wxeb3b7TtvwQ45878' version='1.0'>
jabber: Recv (ssl)(163): <stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>WEBEX-TOKEN</mechanism><mechanism>PLAIN</mechanism></mechanisms></stream:features>
sasl: Mechs found: WEBEX-TOKEN PLAIN
jabber: Sending (ssl) (anonymous@company.com): <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN' xmlns:ga='http://www.google.com/talk/protocol/auth' ga:client-uses-full-bind-result='true'>password removed</auth>
jabber: Recv (ssl)(77): <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized/></failure>
sasl: Mechs found: WEBEX-TOKEN
sasl: No worthy mechs found
I believe that the server sends an ID which should be used on the SSO web page. The SSO web page should then return some other hash which should be send to the Jabber server.
- Can the Jabber server provide the URL for the SSO web page?
- How to pass the ID to the SSO web page (which Jabber message)?
- How to get the hash from the SSO web page and how to pass it back to the Jabber server?
Configure hosts
file on Windows to send request for the Jabber server
via a Linux machine where we run stunnel
and tcpflow
to sniff the
communication.
OR
Try to establish connection via AJAX XMPP and then sniff the communication.
Then try to implement the protocol into the libpurple
.