UID_WRAPPER(1)

πŸ’… uid_wrapper β€” bestie's guide to faking privilege separation

okay so welcome to uid_wrapper(1), the little library that lets you cosplay as root without actually being root. it's giving main character energy but for syscalls. no cap. πŸŽ€


✨ NAME ✨

uid_wrapper β€” a wrapper to fake privilege separation 🫢


✨ SYNOPSIS ✨

LD_PRELOAD=libuid_wrapper.so UID_WRAPPER=1 UID_WRAPPER_ROOT=1
./myapplication

like literally that's it, bestie. one line and your app thinks it runs the world πŸ‘‘


✨ DESCRIPTION ✨

so here's the tea β˜• β€” uid_wrapper does all of this:

  • Allows uid switching as a normal user. yes, as a normal user. slay.
  • Start any application making it believe it is running as root. delulu but make it functional πŸ’–
  • Support for user/group changing in the local thread using the syscalls (like glibc).
  • More precisely this library intercepts seteuid and related calls, and simulates them in a manner similar to the nss_wrapper and socket_wrapper libraries.

some projects like a file server need privilege separation to be able to switch to the connection user and do file operations. uid_wrapper convincingly lies to the application letting it believe it is operating as root and even switching between UIDs and GIDs as needed. it's literally the world's most convincing actor, periodt. 🎭✨


✨ ENVIRONMENT VARIABLES ✨

  • UID_WRAPPER β€” If you load the uid_wrapper and enable it with setting UID_WRAPPER=1 all setuid and setgid will work, even as a normal user. that's the whole magic trick, bestie πŸͺ„
  • UID_WRAPPER_ROOT β€” It is possible to start your application as fake root with setting UID_WRAPPER_ROOT=1. fake it till you make it fr fr πŸ‘‘
  • UID_WRAPPER_DEBUGLEVEL β€” If you need to see what is going on in uid_wrapper itself or try to find a bug, you can enable logging support in uid_wrapper if you built it with debug symbols. so like, only if you compiled with the debug symbols, okay? πŸ›
    • 0 = ERROR
    • 1 = WARNING
    • 2 = DEBUG
    • 3 = TRACE

(yes it goes up to TRACE. she's thorough πŸ’…)

  • UID_WRAPPER_MYUID β€” This environment variable can be used to tell uid_wrapper to let geteuid() return the real (instead of the faked) UID of the user who started the process with uid_wrapper. so you can peek behind the curtain for a sec 🫣
uid_t uid;

setenv("UID_WRAPPER_MYUID", "1", 1);
uid = geteuid();
unsetenv("UID_WRAPPER_MYUID");
  • UID_WRAPPER_DISABLE_DEEPBIND β€” This allows you to disable deep binding in uid_wrapper. This is useful for running valgrind tools or sanitizers like (address, undefined, thread). basically for when your other debugging besties need to come through 🌸

✨ EXAMPLE ✨

$ LD_PRELOAD=libuid_wrapper.so UID_WRAPPER=1 UID_WRAPPER_ROOT=1 id
uid=0(root) gid=0(root) 0(root)

look at that. root root-ing. iconic behaviour only πŸ”₯πŸ‘‘


✨ WORKAROUNDS ✨

If you need to write code that behaves differently depending on whether uid_wrapper is enabled or not, for example in cases where you have to file permissions, you can predefine the uid_wrapper_enabled() function in your project as follows:

bool uid_wrapper_enabled(void)
{
    return false;
}

Since uid_wrapper overloads this function if enabled, you can use it in your code to detect uid_wrapper. so like, you ship the boring false version, and if uid_wrapper is in the building it just takes over. vibe check passed βœ…

lowkey this is the "are we in the simulation" check but for your binary. ngl kind of obsessed.

that's the whole page bestie, go forth and fake that privilege πŸ’œ

β€” written by your girl, dropping the deets from the uid_wrapper(1) manual, dated 2015-11-03. mwah πŸŽ€βœ¨πŸ¦‹