Tuesday, March 27, 2012

Checking client-side certificate verification with openssl

So you have some client software that claims it checks server SSL certs are issued by a valid CA, or better, by a specific CA? How do you check its claims? Set up a simple MITM attack (works for OS X and linux):

Create a self-signed cert:
openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout cert.pem
Fire up the openssl server (man s_server for more options, including simple webserver functionality):
sudo openssl s_server -debug -cert cert.pem -accept 443
Edit your /etc/hosts file and add the domain you are attacking to resolve to localhost:
127.0.0.1 secure.company.com
Run your client.

Tuesday, March 13, 2012

ComputerName vs. LocalHostName vs. HostName on OS X

Hostnames on OS X are...complicated. Using scutil is probably the easiest way to get at them, although there are others. It looks like scutil just parses this plist:

/Library/Preferences/SystemConfiguration/preferences.plist

Note: If you want to get/set these values without shelling out to scutil, check out SCPreferencesPathGetValue and SCPreferencesPathSetValue part of the SystemConfiguration Framework called from python like this.

ComputerName


This is the computer name visible in the GUI in Preferences | Sharing | Computer Name and the scutil manpage describes it as 'The user-friendly name for the system.'
scutil --get ComputerName
Apple says:
The AppleTalk name and the default name used for SLP/DA. The Network browser in the Finder uses SMB/CIFS to find computers that provide Windows file sharing.
SCPreferencesPath: /System/System/ComputerName

LocalHostName


This appears to be only used for Bonjour-aware services on the local network.
scutil --get LocalHostName
Apple says:
The name that designates a computer on a local subnet.
and as of 10.6:
Host names that contain only one label in addition to local, for example "My-Computer.local", are resolved using Multicast DNS (Bonjour) by default. Host names that contain two or more labels in addition to local, for example "server.domain.local", are resolved using a DNS server by default.
SCPreferencesPath: /System/Network/HostNames/LocalHostName

HostName


The name associated with hostname(1) and gethostname(3). Displayed in the default terminal command prompt (user@hostname).
scutil --get HostName
Apple says:
You can’t specify this name during server setup. Server Assistant sets the host name to AUTOMATIC in /etc/hostconfig. This setting causes the server’s host name to be the first name that’s true in this list:
- The name provided by the DHCP or BootP server for the primary IP address
- The first name returned by a reverse DNS (address-to-name) query for the primary IP address
- The local hostname
- The name “localhost”
SCPreferencesPath: /System/System/HostName

Thursday, March 1, 2012

Using a dictionary to populate a format string in python for human and computer-friendly error reporting

Python 2.6 has brought some interesting string formatting options to the table. I recently needed an object that could pass back error information that could be consumed by humans and other code. The new string formatting came in handy.

class ValidationError(Exception):
  """Class for reporting validation errors."""

  BAD_RECORD = 1

  def __init__(self, error, msg, **kwargs):
    """Record Validation Error.

    Requires python 2.6

    Args:
      error: ValidationError code e.g. ValidationError.BAD_RECORD
      msg: format string for human readable version of the error
      **kwargs: kwargs to populate format string
    """
    super(ValidationError, self).__init__(self)
    self.message = msg.format(**kwargs)
    self.error = error
    self.kwargs = dict(kwargs)

  def __str__(self):
    return self.message

You can use it like this:

e = ValidationError(ValidationError.BAD_RECORD,
                    'Bad record detected in {records}',
                    records=records)

So to present the info to a human:
In [18]: print e
Bad record detected in {'a': 12, 'b': 123}
and other code can use:
In [19]: e.error
Out[19]: 1
and access the relevant varaibles like:
In [20]: e.kwargs
Out[20]: {'records': {'a': 12, 'b': 123}}