0

I wrote a program that run some code on the stack without having execution permission on the stack. And before I run the program execute: trap '' SIGSEGV to ensure the program will ignore the signal.

    lqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk
   x0x80486be <_IO_stdin_used+2>    add    (%eax),%al                          x
   x0x80486c0                       mov    $0x12d687,%eax                      x
   x0x80486c5                       mov    $0x12d687,%eax                      x
   x0x80486ca                       mov    $0x12d687,%eax                      x
   x0x80486cf                       mov    $0x12d687,%eax                      x
   x0x80486d4                       add    %ah,0x6c(%esi)                      x
   x0x80486d7                       popa                                       x
   x0x80486d8                       addr16 je,pn 0x8048754                     x
   x0x80486dc                       je     0x80486de                           x
  >x0x80486de                       outsl  %ds:(%esi),(%dx)                    x
   x0x80486df                       jo     0x8048746                           x
   x0x80486e1                       outsb  %ds:(%esi),(%dx)                    x
   x0x80486e2                       and    %ah,0x69(%esi)                      x
   x0x80486e5                       insb   (%dx),%es:(%edi)                    x
   x0x80486e6                       add    %dh,%gs:0x65(%edx)                  x
   x0x80486ea                       popa                                       x
   x0x80486eb                       and    %ah,%fs:0x69(%esi)                  x
   x0x80486ef                       insb   (%dx),%es:(%edi)                    x
   mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj
native process 225742 In:                                   L??   PC: 0x80486de
(gdb) info register eax
eax            0x12d687 1234567
(gdb) si
0x080486d7 in ?? ()
0x080486d8 in ?? ()
0x080486dc in ?? ()
0x080486de in ?? ()

Program received signal SIGSEGV, Segmentation fault.
0x080486de in ?? ()
(gdb)

I know that outsl required higher privileged level and that's why the process terminate. what I don't understand is why the code terminate by SIGSEGV and not another way? because if it will terminate this way it will suppose to ignore the SIGSEGV. In addition I don't understand how the code indeed run on the stack. I thought it will just ignore the signal and skip each instruction in the assembly but the value of eax indeed changed.

checksec child.o
[*] '/tmp/nadav_tiny_hard/child.o'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
// code.c

#include <sys/syscall.h>
#include <sys/user.h>
#include <sys/reg.h>
#include <fcntl.h>


// execute mov eax, 1234567 four times. (not return or finish after that, continue to execute bullshit bits)
unsigned char *shellcode = "\xB8\x87\xD6\x12\x00\xB8\x87\xD6\x12\x00\xB8\x87\xD6\x12\x00\xB8\x87\xD6\x12\x00";

int main()
{
    setvbuf(stdout, 0, 2, 0);
    int (*ret)() = (int(*)())shellcode;
    ret();

    return 0;
}

EDIT:

$ ./code
Segmentation fault (core dumped)

don't know how to check which instruction makes the abort, and I would like to know how to survive sigsegv without terminating immediately, for the purpose of using ptrace.

EDIT2:

according to Hyde isn't it strange that my program called just one time strace and not endless number of time?

$ strace ./code
--- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)
...

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Possibly related: https://stackoverflow.com/questions/8456085/why-cant-i-ignore-sigsegv-signal – hyde Nov 04 '22 at 14:20
  • 1
    Have you tried running under debugger, in disassembly mode? – hyde Nov 04 '22 at 14:20
  • @hyde this question seem very intresting. according to the gdb my program don't stop in the same instruction moreover it execute them, so maybe it just something the gdb do that handle the sigsegv and continue to the next instruction? don't understand what do you mean by "disassembly mode"? – nadav levin Nov 04 '22 at 14:42
  • Well, in *gdb* you might try `stepi` command, for instance. – hyde Nov 04 '22 at 15:22
  • yes I did, used alias si if any matter – nadav levin Nov 04 '22 at 15:33
  • Are you hoping that your string literal will be in an executable page? That might be the case on an old enough Linux kernel, if you compiled with `gcc -m32 -zexecstack` so it uses READ_IMPLIES_EXEC. Or with an old gcc/binutils which puts `.rodata` in the same ELF program segment as `.text`. Modern `ld` puts `.rodata` in pages with read but not exec permission, to reduce the available "gadgets" for ROP and Spectre attacks. See [How to get c code to execute hex machine code?](https://stackoverflow.com/q/9960721) – Peter Cordes Nov 04 '22 at 19:59
  • 1
    Are you sure SIGSEGV can be ignored? The man page for `sigaction` says it returns `EINVAL` if you try to "ignore a signal that cannot be ignored". – Peter Cordes Nov 04 '22 at 20:00
  • 1
    Related: [Why can't I ignore SIGSEGV signal?](https://stackoverflow.com/q/8456085) - but some answers there incorrect state that you'd get an infinite loop of faulting if you did this. In practice you don't, as the question shows you *do* get a SIGSEGV despite `signal` not returning an error when setting it to SIG_IGN. It is true that you wouldn't expect ignoring SIGSEGV to let execution get *past* a faulting instruction, just endlessly retrying it same as if you installed a do-nothing handler that just returned without repairing the situation. – Peter Cordes Nov 04 '22 at 20:22

0 Answers0