When you match :: you are consuming both colons.
Try this using a zero width lookahead:
my $line="root:XXXXXXXXXXXXX:12103::::::";
$line=~s/:(?=:|$)/:NULL/g;
print "\tAFTER\t$line\n" if ( $line =~ /^root:/ );
__OUTPUT__
AFTER root:XXXXXXXXXXXXX:12103:NULL:NULL:NULL:NULL:NULL:NULL