Koki nikleyè sou ICMP

Koki nikleyè sou ICMP

TL; DR: Mwen ekri yon modil nwayo ki pral li kòmandman ki soti nan chaj ICMP a epi egzekite yo sou sèvè a menm si SSH ou a aksidan. Pou moun ki pi enpasyan, tout kòd la se GitHub.

Atansyon! Pwogramè C ki gen eksperyans riske pete nan dlo nan je! Mwen ka menm mal nan tèminoloji a, men nenpòt kritik se akeyi. Pòs la fèt pou moun ki gen yon lide trè graj sou pwogram C epi ki vle gade anndan Linux.

Nan kòmantè yo nan premye mwen an Atik mansyone SoftEther VPN, ki ka imite kèk pwotokòl "regilye", an patikilye HTTPS, ICMP e menm DNS. Mwen ka imajine sèlman premye nan yo k ap travay, paske mwen trè abitye ak HTTP(S), e mwen te oblije aprann tinèl sou ICMP ak DNS.

Koki nikleyè sou ICMP

Wi, mwen te aprann nan 2020 ke ou ka mete yon chaj abitrè nan pake ICMP. Men, pi bon an reta pase pa janm! Epi depi yon bagay ka fè sou li, Lè sa a, li bezwen fè. Depi nan lavi chak jou mwen pi souvan itilize liy lòd la, ki gen ladan SSH, lide yon kokiy ICMP te vin nan tèt mwen an premye. Ak nan lòd yo rasanble yon bengo bullshield konplè, mwen deside ekri li kòm yon modil Linux nan yon lang ke mwen sèlman gen yon lide ki graj. Yon kokiy sa a pa pral vizib nan lis la nan pwosesis, ou ka chaje li nan nwayo a epi li pa pral sou sistèm nan dosye, ou pa pral wè anyen ki sispèk nan lis la nan pò koute. An tèm de kapasite li yo, sa a se yon routki plen véritable, men mwen espere amelyore li epi sèvi ak li kòm yon koki nan dènye rekou lè Mwayèn chaj la twò wo pou konekte via SSH epi egzekite omwen. echo i > /proc/sysrq-triggerretabli aksè san rekòmanse.

Nou pran yon editè tèks, ladrès debaz pwogramasyon nan Python ak C, Google ak vityèl ki ou pa lide mete anba kouto a si tout bagay kraze (si ou vle - lokal VirtualBox / KVM / elatriye) epi ann ale!

Bò kliyan

Li te sanble pou mwen ke pou pati nan kliyan mwen ta dwe ekri yon script ak apeprè 80 liy, men te gen moun ki janti ki te fè li pou mwen. tout travay la. Kòd la te tounen san atann senp, anfòm nan 10 liy enpòtan:

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()

Script la pran de agiman, yon adrès ak yon chaj. Anvan ou voye, chaj la se yon kle anvan run:, nou pral bezwen li pou eskli pakè ak chaj o aza.

Kernel la mande privilèj pou fè pakè, kidonk script la pral oblije kouri kòm sipè-ilizatè. Pa bliye bay pèmisyon ekzekisyon epi enstale scapy tèt li. Debian gen yon pake ki rele python3-scapy. Koulye a, ou ka tcheke ki jan li tout travay.

Kouri ak pwodiksyon lòd la
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!

Sa a se sa li sanble nan sniffer la
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

Chaj la nan pake repons lan pa chanje.

Modil Kernel

Pou konstwi yon machin vityèl Debian w ap bezwen omwen make и linux-headers-amd64, rès la ap vini nan fòm depandans. Mwen pa pral bay tout kòd la nan atik la ou ka klonaj li sou Github.

Konfigirasyon zen

Pou kòmanse, nou bezwen de fonksyon yo nan lòd yo chaje modil la ak dechaje li. Fonksyon pou dechaje pa obligatwa, men lè sa a rmmod li pa pral travay; modil la ap dechaje sèlman lè li fèmen.

#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);

