首页  编辑  

史上最强一键登录Citrix Gateway远程桌面VM【原创】

Tags: /计算机文档/脚本,批处理/   Date Created:

The best tool ever for connect remote VM desktop via Citrix VPN/Gateway by one click 

Cron:
  • No resident app needed, no resource require after connected, no garbage file left(.rdp files)
  • One-Click to connect to remote VM, fast, simple, easy
  • Enable change multi-monitor settings, you can force single monitor or dual monitor for remote desktop
  • Self-signed certification supported
  • Reduce Citrix gateway web portal resource usage
优点:
  • 一键连接Citrix远程桌面
  • 支持自签名证书,见 my.pem,你可以自己转换 Citrix 登录时的证书为 PEM 格式,PFX证书转 PEM 格式,指令如下:
    openssl pkcs12 -in yourfile.pfx -out yourfile.pem -nodes
  • 支持强制多显示器、双显示器支持
  • 没有内存驻留程序,零资源消耗,无垃圾文件(.rdp文件)产生
  • 无需第三方软件支持,只需要Bash支持即可,可以使用git bash或者wsl,也可以使用Mingw等Bash环境
  • 降低Citrix网关的服务器压力
Citrix Gateway远程桌面网关(NetScaler AAA),连接远程虚拟机VM,需要打开网页,登录然后再下载RDP文件,然后打开RDP文件,非常繁琐,并且由于每次都下载RDP文件,导致download目录下积累了大量的.rdp文件,变成垃圾文件,十分恶心。
我们可以使用以下脚本shell(vm.sh,可以用 git bash运行,如果没有自签名证书,请修改opts去掉"--insecure --cert XXXX.pfx:XXXX --cert-type P12",并且git for windows版本应该低于2.33运行,高版本可能出现openssl无法打开证书的问题,或者你使用openssl 3.0以上证书也可以使用新版本),实现一键登录VM(Citrix Gateway 2016):
#!/bin/bash

version=1.2
echo "Citrix Gateway VM 连接工具 v$version"
echo "Copyright© Richard, 2024"
echo "本工具不驻留内存,不消耗任何额外的资源。"

highlight() {
    echo -e "\033[$1m$2\033[0m"
}

uriencode() {
  curl -Gso /dev/null -w %{url_effective} --data-urlencode "data=$1" "0.0.0.0" | cut -d'=' -f2
}

function input() {
	local buf=""
    while true; do
        read -p "$1" $2 buf
        if [ -z "$buf" ]; then
            highlight 41 "输入不能为空,请重新输入。" >&2
        else
            break
        fi
    done
	echo $buf
}

check() {
    if [ $? -ne 0 ]; then
        highlight 41 "失败"
        read -n 1 -s -r -p "按任意键继续..."
        exit 1
    fi
}

if [[ "$1" == "-h" || "$1" == "/?" || "$1" == "--help" ]]; then
    echo "用法:	$0 [-h]"
	echo "例如:"
	echo "	$0	初始化或一键连接"
	echo "	$0 -h	显示帮助"
	echo "初始化只会运行一次,请勿中断初始化过程"
	highlight 41 "若有问题可删除 config.dat, headers.txt 重新初始化"
	echo "可自定义headers.txt,以适配特殊情况"
	exit 0
fi

openssl_version=$(openssl version | awk '{print $2}')
if [[ ! "$openssl_version" < "3.0" ]]; then
	highlight 41 "不支持 Openssl 3.0及以上版本,当前版本 $openssl_version。"echo "请安装 git v2.41.0 及以下版本来运行本脚本"read -n 1 -s -r -p "按任意键继续..."
	exit 1
fi

cd "$(dirname "$(readlink -f "$0")")"
if [ -f config.dat ]; then
    source config.dat
	if [ -z "$version" ] || [ "$(awk 'BEGIN{print ("'$version'" < 1.2) ? "true" : "false" }')" == "true" ]; then
		rm config.dat
	fi
fi

# 初始化或读取配置
if [ -f config.dat ]; then
	# 加载配置
    source config.dat
    salt=$(echo "$salt" | base64 -d)
    password=$(echo "$key" | openssl enc -d -aes-256-cbc -pbkdf2 -base64 -k "$COMPUTERNAME$salt")
