0

I currently got interested in binary exploitation (even though I do not know if today is still useful).

I started studying shellcode and buffer overflow (stack-buffer overflow, specifically). I know that this vulnerability is nowadays rare, but I still want to lean how to perform it (I have to start somewhere). So I wrote this shellcode:

 section .text
    global _start

_start:

    xor rdx, rdx
    push rdx
    mov rax, 0x68732f2f6e69622f
    push rax
    mov rdi, rsp
    push rdx
    push rdi
    mov rsi, rsp
    xor rax, rax
    mov al, 0x3b
    syscall

and a C program to execute it:

char shellcode[] = "\x48\x31\xd2\x52\x48\xb8\x2f\x62\x69\x6e\x2f\x73\x68\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x48\x31\xc0\xb0\x3b\x0f\x05";
int main(){
    void(*f)() = (void(*)())shellcode;
    f();
    return 0;
}

Though when I run it, I got SIGSEGV error.

This is what I get when I use strace:

execve("./exec", ["./exec"], 0x7ffe855b4e80 /* 57 vars */) = 0
brk(NULL)                               = 0x55f5dd4d6000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffcceb7b7b0) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f913a4c2000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=81189, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 81189, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f913a4ae000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P<\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2072888, ...}, AT_EMPTY_PATH) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2117488, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f913a200000
mmap(0x7f913a222000, 1540096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7f913a222000
mmap(0x7f913a39a000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19a000) = 0x7f913a39a000
mmap(0x7f913a3f2000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1f1000) = 0x7f913a3f2000
mmap(0x7f913a3f8000, 53104, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f913a3f8000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f913a4ab000
arch_prctl(ARCH_SET_FS, 0x7f913a4ab740) = 0
set_tid_address(0x7f913a4aba10)         = 5515
set_robust_list(0x7f913a4aba20, 24)     = 0
rseq(0x7f913a4ac060, 0x20, 0, 0x53053053) = 0
mprotect(0x7f913a3f2000, 16384, PROT_READ) = 0
mprotect(0x55f5dc905000, 4096, PROT_READ) = 0
mprotect(0x7f913a4f7000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0x7f913a4ae000, 81189)           = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0x55f5dc906010} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)

This is what I get running the program using GBD (peda):

RAX: 0x0 
RBX: 0x7fffffffde88 --> 0x7fffffffe1e7 ("/home/mastermind/Desktop/Hydrogen/shellcode/exec")
RCX: 0x555555557df8 --> 0x5555555550e0 (<__do_global_dtors_aux>:    endbr64)
RDX: 0x555555558010 --> 0x622fb84852d23148 
RSI: 0x7fffffffde88 --> 0x7fffffffe1e7 ("/home/mastermind/Desktop/Hydrogen/shellcode/exec")
RDI: 0x1 
RBP: 0x7fffffffdd70 --> 0x1 
RSP: 0x7fffffffdd58 --> 0x55555555514b (<main+34>:  mov    eax,0x0)
RIP: 0x555555558010 --> 0x622fb84852d23148 
R8 : 0x0 
R9 : 0x7ffff7fccfb0 (<_dl_fini>:    endbr64)
R10: 0x7ffff7fc88e8 --> 0xb00120000000e 
R11: 0x7ffff7fe1480 (<_dl_audit_preinit>:   endbr64)
R12: 0x0 
R13: 0x7fffffffde98 --> 0x7fffffffe217 ("SHELL=/bin/bash")
R14: 0x555555557df8 --> 0x5555555550e0 (<__do_global_dtors_aux>:    endbr64)
R15: 0x7ffff7ffd000 --> 0x7ffff7ffe2c0 --> 0x555555554000 --> 0x10102464c457f
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x555555558009:  adc    BYTE PTR [rbp+0x55],0x55
   0x55555555800d:  push   rbp
   0x55555555800e:  add    BYTE PTR [rax],al
