tintinweb / scapy-ssl_tls

SSL/TLS layers for scapy the interactive packet manipulation tool
GNU General Public License v2.0
419 stars 156 forks source link

Server automata #59

Closed tintinweb closed 8 years ago

tintinweb commented 8 years ago

since @alexmgr provided the missing ingredient for server mode tlssockets here's a basic server automata. Atm. it is polling the client in a 5s interval for data, will have to change that in future versions.

TLSServerAutomata.graph()

scapy2

start the server:

auto_srv = TLSServerAutomata(debug=9,
                         bind=('0.0.0.0', 8443),
                         pemcert=pemcert,
                         cipher_suite=TLSCipherSuite.RSA_WITH_AES_128_CBC_SHA,
                         response="HTTP/1.1 200 OK\r\n\r\n")
 print auto_srv.run()

automata debug log with state transitions:

WARNING: No route found for IPv6 destination :: (no default route?)
using certificate/keyfile: ../tests/files/openssl_1_0_1_f_server.pem
DEBUG: parse_args - done
DEBUG: parse_args - done
DEBUG: Starting control thread [tid=8316]
DEBUG: Received command RUN
DEBUG: ## state=[BEGIN]
DEBUG: BEGIN
DEBUG: Trying Condition [listen]
DEBUG: Condition [listen] taken to state [WAIT_FOR_CLIENT_CONNECTION]
DEBUG:    + Running action [do_bind]
DEBUG: dobind ('0.0.0.0', 8443) 
DEBUG: switching from [BEGIN] to [WAIT_FOR_CLIENT_CONNECTION]
DEBUG: ## state=[WAIT_FOR_CLIENT_CONNECTION]
DEBUG: accept
DEBUG: new connection: ('192.168.139.1', 10640)
DEBUG: Trying Condition [recv_client_hello]
###[ SSL/TLS ]###
  \records   \
   |###[ TLS Record ]###
   |  content_type= handshake
   |  version   = TLS_1_0
   |  length    = 0x12d
   |###[ TLS Handshake ]###
   |     type      = client_hello
   |     length    = 0x129
   |###[ TLS Client Hello ]###
   |        version   = TLS_1_2
   |        gmt_unix_time= 1622420732
   |        random_bytes= '\x83\xf1|3\x19\x9bj\xc2!\xbe\xe2"\x16\rw\xaf&\xbc!Cl1$\xe2\x9c\xab\x9f+'
   |        session_id_length= 0x0
   |        session_id= ''
   |        cipher_suites_length= 0x92
   |        cipher_suites= ['ECDHE_RSA_WITH_AES_256_GCM_SHA384', 'ECDHE_ECDSA_WITH_AES_256_GCM_SHA384', 'ECDHE_RSA_WITH_AES_256_CBC_SHA384', 'ECDHE_ECDSA_WITH_AES_256_CBC_SHA384', 'ECDHE_RSA_WITH_AES_256_CBC_SHA', 'ECDHE_ECDSA_WITH_AES_256_CBC_SHA', 'DHE_DSS_WITH_AES_256_GCM_SHA384', 'DHE_RSA_WITH_AES_256_GCM_SHA384', 'DHE_RSA_WITH_AES_256_CBC_SHA256', 'DHE_DSS_WITH_AES_256_CBC_SHA256', 'DHE_RSA_WITH_AES_256_CBC_SHA', 'DHE_DSS_WITH_AES_256_CBC_SHA', 'DHE_RSA_WITH_CAMELLIA_256_CBC_SHA', 'DHE_DSS_WITH_CAMELLIA_256_CBC_SHA', 'ECDH_RSA_WITH_AES_256_GCM_SHA384', 'ECDH_ECDSA_WITH_AES_256_GCM_SHA384', 'ECDH_RSA_WITH_AES_256_CBC_SHA384', 'ECDH_ECDSA_WITH_AES_256_CBC_SHA384', 'ECDH_RSA_WITH_AES_256_CBC_SHA', 'ECDH_ECDSA_WITH_AES_256_CBC_SHA', 'RSA_WITH_AES_256_GCM_SHA384', 'RSA_WITH_AES_256_CBC_SHA256', 'RSA_WITH_AES_256_CBC_SHA', 'RSA_WITH_CAMELLIA_256_CBC_SHA', 'ECDHE_RSA_WITH_AES_128_GCM_SHA256', 'ECDHE_ECDSA_WITH_AES_128_GCM_SHA256', 'ECDHE_RSA_WITH_AES_128_CBC_SHA256', 'ECDHE_ECDSA_WITH_AES_128_CBC_SHA256', 'ECDHE_RSA_WITH_AES_128_CBC_SHA', 'ECDHE_ECDSA_WITH_AES_128_CBC_SHA', 'DHE_DSS_WITH_AES_128_GCM_SHA256', 'DHE_RSA_WITH_AES_128_GCM_SHA256', 'DHE_RSA_WITH_AES_128_CBC_SHA256', 'DHE_DSS_WITH_AES_128_CBC_SHA256', 'DHE_RSA_WITH_AES_128_CBC_SHA', 'DHE_DSS_WITH_AES_128_CBC_SHA', 'DHE_RSA_WITH_SEED_CBC_SHA', 'DHE_DSS_WITH_SEED_CBC_SHA', 'DHE_RSA_WITH_CAMELLIA_128_CBC_SHA', 'DHE_DSS_WITH_CAMELLIA_128_CBC_SHA', 'ECDH_RSA_WITH_AES_128_GCM_SHA256', 'ECDH_ECDSA_WITH_AES_128_GCM_SHA256', 'ECDH_RSA_WITH_AES_128_CBC_SHA256', 'ECDH_ECDSA_WITH_AES_128_CBC_SHA256', 'ECDH_RSA_WITH_AES_128_CBC_SHA', 'ECDH_ECDSA_WITH_AES_128_CBC_SHA', 'RSA_WITH_AES_128_GCM_SHA256', 'RSA_WITH_AES_128_CBC_SHA256', 'RSA_WITH_AES_128_CBC_SHA', 'RSA_WITH_SEED_CBC_SHA', 'RSA_WITH_CAMELLIA_128_CBC_SHA', 'ECDHE_RSA_WITH_RC4_128_SHA', 'ECDHE_ECDSA_WITH_RC4_128_SHA', 'ECDH_RSA_WITH_RC4_128_SHA', 'ECDH_ECDSA_WITH_RC4_128_SHA', 'RSA_WITH_RC4_128_SHA', 'RSA_WITH_RC4_128_MD5', 'ECDHE_RSA_WITH_3DES_EDE_CBC_SHA', 'ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA', 'DHE_RSA_WITH_3DES_EDE_CBC_SHA', 'DHE_DSS_WITH_3DES_EDE_CBC_SHA', 'ECDH_RSA_WITH_3DES_EDE_CBC_SHA', 'ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA', 'RSA_WITH_3DES_EDE_CBC_SHA', 'DHE_RSA_WITH_DES_CBC_SHA', 'DHE_DSS_WITH_DES_CBC_SHA', 'RSA_WITH_DES_CBC_SHA', 'DHE_RSA_EXPORT_WITH_DES40_CBC_SHA', 'DHE_DSS_EXPORT_WITH_DES40_CBC_SHA', 'RSA_EXPORT_WITH_DES40_CBC_SHA', 'RSA_EXPORT_WITH_RC2_CBC_40_MD5', 'RSA_EXPORT_WITH_RC4_40_MD5', 'EMPTY_RENEGOTIATION_INFO_SCSV']
   |        compression_methods_length= 0x2
   |        compression_methods= ['DEFLATE', 'NULL']
   |        extensions_length= 0x6d
   |        \extensions\
   |         |###[ TLS Extension ]###
   |         |  type      = ec_point_formats
   |         |  length    = 0x4
   |         |###[ TLS Extension EC Points Format ]###
   |         |     length    = 0x3
   |         |     ec_point_formats= ['uncompressed', 'ansiX962_compressed_prime', 'ansiX962_compressed_char2']
   |         |###[ TLS Extension ]###
   |         |  type      = supported_groups
   |         |  length    = 0x34
   |         |###[ TLS Extension Elliptic Curves ]###
   |         |     length    = 0x32
   |         |     elliptic_curves= ['sect571r1', 'sect571k1', 'secp521r1', 'sect409k1', 'sect409r1', 'secp384r1', 'sect283k1', 'sect283r1', 'secp256k1', 'secp256r1', 'sect239k1', 'sect233k1', 'sect233r1', 'secp224k1', 'secp224r1', 'sect193r1', 'sect193r2', 'secp192k1', 'secp192r1', 'sect163k1', 'sect163r1', 'sect163r2', 'secp160k1', 'secp160r1', 'secp160r2']
   |         |###[ TLS Extension ]###
   |         |  type      = SessionTicket_TLS
   |         |  length    = 0x0
   |         |###[ TLS Extension ]###
   |         |  type      = signature_algorithms
   |         |  length    = 0x20
   |         |###[ TLS Extension Signature And Hash Algorithm ]###
   |         |     length    = 0x1e
   |         |     \algorithms\
   |         |      |###[ TLS Signature Hash Algorithm Pair ]###
   |         |      |  hash_algorithm= sha512
   |         |      |  signature_algorithm= rsa
   |         |      |###[ TLS Signature Hash Algorithm Pair ]###
   |         |      |  hash_algorithm= sha512
   |         |      |  signature_algorithm= dsa
   |         |      |###[ TLS Signature Hash Algorithm Pair ]###
   |         |      |  hash_algorithm= sha512
   |         |      |  signature_algorithm= ecdsa
   |         |      |###[ TLS Signature Hash Algorithm Pair ]###
   |         |      |  hash_algorithm= sha384
   |         |      |  signature_algorithm= rsa
   |         |      |###[ TLS Signature Hash Algorithm Pair ]###
   |         |      |  hash_algorithm= sha384
   |         |      |  signature_algorithm= dsa
   |         |      |###[ TLS Signature Hash Algorithm Pair ]###
   |         |      |  hash_algorithm= sha384
   |         |      |  signature_algorithm= ecdsa
   |         |      |###[ TLS Signature Hash Algorithm Pair ]###
   |         |      |  hash_algorithm= sha256
   |         |      |  signature_algorithm= rsa
   |         |      |###[ TLS Signature Hash Algorithm Pair ]###
   |         |      |  hash_algorithm= sha256
   |         |      |  signature_algorithm= dsa
   |         |      |###[ TLS Signature Hash Algorithm Pair ]###
   |         |      |  hash_algorithm= sha256
   |         |      |  signature_algorithm= ecdsa
   |         |      |###[ TLS Signature Hash Algorithm Pair ]###
   |         |      |  hash_algorithm= sha224
   |         |      |  signature_algorithm= rsa
   |         |      |###[ TLS Signature Hash Algorithm Pair ]###
   |         |      |  hash_algorithm= sha224
   |         |      |  signature_algorithm= dsa
   |         |      |###[ TLS Signature Hash Algorithm Pair ]###
   |         |      |  hash_algorithm= sha224
   |         |      |  signature_algorithm= ecdsa
   |         |      |###[ TLS Signature Hash Algorithm Pair ]###
   |         |      |  hash_algorithm= sha1
   |         |      |  signature_algorithm= rsa
   |         |      |###[ TLS Signature Hash Algorithm Pair ]###
   |         |      |  hash_algorithm= sha1
   |         |      |  signature_algorithm= dsa
   |         |      |###[ TLS Signature Hash Algorithm Pair ]###
   |         |      |  hash_algorithm= sha1
   |         |      |  signature_algorithm= ecdsa
   |         |###[ TLS Extension ]###
   |         |  type      = heartbeat
   |         |  length    = 0x1
   |         |###[ TLS Extension HeartBeat ]###
   |         |     mode      = peer_allowed_to_send
