kitty.model.low_level.container module

Containers are fields that group multiple fields into a single logical unit, they all inherit from Container, which inherits from BaseField.

class kitty.model.low_level.container.Conditional(condition, fields=[], encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]

Bases: kitty.model.low_level.container.Container

Container that its rendering is dependant on a condition

__init__(condition, fields=[], encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]
Parameters:
  • condition (an object that has a function applies(self, Container) -> Boolean) – condition to evaluate
  • fields – enclosed field(s) (default: [])
  • encoder (BitsEncoder) – encoder for the container (default: ENC_BITS_DEFAULT)
  • fuzzable – is container fuzzable (default: True)
  • name – (unique) name of the container (default: None)
Example:
Template([
    Group(['a', 'b', 'c'], name='letters'),
    If(ConditionCompare('letters', '==', 'a'), [
        Static('dvil')
    ])
])
# results in the mutations: advil, b, c
copy()[source]

Copy the container, put an invalidated copy of the condition in the new container

get_rendered_fields(ctx=None)[source]
Parameters:ctx – rendering context in which the method was called
Returns:ordered list of the fields that will be rendered
hash()[source]
Return type:int
Returns:hash of the container
is_default()[source]

Checks if the field is in its default form

Returns:True if field is in default form
render(ctx=None)[source]

Only render if condition applies

Parameters:ctx – rendering context in which the method was called
Return type:Bits
Returns:rendered value of the container
class kitty.model.low_level.container.Container(fields=[], encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]

Bases: kitty.model.low_level.field.BaseField

A logical unit to group multiple fields together

__init__(fields=[], encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]
Parameters:
  • fields (field or iterable of fields) – enclosed field(s) (default: [])
  • encoder (BitsEncoder) – encoder for the container (default: ENC_BITS_DEFAULT)
  • fuzzable – is container fuzzable (default: True)
  • name – (unique) name of the container (default: None)
Example:
Container([
    String('header_name'),
    Delimiter('='),
    String('header_value')
])
append_fields(new_fields)[source]

Add fields to the container

Parameters:new_fields – fields to append
copy()[source]
Returns:a copy of the container
get_field_by_name(name)[source]
Parameters:name – name of field to get
Returns:direct sub-field with the given name
Raises:KittyException if no direct subfield with this name
get_info()[source]

Get info regarding the current fuzzed enclosed node

Returns:info dictionary
get_rendered_fields(ctx=None)[source]
Parameters:ctx – rendering context in which the method was called
Returns:ordered list of the fields that will be rendered
get_structure()[source]
hash()[source]
Return type:int
Returns:hash of the container
is_default()[source]

Checks if the field is in its default form

Returns:True if field is in default form
num_mutations()[source]
Returns:number of mutations in the container
pop()[source]

Remove a the top container from the container stack

push(field)[source]

Add a field to the container, if the field is a Container itself, it should be poped() when done pushing into it

Parameters:field – BaseField to push
render(ctx=None)[source]
Parameters:ctx – rendering context in which the method was called
Return type:Bits
Returns:rendered value of the container
replace_fields(new_fields)[source]

Remove all fields from the container and add new fields

Parameters:new_fields – fields to add to the container
reset()[source]

Reset the state of the container and its internal fields

scan_for_field(field_key)[source]

Scan for a field in the container and its enclosed fields

Parameters:field_key – name of field to look for
Returns:field with name that matches field_key, None if not found
set_offset(offset)[source]

Set the absolute offset of current field, if the field should have default value, set the offset of the sub fields as well.

Parameters:offset – absolute offset of this field (in bits)
set_session_data(session_data)[source]

Set session data in the container enclosed fields

Parameters:session_data – dictionary of session data
class kitty.model.low_level.container.ForEach(mutated_field, fields=[], encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]

Bases: kitty.model.low_level.container.Container

Perform all mutations of enclosed fields for each mutation of mutated_field

__init__(mutated_field, fields=[], encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]
Parameters:
  • mutated_field – (name of) field to perform mutations for each of its mutations
  • fields – enclosed field(s) (default: [])
  • encoder (BitsEncoder) – encoder for the container (default: ENC_BITS_DEFAULT)
  • fuzzable – is container fuzzable (default: True)
  • name – (unique) name of the container (default: None)
Example:
Template([
    Group(['a', 'b', 'c'], name='letters'),
    ForEach('letters', [
        Group(['1', '2', '3'])
    ])
])
# results in the mutations: a1, a2, a3, b1, b2, b3, c1, c2, c3
hash()[source]
Return type:int
Returns:hash of the container
reset(reset_mutated=True)[source]

Reset the state of the container and its internal fields

Parameters:reset_mutated – should reset the mutated field too (default: True)
class kitty.model.low_level.container.If(condition, fields=[], encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]

Bases: kitty.model.low_level.container.Conditional

Render only if condition evalutes to True

class kitty.model.low_level.container.IfNot(condition, fields=[], encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]

Bases: kitty.model.low_level.container.Conditional

Render only if condition evalutes to False

class kitty.model.low_level.container.Meta(fields=[], encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]

Bases: kitty.model.low_level.container.Container

Don’t render enclosed fields

Example:
Container([
    Static('no sp'),
    Meta([Static(' ')]),
    Static('ace')
])
# will render to: 'no space'
get_rendered_fields(ctx=None)[source]
Parameters:ctx – rendering context in which the method was called
Returns:ordered list of the fields that will be rendered
render(ctx=None)[source]
Parameters:ctx – rendering context in which the method was called
Return type:Bits
Returns:empty bits
class kitty.model.low_level.container.OneOf(fields=[], encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]

Bases: kitty.model.low_level.container.Container

Render a single field from the fields (also mutates only one field each time)

Example:
OneOf(fields=[
    String('A'),
    String('B'),
    String('C'),
    String('D'),
])
# 'A', 'AAAA', '%s' ... 'B', 'BBBB' ... 'C' .. 'D'
get_rendered_fields(ctx=None)[source]
Parameters:ctx – rendering context in which the method was called
Returns:ordered list of the fields that will be rendered
render(ctx=None)[source]

Render only the mutated field (or the first one if not in mutation)

Parameters:ctx – rendering context in which the method was called
Return type:Bits
Returns:rendered value of the container
class kitty.model.low_level.container.Pad(pad_length, pad_data='x00', fields=[], fuzzable=True, name=None)[source]

Bases: kitty.model.low_level.container.Container

Pad the rendered value of the enclosed fields

__init__(pad_length, pad_data='\x00', fields=[], fuzzable=True, name=None)[source]
Parameters:
  • pad_length – length to pad up to (in bits)
  • pad_data – data to pad with (default: ‘’)
  • fields – enclosed field(s) (default: [])
  • fuzzable – is fuzzable (default: True)
  • name – (unique) name of the template (default: None)
Example:

Pad a string with ‘ ‘s so it is at least 20 bytes

Pad(fields=String('padded'), pad_data=' ', pad_length=20)
# default result will be: 'padded              '
hash()[source]
Return type:int
Returns:hash of the container
render(ctx=None)[source]
Parameters:ctx – rendering context in which the method was called
Return type:Bits
Returns:rendered value of the container, padded if needed
class kitty.model.low_level.container.PseudoTemplate(name)[source]

Bases: kitty.model.low_level.container.Template

A pseudo template is an empty, immutable template, that can be created with any name. Pseudo templates are useful when fuzzing clients and we want to fuzz a template at differemt stages.

Example:

Let’s say you have a protocol in which a given request is performed twice and you don’t only want to check the handling of the response for each request, but what happens when those responses are different.

This use case happens in various protocols. For example, some USB hosts may ask the same descriptor twice. In the first time, they will only read its length and allocate enough memory for it, and in the second time it will copy the descriptor to the allocated buffer. Providing different descriptors in each response may expose bugs that are similar to time-of-check time-of-use.

When working with a graph model, this can be a problem, as you need to connect the same template to itself to match the stages of the stack, but you cannot do that, as it creates a cycle inside the GraphModel.

The solution is to create PseudoTemplates s with the same name.

Example:
g = GraphModel()
stage1 = PseudoTemplate(original.get_name())
stage2 = PseudoTemplate(original.get_name())
g.connect(original)
g.connect(stage1)
g.connect(stage1, original)
g.connect(stage1, stage2)
g.connect(stage2, original)

This will result in the following (interesting) sequences:

original, stage1 -> original and stage1 -> stage2 -> original

__init__(name)[source]
Parameters:name – name of the template
class kitty.model.low_level.container.Repeat(fields=[], min_times=1, max_times=1, step=1, encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]

Bases: kitty.model.low_level.container.Container

Repeat the enclosed fields. When not mutated, the repeat count is min_times

__init__(fields=[], min_times=1, max_times=1, step=1, encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]
Parameters:
  • fields – enclosed field(s) (default: [])
  • min_times – minimum number of repetitions (default: 1)
  • max_times – maximum number of repetitions (default: 1)
  • step – how many repetitions to add each mutation (default: 1)
  • encoder (BitsEncoder) – encoder for the container (default: ENC_BITS_DEFAULT)
  • fuzzable – is container fuzzable (default: True)
  • name – (unique) name of the container (default: None)
