2010-10-15

Creating a Hashed Password for VNC

For an automated installation project at work I needed to set the password to an UltraVNC server running on Windows.  VNC is a remote desktop protocol and very handy.  For good reason the server's password is not stored in the clear, but rather a (now weakly) encrypted version.

Unfortunately, while the admin GUI of the program will gladly create the result for you and save it to the ultravnc.ini file or registry, what if you need to do it without human intervention?  Even trained chimps are expensive these days and tend to throw crap around when bored.  No one will be around to bring up the window and type it in by hand.

It's a shame to waste time on such a thing because the program really should support it at the command line.  After a few hours of googling, combing forums and source code for answers, I gave up and hacked together something myself.   Instead I used Python to create the "cypher text", which can then be saved to the .ini file or to the Windows registry in whatever manner is easiest.  Since you can choose where to put it, supporting other VNC products is possible too.

I'll squeeze the good parts in here.

Steps:
  1. Install a modern Python 2.x if you don't have it.
  2. Download this module that handles the nuts and bolts of the encryption algorithm: d3des.py
  3. Copy the code below to a file named something like "vnc_enc.py" and save to the same folder:
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    import d3des as d # for brevity - narrow column
    
    def get_vnc_enc(password):
        passpadd = (password + '\x00'*8)[:8]
        strkey = ''.join([ chr(x) for x in d.vnckey ])
        ekey = d.deskey(strkey, False)
    
        ctext = d.desfunc(passpadd, ekey)
        return ctext.encode('hex')
        
    if __name__ == '__main__':
        import sys
        if len(sys.argv) > 1:
            print get_vnc_enc(sys.argv[1])
        else:
            print 'usage: %s <password>' % sys.argv[0]
    
  4. To print the result to the console:
    C:\> vnc_enc.py foo  
    2a4180b2e31f5790
    
  5. Here's a batch file to take a password and write it to the UltraVNC registry area.  This is what I needed for work.  It could be saved to the registry directly with Python, but I've opted to keep these parts of the program separate.  Name it pass2reg.cmd or similar:
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    @echo off
    setlocal
    if "%1" == "" (
        echo usage: %0 ^<password^>
        exit /b
    )
    set regkey=HKLM\SOFTWARE\ORL\WinVNC3\Default
    set valname=Password
    
    rem clumsy cmd way to set value to env var
    for /f "delims=" %%H in ('vnc_enc.py %1') do set ctxt=%%H
    
    echo VNC Text is: %ctxt%
    echo Writing to: %regkey%\%valname%
    reg add %regkey% /v %valname% /t reg_binary /f /d %ctxt%
    echo Writing to: %regkey%\%valname%2
    reg add %regkey%  /v %valname%2 /t reg_binary /f /d %ctxt%
    
  6. If you need to write the result to an ini file instead, try Python's ConfigParser module.  It is easy to use.

That's it.  Python saves the day again.  I'm sure a few minutes from now I'll find someone already solved it.  Happy weekend!


7 comments:

  1. Great work. I used your pl script to work out the hash then I had to deploy this new password to hundreds of machines on my network. To do this I used a simple logon script and the reg import command to import the new registry. Thanks.

    ReplyDelete
  2. This is great! Thanks for the d3des function. I had been trying to figure out how vncpasswd creates the obfuscated password file. They're definitely not using a hash, instead it is a modified DES encryption with a hardcoded key {23,82,107,6,35,78,88,7}

    It appears that this is why the perl script at the following link did not work: http://aarontwc.blogspot.com/2008/11/perl-script-for-vncpasswd.html

    ReplyDelete
  3. Thank you so much! This worked perfectly on my linux box, and let me update the password in my VNC configs at the office.

    ReplyDelete
  4. Thanks for sharing this! Just tried it out and noticed it didn't work for password longer than 8 char out of the box (the fact it hasn't been brought up before means everyone is using password less than 8 chars long!?). Compared to the hash generated by real vnc, realized they are choping the pass into 8 char segments, and process one part at the time, then recombined. Nothing we can't fix with a bit of recursion:)

    def get_vnc_enc(password):
    if (len(password)>8):
    return get_vnc_enc(password[:8]) + get_vnc_enc(password[8:])
    else:
    passpadd = (password + '\x00'*8)[:8]
    strkey = ''.join([ chr(x) for x in d.vnckey ])
    ekey = d.deskey(strkey, False)
    ctext = d.desfunc(passpadd, ekey)
    return ctext.encode('hex')

    ReplyDelete
  5. I really wanted to try this but...
    d3des.py download link is broken
    Can you please fix it?

    ReplyDelete
    Replies
    1. https://www.apt-browse.org/browse/ubuntu/trusty/universe/all/mythbuntu-common/0.72/file/usr/lib/python3/dist-packages/mythbuntu_common/d3des.py

      Delete