DEBUG: Condition [recv_client_hello] taken to state [CLIENT_HELLO_RECV]
###[ TLS Record ]###
  content_type= handshake
  version   = TLS_1_2
  length    = None
###[ TLS Handshake ]###
     type      = server_hello
     length    = None
###[ TLS Server Hello ]###
        version   = TLS_1_2
        gmt_unix_time= 1455151322
        random_bytes= 'gaw\xea\x8d.\xb0\x0f\xd6\xc8\xe9\x10\xc2(8\x8e\xcd\xcc\xd0\xe7\x0f\x9f\xaa\x1a\xb4\xb5\xc8_'
        session_id_length= None
        session_id= 'e\x12\x05N\xc2\xba\xde\x07\x88\xdd\x87\xe4\xd9:\xcfc\x9b\xec\xadR'
        cipher_suite= RSA_WITH_AES_128_CBC_SHA
        compression_method= NULL
        \extensions\
DEBUG: switching from [WAIT_FOR_CLIENT_CONNECTION] to [CLIENT_HELLO_RECV]
DEBUG: ## state=[CLIENT_HELLO_RECV]
DEBUG: Trying Condition [send_server_hello]
DEBUG: Condition [send_server_hello] taken to state [SERVER_HELLO_SENT]
DEBUG:    + Running action [do_send_server_hello]
###[ TLS Record ]###
  content_type= handshake
  version   = TLS_1_2
  length    = None
