Open narendra36 opened 2 years ago
Thanks for the report. I understand the pixel flood attack vector is the same as the one described here (there is also an image for reproducibility): https://hackerone.com/reports/842462
Ideally, I believe this should be addressed inside libvips, perhaps you can open an issue there, and hopefully @jcupitt can provide some insights about it.
Hi, that's an interesting decompression bomb. I see:
$ ls -l lottapixel.jpg
-rw-rw-r-- 1 john john 4856 Jan 14 13:10 lottapixel.jpg
$ vipsheader -a lottapixel.jpg
lottapixel.jpg: 64250x64250 uchar, 3 bands, srgb, jpegload
width: 64250
height: 64250
bands: 3
format: uchar
coding: none
interpretation: srgb
xoffset: 0
yoffset: 0
xres: 0.866142
yres: 0.866142
filename: lottapixel.jpg
vips-loader: jpegload
resolution-unit: in
jpeg-multiscan: 0
jpeg-chroma-subsample: 4:2:0
So 5kb on disc, but huge numbers of pixels.
I can copy like this:
$ /usr/bin/time -f %M:%e vips copy lottapixel.jpg x.jpg
(vips:152750): VIPS-WARNING **: 13:12:43.652: read gave 2 warnings
(vips:152750): VIPS-WARNING **: 13:12:43.652: VipsJpeg: Corrupt JPEG data: bad Huffman code
182804:7.90
So it copies in 180mb of memory and 8s of run time. There's a warning, but it does write an image:
$ vipsheader x.jpg
x.jpg: 64250x64250 uchar, 3 bands, srgb, jpegload
$ ls -l x.jpg
-rw-r--r-- 1 john john 64514329 Jan 14 13:12 x.jpg
And you can view the image, though it's very boring:
(the image viewer is vipsdisp, if you're curious ... it's handy for large images)
So I think everything is working.
There are a lot of bombs like this -- it's easy to make TIFFs that blow up, eg.:
$ vips black x.tif[bitdepth=1,compression=ccittfax4] 1000000 1000000
That's a 1m x 1m pixel TIFF image. It's 200kb on disc, but it'll be a terabyte if you try to decompress it.
The simplest defence is to open the image and check the dimensions before decompressing. Perhaps (in python):
image = pyvips.Image.new_from_file(some_suspicious_file)
if float(image.width) * float(image.height) > decompression_bomb_limit:
error("image too large")
libvips new_from_file
is always fast and never allocates large amounts of memory, so this is safe.
16k x 16k pixels might be a sensible limit, perhaps?
Hi @jcupitt, thanks for the input. I'm getting the same warnings as you mentioned but since these are just warnings so I'm not able to catch it at code level. As you rightly mentioned, one way is just put some limit on dimensions.
But I want to know more about below point:
Thanks for the report. I understand the pixel flood attack vector is the same as the one described here (there is also an image for reproducibility): https://hackerone.com/reports/842462
Ideally, I believe this should be addressed inside libvips, perhaps you can open an issue there, and hopefully @jcupitt can provide some insights about it.
Sure, I will open the same on libvips also.
2. Since VIPS giving the above warnings that means it is a known condition, Should it not be treated as error instead of just warning?
libvips is permissive by default, so it tries to load images if it possibly can. You can make it strict with the fail
option, eg.:
$ vips copy lottapixel.jpg[fail] x.jpg
(vips:174339): VIPS-WARNING **: 17:04:56.219: error in tile 0 x 8
VipsJpeg: Corrupt JPEG data: bad Huffman code
$ echo $?
1
Now it'll stop on any warning and return an error code. This is not always what you want though -- what if an image triggers a harmless warning? Now your users can't upload.
I would block on number of pixels instead. It's much safer and more reliable.
libvips 8.12 deprecates fail
and adds fail-on
instead. You can set this to the type of thing you want to cause a load failure -- pick one of none
, truncated
, error
, warning
.
Sure, I will open the same on libvips also.
I don't think there's anything more libvips can do here, so there's no need for an issue.
Hi, @jcupitt, Thanks for the clarification. :+1:
@h2non, Can you give input on this:
1. bimg having a const defined MaxSize (maximum pixel allowed) in options.go that is approx 16k, can't we use that somehow?
Thanks for the insights @jcupitt!
I plan to implement safe image validation at bimg
level, just for convenience, but in the meantime, you can simply validate the image size before processing it through bimg
.
Example:
package main
import (
"fmt"
"os"
"image"
"log"
"bufio"
"gopkg.in/h2non/bimg.v1"
_ "image/gif"
_ "image/png"
_ "image/jpeg"
)
func main() {
img, err := os.Open("lottapixel.jpg")
if err != nil {
log.Fatal(err)
}
reader := bufio.NewReader(img)
config, format, err := image.DecodeConfig(reader)
if err != nil {
log.Fatal(err)
}
if (config.Width * config.Height) > (bimg.MaxSize * bimg.MaxSize) {
log.Fatal("Image too large")
}
fmt.Println("Valid image of Width", config.Width, "Height:", config.Height, "Format:", format)
// If the image is safe, call bimg then...
}
Oh, nice!
I don't know Go, can this overflow?
if (config.Width * config.Height) > (bimg.MaxSize * bimg.MaxSize) {
It might be better as a double float multiply..
Getting this error from scanner when building an image for AWS. Is it related?
Container image with tag c27512a has vulnerabilities findings: 1
IN1-GOLANG-GITHUBCOMH2NONBIMG-2340903 - github.com/h2non/bimg
> ## Overview
[github.com/h2non/bimg](https://pkg.go.dev/github.com/h2non/bimg#section-readme) is a Small Go package for fast high-level image processing using libvips via C bindings, providing a simple programmatic API.
Affected versions of this package are vulnerable to Denial of Service (DoS) by uploading a crafted image with high pixels size value, which will lead to a high allocation of memory.
Hi, I'm using bimg in one of my project to compress an image. I'm using the process function but if the image is manipulated for pixel flood attack it is stuck there only and gives VIPS warning but not producing any error. After some time it drains out the system RAM that is causing service down.
Faulty Image detail: I have an image of 5kb, 260x260 pixels. In the image itself I exchange the 260x260 values with 0xfafa x 0xfafa (so 64250x64250 pixels). Now from what I remember your service tries to convert the image once uploaded. By loading the 'whole image' into memory, it tries to allocate 4128062500 pixels into memory, flooding the memory and causing DoS.
Can anyone help me to prevent this?