段错误错误6;无法访问操作码字节

问题描述 投票:0回答:1

我正在尝试了解一些有关二进制利用的知识,并且正在构建一个最小的沙箱供我进行实验,但我遇到了一个奇怪的问题。考虑这个 main.c:

// cat > main.c ; make main
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>
#include <unistd.h>

int main()
{
        void (*f)(void);
        char * buf = mmap (0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        int fd = socket(AF_INET, SOCK_STREAM, 0);
        struct addrinfo* sa = malloc(sizeof(struct addrinfo));
        sa->ai_family = AF_INET;
        sa->ai_flags = 0;
        sa->ai_socktype = SOCK_STREAM;
        sa->ai_protocol = 0;

        int ret = getaddrinfo("localhost", "31337",  NULL, &sa);

        // printf("getaddrinfo: %d\n", ret);

        sa->ai_addr->sa_family = AF_INET;

        ret = connect(fd, sa->ai_addr, sa->ai_addrlen);

        // printf("connect: %d\n", ret);
        // perror("connect");
        read(fd, buf, sizeof(buf));
        // printf("buf: %s\n", buf);
        f = buf;
        f();
}

还有这个 elo.asm:

; cat > elo.asm ; 
bits 64
xor eax, eax
inc eax
mov bh, 4
int 0x80

我跑

ncat -k -l --sh-exec "nasm elo.asm  -o /dev/stdout"
,然后
./main
。这可以工作并以看似随机的退出代码退出。当我用
mov bh, 4
替换
mov ebx, 4
时,问题就出现了。这会产生
Segmentation fault
,后跟以下
dmesg
消息:

[20096.076031] main[60973]: segfault at 1 ip 00007f6a8ad4f009 sp 00007ffcc6bce518 error 6 likely on CPU 4 (core 4, socket 0)
[20096.076039] Code: Unable to access opcode bytes at 0x7f6a8ad4efdf.

那是什么?我该如何诊断?我缺少一些填充吗?

c linux security assembly x86
1个回答
0
投票

问题是我试图读取 sizeof(buf),这是我在更改 buf 的构造方式时不小心留下的东西。除了更好的错误检查之外,这里还有代码的工作版本:

/*
This program demonstrates a simple example of a remote code execution
vulnerability. The program connects to a remote server, reads a buffer from
the server and executes it.

To test it, create the following elo.asm file:

    bits 64      ; 64-bit mode
    xor eax, eax ; zero out eax
    inc eax      ; eax = 1
    mov ebx, 4   ; syscall number for sys_exit
    int 0x80     ; call sys_exit

Then set up a server that serves the shellcode, for example:

    ncat -p 31337 -k -l --sh-exec "nasm elo.asm  -o /dev/stdout"

Then run the program and it will execute the shellcode.

WARNING: This program is vulnerable to remote code execution and should not be
used in production. It is only for educational purposes.

*/


#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>

#define BUF_SIZE 4096

int main()
{

        // Let's allocate a buffer with read, write and execute permissions.
        // This way we can write the shellcode to the buffer and execute it.
        // We explicitly set PROT_EXEC to allow the buffer to be executed,
        // bypassing W^X protection.
        char * buf = mmap (0, BUF_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        if (buf == MAP_FAILED) {
                perror("mmap");
                exit(1);
        }

        // Create a socket. This can fail if e.g. the system is out of file
        // descriptors.
        int fd = socket(AF_INET, SOCK_STREAM, 0);
        if (fd == -1) {
                perror("socket");
                exit(1);
        }

        // Allocate a struct addrinfo and set the fields to connect to the
        // server. This can fail if e.g. the system is out of memory.
        struct addrinfo* sa = malloc(sizeof(struct addrinfo));
        if (sa == NULL) {
                perror("malloc");
                exit(1);
        }
        sa->ai_family = AF_INET;
        sa->ai_flags = 0;
        sa->ai_socktype = SOCK_STREAM;
        sa->ai_protocol = 0;
        sa->ai_addr->sa_family = AF_INET;

        // Resolve the address of the server. This can fail if e.g. the address
        // is not found.
        int ret = getaddrinfo("localhost", "31337",  NULL, &sa);
        if (ret != 0) {
                perror("getaddrinfo");
                exit(1);
        }

        // Connect to the server. This can fail if e.g. the server is not
        // reachable.
        ret = connect(fd, sa->ai_addr, sa->ai_addrlen);
        if (ret == -1) {
                perror("connect");
                exit(1);
        }

        // Read the shellcode from the server. This can fail if e.g. the server
        // disconnects.
        ret = read(fd, buf, BUF_SIZE);
        if (ret == -1) {
                perror("read");
                exit(1);
        }

        // Execute the shellcode. We cast the buffer to a function pointer and
        // call it. If this fails, the shellcode is likely invalid.
        void (*f)(void);
        f = buf;
        f();
}
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.