Here's my stencil buffer:

000000000000
000000000000
000000000000
000000000000
000000000000
000000000000
000000000000
000000000000

I render my first portal into the stencil buffer (incrementing as I go):

000000000000
000000000000
001111110000
001111110000
001111110000
001111110000
001111110000
001111110000

I render the portal behind it into the stencil buffer:

000000000000
000000000000
001111110000
001112221100
001112221100
001112221100
001111110000
001111110000

I render the geometry beyond the second portal with the stencil test set to "equal to 2" (2 being the number of portals through which the geometry I'm rendering is being seen), and only pixels that are "behind" the portion of the second portal that is also "behind" the first portal are rendered.

Now, I render the second portal again, subtracting as I go.

000000000000
000000000000
001111110000
001111110000
001111110000
001111110000
001111110000
001111110000

Now I can render the geometry behind the first portal, and so on.

The real algorithm is a lot more complicated than that, but that's how it uses stencil buffers. (Actually, the stencil buffer can technically be done away with, but it improves performance by drastically reducing overdraw.)