23a24,26
> import getpass
> import socket
> 
31a35
> from core.controllers.misc.get_local_ip import get_local_ip
41a46,48
> from scapy.all import sniff, ICMP, IP
> from urlparse import urlparse
> 
46a54
>     @author: Dan Zulla ( dan@zulla.org )
80c88,89
<                 
---
>         self._remote_host = ''
>         self._is_root = any(u == getpass.getuser() for u in ["root", "Administrator"]) # works for linux and windows
90c99,105
<         # We are implementing two different ways of detecting OS Commanding
---
>         # This even feels wrong. Please make it better.
>         try:
>             self._remote_host = socket.gethostbyname(freq.getURL().getDomain())
>         except socket.error, e:
>             return False
> 
>         # We are implementing three different ways of detecting OS Commanding
93a109,110
>         #       - Reverse ICMP connect (privileged)
>         #       - Soon: Reverse TCP connect (unprivileged fall-back)
104a122,185
>         self._with_reverse_icmp(freq)
>         #self._with_reverse_tcp(freq)
> 
>     def _with_reverse_tcp(self, freq):
>         '''
>         Uses "telnet OUR_IP OUR_TEMPORARY_PORT" payloads and checks if our temporary TCP server
>         receives a connect by the hostile server.
> 
>         @param freq: A fuzzableRequest
>         '''
>         pass
> 
>     def _with_reverse_icmp(self, freq):
>         '''
>         Uses "ping" payloads and sniffs for hostile ICMP packets.
> 
>         @param freq: A fuzzableRequest
>         '''
>         if not self._is_root:
>             # soon: fall-back on _with_reverse_tcp
>             return False
> 
>         original_response = self._uri_opener.send_mutant(freq)
>         # Prepare the strings to create the mutants
>         command_list = self._get_reverse_icmp_commands()
>         only_command_strings = [ v.get_command() for v in command_list ]
>         mutants = createMutants( freq , only_command_strings, oResponse=original_response )
> 
>         for mutant in mutants:
>             # Only spawn a thread if the mutant has a modified variable
>             # that has no reported bugs in the kb
>             if self._has_no_bug(mutant):
>                 # fire! (no need for a callback with this technique)
>                 self._run_async(meth=self._uri_opener.send_mutant, args=(mutant,), kwds={})
> 
>         # start capturing ICMP packets that look like they might come from the target
>         packets = sniff(filter="icmp", lfilter=lambda x: x.haslayer(ICMP) and x.haslayer(IP), count=1, timeout=10)
>         self._join()
> 
>         if not packets:
>             return False
> 
>         # check if sender IP is target IP or if sender IP.split(".")[-3] == target IP.split(".")[-3]
>         # i have seen this a lot in the wild. obviously this is subject to a discussion
>         hostile_packet = packets[0][IP]
>         if hostile_packet.src.split(".")[:3] != self._remote_host.split(".")[:3]:
>             return False
> 
>         # Search for the correct command and separator
>         sentOs, sentSeparator = self._get_os_separator(mutant)
> 
>         # Building the vulnerability
>         v = vuln.vuln( mutant )
>         v.setPluginName(self.getName())
>         v.setName( 'OS commanding vulnerability' )
>         v.setSeverity(severity.HIGH)
>         v['os'] = sentOs
>         v['separator'] = sentSeparator
>         v.setDesc( 'OS Commanding was found at: %s using Reverse ICMP or TCP' %mutant.foundAt() )
>         v.setDc( mutant.getDc() )
>         v.setId( original_response.id )
>         v.setURI( original_response.getURI() )
>         v.addToHighlight( hostile_packet.__repr__() )
>         kb.kb.append( self, 'osCommanding', v )
169a251,252
>         command_list.extend(self._get_reverse_icmp_commands())
>         #command_list.extend(self._get_reverse_tcp_commands())
242a326,361
>     def _get_reverse_icmp_commands(self):
>         '''
>         @return: This method returns a list of commands to try to execute in order
>         to make the remote host to connect back to us via ICMP (root required)
>         '''
>         commands = []
>         for special_char in self._special_chars:
>             # Windows
>             cmd_fmt = special_char + 'ping -n 1 %s' %get_local_ip()
>             reverse_cmd  = base_command( cmd_fmt, 'windows', special_char)
>             commands.append( reverse_cmd )
> 
>             # Unix
>             cmd_fmt = special_char + 'ping -c 1 %s' %get_local_ip()
>             reverse_cmd  = base_command( cmd_fmt, 'unix', special_char)
>             commands.append( reverse_cmd )
> 
>             # This is needed for solaris 10
>             cmd_fmt = special_char + '/usr/sbin/ping -s %s 1' %get_local_ip()
>             reverse_cmd = base_command( cmd_fmt, 'unix', special_char)
>             commands.append( reverse_cmd )
> 
>         # Using execution quotes
>         commands.append( base_command( '`ping -n 1 %s`' %get_local_ip(), 'windows', '`'))
>         commands.append( base_command( '`ping -c 1 %s`' %get_local_ip(), 'unix', '`'))
> 
>         # FoxPro uses the "run" macro to exec os commands. I found one of this vulns !!
>         commands.append( base_command( 'run ping -n 1 %s' %get_local_ip(), 'windows', 'run '))
> 
>         # Now I filter the commands based on the targetOS:
>         targetOS = cf.cf.getData('targetOS').lower()
>         commands = [ c for c in commands if c.get_OS() == targetOS or targetOS == 'unknown']
> 
>         return commands
> 
> 
