Wandering Thoughts archives

2011-12-20

SSH, man in the middle attacks, and public key authentication

Mark wrote a comment on my note about nssh:

A warning about 'StrictHostKeyChecking no' by default. I had the same thought as you did, and tested the behavior. When set to 'no', ssh will connect anyway if the host key changes and you're using public key auth (it will print a warning, and disable password based auth however), which doesn't prevent a man in the middle attack if the person has access to your public key (which it's very likely they will have).

I looked at that and said 'that can't be entirely right; access to your public key shouldn't make any difference'. But intuition is a bad guide to security and cryptography, so I went off to read up on the SSH-2 protocol RFCS to see for myself (or at least skim through them). The result was interesting and comes to a stronger conclusion than I was expecting: I believe that if you use public key authentication you're probably immune to man in the middle attacks.

The SSH 'protocol' is actually three pieces: a transport protocol that creates the basic encrypted session, an authentication protocol, and a connection protocol. When a SSH connection starts, the transport protocol negotiates a shared session key and a session identifier and in the process validates the host key of each end. Although I'm not qualified to say if it's fully successful in this, the transport protocol attempts to make sure that the session identifier can't be fully controlled and set by either end; it's always a blend of things from the server and the client.

Once the transport is running, SSH attempts public key authentication in the traditional way: it assembles a known block of data, signs it with the private key, and sends the signature to the server to be verified. Note that the client does not send the block of data, just the signature. This known block of data includes the session identifier. Thus, in order to pass user authentication with the server, you need a signature that uses the session ID of your connection to the server. Unless you know the victim's private key (not just their public key), you need to somehow force the client's connection to you to wind up with the same session ID as your connection to the server so that you can simply relay the client's user authentication message to you on to the server.

I can't categorically say that a man in the middle can't arrange identical session IDs for each connection; I don't know enough cryptography (and understand the SSH protocol that well). However, part of the session ID comes from the public Diffie-Hellman key parameters and my best understanding is that you cannot feasibly recover a D-H key from the public parameters alone. It sure looks like a MITM must do this in order to arrange for identical session IDs; it must present the client's public parameter to the server (instead of its own) and the server's public parameter to the client (instead of its own), yet still wind up with its own valid keys for both connections.

(You can of course trivially impersonate a server (at the SSH level), even without knowing someone's public key. All you have to do is accept whatever signature they send you without even checking it, because the whole user authentication step has no effect on the session encryption; it's only used by the server to decide whether or not to give you access. But this is a lot less dangerous than a genuine MitM attack.)

SshAndMitM written at 13:29:03; Add Comment

2011-12-02

The many ways PCs can dual boot multiple OSes

In response to yesterday's entry, a commentator asked a question related to dual booting. That means it's time to open the can of complexity that is dual booting on PCs. One of the reasons that dual booting is much more complex than how PCs boot the main OS is that there are at least three different ways that you can boot an alternate OS:

  • you can load the other OS's boot sector and jump to it, just as if it was the real MBR being loaded by the BIOS. This is simple and basically guaranteed to work, but it requires that you capture and maintain the boot sector (and the primary partition table that is embedded into it), and the rest of the OS's bootloader has to be on disk where it expects it to be (which may be where your bootloader also wants to go).

    (For obvious reasons this is a favorite technique of boot sector viruses.)

    I believe that GRUB chainloading usually does this. There seems to be more or less a standard where many OSes stick a properly set up copy of their boot sector in the first sector of their BIOS partition.

  • you can load and jump to the other OS's bootloader itself (what's often called the second stage bootloader), loading it either from where it normally lives or from a copy that's located in a place more convenient for you. The drawback of this approach is that loading a bootloader second stage and transferring control to it is somewhat more complicated and more bootloader specific.

    (Although since the second stage is loaded by the boot sector and the boot sector code is very small, this is generally not going to be that complex. Still, second stage bootloaders can live in all sorts of places depending on the OS.)

  • you can directly load and start the other OS's kernel and any additional bits that it needs. The drawback is that loading a kernel, setting it properly, and passing boot parameters to it is complex and OS dependent (and changes every so often, which means that your bootloader has to keep up). Also, generally you need to understand the OS's filesystem (whatever it is), since kernels are usually in the filesystem (unlike live bootloaders).

    However, if everything works this is the most direct way of booting another OS plus you can do everything in a single step; you do not have the user experience of telling the computer to boot another OS twice (once for the real bootloader and once again to the other OS's bootloader).

Every so often people in the open source world have tried to create a common generic boot protocol for loading OS kernels and passing arguments to them; one example is the GRUB Multiboot protocol. These have the goal of eliminating most of the complexity of the last approach, which is especially important for people who are trying to create a generic open source bootloader since they would rather not maintain special kernel setup code for each different free Unix. My impression is that none of these protocols have really caught on and the major open source OSes like Linux have preferred to stick to their existing kernel setup protocols.

Some of dual booting interacts with partitioning. If you use chainloading from the first sector of an OS's partition, well, your bootloader has to be able to find that; generally this only requires knowing the global partitioning scheme in effect (eg, BIOS primary and extended partitions). If your bootloader is directly loading the OS's kernel it needs to understand enough of the OS's own partitioning scheme (if any) to let it find the filesystem with the kernel. If the OS nests its own partitioning scheme inside BIOS partitioning, your bootloader will need to understand both in addition to being able to read the OS's filesystem.

(Here we can see a subtle win from the Linux decision not to have its own disk partitioning scheme. Since Linux partitioning is BIOS partitioning, Linux bootloaders only have to know one sort of partitioning. Or zero sorts of partitioning in the case of LILO.)

Sidebar: the extremely minimal bootloader

All of this description has assumed a relatively sophisticated bootloader. Bootloaders don't have to be sophisticated; they can be extremely minimal instead. A minimal bootloader does not try to understand and parse anything; not partitioning, not filesystems. Instead it loads things through a hardcoded set of mappings of disk blocks (probably encoded as extents) and the mapping information is maintained outside of the bootloader itself. Such a minimal bootloader is completely agnostic about partitioning and filesystems, although the tool to maintain the mapping data needs to be able to generate the block map for files on the disk.

As you might guess from what I said above, LILO is an example of such a bootloader.

DualBootingPCs written at 01:00:44; Add Comment


Page tools: See As Normal.
Search:
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.