source of illustration: Wikimedia.org
When you send a packet to its destination, it often has to pass through multiple routers or 'hops'.
To prevent packets from endlessly circulating through the network due to routing loops (router A points to router B, which points to router A…), they include a Time-To-Live field that is set to a reasonably high value when the packet is created, and each machine the packet passes through reduces this field by one.
When the field reaches zero, the packet is discarded. As a courtesy, the router that discards the packet has the option of generating a new packet using ICMP with the subtype 'TTL exceeded' and sending it back to the source machine to inform it that something is wrong with the network path.
Those clever people in 1987 realised that by manipulating the TTL value, you could select the router that would send this ICMP message.
Send a packet with the TTL set to 1. The first router you hit will reduce it to zero. The packet is now 'dead', so it drops it and sends back TTL Exceeded. This response will come from the IP address of the router - congratulations, you now have the IP address of the first hop.
Now send another packet with the TTL set to 2. The first router will reduce it to 1 and let it through, and the second router will reduce it to zero and drop it. You now have its IP address.
Repeat, increasing the TTL each time until the last hop replies. You now have a complete path.