11
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PythonでSYNパケットを送ってみる

Last updated at Posted at 2016-11-21

#SYNパケットを送るPythonスクリプト
TCPでコネクションを確立する際に送られるSYNパケットを送るPythonスクリプトを書いたのでメモです。

syn.py
import socket, struct
from ctypes import *


SRC_IP = "127.0.0.1"
DST_IP = "127.0.0.1"

SRC_PORT = 1234
DST_PORT = 5678

WINDOWSIZE = 512


class tcphdr(Structure):
    _fields_ = [
            ("src_port", c_uint16),
            ("dst_port", c_uint16),
            ("seq", c_uint32),
            ("ack_seq", c_uint32),
            ("res1", c_uint16, 4),#little endian. from here 
            ("doff", c_uint16, 4),
            ("fin", c_uint16, 1),
            ("syn", c_uint16, 1),
            ("rst", c_uint16, 1),
            ("psh", c_uint16, 1),
            ("ack", c_uint16, 1),
            ("urg", c_uint16, 1),
            ("ece", c_uint16, 1),
            ("cwr", c_uint16, 1),#to here

            #("doff", c_uint16, 4),#big endian. from here
            #("res1", c_uint16, 4),
            #("cwr", c_uint16, 1),
            #("ece", c_uint16, 1),
            #("urg", c_uint16, 1),
            #("ack", c_uint16, 1),
            #("psh", c_uint16, 1),
            #("rst", c_uint16, 1),
            #("syn", c_uint16, 1),
            #("fin", c_uint16, 1),#to here

            ("window", c_uint16),
            ("check", c_uint16),
            ("urg_ptr", c_uint16),
            ]

    def pack(self):
        return buffer(self)[:]


class dummy_iphdr(Structure):
    _fields_ = [
            ("src_ip", c_uint32),
            ("dst_ip", c_uint32),
            ("pad", c_uint8),
            ("protocol", c_uint8),
            ("len", c_uint16),
            ]

    def pack(self):
        return buffer(self)[:]


def ip2int(ip_addr):
    #return struct.unpack("!I", socket.inet_aton(ip_addr))[0]
    #inet_aton returns ip_addr in network byte order. so the '!' above is not required.
    return struct.unpack("I", socket.inet_aton(ip_addr))[0]


def calc_checksum(TCPheader):
    IPheader = dummy_iphdr()
    IPheader.src_ip = ip2int(SRC_IP)
    IPheader.dst_ip = ip2int(DST_IP)
    IPheader.pad = 0
    IPheader.protocol = 6
    IPheader.len = socket.htons(20)
    IPheader_packed = IPheader.pack()

    checksum = 0

    for i in xrange(len(IPheader_packed) / 2):
        temp = struct.unpack("H", IPheader_packed[:2])[0]
        checksum += temp
        IPheader_packed = IPheader_packed[2:]

    TCPheader_packed = TCPheader.pack()

    for i in xrange(len(TCPheader_packed) / 2):
        temp = struct.unpack("H", TCPheader_packed[:2])[0]
        checksum += temp
        TCPheader_packed = TCPheader_packed[2:]

    carry = (checksum >> 16) & 0xffff

    checksum = ~((checksum & 0xffff) + carry)

    return checksum


def build_tcp_syn_packet():
    TCPheader = tcphdr()

    TCPheader.src_port = socket.htons(SRC_PORT)
    TCPheader.dst_port = socket.htons(DST_PORT)

    TCPheader.seq = 1#a random number mihgt be better
    TCPheader.doff = len(TCPheader.pack()) / 4

    TCPheader.fin = 0
    TCPheader.syn = 1
    TCPheader.rst = 0
    TCPheader.psh = 0
    TCPheader.ack = 0
    TCPheader.urg = 0
    TCPheader.ece = 0
    TCPheader.cwr = 0

    TCPheader.check = 0
    TCPheader.window = socket.htons(WINDOWSIZE)
    TCPheader.urg_ptr = 0

    TCPheader.check = calc_checksum(TCPheader)

    return TCPheader


def send_syn_packet():
    syn_packet = build_tcp_syn_packet().pack()

    sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)

    sock.sendto(syn_packet, (DST_IP, DST_PORT))

    sock.close()


def main():
    send_syn_packet()


if __name__ == "__main__":
    main()

#ハマったところ
socketはソケットタイプにSOCK_STREAMを指定しているときはプロトコル番号に0を指定しても自動でIPパケットのプロトコル番号をTCPに設定してくれますが、SOCK_RAWを指定しているときは明示的にIPPROTO_TCPを指定する必要があるみたいです。

チェックサムの計算をする部分でハマりました。inet_atonはネットワークのバイトオーダを返すのに、それをもう一度unpackでネットワークのバイトオーダに直していたので、上手く行きませんでした(結局ネイティブのバイトオーダになっていた?)。

#最後に
書き終わった後にもっとかっこ良いPythonスクリプトみつけました(http://www.binarytides.com/python-syn-flood-program-raw-sockets-linux/ (英語))。

#参考
http://telracsmoratori.blog.fc2.com/blog-entry-116.html
https://ja.wikipedia.org/wiki/Transmission_Control_Protocol

11
13
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?