csd-post.sh 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #!/bin/bash
  2. # Cisco Anyconnect CSD wrapper for OpenConnect
  3. #
  4. # Instead of actually downloading and spawning the hostscan trojan,
  5. # this script posts results directly. Ideally we would work out how to
  6. # interpret the DES-encrypted (yay Cisco!) tables.dat and basically
  7. # reimplement the necessary parts hostscan itself. But prepackaged
  8. # answers, tuned to match what the VPN server currently wants to see,
  9. # will work for most people. Of course it's perfectly possible to make
  10. # this tell the truth and not just give prepackaged answers, and most
  11. # people should do that rather than deliberately circumventing their
  12. # server's security policy with lies. This script exists as an example
  13. # to work from.
  14. if ! xmlstarlet --version > /dev/null 2>&1; then
  15. echo "************************************************************************" >&2
  16. echo "WARNING: xmlstarlet not found in path; CSD token extraction may not work" >&2
  17. echo "************************************************************************" >&2
  18. unset XMLSTARLET
  19. else
  20. XMLSTARLET=true
  21. fi
  22. # cURL 7.39 (https://bugzilla.redhat.com/show_bug.cgi?id=1195771)
  23. # is required to support pin-based certificate validation. Must set this
  24. # to false if using an older version of cURL.
  25. INSECURE=false
  26. if [[ "$INSECURE" == "true" ]]; then
  27. echo "*********************************************************************" >&2
  28. echo "WARNING: running insecurely; will not validate CSD server certificate" >&2
  29. echo "*********************************************************************" >&2
  30. fi
  31. export RESPONSE=$(mktemp /tmp/csdresponseXXXXXXX)
  32. export RESULT=$(mktemp /tmp/csdresultXXXXXXX)
  33. trap 'rm $RESPONSE $RESULT' EXIT
  34. cat >> $RESPONSE <<EOF
  35. endpoint.os.version="$(uname -s)";
  36. endpoint.os.servicepack="$(uname -r)";
  37. endpoint.os.architecture="$(uname -m)";
  38. endpoint.policy.location="Default";
  39. endpoint.device.protection="none";
  40. endpoint.device.protection_version="3.1.03103";
  41. endpoint.device.hostname="$(hostname)";
  42. endpoint.device.port["9217"]="true";
  43. endpoint.device.port["139"]="true";
  44. endpoint.device.port["53"]="true";
  45. endpoint.device.port["22"]="true";
  46. endpoint.device.port["631"]="true";
  47. endpoint.device.port["445"]="true";
  48. endpoint.device.port["9216"]="true";
  49. endpoint.device.tcp4port["9217"]="true";
  50. endpoint.device.tcp4port["139"]="true";
  51. endpoint.device.tcp4port["53"]="true";
  52. endpoint.device.tcp4port["22"]="true";
  53. endpoint.device.tcp4port["631"]="true";
  54. endpoint.device.tcp4port["445"]="true";
  55. endpoint.device.tcp4port["9216"]="true";
  56. endpoint.device.tcp6port["139"]="true";
  57. endpoint.device.tcp6port["53"]="true";
  58. endpoint.device.tcp6port["22"]="true";
  59. endpoint.device.tcp6port["631"]="true";
  60. endpoint.device.tcp6port["445"]="true";
  61. endpoint.device.MAC["FFFF.FFFF.FFFF"]="true";
  62. endpoint.device.protection_extension="3.6.4900.2";
  63. endpoint.fw["IPTablesFW"]={};
  64. endpoint.fw["IPTablesFW"].exists="true";
  65. endpoint.fw["IPTablesFW"].description="IPTables (Linux)";
  66. endpoint.fw["IPTablesFW"].version="1.6.1";
  67. endpoint.fw["IPTablesFW"].enabled="ok";
  68. EOF
  69. shift
  70. TICKET=
  71. STUB=0
  72. while [ "$1" ]; do
  73. if [ "$1" == "-ticket" ]; then shift; TICKET=${1//\"/}; fi
  74. if [ "$1" == "-stub" ]; then shift; STUB=${1//\"/}; fi
  75. shift
  76. done
  77. if [[ "$INSECURE" == "true" ]]; then
  78. # Don't validate server certificate at all
  79. PINNEDPUBKEY="-k"
  80. else
  81. # Validate certificate using pin-sha256 value in CSD_SHA256, or fallback to
  82. # cURL's default certificate validation if not set.
  83. PINNEDPUBKEY="${CSD_SHA256:+"-k --pinnedpubkey sha256//$CSD_SHA256"}"
  84. fi
  85. URL="https://$CSD_HOSTNAME/+CSCOE+/sdesktop/token.xml?ticket=$TICKET&stub=$STUB"
  86. if [ -n "$XMLSTARLET" ]; then
  87. TOKEN=$(curl $PINNEDPUBKEY -s "$URL" | xmlstarlet sel -t -v /hostscan/token)
  88. else
  89. TOKEN=$(curl $PINNEDPUBKEY -s "$URL" | sed -n '/<token>/s^.*<token>\(.*\)</token>^\1^p' )
  90. fi
  91. if [ -n "$XMLSTARLET" ]; then
  92. URL="https://$CSD_HOSTNAME/CACHE/sdesktop/data.xml"
  93. curl $PINNEDPUBKEY -s "$URL" | xmlstarlet sel -t -v '/data/hostscan/field/@value' | while read -r ENTRY; do
  94. # XX: How are ' and , characters escaped in this?
  95. TYPE="$(sed "s/^'\(.*\)','\(.*\)','\(.*\)'$/\1/" <<< "$ENTRY")"
  96. NAME="$(sed "s/^'\(.*\)','\(.*\)','\(.*\)'$/\2/" <<< "$ENTRY")"
  97. VALUE="$(sed "s/^'\(.*\)','\(.*\)','\(.*\)'$/\3/" <<< "$ENTRY")"
  98. if [ "$TYPE" != "$ENTRY" ]; then
  99. case "$TYPE" in
  100. File)
  101. BASENAME="$(basename "$VALUE")"
  102. cat >> $RESPONSE <<EOF
  103. endpoint.file["$NAME"]={};
  104. endpoint.file["$NAME"].path="$VALUE";
  105. endpoint.file["$NAME"].name="$BASENAME";
  106. EOF
  107. TS=$(stat -c %Y "$VALUE" 2>/dev/null)
  108. if [ "$TS" = "" ]; then
  109. cat >> $RESPONSE <<EOF
  110. endpoint.file["$NAME"].exists="false";
  111. EOF
  112. else
  113. LASTMOD=$(( $(date +%s) - $TS ))
  114. cat >> $RESPONSE <<EOF
  115. endpoint.file["$NAME"].exists="true";
  116. endpoint.file["$NAME"].lastmodified="$LASTMOD";
  117. endpoint.file["$NAME"].timestamp="$TS";
  118. EOF
  119. CRC32=$(crc32 "$VALUE")
  120. if [ "$CRC32" != "" ]; then
  121. cat >> $RESPONSE <<EOF
  122. endpoint.file["$NAME"].crc32="0x$CRC32";
  123. EOF
  124. fi
  125. fi
  126. ;;
  127. Process)
  128. if pidof "$VALUE" &> /dev/null; then
  129. EXISTS=true
  130. else
  131. EXISTS=false
  132. fi
  133. cat >> $RESPONSE <<EOF
  134. endpoint.process["$NAME"]={};
  135. endpoint.process["$NAME"].name="$VALUE";
  136. endpoint.process["$NAME"].exists="$EXISTS";
  137. EOF
  138. ## XX: Add '.path' if it's running?
  139. ;;
  140. Registry)
  141. # We silently ignore registry entry requests
  142. ;;
  143. *)
  144. echo "Unhandled hostscan element of type '$TYPE': '$NAME'/'$VALUE'"
  145. ;;
  146. esac
  147. else
  148. echo "Unhandled hostscan field '$ENTRY'"
  149. fi
  150. done
  151. fi
  152. COOKIE_HEADER="Cookie: sdesktop=$TOKEN"
  153. CONTENT_HEADER="Content-Type: text/xml"
  154. URL="https://$CSD_HOSTNAME/+CSCOE+/sdesktop/scan.xml?reusebrowser=1"
  155. curl $PINNEDPUBKEY -s -H "$CONTENT_HEADER" -H "$COOKIE_HEADER" -H 'Expect: ' --data-binary @$RESPONSE "$URL" > $RESULT
  156. cat $RESULT || :
  157. exit 0