###[ TLS Handshake ]###
     type      = certificate
     length    = None
###[ TLS Certificate List ]###
        length    = None
        \certificates\
         |###[ TLS Certificate ]###
         |  length    = None
         |  \data      \
         |   |###[ X509Cert ]###
         |   |  version   = <ASN1_INTEGER[2L]>
         |   |  sn        = <ASN1_INTEGER[13397879971383713459L]>
         |   |  sign_algo = <ASN1_OID['.1.2.840.113549.1.1.5']>
         |   |  sa_value  = <ASN1_NULL[0L]>
         |   |  \issuer    \
         |   |   |###[ X509RDN ]###
         |   |   |  oid       = <ASN1_OID['.2.5.4.6']>
         |   |   |  value     = <ASN1_PRINTABLE_STRING['UK']>
         |   |   |###[ X509RDN ]###
         |   |   |  oid       = <ASN1_OID['.2.5.4.10']>
         |   |   |  value     = <ASN1_BADTAG[<ASN1_DECODING_ERROR['\x0c\rOpenSSL Group']{{Codec <ASN1Codec BER[1]> not found for tag <ASN1Tag UTF8_STRING[12]>}}>]>
         |   |   |###[ X509RDN ]###
         |   |   |  oid       = <ASN1_OID['.2.5.4.11']>
         |   |   |  value     = <ASN1_BADTAG[<ASN1_DECODING_ERROR['\x0c\x19FOR TESTING PURPOSES ONLY']{{Codec <ASN1Codec BER[1]> not found for tag <ASN1Tag UTF8_STRING[12]>}}>]>
         |   |   |###[ X509RDN ]###
         |   |   |  oid       = <ASN1_OID['.2.5.4.3']>
         |   |   |  value     = <ASN1_BADTAG[<ASN1_DECODING_ERROR['\x0c\x1cOpenSSL Test Intermediate CA']{{Codec <ASN1Codec BER[1]> not found for tag <ASN1Tag UTF8_STRING[12]>}}>]>
         |   |  not_before= <ASN1_UTC_TIME['111208140148Z']>
         |   |  not_after = <ASN1_UTC_TIME['211016140148Z']>
         |   |  \subject   \
         |   |   |###[ X509RDN ]###
         |   |   |  oid       = <ASN1_OID['.2.5.4.6']>
         |   |   |  value     = <ASN1_PRINTABLE_STRING['UK']>
         |   |   |###[ X509RDN ]###
         |   |   |  oid       = <ASN1_OID['.2.5.4.10']>
         |   |   |  value     = <ASN1_BADTAG[<ASN1_DECODING_ERROR['\x0c\rOpenSSL Group']{{Codec <ASN1Codec BER[1]> not found for tag <ASN1Tag UTF8_STRING[12]>}}>]>
         |   |   |###[ X509RDN ]###
         |   |   |  oid       = <ASN1_OID['.2.5.4.11']>
         |   |   |  value     = <ASN1_BADTAG[<ASN1_DECODING_ERROR['\x0c\x19FOR TESTING PURPOSES ONLY']{{Codec <ASN1Codec BER[1]> not found for tag <ASN1Tag UTF8_STRING[12]>}}>]>
         |   |   |###[ X509RDN ]###
         |   |   |  oid       = <ASN1_OID['.2.5.4.3']>
         |   |   |  value     = <ASN1_BADTAG[<ASN1_DECODING_ERROR['\x0c\x10Test Server Cert']{{Codec <ASN1Codec BER[1]> not found for tag <ASN1Tag UTF8_STRING[12]>}}>]>
         |   |  pubkey_algo= <ASN1_OID['.1.2.840.113549.1.1.1']>
         |   |  pk_value  = <ASN1_NULL[0L]>
         |   |  pubkey    = <ASN1_BIT_STRING['\x000\x82\x01\n\x02\x82\x01\x01\x00\xf3\x84\xf3\x926\xdc\xb2F\xcafz\xe5)\xc5\xf3I("\xd3\xb9\xfe\xe0\xde\xe48\xce\xee"\x1c\xe9\x91;\x94\xd0r/\x87\x85YKf\xb1\xc5\xf5z\x85]\xc2\x0f\xd3.)X6\xccHk\xa2\xa2\xb5&\xceg\xe2G\xb6\xdfI\xd2?\xfa\xa2\x10\xb7\xc2\x97D~\x874mm\xf2\x8b\xb4U+\xd6!\xdeSK\x90\xea\xfd\xea\xf985+\xf4\xe6\x9a\x0e\xf6\xbb\x12\xab\x87!\xc3/\xbc\xf4\x06\xb8\x8f\x8e\x10\x07\'\x95\xe5B\xcb\xd1\xd5\x10\x8c\x92\xac\xee\x0f\xdc#H\x89\xc9\xc6\x93\x0c"\x02\xe7t\xe7%\x00\xab\xf8\x0f\\\x10\xb5\x85;f\x94\xf0\xfbMW\x06U!"%\xdb\xf3\xaa\xa9`\xbfM\xaay\xd1\xab\x92H\xba\x19\x8e\x12\xech\xd9\xc6\xba\xdf\xecZ\x1c\xd8C\xfe\xe7R\xc9\xcf\x02\xd0\xc7\x7f\xc9~\xb0\x94\xe3SDX\x0b.\xfd)t\xb5\x06\x9b\\D\x8d\xfb2u\xa4:\xa8g{\x872\nP\x8d\xe1\xa2\x13J%\xaf\xe6\x1c\xb1%\xbf\xb4\x99\xa2S\xd3\xa2\x02\xbf\x11\x02\x03\x01\x00\x01']>
         |   |  \x509v3ext \
         |   |   |###[ X509v3Ext ]###
         |   |   |  val       = <ASN1_SEQUENCE[[<ASN1_OID['.2.5.29.19']>, <ASN1_BOOLEAN[-1L]>, <ASN1_STRING['0\x00']>]]>
         |   |   |###[ X509v3Ext ]###
         |   |   |  val       = <ASN1_SEQUENCE[[<ASN1_OID['.2.5.29.15']>, <ASN1_BOOLEAN[-1L]>, <ASN1_STRING['\x03\x02\x05\xe0']>]]>
         |   |   |###[ X509v3Ext ]###
         |   |   |  val       = <ASN1_SEQUENCE[[<ASN1_OID['.2.16.840.1.113730.1.13']>, <ASN1_STRING['\x16\x1dOpenSSL Generated Certificate']>]]>
         |   |   |###[ X509v3Ext ]###
         |   |   |  val       = <ASN1_SEQUENCE[[<ASN1_OID['.2.5.29.14']>, <ASN1_STRING["\x04\x14\x82\xbc\xcf\x00\x00\x13\xd1\xf79%\x9a'\xe7\xaf\xd2\xef \x1bn\xac"]>]]>
         |   |   |###[ X509v3Ext ]###
         |   |   |  val       = <ASN1_SEQUENCE[[<ASN1_OID['.2.5.29.35']>, <ASN1_STRING['0\x16\x80\x146\xc3l\x88\xe7\x95\xfe\xb0\xbd\xec\xce>=\x86\xab!\x81\x87\xda\xda']>]]>
         |   |  sign_algo2= <ASN1_OID['.1.2.840.113549.1.1.5']>
         |   |  sa2_value = <ASN1_NULL[0L]>
         |   |  signature = <ASN1_BIT_STRING["\x00\xa9\xbdMW@t\xfe\x96\xe9+\xd6x\xfd\xb3c\xcc\xf4\x0bM\x12\xcaZt\x8d\x9b\xf2a\xe6\xfd\x06\x11C\x84\xfc\x17\xa0\xeccc6\xb9\x9e6j\xb1\x02Zj[?j\xa1\xea\x05e\xac~@\x1aHe\x88\xd19M\xd3Kw\xe9\xc8\xbb+\x9eZ\xf4\x0849G\xb9\x02\x081\x9a\xf1\xd9\x17\xc5\xe9\xa6\xa5\x96Km@\xa9[e(\xcb\xcb\x00\x03\x82c7\xd3\xad\xb1\x96;v\xf5\x17\x16\x02{\xbdSSFr4\xd6\x08d\x9d\xbbC\xfbd\xb1I\x07w\tazB\x17\x110\x0c\xd9'\\\xf5q\xb6\xf0\x180\xf3~\xf1\x85?2~J\xaf\xb3\x10\xf7l\xc6\x85K-'\xad\n \\\xfb\x8d\x19p4\xb9u_|\x87\xd5\xc3\xec\x93\x13A\xfcs\x03\xb9\x8d\x1a\xfe\xf7&\x86I\x03\xa9\xc5\x82?\x80\r)I\xb1\x8f\xed$\x1b\xfe\xcfX\x90F\xe7\xa8\x87\xd4\x1ey\xef\x99m\x18\x9f>\x8b\x82\x07\xc1C\xc7\xe0%\xb6\xf1\xd3\x00\xd7@\xabK\x7f+z>\xa6\x99LT"]>
###[ TLS Record ]###
  content_type= handshake
  version   = TLS_1_2
  length    = 0x7
###[ TLS Handshake ]###
     type      = server_hello_done
     length    = 0x3
###[ TLS Server Hello Done ]###
        length    = 0x0
        data      = ''
DEBUG: switching from [CLIENT_HELLO_RECV] to [SERVER_HELLO_SENT]
DEBUG: ## state=[SERVER_HELLO_SENT]
DEBUG: Trying Condition [recv_client_key_exchange]
###[ SSL/TLS ]###
  \records   \
   |###[ TLS Record ]###
   |  content_type= handshake
   |  version   = TLS_1_2
   |  length    = 0x106
   |###[ TLS Handshake ]###
   |     type      = client_key_exchange
   |     length    = 0x102
   |     explicit_iv= ''
   |     mac       = ''
   |     padding   = ''
   |###[ TLS Client Key Exchange ]###
   |###[ TLS RSA Client Params ]###
   |           length    = 0x100
   |           data      = '\x8e\xbb\xb9\x94^1>d\x13\xa0\x97\xe1\xdd\xde-\xb1\xa3^\xad\x88\x15(7G)p\x8au:2\xa0?Bog\xa9QkS\x12Y\xa0\xc7\x05/\x92\xa0\x0cB\xb2\x94\xeb\x11\xfd\x07]\x0b\xd9\x0c\xf6G\x06"\xaa\xfa\x12sp&\xe2\xb4\x0f\xab0\x8a\xeb\xbfB\x8fCL\xe0\xae=\xeeip\xb5C\x9f6\x8fOFz.\xae\xc5\xe8\x9b\xeeV\x86J\xde_\xc6\xa9\x13H=\r;\xa4\x05\xc3\xa6O9\xe0s\xee\xed\xf0\xe1\xdf\x1d4o\xe9\xeco\x8c&\x91F\xad\xad\x00\xe8\x97\x05\xb8 \xf0J\xfaD5(\xb2\t\xaa\xc6cQ\xde8)\x0c\xb4A\xda\x1c`\xed\x8a\x8d\x98\x9b7]\xf9&8\xde\xe8SRp\xb1\xd1z \xe6B$\xb2\xc6\xbaKaD\xa8\xb7\xe1\xe5\xf34T\x03\xf6\xf2\xd3\xf7\xf6e\xed\x1d\xaf\xde\xcc\xd8RvH1\xed\x7f\xc2{\x14\xc2\xec\xd3\xd2\xb3,\x8a\xdb\xc3\xacfP\xe1z\xaf\xc2|#\x1e4\x8c\x89\x014ts\xa5L\xcf\xc4DM\xa5\xd4'
   |###[ TLS Record ]###
   |  content_type= change_cipher_spec
   |  version   = TLS_1_2
   |  length    = 0x1
   |###[ TLS ChangeCipherSpec ]###
   |     message   = '\x01'
   |###[ TLS Record ]###
   |  content_type= handshake
   |  version   = TLS_1_2
   |  length    = 0x40
   |###[ TLS Handshake ]###
   |     type      = finished
   |     length    = 0xc
   |     explicit_iv= '\x04\n\x00`v\x1d\xb65\x824k\xedC\x1a\x1f\x9b'
   |     mac       = ' \x05\xe9\xaa\xea\xa1\xcd\x1f:\xdb;\xdf~\xcf\xb8\xf1@\xfe.\xc1'
   |     padding   = '\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b'
   |     padding_len= 0xb
   |###[ TLS Handshake Finished ]###
   |        data      = '\xa0\xb6\xfb\xa1.\x84\x83\xa1UBe\x8c'
