The memory a program uses includes both what you would think of as "data" (text you wrote, an image you're viewing, the script source code your web browser downloaded, a string of text which is being built by that script...), what you might think of as "metadata" (a mapping of free and used memory blocks, pointers to the start of those memory blocks, pointers linking that text string to the functions that can be executed on it, pointers to loaded libraries such as IE's jscript.dll that parses and compiles JavaScript), and executable code (the actual binary code the CPU runs, including the DLL contents, the result of compiling the JS, and the functions on "objects" in data).
When memory corruption occurs, an attacker can usually exert some control over where and how it occurs. For example, if the attacker finds a way to cause some data to be deleted but the program to treat it as still present (called a "use after free" vulnerability, and relatively common in JavaScript engines), the attacker's script could then create a new data object (such as an array of carefully-chosen bytes) that is a similar size and will be created in the same place as the deleted-but-still-usable object. The attacker then might set some value on the deleted object, but because the memory that defines the object holds some totally new data now (the attacker-crafted array) it actually changes some value that the attacker isn't supposed to be able to control such as the extent of the array. The attacker then uses the array - which the program now thinks is super-long, extending well beyond the allocated chunk of memory that it is actually stored in and into memory used for other things - and does something like change the "return pointer" metadata that says "when this block of code finishes, continue executing code over here". The attacker changes this return pointer so that the code that will run after the current function ends does something like launch a program the attacker wrote, executing arbitrary code on the victim's computer.
This type of attack (use-after-free to gain an arbitrary-offset memory read/write, using that to overwrite the return address into some attacker-desired function) is but one of many, many ways to exploit memory corruption. Some other memory corruption vulns are double-free (trying to delete the same block of memory twice, which is dangerous because you may end up treating attacker-controlled data as though it is actually metadata about the memory allocations and thus change data the user shouldn't have access to), buffer overflows on the stack or heap (two different places program data goes; the stack is where you'll also find things like return pointers and the heap where you'll find things like function tables and arbitrary-length arrays) where you can write past the end of a memory allocation and change other data, integer overflow where the program does some math on two numbers that ends up with a result too big for the program to hold in the space it reserved for that number, so it loses part of that number and treats the totally-different number as a pointer into safe memory when in fact it could be anything at all, and so on.