Силсилаи ҳастаӣ бар ICMP

Силсилаи ҳастаӣ бар ICMP

ХИБ; DR: Ман як модули ядро ​​​​менависам, ки фармонҳоро аз бори ICMP мехонад ва онҳоро дар сервер иҷро мекунад, ҳатто агар SSH-и шумо суқут кунад. Барои аз ҳама бесабр, ҳама рамзи аст Гитуб.

Эзоҳ! Барномасозони ботаҷрибаи C хатари ба ашк рехтанро доранд! Шояд ман ҳатто дар истилоҳот иштибоҳ карда бошам, аммо ҳар гуна интиқод қобили қабул аст. Ин паём барои онҳое пешбинӣ шудааст, ки дар бораи барномасозии C тасаввуроти дағалона доранд ва мехоҳанд ба дохили Linux назар кунанд.

Дар шарҳҳои аввалини ман мақола ёдовар шуд SoftEther VPN, ки метавонад ба баъзе протоколҳои "муқаррарӣ", аз ҷумла HTTPS, ICMP ва ҳатто DNS тақлид кунад. Ман тасаввур карда метавонам, ки танҳо аввалини онҳо кор мекунанд, зеро ман бо HTTP(S) хеле ошно ҳастам ва ман маҷбур будам, ки нақбкаширо тавассути ICMP ва DNS омӯзам.

Силсилаи ҳастаӣ бар ICMP

Бале, дар соли 2020 ман фаҳмидам, ки шумо метавонед ба бастаҳои ICMP боркунии ихтиёрӣ ворид кунед. Аммо дер беҳтар аз ҳаргиз! Ва азбаски дар ин бора коре кардан мумкин аст, пас он бояд анҷом дода шавад. Азбаски дар ҳаёти ҳаррӯзаи худ ман аксар вақт сатри фармонро истифода мебарам, аз ҷумла тавассути SSH, идеяи қабати ICMP аввал ба сари ман омад. Ва барои ҷамъ овардани як бингои мукаммал, ман қарор додам, ки онро ҳамчун модули Linux ба забоне нависам, ки ман танҳо тасаввуроти ноҳамвор дорам. Чунин қабил дар рӯйхати равандҳо намоён нахоҳад шуд, шумо метавонед онро ба ядро ​​бор кунед ва он дар системаи файлӣ нахоҳад буд, шумо дар рӯйхати портҳои гӯшкунӣ ягон чизи шубҳанокро намебинед. Дар робита ба қобилиятҳои он, ин як руткити мукаммал аст, аммо ман умедворам, ки онро такмил медиҳам ва онро ҳамчун як қабати охирин истифода мебарам, вақте ки миёнаи сарборӣ барои ворид шудан тавассути SSH ва ҳадди аққал иҷро кардан хеле баланд аст echo i > /proc/sysrq-triggerбарои барқарор кардани дастрасӣ бе бозсозӣ.

Мо муҳаррири матн, малакаҳои асосии барномасозӣ дар Python ва C, Google ва виртуалӣ ки шумо зид нестед, ки ба зери корд гузоред, агар ҳама чиз вайрон шавад (ихтиёрӣ - VirtualBox / 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:, мо ба он ниёз дорем, то бастаҳоро бо борҳои тасодуфӣ истисно кунем.

Ядро барои таҳияи бастаҳо имтиёзҳо талаб мекунад, аз ин рӯ скрипт бояд ҳамчун суперкорбар иҷро карда шавад. Фаромӯш накунед, ки иҷозати иҷро ва насби худи scapy. Debian дорои бастаи ном дорад 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

Сарборӣ дар бастаи ҷавоб тағир намеёбад.

Модули ядро ​​​​

Барои сохтани мошини виртуалии Debian ба шумо ҳадди аққал лозим аст 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;
      }

    Ман озмоиш накардаам, ки бе тафтиши сарлавҳаҳои IP чӣ рӯй медиҳад. Дониши ҳадди ақали ман дар бораи 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 ва он дорои санаи фиристодани дархост мебошад, яъне шумо ҳама чизро дуруст кардед ва ман ҳама чизро дуруст кардам.

хулоса

Таҷрибаи аввалини ман бо рушди ҳастаӣ назар ба он ки ман интизор будам, хеле осонтар буд. Ҳатто бидуни таҷрибаи рушд дар C, тамаркуз ба маслиҳатҳои компилятор ва натиҷаҳои Google, ман тавонистам як модули корӣ нависам ва худро ҳамчун ҳакери ядро ​​​​ва ҳамзамон кӯдаки скрипт ҳис кунам. Илова бар ин, ман ба канали Newbies Kernel рафтам, ки дар он ҷо ба ман гуфтанд, ки истифода барам schedule_work() ба ҷои занг задан call_usermodehelper() дар дохили қалмоқе худаш ва ӯро шарманда кард, дуруст гумонбар як қаллобӣ. Сад сатри код барои ман тақрибан як ҳафтаи рушд дар вақти холӣ арзиш дошт. Таҷрибаи бомуваффақият, ки афсонаи шахсии маро дар бораи мураккабии азими рушди система нест кард.

Агар касе розӣ шавад, ки баррасии кодро дар Github анҷом диҳад, ман миннатдор хоҳам буд. Ман боварӣ дорам, ки ман бисёр хатогиҳои беақл содир кардам, махсусан ҳангоми кор бо сатр.

Силсилаи ҳастаӣ бар ICMP

Манбаъ: will.com

Илова Эзоҳ