how to use scapy to decode H2C message - scapy

scapy has a module named http2, and in its information: "encode/decode HTTP/2 Frames"
import scapy.contrib.http2 as http2
packets = rdpcap("in.pcapng")
for p in packets:
if p.haslayer(TCP):
p[TCP].payload # how to turn this into a http2.H2Seq or http2.H2Frame??
p[TCP].payload.name gives "raw", and p.haslayer(http2.H2Seq) or http2.H2Frame gives false.
I would like to turn this packet into a http2 one, and then parse headers or data if any.

Related

SSDP M-search does not work for unicast - single IP

SSDP M-search request for discovery works great for multicast address 239.255.255.250. However, I have a requirement to send this request to a specific IP. It does not work. As per the UPnP architecture document unicast discover message is supported, with a small difference from the multicast message
The multi-cast message is
M-SEARCH * HTTP/1.1
HOST:239.255.255.250:1900
MAN:ssdp:discover
ST:ssdp:all
MX:1
Unicast message is similar - except that the multicast IP is changed to specific IP and MX:1 is removed (as per the specification - did not find any code sample for unicast discover m-search)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32)
msg = 'M-SEARCH * HTTP/1.1\r\nHOST:239.255.255.250:1900\r\nMAN:\"ssdp:discover\"\r\nST:ssdp:all\r\nMX:1\r\n\r\n'
s.sendto(msg.encode('utf-8'), ('239.255.255.250', 1900))
resp = s.recv(1024)
print (resp)
This works great. But the following doesn't - the recv() call times out
sock_1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
msg = 'M-SEARCH * HTTP/1.1\r\nHOST:<specific ip>:1900\r\nMAN:\"ssdp:discover\"\r\nST:ssdp:all\r\n\r\n'
sock_1.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32)
sock_1.settimeout(30)
sock_1.sendto(msg.encode('utf-8'), ('<specific ip>', 1900))
resp = sock_1.recv(1024)
I have tried a few more variations of 'setsockopt' which did not work.
Please share if there are any clues for possible reasons - could it be from the device side that it responds to the multicast on 1900 but not to the unicast message?
Thanks in advance!
msg = 'M-SEARCH * HTTP/1.1\r\nHOST:<specific ip>:1900\r\nMAN:\"ssdp:discover\"\r\nST:ssdp:all\r\n'
You're missing a final \r\n in the end (it's for the empty line signaling end of headers: without it the receiver will just keep waiting for more).
The only difference with a unicast m-search is the HOST, like you've got.
Are you binding the socket? It should be bound to port 0. Here's an example of setting up a socket for ssdp: https://github.com/lbryio/aioupnp/blob/master/aioupnp/protocols/multicast.py#L64
In addition to the final \r\n pointed out by Jussi, you may find you need to try different permutations of the M-SEARCH format, some gateways are very finicky. For some the value for MAN must be in quotes, for others it must not. Additional quirks are the order of MAN, MX, ST and the capitalization of HOST/Host and MAN/Man . You may also need to try a variety of search targets.

How to change the payload of a packet on retransmission?

I want to try to implement the RSTEG method using scapy. That is, send a packet, the receiver does not send a confirmation message, this packet is sent again, but with a steganogram in the payload, the receiver again does not send a confirmation message. Then this package is sent again, but without the steganogram. (the same packet is sent three times, but a steganogram is sent a second time.) Is it possible to implement it with Scapy, How can I do that?
With the creation of packets and they are sent there is no problem. I can use timeout and retry to not receive the confirmation message and resend the package. But I do not understand how in this case to change the payload and at the end to get a confirmation message.
You can do something like -
packet=IP() / UDP() / ... / Raw(load=your_data) # the ... are for all your other protocols
response=sr1(packet, timeout=5)
if response is None:
# response is not received, send it 2nd time
packet[Raw].load = your_data_with_steganogram
response=sr1(packet, timeout=1)
if response is None:
# response is not received, send it 3rd time
packet[Raw].load = your_data
response=sr1(packet, timeout=1)

Why doesn't peer send handshake message in response to the handshake message I send?