Examples:
Repeat([Static('a')], min_times=5, fuzzable=False)
# will render to: 'aaaaa'
Repeat([Static('a')], min_times=5, max_times=10, step=5)
# will render to: 'aaaaa', 'aaaaaaaaaa'
get_rendered_fields(ctx=None)[source]
Parameters:ctx – rendering context in which the method was called
Returns:ordered list of the fields that will be rendered
hash()[source]
Return type:int
Returns:hash of the container
render(ctx=None)[source]
Parameters:ctx – rendering context in which the method was called
Return type:Bits
Returns:rendered value of the container, repeated
class kitty.model.low_level.container.Switch(field_dict, key_field, default_key, encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]

Bases: kitty.model.low_level.container.OneOf

When switch is not mutating, it will render one of the fields, choosing the one with a key that matchs the value of key_field. When switch is mutating, it will mutate and render one of its fields each time, setting the value of the key_field field to the mutated field key.

__init__(field_dict, key_field, default_key, encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]
Parameters:
  • field_dict – dictionary of key:field
  • key_field – (name of) field that switch takes the key from
  • default_key – key to use if the key_field’s value doesn’t match any key
  • encoder (BitsEncoder) – encoder for the container (default: ENC_BITS_DEFAULT)
  • fuzzable – is container fuzzable (default: True)
  • name – (unique) name of the container (default: None)
Example:
Container(fields=[
    BE16(name='opcode', value=1),
    Switch(name='opcode_params', key_field='opcode', default_key=1, field_dict={
        1: Container(name='opcode_1_params', fields=[
            BE32(name='param1', value=3),
        ]),
        2: Container(name='opcode_2_params', fields=[
            BE32(name='param1', value=4),
            BE32(name='param2', value=5),
        ]),
    })
])
render(ctx=None)[source]

Render only a single field (see class docstring for more details)

Parameters:ctx – rendering context in which the method was called
Return type:Bits
Returns:rendered value of the container
class kitty.model.low_level.container.TakeFrom(fields=[], min_elements=1, max_elements=None, encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]

Bases: kitty.model.low_level.container.OneOf

Render to only part of the enclosed fields, performing all mutations on them

__init__(fields=[], min_elements=1, max_elements=None, encoder=<kitty.model.low_level.encoder.BitsEncoder object>, fuzzable=True, name=None)[source]
Parameters:
  • fields (field or iterable of fields) – enclosed field(s) (default: [])
  • min_elements – minimum number of elements in the sub set
  • max_elements – maximum number of elements in the sub set
  • encoder (BitsEncoder) – encoder for the container (default: ENC_BITS_DEFAULT)
  • fuzzable – is container fuzzable (default: True)
  • name – (unique) name of the container (default: None)
Example:
TakeFrom(fields=[
    Static('A'), Static('B'), Static('C'),
    Static('D'), Static('E'), Static('F'),
])
# 'E', 'B', 'D', 'F', 'C', 'A', 'CE', 'FC', 'CF', 'BD', 'AF', 'BED',
# 'EBC', 'CDB', 'DCA', 'BFAD', 'FCBD', 'DBCF', 'BFACD' ...
get_field_by_name(name)[source]

Since TakeFrom constructs sub-containers and excercises OneOf, It needs to skip this sub-container when looking for field by name.

Parameters:name – name of field to get
hash()[source]
Return type:int
Returns:hash of the container
reset()[source]

Reset the state of the container and its internal fields

class kitty.model.low_level.container.Template(fields=[], encoder=<kitty.model.low_level.encoder.ByteAlignedBitsEncoder object>, fuzzable=True, name=None)[source]

Bases: kitty.model.low_level.container.Container

Top most container of a message, serves a the only interface to the high level model

__init__(fields=[], encoder=<kitty.model.low_level.encoder.ByteAlignedBitsEncoder object>, fuzzable=True, name=None)[source]
Parameters:
  • fields – enclosed field(s) (default: [])
  • encoder (BitsEncoder) – encoder for the container (default: ENC_BITS_BYTE_ALIGNED)
  • fuzzable – is fuzzable (default: True)
  • name – (unique) name of the template (default: None)
Example:
Template([
    Group(['a', 'b', 'c']),
    Group(['1', '2', '3'])
])

# the mutations are: a1, b1, c1, a1, a2, a3
copy()[source]

We might want to change it in the future, but for now...

Raises:KittyException, as it should not be copied
get_info()[source]

Get info regarding the current template state

Returns:info dictionary
class kitty.model.low_level.container.Trunc(max_size, fields=[], fuzzable=True, name=None)[source]

Bases: kitty.model.low_level.container.Container

Truncate the size of the enclosed fields

__init__(max_size, fields=[], fuzzable=True, name=None)[source]
Parameters:
  • max_size – maximum size of the container (in bits)
  • fields – enclosed field(s) (default: [])
  • fuzzable – is fuzzable (default: True)
  • name – (unique) name of the template (default: None)
hash()[source]
Return type:int
Returns:hash of the container
render(ctx=None)[source]
Parameters:ctx – rendering context in which the method was called
Return type:Bits
Returns:rendered value of the container