It is because `Attributes` have `UpValues` associated with them so at the end you are not trying to `Set` to `Attributes[Foo]` but it will be translated.
You can mimic that with e.g. `UpSetDelayed (^:=)`:
ClearAll[f]
Set[f[x_], attr_] ^:= SetAttributes[x, attr];
SetAttributes[f, {Protected, HoldFirst}]
----------
f = 2
> Set::wrsym: Symbol f is Protected. >>
f[x] = HoldFirst (*no error*)
Attributes[x]
> {HoldFirst}