Homebrew, open source, repurposed, hacked, software defined, open hardware

Monday 13 October 2014

Citrix Access Gateway 2010 phoenix BIOS and lubuntu linux installation

Hmm, an unloved, discarded, Citrix Access Gateway. IEC power socket and a USB socket at the back, as well as two ethernet ports, and a DB9 serial port at the front. Are those mini DIN keyboard and mouse sockets hiding behind the front panel?
I wonder if we can repurpose this as a rack mounted linux box? 


 Inspection of the back panel confirms it is a Citrix Access Gateway (CAG) model 2010


Time to void the warranty...


It's got a super server motherboard, 80 GB HDD, P4 pentium processor, a PCI card riser and 2x512MB = 1GB RAM on board, and it seems we don't need to do a headless server installation of linux, since it has a VGA port and a few more USB ports available.


The server booted off a lubuntu 14.04 USB installer without complaint. Luckily the BIOS did not need to be told to boot off the USB stick ahead of the HDD.


The installation went smoothly, and sucked down the additional packages over ethernet. sshd was also installed to allow access over the local network.
 

The box didn't want to power down fully, or quieten the cooling fans, which were running at full speed. The BIOS was locked down with a password, so hitting Delete on booting wasn't helpful.

Attempts to short the JBT1 pads with the power disconnected and leaving the lithium cell CMOS battery out overnight did not get rid of the BIOS password.

The python script listed below for Phoenix BIOS password checksums was found and successfully used to brute force the Citrix Access Gateway BIOS password checksum [06626].

The BIOS password error checksum was: [06626]
The Citrix Access Gateway 2010 BIOS password was found to be: bfsyxxm

The Citrix Access Gateway 2010 model uses a generic pheonix BIOS checksum, it seems.

Entering the BIOS password allowed the BIOS password to be changed to something easier to remember, and the "always power on", and "full speed" fan settings were able to be changed, to make the unit quieter and able to power down properly.

Here's the python script used to brute force the BIOS password:
#!/usr/bin/python

# Copyright 2009:  dogbert <dogber1@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#

# This script generates master passwords which can be used to unlock the BIOS
# password of most Phoenix BIOS versions. It also works for some versions of
# FSI, HP and Compaq laptops which use slightly different hashing algorithms
# in the BIOS.
# You have to install python 2.x for running this script.

import os, random

keyboardDict = {  2: '1',  3: '2',  4: '3',  5: '4',  6: '5',  7: '6',  8: '7',  9: '8', 10: '9', 11: '0',
                 16: 'q', 17: 'w', 18: 'e', 19: 'r', 20: 't', 21: 'y', 22: 'u', 23: 'i', 24: 'o', 25: 'p',
                 30: 'a', 31: 's', 32: 'd', 33: 'f', 34: 'g', 35: 'h', 36: 'j', 37: 'k', 38: 'l',
                 44: 'z', 45: 'x', 46: 'c', 47: 'v', 48: 'b', 49: 'n', 50: 'm' }

def keyboardEncToAscii(inKey):
    out = ""
    for c in inKey:
        if c != 0: out += keyboardDict[c]
    return out

def asciiToKeyboardenc(inAscii):
    out = []
    asciiDict = dict([(a,k) for k,a in keyboardDict.iteritems()])
    for c in inAscii:
        if c != 0: out.append(asciiDict[c])
    return out


# The phoenix implementation of the CRC-16 contains a rather severe bug
# quartering the image space of the function: both the first and second MSB
# are always zero regardless of the input.
# For a working implementation, you'd have to change the polynom from 0x2001
# to e.g. 0xA001.
def badCRC16(pwd, salt=0):
    hash = salt
    for c in pwd:
        hash ^= c
        for i in range(0,8):
            if (hash & 1):
                hash = (hash >> 1) ^ 0x2001
            else:
                hash = (hash >> 1)
    return hash


def bruteForce(hash, salt=0, digitsOnly=False, charsOnly=True, minLen=3, maxLen=8):
    global keyboardDict
    keyboardDictOrig = keyboardDict
    if digitsOnly:
        keyboardDict = dict(zip(list(keyboardDict.keys())[0:9],list(keyboardDict.values())[0:9]))
    elif charsOnly:
        keyboardDict = dict(zip(list(keyboardDict.keys())[10:36],list(keyboardDict.values())[10:36]))

    encodedPwd = []
    for i in range(0, 7):
        encodedPwd.append(list(keyboardDict.keys())[0])
    random.seed()
    if hash > 0x3FFF:
        return "invalid hash code"
    while 1:
        # generate random password
        rndVal = random.random()*len(keyboardDict)
        for i in range(0,len(encodedPwd)):
            value = int(rndVal % len(keyboardDict))
            encodedPwd[i] = list(keyboardDict.keys())[value]
            rndVal = rndVal * len(keyboardDict)
        # test substrings of the random password
        for i in range(minLen, maxLen+1):
            if badCRC16(encodedPwd[0:i], salt) == hash:
                keyboardDict = keyboardDictOrig
                encodedPwd = encodedPwd[0:i]
                return keyboardEncToAscii(encodedPwd[0:i])



print("Master Password Generator for Phoenix BIOS (five decimal digits version)")
print("Copyright (C) 2009 dogbert <dogber1@gmail.com>")
print("")
print("After entering the wrong password for the third time, you will receive a")
print("decimal number from which the master password can be calculated,")
print("e.g. 12345")
print("")
print("Please enter the number: ")
code = raw_input().replace('[', '').replace(']', '')
hash = int(code)
print("")
print("Brute forcing passwords...")
print("Generic Phoenix BIOS:          " + bruteForce(hash, 0))
print("HP/Compaq Phoenix BIOS:        " + bruteForce(hash, salt=17232))
print("FSI Phoenix BIOS (generic):    " + bruteForce(hash, salt=65, minLen=3, maxLen=7,digitsOnly=True))
print("FSI Phoenix BIOS ('L' model):  " + bruteForce(hash+1, salt=ord('L'), minLen=3, maxLen=7,digitsOnly=True))
print("FSI Phoenix BIOS ('P' model):  " + bruteForce(hash+1, salt=ord('P'), minLen=3, maxLen=7,digitsOnly=True))
print("FSI Phoenix BIOS ('S' model):  " + bruteForce(hash+1, salt=ord('S'), minLen=3, maxLen=7,digitsOnly=True))
print("FSI Phoenix BIOS ('X' model):  " + bruteForce(hash+1, salt=ord('X'), minLen=3, maxLen=7,digitsOnly=True))
print("")
print("done.")
print("")
print("Please note that the password has been encoded for the standard US")
print("keyboard layout (QWERTY).")
if (os.name == 'nt'):
    print("Press a key to exit...")
    raw_input()