DEBUG: Condition [recv_client_key_exchange] taken to state [CLIENT_KEY_EXCHANGE_RECV]
DEBUG: switching from [SERVER_HELLO_SENT] to [CLIENT_KEY_EXCHANGE_RECV]
DEBUG: ## state=[CLIENT_KEY_EXCHANGE_RECV]
DEBUG: switching from [CLIENT_KEY_EXCHANGE_RECV] to [CLIENT_CHANGE_CIPHERSPEC_RECV]
DEBUG: ## state=[CLIENT_CHANGE_CIPHERSPEC_RECV]
DEBUG: switching from [CLIENT_CHANGE_CIPHERSPEC_RECV] to [CLIENT_FINISH_RECV]
DEBUG: ## state=[CLIENT_FINISH_RECV]
DEBUG: Trying Condition [send_server_ccs]
DEBUG: Condition [send_server_ccs] taken to state [SERVER_CCS_SENT]
DEBUG:    + Running action [do_send_server_ccs]
DEBUG: switching from [CLIENT_FINISH_RECV] to [SERVER_CCS_SENT]
DEBUG: ## state=[SERVER_CCS_SENT]
DEBUG: Trying Condition [send_server_finish]
DEBUG: Condition [send_server_finish] taken to state [SERVER_FINISH_SENT]
DEBUG:    + Running action [do_send_server_finish]
DEBUG: switching from [SERVER_CCS_SENT] to [SERVER_FINISH_SENT]
DEBUG: ## state=[SERVER_FINISH_SENT]
DEBUG: Trying Condition [recv_client_appdata]
DEBUG: polling in 5sec intervals until data arrives.
###[ SSL/TLS ]###
  \records   \
   |###[ SSL/TLS ]###
   |  \records   \
   |   |###[ TLS Record ]###
   |   |  content_type= application_data
   |   |  version   = TLS_1_2
   |   |  length    = 0x40
   |   |###[ TLS Plaintext ]###
   |   |     data      = 'GET / HTTP/1.1\n'
   |   |     explicit_iv= "\xecQ'I\xd0f2\xbd#\x9aO\x17\xea\x89\x9a]"
   |   |     mac       = '=\x11\xaf\x8d\xdcP\x0f\xdb\xbbY\xea<\x83\xc3$\xd7\xe7\x06\xaag'
   |   |     padding   = '\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c'
   |   |     padding_len= 0xc
   |   |###[ TLS Record ]###
   |   |  content_type= application_data
   |   |  version   = TLS_1_2
   |   |  length    = 0x40
   |   |###[ TLS Plaintext ]###
   |   |     data      = 'Host: localhost\n'
   |   |     explicit_iv= 'G\xb4\xb0IVH\xf2w,\x13\xdd\xf7\x96\x8c0\x0b'
   |   |     mac       = '\x10\xa2\xeb\xe4!O@oY\xe4\x11\xea\xad\xe4\xfd\t\xab\xb6EZ'
   |   |     padding   = '\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b'
   |   |     padding_len= 0xb
   |   |###[ TLS Record ]###
   |   |  content_type= application_data
   |   |  version   = TLS_1_2
   |   |  length    = 0x30
   |   |###[ TLS Plaintext ]###
   |   |     data      = '\n'
   |   |     explicit_iv= '\xa4\x03/>\xe6z\xbb\xc4F(\xfe\x1b\xb1r\r\xa1'
   |   |     mac       = ' u%\x9c\x8bAK\x97\x9awg\xef\x98S\xf7\x01)t\x0e]'
   |   |     padding   = '\n\n\n\n\n\n\n\n\n\n'
   |   |     padding_len= 0xa