Kisa k ap pase isit la:

  1. De dosye header yo rale nan manipile modil la tèt li ak netfilter la.
  2. Tout operasyon ale nan yon netfilter, ou ka mete kwòk nan li. Pou fè sa, ou bezwen deklare estrikti a nan ki zen an pral configuré. Bagay ki pi enpòtan an se presize fonksyon an ki pral egzekite kòm yon zen: nfho.hook = icmp_cmd_executor; Mwen pral rive nan fonksyon an tèt li pita.
    Lè sa a, mwen mete tan an pwosesis pou pake a: NF_INET_PRE_ROUTING espesifye pou trete pake a lè li premye parèt nan nwayo a. Èske yo ka itilize NF_INET_POST_ROUTING pou trete pake a pandan l ap soti nan nwayo a.
    Mwen mete filtè a IPv4: nfho.pf = PF_INET;.
    Mwen bay zen mwen an pi gwo priyorite: nfho.priority = NF_IP_PRI_FIRST;
    Apre sa, mwen anrejistre estrikti done a kòm zen aktyèl la: nf_register_net_hook(&init_net, &nfho);
  3. Fonksyon final la retire zen an.
  4. Lisans lan endike klèman pou konpilatè a pa pote plent.
  5. Fonksyon module_init() и module_exit() mete lòt fonksyon pou inisyalize ak mete fen nan modil la.

Rekipere chaj la

Koulye a, nou bezwen ekstrè chaj la, sa a te tounen soti yo dwe travay ki pi difisil. Kernel la pa gen fonksyon entegre pou travay ak chaj ou ka sèlman analize tèt pwotokòl ki pi wo yo.

#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;
}

Sak ap pase:

  1. Mwen te oblije mete fichye header adisyonèl, fwa sa a pou manipile tèt IP ak ICMP.
  2. Mwen mete longè liy maksimòm lan: #define MAX_CMD_LEN 1976. Poukisa egzakteman sa a? Paske du a plenyen pou sa! Yo te deja sijere m 'ke mwen bezwen konprann chemine a ak pil, yon jou mwen pral definitivman fè sa a e petèt menm korije kòd la. Mwen imedyatman mete liy lan ki pral gen kòmandman an: char cmd_string[MAX_CMD_LEN];. Li ta dwe vizib nan tout fonksyon mwen pral pale sou sa a an plis detay nan paragraf 9.
  3. Koulye a, nou bezwen inisyalize (struct work_struct my_work;) estrikti epi konekte li ak yon lòt fonksyon (DECLARE_WORK(my_work, work_handler);). Mwen pral pale tou sou poukisa sa nesesè nan nevyèm paragraf la.
  4. Koulye a, mwen deklare yon fonksyon, ki pral yon zen. Kalite ak agiman aksepte yo dikte pa netfilter la, nou sèlman enterese nan skb. Sa a se yon tanpon priz, yon estrikti done fondamantal ki gen tout enfòmasyon ki disponib sou yon pake.
  5. Pou fonksyon an travay, w ap bezwen de estrikti ak plizyè varyab, ki gen ladan de iteratè.
      struct iphdr *iph;
      struct icmphdr *icmph;
    
      unsigned char *user_data;
      unsigned char *tail;
      unsigned char *i;
      int j = 0;
  6. Nou ka kòmanse ak lojik. Pou modil la travay, pa gen okenn pake ki pa bezwen ICMP Echo, kidonk nou analize tanpon an lè l sèvi avèk fonksyon entegre epi jete tout pake ki pa ICMP ak ki pa Echo. Retounen NF_ACCEPT vle di aksepte pakè a, men ou ka tou lage pakè lè w retounen 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;
      }

    Mwen pa te teste sa ki pral rive san yo pa tcheke tèt IP yo. Konesans minim mwen an nan C di m 'ke san yo pa chèk adisyonèl, gen yon bagay terib oblije rive. Mwen pral kontan si ou dekouraje m 'nan sa a!

  7. Kounye a ke pake a se nan kalite egzak ou bezwen an, ou ka ekstrè done yo. San yo pa yon fonksyon entegre, ou dwe premye jwenn yon konsèy sou kòmansman chaj la. Sa a se fè nan yon sèl kote, ou bezwen pran konsèy la nan kòmansman an nan header ICMP la epi deplase li nan gwosè a nan header sa a. Tout sèvi ak estrikti icmph: user_data = (unsigned char *)((unsigned char *)icmph + (sizeof(icmph)));
    Fen header la dwe matche ak fen chaj la nan skb, Se poutèt sa nou jwenn li lè l sèvi avèk mwayen nikleyè nan estrikti ki koresponn lan: tail = skb_tail_pointer(skb);.

    Koki nikleyè sou ICMP

    Yo te vòlè foto a kon sa, ou ka li plis sou tanpon priz la.

  8. Yon fwa ou gen endikasyon nan kòmansman ak nan fen, ou ka kopye done yo nan yon fisèl cmd_string, tcheke li pou prezans yon prefiks run: epi, swa jete pake a si li manke, oswa reekri liy lan ankò, retire prefiks sa a.
  9. Sa a se li, kounye a ou ka rele yon lòt moun kap okipe: schedule_work(&my_work);. Depi li pa posib yo pase yon paramèt nan yon apèl konsa, liy lan ak lòd la dwe mondyal. schedule_work() pral mete fonksyon ki asosye ak estrikti ki pase a nan keu jeneral la nan pwogramasyon an travay epi li konplete, sa ki pèmèt ou pa tann pou lòd la fini. Sa a se nesesè paske zen an dwe trè vit. Sinon, chwa ou se ke pa gen anyen pral kòmanse oswa ou pral jwenn yon panik nwayo. Reta se tankou lanmò!
  10. Sa a li, ou ka aksepte pake a ak yon retounen korespondan.

Rele yon pwogram nan espas itilizatè

Fonksyon sa a se pi konprann. Non li te bay nan DECLARE_WORK(), kalite a ak agiman aksepte yo pa enteresan. Nou pran liy lan ak lòd la epi pase li antyèman nan koki a. Kite l 'fè fas ak analiz, chèche binè ak tout lòt bagay.

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. Mete agiman yo nan yon etalaj de fisèl argv[]. Mwen pral sipoze ke tout moun konnen ke pwogram yo aktyèlman egzekite fason sa a, epi yo pa kòm yon liy kontinyèl ak espas.
  2. Mete varyab anviwònman yo. Mwen mete sèlman PATH ak yon seri minimòm chemen, mwen espere ke yo tout te deja konbine /bin с /usr/bin и /sbin с /usr/sbin. Lòt chemen raman enpòtan nan pratik.
  3. Fè, ann fè li! Fonksyon Kernel call_usermodehelper() aksepte antre. chemen binè a, etalaj agiman, etalaj varyab anviwònman an. Isit la mwen sipoze tou ke tout moun konprann siyifikasyon an nan pase chemen an nan dosye a ègzèkutabl kòm yon agiman separe, men ou ka mande. Dènye agiman an presize si wi ou non pou tann pou pwosesis la fini (UMH_WAIT_PROC), kòmanse pwosesis (UMH_WAIT_EXEC) oswa pa tann ditou (UMH_NO_WAIT). Èske gen kèk plis UMH_KILLABLE, Mwen pa t 'gade nan li.

Asanble

Asanble modil nwayo a fèt atravè kad fè nwayo a. Rele make andedan yon anyè espesyal ki mare ak vèsyon nwayo a (ki defini isit la: KERNELDIR:=/lib/modules/$(shell uname -r)/build), epi kote modil la pase nan varyab la M nan agiman yo. icmpshell.ko ak sib pwòp itilize fondasyon sa a antyèman. NAN obj-m endike fichye objè a ki pral konvèti nan yon modil. Sentaks ki refè main.o в icmpshell.o (icmpshell-objs = main.o) pa sanble trè lojik pou mwen, men se pou li.

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

Nou kolekte: make. Chaje: insmod icmpshell.ko. Fè, ou ka tcheke: sudo ./send.py 45.11.26.232 "date > /tmp/test". Si ou gen yon dosye sou machin ou /tmp/test epi li gen dat yo te voye demann lan, sa vle di ou te fè tout bagay byen e mwen te fè tout bagay byen.

Konklizyon

Premye eksperyans mwen ak devlopman nikleyè te pi fasil pase mwen te espere. Menm san eksperyans nan devlope nan C, konsantre sou sijesyon konpilateur ak rezilta Google, mwen te kapab ekri yon modil k ap travay epi santi mwen tankou yon pirate nwayo, ak an menm tan an yon timoun script. Anplis de sa, mwen te ale nan chanèl Kernel Newbies la, kote yo te di mwen sèvi ak schedule_work() olye pou yo rele call_usermodehelper() andedan zen nan tèt li ak wont l ', rezon sispèk yon tronpe. Yon santèn liy kòd koute m 'apeprè yon semèn nan devlopman nan tan lib mwen an. Yon eksperyans siksè ki detwi mit pèsonèl mwen sou konpleksite akablan nan devlopman sistèm.

Si yon moun dakò fè yon revizyon kòd sou Github, mwen pral rekonesan. Mwen trè asire w ke mwen te fè yon anpil nan erè estipid, espesyalman lè w ap travay ak fisèl.

Koki nikleyè sou ICMP

Sous: www.habr.com

Add nouvo kòmantè