This is a PoC service for the new and improved ASLR, “Fully Unguessable Convoluted Kinetogenic Userspace Pseudoransomization”(F.U.C.K.U.P. for short).
Each time a user executes a command, F.U.C.K.U.P. changes the base address of memory where the binary is mapped according to a random number produced by the generation algorithm similar to WELL512.
We can select from the following commands:
- Quit: simply
- Display info: Display an introduction. Nothing interesting.
- Change random: Generate a random value and move mappings correspondingly.
- View state info: Show the current random value and then change the value as same as “Change random”.
- Test stack smash: Cause stack based buffer overflow by 100 bytes against a 10-byte buffer.
Actually, I don’t know the detailed implementations of these commands except for “Test stack smash”, for it was not I but another team member who coped with this challenge at first.
It seems that the author’s intended solution is to use SMT solver like z3 to predict random values generated, and my teammate attempted to do that.
It, however, didn’t work correctly since we were unfamiliar with and poor at using SMT solver.
So I decided to try to solve this problem by the really “pwnwise” solution.
First, I suspected Partial Overwrite could be used.
Yes, actually it can be.
stack_smash(sub_8048521), there is called
read_n(sub_8048363) which simply receives input as this:
sum = 0;
nread = read(0, addr, n-sum);
if (nread != -1) sum += nread;
} while (sum < n);
As you may see, this implementation is weird because using
read(0, addr, n-sum) instead of
read(0, addr+sum, n-sum).
Therefore, it is possible to do Partial Overwrite by splitting input into several.
@wapiflapi, a great hacker in France shares the exploit using this method(http://hastebin.com/iyinepaxen.py).
Very simple, isn’t it?
BUT I COULD NOT COME UP WITH IT.
Because I misread
read(0, addr+sum, n-sum).
So at that time I thought “Wow, nice security. I have no choice but to overwrite a buffer completely by 100 bytes. If I can’t use Partial Overwrite, then how can I solve this…?”. Too stupid.
Okay, let me explain how I solved this problem even though I couldn’t use z3 and Partial Overwrite.
Thinking that the return address is always overwritten by a buffer overflow, I had to overwrite it with some valid address.
Here, valid address means a address being mapped and executable.
So there are two possible ways to exploit the binary:
- Fix valid addresses somehow.
- Use the addresses which are always fixed.
I thought the former could be realized because the number of mapped addresses goes on increasing by
mmap is called like this:
seedf = randf(state) * 4294967295.0;
seedl = (int)seedf;
expect = (void *)(seedl & 0xFFFFF000);
actual = mmap(expect, 0x7000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
} while (expect != actual);
As you can see, the mapped addresses won’t be unmapped even if it fails to establish mappings at expected addresses.
Therefore, the more the number of mapped addresses has increased, the less the number of the possible addresses capable of being becomes.
But this approach isn’t realistic because it needs to do “Change random” many times(about thouthands or hundreds of thouthands times).
The latter, actually, can be realized: using VDSO.
I think everyone knows this, but VDSO ASLR is weaker than ASLR on the other sections(that entropy is usually only 2 bytes) and there is a famous exploit method, Sigreturn Oriented Programming(SROP).
That means we can solve this problem by doing brute force 256 times.
It was a little bit difficult for me to write the exploit due to the limitation that I had to do ROP only with gadgets on VDSO and that I was allowed to use only 78 bytes for ROP.
stack_addr = vdso - 0x800 does work correctly is described in my paper.
sysenter is a good gadget for stack pivotting!
['\nbin\nboot\ndev\netc\nhome\ninitrd.img\ninitrd.img.old\nlib\nlib64\nlost+found\nmedia\nmnt\nopt\nproc\nroot\nrun\nsbin\nsrv\nsys\ntmp\nusr\nvar\nvmlinuz\nvmlinuz.old\nfuckup\nubuntu\nflag\nfuckup\n/home/fuckup/flag\n/home/fuckup/flag\nThe flag is: z3 always helps\n']
Sleep enough not to misread disas.
written by hugeh0ge(@hugeh0ge)