yrp604 / rappel

A linux-based assembly REPL for x86, amd64, armv7, and armv8
Other
1.16k stars 55 forks source link

Fail to execute #2

Open HalosGhost opened 8 years ago

HalosGhost commented 8 years ago

When I try to execute any instruction (for example, inc rax), I get the following output before the list of registers (which do not change).

ptrace() - failed to write value 0xccccccccccc0ff48 to 0x0000000000400000

When executing with -v, I get the following:

Trying to assemble(8):
inc rax
@nasm is pid 6057
Process 6057 has exited with status 0
Got asm(3):
48 ff c0                                                H..
ptrace_write: 0x0000000000400000 = 0xccccccccccc0ff48
ptrace() - failed to write value 0xccccccccccc0ff48 to 0x0000000000400000

I am wondering if this is because of Grsec's PaX, but if it is, there was nothing registered in dmesg as there usually is. Any idea what might be going wrong?

yrp604 commented 8 years ago

Hm, what is kernel.grsecurity.harden_ptrace? Alternatively if you run it as root, does it work?

According to the docs that sysctl shouldn't affect ptrace in this case (because the tracee is a child process of the tracer) but Im curious. If it's enabled, does disabling it make the problem go away?

When you run it verbosely, it should give you the child pid. Does that process still exist after the failed write?

What does '.read 0x400000 1' return? (from inside rappel).

I don't have a grsec machine handy at the moment, but will get one spun up after the weekend if we still can't resolve it.

HalosGhost commented 8 years ago

kernel.grsecurity.harden_ptrace is 1. Running rappel as root did not fix the issue. Changing that sysctl value to 0 had no effect. the PIDs appear to be gone afterward (no zombies afaict), and .read 0x400000 1 returned the following: 0x0000000000400000: cc

This seems like a really cool project, so I'll be excited to test it if the issue can be solved.

yrp604 commented 8 years ago

Hm, can you try a patch for me?

diff --git a/elf_amd64.c b/elf_amd64.c
index 546841c..52ef9f1 100644
--- a/elf_amd64.c
+++ b/elf_amd64.c
@@ -74,7 +74,7 @@ const size_t gen_elf_amd64(
        Elf64_Phdr *const phdr = (Elf64_Phdr *) ((uint8_t *) e + sizeof(Elf64_Ehdr));

        phdr->p_type = PT_LOAD;
-       phdr->p_flags = PF_X | PF_R;
+       phdr->p_flags = PF_X | PF_R | PF_W;
        phdr->p_offset = PAGE_SIZE;
        phdr->p_vaddr = start - pg_align_dist;
        phdr->p_paddr = 0;
HalosGhost commented 8 years ago

that resulted in a hang and an eventual throw of a similar ptrace error. However, a new message shows up in dmesg as a result (it made PaX angry):

[302058.373172] grsec: denied RWX mmap of /home/halosghost/.rappel/rappel-exec.VuEudR by /home/halosghost/.rappel/rappel-exec.VuEudR[3:20588] uid/euid:1000/1000 gid/egid:1000/1000, parent /home/halosghost/prj/rappel/bin/rappel[rappel:20587] uid/euid:1000/1000 gid/egid:1000/1000
[302058.373271] PAX: execution attempt in: (null), 00000000-00000000 00000000
[302058.373274] PAX: terminating task: (null)(3):20588, uid/euid: 1000/1000, PC: 0000036257e64a37, SP: 000003cbad98a248
[302058.373287] PAX: bytes at PC: ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??
[302058.373307] PAX: bytes at SP-8: ???????????????? ???????????????? ???????????????? ???????????????? ???????????????? ???????????????? ???????????????? ???????????????? ???????????????? ???????????????? ????????????????
[302058.373323] grsec: bruteforce prevention initiated for the next 30 minutes or until service restarted, stalling each fork 30 seconds.  Please investigate the crash report for /home/halosghost/prj/rappel/bin/rappel[3:20588] uid/euid:1000/1000 gid/egid:1000/1000, parent /home/halosghost/prj/rappel/bin/rappel[rappel:20587] uid/euid:1000/1000 gid/egid:1000/1000

I gave a shot to setting PaX to give rappel RWX rights, but the same message showed up.

yrp604 commented 8 years ago

Ok, I think I know whats happening.

Rappel creates an elf runs it, and rewrites it at runtime to include the result of assembled instructions. The text segment of the created elf, by default is read/execute. Normally ptrace can write to read/execute pages, because its ptrace and it doesn't really care what memory protections the tracee thinks it has. You can see some evidence of this -- the ptrace_read() call works, but the ptrace_write() fails. Im guessing this is because PaX hardens memory accesses.

The patch I gave you changed the generated elf to map the text section RWX. My guess is this would remove the ptrace_write() error, but PaX kills it, probably due to MPROTECT.

I'll poke at it it next week in depth and confirm this, but if this is fact the reason I don't see an easy way around it. The benefits MPROTECT provides are solid, and probably outweighs the utility of using rappel.

fwiw you should still be able to use it in pipe mode, right? i.e 'echo "inc rax; inc rax" | rappel' works?

HalosGhost commented 8 years ago

Fair enough! running through a pipe outputs without any ptrace error and does not hang. However, it does not reflect the execution of the instructions passed (e.g., rax is not incremented at all from the line you mention. It also finishes with the following:

Process died with signal: 9
Exited: 9
yrp604 commented 8 years ago

Man, I really need to test with grsec. Thanks for the report, and sorry it's been such a hassle. Will let you know when I understand a bit more whats going on.

HalosGhost commented 8 years ago

No worries, and thank you for the help!

yrp604 commented 8 years ago

So two months later I finally got around to figuring this out. This is controlled by PAX_MPROTECT (https://pax.grsecurity.net/docs/mprotect.txt).

Honestly, having PAX_MPROTECT is probably better than running rappel in interactive mode. Now to figure out why the pipe mode doesn't work...

In any case, thanks a lot for the report. I'll update the readme to indicate that it's not supported under grsec.

HalosGhost commented 8 years ago

Well, PaX is an optional extension, so it'd be unsupported under PaX, not grsec. However, PaX allows configuration to specifically whitelist particular applications. I am happy to do so for rappel, because this is such a cool tool. Rather, I would recommend documenting whitelisting rappel in /etc/paxd.conf.