Linux etc ld so preload

What is / does ld.so.preload do?

I stumbled upon a file called ld.so.preload and can’t find any real usage for it. Does it have something to do with the env variable LD_PRELOAD ?

1 Answer 1

Good question! Actually, /etc/ld.so.preload replaces, in a way, LD_PRELOAD.

LD_PRELOAD is subject to severe restrictions due to a security concern: it cannot execute arbitrary setuid binaries because, if it could, you could substitute library routines with your own malicious code, see for instance here for a nice discussion. In fact, you can read in ld.so’user manual:

LD_PRELOAD

A list of additional, user-specified, ELF shared libraries to be loaded before all others. The items of the list can be separated by spaces or colons. This can be used to selectively override functions in other shared libraries. The libraries are searched for using the rules given under DESCRIPTION. For set-user-ID/set-group-ID ELF binaries, preload pathnames containing slashes are ignored, and libraries in the standard search directories are loaded only if the set-user-ID permission bit is enabled on the library file.

Instead, the file /etc/ld.so.preload suffers from no such limitation, the idea being that, if you can read/write to the directory /etc, you already have root credentials. Hence its use. Just keep in mind that you may use /etc/ld.so.preload even though you do not seem to have one at first: it is nothing but a feature of glibc, hence of all Linux distros (but not, to the best of my knowledge, of Unix flavors), thus you can create it and put into it the name of whichever setuid library in any Linux distro, and it will work.

Читайте также:  Kali linux terminal все команды

Источник

Операция «Предзагрузка». Создаем userland-руткиты в Linux с помощью LD_PRELOAD

В ник­сах сущес­тву­ет перемен­ная сре­ды, при ука­зании которой твои биб­лиоте­ки будут заг­ружать­ся рань­ше осталь­ных. А это зна­чит, что появ­ляет­ся воз­можность под­менить сис­темные вызовы. Называ­ется перемен­ная LD_PRELOAD , и в этой статье мы под­робно обсу­дим ее зна­чение в сок­рытии (и обна­руже­нии!) рут­китов.

Офи­циаль­но глав­ное пред­назна­чение LD_PRELOAD — отладка или про­вер­ка фун­кций в динами­чес­ки под­клю­чаемых биб­лиоте­ках. Если не хочет­ся исправ­лять и переком­пилиро­вать саму биб­лиоте­ку, то мож­но вос­поль­зовать­ся перемен­ной сре­ды.

К при­меру, если нам нуж­но пред­загру­зить биб­лиоте­ку ld.so, то у нас будет два спо­соба:

  1. Ус­тановить перемен­ную сре­ды LD_PRELOAD с фай­лом биб­лиоте­ки.
  2. За­писать путь к биб­лиоте­ке в файл / etc/ ld. so. preload .

В пер­вом слу­чае мы объ­явля­ем перемен­ную с биб­лиоте­кой для текуще­го поль­зовате­ля и его окру­жения. Во вто­ром же наша биб­лиоте­ка будет заг­ружена рань­ше осталь­ных для всех поль­зовате­лей сис­темы.

Нам инте­ресен как раз вто­рой спо­соб: имен­но он час­то исполь­зует­ся в рут­китах для перех­вата некото­рых вызовов, таких как чте­ние фай­ла, лис­тинг дирек­тории, про­цес­сов и про­чих фун­кций, поз­воля­ющих зло­умыш­ленни­ку скры­вать свое при­сутс­твие в сис­теме.

www

В осно­ве это­го иссле­дова­ния — пуб­ликация Абхи­нава Тха­кура Crafting LD_PRELOAD Rootkits in Userland.

Переопределение системных вызовов

Преж­де чем мы нач­нем сбли­жение с реаль­ными фун­кци­ями рут­китов, давай на неболь­шом при­мере покажу, как мож­но перех­ватить вызов стан­дар­тной фун­кции malloc().

Для это­го напишем прос­тую прог­рамму, которая выделя­ет блок памяти с помощью фун­кции malloc( ) , затем помеща­ет в него фун­кци­ей strncpy( ) стро­ку «I’ll be back» и выводит ее пос­редс­твом fprintf( ) по адре­су, который вер­нула malloc( ) .

Соз­даем файл call_malloc. c :

Те­перь напишем прог­рамму, пере­опре­деля­ющую malloc( ) . Внут­ри — фун­кция с тем же име­нем, что и в libc. Наша фун­кция не дела­ет ничего, кро­ме вывода стро­ки в STDERR c помощью fprintf( ) .

Читайте также:  Как просмотреть папку linux

Соз­дадим файл libmalloc. c :

