p2 = p1; // what happens here?
You are simply copying the value (pointed memory address) of p1 into p2. This is no different than doing this:
int i1, i2;
i1 = 12345;
i2 = i1;
However, because the value in question in a memory address allocated with new, you now have a memory leak, as you have lost your only pointer to the 2nd allocated int that p2 was previously pointing at. Now p1 and p2 are both pointing at the 1st int in memory.
cout << "pointer 2 is " << *p2 << endl << *p1 << endl; // both give out 5
Yes, because p1 and p2 are pointing at the same memory address.
delete p1; // what happens to p2 ?
Nothing happens to p2 here, it is still pointing at the same memory address it was before. p1 and p2 are independent variables, so a change to one does not affect the other. But, the delete has deallocated the 1st int that was stored at the memory address being pointed at by p1 and p2, so now they are both dangling pointers to invalid memory. Since you don't use p1 after this, that is ok for p1, but for p2 the next statements:
cout << "pointer 2 is " << *p2 << endl;
delete p2;
Will cause Undefined Behavior, because you are accessing invalid memory via the dangling p2. The read may succeed in returning stale data that is still present at the memory address, or it may return garbage, or it may crash. The delete will almost certainly crash, since the memory has already been freed earlier, but that is not guaranteed either. Undefined Behaivor is just that - undefined - so literally anything could happen.