#c #linux #sockets #networking #spoofing
Вопрос:
Я работаю над подделкой пакетов и отправкой их через необработанный сокет с помощью
int s = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);
У меня есть несколько вопросов. Пакет, который я подделал (и в каждом руководстве, которое я нашел в Интернете), начинался с iphdr. Функция sendto автоматически добавляет в нее ethhdr. Поскольку я его не добавляю, я не могу его изменить.
Первый вопрос заключался в том, могу ли я каким-либо образом манипулировать ethhdr.
Во — вторых, в iphdr мой sendto действует по-разному в зависимости от значения iph — >мгп. Если я установлю значение 5 (как обычно), оно изменится
- Мое значение контрольной суммы
- iph->tot_len к большому концу
- Значение адреса источника в iphdr для IP-адреса моих компьютеров, если оно равно 0.0.0.0
Однако при любом другом значении это позволяет пакету проходить гладко без каких-либо изменений.
Вот скриншот с iph->ihl, установленным на 3 (не 5)[Точно так же]
Вот скриншот с iph->ihl, установленным на 5 [Изменено]
Вот сценарии:
recv.c
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#include<errno.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<sys/ioctl.h>
#include<net/if.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<netinet/if_ether.h>
#include<netinet/udp.h>
#include<linux/if_packet.h>
#include<arpa/inet.h>
#define min(x,y) (x<y)?x:y
void pkt_hex_dump(uint8_t *data, size_t len)
{
int rowsize = 16;
int i, l, linelen, remaining;
int li = 0;
uint8_t ch;
printf("nPacket hex dump:n");
printf("Packet Size = %ldn", len);
remaining = len;
for (i = 0; i < len; i = rowsize) {
printf("dt", li);
linelen = min(remaining, rowsize);
remaining -= rowsize;
for (l = 0; l < linelen; l ) {
ch = data[l];
printf("X ", (uint32_t) ch);
}
data = linelen;
li = 10;
printf("n");
}
}
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*)amp;oddbyte)=*(u_char*)ptr;
sum =oddbyte;
}
sum = (sum>>16) (sum amp; 0xffff);
sum = sum (sum>>16);
answer=(short)~sum;
return(answer);
}
int main()
{
int sock_r = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
if (sock_r == -1) {
printf("error in socket");
return -1;
}
unsigned char* buffer = (unsigned char *)malloc(65536);
memset(buffer,0,65536);
while(1)
{
int saddr_len, buflen;
struct sockaddr saddr;
saddr_len = sizeof saddr;
buflen = recvfrom(sock_r, buffer, 65536, 0, amp;saddr, (socklen_t *)amp;saddr_len);
printf("n[NEW PACKET]n");
unsigned char* data = buffer sizeof(struct ethhdr) sizeof(struct iphdr) sizeof(struct udphdr);
if(buflen<0)
{
printf("error in reading recvfrom functionn");
return -1;
}
union ipv4
{
__be32 src;
uint8_t ip[4];
};
struct iphdr *iph = (struct iphdr *)(buffer sizeof(struct ethhdr));
union ipv4 src_ip;
src_ip.src = iph->saddr;
struct udphdr *udph = (struct udphdr *)(buffer sizeof(struct ethhdr) sizeof(struct iphdr));
printf("Source = %d.%d.%d.%dn",(int)src_ip.ip[0],(int)src_ip.ip[1],(int)src_ip.ip[2],(int)src_ip.ip[3]);
printf("Checksum Value : %dn",(int)iph->check);
printf("Checksum UDP : %dn",(int)udph->check);
printf("Data Received:n%sn",data);
pkt_hex_dump((uint8_t *)iph,buflen - sizeof(struct ethhdr));
//recheck csum values
iph->check = 0;
udph->source = 0;
udph->dest = 0;
udph->len = 0;
udph->check = 0;
printf("nRechecking Checksum:%4Xnn",csum((unsigned short *)iph,iph->tot_len));
}
close(sock_r);
}
отправить.c
#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/udp.h> //Provides declarations for udp header
#include<netinet/ip.h> //Provides declarations for ip header
#define min(x,y) (x<y)?x:y
void pkt_hex_dump(uint8_t *data, size_t len)
{
int rowsize = 16;
int i, l, linelen, remaining;
int li = 0;
uint8_t ch;
printf("nPacket hex dump:n");
printf("Packet Size = %ldn", len);
remaining = len;
for (i = 0; i < len; i = rowsize) {
printf("dt", li);
linelen = min(remaining, rowsize);
remaining -= rowsize;
for (l = 0; l < linelen; l ) {
ch = data[l];
printf("X ", (uint32_t) ch);
}
data = linelen;
li = 10;
printf("n");
}
}
struct pseudo_header
{
u_int32_t source_address;
u_int32_t dest_address;
u_int8_t placeholder;
u_int8_t protocol;
u_int16_t udp_length;
};
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*)amp;oddbyte)=*(u_char*)ptr;
sum =oddbyte;
}
sum = (sum>>16) (sum amp; 0xffff);
sum = sum (sum>>16);
answer=(short)~sum;
return(answer);
}
int main (void)
{
int s = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);
if(s == -1)
{
perror("Failed to create raw socket");
exit(1);
}
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(80);
sin.sin_addr.s_addr = inet_addr ("10.0.2.15");
char *datagram = (char*)malloc(4096);
memset (datagram, 0, 4096);
struct iphdr *iph = (struct iphdr *)datagram;
char* data = datagram sizeof(struct iphdr) sizeof(struct udphdr);
strcpy(data,"Hello I am here.n");
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof (struct iphdr) sizeof (struct udphdr) strlen(data);
iph->id = htonl (85492);
iph->frag_off = 0;
iph->ttl = 255;
iph->protocol = IPPROTO_UDP;
iph->check = 0; //Set to 0 before calculating checksum
//iph->saddr = inet_addr ( "1.2.3.4" ); //Spoof the source ip address
iph->daddr = sin.sin_addr.s_addr;
iph->check = csum ((unsigned short *) datagram, iph->tot_len);
struct udphdr *udph = (struct udphdr *)(datagram sizeof(struct iphdr));
udph->source = htons (6666);
udph->dest = htons (8622);
udph->len = htons(8 strlen(data));
udph->check = 0; //leave checksum 0 now, filled later by pseudo header
struct pseudo_header psh;
psh.source_address = inet_addr( "1.2.3.4" );
psh.dest_address = sin.sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_UDP;
psh.udp_length = htons(sizeof(struct udphdr) strlen(data) );
int psize = sizeof(struct pseudo_header) sizeof(struct udphdr) strlen(data);
unsigned char *pseudogram = malloc(psize);
memcpy(pseudogram , (char*) amp;psh , sizeof (struct pseudo_header));
memcpy(pseudogram sizeof(struct pseudo_header) , udph , sizeof(struct udphdr) strlen(data));
udph->check = csum( (unsigned short*) pseudogram , psize);
//while (1)
{
if (sendto (s, datagram, iph->tot_len , 0, (struct sockaddr *) amp;sin, sizeof (sin)) < 0)
{
perror("sendto failed");
}
else
{
printf ("Packet Send. Length : %d n" , iph->tot_len);
printf("Checksum Value : %dn",(int)iph->check);
printf("Checksum UDP : %dn",(int)udph->check);
pkt_hex_dump(datagram,iph->tot_len);
}
}
close(s);
return 0;
}
P. S Может ли кто-нибудь также указать, почему пакет отправляется дважды, потому что у меня есть функция sendto только один раз в сценарии.
Комментарии:
1. ответ на первый вопрос заключается в том, что вам нужен необработанный сокет для управления заголовком ethernet (тот же, который вы используете на своем приемнике).
2. ответ на второй вопрос: этот тип сокета, вероятно, означает, что ядро выполняет обработку IP-адресов (т. Е. Определяет, куда отправлять пакет и т. Д.). Если длина вашего заголовка равна 5 (что правильно), то ядро анализирует заголовок и выполняет обработку. если длина вашего заголовка равна 3, то ядро не сможет проанализировать заголовок. В данном случае я вообще не знаю, почему это работает.
3. Спасибо, что убрали кое-что из вещей. Я все еще не знаю точных параметров для инициализации моего требуемого сокета (я не могу точно использовать тот, который я использовал в приемнике, так как он не отправляет пакеты)(я осмотрюсь и выясню это).
4. Во-вторых, если у вас или у кого-либо есть какие-либо сведения о том, как ядро Linux вычисляет контрольную сумму, это было бы очень полезно. Я видел, как заполнял ipheader и заполнял данные, а затем вычислял контрольную сумму. Но моя контрольная сумма, похоже, отличается от расчетной контрольной суммы linux.
5. Огромное спасибо. Сокет AF_PACKET отправляет необработанные пакеты с ethhdr (хотя мне нужно изменить структуру адресов, используемую для функции sendto). И я буду больше изучать значение контрольной суммы, но теперь у меня есть чувство направления. Вы действительно очень помогли.