How to read a packet TLS meta-data with scapy python
Question:
How can I read TLS information (record length, record type…) from a packet using scapy. I have used load_layer(‘tls’) and I’m able to read some information when there is a single TLS record in a packet but when there is multiple TLS record in a packet I’m only able to read the first TLS record.
For exemple this packet contain 3 TLS record and when I want to read the records length with scapy I only get the first record length
Answers:
Total TLS decoding
As you’ve found, scapy doesn’t decode the entire packet. But this is fine, because we can manually decode the TLS sections that scapy currently considers as a “Raw load” of bytes.
>>> pkts = rdpcap("facebook.com.pcap")
>>> extra_tls_layers = TLS(pkts[5]["TLS"].load)
>>> # We can see that TLS is now decoded, with two new layers:
>>> extra_tls_layers.show()
###[ TLS ]###
type= application_data
version= TLS 1.2
len= 1017 [deciphered_len= 1017]
iv= b''
msg
|###[ TLS Application Data ]###
| data= 'x1fx11xc4xabx920lxae]=x10xd4x13x81kx14x98ex8bxcdxa0...
mac= b''
pad= b''
padlen= None
###[ TLS ]###
type= application_data
version= TLS 1.2
len= 1517 [deciphered_len= 240]
iv= b''
msg
|###[ TLS Application Data ]###
| data= 'xacx0bxdaxbaxe8zx99xadx0b_x82x96cxb3xffx9fxcc...
mac= b''
pad= b''
padlen= None```
To access a value of each of these layers (the newly decoded layers start at 0, 2), use the deciphered_len
attribute.
>>> pkts[5][TLS][0].deciphered_len
122
>>> pkts[5][TLS][5].deciphered_len
1
>>> extra_tls_layers[0].deciphered_len
1017
>>> extra_tls_layers[2].deciphered_len
240
Verifying completeness
The length of the entire TLS section is 1400 here, which we get with len(pkts[5][TLS])
. Note that the TLS record header is 5 bytes (content type = 1 byte, version = 2 bytes, length = 2 bytes).
So with a budget of 1400 bytes, let’s check the record lengths:
- record 1: 5 + 122 => 127
- record 2: 5 + 1 => 6
- record 3: 5 + 1017 => 1022
- record 4: 5 + 240 => 245
Checking that the 4 TLS records add up,
127 + 6 + 1022 + 245 = 1400 for the TLS section.
Raw packet #6
For future readers, if the pcap is not available, and you’re in the scapy interpreter, this is the relevant packet bytes for packet 6:
>>> pkt = b'x00r:x8ax18Px124Vxx9axbcx08x00Ex00x05xa0Exfc@x00Rx06)Ex9dxf0x08#nx00x04x04x01xbbxca`0l;1xfax93nxc2Px10x00r<xd3x00x00x16x03x03x00zx02x00x00vx03x03x94x01xb5xcc1bx86Jhx85xf0vGxb7#xe7xd2nx1dxd0'x01x8dxb6xabxa9x8afx92=h= x98x0fJKbJxff(swxcbdWxaex16x17xecxecxb7xbax139x92/9xedxc2xebxa3x07x88xaax13x01x00x00.x00+x00x02x03x04x003x00$x00x1dx00 xedxfdx0f*x87x9a;Qxbbx88nxad*x9d,Cx96xddx14xabxd8xd8}xf9(x8fxcbxb3x10+xa63x14x03x03x00x01x01x17x03x03x03xf9x1fx11xc4xabx920lxae]=x10xd4x13x81kx14x98ex8bxcdxa0x9fxcaxfdxcfxd5xc2xa3xc9Sxd0x86Gxf3xdcx08x8a,x15xbe+x84xfdx87x8bkx956zOxb3;x875xf4xbdx01xe7`x0f=x08xc5xd8xe6x9exa4xd9xa3x89C^x07y"x85xb9|xfc:{x19x99rx9avx15{xf6xf4x91x97xfdxe6x7fxbfx1cx81xb9x81xc7Wxbaox98X>n'x91x11Xx9660x92\ubxb896xcerx84xe0x82:r{xffxbetxea*x03x97Iwxc8x8bx1dxe3mxe2%x054xc7x0ex9exe2LQ")ax11Mx92eY=xccx89x9cjxaexa73xf0x90xf9.&xf5x14xbc\x8fxa5xfcx0e"bDxcex92xb0x9dxc3xddmxc2x94x90x93Tnoxc7x10kx1axdfPxecFxa9xebxe3=xe4xe5xf5x8bx1a]lx82xdbx93x0cxb7Qx15bSx97xd6xuxecx0fd5$xb03Axa8x14 x00xd7hx82xb0xb7xb3QYx82%sxf8Hx1axf3xa1xacxcdx07xb0=xdcdvx16yx91Dxb1xbfzqx92xcfx07xefx84x8c'xefDx05xcbxe1xd1x01'xcfxbedGrgx94x073x9cxe7e-xd3xd2|x0exa2xeb$xc2xe3xa4&`x9cxd6xe9xf3xd4fPxf5xdbx10x85xbfxc8xa1x86d;x9exe3xa2xcexe2Txxba~gtx8exbd5xce8Tx00xa4*xc7x15xf1xa3xaex90xearTx03xcaKxb9xf8x04-xd7xebxfbxc1<}x95x85xd97'xfbIHxcfx07x85Gxd7xe6~xaebx14*xcfxe2@xbcxa5xc79+x1exffx90 Df[xc3xb9;x9cx8ax0bx02xb4*xb7s/x9cxaa{xb7xbd4xfbx00xa7xa6uxdf0x84x060xbf#x17xbax0exbex86x83xc8hxba!x86jx04x98x0c/xfaxe2wpx16:zx04xc5xc0yox06xfdxcdx9fCxJxb0fSx989x1cxe5xfex18Klx8b'xcday%xe5xa7xa6T_`x07{xdcxe7OIx80x03xc9x92(x9fxa5xeex0exacxc4x01`g*|x88x13x8dxe3Ix8dZ;xfdcVxc0xdb,*@xd4Yxd7x9bxe0xd0J6uxednxe3VRxabxb5x(xe7x9cFxfdxc0xeaxf2xb5xc2xcerxd1xecxb6 {xce;<x8fnx80xa0xf7Wxf0R"x80Nxdcx82x92x19waxb3/xabxf6xecx99xfaxcaxebx08xafx97xc8x89gxddxf3xf2xb1|Yoxcax0bxd3_n/x8e!xf7x11b&xaexedxa3xcc\xebxbfx19xd6xacEx02n[xa4i(xaax0cQxcfxf0xf6"`x04Mxe9%x8exfdRoxae]eA6}lx1exe2x04[xf0x93xa2)x02xf1xd0&x00_Jxd3yx99x90(x85VrNtxf3zxfelxd7.x80x07x8ex1f=x9cxebrKx06 6-Oxb1x8fxfaxc6"fx02t%xf8qxb5x14xcbp*xb4!({rx00Sxf1x19txb2xafs`xd1x0bxc8x14V]{Bx15xc4xc3x06x08nxa02&xe1`bxf0xd8PZLxb5x8bx93xb8<a[xccx07xadtrxa3hbNvxa9t)xb4hBxe5xf5xe1xbbxdex03xe3x14xacxe2xb6ixfex9a/"x95x9332 xabuxbbx1axf2xx85Cxad;x8dx87x95;x14O%xa9fxe1x10xxce">-xb3.xc9wxf0fBxfe;xddxeaxf5x85xa2'x8bx08xe8x1cxb8xebx7fbxd4xf0xbax7fxfdx9a{x92]x0bp5x91.Q'x03Qxf9#xbc{x93xa9xc9x96W&xb8x15x8dxa9_kxd2x8bzx90xdexc0xa1`xe4r8xd2Wxfbx1fxd2]S?xe4x0cK^xdexfdsxd3xf0xc6xb9x04x05xd1xf6xb3xd8x0fz6xdfx86xa8Zx1cjxadOxa0x89;x94%xa4K"`x8b:xdcxb6xa0=gxc7x04k/fx04xf5Ex00xddrxbd]xe8x869+xd7x85xb3{yGx1bHx8fnxadxd5xd7xeaxf6ux13x85xcdxa3$xbaF~x1exc1M#>n!x97xcdx1aFx86x84xb2x9bxf9u}x96xc68x89x97x17x03x03x05xedxacx0bxdaxbaxe8zx99xadx0b_x82x96cxb3xffx9fxcctxbd x9cMx0bPxe2xb0xa5@xfb)xda:Kx9b-xb0x0bxb36pxe2<oOjx96x10xe2jEq oxc8x99xf2x0esx9fjxc5x0cxc5xc0x83x92>x9dx05x17xedx85xc8,Qxf1Wxa9xacx9ezx19x14x90ix1efxe8Exd6xf1x9fxe0xc1@xed'x88xb13xf5;pgx18xc19,xe2uxefTJxd2x08xb5x8exf2xcfxd2xcexf0Lxfa]x95x05wkx8fx85xa2x8aQx00x12rx0fxa6xa9x88:4xb3xa3zxa8xf6xeaVx1cx86wxcexe7x97xf4xc3x19.nxe7>xb2x8djxcf\xaf5{$xa0Lx1ex15xb6xd4xc7xdbxbcx99l"Dx890Kxa8x03x0fzxfdx88xabHxcbxbexbc0xa3xbetpx90xd3_BGex93[x98x9cxf86xc8xddxb3]x1cxf0x83xbfxbfsxccjxbdx8fRx8dx9etxe8xcexd33R/'
>>> # To reconstitute, create an Ethernet packet
>>> new_pkt = Ether(pkt)
How can I read TLS information (record length, record type…) from a packet using scapy. I have used load_layer(‘tls’) and I’m able to read some information when there is a single TLS record in a packet but when there is multiple TLS record in a packet I’m only able to read the first TLS record.
For exemple this packet contain 3 TLS record and when I want to read the records length with scapy I only get the first record length
Total TLS decoding
As you’ve found, scapy doesn’t decode the entire packet. But this is fine, because we can manually decode the TLS sections that scapy currently considers as a “Raw load” of bytes.
>>> pkts = rdpcap("facebook.com.pcap")
>>> extra_tls_layers = TLS(pkts[5]["TLS"].load)
>>> # We can see that TLS is now decoded, with two new layers:
>>> extra_tls_layers.show()
###[ TLS ]###
type= application_data
version= TLS 1.2
len= 1017 [deciphered_len= 1017]
iv= b''
msg
|###[ TLS Application Data ]###
| data= 'x1fx11xc4xabx920lxae]=x10xd4x13x81kx14x98ex8bxcdxa0...
mac= b''
pad= b''
padlen= None
###[ TLS ]###
type= application_data
version= TLS 1.2
len= 1517 [deciphered_len= 240]
iv= b''
msg
|###[ TLS Application Data ]###
| data= 'xacx0bxdaxbaxe8zx99xadx0b_x82x96cxb3xffx9fxcc...
mac= b''
pad= b''
padlen= None```
To access a value of each of these layers (the newly decoded layers start at 0, 2), use the deciphered_len
attribute.
>>> pkts[5][TLS][0].deciphered_len
122
>>> pkts[5][TLS][5].deciphered_len
1
>>> extra_tls_layers[0].deciphered_len
1017
>>> extra_tls_layers[2].deciphered_len
240
Verifying completeness
The length of the entire TLS section is 1400 here, which we get with len(pkts[5][TLS])
. Note that the TLS record header is 5 bytes (content type = 1 byte, version = 2 bytes, length = 2 bytes).
So with a budget of 1400 bytes, let’s check the record lengths:
- record 1: 5 + 122 => 127
- record 2: 5 + 1 => 6
- record 3: 5 + 1017 => 1022
- record 4: 5 + 240 => 245
Checking that the 4 TLS records add up,
127 + 6 + 1022 + 245 = 1400 for the TLS section.
Raw packet #6
For future readers, if the pcap is not available, and you’re in the scapy interpreter, this is the relevant packet bytes for packet 6:
>>> pkt = b'x00r:x8ax18Px124Vxx9axbcx08x00Ex00x05xa0Exfc@x00Rx06)Ex9dxf0x08#nx00x04x04x01xbbxca`0l;1xfax93nxc2Px10x00r<xd3x00x00x16x03x03x00zx02x00x00vx03x03x94x01xb5xcc1bx86Jhx85xf0vGxb7#xe7xd2nx1dxd0'x01x8dxb6xabxa9x8afx92=h= x98x0fJKbJxff(swxcbdWxaex16x17xecxecxb7xbax139x92/9xedxc2xebxa3x07x88xaax13x01x00x00.x00+x00x02x03x04x003x00$x00x1dx00 xedxfdx0f*x87x9a;Qxbbx88nxad*x9d,Cx96xddx14xabxd8xd8}xf9(x8fxcbxb3x10+xa63x14x03x03x00x01x01x17x03x03x03xf9x1fx11xc4xabx920lxae]=x10xd4x13x81kx14x98ex8bxcdxa0x9fxcaxfdxcfxd5xc2xa3xc9Sxd0x86Gxf3xdcx08x8a,x15xbe+x84xfdx87x8bkx956zOxb3;x875xf4xbdx01xe7`x0f=x08xc5xd8xe6x9exa4xd9xa3x89C^x07y"x85xb9|xfc:{x19x99rx9avx15{xf6xf4x91x97xfdxe6x7fxbfx1cx81xb9x81xc7Wxbaox98X>n'x91x11Xx9660x92\ubxb896xcerx84xe0x82:r{xffxbetxea*x03x97Iwxc8x8bx1dxe3mxe2%x054xc7x0ex9exe2LQ")ax11Mx92eY=xccx89x9cjxaexa73xf0x90xf9.&xf5x14xbc\x8fxa5xfcx0e"bDxcex92xb0x9dxc3xddmxc2x94x90x93Tnoxc7x10kx1axdfPxecFxa9xebxe3=xe4xe5xf5x8bx1a]lx82xdbx93x0cxb7Qx15bSx97xd6xuxecx0fd5$xb03Axa8x14 x00xd7hx82xb0xb7xb3QYx82%sxf8Hx1axf3xa1xacxcdx07xb0=xdcdvx16yx91Dxb1xbfzqx92xcfx07xefx84x8c'xefDx05xcbxe1xd1x01'xcfxbedGrgx94x073x9cxe7e-xd3xd2|x0exa2xeb$xc2xe3xa4&`x9cxd6xe9xf3xd4fPxf5xdbx10x85xbfxc8xa1x86d;x9exe3xa2xcexe2Txxba~gtx8exbd5xce8Tx00xa4*xc7x15xf1xa3xaex90xearTx03xcaKxb9xf8x04-xd7xebxfbxc1<}x95x85xd97'xfbIHxcfx07x85Gxd7xe6~xaebx14*xcfxe2@xbcxa5xc79+x1exffx90 Df[xc3xb9;x9cx8ax0bx02xb4*xb7s/x9cxaa{xb7xbd4xfbx00xa7xa6uxdf0x84x060xbf#x17xbax0exbex86x83xc8hxba!x86jx04x98x0c/xfaxe2wpx16:zx04xc5xc0yox06xfdxcdx9fCxJxb0fSx989x1cxe5xfex18Klx8b'xcday%xe5xa7xa6T_`x07{xdcxe7OIx80x03xc9x92(x9fxa5xeex0exacxc4x01`g*|x88x13x8dxe3Ix8dZ;xfdcVxc0xdb,*@xd4Yxd7x9bxe0xd0J6uxednxe3VRxabxb5x(xe7x9cFxfdxc0xeaxf2xb5xc2xcerxd1xecxb6 {xce;<x8fnx80xa0xf7Wxf0R"x80Nxdcx82x92x19waxb3/xabxf6xecx99xfaxcaxebx08xafx97xc8x89gxddxf3xf2xb1|Yoxcax0bxd3_n/x8e!xf7x11b&xaexedxa3xcc\xebxbfx19xd6xacEx02n[xa4i(xaax0cQxcfxf0xf6"`x04Mxe9%x8exfdRoxae]eA6}lx1exe2x04[xf0x93xa2)x02xf1xd0&x00_Jxd3yx99x90(x85VrNtxf3zxfelxd7.x80x07x8ex1f=x9cxebrKx06 6-Oxb1x8fxfaxc6"fx02t%xf8qxb5x14xcbp*xb4!({rx00Sxf1x19txb2xafs`xd1x0bxc8x14V]{Bx15xc4xc3x06x08nxa02&xe1`bxf0xd8PZLxb5x8bx93xb8<a[xccx07xadtrxa3hbNvxa9t)xb4hBxe5xf5xe1xbbxdex03xe3x14xacxe2xb6ixfex9a/"x95x9332 xabuxbbx1axf2xx85Cxad;x8dx87x95;x14O%xa9fxe1x10xxce">-xb3.xc9wxf0fBxfe;xddxeaxf5x85xa2'x8bx08xe8x1cxb8xebx7fbxd4xf0xbax7fxfdx9a{x92]x0bp5x91.Q'x03Qxf9#xbc{x93xa9xc9x96W&xb8x15x8dxa9_kxd2x8bzx90xdexc0xa1`xe4r8xd2Wxfbx1fxd2]S?xe4x0cK^xdexfdsxd3xf0xc6xb9x04x05xd1xf6xb3xd8x0fz6xdfx86xa8Zx1cjxadOxa0x89;x94%xa4K"`x8b:xdcxb6xa0=gxc7x04k/fx04xf5Ex00xddrxbd]xe8x869+xd7x85xb3{yGx1bHx8fnxadxd5xd7xeaxf6ux13x85xcdxa3$xbaF~x1exc1M#>n!x97xcdx1aFx86x84xb2x9bxf9u}x96xc68x89x97x17x03x03x05xedxacx0bxdaxbaxe8zx99xadx0b_x82x96cxb3xffx9fxcctxbd x9cMx0bPxe2xb0xa5@xfb)xda:Kx9b-xb0x0bxb36pxe2<oOjx96x10xe2jEq oxc8x99xf2x0esx9fjxc5x0cxc5xc0x83x92>x9dx05x17xedx85xc8,Qxf1Wxa9xacx9ezx19x14x90ix1efxe8Exd6xf1x9fxe0xc1@xed'x88xb13xf5;pgx18xc19,xe2uxefTJxd2x08xb5x8exf2xcfxd2xcexf0Lxfa]x95x05wkx8fx85xa2x8aQx00x12rx0fxa6xa9x88:4xb3xa3zxa8xf6xeaVx1cx86wxcexe7x97xf4xc3x19.nxe7>xb2x8djxcf\xaf5{$xa0Lx1ex15xb6xd4xc7xdbxbcx99l"Dx890Kxa8x03x0fzxfdx88xabHxcbxbexbc0xa3xbetpx90xd3_BGex93[x98x9cxf86xc8xddxb3]x1cxf0x83xbfxbfsxccjxbdx8fRx8dx9etxe8xcexd33R/'
>>> # To reconstitute, create an Ethernet packet
>>> new_pkt = Ether(pkt)