I've started writing my own BitTorrent client in Python 3 recently. And all was perfect until I faced the following issue:
Instead of a response handshake when I send a formatted handshake message to one of the peers, I do not get anything (b'' when buff is not decoded). Here is the code:
handshakemsg = chr(19)+"BitTorrent protocol"+8*chr(0)+
getinfohash()+"HAHA-0142421214125A-")
s.send(handshakemsg.encode())
print("Connection to peer accepted")
buff = s.recv(len(handshakemsg))
print(buff)
That's the proper way of sending handshake message I think, but the response doesn't look like the one described in the specification. I'm wondering why is that happening, and how can I avoid that?
http://bittorrent.org/beps/bep_0003.html#peer-protocol
After the fixed headers come eight reserved bytes, which are all zero in all current implementations. If you wish to extend the protocol using these bytes, please coordinate with Bram Cohen to make sure all extensions are done compatibly.
Next comes the 20 byte sha1 hash of the bencoded form of the info value from the metainfo file.
Yours is 40 (hex-encoded). Bittorrent is a binary protocol, not text.
Make sure the whole handshake message is sent to remote peer, so try to use socket.sendall() method.
change:
s.send(handshakemsg.encode())
to:
s.sendall(handshakemsg.encode())

urllib3 debug request header

I'm using urllib3 and I want to see the headers that are send.
I've found this in documentation but it doesn't print the headers:
urllib3.add_stderr_logger(1)
Is there any way of doing this?
Right now, the best way to achieve really verbose logging that includes headers sent in urllib3 is to override the default value in httplib (which is used internally).
For Python 3:
# You'll need to do this before urllib3 creates any http connection objects
import http.client
http.client.HTTPConnection.debuglevel = 5
# Now you can use urllib3 as normal
import urllib3
http = urllib3.PoolManager()
r = http.request('GET', ...)
In Python 2, the HTTPConnection object lives under the httplib module.
This will turn on verbose logging for anything that uses httplib. Note that this is not using the documented API for httplib, but it's monkeypatching the default value for the HTTPConnection class.
The goal is to add better urllib3-native logging for these kinds of things, but it hasn't been implemented yet. Related issue: https://github.com/shazow/urllib3/issues/107

linux raw ethernet socket bind to specific protocol

I'm writing code to send raw Ethernet frames between two Linux boxes. To test this I just want to get a simple client-send and server-receive.
I have the client correctly making packets (I can see them using a packet sniffer).
On the server side I initialize the socket like so:
fd = socket(PF_PACKET, SOCK_RAW, htons(MY_ETH_PROTOCOL));
where MY_ETH_PROTOCOL is a 2 byte constant I use as an ethertype so I don't hear extraneous network traffic.
when I bind this socket to my interface I must pass it a protocol again in the socket_addr struct:
socket_address.sll_protocol = htons(MY_ETH_PROTOCOL);
If I compile and run the code like this then it fails. My server does not see the packet. However if I change the code like so:
socket_address.sll_protocol = htons(ETH_P_ALL);
The server then can see the packet sent from the client (as well as many other packets) so I have to do some checking of the packet to see that it matches MY_ETH_PROTOCOL.
But I don't want my server to hear traffic that isn't being sent on the specified protocol so this isn't a solution. How do I do this?
I have resolved the issue.
According to http://linuxreviews.org/dictionary/Ethernet/ referring to the 2 byte field following the MAC addresses:
"values of that field between 64 and 1522 indicated the use of the new 802.3 Ethernet format with a length field, while values of 1536 decimal (0600 hexadecimal) and greater indicated the use of the original DIX or Ethernet II frame format with an EtherType sub-protocol identifier."
so I have to make sure my ethertype is >= 0x0600.
According to http://standards.ieee.org/regauth/ethertype/eth.txt use of 0x88b5 and 0x88b6 is "available for public use for prototype and vendor-specific protocol development." So this is what I am going to use as an ethertype. I shouldn't need any further filtering as the kernel should make sure to only pick up ethernet frames with the right destination MAC address and using that protocol.
I've worked around this problem in the past by using a packet filter.
Hand Waving (untested pseudocode)
struct bpf_insn my_filter[] = {
...
}
s = socket(PF_PACKET, SOCK_DGRAM, htons(protocol));
struct sock_fprog pf;
pf.filter = my_filter;
pf.len = my_filter_len;
setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof(pf));
sll.sll_family = PF_PACKET;
sll.sll_protocol = htons(protocol);
sll.sll_ifindex = if_nametoindex("eth0");
bind(s, &sll, sizeof(sll));
Error checking and getting the packet filter right is left as an exercise for the reader...
Depending on your application, an alternative that may be easier to get working is libpcap.

Resources