Как перевести hex_dump пакета, полученного в kernel mode(kernel_module), в pcap?

Тема в разделе "WASM.BEGINNERS", создана пользователем 2Hard2Forget, 11 ноя 2020.

  1. 2Hard2Forget

    2Hard2Forget Member

    Публикаций:
    0
    Регистрация:
    27 авг 2018
    Сообщения:
    86
    Я пишу модуль ядра под линукс(Xubuntu x64). Версия ядра - 5.4.0-52-generic. Мой kernel-module ловит трафик(пакеты) с интерфейса и выводит их в hex_dump виде:

    Nov 10 10:03:32 ubuntu kernel: [389547.450504] Packet hex dump:
    Nov 10 10:03:32 ubuntu kernel: [389547.450513] 000000 01 00 5E 00 00 FB 04 B4 29 BB 83 8F 08 00 45 00
    Nov 10 10:03:32 ubuntu kernel: [389547.450591] 000010 00 69 00 01 40 00 FF 11 75 D6 C0 A8 64 08 E0 00
    Nov 10 10:03:32 ubuntu kernel: [389547.450609] 000020 00 FB 14 E9 14 E9 00 55 57 DE 00 22 00 00 00 03
    Nov 10 10:03:32 ubuntu kernel: [389547.450620] 000030 00 00 00 00 00 00 09 5F 36 37 34 41 30 32 34 33
    Nov 10 10:03:32 ubuntu kernel: [389547.450631] 000040 04 5F 73 75 62 0B 5F 67 6F 6F 67 6C 65 63 61 73
    Nov 10 10:03:32 ubuntu kernel: [389547.450642] 000050 74 04 5F 74 63 70 05 6C 6F 63 61 6C 00 00 0C 00
    Nov 10 10:03:32 ubuntu kernel: [389547.450652] 000060 01 09 5F 38 45 36 43 38 36

    Этот вывод я получил путём вызова : tail -f /var/log/kern.log под рутом.
    Вся проблема в том, что мне нужно этот вывод сохранить как pcap-файл. Я знаю про text2pcap, но она сама и её библиотека libpcap написана для user-mode(вроде бы, может я не прав?), поэтому я не могу ей воспользоваться сидя в ядре. Поэтому у меня 2 вопроса:
    Можно ли создать процесс из kernel_module в user-mode,чтобы воспользоваться text2pcap и передать ей параметры?
    Если нет, то как ещё можно сохранить содержимое трафика в файл в формате pcap(опять же сидя в kernel module)?
    Исходник:​
    Код (C):
    1. /*  Sample linux kernel module program to "capture all network packets" */
    2.  
    3. #include <linux/module.h> // included for all kernel modules
    4. #include <linux/kernel.h> // included for KERN_INFO
    5. #include <linux/init.h> // included for __init and __exit macros
    6. #include <linux/skbuff.h> // included for struct sk_buff
    7. #include <linux/if_packet.h> // include for packet info
    8. #include <linux/ip.h> // include for ip_hdr
    9. #include <linux/netdevice.h> // include for dev_add/remove_pack
    10. #include <linux/if_ether.h> // include for ETH_P_ALL
    11. #include <linux/unistd.h>
    12. MODULE_LICENSE("GPL");
    13. MODULE_AUTHOR("Tester");
    14. MODULE_DESCRIPTION("Sample linux kernel module program to capture all network packets");
    15.  
    16. struct packet_type ji_proto;
    17. void pkt_hex_dump(struct sk_buff *skb)
    18. {
    19.     size_t len;
    20.     int rowsize = 16;
    21.     int i, l, linelen, remaining;
    22.     int li = 0;
    23.     uint8_t *data, ch;
    24.  
    25.     printk("Packet hex dump:\n");
    26.     data = (uint8_t *) skb_mac_header(skb);
    27.  
    28.     if (skb_is_nonlinear(skb)) {
    29.         len = skb->data_len;
    30.     } else {
    31.         len = skb->len;
    32.     }
    33.  
    34.     remaining = len;
    35.     for (i = 0; i < len; i += rowsize) {
    36.         printk("%06d\t", li);
    37.  
    38.         linelen = min(remaining, rowsize);
    39.         remaining -= rowsize;
    40.  
    41.         for (l = 0; l < linelen; l++) {
    42.             ch = data[l];
    43.             printk(KERN_CONT "%02X ", (uint32_t) ch);
    44.         }
    45.  
    46.         data += linelen;
    47.         li += 10;
    48.  
    49.         printk(KERN_CONT "\n");
    50.     }
    51. }
    52.  
    53. int ji_packet_rcv (struct sk_buff *skb, struct net_device *dev,struct packet_type *pt, struct net_device *orig_dev)
    54. {
    55. printk(KERN_INFO "New packet captured.\n");
    56.  
    57. /* linux/if_packet.h : Packet types */
    58. // #define PACKET_HOST 0 /* To us */
    59. // #define PACKET_BROADCAST 1 /* To all */
    60. // #define PACKET_MULTICAST 2 /* To group */
    61. // #define PACKET_OTHERHOST 3 /* To someone else */
    62. // #define PACKET_OUTGOING 4 /* Outgoing of any type */
    63. // #define PACKET_LOOPBACK 5 /* MC/BRD frame looped back */
    64. // #define PACKET_USER 6 /* To user space */
    65. // #define PACKET_KERNEL 7 /* To kernel space */
    66. /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */
    67. // #define PACKET_FASTROUTE 6 /* Fastrouted frame */
    68.  
    69. switch (skb->pkt_type)
    70. {
    71. case PACKET_HOST:
    72. printk(KERN_INFO "PACKET to us − ");
    73. break;
    74. case PACKET_BROADCAST:
    75. printk(KERN_INFO "PACKET to all − ");
    76. break;
    77. case PACKET_MULTICAST:
    78. printk(KERN_INFO "PACKET to group − ");
    79. break;
    80. case PACKET_OTHERHOST:
    81. printk(KERN_INFO "PACKET to someone else − ");
    82. break;
    83. case PACKET_OUTGOING:
    84. printk(KERN_INFO "PACKET outgoing − ");
    85. break;
    86. case PACKET_LOOPBACK:
    87. printk(KERN_INFO "PACKET LOOPBACK − ");
    88. break;
    89. case PACKET_FASTROUTE:
    90. printk(KERN_INFO "PACKET FASTROUTE − ");
    91. break;
    92. }
    93. //printk(KERN_CONT "Dev: %s ; 0x%.4X ; 0x%.4X \n", skb->dev->name, ntohs(skb->protocol), ip_hdr(skb)->protocol);
    94. struct ethhdr *ether = eth_hdr(skb);
    95.  
    96.  
    97.  
    98. //printk("Source: %x:%x:%x:%x:%x:%x\n", ether->h_source[0], ether->h_source[1], ether->h_source[2], ether->h_source[3], ether->h_source[4], ether->h_source[5]);
    99.  
    100. //printk("Destination: %x:%x:%x:%x:%x:%x\n", ether->h_dest[0], ether->h_dest[1], ether->h_dest[2], ether->h_dest[3], ether->h_dest[4], ether->h_dest[5]);
    101.  
    102. //printk("Protocol: %d\n", ether->h_proto);
    103. pkt_hex_dump(skb);
    104. kfree_skb (skb);
    105. return 0;
    106. }
    107.  
    108. static int __init
    109. ji_init(void)
    110. {
    111. /* See the <linux/if_ether.h>
    112. When protocol is set to htons(ETH_P_ALL), then all protocols are received.
    113. All incoming packets of that protocol type will be passed to the packet
    114. socket before they are passed to the protocols implemented in the kernel. */
    115. /* Few examples */
    116. //ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */
    117. //ETH_P_IP 0x0800 /* Internet Protocol packet */
    118. //ETH_P_ARP 0x0806 /* Address Resolution packet */
    119. //ETH_P_LOOPBACK 0x9000 /* Ethernet loopback packet, per IEEE 802.3 */
    120. //ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */
    121. //ETH_P_802_2 0x0004 /* 802.2 frames */
    122. //ETH_P_SNAP 0x0005 /* Internal only */
    123.  
    124. ji_proto.type = htons(ETH_P_IP);
    125.  
    126. /* NULL is a wildcard */
    127. //ji_proto.dev = NULL;
    128. ji_proto.dev = dev_get_by_name (&init_net, "enp0s3");
    129.  
    130. ji_proto.func = ji_packet_rcv;
    131.  
    132. /* Packet sockets are used to receive or send raw packets at the device
    133. driver (OSI Layer 2) level. They allow the user to implement
    134. protocol modules in user space on top of the physical layer. */
    135.  
    136. /* Add a protocol handler to the networking stack.
    137. The passed packet_type is linked into kernel lists and may not be freed until
    138.   it has been removed from the kernel lists. */
    139. dev_add_pack (&ji_proto);
    140.  
    141. printk(KERN_INFO "Module insertion completed successfully!\n");
    142. return 0; // Non-zero return means that the module couldn't be loaded.
    143. }
    144.  
    145. static void __exit
    146. ji_cleanup(void)
    147. {
    148. dev_remove_pack(&ji_proto);
    149. printk(KERN_INFO "Cleaning up module....\n");
    150. }
    151.  
    152. module_init(ji_init);
    153. module_exit(ji_cleanup);
     
  2. f13nd

    f13nd Well-Known Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    1.954
    Насколько я понимаю это езернет-пакет у тебя. Вроде как pcap поддерживает формат k12, загугли примеры и увидишь как просто в этот формат впихнуть езернет-кадр.
     
    2Hard2Forget нравится это.
  3. X-Shar

    X-Shar Active Member

    Публикаций:
    0
    Регистрация:
    24 фев 2017
    Сообщения:
    354
    Wireshark позволяет загружать данные в хекс формате...

    Переделайте лог так:

    Код (Text):
    1. 000000 01 00 5E 00 00 FB 04 B4 29 BB 83 8F 08 00 45 00
    2. 000010 00 69 00 01 40 00 FF 11 75 D6 C0 A8 64 08 E0 00
    3. 000020 00 FB 14 E9 14 E9 00 55 57 DE 00 22 00 00 00 03
    4. 000030 00 00 00 00 00 00 09 5F 36 37 34 41 30 32 34 33
    5. 000040 04 5F 73 75 62 0B 5F 67 6F 6F 67 6C 65 63 61 73
    6. 000050 74 04 5F 74 63 70 05 6C 6F 63 61 6C 00 00 0C 00
    7. 000060 01 09 5F 38 45 36 43 38 36
    Потом загрузите его в ваершарк, вот:

    File->Import From Hex Dump
     
  4. 2Hard2Forget

    2Hard2Forget Member

    Публикаций:
    0
    Регистрация:
    27 авг 2018
    Сообщения:
    86
    Мне же всё-таки нужно сделать это в программе
     
  5. X-Shar

    X-Shar Active Member

    Публикаций:
    0
    Регистрация:
    24 фев 2017
    Сообщения:
    354
    Тогда как вариант вызвать юзермодное приложение из ядра, можно с параметрами, кури call_usermodehelper.

    В сети примеры есть...
    --- Сообщение объединено, 11 ноя 2020 ---
    Тут пример кода можно найти:https://www.ibm.com/developerworks/ru/library/l-linux_kernel_37/index.html

    Как запустить юзермодное приложение из ядра...
     
    2Hard2Forget нравится это.
  6. M0rg0t

    M0rg0t Well-Known Member

    Публикаций:
    0
    Регистрация:
    18 окт 2010
    Сообщения:
    1.574
    Mikl___ нравится это.
  7. 2Hard2Forget

    2Hard2Forget Member

    Публикаций:
    0
    Регистрация:
    27 авг 2018
    Сообщения:
    86
    Если вы про BinDiff, то препод принял даже не проверяя, вроде бы он сам не шарит за такое. Поэтому я и не понял прав ли я был в поиске уязвимости или нет, поэтому мне нечего комментировать по этому поводу.
    Если вы про задание, где нужно было без букв алфавита написать программу, то мне ответили в том же треде - https://wasm.in/threads/izbavitsja-...ablicu-imports-v-ida.33470/page-2#post-412883
    Кто-то невзначай спросил и я назвал, кто смог это сделать.
    В чём проблема?
    --- Сообщение объединено, 11 ноя 2020 ---
    Я попытался запустить text2pcap. Для этого написал тестовый модуль ядра:
    Код (C):
    1. #include <linux/module.h>
    2. #include <linux/moduleparam.h>
    3. #include <linux/kernel.h>
    4. #include <linux/init.h>
    5. #include <linux/stat.h>
    6. static char *str;
    7. module_param( str, charp, S_IRUGO );
    8.  
    9. static int __init exec_init( void )
    10. {
    11.    int rc=0;
    12.     static char *envp[] = {
    13.     "SHELL=/bin/bash",
    14.     "HOME=/home/tester",
    15.     "USER=tester",
    16.    "PATH=/usr/bin/",
    17.     "DISPLAY=:0",
    18.     "PWD=/home/tester",
    19.     NULL};
    20.    //static char* envp[]={NULL};
    21.  
    22.    char *argv[] = {"/usr/bin/text2pcap", "-o","-hex","/home/tester/test.txt","/home/tester/output.pcap",NULL};
    23.    rc = call_usermodehelper(argv[0], argv, envp, UMH_NO_WAIT);
    24.    printk("RC is: %i \n", rc);
    25.    return 0;
    26. }
    27. static void __exit exec_exit(void)
    28. {
    29.     printk(KERN_INFO "Goodbye\n");
    30. }
    31.  
    32.  
    33. module_init( exec_init );
    34. module_exit(exec_exit);
    35. MODULE_LICENSE( "GPL" );
    36. MODULE_AUTHOR( "Tester" );
    37. MODULE_VERSION( "2.1" );
    38.  
    Вывод:
    Nov 11 10:34:18 ubuntu kernel: [420581.514128] RC is: 0
    Nov 11 10:45:10 ubuntu kernel: [421233.493965] Goodbye

    Я не совсем понимаю, где ошибаюсь. Вроде бы ноль означает, что функция завершилась успешно и мы не ждём её завершения(так как используем UMH_NO_WAIT). Но если всё-таки ожидать завершения нового процесса(то есть использовать UMH_WAIT_PROC), то выводится такое, то есть уже 256 вместо нуля:
    Nov 11 11:05:43 ubuntu kernel: [422466.444724] RC is: 256
    Nov 11 11:05:52 ubuntu kernel: [422475.473028] Goodbye

    Я понимаю, что нужно правильно выставить envp и argv.
    Для envp я выставил путь к Шелл(даже сделал симлинк с dash на bash - ничего не изменилось). Остальные параметры выставил по примеру отсюда https://unix.stackexchange.com/ques...om-a-linux-kernel-module#comment630768_355951

    В argv параметрах выставил те же параметры, как если бы запускал из консоли , то есть text2pcap -o hex test.txt output.pcap. и везде использовал абсолютные пути. Но не появляется файл pcap
     
  8. 2Hard2Forget

    2Hard2Forget Member

    Публикаций:
    0
    Регистрация:
    27 авг 2018
    Сообщения:
    86
    нужно запускать без "-" у hex *facepalm*