david942j / one_gadget

The best tool for finding one gadget RCE in libc.so.6

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Version 1.8.0 defaults to posix_spawn gadgets

0x4d5a-ctf opened this issue · comments

Seems like version 1.8.0 prefers the posix_spawn gadgets and does not list execve-gadgets with default output-level 0. Those posix_spawn gadgets have much harder contraints and shouldn't be displayed instead of the easier execve-gadgets.

Tests were conducted on the libc of the Ubuntu Docker: FROM ubuntu@sha256:a02c32cf0c2a7e8743c74deef66637aa70e063c9bd40e9e1f8c0b3ea0750b0ba

/usr/lib/x86_64-linux-gnu/libc.so.6: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=89c3cb85f9e55046776471fed05ec441581d1969, for GNU/Linux 3.2.0, stripped

Output with one_gadget 1.7.4:

root@ecb44960ff3e:/home/ctf# one_gadget --version
OneGadget Version 1.7.4
root@ecb44960ff3e:/home/ctf# one_gadget /usr/lib/x86_64-linux-gnu/libc.so.6
0xebcf1 execve("/bin/sh", r10, [rbp-0x70])
constraints:
  address rbp-0x78 is writable
  [r10] == NULL || r10 == NULL
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL

0xebcf5 execve("/bin/sh", r10, rdx)
constraints:
  address rbp-0x78 is writable
  [r10] == NULL || r10 == NULL
  [rdx] == NULL || rdx == NULL

0xebcf8 execve("/bin/sh", rsi, rdx)
constraints:
  address rbp-0x78 is writable
  [rsi] == NULL || rsi == NULL
  [rdx] == NULL || rdx == NULL

Output with 1.8.0:

root@ecb44960ff3e:/home/ctf# gem install one_gadget --version 1.8.0
Fetching one_gadget-1.8.0.gem
Successfully installed one_gadget-1.8.0
Parsing documentation for one_gadget-1.8.0
Installing ri documentation for one_gadget-1.8.0
Done installing documentation for one_gadget after 3 seconds
1 gem installed
root@ecb44960ff3e:/home/ctf# one_gadget --version
OneGadget Version 1.8.0
root@ecb44960ff3e:/home/ctf# one_gadget /usr/lib/x86_64-linux-gnu/libc.so.6
0x50a37 posix_spawn(rsp+0x1c, "/bin/sh", 0, rbp, rsp+0x60, environ)
constraints:
  rsp & 0xf == 0
  rcx == NULL
  rbp == NULL || (u16)[rbp] == NULL

0x10dbc2 posix_spawn(rsp+0x64, "/bin/sh", [rsp+0x40], 0, rsp+0x70, [rsp+0xf0])
constraints:
  [rsp+0x70] == NULL
  [[rsp+0xf0]] == NULL || [rsp+0xf0] == NULL
  [rsp+0x40] == NULL || (s32)[[rsp+0x40]+0x4] <= 0

0x10dbca posix_spawn(rsp+0x64, "/bin/sh", [rsp+0x40], 0, rsp+0x70, r9)
constraints:
  [rsp+0x70] == NULL
  [r9] == NULL || r9 == NULL
  [rsp+0x40] == NULL || (s32)[[rsp+0x40]+0x4] <= 0

0x10dbcf posix_spawn(rsp+0x64, "/bin/sh", rdx, 0, rsp+0x70, r9)
constraints:
  [rsp+0x70] == NULL
  [r9] == NULL || r9 == NULL
  rdx == NULL || (s32)[rdx+0x4] <= 0

Thanks for your report!

TBH it might not be clear which set of constraints is easier to achieve:

  address rbp-0x78 is writable
  [rsi] == NULL || rsi == NULL
  [rdx] == NULL || rdx == NULL

vs

  [rsp+0x70] == NULL
  [r9] == NULL || r9 == NULL
  rdx == NULL || (s32)[rdx+0x4] <= 0

But let me check whether I should properly tune my scoring system of gadgets' constraints.

True, the "easier to achieve" rating was quite subjective for my special use case. I still think that, from my limited personal experience, constraints on the stack are harder to fulfill.

Thanks for taking a look into it and the fast response!

With the PR it becomes:

0x50a37 posix_spawn(rsp+0x1c, "/bin/sh", 0, rbp, rsp+0x60, environ)
constraints:
  rsp & 0xf == 0
  rcx == NULL
  rbp == NULL || (u16)[rbp] == NULL

0xebcf1 execve("/bin/sh", r10, [rbp-0x70])
constraints:
  address rbp-0x78 is writable
  [r10] == NULL || r10 == NULL
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL

0xebcf5 execve("/bin/sh", r10, rdx)
constraints:
  address rbp-0x78 is writable
  [r10] == NULL || r10 == NULL
  [rdx] == NULL || rdx == NULL

0xebcf8 execve("/bin/sh", rsi, rdx)
constraints:
  address rbp-0x78 is writable
  [rsi] == NULL || rsi == NULL
  [rdx] == NULL || rdx == NULL

This result looks better to me as well

Released v1.8.1