Те­перь с помощью GCC ском­пилиру­ем наш код:

$ ls
call_malloc.c libmalloc.c

$ gcc -Wall -fPIC -shared -o libmalloc. so libmalloc. c -ldl
$ gcc -o call_malloc call_malloc. c
$ ls
call_malloc call_malloc.c libmalloc.c libmalloc.so

Вы­пол­ним нашу прог­рамму call_malloc:

$ ./ call_malloc
malloc(): 0x5585b2466260
Str: I’ll be back

Пос­мотрим, какие биб­лиоте­ки исполь­зует наша прог­рамма, с помощью ути­литы ldd:

$ ldd ./ call_malloc
linux-vdso.so.1 (0x00007fff0cd81000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0d35c74000)
/lib64/ld-linux-x86-64.so.2 (0x00007f0d35e50000)

От­лично вид­но, что без исполь­зования пред­загруз­чика LD_PRELOAD стан­дар­тно заг­ружа­ются три биб­лиоте­ки:

  1. linux-vdso. so. 1 — пред­став­ляет собой вир­туаль­ный динами­чес­кий раз­деля­емый объ­ект (Virtual Dynamic Shared Object, vDSO), который при­меня­ется для опти­миза­ции час­то исполь­зуемых сис­темных вызовов. Его мож­но игно­риро­вать (под­робнее — man 7 vdso ).
  2. libc. so. 6 — биб­лиоте­ка libc с исполь­зуемой нами фун­кци­ей malloc( ) в прог­рамме call_malloc .
  3. ld-linux-x86-64. so. 2 — сам динами­чес­кий ком­понов­щик.

Те­перь давай опре­делим перемен­ную LD_PRELOAD и поп­робу­ем перех­ватить malloc( ) . Здесь я не буду исполь­зовать export и огра­ничусь однос­троч­ной коман­дой для прос­тоты:

$ LD_PRELOAD=./ libmalloc. so ./ call_malloc
Hijacked malloc(256)
Ошиб­ка сег­менти­рова­ния

Мы успешно перех­ватили malloc( ) из биб­лиоте­ки libc. so , но сде­лали это не сов­сем чис­то. Фун­кция воз­вра­щает зна­чение ука­зате­ля NULL, что при разыме­нова­нии strncpy( ) в прог­рамме ./ call_malloc вызыва­ет ошиб­ку сег­менти­рова­ния. Испра­вим это.

Обработка сбоев

Что­бы иметь воз­можность незамет­но выпол­нить полез­ную наг­рузку рут­кита, нам нуж­но вер­нуть зна­чение, которое вер­нула бы пер­воначаль­но выз­ванная фун­кция. У нас есть два спо­соба решить эту проб­лему:

  • на­ша фун­кция malloc( ) дол­жна реали­зовы­вать фун­кци­ональ­ность malloc( ) биб­лиоте­ки libc по зап­росу поль­зовате­ля. Это пол­ностью изба­вит от необ­ходимос­ти исполь­зовать malloc( ) из libc. so ;
  • libmalloc. so каким‑то обра­зом дол­жна иметь воз­можность вызывать malloc( ) из биб­лиоте­ки libc и воз­вра­щать резуль­таты вызыва­ющей прог­рамме.
Читайте также:  Linux check ip routing

Каж­дый раз при вызове malloc( ) динами­чес­кий ком­понов­щик вызыва­ет вер­сию malloc( ) из libmalloc. so , пос­коль­ку это пер­вое вхож­дение malloc( ) . Но мы хотим выз­вать сле­дующее вхож­дение malloc( ) — то, что находит­ся в libc. so .

Так про­исхо­дит потому, что динами­чес­кий ком­понов­щик внут­ри исполь­зует фун­кцию dlsym( ) из / usr/ include/ dlfcn. h для поис­ка адре­са, заг­ружен­ного в память.

По умол­чанию в качес­тве пер­вого аргу­мен­та для dlsym( ) исполь­зует­ся дес­крип­тор RTLD_DEFAULT , который воз­вра­щает адрес пер­вого вхож­дения сим­вола. Одна­ко есть еще один псев­доука­затель динами­чес­кой биб­лиоте­ки — RTLD_NEXT , который ищет сле­дующее вхож­дение. Исполь­зуя RTLD_NEXT , мы можем най­ти фун­кцию malloc( ) биб­лиоте­ки libc. so .

От­редак­тиру­ем libmalloc. с . Ком­мента­рии объ­ясня­ют, что про­исхо­дит внут­ри прог­раммы:

Источник

Оцените статью
Adblock
detector