linuxthor / uul

ELF binary that runs on several different *nix flavours. Works out which variant it's being run on and runs code specific to that.
39 stars 0 forks source link

uul

"..It's a Unix system! I know this!.."

Uul (pronounced "ool") is a PoC 'Universal Unix Loader.' This code when assembled produces an x86_64 ELF binary that can run unmodified on a number of different Unix(-like) systems. The code will determine the flavour of *nix it's being run on and jump into a code path specific to that system.

Unmodified the uul ELF binary has been tested to work on:

Structurally the file is a standard ELF x86_64 binary with two additional mandatory sections '.note.openbsd.ident' for OpenBSD and '.note.netbsd.ident' for NetBSD. Additionally a .comment section is added with a reference to a GCC version to suppress warnings on Haiku. The OSABI field in the ELF header is set to 0x09 ("FreeBSD") allowing FreeBSD to load the file.

The code exploits differences in syscall numbering to determine which system 'family' it's currently running on. 64 bit versions of Linux follow a different system call numbering to 64 bit versions of BSD/SunOS with 64 bit versions of Haiku having yet another, different system call numbering. We can use this as a gadget to work out what system family we're running on based on the return value of certain system calls.

Firstly system call 12 is executed, this is create_sem on Haiku, chdir on *BSD and brk on Linux. On Haiku create_sem will return a sem_id for the sem (for example 0x909) on BSD chdir will return 0 for success and on Linux brk will return the new value of the brk when called with a reasonable argument or the value of the existing brk in case of error (see the 'Linux notes' section of the brk(2) man page for the difference between the brk syscall, which works as described above, vs the glibc wrapper which may return values such as 0 or -1)

In this PoC the first argument to syscall 12 points to the string '/tmp' as does the second argument. The return value from this system call is checked to see if it is less than 0xffff and if so we branch to a test for Haiku or BSD/Solaris. If the return value is greater than 0xffff we can enter the Linux code path as this appears to be the return value of brk rather than the Haiku sem_id or the BSD/SunOS chdir success value. Next we test to see if this is Haiku or BSD/Solaris by checking if the return value is zero - if it is greater than zero we enter the Haiku code path. Finally we determine if this is BSD or Solaris by attempting to chdir to /system which is (by default) a valid path on Solaris but not on BSD.

Assemble on Linux with:

nasm -f elf64 -o uul.o uul.asm
ld -o uul uul.o
elfedit --output-osabi FreeBSD uul 

$ file uul
uul: ELF 64-bit LSB executable, x86-64, version 1 (FreeBSD), statically linked, 
for OpenBSD, for NetBSD 2.0, not stripped

Linux

strace ./uul
execve("./uul", ["./uul"], [/* 50 vars */]) = 0
brk(0x600234)                           = 0x82b000
write(1, "Linux\n", 6Linux
)                  = 6
exit(42)        

FreeBSD

root@freebsd:~ # ktrace /tmp/uul
BSD
root@freebsd:~ # kdump
   755 ktrace   RET   ktrace 0
   755 ktrace   CALL  execve(0x7fffffffee27,0x7fffffffebc0,0x7fffffffebd0)
   755 ktrace   NAMI  "/tmp/uul"
   755 uul      RET   execve JUSTRETURN
   755 uul      CALL  chdir(0x600234)
   755 uul      NAMI  "/tmp"
   755 uul      RET   chdir 0
   755 uul      CALL  chdir(0x60022c)
   755 uul      NAMI  "/system"
   755 uul      RET   chdir -1 errno 2 No such file or directory
   755 uul      CALL  write(0x1,0x60023f,0x4)
   755 uul      GIO   fd 1 wrote 4 bytes
       "BSD
       "
   755 uul      RET   write 4
   755 uul      CALL  exit(0x45)

OpenBSD

openbsd# ktrace /tmp/UUL
BSD
openbsd# kdump
 84686 ktrace   RET   ktrace 0
 84686 ktrace   CALL  execve(0x7f7fffff4def,0x7f7fffff4cf0,0x7f7fffff4d00)
 84686 ktrace   NAMI  "/tmp/UUL"
 84686 ktrace   ARGS
        [0] = "/tmp/UUL"
 84686 UUL      RET   execve 0
 84686 UUL      CALL  chdir(0x600234)
 84686 UUL      NAMI  "/tmp"
 84686 UUL      RET   chdir 0
 84686 UUL      CALL  chdir(0x60022c)
 84686 UUL      NAMI  "/system"
 84686 UUL      RET   chdir -1 errno 2 No such file or directory
 84686 UUL      CALL  write(1,0x60023f,0x4)
 84686 UUL      GIO   fd 1 wrote 4 bytes
       "BSD
       "
 84686 UUL      RET   write 4
 84686 UUL      CALL  exit(69)

