Skip to content
This repository has been archived by the owner on Dec 12, 2023. It is now read-only.

Optional checksum for images #103

Open
jesseendahl opened this issue Sep 4, 2015 · 9 comments
Open

Optional checksum for images #103

jesseendahl opened this issue Sep 4, 2015 · 9 comments

Comments

@jesseendahl
Copy link

It would be great if imagr had an option for verifying checksums of images before serving them to clients, such that an image that has been tampered with won't get served to clients.

This is useful in an attack scenario where the web server where you're serving imagr images from has been compromised and the attacker has replaced your legit images with backdoored ones, but your imagr server has not been compromised. In this scenario, the imagr server could alert you that the remote image has been tampered with because the image hash doesn't match what you've specified in your imagr_config.plist.

This would have the additional benefit of protecting imagr from SSL/TLS MITM attacks if you're pulling images over HTTP.

I imagine something like this:

<dict>
  <key>type</key>
  <string>image</string>
  <key>url</key>
  <string>http://192.168.178.135/osx_custom_150410-10.10.3-14D131.hfs.dmg</string>
  <key>item_hash</key>
  <string>e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855</string>
</dict>

You might be able to easily reuse some code from Munki for this:

https://github.com/munki/munki/blob/master/code/tools/pkginfo_hash_updater.py

@keeleysam
Copy link
Member

Unfortunately there's not really any way to do this without downloading the
image to a ramdisk, and most machines don't have enough memory to do that.
Imagr uses asr to restore directly from the URL, and it would have no
opportunity to calculate the hash.

On Thursday, September 3, 2015, Jesse Endahl notifications@github.com
wrote:

It would be great if imagr had an option for verifying checksums of images
before serving them to clients, such that an image that has been tampered
with won't get served to clients.

This is useful in an attack scenario where the web server where you're
serving imagr images from has been compromised and the attacker has
replaced your legit images with backdoored ones, but your imagr server has
not been compromised. In this scenario, the imagr server could alert
you that the remote image has been tampered with because the image hash
doesn't match what you've specified in your imagr_config.plist.

This would have the additional benefit of protecting imagr from SSL/TLS
MITM attacks if you're pulling images over HTTP.

I imagine something like this:

type image url http://192.168.178.135/osx_custom_150410-10.10.3-14D131.hfs.dmg item_hash e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

You might be able to easily reuse some code from Munki for this:

https://github.com/munki/munki/blob/master/code/tools/pkginfo_hash_updater.py


Reply to this email directly or view it on GitHub
#103.

Samuel Keeley

@bruienne
Copy link
Contributor

bruienne commented Sep 4, 2015

One way to get around that is to read the file in 128 byte chunks, putting less strain on available storage, something like this (swap md5 with sha256): http://stackoverflow.com/a/4213255

@bruienne
Copy link
Contributor

bruienne commented Sep 4, 2015

Whipped up something that should work to checksum an image without needing local storage: bruienne@8b23f2a

@grahamgilbert
Copy link
Collaborator

Make it work and I'll merge it in. Although most people seem to keep their config plist and images on the same server, so not sure how much safer this will be.

@larkost
Copy link
Contributor

larkost commented Jan 26, 2016

@bruienne's solution downloads the image one for checksumming, then a second time by asr for actual imaging. On most networks this is going to be a bigger hit that people want. There are a few alternatives:

  1. Require a local scratch space to download the whole file into. The file can even be checksummed while in-flight like @bruienne showed (but I would skip using the third-party requests module). Of course this option is nearly unworkable since it would require some UI to specify the scratch space (probably).

  2. Make a http proxy that would sit in front of asr (which would see it over the loopback interface). This is surprisingly uncomplicated in Python for http, but gets surprisingly difficult when you want to use https with all the bells and whistles. It is possible that gurl.py could be hacked up to be that proxy... I would have to experiment a bit on that. Formally I would have said it would be easy to add the server side of that proxy in twisted with no extra requirements, but Apple has stopped including it with their built-in Python.

    The biggest drawback to this approach would be that you would be nearly complete on imaging before you would notice that it does not checksum properly. You could break the file up into chunks where each chunk has a checksum (ala bittorrent), and so you would have earlier warning (maybe even not release each chunk to asr until it passes), but you still have the issue that you might abort a partial imaging session, leaving an unbootable volume.

  3. A third option is to is to use hdiutil imageinfo -plist to read out the overall checksum in that information over http. Since it is only reading the header information that is a relatively small http read. While this is not as cryptographically secure as either of the two other methods (uses CRC32, which is not challenging to find collisions for), I believe that asr will use it to verify the image at the end (that does need to be checked). At the minimum it would be a speed-bump large enough to dissuade most attackers.

Personally I like the http proxy option, but part of that is because I have been thinking of building something like that for a while. If one of these seem like a good idea I might contribute the code for it.

@grahamgilbert
Copy link
Collaborator

If we can get the HTTP proxy to work reliably, then I like that idea, because it works around ASR and hdiutil's other limitations (no SSL verification and no auth off the top of my head),

@larkost
Copy link
Contributor

larkost commented Jan 26, 2016

@grahamgilbert: Just being pedantic, so others are clear about it: you are ok with the idea that the error might not come until we have already laid down 90%+ of the image? What should happen with the broken volume? Erase it?

And is there any objection to me writing this in swift? I want to learn that language, and this seems like a good place for it. Of course I would include the makefile work to get it running.

@grahamgilbert
Copy link
Collaborator

Imaging is a destructive task anyway. If something goes wrong with ASR we
get a borked volume. I don't think we should do anything when it fails
really, just throw up the error and let the admin know.

On 26 January 2016 at 19:34, Karl Kuehn notifications@github.com wrote:

@grahamgilbert https://github.com/grahamgilbert: Just being pedantic,
so others are clear about it: you are ok with the idea that the error might
not come until we have already laid down 90%+ of the image? What should
happen with the broken volume? Erase it?


Reply to this email directly or view it on GitHub
#103 (comment)
.

@erikng
Copy link
Contributor

erikng commented Oct 30, 2017

With the RAM disk option being implemented as of Imagr 1.4, this is possible now, though hasn't been coded.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants