import logging
from rex import Vulnerability
from rex.exploit import CannotExploit
from rex.exploit.cgc import CGCType1CircumstantialExploit
from ..technique import Technique

l = logging.getLogger("rex.exploit.techniques.linux.circumstantial_set_register")

class CircumstantialSetRegister(Technique):

    name = "circumstantially_set_register"

    applicable_to = ['cgc']

    cgc_registers = ["eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"]

    bitmask_threshold = 20

    # this technique should create an exploit which is a type1 pov
    pov_type = 1

    def set_register(self, register):
        '''
        set a register with shellcode on cgc
        '''

        # can only exploit ip overwrites
        ct = self.crash.crash_type
        if ct != Vulnerability.IP_OVERWRITE and ct != Vulnerability.PARTIAL_IP_OVERWRITE:
            raise CannotExploit("[%s] cannot control ip" % self.name)


        state = self.crash.state

        # see if the register value is nearly unconstrained
        reg = getattr(state.regs, register)

        # we need to make sure that the pc and this register don't conflict
        conflict = not state.satisfiable(extra_constraints=(reg != state.regs.pc,))
        if conflict:
            raise CannotExploit("register %s conflicts with pc, pc and register must be equal" % register)

        # test each bit of the register
        unconstrained_bitcnt = 0
        for bit in xrange(reg.size()):
            l.debug("testing symbolic control of bit %d in register %s", bit, register)
            set_bit = state.satisfiable(extra_constraints=((reg & 1 << (bit)) == (1 << bit),))
            unset_bit = state.satisfiable(extra_constraints=((reg & ~(1 << (bit))) == 0,))
            if set_bit and unset_bit:
                unconstrained_bitcnt += 1

        if unconstrained_bitcnt >= CircumstantialSetRegister.bitmask_threshold:
            l.info("can circumstantially set register %s", register)

            return CGCType1CircumstantialExploit(self.crash, register)
        else:
            raise CannotExploit("register %s's value does not appear to be unconstrained" % register)

    def apply(self, **kwargs):

        register_setters = [ ]
        for register in CircumstantialSetRegister.cgc_registers:
            try:
                register_setters.append(self.set_register(register))
            except CannotExploit as e:
                l.warning("could not set register %s circumstantially (%s)", register, e.message)

        return register_setters

import logging
from rex import Vulnerability
from rex.exploit import CannotExploit
from rex.exploit.cgc import CGCType1CircumstantialExploit
from ..technique import Technique

l = logging.getLogger("rex.exploit.techniques.circumstantial_set_register")

class CircumstantialSetRegister(Technique):

    name = "circumstantially_set_register"

    applicable_to = ['cgc']

    cgc_registers = ["eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"]

    bitmask_threshold = 20

    # this technique should create an exploit which is a type1 pov
    pov_type = 1

    def set_register(self, register):
        '''
        set a register with shellcode on cgc
        '''

        # can only exploit ip overwrites
        ct = self.crash.crash_type
        if ct != Vulnerability.IP_OVERWRITE and ct != Vulnerability.PARTIAL_IP_OVERWRITE:
            raise CannotExploit("[%s] cannot control ip" % self.name)


        state = self.crash.state

        # see if the register value is nearly unconstrained
        reg = getattr(state.regs, register)

        # we need to make sure that the pc and this register don't conflict
        conflict = not state.satisfiable(extra_constraints=(reg != state.regs.pc,))
        if conflict:
            raise CannotExploit("register %s conflicts with pc, pc and register must be equal" % register)

        # test each bit of the register
        unconstrained_bitcnt = 0
        for bit in xrange(reg.size()):
            l.debug("testing symbolic control of bit %d in register %s", bit, register)
            set_bit = state.satisfiable(extra_constraints=((reg & 1 << (bit)) == (1 << bit),))
            unset_bit = state.satisfiable(extra_constraints=((reg & ~(1 << (bit))) == 0,))
            if set_bit and unset_bit:
                unconstrained_bitcnt += 1

        if unconstrained_bitcnt >= CircumstantialSetRegister.bitmask_threshold:
            l.info("can circumstantially set register %s", register)

            return CGCType1CircumstantialExploit(self.crash, register)
        else:
            raise CannotExploit("register %s's value does not appear to be unconstrained" % register)

    def apply(self, **kwargs):

        register_setters = [ ]
        for register in CircumstantialSetRegister.cgc_registers:
            try:
                register_setters.append(self.set_register(register))
            except CannotExploit as e:
                l.warning("could not set register %s circumstantially (%s)", register, e.message)

        return register_setters

Update circumstantial register setter's technique log banner