Skip to content

Instantly share code, notes, and snippets.

@p120ph37
Created January 2, 2014 01:34
Show Gist options
  • Save p120ph37/8213727 to your computer and use it in GitHub Desktop.
Save p120ph37/8213727 to your computer and use it in GitHub Desktop.
Command-line implementation of Symantec's "VIP Access" token application on OSX. This will read from the same secret key and produce the same time-based one-time-passwords as the GUI application, but with output that can be captured and used in scripts. This can be useful for things like automating two-factor AnyConnect VPN logins through openco…
#!/usr/bin/expect -f
#
# VIPAccess.exp
#
# Command-line emulation of Symantec's VIP Access software token.
# Usage:
# ./VIPAccess.exp [v]
# If the "v" argument (or any argument) is specified, verbose output
# will be produced on stderr. The OTP value will be output on stdout.
#
set timeout 10
log_user 0
set aes_key D0D0D0E0D0D0DFDFDF2C34323937D7AE
set keychain /Users/$env(USER)/Library/Keychains/VIPAccess.keychain
proc vlog { s } { if $::argc { puts stderr $s } }
vlog "Finding machine serial number (used by VIPAccess to secure the keychain.):"
spawn /bin/sh -c "ioreg -rac IOPlatformExpertDevice | xpath 'plist/array/dict/key\[.=\"IOPlatformSerialNumber\"\]/following-sibling::*\[position()=1\]/text()' 2>/dev/null"
expect eof
set serial $expect_out(buffer)
vlog " $serial"
vlog "Reading encrypted Credential ID and OTP secret key from $keychain:"
spawn security unlock-keychain $keychain
expect "password to unlock $keychain: "
send "${serial}SymantecVIPAccess$env(USER)\n"
expect eof
spawn security find-generic-password -gl CredentialStore $keychain
expect -re \"acct\"<blob>=\"\(\[a-zA-Z0-9/+\]+=\)\"
set id_crypt $expect_out(1,string)
vlog " $id_crypt"
expect -re password:\ \"\(\[a-zA-Z0-9/+\]+=\)\"
set key_crypt $expect_out(1,string)
vlog " $key_crypt"
vlog "Decrypting Credential ID and OTP key:"
spawn /bin/sh -c "openssl enc -aes-128-cbc -d -K $aes_key -iv 0 -a <<< '$id_crypt'"
expect -re \(.*\)Symantec
set id_plain $expect_out(1,string)
vlog " $id_plain"
spawn /bin/sh -c "openssl enc -aes-128-cbc -d -K $aes_key -iv 0 -a <<< '$key_crypt' | xxd -p"
expect -re \[0-9a-f\]+
set key_plain $expect_out(0,string)
vlog " $key_plain"
vlog "Generating current OTP using secret key."
spawn oathtool --totp $key_plain
expect -re \\d+
set otp $expect_out(0,string)
puts $otp
@p120ph37
Copy link
Author

p120ph37 commented Mar 15, 2021

@aselvan, your issue isn't that the password is wrong, it's that since OSX 10.12, there is an additional layer of access-control on keychains, in addition to the unlock mechanism. The first time this script tries to access your VIPAccess.keychain, OSX will pop up a prompt window asking (again) for the keychain password. If you paste the password there, and hit "Always Allow", that prompt will not reappear on subsequent runs of this script. (note: the same applies to the shell variant of this script that @ykhemani created).

You can echo the password to your terminal with this command if you like (for easy copy+paste into that popup dialog):

serial=$(ioreg -rac IOPlatformExpertDevice | xpath 'plist/array/dict/key[.="IOPlatformSerialNumber"]/following-sibling::*[position()=1]/text()' 2>/dev/null)
echo ${serial}SymantecVIPAccess${USER}

You can read a little bit about this additional authorization mechanism here: https://mostlikelee.com/blog-1/2017/9/16/scripting-the-macos-keychain-partition-ids

