Reputation: 1656
I'm trying to build a simple Scapy script which manually manages 3-way-handshake, makes an HTTP GET request (by sending a single packet) to a web server and manually manages response packets (I need to manually send ACK packets for the response).
Here is the beginning of the script:
#!/usr/bin/python
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
# Import scapy
from scapy.all import *
# beginning of 3-way-handshake
ip=IP(dst="www.website.org")
TCP_SYN=TCP(sport=1500, dport=80, flags="S", seq=100, options=[('NOP', None), ('MSS', 1448)])
TCP_SYNACK=sr1(ip/TCP_SYN)
my_ack = TCP_SYNACK.seq + 1
TCP_ACK=TCP(sport=1500, dport=80, flags="A", seq=101, ack=my_ack)
send(ip/TCP_ACK)
TCP_PUSH=TCP(sport=1500, dport=80, flags="PA", seq=102, ack=my_ack)
send(ip/TCP_PUSH)
# end of 3-way-handshake
# beginning of GET request
getString = 'GET / HTTP/1.1\r\n\r\n'
request = ip / TCP(dport=80, sport=1500, seq=103, ack=my_ack + 1, flags='A') / getString
# help needed from here...
The script above completes the 3-way-handshake and prepares the HTTP GET request.
Then, I've to send the request through:
send(request)
Now, after the sending, I should obtain/manually read the response.
My purpose is indeed to read the response by manually sending the ACK packets of the response (this is the main focus of the script).
How can I do that?
Is the send(_)
function appropriate, or it's better to use something like response = sr1(request)
(but in this case, I suppose ACK are automatically sent)?
Upvotes: 2
Views: 2614
Reputation: 348
TCP_PUSH=TCP(sport=1500, dport=80, flags="PA", seq=102, ack=my_ack) send(ip/TCP_PUSH)
seq should be 101 not 102
Upvotes: 0
Reputation: 133
Did you try:
responce = sr1(request)
print responce.show2
Also try using a different sniffer like wireshark or tcpdump as netcat has a few bugs.
Upvotes: -1
Reputation: 7604
Use sr(), read the data in from every ans that is received (you'll need to parse, as you go, the Content-Length or the chunk lengths depending on whether you're using transfer chunking) then send ACKs in response to the last element in the ans list, then repeat until the end criteria is satisfied (don't forget to include a global timeout, I use eight passes without getting any replies which is 2 seconds).
Make sure sr is sr(req, multi=True, timeout=0.25) or thereabouts. Occasionally as you loop around there will be periods where no packets turn up, that's why HTTP has all those length specs. If the timeout is too high then you might find the server gets impatient waiting for the ACKs and starts re-sending.
Note that when you're using transfer chunking you can also attempt to cheat and just read the 0\r\n\r\n but then if that's genuinely in the data stream... yeah. Don't rely on the TCP PSH, however tempting that may look after a few Wireshark sessions with trivial use-cases.
Obviously the end result isn't a completely viable user-agent, but it's close enough for most purposes. Don't forget to send Keep-Alive headers, RST on exceptions and politely close down the TCP session if everything works.
Remember that RFC 2616 isn't 176 pages long just for giggles.
Upvotes: 2