Lots of RDP

xrayspx's picture
Music: 

Annie Lennox - Why?

Do you do lots of RDP? Like lots and lots? I do, and even with password management it's annoying. I tend to use generated passwords for all my normal user, Domain Admin user and obviously Administrator accounts. That means lots of workarounds to deal with those passwords while doing bulk RDP sessions.

A typical use case for me is to RDP to 20 machines at a time, run a thing, wait, and log out. I've always scripted this, but not always in strictly the safest way. Plaintext passwords stored in a script, or read off disk. The philosophy is "if someone can read this script, I've already lost the game anyway", but still it's ugly and sick, and so I fixed it. In my defense, the Red Team never did pop my laptop...

I already use gpg-agent to facilitate unpacking of log files. On my syslog servers I roll logs over hourly, gzip them and then gpg encrypt them to my key. Then I can download a bunch of them, run my logunpack script, enter my passphrase once and since gpg-agent caches that credential for a period of time, decrypt all my files in one go.

What I wanted here was basically a way to have keepassxc.cli "hold the door open" and cache the passphrase like gpg-agent does. So what I've done is to use gpg-agent itself for that purpose. I have a GPG encrypted file containing my KeePass-XC passphrase, and I open it using gpg-agent, so it can be reused until gpg-cache-ttl expires.

I've also always had slightly different copies of this script for use cases of "Fullscreen on my laptop" and "fullscreen on larger displays", so I have a switch here for "resolution" as well. "fs" for fullscreen or "fsbm" for "big monitors". Since I'll never go to my office again, that's pretty much never going to get used. The default for the $res value will remain 1280x960. Reasonable enough.

I also added prompts so that it'll ask for host, domain, user and password if you run the script with no prompts from a shell. So /that/ will be super useful to me when I have to do a one-off connection to some remote host but don't need a whole launcher for it. While I'm at it, I put in the -b switch so that you can have it generate a launcher based on that input. That saves me hand editing a template when I add a new RDP host.

I use Linux, but this should work with minimal-if-any changes on Mac and Windows/Cygwin, both of which can run xfreerdp and gpg-agent. I have a good automated ssh-tunneled RDP setup for my Mac, so I might try using that with this so I can use a 4k display for those "busy RDP days".

Being that I do run Linux, here's how I launch this. KDE desktop files like this:


xrayspx@dummyhost:~/rdps$ cat windowsmachine
#!/usr/bin/env xdg-open
[Desktop Entry]
Comment[en_US]=
Comment=
Exec=/home/xrayspx/bin/rdplauncher.sh -h windowsmachine -d domain -u xrayspx
GenericName[en_US]=
GenericName=windowsmachine
Icon=remmina
MimeType=
Name[en_US]=
Name=windowsmachine
Path=
StartupNotify=true
Terminal=false
TerminalOptions=
Type=Application
X-DBUS-ServiceName=windowsmachine
X-DBUS-StartupType=
X-KDE-SubstituteUID=false
X-KDE-Username=

So anyway, here's the thing - Oh good, the code tag doesn't work anymore and so all my whitespace is gone. Ah well fuck it I'll fix it with &nbsp like a fucking old man:

--------------------------------------------

#! /bin/bash

# For that logfile debugging #
#stamp=$(date +%Y%m%d-%H%M)
#logfile="/home/xrayspx/bin/rdp-$stamp"

while getopts ":h:d:u:p:r:b" options
do
    case "${options}" in
    b) build="1";;
    h) host=${OPTARG};;
    d) domain=${OPTARG};;
    u) user=${OPTARG};;
    p) pval="$OPTARG";;
    r) rval="$OPTARG";;
    ?) printf "Usage %s: [-b build new launcher] [-h hostname] [-d domain] [-u user] [-p password id (id of password in gpg file)] [-r resolution (fs, fs-bigmon)] args\n" $0
       exit 2;;
    esac
done

#Lowercase usernames for later matching, set width x height which I may make variable someday.
user=$(echo $user | tr '[:upper:]' '[:lower:]')
width="1280"
height="960"

#For use as a command-line client for one-off RDP sessions
if [ -z $host ]
  then
  read -p "Hostname:" host
  read -p "Username:" user
  read -s -p "Password:" pass
  echo ""
  read -p "Domain:" domain

  if [ "$build" = "1" ]
    then
    cp /home/xrayspx/rdps/rdp.template /home/xrayspx/rdps/$host
    sed -i 's/host.template/$host/g' /home/xrayspx/rdps/$host
    sed -i 's/user.template/$user/g' /home/xrayspx/rdps/$host
    sed -i 's/domain.template/$domain/g' /home/xrayspx/rdps/$host
  fi
fi

if [ -z "$pass" ]
  then

  kpass=$(GPG_AGENT_INFO="" gpg -q -d ~/bin/kp.gpg)

  if [ $domain = "domain1" ]
    then

    if [ -z "$user" ]
      then
      user="xrayspx"
      kpentry="domain1-user"
    fi
    if [ "$user" = "xrayspx" ]
      then
      kpentry="domain1-user"
    fi
    if [ "$user" = "administrator" ]
      then
      kpentry="domain1-admin"
    fi
  fi

  if [ $domain = "domain2" ]
    then
      if [ -z "$user" ]
        then
        user="xrayspx-domainadmin"
        kpentry="domain2-domainadmin"
      fi
      if [ "$user" = "xrayspx-domainadmin" ]
        then
        kpentry="domain2-domainadmin"
      fi
      if [ "$user" = "administrator" ]
        then
        kpentry="domain2-admin"
      fi
      if [ "$user" = "xrayspx" ]
        then
        kpentry="work"
      fi
  fi

  if [ $domain = "local" ]
    then
      if [ "$user" = "administrator" ]
        then
        kpentry="domain1-localadmin"
      fi
  fi
pass=$(echo "$kpass" | keepassxc.cli  show -s ~/Nextcloud/kees/keep.kdbx $kpentry | grep "Password:" | awk -F "Password: " '{print $2}')
fi

if [ "$rval" = "fs" ]
  then
  cmd="xfreerdp +clipboard +compression /cert-ignore /w:$width /h:$height /bpp:16 /v:$host /u:$user /d:$domain /p:$pass /f /floatbar"
else cmd="xfreerdp +clipboard +compression /cert-ignore /w:$width /h:$height /bpp:16 /v:$host /u:$user /d:$domain /p:$pass"
fi
#echo $cmd >> $logfile

$($cmd) &

--------------------------------------------