Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Cisco Anyconnect CSD wrapper for OpenConnect (exhanced to autodownload and autoupdate hostscan)
#!/bin/bash
# Cisco Anyconnect CSD wrapper for OpenConnect
# Enter your vpn host here
CSD_HOSTNAME=
if [[ -z ${CSD_HOSTNAME} ]]
then
echo "Define CSD_HOSTNAME with vpn-host in script text. Exiting."
exit 1
fi
HOSTSCAN_DIR="$HOME/.cisco/hostscan"
LIB_DIR="$HOSTSCAN_DIR/lib"
BIN_DIR="$HOSTSCAN_DIR/bin"
BINS=("cscan" "cstub" "cnotify")
# parsing command line
shift
URL=
TICKET=
STUB=
GROUP=
CERTHASH=
LANGSELEN=
while [ "$1" ]; do
if [ "$1" == "-ticket" ]; then shift; TICKET=$1; fi
if [ "$1" == "-stub" ]; then shift; STUB=$1; fi
if [ "$1" == "-group" ]; then shift; GROUP=$1; fi
if [ "$1" == "-certhash" ]; then shift; CERTHASH=$1; fi
if [ "$1" == "-url" ]; then shift; URL=$1; fi
if [ "$1" == "-langselen" ];then shift; LANGSELEN=$1; fi
shift
done
ARCH=$(uname -m)
if [[ "$ARCH" == "x86_64" ]]
then
ARCH="linux_x64"
else
ARCH="linux_i386"
fi
# creating dirs
for dir in $HOSTSCAN_DIR $LIB_DIR $BIN_DIR ; do
if [[ ! -f $dir ]]
then
mkdir -p $dir
fi
done
# getting manifest, and checking binaries
wget --no-check-certificate -c "https://${CSD_HOSTNAME}/CACHE/sdesktop/hostscan/$ARCH/manifest" -O "$HOSTSCAN_DIR/manifest"
# generating md5.sum with full paths from manifest
export HOSTSCAN_DIR=$HOSTSCAN_DIR
cat $HOSTSCAN_DIR/manifest | sed -r 's/\(|\)//g' | awk '{ cmd = "find $HOSTSCAN_DIR -iname " $2; while (cmd | getline line) { print $4, line; } }' > $HOSTSCAN_DIR/md5.sum
# check number of files either
MD5_LINES=`wc --lines $HOSTSCAN_DIR/md5.sum | awk '{ print $1; }'`
MANIFEST_LINES=`wc --lines $HOSTSCAN_DIR/manifest | awk '{ print $1; }'`
echo "Got $MANIFEST_LINES files in manifes, locally found $MD5_LINES"
# check md5
md5sum -c $HOSTSCAN_DIR/md5.sum
if [[ "$?" -ne "0" || "$MD5_LINES" -ne "$MANIFEST_LINES" ]]
then
echo "Corrupted files, or whatever wrong with md5 sums, or missing some file"
# just download every file mentioned in manifest (not ideal, but hopefully should be enough)
FILES=( $(cat $HOSTSCAN_DIR/manifest | sed -r 's/\(|\)//g' | awk '{ print $2; }') )
WORK_DIR=`pwd`
TMP_DIR=`mktemp -d` && cd $TMP_DIR
for i in ${FILES[@]} ; do
FILE="$(basename "$i")"
echo "Downloading: $FILE to $TMP_DIR"
wget --no-check-certificate -c "https://${CSD_HOSTNAME}/CACHE/sdesktop/hostscan/$ARCH/$FILE" -O $FILE
# some files are in gz (don't understand logic here)
if [[ ! -f $FILE || ! -s $FILE ]]
then
# remove 0 size files
if [[ ! -s $FILE ]]; then
rm $FILE
fi
echo "Failure on $FILE, trying gz"
FILE_GZ=$FILE.gz
wget --no-check-certificate -c "https://${CSD_HOSTNAME}/CACHE/sdesktop/hostscan/$ARCH/$FILE_GZ" -O $FILE_GZ
gunzip --verbose --decompress $FILE_GZ
fi
# don't know why, but my version of hostscan requires tables to be stored in libs
echo $FILE | grep --extended-regexp --quiet --invert-match ".so|tables.dat"
IS_LIB=$?
if [[ "$IS_LIB" -eq "1" ]]
then
cp --verbose $FILE $LIB_DIR
else
cp --verbose $FILE $BIN_DIR
fi
done
for i in ${BINS[@]} ; do
echo "Setting excecution bit on: $BIN_DIR/$i"
chmod u+x $BIN_DIR/$i
done
cd $WORK_DIR
rm -rf $TMP_DIR
fi
# cstub doesn't care about logging options, sic!
#ARGS="-log debug -ticket $TICKET -stub $STUB -group $GROUP -host $URL -certhash $CERTHASH"
ARGS="-log error -ticket $TICKET -stub $STUB -group $GROUP -host $URL -certhash $CERTHASH"
echo "Launching: $BIN_DIR/cstub $ARGS"
$BIN_DIR/cstub $ARGS
@asarkar
Copy link

