Skip to content

Instantly share code, notes, and snippets.

@mschmitt
Created December 21, 2019 23:09
Show Gist options
  • Save mschmitt/c214bfc560881ac3d68c5b11298ba318 to your computer and use it in GitHub Desktop.
Save mschmitt/c214bfc560881ac3d68c5b11298ba318 to your computer and use it in GitHub Desktop.
steam_login.sh - proof of concept for automatically logging in to Steam
#!/bin/bash
# Wrapper for verbose exiting
function errexit(){
echo "Error: $1"
exit 1
}
# Check for availability of external prerequisites
[[ -x "$(command -v curl)" ]] || errexit "curl is required but not installed"
[[ -x "$(command -v jq)" ]] || errexit "jq is required but not installed"
[[ -x "$(command -v openssl)" ]] || errexit "openssl is required but not installed"
# Curl cookie storage
COOKIEJAR=~/.cookiejar.steam
CURL="curl --progress-bar --cookie-jar $COOKIEJAR --cookie $COOKIEJAR"
# Test whether we're already logged in.
# Permalink to own profile found at:
# https://www.reddit.com/r/Steam/comments/30kvjt/link_that_brings_you_to_your_own_profile/
LOCATION=$($CURL -o/dev/null -w '%{redirect_url}' https://steamcommunity.com/my/profile)
# If we get redirected to a login page, we aren't already logged in.
if [[ ! "$LOCATION" =~ steamcommunity.com/login/home/ ]]
then
printf "Already logged in. Profile URL is: %s\n" "$LOCATION"
exit 0
fi
# Clean up all the temp files we're going to create:
function cleanup(){
rm -f "$CURLTMP"
rm -f "$ASN1TMP"
rm -f "$DERTMP"
rm -f "$PEMTMP"
rm -f "$RSATMP"
}
trap cleanup INT QUIT TERM EXIT
CURLTMP="$(mktemp)"
ASN1TMP="$(mktemp)"
DERTMP="$(mktemp)"
PEMTMP="$(mktemp)"
RSATMP="$(mktemp)"
# User and password can be supplied as environment variables
if [[ ! -v STEAMUSER ]]
then
read -p "Steam Username: " STEAMUSER
fi
if [[ ! -v STEAMPASS ]]
then
read -p "Steam Password: " STEAMPASS
fi
# Get the RSA key that will be used to encrypt the password
$CURL 'https://steamcommunity.com/login/getrsakey/' \
--form "username=$STEAMUSER" \
> "$CURLTMP" || errexit 'curl_rsakey'
SUCCESS=$(jq --raw-output '.success' < "$CURLTMP")
if [[ ! "$SUCCESS" == 'true' ]]
then
errexit 'get rsakey'
fi
# Encryption requires modulus and exponent,
# login requires the timestamp that was received.
MOD=$(jq --raw-output '.publickey_mod' < "$CURLTMP")
EXP=$(jq --raw-output '.publickey_exp' < "$CURLTMP")
TIME=$(jq --raw-output '.timestamp' < "$CURLTMP")
# Generate an RSA public key from modulus and exponent
# by providing an ASN1 description file.
# https://stackoverflow.com/a/36448243/263310
cat >>"$ASN1TMP" <<End
# Start with a SEQUENCE
asn1=SEQUENCE:pubkeyinfo
# pubkeyinfo contains an algorithm identifier and the public key wrapped
# in a BIT STRING
[pubkeyinfo]
algorithm=SEQUENCE:rsa_alg
pubkey=BITWRAP,SEQUENCE:rsapubkey
# algorithm ID for RSA is just an OID and a NULL
[rsa_alg]
algorithm=OID:rsaEncryption
parameter=NULL
# Actual public key: modulus and exponent
[rsapubkey]
n=INTEGER:0x$MOD
e=INTEGER:0x$EXP
End
# Generate an actual public key from ASN1, DER only.
openssl asn1parse -genconf "$ASN1TMP" -out "$DERTMP" -noout || errexit 'asnparse'
# Convert to PEM because this is how I roll
openssl rsa -in "$DERTMP" -inform der -pubin -out "$PEMTMP" 2>/dev/null || errexit 'rsa'
# Encrypt the password
echo -n "$STEAMPASS" | openssl rsautl -encrypt -pkcs -inkey "$PEMTMP" -pubin > "$RSATMP" || errexit 'rsautl'
# Encode the encrypted password as b64, remove linebreaks
CRYPTPW=$(openssl base64 < "$RSATMP" | tr -d '\n') || errexit 'base64'
# Log in using user name and password
$CURL 'https://steamcommunity.com/login/dologin/' \
--data-urlencode "username=$STEAMUSER" \
--data-urlencode "password=$CRYPTPW" \
--data-urlencode "twofactorcode=" \
--data-urlencode "rsatimestamp=$TIME" \
--data-urlencode "remember_login=true" > "$CURLTMP" || errexit 'curl_pre_2fa'
# Steam should now return a request for two factor authentication
# We could simply ask the user for 2FA and submit it, but then they
# wouldn't get the popup on their mobile phone.
#
# If Steam asks for a CAPTCHA, you've been recognized
# as being a machine and the world has officially ended.
CAPTCHA=$(jq --raw-output '.captcha_needed' < "$CURLTMP")
REQ2FA=$(jq --raw-output '.requires_twofactor' < "$CURLTMP")
if [[ "$CAPTCHA" == 'true' ]]
then
errexit 'response_steam_wants_captcha'
fi
if [[ ! "$REQ2FA" == 'true' ]]
then
errexit 'response_pre_2fa'
fi
# Ask for 2FA token and resubmit same request as above.
read -p "Steam 2-factor token: " STEAM2FATOKEN
$CURL 'https://steamcommunity.com/login/dologin/' \
--data-urlencode "username=$STEAMUSER" \
--data-urlencode "password=$CRYPTPW" \
--data-urlencode "twofactorcode=$STEAM2FATOKEN" \
--data-urlencode "rsatimestamp=$TIME" \
--data-urlencode "remember_login=true" > "$CURLTMP" || errexit 'curl_post_2fa'
# Final check for completed login.
LOGIN=$(jq --raw-output '.login_complete' < "$CURLTMP")
if [[ "$LOGIN" == 'true' ]]
then
echo "Login succeeded."
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment