пятница, 29 июля 2022 г.

dirty secrets of ld.so

As you can know you can set library path under linux with several ways:

  • envvar LD_LIBRARY_PATH, but it can be removed somewhere inside program so /proc/pid/environ is useless (as usually they expose via official API only useless trash but carefully hiding any really important things)
  • via option --library-path to ld.so - like /lib64/ld-linux-x86-64.so.2 --library-path path someprogram Again command line can be patched
  • via /etc/ld.so.conf - this file also can be patched after your program was launched
So good question is "is there some trusted source to see what library path was installed for some running program?"

Yes, this is ld,so itself - because it uses this data while dynamically loading some modules, So long story short: value from --library-path & LD_LIBRARY_PATH stored in variable library_path and whole directory set in rtld_search_dirs
Bad news - they are not exported and even worse - they are hard to find even using disassembler

суббота, 9 июля 2022 г.

PoC to blind pamspy

Lets disasm jit code from this spyware:

 [8] prog 0xffffb02dc0133000 id 160 len 46 jited_len 215 aux 0xffff8ccb58fab400 used_maps 1 used_btf 0 func_cnt 0
     tag: 0F 86 19 76 BC 37 68 B3
  stack_depth: 16
  num_exentries: 0
  type: 2 BPF_PROG_TYPE_KPROBE
  expected_attach_type: 0 BPF_CGROUP_INET_INGRESS
  used maps:
   [0] 0xffff8ccbc1b1c600 - rb
...
ffffffffc07bc801 e80a38e6f1  call 0xffffffffb2620010 ; bpf_ringbuf_submit
ffffffffc07bc806 31c0        xor eax, eax
ffffffffc07bc808 415e        pop r14
ffffffffc07bc80a 415d        pop r13
ffffffffc07bc80c 5b          pop rbx
ffffffffc07bc80d c9          leave
ffffffffc07bc80e c3          ret

and in ebpf opcodes:
43 85 00 00 00 C0 CF 02 00 call 0x2CFC0 ; bpf_ringbuf_submit
44 B7 00 00 00 00 00 00 00 mov r0, 0
45 95 00 00 00 00 00 00 00 ret

Here 0x2CFC0 is offset to bpf_ringbuf_submit from __bpf_call_base
The last call submit some data to bpf map rb with type BPF_MAP_TYPE_RINGBUF. If we could patch this function no data will be passed to usermode. How are these native function addresses filled in at all?