Forked from anonymous/corporate-linux-desktop-howto.md
Created
November 3, 2015 17:09
Revisions
-
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,623 @@ How to run Linux desktop in a corporate environment =================================================== DISCLAIMER ---------- **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.** Description ----------- 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). Why to use Linux? ----------------- 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 Distribution ------------ 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. User's certificates ------------------- 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. ### User's certificate extraction For this we can use [Mimikatz](https://github.com/gentilkiwi/mimikatz). Mimikatz allows to [extract](http://theunixtips.com/export-nonexporteable-private-certificate-from-symantec-pki/) 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 ``` ### Public certificate and private key extraction (optional) 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 ``` ### Using YubiKey NEO 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](https://www.yubico.com/products/yubikey-hardware/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](https://developers.yubico.com/yubikey-piv-manager/) or [CLI](https://developers.yubico.com/PIV/Tools/Yubico_PIV_Tool.html). 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 ``` WiFi ---- 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 --- 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. ### Cisco AnyConnect Connection to Cisco AnyConnect VPN is possible with [OpenConnect](http://www.infradead.org/openconnect/) client. The best way how to connect to this device is to use [OpenConnect](http://www.infradead.org/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 ``` ### Nortel Use `vpnc` to connect to Nortel VPN. It requires special [branch](https://svn.unix-ag.uni-kl.de/vpnc/branches/vpnc-nortel/) 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 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](https://github.com/samm-git/jvpn). The installation and configuration of `jvpn` is straightforward. There is certain support support for Juniper VPN in [OpenConnect](http://www.infradead.org/openconnect/juniper.html). If the Juniper VPN requires user's certificate, then this is probably preffered solution as OpenConnect supports PKCS#11 interface used by Yubikey NEO. ### Check Point TODO Email ----- Use Webmail or [Davmail](http://davmail.sourceforge.net). WebEx ----- 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. Instant Messaging ----------------- ### Microsoft Communicator If the company is using _Microsoft Communicator_, then Pidgin with SIPE plugin should work. ### Jabber If the company is using _Cisco Jabber_, then alternative Jabber client (e.g. Pidgin) should [work](http://csh.us/2012/07/09/pidgin-support-for-cisco-webex-im/). 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. #### Problem with SSO 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. #### Questions - 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? #### Possible solution 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](https://developer.cisco.com/media/AJAX-XMPP-Library-Index/index.html) and then sniff the communication. Then try to implement the protocol into the `libpurple`.