$30 off During Our Annual Pro Sale. View Details »

Whitelisting LD_PRELOAD For Fun and No Profit

Whitelisting LD_PRELOAD For Fun and No Profit

Sometimes bolting a security solution on the side of technology just doesn’t work as well as built-in protection. One example of this on Linux systems is libpreloadvaccine, a whitelisting solution I built that aimed, and failed, to provide foolproof protection against abuse of LD_PRELOAD process injection. This talk will cover how adversaries use LD_PRELOAD, how its built-in audit system works, and how the audit system can be leveraged for whitelisting. We’ll also examine design and implementation considerations for whitelisting, closing the talk by showing how checks built into the dynamic linker would be much more effective than a solution thrown on top.

Tony M Lambert

February 01, 2020
Tweet

More Decks by Tony M Lambert

Other Decks in Programming

Transcript

  1. Whitelisting
    LD_PRELOAD
    For Fun and No Profit

    View Slide

  2. ▪ Professional tinkerer & educator
    ▪ Recovering system administrator
    ▪ Love to make bad guys have bad days
    Tony Lambert
    Detection Engineer/Intel
    Red Canary
    @ForensicITGuy
    id -un

    View Slide

  3. What is LD_PRELOAD and how is it used?
    Examining the rtld-audit subsystem
    Whitelisting LD_PRELOAD
    What worked and what didn’t
    Overview

    View Slide

  4. ▪ glibc & musl environment variable
    ▪ Injects arbitrary SO file into process
    ▪ LD_PRELOAD or /etc/ld.so.preload
    Intro to LD_PRELOAD

    View Slide

  5. rtld.c

    View Slide

  6. Get Started With Env Var
    LS
    SHELL=/bin/bash
    PATH=/long/list/of/folders

    LD_PRELOAD=injected.so
    /proc/PID/env

    View Slide

  7. Make It Persistent
    $ LD_PRELOAD=injected.so ls
    $ export LD_PRELOAD=injected.so
    # echo injected.so > /etc/ld.so.preload
    # echo LD_PRELOAD=injected.so >> /etc/profile

    View Slide

  8. It Can Be Good!
    LS
    libdl.so
    libc.so test-libc.so

    View Slide

  9. Evil Use Cases
    ■ Hooking functions and calls
    ■ Automatic code execution on load

    View Slide

  10. Hooking Functions
    ■ Define function with same name
    ■ Manipulate output and fool user
    ■ libprocesshider

    View Slide

  11. It Can be Very Bad!
    PS
    libc.so
    readdir()
    evil.so
    readdir()
    Intact Listing
    Bash
    Python evil.py
    Tainted Listing
    Bash
    ...

    View Slide

  12. Hooking Example

    View Slide

  13. Execution on Load
    ■ No knowledge of target binary needed
    ■ Code stored in ELF .init section
    ■ Zombie Ant Farm Project

    View Slide

  14. Execution Example

    View Slide

  15. The rtld-audit Subsystem
    ■ Audit API for the dynamic linker
    ■ Write a SO library to implement
    ■ Use with LD_AUDIT variable

    View Slide

  16. Lots of functions
    la_objsearch()
    la_activity()
    la_objopen()
    la_objclose()
    la_preinit()
    la_symbind*()
    la_pltenter()
    la_pltexit()

    View Slide

  17. At First, I Wanted to Log
    la_objsearch()
    la_activity()
    la_objopen()
    la_objclose()
    la_preinit()
    la_symbind*()
    la_pltenter()
    la_pltexit()

    View Slide

  18. I Realized I Could Prevent
    la_objsearch()
    la_activity()
    la_objopen()
    la_objclose()
    la_preinit()
    la_symbind*()
    la_pltenter()
    la_pltexit()

    View Slide

  19. Intercept Before Load
    la_objsearch()
    The dynamic linker invokes this function to inform
    the auditing library that it is about to search for a
    shared object.
    rtld-audit(7) manpage

    View Slide

  20. You Had Me At “return NULL”
    la_objsearch()
    ...returns the pathname that the dynamic linker
    should use... If NULL is returned, then this
    pathname is ignored for further processing.
    rtld-audit(7) manpage

    View Slide

  21. View Slide

  22. Let’s Block Some Preloads!
    ■ Define unauthorized preloads
    ■ Define authorized preloads
    ■ Monitor for unauthorized loads
    ■ Mitigate the loads

    View Slide

  23. Unauthorized Preloads
    ■ Unpredictable preloads
    ■ Unlimited forms of evil
    ■ Block by default

    View Slide

  24. Authorized Preloads
    ■ Unpredictable system configuration
    ■ Wanted ease of administration
    ■ Modeled after cron.allow, hosts.allow

    View Slide

  25. Monitor & Block Preloads
    ■ Intercept module search
    ■ Check the allowed list
    ■ Return NULL if not allowed to block

    View Slide

  26. Enter Libpreloadvaccine!
    ■ LD_AUDIT SO library
    ■ Intercepts and blocks
    ■ Just worksTM
    github.com/ForensicITGuy/libpreloadvaccine
    Logo left intentionally blank.

    View Slide

  27. Simple Logic

    View Slide

  28. Simple Authorized List
    /etc/libpreloadvaccine.allow
    ■ Check the allowed list
    ■ Return NULL if not allowed to block

    View Slide

  29. Simple Deployment
    1. Compile with gcc
    2. Move to folder
    3. Set LD_AUDIT
    export LD_AUDIT=/usr/lib/libpreloadvaccine.so

    View Slide

  30. Success! Sort of...

    View Slide

  31. Catch it in Action!

    View Slide

  32. And Bypass it After!

    View Slide

  33. Lessons Learned

    View Slide

  34. Keep Security Close to Code
    ■ Bolted on solutions don’t always work
    ■ Code inside rtld.c would be harder to bypass
    ■ Attackers with root can have unlimited access

    View Slide

  35. FEEDBACK
    Q & A
    REDCANARY.COM/BLOG
    @REDCANARYCO
    GITHUB.COM/FORENSICITGUY/LIBPRELOADVACCINE
    @FORENSICITGUY

    View Slide