├── README.md └── uul.asm /README.md: -------------------------------------------------------------------------------- 1 | # uul 2 | 3 | *"..It's a Unix system! I know this!.."* 4 | 5 | Uul (pronounced "ool") is a PoC 'Universal Unix Loader.' This code when assembled produces an x86_64 6 | ELF binary that can run unmodified on a number of different Unix(-like) systems. The code will 7 | determine the flavour of \*nix it's being run on and jump into a code path specific to that system. 8 | 9 | Unmodified the uul ELF binary has been tested to work on: 10 | 11 | - Linux 12 | - FreeBSD 13 | - OpenBSD 14 | - NetBSD 15 | - Dragonfly BSD 16 | - Haiku (BeOS successor) 17 | - Illumos (SunOS successor) 18 | 19 | Structurally the file is a standard ELF x86_64 binary with two additional mandatory sections 20 | '.note.openbsd.ident' for OpenBSD and '.note.netbsd.ident' for NetBSD. Additionally a .comment 21 | section is added with a reference to a GCC version to suppress warnings on Haiku. The OSABI field 22 | in the ELF header is set to 0x09 ("FreeBSD") allowing FreeBSD to load the file. 23 | 24 | The code exploits differences in syscall numbering to determine which system 'family' it's currently 25 | running on. 64 bit versions of Linux follow a different system call numbering to 64 bit versions of BSD/SunOS 26 | with 64 bit versions of Haiku having yet another, different system call numbering. We can use this as a gadget 27 | to work out what system family we're running on based on the return value of certain system calls. 28 | 29 | Firstly system call 12 is executed, this is create_sem on Haiku, chdir on \*BSD and brk on Linux. 30 | On Haiku create_sem will return a sem_id for the sem (for example 0x909) on BSD chdir will return 0 for 31 | success and on Linux brk will return the new value of the brk when called with a reasonable argument or the 32 | value of the existing brk in case of error (see the 'Linux notes' section of the brk(2) man page for the 33 | difference between the brk syscall, which works as described above, vs the glibc wrapper which may return 34 | values such as 0 or -1) 35 | 36 | In this PoC the first argument to syscall 12 points to the string '/tmp' as does the second argument. The 37 | return value from this system call is checked to see if it is less than 0xffff and if so we branch to a 38 | test for Haiku or BSD/Solaris. If the return value is greater than 0xffff we can enter the Linux code path as 39 | this appears to be the return value of brk rather than the Haiku sem_id or the BSD/SunOS chdir success value. 40 | Next we test to see if this is Haiku or BSD/Solaris by checking if the return value is zero - if it is greater 41 | than zero we enter the Haiku code path. Finally we determine if this is BSD or Solaris by attempting to chdir to 42 | /system which is (by default) a valid path on Solaris but not on BSD. 43 | 44 | Assemble on Linux with: 45 | ``` 46 | nasm -f elf64 -o uul.o uul.asm 47 | ld -o uul uul.o 48 | elfedit --output-osabi FreeBSD uul 49 | 50 | $ file uul 51 | uul: ELF 64-bit LSB executable, x86-64, version 1 (FreeBSD), statically linked, 52 | for OpenBSD, for NetBSD 2.0, not stripped 53 | 54 | ``` 55 | Linux 56 | ``` 57 | strace ./uul 58 | execve("./uul", ["./uul"], [/* 50 vars */]) = 0 59 | brk(0x600234) = 0x82b000 60 | write(1, "Linux\n", 6Linux 61 | ) = 6 62 | exit(42) 63 | ``` 64 | FreeBSD 65 | ``` 66 | root@freebsd:~ # ktrace /tmp/uul 67 | BSD 68 | root@freebsd:~ # kdump 69 | 755 ktrace RET ktrace 0 70 | 755 ktrace CALL execve(0x7fffffffee27,0x7fffffffebc0,0x7fffffffebd0) 71 | 755 ktrace NAMI "/tmp/uul" 72 | 755 uul RET execve JUSTRETURN 73 | 755 uul CALL chdir(0x600234) 74 | 755 uul NAMI "/tmp" 75 | 755 uul RET chdir 0 76 | 755 uul CALL chdir(0x60022c) 77 | 755 uul NAMI "/system" 78 | 755 uul RET chdir -1 errno 2 No such file or directory 79 | 755 uul CALL write(0x1,0x60023f,0x4) 80 | 755 uul GIO fd 1 wrote 4 bytes 81 | "BSD 82 | " 83 | 755 uul RET write 4 84 | 755 uul CALL exit(0x45) 85 | ``` 86 | OpenBSD 87 | ``` 88 | openbsd# ktrace /tmp/UUL 89 | BSD 90 | openbsd# kdump 91 | 84686 ktrace RET ktrace 0 92 | 84686 ktrace CALL execve(0x7f7fffff4def,0x7f7fffff4cf0,0x7f7fffff4d00) 93 | 84686 ktrace NAMI "/tmp/UUL" 94 | 84686 ktrace ARGS 95 | [0] = "/tmp/UUL" 96 | 84686 UUL RET execve 0 97 | 84686 UUL CALL chdir(0x600234) 98 | 84686 UUL NAMI "/tmp" 99 | 84686 UUL RET chdir 0 100 | 84686 UUL CALL chdir(0x60022c) 101 | 84686 UUL NAMI "/system" 102 | 84686 UUL RET chdir -1 errno 2 No such file or directory 103 | 84686 UUL CALL write(1,0x60023f,0x4) 104 | 84686 UUL GIO fd 1 wrote 4 bytes 105 | "BSD 106 | " 107 | 84686 UUL RET write 4 108 | 84686 UUL CALL exit(69) 109 | ``` 110 | NetBSD 111 | ``` 112 | # ktrace /tmp/uul 113 | BSD 114 | # kdump 115 | 147 1 ktrace EMUL "netbsd" 116 | 147 1 ktrace CALL execve(0x7f7fffbfa487,0x7f7fffbf9f18,0x7f7fffbf9f28) 117 | 147 1 ktrace NAMI "/tmp/uul" 118 | 147 1 uul EMUL "netbsd" 119 | 147 1 uul RET execve JUSTRETURN 120 | 147 1 uul CALL chdir(0x600234) 121 | 147 1 uul NAMI "/tmp" 122 | 147 1 uul RET chdir 0 123 | 147 1 uul CALL chdir(0x60022c) 124 | 147 1 uul NAMI "/system" 125 | 147 1 uul RET chdir -1 errno 2 No such file or directory 126 | 147 1 uul CALL write(1,0x60023f,4) 127 | 147 1 uul GIO fd 1 wrote 4 bytes 128 | "BSD\n" 129 | 147 1 uul RET write 4 130 | 147 1 uul CALL exit(0x45) 131 | ``` 132 | Dragonfly BSD 133 | ``` 134 | dfly# ktrace /tmp/uul 135 | BSD 136 | dfly# kdump 137 | 877:1 ktrace RET ktrace 0 138 | 877:1 ktrace CALL umtx_wakeup(0x80044ed80,0) 139 | 877:1 ktrace RET umtx_wakeup 0 140 | 877:1 ktrace CALL umtx_wakeup(0x80044ed80,0) 141 | 877:1 ktrace RET umtx_wakeup 0 142 | 877:1 ktrace CALL umtx_wakeup(0x80044ed80,0) 143 | 877:1 ktrace RET umtx_wakeup 0 144 | 877:1 ktrace CALL execve(0x7fffffdfdc17,0x7fffffdfd9d0,0x7fffffdfd9e0) 145 | 877:1 ktrace NAMI "/tmp/uul" 146 | 877:1 uul RET execve 0 147 | 877:1 uul CALL chdir(0x600234) 148 | 877:1 uul NAMI "/tmp" 149 | 877:1 uul RET chdir 0 150 | 877:1 uul CALL chdir(0x60022c) 151 | 877:1 uul NAMI "/system" 152 | 877:1 uul RET chdir -1 errno 2 No such file or directory 153 | 877:1 uul CALL write(0x1,0x60023f,0x4) 154 | 877:1 uul GIO fd 1 wrote 4 bytes 155 | "BSD 156 | " 157 | 877:1 uul RET write 4 158 | 877:1 uul CALL exit(0x45) 159 | ``` 160 | Haiku 161 | ``` 162 | ~> strace /tmp/uul 163 | [ 521] _kern_image_relocated(0x140b) (860 us) 164 | [ 521] _kern_set_area_protection(0x36fe, 0x5) = 0x0 No error (5 us) 165 | [ 521] _kern_create_sem(0x600234, "/tmp") = 0x1175 (2 us) 166 | Haiku 167 | [ 521] _kern_write(0x1, 0x0, 0x600249, 0x6) = 0x6 (6 us) 168 | [ 521] _kern_exit_thread(0x0) (2 us) 169 | ``` 170 | SunOS 171 | ``` 172 | root@openindiana:~# truss /tmp/uul. 173 | execve("/tmp/uul.", 0xFFFFFD7FFFDFB388, 0xFFFFFD7FFFDFB398) argc = 1 174 | chdir("/tmp") = 0 175 | chdir("/system") = 0 176 | SunOS 177 | write(1, " S u n O S\n", 6) = 6 178 | _exit(69) 179 | ``` 180 | 181 | Tested versions: 182 | ``` 183 | Linux - Ubuntu 20.04 LTS 184 | FreeBSD - FreeBSD 12.1-RELEASE r354233 GENERIC 185 | OpenBSD - OpenBSD 6.8 GENERIC#114 amd64 186 | NetBSD - NetBSD 8.1 (GENERIC) 187 | Dragonfly BSD - DragonFly v5.4.3-RELEASE (X86_64_GENERIC) 188 | Haiku - Haiku-r1-beta1 189 | Illumos - OpenIndiana Hipster-Minimal-20200504 190 | ``` 191 | Based on two earlier PoC: 192 | https://github.com/linuxthor/sixnix 193 | https://github.com/linuxthor/OpenLSD 194 | -------------------------------------------------------------------------------- /uul.asm: -------------------------------------------------------------------------------- 1 | BITS 64 2 | osabi 0x09 ; FreeBSD 3 | 4 | global _start 5 | _start: 6 | mov rax, 12 ; Haiku create_sem / BSD chdir / Linux brk 7 | mov rdi, tmp 8 | mov rsi, tmp 9 | syscall 10 | 11 | cmp rax, 0xffff 12 | jl maybe_haiku 13 | 14 | linux: 15 | mov rax, 1 ; Linux sys_write 16 | mov rdi, 1 17 | mov rsi, linz 18 | mov rdx, lbyte 19 | syscall 20 | 21 | mov rax, 60 ; Linux sys_exit 22 | mov rdi, 42 23 | syscall 24 | 25 | maybe_haiku: 26 | cmp rax, 1 27 | jl bors 28 | 29 | haiku: 30 | ; 31 | ; Haiku code 32 | ; 33 | mov rax, 144 ; Haiku 34 | mov rdi, 1 35 | mov rsi, 0 36 | mov rdx, hmsg 37 | mov r10, hlen 38 | syscall 39 | 40 | jmp hexit 41 | 42 | bors: 43 | ; 44 | ; SunOS code 45 | ; 46 | mov rdi, sunz 47 | mov rax, 12 ; chdir 48 | syscall 49 | 50 | cmp rax,0 51 | jne bsd 52 | 53 | mov rdi,1 54 | mov rsi,suno 55 | mov rdx,sunob 56 | mov rax,4 57 | syscall 58 | 59 | jmp bexit 60 | 61 | ; 62 | ; BSD code 63 | ; 64 | bsd: 65 | mov rdi,1 66 | mov rsi,obsd 67 | mov rdx,obyte 68 | mov rax,4 ; sys_write 69 | syscall 70 | 71 | bexit: 72 | mov rdi,69 73 | mov rax,1 ; sys_exit 74 | syscall 75 | 76 | hexit: 77 | mov rdi, 0 78 | mov rax, 56 79 | syscall 80 | 81 | section .data 82 | sunz db '/system',0 83 | tmp db '/tmp',0 84 | suno db 'SunOS',0x0a 85 | sunob equ $-suno 86 | obsd db 'BSD',0x0a 87 | obyte equ $-obsd 88 | linz db 'Linux',0x0a 89 | lbyte equ $-linz 90 | hmsg db 'Haiku',0x0a 91 | hlen equ $-hmsg 92 | 93 | section .note.openbsd.ident 94 | align 2 95 | dd 8 96 | dd 4 97 | dd 1 98 | db 'OpenBSD',0 99 | dd 0 100 | align 2 101 | 102 | section .note.netbsd.ident 103 | dd 7,4,1 104 | db 'NetBSD',0 105 | db 0 106 | dd 200000000 107 | 108 | section .comment 109 | db 0,"GCC: (GNU) 4.2.0",0 ; Haiku 110 | 111 | --------------------------------------------------------------------------------