After reading the above article, you might think you can apply the "Always Allow" action directly from the terminal by doing this (but it won't work):

keychain=/Users/${USER}/Library/Keychains/VIPAccess.keychain
security set-generic-password-partition-list -S teamid:9PTGMPNXZ2,apple-tool: -k "${serial}SymantecVIPAccess${USER}" $keychain

It won't work because OSX now checks not only the partition-id but also the application-name of the accessing application, and there is currently no security subcommand to add application authorizations to an existing keychain entry. So long story short, the simplest way to do this is to just paste the password into the popup and hit "Always Allow". Or use @cyrozap's Python app instead of the Symantec app entirely: https://github.com/cyrozap/python-vipaccess

@aselvan
Copy link

aselvan commented Mar 16, 2021

@p120ph37,
Update: Please ignore my response earlier on password not working. I missed reading your note about the second time prompt. I got past that step and retrieved the secret key which is really what I am after. I have written a script that I use which is a wrapper on top of oathtool for all my other 2F needs so all I needed was the SymantecVIP secret key to generate TOTP. I am good now, thanks again.

@Mike-c-Jackson
Copy link

Mike-c-Jackson commented Mar 1, 2024

In using the serial extraction in the original script (uncommented line in below code excerpt), I get no value returned.

Finding machine serial number (used by VIPAccess to secure the keychain.):
serial    
Reading encrypted Credential ID and OTP secret key from...VIPAccess.keychain:

When using the different option mentioned by @p120ph37 (first commented line in below code excerpt) I get the serial, but with quotes and a carriage return

Finding machine serial number (used by VIPAccess to secure the keychain.):
serial     "NKXXW9F0J0"

Reading encrypted Credential ID and OTP secret key from ...VIPAccess.keychain:

I found the following code (second commented line in below code excerpt) that gives me just the serial, but it still contains the carriage return, so when it creates the password to unlock the keychain, the result shows with the carriage return so it always fail

Finding machine serial number (used by VIPAccess to secure the keychain.):
serial    NKXXW9F0J0

Reading encrypted Credential ID and OTP secret key from ...VIPAccess.keychain:
NKXXW9F0J0
SymantecVIPAccess...

Code options used:

spawn /bin/sh -c "ioreg -rac IOPlatformExpertDevice | xpath 'plist/array/dict/key\[.=\"IOPlatformSerialNumber\"\]/following-sibling::*\[position()=1\]/text()' 2>/dev/null"
# spawn /bin/sh -c "ioreg -rd1 -c IOPlatformExpertDevice | grep 'IOPlatformSerialNumber' | cut -f2- -d'=' | cut -f1 -d','"
# spawn /bin/sh -c "ioreg -l | grep IOPlatformSerialNumber | cut -c 37-46"
expect eof
set serial $expect_out(buffer)
vlog "serial    $serial"

Any thoughts on how to remove the carriage return?

@aselvan
Copy link

aselvan commented Mar 1, 2024

@Mike-c-Jackson
I wrote a wrapper script based on the code presented here couple of years back. The script still works fine (I just tried on my iMac/intel and macbook/m2) with the latest macOS version. You can give it a try and see if you can get past your issue. It is at the link below.

https://github.com/aselvan/scripts/blob/master/security/symantec_vipaccess_key.sh

@Lukasavicus
Copy link

Please advice for someone new to that:

I currently have VIP installed in desktop and I'm trying to make an automatic way to get the token (which is changed in 30 seconds) for some automation.

I don't have a VIPAccess.keychain file, I only have VIPAccess.keychain-db (I don't know if it the same the script is trying to use).
And every time I run the script this Keychain application is prompting me to input a password that I don't know what it is (it's not my macbook password at least).

@mrg50
Copy link

mrg50 commented Dec 6, 2024

I also have the file VIPAccess.keychain-db instead of VIPAccess.keychain. I installed Saymantec VIP on Dec6.

@aselvan
Copy link

aselvan commented Dec 6, 2024

I also have the file VIPAccess.keychain-db instead of VIPAccess.keychain. I installed Saymantec VIP on Dec6.

My script was almost 4 years old. It looks like the name of the keychain file has changed in the meantime. I updated the script and tested it as well. Amazingly, it still works. Enjoy!

@aselvan
Copy link

aselvan commented Dec 6, 2024

Please advice for someone new to that:

I currently have VIP installed in desktop and I'm trying to make an automatic way to get the token (which is changed in 30 seconds) for some automation.

I don't have a VIPAccess.keychain file, I only have VIPAccess.keychain-db (I don't know if it the same the script is trying to use). And every time I run the script this Keychain application is prompting me to input a password that I don't know what it is (it's not my macbook password at least).

My script was almost 4 years old. It looks like the name of the keychain file has changed in the meantime. I updated the script and tested it as well. Amazingly, it still works. Enjoy!

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