diff --git a/atomics/T1040/T1040.yaml b/atomics/T1040/T1040.yaml index 2fb0a94c..2296d265 100644 --- a/atomics/T1040/T1040.yaml +++ b/atomics/T1040/T1040.yaml @@ -153,4 +153,122 @@ atomic_tests: cleanup_command: |- pktmon filter remove name: command_prompt - elevation_required: true \ No newline at end of file + elevation_required: true +- name: Packet Capture Linux socket AF_PACKET,SOCK_RAW with sudo + description: | + Captures packets with domain=AF_PACKET, type=SOCK_RAW for a few seconds. + supported_platforms: + - linux + input_arguments: + csource_path: + description: Path to C program source + type: String + default: PathToAtomicsFolder/T1040/src/linux_pcapdemo.c + program_path: + description: Path to compiled C program + type: String + default: /tmp/t1040_linux_pcapdemo + dependency_executor_name: bash + dependencies: + - description: | + compile C program + prereq_command: | + exit 1 + get_prereq_command: | + cc #{csource_path} -o #{program_path} + executor: + command: | + sudo #{program_path} -a -t 3 + cleanup_command: | + rm -f #{program_path} + name: bash + elevation_required: true +- name: Packet Capture Linux socket AF_INET,SOCK_RAW,TCP with sudo + description: | + Captures packets with domain=AF_INET,type=SOCK_RAW,protocol=TCP for a few seconds. + supported_platforms: + - linux + input_arguments: + csource_path: + description: Path to C program source + type: String + default: PathToAtomicsFolder/T1040/src/linux_pcapdemo.c + program_path: + description: Path to compiled C program + type: String + default: /tmp/t1040_linux_pcapdemo + dependency_executor_name: bash + dependencies: + - description: | + compile C program + prereq_command: | + exit 1 + get_prereq_command: | + cc #{csource_path} -o #{program_path} + executor: + command: | + sudo #{program_path} -4 -p 6 -t 3 + cleanup_command: | + rm -f #{program_path} + name: bash + elevation_required: true +- name: Packet Capture Linux socket AF_INET,SOCK_PACKET,UDP with sudo + description: | + Captures packets with domain=AF_INET,type=SOCK_PACKET,protocol=UDP for a few seconds. + SOCK_PACKET is "obsolete" according to the man page, but still works on Ubuntu 20.04 + supported_platforms: + - linux + input_arguments: + csource_path: + description: Path to C program source + type: String + default: PathToAtomicsFolder/T1040/src/linux_pcapdemo.c + program_path: + description: Path to compiled C program + type: String + default: /tmp/t1040_linux_pcapdemo + dependency_executor_name: bash + dependencies: + - description: | + compile C program + prereq_command: | + exit 1 + get_prereq_command: | + cc #{csource_path} -o #{program_path} + executor: + command: | + sudo #{program_path} -4 -P -p 17 -t 3 + cleanup_command: | + rm -f #{program_path} + name: bash + elevation_required: true +- name: Packet Capture Linux socket AF_PACKET,SOCK_RAW with BPF filter for UDP with sudo + description: | + Captures packets with domain=AF_PACKET,type=SOCK_RAW for a few seconds. + Sets a BPF filter on the socket to filter for UDP traffic. + supported_platforms: + - linux + input_arguments: + csource_path: + description: Path to C program source + type: String + default: PathToAtomicsFolder/T1040/src/linux_pcapdemo.c + program_path: + description: Path to compiled C program + type: String + default: /tmp/t1040_linux_pcapdemo + dependency_executor_name: bash + dependencies: + - description: | + compile C program + prereq_command: | + exit 1 + get_prereq_command: | + cc #{csource_path} -o #{program_path} + executor: + command: | + sudo #{program_path} -a -f -t 3 + cleanup_command: | + rm -f #{program_path} + name: bash + elevation_required: true diff --git a/atomics/T1040/src/linux_pcapdemo.c b/atomics/T1040/src/linux_pcapdemo.c new file mode 100644 index 00000000..0e608612 --- /dev/null +++ b/atomics/T1040/src/linux_pcapdemo.c @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include +#include +#include + +#include //Provides declarations for icmp header +#include //Provides declarations for udp header +#include //Provides declarations for tcp header +#include //Provides declarations for ip header +#include +#include + +static const struct option longopts[] = { + { "afpacket", no_argument, NULL, 'a'}, + { "afinet4", no_argument, NULL, '4'}, + { "afinet6", no_argument, NULL, '6'}, + { "protocol", required_argument, NULL, 'p'}, + { "sockpacket", no_argument, NULL, 'P'}, + { "sockraw", no_argument, NULL, 'R'}, + { "time", required_argument, NULL, 't'}, + { 0, 0, 0, 0 } +}; + +static void usage(const char *progname) +{ + printf("usage: %s \n", progname); + printf(" -a --afpacket Set domain to AF_PACKET.\n"); + printf(" -4 --afinet Set domain to AF_INET (default).\n"); + printf(" -6 --afinet6 Set domain to AF_PACKET.\n"); + printf(" -p --protocol Integer value to set as protocol argument. For AF_INET default is IPPROTO_TCP=6. Others:IPPROTO_UDP=17 IPPROTO_ICMP=1\n"); + printf(" -P --sockpacket Set sock_type to SOCK_PACKET.\n"); + printf(" -R --sockraw Set sock_type to SOCK_RAW (default)\n"); + printf(" -t --time Exit after number of seconds. Default is to run until killed.\n"); +} + +void ProcessPacket(unsigned char* buf, int size, int af); + +int sock_raw; +int tcp=0,udp=0,icmp=0,others=0,igmp=0,total=0,i,j; +struct sockaddr_in source,dest; + +int main(int argc, char *argv[]) +{ + int af = AF_INET; + int sock_type = SOCK_RAW; + int sock_protocol_inet = IPPROTO_TCP; + int sock_protocol = sock_protocol_inet; + int timeout = 0; + + int sock_protocol_packet = htons(3); // AF_PACKET + + int saddr_size , data_size; + struct sockaddr saddr; + struct in_addr in; + + unsigned char *buffer = (unsigned char *)malloc(65536); + + int c; + + while(1) + { + int option_index = 0; + + c = getopt_long(argc, argv, "a46p:PRt:", longopts, &option_index); + if (c == -1) + break; + + switch (c) { + case 'a': + af = AF_PACKET; + sock_protocol = sock_protocol_packet; + break; + case '4': + af = AF_INET; + break; + case '6': + af = AF_INET6; + break; + case 'P': + sock_type = SOCK_PACKET; + break; + case 'R': + sock_type = SOCK_RAW; + break; + case 'p': + sock_protocol = atoi(optarg); + printf("using protocol=%d (0x%x)\n", sock_protocol, sock_protocol); + break; + case 't': + timeout = atoi(optarg); + printf("will exit after %d seconds\n", timeout); + break; + default: + printf("invalid argument: '%c'\n", c); + usage(argv[0]); + return -1; + } + } + + printf("Starting...\n"); + + // create RAW socket to capture packets + + sock_raw = socket(af , sock_type , sock_protocol); + if(sock_raw < 0) + { + printf("Socket Error\n"); + return 1; + } + time_t tstop = time(NULL) + timeout; + while(1) + { + int flags = MSG_DONTWAIT; + saddr_size = sizeof saddr; + //Receive a packet + data_size = recvfrom(sock_raw , buffer , 65536 , flags , &saddr , &saddr_size); + if(data_size <0 ) + { + if (EAGAIN == errno || EWOULDBLOCK == errno) { + usleep(15000); + if (timeout > 0 && time(NULL) >= tstop) { + break; + } + continue; + } + + printf("Recvfrom error , failed to get packets\n"); + return 1; + } + + ProcessPacket(buffer , data_size, af); + } + close(sock_raw); + printf("Finished\n"); + return 0; +} + +void ProcessPacket(unsigned char* buffer, int size, int af) +{ + ++total; + + if (AF_PACKET == af) + { + return; // TODO: parse ether + } + + //Get the IP Header part of this packet + struct iphdr *iph = (struct iphdr*)buffer; + switch (iph->protocol) //Check the Protocol and do accordingly... + { + case IPPROTO_ICMP: + ++icmp; + break; + + case IPPROTO_TCP: + ++tcp; + break; + + case IPPROTO_UDP: + ++udp; + break; + + default: + ++others; + break; + } + printf("TCP : %d UDP : %d ICMP : %d Others : %d Total : %d\n",tcp,udp,icmp,others,total); +}