DEBUG: Condition [recv_client_appdata] taken to state [CLIENT_APPDATA_RECV]
DEBUG: switching from [SERVER_FINISH_SENT] to [CLIENT_APPDATA_RECV]
DEBUG: ## state=[CLIENT_APPDATA_RECV]
DEBUG: Trying Condition [send_server_response]
DEBUG: Condition [send_server_response] taken to state [SERVER_APPDATA_SENT]
DEBUG:    + Running action [do_send_server_response]
DEBUG: switching from [CLIENT_APPDATA_RECV] to [SERVER_APPDATA_SENT]
DEBUG: ## state=[SERVER_APPDATA_SENT]
DEBUG: switching from [SERVER_APPDATA_SENT] to [END]
DEBUG: ## state=[END]
None
DEBUG: Stopping control thread (tid=8316)

client output

#> openssl s_client -connect 192.168.139.1:8443 -tls1_2
...
New, TLSv1/SSLv3, Cipher is AES128-SHA
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : AES128-SHA
    Session-ID: 6512054EC2BADE0788DD87E4D93ACF639BECAD52
    Session-ID-ctx:
    Master-Key: 3B9EAC4FA6111AC5F984AA780639DDBFD3361D8E6B4CCA313E4DD6A60DBCF623CA257B3873603B673980DFA9CBA715AC
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1455151800
    Timeout   : 7200 (sec)
    Verify return code: 21 (unable to verify the first certificate)

---
GET / HTTP/1.1
Host: localhost

HTTP/1.1 200 OK

closed
alexmgr commented 8 years ago

+2 ;). Looks good.

More general question, is there a way to "break out" of the automata state at some point? The idea would be to use the automata to reach a known good state (say TLSClientKeyExchange) and then start fuzzing the state machine by sending out of state packets. I think that would be efficient in fuzzing the state machine from a given state. Any thoughts?

tintinweb commented 8 years ago

The first commit was my initial try with the TLSSocket (some months ago) and the second (54a22f9) switches to the new TLSSocket.accept interface doing the conversion early (just took this from your rsa_server example :)).

I like your fuzzing approach which is better than what I had in mind :) I am currently thinking about adding an interface to the automata that allows an implementation to override any state/transition. That way we'd have a protocol conform SM if you do not override anything and you can still selectively change actions/states/conditions from a custom implementation.

tintinweb commented 8 years ago

here's my first try of a generic interface to override SM states/actions/conditions but it is still a bit sub-optimal because

  1. handling is a bit confusing - especially names of states/transitions
  2. while it is possible to chain overrides for a function (state/transition/...) there is no way to have only one func receive the packet and pass it down the chain (the first one to call sock.recvall gets the data) to the original implementation. To overcome this we could a) move away from the deco approach and define explicit hook points (begin of function, after recv, before send) or b) pass the received packet down the function chain where a) keeps the code readable and b) requires extra code.

At this point I am a bit in favor of 2.a. What do you think?

Here's an example of the current approach that skips the server certificates message.

client:

>>> TLS 1.0 Handshake [length 00c6], ClientHello
<<< TLS 1.0 Handshake [length 003e], ServerHello
<<< TLS 1.0 Handshake [length 0004], ServerHelloDone
>>> TLS 1.0 Alert [length 0002], fatal unexpected_message
alexmgr commented 8 years ago

This is nice!

I haven't had a look at the details yet, but I don't think we need to bother with callback chaining. What use case did you have in mind where you'd need to chain callbacks?

I think your current approach is really good, we probably just need to add a static array of states where one can do something like this:

# STATES = [SERVER_HELLO_DONE, ...]

def jump_to_server_hello_done(*args, **kwargs):
    raw_input(" **** -------------> override state, directly jump to SERVER_CERTIFICATES_SENT aka. SERVER_HELLO_DONE")
    raise auto_srv.STATES[random.randint(0, len(STATES) - 1)]()

auto_srv.register_callback('send_server_hello', jump_to_server_hello_done)

One thing which could be nice would be to have a mapping between states and scapy pkts, say {TLSServerHello: "send_server_hello"}, It could make the callback setting more readable. E.g: auto_srv.register_callback(TLSServerHello, jump_to_server_hello_done) and the corresponding raise auto_srv.STATES[TLSServerHelloDone]()

Otherwise, this is going to make state fuzzing completely approachable! This is super neat.

tintinweb commented 8 years ago

sry, been busy. will have the PR updated with your suggestions by the end of the week, probably earlier.

tintinweb commented 8 years ago

I've removed the chaining (did not make sense to have) and added a mapping from scapy tls-layer to state and actions. Besides that the automata baseclass already tracks a list of all available states or actions (and conditions) in automata.states resp. automata.actions that would provide an interface to random transitions like raise getattr(auto_srv,random.choice(auto_srv.states.keys()))(). This allows easy callback registrations like:

auto_srv.register_callback(auto_srv.ACTIONS[TLSServerHello], jump_to_server_hello_done)

I've added a line to examples.tls_server_automata to prints states/actions and the mapping on execution so that we do not have to look this up.

The bigger problem is that the @hookable decorator in combination with @ATMT.condition breaks scapy.automata.graph() (the resulting graph is missing states or edges). This is unfortunate as decorating the states and transitions is pretty comfortable and enhances code readability in contrast to having some inspect.stack magic and explicit calls to run potential callbacks in every hookable function :/ The decorator breaks graph() as we're actually wrapping the original function which causes graph()s voodo magic to fail. I do not see a nice workaround for this.

I've also added the server_key_exchange states just to complete the SM. They're not doing anything atm. Here's the full graph:

scapy2

I currently see two options:

pretty unhappy with both options.

alexmgr commented 8 years ago

Hi Tin,

Didn't have time to check this out in detail yet, but from you're description, it's looking good. I'm hoping to have a more detailed look tomorrow. Sorry about the delay!

alexmgr commented 8 years ago

Just had a quick look at this. This might be stupid, but would this not work if you switched the decorator order? You'd just be re-wrapping the stuff scapy does. I looked internally, and it seems to add some attributes to the decorated functions. But that mixed with graph() being a meta-class function will make things a bit crazy to tshoot... It might also being functools.wrap() interfering with scapy internals, since it redefines a bunch of __ variables.

tintinweb commented 8 years ago

this caused me a lot of headache.

root cause scapy relies on reflection (investigating <caller_f>.func_code) to plot ATMT.Conditions with graph(); see: https://github.com/secdev/scapy/blob/40045ea3e97e78be085a315520b3a86bbb3fe0ac/scapy/automaton.py#L304. therefore wrapping an ATMT.Condition kind of function is going to break plotting for conditions as scapy simply cannot find any known state names in the caller func_code. Changing the decorator order won't help either.

solution

this way, graph() works fine as long as it is being called before run(). I guess this is the typical use-case. If it is not, we could as well fix it after run().

tintinweb commented 8 years ago

//had to rebase off master.

its a pretty old PR therefore I'd vote to merge (if there are no blockers) and refine it with specific use-cases in mind. :)

alexmgr commented 8 years ago

Agreed. It doesn't touch any core code anyway. I'll try and give this a test run next week. Got some use cases for it.

Nice stuff ;) Alex

tintinweb commented 8 years ago

:+1: