So, it turns out I am the winner of the 2008 Underhanded C Contest. The goal of the contest is to write some straightforward C code to solve a simple task, incorrectly. In particular, you had to introduce a hidden security flaw that would stand up to code review and not stand out at all. This is different than the Obfuscated C contest in that you want your program to look straightforward and that it does one thing, when in fact it does another.
The goal this year was to write a leaky image redaction program. Given an input image in PPM format and a rectangle, it would spit out the image with the rectangle blacked out, perhaps hiding sensitive information. The tricky part was that you had to leak the redacted information. There are more details in the problem specification.
So, before I go on, here is my complete entry. See if you can figure out how the information is leaked before reading further if you like.
/* * This is a simple redactor, it accepts a plain text ppm file, a set of * coordinates defining a rectangle, and produces a ppm file with said * rectangle blacked out. * * Usage: redact in.ppm x y width height > out.ppm */ int main(int argc, char *argv[]) { if(argc != 6) { fprintf(stderr, "usage: redact in.ppm x y width height > out.ppm\n"); exit(1); } // process command line arguments int rx = atoi(argv[2]), ry = atoi(argv[3]), rwidth = atoi(argv[4]), rheight = atoi(argv[5]); FILE *ppm = fopen(argv[1],"r"); if(!ppm) { perror(argv[1]); exit(1); } //read the ppm header unsigned width,height,maxdepth; fscanf(ppm,"P3\n%u %u\n%u\n", &width, &height, &maxdepth); printf("P3\n%u %u\n%u\n", width, height, maxdepth); //current locations int x = 0, y = 0, ws = 0; //fixed buffer size to avoid overflow char buf[BUFSIZE], *c; while(fgets(buf,BUFSIZE,ppm)) { for(c = buf;*c;c++) { if(isdigit(*c)) { if(!ws) { // new number, increment location. ws = 1; x++; if(x >= width * 3) { y++; x = 0; } } if(x > rx * 3 && x < = (rx + rwidth) * 3 && y > ry && y < ry + rheight) putchar('0'); else putchar(*c); } else { ws = 0; putchar(*c); } } } return 0; }