NetBSD

# ktrace /tmp/uul
BSD
# kdump
   147      1 ktrace   EMUL  "netbsd"
   147      1 ktrace   CALL  execve(0x7f7fffbfa487,0x7f7fffbf9f18,0x7f7fffbf9f28)
   147      1 ktrace   NAMI  "/tmp/uul"
   147      1 uul      EMUL  "netbsd"
   147      1 uul      RET   execve JUSTRETURN
   147      1 uul      CALL  chdir(0x600234)
   147      1 uul      NAMI  "/tmp"
   147      1 uul      RET   chdir 0
   147      1 uul      CALL  chdir(0x60022c)
   147      1 uul      NAMI  "/system"
   147      1 uul      RET   chdir -1 errno 2 No such file or directory
   147      1 uul      CALL  write(1,0x60023f,4)
   147      1 uul      GIO   fd 1 wrote 4 bytes
       "BSD\n"
   147      1 uul      RET   write 4
   147      1 uul      CALL  exit(0x45)

Dragonfly BSD

dfly# ktrace /tmp/uul
BSD
dfly# kdump
  877:1    ktrace   RET   ktrace 0
  877:1    ktrace   CALL  umtx_wakeup(0x80044ed80,0)
  877:1    ktrace   RET   umtx_wakeup 0
  877:1    ktrace   CALL  umtx_wakeup(0x80044ed80,0)
  877:1    ktrace   RET   umtx_wakeup 0
  877:1    ktrace   CALL  umtx_wakeup(0x80044ed80,0)
  877:1    ktrace   RET   umtx_wakeup 0
  877:1    ktrace   CALL  execve(0x7fffffdfdc17,0x7fffffdfd9d0,0x7fffffdfd9e0)
  877:1    ktrace   NAMI  "/tmp/uul"
  877:1    uul      RET   execve 0
  877:1    uul      CALL  chdir(0x600234)
  877:1    uul      NAMI  "/tmp"
  877:1    uul      RET   chdir 0
  877:1    uul      CALL  chdir(0x60022c)
  877:1    uul      NAMI  "/system"
  877:1    uul      RET   chdir -1 errno 2 No such file or directory
  877:1    uul      CALL  write(0x1,0x60023f,0x4)
  877:1    uul      GIO   fd 1 wrote 4 bytes
       "BSD
       "
  877:1    uul      RET   write 4
  877:1    uul      CALL  exit(0x45)

Haiku

~> strace /tmp/uul
[   521] _kern_image_relocated(0x140b) (860 us)
[   521] _kern_set_area_protection(0x36fe, 0x5) = 0x0 No error (5 us)
[   521] _kern_create_sem(0x600234, "/tmp") = 0x1175 (2 us)
Haiku
[   521] _kern_write(0x1, 0x0, 0x600249, 0x6) = 0x6 (6 us)
[   521] _kern_exit_thread(0x0) (2 us)

SunOS

root@openindiana:~# truss /tmp/uul.
execve("/tmp/uul.", 0xFFFFFD7FFFDFB388, 0xFFFFFD7FFFDFB398)  argc = 1
chdir("/tmp")                                   = 0
chdir("/system")                                = 0
SunOS
write(1, " S u n O S\n", 6)                     = 6
_exit(69)

Tested versions:

Linux   -       Ubuntu 20.04 LTS
FreeBSD -       FreeBSD 12.1-RELEASE r354233 GENERIC
OpenBSD -       OpenBSD 6.8 GENERIC#114 amd64    
NetBSD  -       NetBSD 8.1 (GENERIC)
Dragonfly BSD - DragonFly v5.4.3-RELEASE (X86_64_GENERIC)
Haiku -         Haiku-r1-beta1
Illumos -       OpenIndiana Hipster-Minimal-20200504

Based on two earlier PoC:
https://github.com/linuxthor/sixnix
https://github.com/linuxthor/OpenLSD