1. Leak heap address by changing setting the length of name of the animal to 0x14.
2. Trigger the overflow in feed function by feeding/walking appropriately.
3. Allocate 2 consecutive chunks and free the first one.
4. Allocate another chunk (the same first one as above) and overflow into the second one.
5. Overflow such that on freeing the second chunk, it coalesces with an animal chunk at the start.
6. That animal chunk's feeds[0] and feeds[1] would be taken as 'fd' and 'bk' pointers.
7. Trigger overflow in that chunk to initialize fd->bk and bk->fd properly.
8. Allocate chunks from that animal chunk to overwrite 'species' with the heap address of chunk in unsorted bin + 0x10 and leak libc.
9. Keep on allocating to forge the next animal chunk and set likes > 14.
10. Walk any existing chunk and overwrite the contents of the animal chunk's feed to clear invalid pointers and also setup pointers to '\_\_free_hook' and '/bin/sh'.
11. Overwrite free hook with system.

Original writeup (https://github.com/DhavalKapil/ctf-writeups/blob/master/codegate-2018/zoo/exploit.py).