저번에 말씀드린 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 staticNetworkInterface[] devices = JpcapCaptor.getDeviceList();// interface list displayfor (int i = 0; i < devices.length; i++)System.out.println(i + ":" + devices[i].name + "("+ devices[i].description + ")");
// select interfaceSystem.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 startDump_for_thread t = new Dump_for_thread(); ///스레드 생성해서 sending과 capture를 동시에...Thread thd1 = new Thread(t);thd1.start();try { //just wait.. because interval..no reasonrseinIntThread.sleep(2 * 1000); ///보내는 시작 속도가 캡쳐시작속도보다 빨라서 2초기다리고} catch (InterruptedException e) { }//Target IP setting //커맨드 형식에 따라 IP를 받아서 셋팅가능토록 배열에 저장해두고byte[] TarIp = InetAddress.getByName(args[0]).getAddress();//Target mask setting //커맨드 형식에 따라 마스크 정보를 입력받아 스캔할 범위를 자동으로 지정byte startIp=0; //마스크에 따른 시작 IPbyte endIp=0; //마스크에 따른 마지막IPint 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 initJpcapSender sender = JpcapSender.openDevice(devices[device]);// make raw packetPacket 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, Lengthpb[14] = (byte) 0x45; ///헤더 길이 5*4 =20 type변경시 헤더길이 변경해줘야함//TOS //상황에따라 수정가능 .. 보통건드리지 않고pb[15] = (byte) 0x00;// Total Length0 //전체 데이터의 길이를 구하기 위해 계산 16비트이므로 최대 2^16pb[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
//TYPEpb[34] = (byte)0x08; //request//Codepb[35] = (byte)0x00; ////Checksumpb[36] = 0; //일단 비워두고 나중에 계산해서 채움pb[37] = 0;//IDintpb[38] = 0; //보내는 쪽이므로 신경쓸필요없음pb[39] = 0;//Sequence Numberpb[40] = 0; //보내는 쪽이므로 신경쓸필요없음pb[41] = 0;///data 임의데이터 생성for (int i = 0; i < 22; i++)pb[42+i] = (byte)i;//Checksumbyte ICMPHeader[] = new byte[30]; ///IPHeader과 마찬가지로for(int i=0; i<30; i++){ICMPHeader[i] = pb[i+34];}//////////ICMP Checksumpb[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 />
//////////////// dump.java ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////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 blocke.printStackTrace();}jpcap.loopPacket(-1, new dump());}}<br />
===============================================================================================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 를 이용한 스캔에서는 수정되는 부분만 올리고 설명하도록 하겠습니다.
'프로그래밍 > jpcap programming' 카테고리의 다른 글
SynFlooding 이해와 공격 소스포함 (0) | 2011.07.22 |
---|---|
MIMA 중간자 공격 구현 및 설명 (0) | 2011.07.04 |
jpcap 을 이용한 ARP spoofing소스 (request) (0) | 2011.06.03 |
ARP 이해 및 공격방어 (0) | 2011.06.02 |
Jpcap을 이용한 패킷 보내기 2 (0) | 2011.06.02 |