wheel of robots was one of the pwn challenges in the Insomnihack main event with medium difficulty. You could choose from 6 robots to add to the ‘wheel of robots’. Some robots have an adjustable attribute which determined the maximum size their name could take.
You could change the name of robots you already added to the wheel of robots, or delete them.
Once you added 3 robots to the wheel, you could spin it. One of the three robots was then
selected and an action executed depending on the robot. For most robots, the name was printed
Internally, the robots had each a flag and a pointer in the
BSS. The flag was set when a
robot got selected, and cleared when it was deleted. The pointer pointed to the name which was
allocated on the heap.
There were (at least) two potential bugs, but one of them can not be triggered until you already had full control.
The vulnerability that could not be used was an integer overflow regarding the
calloc size of the destructor robot, as its
powerful attribute is multiplied by 20 and used as 4-byte integer. When you later change the name,
powerful will be treated as an 8-byte integer and not overflow, allowing you to smash the heap. However, only 4 characters were read in while setting the size, hence it is not exploitable on its own.
The second bug was a one-byte overflow when reading the choice in the main menu. 5 bytes are read with the read function into a 4-byte sized array. Directly behind that array is the initialisation flag of the robot ‘Bender’. This allows you to set and unset this flag.
One bigger issue was that you had no control over what was printed until the final spin of the wheel, where sometimes the robots name got printed. This means that you could not leak addresses and were practically blind until you managed to do a return to main. Luckily, the wheel ended with an exit library call, and the idea was to reroute it to the main function instead. I split the exploit in the following four phases:
The first step is to smash the heap, and to break out of the control structures. The plan is to get a dangling pointer to a freed fast bucket to corrupt the linked list and alter the address of future buckets spawned. To achieve this, I first allocated the Bender robot, as I can set it to initialized later, which provides a dangling pointer. I immediately freed it again. Unfortunately, the size of the chunk was not right to get to a pointer structure, so I had to get a different chunk in the same place. The chunk was not consolidated with the top chunk immediately, so I allocated and freed the Billionaire bot to make sure the heap gets cleaned up. Then I allocated and freed the Evil bot with cruelty 5, which spawns a 0x70 sized chunk. Also I set Bender to be initialized. Now Benders name points to the free chunk of Evil Bots name.
Now that we have a dangling pointer to a free fast bucket on the heap we can manipulate the
next_ptr such that the second bucket of that size allocated from now will be at an address of our choice. To convert this into something usefull i searched around the binary some time and finaly found a suitable location. Right behind the GOT entries where the pointers to the names of the robots and the initialisation flags. I changed the
next_ptr to point to 0x10 before the 0x7f byte of the stdout file pointer, pointing into the libc. Changing the robots name now allows me to manipulate all the pointers and also initialisation variables.
Now that we can make the robots names to point anywhere, I let four of them point to calloc in the GOT, one to exit and I used one for persistent access to the pointer array. I overwrote
exit to now point into the
main function, such that spinning the wheel will not exit the program but rather give me a leak and then continue to the main menu like nothing had happened.
Spinning the wheel sometimes prints the name of the robot, and as four of the names point to a libc address in the GOT i have a four out of six chance to leak a libc address. With the libc address I calculate the address of
system and use my persistent access to the pointer array to overwrite the
free pointer to point to
system instead, and because the bucket is unalinged there were exactly three bytes available before the pointer array.
I conveniently put
sh\0 there, so destroying the robot will free the chunk and call
system with ‘sh’ as argument.