david942j / one_gadget

The best tool for finding one gadget RCE in libc.so.6
MIT License
2.07k stars 139 forks source link

Enhance the constraints for `argv` and `envp` #206

Closed lebr0nli closed 1 year ago

lebr0nli commented 1 year ago

Before this PR, one_gadget can't handle argv and envp well, especially when argv is on the stack.


For example, with libc 2.37 from http://archive.ubuntu.com/ubuntu/pool/main/g/glibc//libc6_2.37-0ubuntu2_amd64.deb, one_gadget might found the gadget like this:

截圖 2023-07-08 下午7 02 02

But this is not true, the disassembly of this gadget is something like:

e2f95: 49 c7 47 10 00 00 00 mov QWORD PTR [r15+0x10],0x0
e2f9c: 00
e2f9d: 4c 89 ea mov rdx,r13
e2fa0: 4c 89 fe mov rsi,r15
e2fa3: 48 89 cf mov rdi,rcx
e2fa6: e8 75 f5 ff ff call e2520 <execve>
...
...
e3219: 48 8d 0d b2 1f 0d 00 lea rcx,[rip+0xd1fb2] # 1b51d2 <not_available+0x174>
e3220: 4c 89 65 b8 mov QWORD PTR [rbp-0x48],r12
e3224: 4c 8d 7d b0 lea r15,[rbp-0x50]
e3228: 48 89 4d b0 mov QWORD PTR [rbp-0x50],rcx
e322c: e9 64 fd ff ff jmp e2f95 <execvpe+0x275>

So there are several problems:

  1. [rbp-0x50] doesn't need to be NULL, because it will eventually be set to rip+0xd1fb2(the address of "/bin/sh"). In addition, rbp-0x50 cannot be NULL because rbp-0x50 should be writable.
  2. When execve is called, its argv will be [rbp-0x50]. [rbp-0x50] will be set to the address of "/bin/sh", [rbp-0x48] will be set to r12, and [rbp-0x40] will be set to NULL. So the correct constraint is that r12 need to be NULL or somehow {"/bin/sh", r12, NULL} is a valid argv (e.g. r12 points to address of "-").
  3. When execve is called, r13 will become its envp. But [r13] or r13 doesn't always need to be NULL. Actually, the content of envp is not very important most of the time, if it's not NULL, we just need to make sure it's pointing to a readable address with some continuous readable addresses inside it that make r13 can become a valid envp.

After this PR, one_gadget will find the correct constraints for this gadget and show more useful information:

截圖 2023-07-08 下午12 56 25

More before/after for the libc in http://archive.ubuntu.com/ubuntu/pool/main/g/glibc//libc6_2.37-0ubuntu2_amd64.deb:

^ Similar to the first example, [rbp-0x50] is not control by user, the correct constraints are rax == NULL or {"/bin/sh", rax, NULL} is a valid argv.

^ By showing more details, users can easier know that if they can control [rsp+0x70] to store a readable address(since sh won't bother by weird argv[0]) and luckily [rsp+0x78] is NULL, they can spawn the shell.


Not very sure if this PR fully fixes the problem that #120 mentioned, but hopefully it should at least fix the case when argv is on the stack for x86 libc. Also, the enhancements and fixes introduced by this PR still have some TODOs (I mentioned them in the comment, e.g. the scoring parts). Currently, I don't have a good idea for resolving them, let me know if you have any ideas that I can improve in this PR. (Or maybe we can just leave them for now and fix them in another PR if they don't affect too much :p)

david942j commented 1 year ago

Thanks for this nice enhancement!

I haven't looked into the implementation yet, but you may want to resolve the tests failure first: https://github.com/david942j/one_gadget/actions/runs/5506576476/job/15242511295

Because your changes there seem to be more gadgets found.

lebr0nli commented 1 year ago

I haven't looked into the implementation yet, but you may want to resolve the tests failure first:

Ok, done. I updated the tests and also fixed a bug I found while I examined some of the gadgets. Please let me know if anything is missing!

david942j commented 1 year ago

Merged, thanks a lot for the contribution!

lebr0nli commented 11 months ago

This patch seemed to work well during the recent CTF challenge I played, and I have actually seen someone fail to solve the challenge because they get misled by the old version one_gadget lol. Should we bump the version or maybe make a beta release?

Also seems we need to update the gadgets/constraints saved on the remote(?), seems like I still need to add a -f flag to avoid one_gadget fetching the wrong constraints from the remote sometimes.

I can probably help if I have some time(if needed :p), could you give me some guides to helping maintain these? Thanks!

david942j commented 11 months ago

remote actually means on github, let me do the update and release a new version

david942j commented 11 months ago

v1.9.0 released

lebr0nli commented 11 months ago

Thanks!