I want to send an HTTP packet to port 31112, but I want to change the IP identification header to 0xabcd.
What I am doing is using iptables for, whatever packet with destination port 31112, redirect it to a queue:
iptables -A OUTPUT -p tcp --dport 31112-j NFQUEUE --queue-num 1
I have also enabled forwarding:
sysctl -w net.ipv4.ip_forward=1
My program is this one:
#!/usr/bin/env python
from netfilterqueue import NetfilterQueue
from scapy.all import *
def print_and_accept(pkt):
data = pkt.get_payload()
ip_h = IP(data)
print ('source: ' + ip_h[IP].src)
print ('destination: ' + ip_h[IP].dst)
print ('IP TTL: ' + str(ip_h[IP].ttl))
print (str (ip_h[TCP].payload))
ip_h[IP].ttl = 40
ip_h[IP].id = 0xabcd
#print (ip_h[IP].id)
del ip_h[IP].chksum
send(ip_h,verbose=0)
nfqueue = NetfilterQueue()
nfqueue.bind(1, print_and_accept)
try:
nfqueue.run()
except KeyboardInterrupt:
print ('\nProgram Ended')
And, when I send a curl to my destination:
curl http://serverexample.com:31112/
I get this in my program's output:
source: 192.168.206.128
destination: 35.182.181.240
IP TTL: 64
It is weird that I don't capture this:
print (str (ip_h[TCP].payload))
which I think it must be something like "GET / HTTP/1.1" and whatever headers might follow.
I want to know if someone can spot the issue.
Regards
You change the source of the TCP SYN, which means that the SYN+ACK from the server gets send to the IP address you gave at source - and thus does not arrive at your system. This means the TCP handshake will not be completed. But transfer of application data (i.e. the HTTP messages) will only be done after a completed TCP handshake.
Related
On Windows 10 I want to read data from UDP port 9001. I have created the following script which does not give any output (python 3.10.9):
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("", 9001))
while True:
data, addr = sock.recv(1024)
print(f"received message: {data.decode()} from {addr}")
I checked that a device is sending UDP data on port 9001 using wireshark. But the above code just "runs" on powershell without any output (and without any errors).
Any ideas how to fix this?
I found this page with a powershell script that is supposed to listen to a UDP port. So I tried this and created a file Start-UDPServer.ps1 with the content as described in that page as follows:
function Start-UDPServer {
[CmdletBinding()]
param (
# Parameter help description
[Parameter(Mandatory = $false)]
$Port = 10000
)
# Create a endpoint that represents the remote host from which the data was sent.
$RemoteComputer = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Any, 0)
Write-Host "Server is waiting for connections - $($UdpObject.Client.LocalEndPoint)"
Write-Host "Stop with CRTL + C"
# Loop de Loop
do {
# Create a UDP listender on Port $Port
$UdpObject = New-Object System.Net.Sockets.UdpClient($Port)
# Return the UDP datagram that was sent by the remote host
$ReceiveBytes = $UdpObject.Receive([ref]$RemoteComputer)
# Close UDP connection
$UdpObject.Close()
# Convert received UDP datagram from Bytes to String
$ASCIIEncoding = New-Object System.Text.ASCIIEncoding
[string]$ReturnString = $ASCIIEncoding.GetString($ReceiveBytes)
# Output information
[PSCustomObject]#{
LocalDateTime = $(Get-Date -UFormat "%Y-%m-%d %T")
SourceIP = $RemoteComputer.address.ToString()
SourcePort = $RemoteComputer.Port.ToString()
Payload = $ReturnString
}
} while (1)
}
and started it in an Powershell terminal (as admin) as
.\Start-UDPServer.ps1 -Port 9001
and it returned to the Powershell immediately without ANY output (or error message). Maybe windows is broken?
If there is a solution to finally listen to UDP port 9001, I still strongly prefer a python solution!
As far as I can see, your posted Python code should have given you an error when run if it was receiving any data, so that suggests that the data was not getting to the process at all.
I'd recommend checking your Windows Firewall settings for that port, and any other host-based firewalls you might be running.
But also, the recv() method does not return a tuple. recvfrom() does, so the following code works:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("", 9001))
while True:
data, addr = sock.recvfrom(1024)
print(f"received message: {data.decode()} from {addr}")
A tangential note: the Powershell script does not actually start a UDP server, it just creates a function to do so. So you need to add a line Start-UDPServer -Port 9001 at the end to call the function if you want it to actually listen for datagrams.
#!/usr/bin/python
from scapy.all import *
def findWeb():
a = sr1(IP(dst="8.8.8.8")/UDP()/DNS(qd=DNSQR(qname="www.google.com")),verbose=0)
return a[DNSRR].rdata
def sendPacket(dst,src):
ip = IP(dst = dst)
SYN = TCP(sport=1500, dport=80, flags='S')
SYNACK = sr1(ip/SYN)
my_ack = SYNACK.seq + 1
ACK = TCP(sport=1050, dport=80, flags='A', ack=my_ack)
send(ip/ACK)
payload = "stuff"
PUSH = TCP(sport=1050, dport=80, flags='PA', seq=11, ack=my_ack)
send(ip/PUSH/payload)
http = sr1(ip/TCP()/'GET /index.html HTTP/1.0 \n\n',verbose=0)
print http.show()
src = '10.0.0.24'
dst = findWeb()
sendPacket(dst,src)
I'm trying to do HTTP packets with SCAPY
I am using UBUNTU on VMwaer
The problem is that every time I send messages I have RESET
How do we fix it?
Thanks
sniff package image
Few things I notice wrong.
1. You have your sequence number set statically (seq=11) which is wrong. Sequence numbers are always randomly generated and they must be used as per RFC793. So the sequence should be = SYNACK[TCP].ack
You set your source port as 1500 during SYN packet, but then you use it as 1050 (typo?)
You don't need extra payload/PUSH.
Also, have a look at these threads:
How to create HTTP GET request Scapy?
Python-Scapy or the like-How can I create an HTTP GET request at the packet level
I need to create HTTP GET request and save the data response.
I tried to use this:
syn = IP(dst=URL) / TCP(dport=80, flags='S')
syn_ack = sr1(syn)
getStr = 'GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n'
request = IP(dst='www.google.com') / TCP(dport=80, sport=syn_ack[TCP].dport,
seq=syn_ack[TCP].ack, ack=syn_ack[TCP].seq + 1, flags='A') / getStr
reply = sr1(request)
print reply.show()
But when I print reply I don't see any data response.
In addition, when I checked in 'Wireshark' I got SYN, SYN/ACK but I didn't get an ACK.
Image:
Edit:
I try to do that now:
# Import scapy
from scapy.all import *
# Print info header
print "[*] ACK-GET example -- Thijs 'Thice' Bosschert, 06-06-2011"
# Prepare GET statement
get='GET / HTTP/1.0\n\n'
# Set up target IP
ip=IP(dst="www.google.com")
# Generate random source port number
port=RandNum(1024,65535)
# Create SYN packet
SYN=ip/TCP(sport=port, dport=80, flags="S", seq=42)
# Send SYN and receive SYN,ACK
print "\n[*] Sending SYN packet"
SYNACK=sr1(SYN)
# Create ACK with GET request
ACK=ip/TCP(sport=SYNACK.dport, dport=80, flags="A", seq=SYNACK.ack, ack=SYNACK.seq + 1) / get
# SEND our ACK-GET request
print "\n[*] Sending ACK-GET packet"
reply,error=sr(ACK)
# print reply from server
print "\n[*] Reply from server:"
print reply.show()
print '\n[*] Done!'
but its print me in reply from server;
0000 IP / TCP 192.168.44.130:23181 > 216.58.208.164:http A / Raw ==>
IP / TCP 216.58.208.164:http > 192.168.44.130:23181 A / Padding None
And I need Line-based text data: text/html.
You are sending a RST segment in response to the SYN-ACK because your kernel has no knowledge of the SYN you sent via Scapy (see here). This could be solved with an iptable rule:
iptables -A OUTPUT -p tcp --tcp-flags RST RST -s <your ip> -j DROP
Because you are ending the connection with that RST segment, when you send your HTTP request, the endpoint answers with a RST too because connection is not established and so you are using show() on a RST segment with no data, that is why you do not see anything.
You are sending a SYN and correctly receiving a SYN_ACK. At this point, you should generate and send an ACK based on the SYN_ACK that you've received, and THEN finally transmit the HTTP GET request. It seems that you are somewhat confused about the TCP 3-way handshake mechanism. In short, you are not supposed to 'get' an ACK, you are supposed to generate and send this yourself.
After setting the rule in your iptables as has been suggested above, you could do the following :
from scapy.all import *
seq = 12345
sport = 1040
dport = 80
ip_packet = IP(dst='192.168.56.107')
syn_packet = TCP(sport=sport, dport=dport, flags='S', seq=seq)
packet = ip_packet/syn_packet
synack_response = sr1(packet)
next_seq = seq + 1
my_ack = synack_response.seq + 1
ack_packet = TCP(sport=sport, dport=dport, flags='A', seq=next_seq, ack=my_ack)
send(ip_packet/ack_packet)
payload_packet = TCP(sport=sport, dport=dport, flags='A', seq=next_seq, ack=my_ack)
payload = "GET / HTTP/1.0\r\nHOST: 192.168.56.107\r\n\r\n"
reply, error = sr(ip_packet/payload_packet/payload, multi=1, timeout=1)
for r in reply:
r[0].show2()
r[1].show2()
Hope this helps. Basically, the first response you get back does not really hold the HTTP response data. I tested the script against an INETSIM simulated HTTP server and in that case (at least) the first packet (after the 3-way TCP handshake) that the server responded with was a series of NULL (0x00) bytes. Hence using multi somehow did the stuff in my case.
Hello I am using nfqueue and scapy and I my goal is to recieve packets at my NFQUEUE, change the payload and resend them.
I can change fields like the TTL without any kind of problem, but when it comes to change the payload, I am encoutering problems.
When I change the payload, I sniff the packet with wireshark and apparently I send the packet with the payload modified, but the server doesn't answer.
This is my code:
#!/usr/bin/env python
import nfqueue
from scapy.all import *
def callback(payload):
data = payload.get_data()
pkt = IP(data)
pkt[TCP].payload = str(pkt[TCP].payload).replace("ABC","GET")
pkt[IP].ttl = 40
print 'Data: '+ str(pkt[TCP].payload)
print 'TTL: ' + str(pkt[IP].ttl)
del pkt[IP].chksum
payload.set_verdict_modified(nfqueue.NF_ACCEPT, str(pkt), len(pkt))
def main():
q = nfqueue.queue()
q.open()
q.bind(socket.AF_INET)
q.set_callback(callback)
q.create_queue(0)
try:
q.try_run() # Main loop
except KeyboardInterrupt:
q.unbind(socket.AF_INET)
q.close()
main()
I have set this rule for outgoing traffic to port 80: iptables -I OUTPUT -s 192.168.1.10 -p tcp --dport 80 -j NFQUEUE
And, to test it, for example I open telnet to google port 80, do a GET / HTTP/1.1 and this is what I see:
TTL: 40
DATA: GET / HTTP/1.1
Now, if I do ABC / HTTP/1.1 I receive no answer! My telnet just get stuck.
I have also tried on HTTP websites browers to browse something, check on wireshark how my TTL is really changing to 40, then, browse the string "ABC" and my browser again get stuck.
I sniff the request changed to GET but I receive no answer.
Thank is kind of giving me a headache and I would really appreciate if someone with more experience could lead me to the right way. Thank you in advance.
I added the line for recalculate the TCP checksum, that was usefull.
That only works if I change payload I don't alter the lenght of it, otherwise, I would need to change the field length of the IP Header, and answering myself, and maybe other people that is looking for this answer, I achieve that just by doing:
payload_before = len(pkt[TCP].payload)
pkt[TCP].payload = str(pkt[TCP].payload).replace("Heading","Other string")
payload_after = len(pkt[TCP].payload)
payload_dif = payload_after - payload_before
pkt[IP].len = pkt[IP].len + payload_dif
I know that I have to change more fields, because sometimes, if you add enough payload for needing to fragment into a new packet, you have to change more fields.
Currently I don't know how to achieve this efficiently but little by little. Hope someone find my solution for altering the payload useful.
In the second case, you are tampering the TCP layer as well as the IP layer.
You're letting Scapy fix the IP checksum, but not the TCP one. Change del pkt[IP].chksum to del pkt[IP].chksum pkt[TCP].chksum in your code.
I'm trying to set up a remote backup server for dar, along these lines. I'd really like to do all the piping with python if possible, but I've asked a separate question about that.
Using netcat in subprocess.Popen(cmd, shell=True), I succeeded in making a differential backup, as in the examples on the dar site. The only two problems are:
I don't know how to assign port numbers dynamically this way
If I execute the server in the background, it fails. Why?
Update: This doesn't seem to be related to netcat; it hangs even without netcat in the mix.
Here's my code:
from socket import socket, AF_INET, SOCK_STREAM
import os, sys
import SocketServer
import subprocess
class DarHandler(SocketServer.BaseRequestHandler):
def handle(self):
print('entering handler')
data = self.request.recv(1024).strip()
print('got: ' + data)
if data == 'xform':
cmd1 = 'nc -dl 41201 | dar_slave archives/remotehost | nc -l 41202'
print(cmd1)
cmd2 = 'nc -dl 41200 | dar_xform -s 10k - archives/diffbackup'
print(cmd2)
proc1 = subprocess.Popen(cmd1, shell=True)
proc2 = subprocess.Popen(cmd2, shell=True)
print('sending port number')
self.request.send('41200')
print('waiting')
result = str(proc1.wait())
print('nc-dar_slave-nc returned ' + result)
result = str(proc2.wait())
print('nc-dar_xform returned ' + result)
else:
result = 'bad request'
self.request.send(result)
print('send result, exiting handler')
myaddress = ('localhost', 18010)
def server():
server = SocketServer.TCPServer(myaddress, DarHandler)
print('listening')
server.serve_forever()
def client():
sock = socket(AF_INET, SOCK_STREAM)
print('connecting')
sock.connect(('localhost', 18010))
print('connected, sending request')
sock.send('xform')
print('waiting for response')
port = sock.recv(1024)
print('got: ' + port)
try:
os.unlink('toslave')
except:
pass
os.mkfifo('toslave')
cmd1 = 'nc -w3 localhost 41201 < toslave'
cmd2 = 'nc -w3 localhost 41202 | dar -B config/test.dcf -A - -o toslave -c - | nc -w3 localhost ' + port
print(cmd2)
proc1 = subprocess.Popen(cmd1, shell=True)
proc2 = subprocess.Popen(cmd2, shell=True)
print('waiting')
result2 = proc2.wait()
result1 = proc1.wait()
print('nc<fifo returned: ' + str(result1))
print('nc-dar-nc returned: ' + str(result2))
result = sock.recv(1024)
print('received: ' + result)
sock.close()
print('socket closed, exiting')
if __name__ == "__main__":
if sys.argv[1].startswith('serv'):
server()
else:
client()
Here's what happens on the server:
$ python clientserver.py serve &
[1] 4651
$ listening
entering handler
got: xform
nc -dl 41201 | dar_slave archives/remotehost | nc -l 41202
nc -dl 41200 | dar_xform -s 10k - archives/diffbackup
sending port number
waiting
[1]+ Stopped python clientserver.py serve
Here's what happens on the client:
$ python clientserver.py client
connecting
connected, sending request
waiting for response
got: 41200
nc -w3 localhost 41202 | dar -B config/test.dcf -A - -o toslave -c - | nc -w3 localhost 41200
waiting
FATAL error, aborting operation
Corrupted data read on pipe
nc<fifo returned: 1
nc-dar-nc returned: 1
The client also hangs, and I have to kill it with a keyboard interrupt.
I'd cut my losses and start over. This solution attempt is very complicated and kludgy. There are many ready-made solutions in the area:
10 outstanding Linux backup utilities
Fwbackups sounds good if you want to take the easy route, rsync+ssh for the hard core.
Use Popen.communicate() instead of Popen.wait().
The python documentation for wait() states:
Warning: This will deadlock if the child process generates enough output to a stdout or stderr pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that.
Dar and its related executables should get a -Q if they aren't running interactively.
When syncronizing multiple processes, make sure to call communicate() on the 'weakest link' first: dar_slave before dar_xform and dar before cat. This was done correctly in the question, but it's worth noting.
Clean up shared resources. The client process is holding open a socket from which dar_xform is still reading. Attempting to send/recv data on the initial socket after dar and friends are finished without closing that socket will therefore cause a deadlock.
Here is a working example which doesn't use shell=True or netcat. An advantage of this is I can have the secondary ports assigned dynamically and therefore could conceivably serve multiple backup clients simultaneously.