Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Meta protocol flush_all method is vulnerable to code injection (Lack of input type check) #932

Closed
xhzeem opened this issue Oct 25, 2022 · 7 comments

Comments

@xhzeem
Copy link

xhzeem commented Oct 25, 2022

Hi there,
I'm a security researcher currently doing research on Memcached wrappers vulnerabilities. I was doing some source code reviewing on your wrapper and noticed that the flush_all method on the meta protocol takes a delay value and passes it to the server without any checks, which can be used to smuggle commands to the Memcached server if an attacker has control over the value passed to the flush_all method.

def flush(delay = 0)
write(RequestFormatter.flush(delay: delay))
response_processor.flush unless quiet?
end

def self.flush(delay: nil, quiet: false)
cmd = +'flush_all'
cmd << " #{delay}" if delay
cmd << ' noreply' if quiet
cmd + TERMINATOR
end

Proof of Concept

require 'dalli'

# Proof of Concept by @xhzeem
$mcmeta = Dalli::Client.new('localhost:11211', protocol: :meta)
$mcmeta.set('xhzeem','meta')
$mcmeta.get("xhzeem") # b64_if_reg_match(\s)
puts $mcmeta.flush_all("\nset xhzeem 1 1000 8\ninjected") # :D

Suggested Fix:

You should just add a simple check for the delay type and confirm it's a number or keep the 0 value.

@xhzeem xhzeem changed the title Meta protocol flush_all function is vulnerable to code injection (Lack of input type check) Meta protocol flush_all method is vulnerable to code injection (Lack of input type check) Oct 25, 2022
@petergoldstein
Copy link
Owner

Thanks @xhzeem - very helpful. While I'm not sure that the threat surface here is that large (if you have control over the flush_all argument you probably have control over the Dalli client), but I agree that this should be sanitized. I'll get a fix in shortly.

@xhzeem
Copy link
Author

xhzeem commented Oct 25, 2022

Thanks for your fast response...
Indeed the impact isn't very high for this case as the flush_all method will not be controlled by the user in most cases, in a case where a user sets a timer to restore or similar.

Anyway, the point here is not about being able to write ruby code, but instead passing unsafe user-controlled data to that method which can be used in some cases by malicious actors to inject more commands into the Memcached server.

petergoldstein added a commit that referenced this issue Oct 25, 2022
Sanitizes the flush input for the meta protocol
@xhzeem
Copy link
Author

xhzeem commented Oct 25, 2022

I see the fix is sufficient.
Nice job

@xhzeem
Copy link
Author

xhzeem commented Oct 26, 2022

I’ll do some final checks today and confirm I cannot find any other similar issues

@xhzeem
Copy link
Author

xhzeem commented Oct 26, 2022

I'm unable to get some tests done right so if you can help to confirm

def delete(key, cas)

How should I call this method and pass the cas?

def touch(key, ttl)

The touch function is lacking the ttl = TtlSanitizer.sanitize(ttl) if ttl part, but as far as my tests it is still only accepting numbers in the TTL, I cannot get the flow exactly.

If you can confirm those two methods are safe I think everything else is good so far as of my checks.
delete => cas variable
touch => ttl variable

@petergoldstein
Copy link
Owner

@xhzeem I'll take a look.

I don't think Dalli does any material checking on the format of the CAS, but memcached does require the CAS to be a 64-bit value. So that's an easy sanitize. I'll add that and a corresponding test.

Regarding touch, the ttl is sanitized at the Dalli::Client level I believe.

@xhzeem
Copy link
Author

xhzeem commented Oct 29, 2022

Good job I've checked the lastest version and to me, everything looks great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants