import dshell
import util
from httpdecoder import HTTPDecoder

import re


class DshellDecoder(HTTPDecoder):

    def __init__(self):
        HTTPDecoder.__init__(self,
                            name='joomla-cve-2015-8562',
                            description='detect and dissect malformed HTTP headers targeting Joomla',
                            filter='tcp and (port 80 or port 8080 or port 8000)',
                            filterfn=lambda ((sip, sp), (dip, dp)): sp in (
                                80, 8000, 8080) or dp in (80, 8000, 8080),
                            author='bg',
                            optiondict={
                                'raw_payload': {'action': 'store_true', 'help':'return the raw payload (do not attempt to decode chr encoding)'}
                            },
                            longdescription='''
Usage Examples:
---------------

  decode -d joomla-cve-2015-8562 *.pcap
joomla-cve-2015-8562 2015-12-15 20:17:18    192.168.1.119:43865 <-    192.168.1.139:80    ** x-forwarded-for -> system('touch /tmp/2'); **

 The module assumes the cmd payload is encoded using chr.  To turn this off run:

  decode -d joomla-cve-2015-8562 --joomla-cve-2015-8562_no_eval *.pcap
oomla-cve-2015-8562 2015-12-15 20:17:18    192.168.1.119:43865 <-    192.168.1.139:80    ** x-forwarded-for -> "eval(chr(115).chr(121).chr(115).chr(116).chr(101).chr(109).chr(40).chr(39).chr(116).chr(111).chr(117).chr(99).chr(104).chr(32).chr(47).chr(116).chr(109).chr(112).chr(47).chr(50).chr(39).chr(41).chr(59)); **
'''
                            )

        self.ioc = 'JFactory::getConfig();exit'

    def attempt_decode(self, cmd):
        ptext = ''
        for c in re.findall('\d+', cmd):
            ptext += chr(int(c))
        return ptext


    def parse_cmd(self, data):
        start = data.find('"feed_url";')+11
        end = data.find(self.ioc)
        chunk = data[start:end]

        try:
            cmd = chunk.split(':')[-1]
            if self.raw_payload:
                return cmd

            plaintext_cmd = self.attempt_decode(cmd)
            return plaintext_cmd
        except:
            return None

    def HTTPHandler(self, conn, request, response, requesttime, responsetime):
        if not request:
            return

        if self.ioc not in str(request):
            # indicator of (potential) compromise is not here
            return

        # there is an attempt to exploit Joomla!

        # The Joomla exploit could be sent any HTTP header field
        for hdr in request.headers:
            if self.ioc in request.headers[hdr]:
                cmd = self.parse_cmd(request.headers[hdr])
                if cmd:
                    self.alert('{} -> {}'.format(hdr, cmd), **conn.info())


if __name__ == '__main__':
    dObj = DshellDecoder()
    print dObj
else:
    dObj = DshellDecoder()