=> 0x555555558010 <shellcode>:  xor    rdx,rdx
   0x555555558013 <shellcode+3>:    push   rdx
   0x555555558014 <shellcode+4>:    movabs rax,0x5068732f6e69622f
   0x55555555801e <shellcode+14>:   mov    rdi,rsp
   0x555555558021 <shellcode+17>:   push   rdx
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdd58 --> 0x55555555514b (<main+34>: mov    eax,0x0)
0008| 0x7fffffffdd60 --> 0x0 
0016| 0x7fffffffdd68 --> 0x555555558010 --> 0x622fb84852d23148 
0024| 0x7fffffffdd70 --> 0x1 
0032| 0x7fffffffdd78 --> 0x7ffff7c23a90 (<__libc_start_call_main+128>:  mov    edi,eax)
0040| 0x7fffffffdd80 --> 0x7fffffffde70 --> 0x7fffffffde78 --> 0x38 ('8')
0048| 0x7fffffffdd88 --> 0x555555555129 (<main>:    endbr64)
0056| 0x7fffffffdd90 --> 0x155554040 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000555555558010 in shellcode ()

Can you please help me figure out what the problem is here? I have tried countless times, changing the shellcode, analysing the program using GDB, but still the memory segmentation error present itself. If I am not able to execute the shellcode, I am not even able to exploit the stack-overflow vulnerability.

Thanks in advance for any useful answer.

Just as a side note:

  1. I compiled the program using: gcc -m64 -fno-stack-protector -z execstack -o exec exec.c

  2. Got the shellcode using objdump

2
  • Can you show the registry values at the time of the segfault? What error do you get when you run the program under strace ?
    – wireghoul
    Commented Jul 26, 2023 at 2:03
  • Edited the question, thanks for your help, in case Commented Jul 26, 2023 at 7:32

1 Answer 1

0

The strace shows that the crash is caused by a object access error (SEGV_ACCERR):

--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0x55f5dc906010} ---

This appear to be mix of of the compiler/crash handling that I am not familiar with and your code. You set the stack to executable, but your shellcode is living at 0x55f5dc906010. In gdb you can see that the stack is at 0x7f....

0000| 0x7fffffffdd58 --> 0x55555555514b (<main+34>: mov    eax,0x0)
0008| 0x7fffffffdd60 --> 0x0 
0016| 0x7fffffffdd68 --> 0x555555558010 --> 0x622fb84852d23148 
0024| 0x7fffffffdd70 --> 0x1 
0032| 0x7fffffffdd78 --> 0x7ffff7c23a90 (<__libc_start_call_main+128>:  mov    edi,eax)
0040| 0x7fffffffdd80 --> 0x7fffffffde70 --> 0x7fffffffde78 --> 0x38 ('8')
0048| 0x7fffffffdd88 --> 0x555555555129 (<main>:    endbr64)
0056| 0x7fffffffdd90 --> 0x155554040 

So you would need to put your code on the stack and execute it or change the memory permissions on the memory that contains your global shellcode variable.

When you're compiling exploit proofs you may also want to disable PIE (-no-pie) and source fortification (-U_FORTIFY_SOURCE).

You can however, still verify your shellcode other ways. This is my preferred process (using nasm). I put your assembly code into a file called t.asm and run this command which compiles, links and runs the code:

nasm -felf64 t.asm && ld t.o && ./a.out
$

And then you can get the bytes of the disassembly using objdump as you would otherwise:

objdump -M intel -d a.out

a.out:     file format elf64-x86-64


Disassembly of section .text:

0000000000401000 <_start>:
  401000:       48 31 d2                xor    rdx,rdx
  401003:       52                      push   rdx
  401004:       48 b8 2f 62 69 6e 2f    movabs rax,0x68732f2f6e69622f
  40100b:       2f 73 68
  40100e:       50                      push   rax
  40100f:       48 89 e7                mov    rdi,rsp
  401012:       52                      push   rdx
  401013:       57                      push   rdi
  401014:       48 89 e6                mov    rsi,rsp
  401017:       48 31 c0                xor    rax,rax
  40101a:       b0 3b                   mov    al,0x3b
  40101c:       0f 05                   syscall
1
  • Thanks for your help, but, if I verify the shellcode simply executing into the terminal I am not sure if I can execute it inside the stack, hence if the stack-base overflow exploitation will be successful. So far it hasn't been at all. Even if I disable ASLR and NX still the OS manage to get segmentation fault without executing the injected code (I am on a x86_64 arch) Commented Jul 27, 2023 at 4:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .