Let's try to explain this in simpler language.
As you might have figured out, buffer overflow occurs when you fill in more data than was actually reserved for it.
In the context of the program, the buffer array has been allocated 16 bytes. If you put in more than 16 bytes, a buffer overflow occurs. As a result of buffer overflow, you overwrite memory in the region immediately following the buffer.
To exploit this buffer overflow you need to understand how a function call happens.
In x86 assembly, function calls are usually done via the call instruction. What this instruction does is change the instruction pointer (in simpler terms, the current line of code being executed) to the function address. Before transferring control, it saves the current instruction pointer (IP) on the stack. The IP is saved so that the processor can return the control to the caller after it has executed the callee function.
Now both the buffer array and the IP is saved on the stack. The buffer array has a max capacity of 16 bytes. So naturally, if you keep fill in more than 16 bytes, it will overwrite the memory in the rejoining adjoining the buffer.
With carefully crafted input, it is possible to overwrite the saved IP on the stack (as both the buffer and IP are located on the stack). The consequence of this is when the function tries to return, it will use the overwritten value instead of the original saved IP.
If you supply a specially crafted input which overwrites the saved IP with the address of the win() function while calling check(), you have exploited the buffer overflow. This is exactly the thing you need to do.