The visiting Italians started this Champions League encounter the brighter of the two sides and found themselves two goals to the good within the opening 16 minutes.
Urby Emanuelson claimed their first with a deflected free kick, before reported Manchester United transfer target Stephan El Shaarawy beat two members of the Zenit defence before shooting low into the net.
Zenit's response to Milan's double was positive and after both Alexander Kerzhakov and Hulk had been denied by goalkeeper Christian Abbiati, the latter of the two strikers reduced the arrears on the stroke of half-time.
The Brazilian international found himself with time and space inside the area and sent the ball beyond the reach of Abbiati to bring his side back into contention.
The home side then levelled three minutes after the restart when Roman Shirokov headed in a cross as Hulk turned provider.
Both teams then created chances to find the winning goal, which eventually went the way of Milan 15 minutes from time. In trying to prevent Milan substitute Giampaolo Pazzini from scoring, Hubocan turned the ball into his own net.
Maxim Kanunnikov almost drew the hosts level in the closing stages, but Abbiati got down low to turn the 21-year-old's effort wide of the target.
Milan now top their group with four points, while Zenit sit bottom without a single point.