1

Here's my shellcode:

    xor rax, rax
    xor rdi, rdi
    xor rsi, rsi
    xor rdx, rdx

    ; getting address of `pathname`
    mov rdi, [something]
    mov al, 59
    mov rdi, rsp
    syscall

    xor rax,rax
    mov al, 60
    xor rdi, rdi
    syscall

_pathname:
    db "/usr/bin/shutdown",0

Simple execve and exit, that's all. The problem is that I can't get the absolute address in order to access pathname. The "solution" to this, that I have found, is rigging the code something like this:

call _end

_start:
    pop rdi ; absolute address of _start
    ; then add bytes to get to address of _end

_end:
    call start
    db "/usr/bin/shutdown", 0

This never made sense to me, and it didn't work. I also tried using FPU instructions, which were supposed to work as well, but they didn't work either.

Anybody have a solution?

OS: Linux
Architecture: amd64

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
R-Rothrock
  • 303
  • 2
  • 14

1 Answers1

3

On x86-64 you have RIP-relative addressing modes, so you should be able to simply do lea rdi, [rel _pathname]. The assembler computes the displacement between the address of the current instruction (or actually the next one) and the label _pathname, and encodes it into the instruction. At runtime this displacement is added to rip and the result placed in rdi.

x86-32 doesn't have relative addressing modes, so in 32-bit mode, your call/pop trick is the standard way to accomplish this, despite being awkward. And it does work in 64-bit mode too. But the address popped by pop rdi isn't the address of _start; rather it's the return address pushed by the call _start instruction, i.e. the address of the byte following the call _start instruction. In this case it is exactly the first byte of your /usr/bin/shutdown string, so in fact you wouldn't have to add anything.

Note that you are passing a null pointer as the argv and envp arguments to execve. This is legal for the kernel, but the shutdown program is probably not expecting this and it may crash upon startup. So you might have to do some more work to construct a minimal argument vector with argv[0] == "shutdown" at least.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • 4
    Note that shellcode needs to be free of `00` bytes, so `[RIP+rel32]` is only usable with negative displacements (or with some large constant added that you subtract from the final address, like `lea rdi, [rel foo + 0x01010101]` / `sub rdi, 0x01010101` as in [Avoiding 0xFF bytes in shellcode using CALL to read RIP?](https://stackoverflow.com/a/55783375)) Without trickery, this means your code has to be after the string so you need to `jmp` over it, and it can't have a terminating 0. – Peter Cordes Jul 04 '23 at 16:36
  • 1
    The jmp/call/pop trick is more compact, and the backwards `call` makes the rel32 negative. (The OP used `call _end` instead of `jmp _end` which breaks this trick because there's no `call rel8`; the forward `call` will have zeros in the `call rel32` encoding.) – Peter Cordes Jul 04 '23 at 16:42
  • @NateEldredge `execve("\1", NULL, NULL) = -1 ENOENT (No such file or directory)` from `strace` when using `lea rdi, [rel _pathname + 0x69696969]` and `sub rdi, 0x69696969`. Any more wisdom? – R-Rothrock Jul 04 '23 at 18:08
  • 1
    @R-Rothrock: It works for me. You did remember to remove the `mov rdi, rsp` right? Otherwise please post a [mcve] of the code you are testing. – Nate Eldredge Jul 04 '23 at 20:07
  • @R-Rothrock: `"\1"` as the path could be the result of doing `mov rdi, rsp` while RSP was still pointing to `argc` (which it does in the Linux process-startup state.) BTW, `_start` is a very bad choice of label name if you're going to put code ahead of it. If you did `global _start`, the linker would set the process entry point to `_start`, so execution would start there, instead of at the top of the text section (`ld`'s default if there's no exported `_start` symbol.) – Peter Cordes Jul 04 '23 at 20:24
  • @PeterCordes I know, I didn't paste the whole file. And yes. I forgot to remove the `mov rdi, rsp` line. Many thanks. – R-Rothrock Jul 05 '23 at 14:17