After an uneventful first half, Milan scored four unanswered second-half goals having gone 2-0 down to Juve strikes from Adrien Rabiot and Cristiano Ronaldo.
Ibrahimovic’s 62nd-minute penalty offered hope, before Franck Kessie and Rafael Leao completed a five-minute turnaround. Ante Rebic added a fourth to secure a memorable victory with 10 minutes remaining.
Defeat sees Maurizio Sarri’s side miss the chance to move 10 points clear of second-placed Lazio, who lost 2-1 to relegation-threatened Lecce earlier on Tuesday.
It took Maurizio Sarri’s visitors until first-half injury time to register their first shot on target, but Rabiot’s spectacular finish from the edge of the box – after running with the ball from his own half – sparked the contest into life.
Ronaldo, who became the first player to reach 25 Serie A goals in a season for the club since 1961 on Saturday, met Juan Cuadrado’s pass to score for a fifth successive game and leave Juve in control.
However, Ibrahimovic’s spot-kick, which was awarded after Leonardo Bonucci was penalised for handball, flipped the momentum.
A fired-up Milan continued to attack Sarri’s shell-shocked side and were rewarded as Rebic swept home to seal three points which send a resurgent Milan up to fifth.