one_gadget
one_gadget copied to clipboard
jmp_case_candidates() "bad value for range" error
Some nonstandard versions of GLIBC can cause one_gadget v1.8.0 and later to error with "bad value for range" in jmp_case_candidates() from lib/one_gadget/fetchers/amd64.rb
git bisect suggests this problem was introduced in commit 8765130054a135031810f6fe7fa943ebc22787e1
The problem seems to be a change to this line: https://github.com/david942j/one_gadget/blob/acef31b387d4a18e550c9b4aaad259cb57a18b2b/lib/one_gadget/fetchers/amd64.rb#L36
Where the -A argument passed to egrep was changed from 3 to 8. Anything below 8 doesn't seem to cause problems, but 8 will trigger the error later in the function.
I'm not a Ruby developer so this is as far as I could take this issue. I also appreciate this only appears to affect nonstandard GLIBC builds, so I understand if it's not a priority. Attached is a GLIBC build that triggers this bug: libc-2.30.zip
Thanks for building this great tool and for making it available!
EDIT: After further testing, this problem seems to only manifest in Ubuntu 18.04, later versions of the same OS aren't affected. Perhaps this points to a binutils issue?
Thanks for the report! So you mean testing the same libc but running one_gadget on different Ubuntu version leads to different results? If that's the case then it's likely a binutils issue. I will take a look on what happened to Ubuntu18.04.
Out of curiosity, what do you mean by "non-standsard"? How did you acquire this special libc?
So you mean testing the same libc but running one_gadget on different Ubuntu version leads to different results?
Precisely. It sounds weird but yeah perhaps a binutils tool is producing different output per version 🤷♂️
Out of curiosity, what do you mean by "non-standsard"? How did you acquire this special libc?
Oh I just mean that they're not the ones bundled with any desktop Linux OS, they're built locally with whichever version of GCC I had available. Some of them (like the one linked above) were built with options like --disable-experimental-malloc, but other than that they should pretty closely resemble common libc.so.6 binaries found on any GLIBC-powered system. I only note this because one_gadget 1.8.1 will happily parse the libc.so.6 that ships with Ubuntu 18.04, but not any of the locally built ones.
It looks like the problem arises on Ruby versions prior to 2.6, which raise ArgumentError when nil is used in a range
e.g. array[0..nil]
This happens in jmp_case_candidates() when encountering a candidate gadget that doesn't terminate in a call to execve() after a jmp instruction. In this situation, an error occurs on the following line: https://github.com/david942j/one_gadget/blob/acef31b387d4a18e550c9b4aaad259cb57a18b2b/lib/one_gadget/fetchers/amd64.rb#L47
We end up with remain[0..nil] due to the match() call never finding a "call ... <execve>" string.
In Ruby 2.6 and later this implies the entire remain array is to be used, but earlier versions before nil was allowed in ranges will throw ArgumentError.