How to get the length of http response python scapy - python

So I am writing a python scapy script that will first just complete a 3 way handshake, send an http get, and then close the connection.
This is the code so far:
!/usr/bin/env python
from scapy.all import *
getStr = 'GET / HTTP/1.0\r\nHost: www.google.com\r\n\r\n'
#Send SYN
syn = IP(src="31.31.31.10",dst='31.31.31.17') / TCP(dport=80,sport=RandShort(),flags='S')
syn_ack = sr1(syn)`
#Send GET w/ ACK of server's SA
get1 = (IP(src="31.31.31.10",dst="31.31.31.17")/TCP(dport=80, sport=syn_ack[TCP].dport,seq=syn_ack[TCP].ack, ack=syn_ack[TCP].seq + 1, flags='PA')/getStr)
send (get1)
pkts = sniff(count=1,filter="host 31.31.31.17 and port 80",prn=lambda x:x.summary())
print pkts.sprintf("%TCP.len%") #Will this work? I am getting an issue here
AttributeError: 'list' object has no attribute 'sprintf'
Basically I just want to extract the len of data from the PA, which is the http response, so I can correctly generate the following sequence number to ACK the http response.
I have also tried: ans,uns=sr(get1) But I could not find a good way to get the length from this either.
I have also tried: print len(pkts.getlayer(TCP)) AttributeError: 'list' object has no attribute 'getlayer'
Any help would be appreciated

As you suspected since you have used a plural, pkts is a PacketList and not a Packet.
You can use:
for p in pkts:
if TCP in p:
print len(p[TCP].payload)
You can add and not isinstance(p[TCP].payload, NoPayload) if you want to skip packets with no data.
You can also modify the BPF filter so that it reads: "host 31.31.31.17 and tcp port 80" (add tcp).

Scapy overloads a lot of internal attributes in it's base class, one of the being __len__. Building on #Pierre's answer I would think that
for p in pkts:
print len(p)
if you need only for the length of the TCP packet and onward only, try:
for p in pkts:
print len(p[TCP])
have a look in the Scapy source at scapy/packet.py to figure you what else is overloaded by class Packet.

Do not use packet[TCP].payload alone, it includes the padding and will give you an incorrect length if the packet has padding.
Instead, you can use:
tcp_payload_len = len(pkt[TCP].payload)
if pkt.haslayer(Padding):
tcp_payload_len -= len(pkt[Padding])
see: https://github.com/secdev/scapy/issues/707

Related

How to send a request using socket and check status code?

So I am very new to Python and am now trying to understand how to send a request using TCP in Python. The sample code and document is not very helpful (to me, as I don't understand Java).
The document:
https://www.sharekhan.com/Upload/General/TradeTigerAPIForClient.pdf
I have the following till now
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server = '192.168.43.211'
port = 800
request = "DataLength = 196|Transcode = 1|LoginId = ***|MemberPassword = sh*|TradingPassword = S77*| IP = 192.618.31.211|Reserved = |"
s.connect((server,port))
s.send(request.encode())
result = s.recv(4096)
If I use this the program shows I am connected and the result is b''
I also tried
request = "|DataLength =108|Transcode = 21|Exchange Code=NC|Reserved=|"
result is b'Hurray you are connected'
How do I use the commands from the document to get data?
According to this, you can send a TCP packet like this:
import socket
server = '192.168.31.211'
port = 80
buffer_size = 4096
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((server, port))
sock.send(message)
data = sock.recv(buffer_size)
sock.close()
Note I didn't include your message here, nor did I encode your data. However, as was pointed out in the comments, your IP address is incorrectly written and refers to a private IP address, according to the IANA so if you're trying to send out over a public network, this won't work. Additionally, I have noticed a couple of other problems with your code:
Your message looks like you've manually included TCP header information. Be aware that by using the socket library the way you are and the way I have suggested, you are making a TCP request. The header information will therefore be included with your request so you don't need to include it yourself.
What you have here is the client code and you didn't include any server code. Have you written code for your server? If not, you'll need some.
Otherwise, I can't see any problems with your code.

What is the best way to fork scapy in order to duplicate packets

I have a pretty simple script which supposed to duplicate packets using scapy:
from scapy.all import *
import pprint
ips = [
"192.168.0.1",
"192.168.0.2",
"192.168.0.3",
"192.168.0.4",
"192.168.0.5",
"192.168.0.6",
"192.168.0.7"
]
def dup_pkt(pkt):
pprint.pprint(pkt)
if pkt[IP].dst == "10.0.0.1":
for ip in ips:
pkt2 = copy.deepcopy(pkt)
pkt2[IP].dst = ip
print "Packet1:",pkt[IP].dst,"Packet2:",pkt2[IP].dst
send(pkt2)
pkts = sniff(prn=dup_pkt, filter="port 53", store=0, count=2)
Instead of the for loop, I wish to send it to the multiple destination all at once. I thought about forking processes which each one will send the packets but it still leaves me with the for loop.
Also - send() is very slow, but sendp() does not fit as I have different destinations.
I've read this one: how to send one udp packet multiple time in scapy ? but there is no answer there.
How can I send multiple packets at once?
Thanks
The send() function can receive a list of packets to send:
def dup_pkt(pkt):
pprint.pprint(pkt)
if pkt[IP].dst == '10.0.0.1':
pkts = []
for ip in ips:
pkt2 = pkt.copy() # use the copy method rather than copy.deepcopy
pkt2[IP].dst = ip
pkts.append(pkt2)
print "Packet1: ", pkt[IP].dst, " Packet2: ", pkt2[IP].dst
send(pkts) # send all packets at once

Sending a ICMPv6 Packet with VLAN while using Impacket

Hey guys I am quite a bind I have this function
def send_ra_packet(self,source_link_layer, send_frequency,vlan_id = 0):
ip = IP6.IP6()
ip.set_source_address(self.get_source_address())
ip.set_destination_address(self.get_target_address())
ip.set_traffic_class(0)
ip.set_flow_label(0)
ip.set_hop_limit(64)
s = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_ICMPV6)
payload = self.create_ra_message(source_link_layer)
print send_frequency
for i in range(0, send_frequency):
icmp = ICMP6.ICMP6()
icmp.set_byte(0, 134) # Put Type?
icmp.set_byte(1, 00) # Put Code?
payloadObject = ImpactPacket.Data()
payloadObject.set_data(payload)
icmp.contains(payloadObject)
# Have the IP packet contain the ICMP packet (along with its payload).
ip.contains(icmp)
ip.set_next_header(ip.child().get_ip_protocol_number())
ip.set_payload_length(ip.child().get_size())
eth = ImpactPacket.Ethernet()
vlan = ImpactPacket.EthernetTag()
vlan.set_vid(1)
eth.push_tag(vlan)
icmp.calculate_checksum()
eth.contains(ip)
print icmp.get_packet()
# Send it to the target host.
s.sendto(eth.get_packet(), (self.get_target_address(), 0))
print "Success Sending Packet - %d " % (i)
A quick overview of the function will tell you that I am creating a RA Packet and sending it in my network, my problem here is that I can't seem to send an RA Packet with VLAN.
My additional code starting from eth = ImpacketPacket.Ethernet()
will tell you I created a Header that has a VLAN and made it as a parent of ip which has the instance IPV6.
My problem is that when ever I run the code the resulting packet that will be sent is Uknown (0)
which means that it is either corrupted or cannot be understand.
I am quite stuck with this problem for almost a week now and tried numerous ways to send it. I am not sure anymore what is the bug, if ever I send the packet with icmp instead of eth it works fine`

Python Port Scanner

Am newbie to python and stuck at a point. I want to create port scanner with using only python 3 inbuilt libraries (means avoiding scapy etc) I have following code :
import socket
for i in range(1,26):
s = socket.socket()
s.settimeout(0.5)
ip = "74.207.244.221" #scanme.nmap.org
response = s.connect_ex((ip, i))
if response:
print ("%d\tclose" %i)
else:
print ("%d\topen" %i)
s.close()
Now I want to add 2 functionalities to this : that is
Distinguish between close and filtered ports . In both cases am receiving same errno in return so how can I check if I have received back a rst packet or nothing ? As far as I have tried s.recv() isn't working for this.
I want to control the number of tries (attempts), i.e I want to send only one or two syn packets. I don't want this program to send more than 2 syn packets for probes. How can this thing be achieved ?
Distinguish between close and filtered ports . In both cases am
receiving same errno in return so how can I check if I have received
back a rst packet or nothing
You've probably only checked with servers that send back a RST. Here's what I tried:
First case, normal config:
>>> os.strerror(s.connect_ex((ip, 81)))
'Connection refused'
Second, with manual iptables:
iptables -A OUTPUT -p tcp --dport 81 -j DROP
>>> os.strerror(s.connect_ex((ip, 81)))
'Resource temporarily unavailable'
I want to control the number of tries (attempts), i.e I want to send
only one or two syn packets.
I don't think there's a setsockopt TCP option exposed, but on linux there's:
net.ipv4.tcp_syn_retries
However, since you limited the timeout for the socket, all operations that don't finish within 0.5 seconds will time out. So it's likely only 1 or 2 SYNs will leave the station.
#!/usr/bin/python
import socket
s = socket.socket(socket.AF_INET, socekt.SOCK_STREAM)
host = 74.207.244.221
def portscan(port):
try:
s.connect((host,port))
return True
else:
return False
for x in range(1,255):
if portscan(x):
print('Port',x,'Is Open')

python icmp raw socket implementation

i am relatively new to python, so please be considerate...
i'm implementing a server and a client via raw_sockets.
i have the necessary privileges.
now, the server i defined so:
host = socket.gethostbyname(socket.gethostname())
address = (host, 22224)
sockSer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
sockSer.bind(address)
sockSer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
packet, addr = sockSer .recvfrom(4096) # wait for packet from client
Q1) why can't i simply type: hosts = 'localhost'.
if i do so, it doesn't allow me to write the line: sockSer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON). and then the server doesn't receive my client's messages.
only when doing gethostbyname(socket.gethostname()) i get 192.168.1.101
and then it works.
in a different class:
the client socket:
host = socket.gethostbyname(socket.gethostname())
address = (host, 22224)
sockCli = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
Q2) do i also need to type: sockCli.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
or maybe sockCli.connect(address)? seems that it works without the connect command.
for the client socket?
now, the problems arise when i do the following:
1) send a packet from client to server:
header=...
payload='a'
sockCli.sendto(header + payload, address)
2) receive packet in server and send something back to client:
while(true):
data, addr = sockSer.recvfrom(4096)
header2=...
payload2='b'
sockSer.sendto(header2 + payload2, addr)
now, my important question is:
Q3) the server sent only 1 packet to client, with payload 'b'.
what happens is, my client actually receives 2 packets in the while loop:
first packet is what the client itself sent to server, and the other packet is what the client got from the server.
hence my output is 'ab' instead of simply 'b'
why is this happening???
NOTE: i didn't type the entire code, but i think my syntax,parsing,header composition etc.. are correct.
is there an obvious problem in my code?
if necessary i'll upload the entire code.
thanks
I got this too.
my solution is add a judge in the receive code,such as if I send Ping package so I only want ECHO Reply( type 0 code 0), I write
if type != 0:
continue
and you also can write as
if addr == my_ip:
continue
It seems not has any smooth solution
Q1: I was able to bind to localhost and call IOCTL with both parameters just fine. Assuming your client is also running on the same system, ensure the client is sending to "localhost", otherwise your server will never receive the packets. If your client is on another system, obviously your server will never receive the packets.
Q2: You do not need IOCTL for sending the packet. Just send it via sendto().
Q3: The reason you're seeing two replies is, the kernel is also processing the echo request, in addition to your own user-space code.
Although you can use ICMP for arbitrary message passing, as someone else pointed out this isn't its intended design. You may find that your data portion is truncated out in message replies. For example, when sending echo requests, your reply likely will contain everything you sent; however, a reply that is type 3 code 3 may not include your data, but only the first 8 bytes of the ICMP header.

Categories

Resources