[Bro-Dev] SMB Analyzer code factorization

Bencteux Jeffrey jeffrey.bencteux at ssi.gouv.fr
Fri Jun 8 05:04:25 PDT 2018


Hi all,


As I looked into SMBv1 analyzer, I found that most of the files
describing SMB messages have code duplication. According to the SMB
specification ([MS-CIFS]), SMB messages are composed of a fixed-length
header (defined as SMB_Header in smb1-protocol.pac for Bro) and then of
two "blocks" : the parameter block (section 2.2.3.2) and the data block
(section 2.2.3.3). Every message of the protocol I saw in the
specification or encountered in trafic always followed that scheme.
However, in Bro's SMBv1 analyzer, each .pac file describing a particular
type of message reimplement the two blocks common fields.


The SMB PDU is defined as such :


type SMB_PDU(...) = record {

    header: SMB_Header(...)

    message: case msg_len of {

        35 -> no_msg: SMB_No_Message;

        default -> msg: SMB_Message(...);

    };

};


SMB_Message is just a switch between SMB_Message_request and
SMB_Message_Response. Then these two are defined as a switch on command
type :


type SMB_Message_Request(...) = case command of {

    SMB_COM_READ_ANDX -> read_andx: SMB1_read_andx_request(...);

    ...

};


And then every command is implemented like this one :


type SMB_read_andx_request(...) = record {

    word_count: uint8

    ... specific fields ...

    byte_count: uint16;

    ... specific fields ...

};


I feel like it would be a good idea to abstract the two blocks : it
would factorize code. Also, there is currently no check on the value of
word_count field or byte_count field for the rest of the payload. This
could lead to protocol violations from BinPAC if you have a byte_count
set to 0 and then a following field trying to parse a SMB_String for
example (see SMB1_transaction_request record in smb1-com-transaction.pac
for an example of that).


A solution could be to change SMB_Message_* to something closer to what
the specification describe by dividing every message in two half
structures :


type SMB_Message_Request(...) = record {

    parameter_block: SMB_Request_Parameters(...);

    data_block: SMB_Request_Data(...);

};


type SMB_Request_Parameters(...) = record {

    word_count: uint8;

    # Maybe a check on word_count here? Some messages seems to have a
predefined value for this field

    words: SMB_Request_Words(...);

};


type SMB_Request_Data(...) = record {

    byte_count: uint16;

    data_or_not: case byte_count of {

        0 -> none: empty;

        default -> bytes: SMB_Request_Bytes(...);

    };

};


And then SMB_Request_Words and SMB_Request_Bytes would be switch on
different messages types :


type SMB_Request_Words(...) = case command of {

    SMB_COM_READ_ANDX -> words_read_and_x:
SMB1_Words_read_andx_request(...);

    ...

};


type SMB_Request_Bytes(...) = case command of {

    SMB_COM_READ_ANDX -> bytes_read_and_x:
SMB1_Bytes_read_andx_request(...);

    ...

};


Of course, it means splitting every existing message and re factoring a
lot of code of the analyzer, but it would be easier then to address
problems such as the one quoted as example above. What do you think of it ?


Regards,


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
Url : http://mailman.icsi.berkeley.edu/pipermail/bro-dev/attachments/20180608/2a9c29dc/attachment.bin 


More information about the bro-dev mailing list