else
	highlight 41 "开始初始化配置,若有问题可删除 config.dat 重新初始化"
    read -p "请输入Citrix网关地址(默认: https://www.citrix_gateway.com): " server
	server=${server:-https://www.citrix_gateway.com}
	user=$(input "用户名(corp id): ")
    password=$(input "请输入密码, \字符用\\\\替代: " -s)
	password=$(uriencode "$password")
	echo
    read -p "目标VM IP地址(若有多个VM必输,否则可选): " ip
    read -p "多显示器支持,多个用逗号分隔(例如0,1表示在第1、2个显示器显示,不输表示单显示器模式): " monitors

    salt=$(openssl rand -hex 10)
    key=$(echo "$password" | openssl enc -aes-256-cbc -pbkdf2 -base64 -k "$COMPUTERNAME$salt")
    salt=$(echo -n "$salt" | base64)

	# 保存配置
    echo "server=$server" > config.dat
    echo "user=$user" >> config.dat
    echo "ip=$ip" >> config.dat
    echo "salt=$salt" >> config.dat
    echo "key=$key" >> config.dat
    echo "version=$version" >> config.dat
    echo "monitors=$monitors" >> config.dat
fi

# echo $server - $user - $password - $ip

if [ -f desktop.rdp ]; then
	rm desktop.rdp
fi
if [ ! -f headers.txt ]; then
	cat <<EOF >headers.txt
Accept: application/xml, text/xml, */*; q=0.01
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: no-cache
Connection: keep-alive
Origin: $server
Pragma: no-cache
Referer: $server
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0
X-Citrix-AM-CredentialTypes: none, username, domain, password, newpassword, passcode, savecredentials, textcredential, webview, nsg-epa, nsg-x1, nsg-setclient, nsg-eula, nsg-tlogin, nsg-fullvpn, nsg-hidden, nsg-auth-failure, nsg-auth-success, nsg-epa-success, nsg-l20n, GoBack, nf-recaptcha, ns-dialogue, nf-gw-test, nf-poll, nsg_qrcode, nsg_manageotp, negotiate, nsg_push, nsg_push_otp, nf_sspr_rem
X-Citrix-AM-LabelTypes: none, plain, heading, information, warning, error, confirmation, image, nsg-epa, nsg-epa-failure, nsg-login-label, tlogin-failure-msg, nsg-tlogin-heading, nsg-tlogin-single-res, nsg-tlogin-multi-res, nsg-tlogin, nsg-login-heading, nsg-fullvpn, nsg-l20n, nsg-l20n-error, certauth-failure-msg, dialogue-label, nsg-change-pass-assistive-text, nsg_confirmation, nsg_kba_registration_heading, nsg_email_registration_heading, nsg_kba_validation_question, nsg_sspr_success, nf-manage-otp
X-Citrix-IsUsingHTTPS: Yes
X-Requested-With: XMLHttpRequest
sec-ch-ua: "Microsoft Edge";v="123", "Not:A-Brand";v="8", "Chromium";v="123"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
EOF
fi

opts="-s -H @headers.txt --insecure --cert xxx.pfx:xxx --cert-type P12"
echo 获取鉴权环境...
curl $opts -i -o response.txt -X 'POST' "$server/nf/auth/getAuthenticationRequirements.do"
check
url=$(grep -o '<PostBack>[^<]*</PostBack>' response.txt | sed 's/<\/\?PostBack>//g')
context=$(echo "$url" | sed 's/\/nf\/auth\/doCert\.do?//')
echo url=$url
echo

echo 获取令牌 NSC_TMAS...
curl $opts -i -o response.txt -X 'POST' "$server$url" --data-raw \"$context\"
check
NSC_TMAS=$(grep -o 'NSC_TMAS=[^;]*' response.txt | sed 's/NSC_TMAS=//')
cookie="NSC_TMAS=$NSC_TMAS"
echo $cookie
echo

echo 开始鉴权...
# curl $opts -i -o response.txt -X 'POST' "$server/nf/auth/doAuthentication.do" -b "$cookie" --data-urlencode "login=$user" --data-urlencode "passwd=$password" --data-urlencode "domain=ss_corp" --data-urlencode "loginBtn=Log+On" --data-urlencode "StateContext="
curl $opts -i -o response.txt -X 'POST' "$server/nf/auth/doAuthentication.do" -b "$cookie" --data-raw "login=$user&passwd=$password&domain=ss_corp&loginBtn=Log+On&StateContext="
check
NSC_AAAC=$(grep -o 'NSC_AAAC=[^;]*' response.txt | sed 's/NSC_AAAC=//')
cookie="NSC_SAMS=Strict;NSC_AAAC=$NSC_AAAC"
StateContext=$(grep -o '<StateContext>[^<]*</StateContext>' response.txt | sed 's/<\/\?StateContext>//g')

echo $cookie
echo Context: $StateContext
echo

echo 配置客户端...
curl $opts -i -o response.txt -X 'POST' "$server/p/u/setClient.do" -b "$cookie" --data-raw "nsg-setclient=cvpn&StateContext=$StateContext"
check
NSC_TEMP=$(grep -o 'NSC_TEMP=[^;]*' response.txt | sed 's/NSC_TEMP=//')
cookie="NSC_SAMS=Strict; NSC_AAAC=$NSC_AAAC; NSC_TEMP=$NSC_TEMP"
echo $cookie
echo

echo 获取远程VM地址清单...
curl $opts -i -o response.txt -X 'GET' "$server/cgi/resources/list" -b "$cookie"
content=$(grep -o '"content":"[^"]*"' response.txt | awk -F '"' '{print $4}')
check
echo $content
echo
if [ -z "$ip" ]; then
	rdpUrl="$content"
else
	echo 抽取 $ip 对应的地址...
	rdpUrl=$(echo "$content" | awk -v ip="$ip" '{for(i=1;i<=NF;i++) if($i ~ ip) print $i}')
fi

echo 下载RDP配置文件: $rdpUrl
curl $opts -o desktop.rdp -X 'GET' "$rdpUrl" -b "$cookie"
check

echo 更改为单个桌面连接...
echo >>desktop.rdp
if [ ! -z "$monitors" ]; then
	echo "selectedmonitors:s:$monitors">>desktop.rdp
fi
echo "compression:i:1">>desktop.rdp
echo "username:s:$user">>desktop.rdp
echo "domain:s:corpdev">>desktop.rdp
echo "desktopscalefactor:i:100">>desktop.rdp
sed -i 's/redirectclipboard:i:0/redirectclipboard:i:1/g' desktop.rdp
# sed -i 's/redirectdrives:i:0/redirectdrives:i:1/g' desktop.rdp
if [ -z "$monitors" ]; then
	sed -i 's/use multimon:i:1/use multimon:i:0/g' desktop.rdp
fi
echo 等待远程服务器配置就绪...
highlight 44\;97 "若失败请手动打开 desktop.rdp 或重试..."
highlight 44\;97 "请勿勾选记住密码,因为连接每次都不一样"
sleep 10
echo 启动远程桌面
$SYSTEMROOT\\System32\\cmd.exe //c start mstsc //admin desktop.rdp &
sleep 1
rm response.txt

下载的Citrix Gateway RDP文件示例:
redirectclipboard:i:0
redirectdrives:i:0
redirectprinters:i:0
redirectcomports:i:0
redirectpnpdevices:i:0
keyboardhook:i:2
audiocapturemode:i:0
videoplaybackmode:i:1
use multimon:i:0
negotiate security layer:i:1
enablecredsspsupport:i:1
authentication level:i:0
full address:s:www.citrix_gateway_server.com:443
loadbalanceinfo:s:52bc4a0fb4ed87904d57f6896212fd79a20a1b63c5fa4f73a477d0e339af5ba23c72
运行效果:

错误处理

  • schannel: AcquireCredentialsHandle failed: SEC_E_NO_CREDENTIALS
这是因为git for windows 使用了 openssl 3.x 版本编译导致的,从 git for windows 3.41.0 以上版本开始,用的是 openssl 3.x 编译的,openssl 3.x 很多老的 provider 不提供了,而你提供的证书是老版本(Openssl 1.x编译的),所以一些证书不兼容。请使用 git for windows 3.41.0 及以下版本运行。或者试着用新版本openssl 制作证书。
  • 鉴权失败
如下图:
此时需要核对用户名和密码是否正确,可以删除 config.dat 后重试。密码是网页登录密码,不是包含 $ 的那个密码!!!
  • 多个VM
上图是没有配置好IP导致的,请打开config.dat,配置IP地址即可。
  • 获取VM地址清单失败
这是因为账户属于特殊账户,和普通用户流程不一样,暂时不支持。你可以自己根据实际情况调整脚本代码。

auto_login_requests.py (38.9KB)