asarkar commented Oct 29, 2018

I rewrote the script to not use any additional software and tested it on macOS Mojave
https://gist.github.com/asarkar/fb4452a4abdf9e4a9752a7d55d2cdc93

@jcfaracco
Copy link

jcfaracco commented Dec 11, 2018

Guys,

Is anyone seeing this error like me? Or did anyone have the same experience?

[Tue Dec 11 15:23:26.098 2018][cstub][debug][hs_download_file] attempting to download file: /CACHE/sdesktop/hostscan/linux_x64/libcsd.so.gz
[Tue Dec 11 15:23:26.098 2018][cstub][trace][hs_transport_setpeer] setting peer
[Tue Dec 11 15:23:26.098 2018][cstub][trace][hs_transport_setpeer] setting l2 peer: (https://MY_HOSTNAME)
[Tue Dec 11 15:23:26.098 2018][cstub][trace][hs_transport_setpeer] setting peer done. peer = https://MY_HOSTNAME, referrer = https://MY_HOSTNAME
[Tue Dec 11 15:23:26.098 2018][cstub][trace][hs_transport_setredircount] setting redirects
[Tue Dec 11 15:23:26.099 2018][cstub][trace][hs_transport_setredircount] setting redirects: (10)
[Tue Dec 11 15:23:26.099 2018][cstub][trace][hs_transport_setredircount] setting redirects done
[Tue Dec 11 15:23:26.099 2018][cstub][trace][hs_transport_get] sending get request
[Tue Dec 11 15:23:26.460 2018][cstub][debug][hs_transport_curl_get] libcurl error: Error

[Tue Dec 11 15:23:26.460 2018][cstub][warn][hs_transport_get] sending get request failed
[Tue Dec 11 15:23:26.460 2018][cstub][error][hs_download_file] unable to contact peer: (https://MY_HOSTNAME).

Obviously, I'm using MY_HOSTNAME to hide my server name. How can I avoid/fix libcurl errors since I'm not using or downloading it?
Btw, I can ping and access the real server name hidden by MY_HOSTNAME.

@Jomik
Copy link

Jomik commented Dec 18, 2018

I seem to be missing cnotify, which I guess could be what causes the loop that people have mentioned.
I also get the an error when trying to execute cstub, both via the script and manually.

Failed to execute process './cstub'. Reason:
The file './cstub' does not exist or could not be executed.

The file is there though.

@salim-b
Copy link

salim-b commented Jan 29, 2019

Just wanted to remind people, that OpenConnect includes a csd-wrapper.sh (based on this Gist) as well as a csd-post.sh script these days: https://gitlab.com/openconnect/openconnect/tree/master/trojans

For obvious reasons (see below) it's recommended to use csd-post.sh if possible!

From the official OpenConnect documentation:

The OpenConnect distribution includes two alternative scripts to support the execution or spoofing of the CSD behaviour, in the trojans/ subdirectory:

  • csd-wrapper.sh: This script accepts the same options as some versions of the CSD trojan binary, (-ticket, -stub, -group, -certhash, -url, -langselen), downloads the files required by the binary, and then wraps the execution of the cstub binary. Because of the security dangers of executing a server-provided trojan binary, this script should ideally be executed with the permissions of a low-privilege user (e.g. --csd-user=nobody --csd-wrapper=trojans/csd-wrapper.sh).
  • csd-post.sh: This script does not actually run the CSD trojan binary. Instead, it emulates the behaviour of the CSD trojan, creating a plaintext report similar to the one that the CSD trojans build, and uploading it to the server sent by the VPN gateway. The report may need to be customized in order to be accepted by some servers; the hostscan-bypass tool may help with this. Because this script does not actually execute a trojan binary, and because its complete output is easily visible in the script, the security concerns are greatly alleviated.

@Gilks
Copy link

Gilks commented Feb 23, 2019

Hey! Saw some traffic coming to the hostscan-bypass from this gist. I just wanted to add on to what salim-b was saying. The hostscan-bypass creates a customized csd file for your environment. If you have access to a machine that you know works, you are able to MITM the exact values it uses to authenticate to the VPN endpoint. If the included csd wrappers are not working, hostscan-bypass will.

@unknownbreaker
Copy link

unknownbreaker commented Mar 22, 2019

So based on all the Q&A above, how would one summarize the instructions needed to emulate a Cisco Anyconnect VPN connection?

@asarkar
Copy link

asarkar commented Mar 23, 2019

@salim-b There is no documentation for the usage of the csd scripts from openconnect. Those are just as useful as the trash I took out this morning.

@blancNoir
Copy link

blancNoir commented Apr 5, 2019

thank you, this worked like a charm! (running on manjaro)

@Marston
Copy link

Marston commented Sep 2, 2019

Trying to run this on a Mac Mojave but it's caught in a loop where I get:

Refreshing +CSCOE+/sdesktop/wait.html after 1 second...
GET https://vpn.xxx.com/+CSCOE+/sdesktop/wait.html
SSL negotiation with vpn.xxx.com
Connected to HTTPS on vpn.xxx.com

What's going on here? How can I fix it?

@silveiralexf
Copy link

silveiralexf commented Oct 27, 2019

thanks for this!

@AlexLu202
Copy link

AlexLu202 commented Jan 9, 2020

I've got Bad CPU type in executable. I guess because of my os is catalina? Any solutions?

@ngrigoriev
Copy link

ngrigoriev commented Feb 17, 2020

@AlexLu202 Same here - have you learned anything?

@ngrigoriev
Copy link

ngrigoriev commented Feb 17, 2020

@AlexLu202

Never mind, the solution appears quite simple.

Find this line:

ARCH="darwin_i386"

Replace with:

ARCH="darwin_x64"

It worked for me.

@dlewis7444
Copy link

dlewis7444 commented Mar 16, 2020

Seemed to work - downloaded a bunch of files - but then I'm getting "drbg_instantiate failed".

No idea what that means. Google not much help. Anybody?

Refreshing +CSCOE+/sdesktop/wait.html after 1 second...
drbg_instantiate failed
drbg_instantiate failed
GET https:///+CSCOE+/sdesktop/wait.html
SSL negotiation with
double free or corruption (!prev)
Connected to HTTPS on
Refreshing +CSCOE+/sdesktop/wait.html after 1 second...

And continues on forever

@SoptikHa2
Copy link

SoptikHa2 commented Apr 3, 2020

@dlewis7444 same issue here, did you find a solution?

@fernandoracca
Copy link

fernandoracca commented Apr 6, 2020

regarding the loop problem, i had to tweak the csd-wrapper script to get it to work with my servers:

#PINNEDPUBKEY="-s ${CSD_SHA256:+"-k --pinnedpubkey sha256//$CSD_SHA256"}"
PINNEDPUBKEY="--insecure ${CSD_SHA256:+"-k --pinnedpubkey sha256//$CSD_SHA256"}"

then it started working, once the script succeeded downloading the files on $HOSTSCAN_DIR ($HOME/.cisco/hostscan)

@cowbe0x004
Copy link

cowbe0x004 commented May 1, 2020

regarding the loop problem, i had to tweak the csd-wrapper script to get it to work with my servers:

#PINNEDPUBKEY="-s ${CSD_SHA256:+"-k --pinnedpubkey sha256//$CSD_SHA256"}"
PINNEDPUBKEY="--insecure ${CSD_SHA256:+"-k --pinnedpubkey sha256//$CSD_SHA256"}"

then it started working, once the script succeeded downloading the files on $HOSTSCAN_DIR ($HOME/.cisco/hostscan)

What did you tweak?

@amritjsr
Copy link

amritjsr commented Aug 29, 2020

How to make this work for Raspberry-Pi ( ARM Based Processor ) ?
THanks on Advance

@miratim
Copy link

miratim commented Sep 2, 2020

Recently upgraded to ubuntu 20.10 because I'm an idiot, and since then, the csd_wrapper.sh is failed with a very specific set of errors.

I can't make heads or tails of it. Any quick tips on what I need to look at here?

Thanks!

  1. From the VPN panel dialog logs:
    ...
    XML POST enabled
    CSD script '/home/mirat/.cisco/csd-wrapper.sh' returned non-zero status: 243
    Authentication may fail. If your script is not returning zero, fix it.
    ...

  2. From within the cstub.log under .cisco/hostscan:

[Wed Sep 02 11:35:16.482 2020][cstub]Function: hs_file_verify_with_killdate Thread Id: 0x13900300 File: /tmp/build/thehoff/Negasonic_MR30.221858515975/Negasonic_MR3/posture/common/libcommon/hs_file_verify_linux.c Line: 354 Level: debug :: verifying file signature: file = [/home/mirat/.cisco/hostscan/lib/libcsd.so], signer = [Cisco Systems, Inc.], type = [2]
[Wed Sep 02 11:35:16.494 2020][cstub]Function: verify_cb Thread Id: 0x13900300 File: /tmp/build/thehoff/Negasonic_MR30.221858515975/Negasonic_MR3/posture/common/libcommon/hs_file_verify_linux.c Line: 694 Level: error :: Error 20, unable to get local issuer certificate
[Wed Sep 02 11:35:16.494 2020][cstub]Function: verify_cert Thread Id: 0x13900300 File: /tmp/build/thehoff/Negasonic_MR30.221858515975/Negasonic_MR3/posture/common/libcommon/hs_file_verify_linux.c Line: 978 Level: error :: Certificate is not trusted
[Wed Sep 02 11:35:16.495 2020][cstub]Function: hs_file_verify_with_killdate Thread Id: 0x13900300 File: /tmp/build/thehoff/Negasonic_MR30.221858515975/Negasonic_MR3/posture/common/libcommon/hs_file_verify_linux.c Line: 458 Level: error :: unable to verify the certificate trust.
[Wed Sep 02 11:35:16.495 2020][cstub]Function: hs_dl_load Thread Id: 0x13900300 File: /tmp/build/thehoff/Negasonic_MR30.221858515975/Negasonic_MR3/posture/common/libcommon/hs_dlhandler.c Line: 101 Level: error :: file signature invalid, not loading library (/home/mirat/.cisco/hostscan/lib/libcsd.so).
[Wed Sep 02 11:35:16.495 2020][cstub]Function: get_csd_handle Thread Id: 0x13900300 File: /tmp/build/thehoff/Negasonic_MR30.221858515975/Negasonic_MR3/posture/asa/libcsd/libcsd_static.c Line: 42 Level: error :: unable to load csd library: /home/mirat/.cisco/hostscan/lib/libcsd.so.
[Wed Sep 02 11:35:16.495 2020][cstub]Function: run Thread Id: 0x13900300 File: /tmp/build/thehoff/Negasonic_MR30.221858515975/Negasonic_MR3/posture/asa/cstub/main.c Line: 821 Level: error :: unable to initialize csd library.

@gskjold
Copy link

gskjold commented Oct 26, 2020

I have the same issue after upgrade to Ubuntu 20.10 as you @miratim , did you find any solution?

@miratim
Copy link

miratim commented Oct 26, 2020

@sharkodlak
Copy link

sharkodlak commented Jan 18, 2021

I had same issue. From log I found that file .cisco/hostscan/lib/libcsd.so signed by Cisco Systems, Inc. cant be verified.
Solved by adding VeriSign G5 among ca-certificates.

@danparisi
Copy link

danparisi commented Feb 5, 2021

Thanks @sharkodlak,
I had the same issue on ubuntu, and fixed adding the certificate as suggested by you.

Here is a guide on how to do that:
https://brian.haun.me/how-to-update-root-ca-certs.html

Copy link

ghost commented Feb 5, 2021

@sharkodlak @danparisi do you have this certificate's fingerprint? I cant find it on verisign.com... Any links? Thanks!

@danparisi
Copy link

danparisi commented Feb 5, 2021

@unb9rn No I don't, I just followed the guide I linked above. I think it's an old certificate but I didn't find any other solution to let it work

@BishopWolf
Copy link

BishopWolf commented Feb 5, 2021

Nothing is working

POST https://myvpn/global-protect/prelogin.esp?tmp=tmp&clientVer=4100&clientos=Linux
Connected to myvpn:443
SSL negotiation with myvpn
Connected to HTTPS on myvpn with ciphersuite (TLS1.2)-(RSA)-(AES-256-GCM)
Enter login credentials
POST https://myvpn/global-protect/getconfig.esp
Portal set HIP report interval to 60 minutes).
1 gateway servers available:
  GW-*** (myvpn)
Please select GlobalProtect gateway.
GATEWAY: [GW-***]:GW-***
POST https://myvpn/ssl-vpn/login.esp
GlobalProtect login returned authentication-source=Auth_Seq_Standard
GlobalProtect login returned usually-equals-4=4
GlobalProtect login returned usually-equals-unknown=unknown
POST https://myvpn/ssl-vpn/getconfig.esp
Session will expire after 43200 minutes.
Tunnel timeout (rekey interval) is 180 minutes.
Idle timeout is 180 minutes.
No MTU received. Calculated 1422 for ESP tunnel
POST https://myvpn/ssl-vpn/hipreportcheck.esp
/usr/lib/openconnect/csd-wrapper.sh: line 122: /home/nobody/.cisco/hostscan/manifest: No such file or directory
/usr/lib/openconnect/csd-wrapper.sh: line 129: /home/nobody/.cisco/hostscan/bin/cstub: No such file or directory
POST https://myvpn/ssl-vpn/hipreport.esp
Missing or invalid required input parameters
HIP report submission failed.
Creating SSL connection failed

@cer28
Copy link

cer28 commented Feb 8, 2021

Thanks @sharkodlak and @danparisi, this solution also worked for me to get past the unable to get local issuer certificate error validating the signed libcsd.so file. There was no indication what certificate it needed, so this was vital information.

For me on Ubuntu 20.04 it was a slightly different process:

@pablomarti
Copy link

pablomarti commented Mar 6, 2021

Thank you @sharkodlak and @danparisi and also thank you @cer28 for summarizing, it works for me.

@dolfinus
Copy link

dolfinus commented Mar 24, 2021

Thanks @sharkodlak @danparisi @cer28, it works for me too

@janotav
Copy link

janotav commented May 4, 2022

The workaround I used on Ubuntu 22.04:

  1. Build custom docker image based on older Ubuntu where security wasn't that strict, something like
FROM ubuntu:18.04

RUN apt update \
  && apt install -y wget

and build it:

docker build -t unsecuressl:latest .
  1. In the script replace direct wget invocation with one using this image. Instead of
wget --no-check-certificate -c "https://${CSD_HOSTNAME}/CACHE/sdesktop/hostscan/$ARCH/manifest" -O "$HOSTSCAN_DIR/manifest"

do

docker run --rm --entrypoint wget unsecuressl:latest --no-check-certificate -c "https://${CSD_HOSTNAME}/CACHE/sdesktop/hostscan/$ARCH/manifest" -O- > "$HOSTSCAN_DIR/manifest"

Similarly replace other occurrences.

After doing these changes, I was able to connect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment