C#の勉強を兼ねて、単純なポートスキャンコードを書いてみました。
raw socketで実現出来ると思ったのですが、実験したところIPパケットまでは送れましたが、TCPパケットは送れませんでした。
どうやらXP SP2からセキュリティ上の理由により、raw socketに制限が設けられたそうです。
そこで、Windows版Wireshark、nmapなどでも利用されているWinPcapを使うことにしました。
SharpPcapというC#用のラッパーがあったので、それを使います。
TCP/IPヘッダに関しては以下を
SharpPcapの使い方に関しては以下を
ポートスキャンに関しては以下を主に参考にしました。
デバイスと送信先IPを入力すると、Well known portに対してSYNスキャンを試みます。
開いているポートがあれば、表示します。
(Debug.WriteLineでコンソールへの出力もしているので、Debugビルドしてください)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
- | - | - | - | | - ! - | | ! | - ! | | | | - | ! | | | | | - ! | - - | ! - | | ! ! | - | | ! | - ! | | - ! | | | | - ! | - ! | - - ! | | | - ! | | - ! | | | - ! | | | | - | ! | | | - | - - ! | - ! | - | ! - | - - ! ! | ! | - - | ! | - | ! | - - ! | - - ! | ! ! | - | ! ! ! | - ! ! | - | ! | | | ! ! !using System; using PacketDotNet; using SharpPcap; using System.Diagnostics; using System.Net; using System.Net.NetworkInformation; namespace winpcap_test { public class Program { public static void Main(string[] args) { try { Debug.Listeners.Add(new TextWriterTraceListener(Console.Out)); // デバイスが無ければ終了 if (LivePcapDeviceList.Instance.Count < 1) { Debug.WriteLine("No. Devices were found on this machine"); return; } // デバイス一覧から、使用するデバイスを選択させる Debug.WriteLine("The following devices are available on this machine:"); Debug.WriteLine("----------------------------------------------------"); Debug.WriteLine(""); int i = 0; foreach (LivePcapDevice dev in LivePcapDeviceList.Instance) { Debug.WriteLine(String.Format("{0}) {1}", i++, dev.Description)); } Debug.WriteLine(""); Debug.Write("-- Please choose a device to send a packet on: "); i = int.Parse(Console.ReadLine()); LivePcapDevice device = LivePcapDeviceList.Instance[i]; // 送信元IPアドレス取得 String srcIPAddress = ""; foreach (PcapAddress addr in device.Interface.Addresses) { // ARPを送って送信先MACアドレスを取得したいので、IPv4アドレスを探す // ネットマスクの有無をみる簡易判定 if (addr.Netmask.ToString() != "") { srcIPAddress = addr.Addr.ToString(); break; } } if (srcIPAddress == "") { Debug.WriteLine("No. IP Address were found on this devices"); return; } // 送信先IPアドレス取得 Console.Write("-- Please target IP address: "); String targetIPAddress = Console.ReadLine(); // 送信先MACアドレス取得 ARP arp = new ARP(); PhysicalAddress targetMacAddress = arp.Resolve(IPAddress.Parse(targetIPAddress), device.Name, IPAddress.Parse(srcIPAddress)); // デバイスオープン device.Open(DeviceMode.Normal, 20); // SYNスキャン Debug.WriteLine("-- Scanning well known tcp port. Please wait..."); for (ushort targetPort = 0; targetPort <= 1024; targetPort++) { // TCPヘッダ生成 TcpPacket tcpPacket = new TcpPacket(1024, targetPort); tcpPacket.Syn = !tcpPacket.Syn; tcpPacket.WindowSize = 4096; // IPヘッダ生成 IPv4Packet ipPacket = new IPv4Packet(IPAddress.Parse(srcIPAddress), IPAddress.Parse(targetIPAddress)); // Ethernetヘッダ生成 EthernetPacket ethernetPacket = new EthernetPacket(device.Interface.MacAddress, targetMacAddress, EthernetPacketType.None); // TCPパケット作成 ipPacket.PayloadPacket = tcpPacket; tcpPacket.UpdateTCPChecksum(); ethernetPacket.PayloadPacket = ipPacket; ipPacket.UpdateIPChecksum(); // フィルタセット // ターゲットIP、Portからのパケットかつ、SYN/ACKまたはRSTが立っているものをキャッチする device.Filter = "src host " + targetIPAddress + " and src port " + targetPort + " and (tcp[13] & 18 != 0) or (tcp[13] & 4 != 0)"; const int maxRetryCount = 3; for (int retryCount = 0; retryCount < maxRetryCount; retryCount++) { try { // TCPパケット送信 device.SendPacket(ethernetPacket); // 受信パケット取得 RawPacket rawpacket = device.GetNextPacket(); // 取得できなかったら、数回繰り返す // それでダメなら、filtered判定 if (rawpacket == null) { if ((retryCount + 1) >= maxRetryCount) { //Debug.WriteLine("Port " + targetport + " is filtered"); break; } continue; } else { // SYN/ACKフラグが立っていたら、open判定 // RSTフラグが立っていたらclosed判定 TcpPacket response = TcpPacket.GetEncapsulated(Packet.ParsePacket(rawpacket)); if (response.Ack == true && response.Syn == true) { Debug.WriteLine("Port " + targetPort + " is open"); } else if (response.Rst == true) { //Debug.WriteLine("Port " + targetport + " is closed"); } else { //Debug.WriteLine("Port " + targetport + " is unknown"); } break; } } catch (Exception e) { Debug.WriteLine(String.Format("{0}({1})", e.Message, e.Source)); } } } // 後始末 device.Close(); } catch (Exception e) { Debug.WriteLine(String.Format("Error:{0}({1})", e.Message, e.Source)); } Debug.WriteLine("-- Please return any keys."); Console.ReadLine(); } } }