They add an extra dimension to the code without a significant change to the syntax. Think about this:
int a;
a = 5
There's only one thing to change: a. You can write a = 6 and the results are obvious to most people. But now consider:
int *a;
a = &some_int;
There are two things about a that are relevant at different times: the actual value of a, the pointer, and the value "behind" the pointer. You can change a:
a = &some_other_int;
...and some_int is still around somewhere with the same value. But you can also change the thing it points to:
*a = 6;
There's a conceptual gap between a = 6, which has only local side effects, and *a = 6, which could affect a bunch of other things in other places. My point here is not that the concept of indirection is inherently tricky, but that because you can do both the immediate, local thing with a or the indirect thing with *a... that might be what confuses people.