Slige niuclasach thairis air ICMP

Slige niuclasach thairis air ICMP

TL; DR: Tha mi a’ sgrìobhadh modal kernel a leughas òrdughan bho uallach pàighidh ICMP agus a chuireas an gnìomh iad air an fhrithealaiche eadhon ged a thuiteas an SSH agad. Airson an fheadhainn as mì-fhoighidneach, tha an còd gu lèir GitHub.

Rabhadh! Tha cunnart ann gum bi prògramadairean eòlach C a’ spreadhadh a-steach do dheòir fala! Is dòcha gu bheil mi eadhon ceàrr anns a’ bhriathrachas, ach tha fàilte air càineadh sam bith. Tha an dreuchd ag amas air an fheadhainn aig a bheil beachd gu math garbh air prògramadh C agus a tha airson coimhead a-steach do thaobh a-staigh Linux.

Anns na beachdan don chiad fhear agam artaigil air ainmeachadh SoftEther VPN, a dh’ fhaodadh atharrais air cuid de phròtacalan “cunbhalach”, gu sònraichte HTTPS, ICMP agus eadhon DNS. Chan urrainn dhomh smaoineachadh ach a’ chiad fhear dhiubh ag obair, leis gu bheil mi gu math eòlach air HTTP(S), agus bha agam ri tunail ionnsachadh thairis air ICMP agus DNS.

Slige niuclasach thairis air ICMP

Tha, ann an 2020 dh’ ionnsaich mi gun urrainn dhut uallach pàighidh neo-riaghailteach a chuir a-steach do phasganan ICMP. Ach nas fheàrr anmoch na riamh! Agus bhon a ghabhas rudeigin a dhèanamh mu dheidhinn, feumar a dhèanamh. Leis gu bheil mi nam bheatha làitheil mar as trice a’ cleachdadh an loidhne-àithne, a’ toirt a-steach tro SSH, thàinig am beachd air slige ICMP gu m’ inntinn an-toiseach. Agus airson bingo tarbh-thairis iomlan a chruinneachadh, chuir mi romham a sgrìobhadh mar mhodal Linux ann an cànan air nach eil agam ach beachd garbh. Cha bhith an leithid de shlige ri fhaicinn anns an liosta de phròiseasan, faodaidh tu a luchdachadh a-steach don kernel agus cha bhith e air an t-siostam faidhle, chan fhaic thu dad amharasach anns an liosta de phuirt èisteachd. A thaobh a chomasan, is e rootkit làn-chuimseach a tha seo, ach tha mi an dòchas a leasachadh agus a chleachdadh mar shlige mar an roghainn mu dheireadh nuair a tha an cuibheasachd luchdaidh ro àrd airson logadh a-steach tro SSH agus a chuir an gnìomh co-dhiù. echo i > /proc/sysrq-triggergus ruigsinneachd a thoirt air ais gun ath-thòiseachadh.

Gabhaidh sinn deasaiche teacsa, sgilean prògramadh bunaiteach ann am Python agus C, Google agus mas-fhìor nach eil dragh agad a chuir fon sgian ma bhriseas a h-uile càil (roghainneil - ionadail VirtualBox / KVM / msaa) agus rachamaid!

Taobh neach-dèiligidh

Bha e coltach riumsa gum feumadh mi sgriobt a sgrìobhadh le timcheall air 80 loidhne airson a’ phàirt teachdaiche, ach bha daoine coibhneil ann a rinn e dhòmhsa an obair uile. Bha an còd gu math sìmplidh ris nach robh dùil, a’ freagairt air 10 loidhnichean cudromach:

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

Gabhaidh an sgriobt dà argamaid, seòladh agus uallach pàighidh. Mus tèid a chuir, tha iuchair air thoiseach air an luchd pàighidh run:, bidh feum againn air gus pasganan le luchdan pàighidh air thuaiream a thoirmeasg.

Feumaidh an kernel sochairean airson pasganan a chiùradh, agus mar sin feumaidh an sgriobt a bhith air a ruith mar superuser. Na dì-chuimhnich ceadan cur gu bàs a thoirt seachad agus stàladh scapy fhèin. Tha pasgan aig Debian ris an canar python3-scapy. A-nis faodaidh tu sgrùdadh a dhèanamh air mar a tha e uile ag obair.

A 'ruith agus a' toirt a-mach an àithne
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!

Seo mar a tha e coltach anns an sniffer
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

Chan atharraich an t-uallach pàighidh sa phasgan freagairt.

Modal kernel

Gus inneal brìgheil Debian a thogail a-steach feumaidh tu co-dhiù make и linux-headers-amd64, thig an còrr ann an cruth eisimeileachd. Cha toir mi seachad an còd gu lèir san artaigil; faodaidh tu clone a dhèanamh air Github.

Suidheachadh dubhan

An toiseach, feumaidh sinn dà ghnìomh gus am modal a luchdachadh agus a luchdachadh. Chan eil feum air a’ ghnìomh airson dì-luchdachadh, ach an uairsin rmmod chan obraich e; cha tèid am modal a luchdachadh ach nuair a bhios e dheth.

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

Dè tha dol an seo:

  1. Tha dà fhaidhle cinn air an tarraing a-steach gus am modal fhèin agus an lìon-inneal a làimhseachadh.
  2. Bidh a h-uile gnìomhachd a’ dol tro lìon criathra, faodaidh tu dubhan a shuidheachadh ann. Gus seo a dhèanamh, feumaidh tu innse dè an structar anns am bi an dubhan air a rèiteachadh. Is e an rud as cudromaiche an gnìomh a thèid a chuir gu bàs mar dubhan a shònrachadh: nfho.hook = icmp_cmd_executor; Ruigidh mi chun ghnìomh fhèin nas fhaide air adhart.
    An uairsin shuidhich mi an ùine giollachd airson a’ phacaid: NF_INET_PRE_ROUTING a 'sònrachadh a' phacaid a phròiseasadh nuair a nochdas e an toiseach san kernel. Faodar a chleachdadh NF_INET_POST_ROUTING gus am pasgan a phròiseasadh fhad ‘s a thig e a-mach às an kernel.
    Shuidhich mi an criathrag gu IPv4: nfho.pf = PF_INET;.
    Bheir mi am prìomhachas as àirde dha mo dubhan: nfho.priority = NF_IP_PRI_FIRST;
    Agus bidh mi a’ clàradh an structar dàta mar an fhìor dubhan: nf_register_net_hook(&init_net, &nfho);
  3. Bidh an gnìomh mu dheireadh a 'toirt air falbh an dubhan.
  4. Tha an cead air a chomharrachadh gu soilleir gus nach dèan an neach-cruinneachaidh gearan.
  5. Feartan module_init() и module_exit() suidhich gnìomhan eile gus am modal a thòiseachadh agus a thoirt gu crìch.

A 'faighinn air ais an t-uallach pàighidh

A-nis feumaidh sinn an t-uallach pàighidh a thoirt a-mach, b’ e seo an obair as duilghe. Chan eil gnìomhan togte aig an kernel airson a bhith ag obair le luchdan pàighidh; chan urrainn dhut ach cinn-cinn de phròtacalan àrd-ìre a pharsadh.

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

Dè tha dol:

  1. B’ fheudar dhomh faidhlichean cinn a bharrachd a thoirt a-steach, an turas seo gus cinn-cinn IP agus ICMP a làimhseachadh.
  2. Shuidhich mi an fhad loidhne as àirde: #define MAX_CMD_LEN 1976. Carson dìreach seo? Leis gu bheil an compiler a’ gearan mu dheidhinn! Tha iad mar-thà air moladh dhomh gum feum mi a’ chruach agus an tiùrr a thuigsinn, uaireigin nì mi seo gu cinnteach agus is dòcha eadhon an còd a cheartachadh. Shuidhich mi sa bhad an loidhne anns am bi an àithne: char cmd_string[MAX_CMD_LEN];. Bu chòir dha a bhith follaiseach anns a h-uile gnìomh; Bruidhnidh mi mu dheidhinn seo nas mionaidiche ann am paragraf 9.
  3. A-nis feumaidh sinn tòiseachadh (struct work_struct my_work;) structar agus ceangail e ri gnìomh eile (DECLARE_WORK(my_work, work_handler);). Bruidhnidh mi cuideachd carson a tha seo riatanach anns an naoidheamh paragraf.
  4. A-nis tha mi a 'foillseachadh gnìomh, a bhios na dubhan. Tha an seòrsa agus argamaidean ris an deach gabhail air an òrdachadh leis an netfilter, chan eil ùidh againn ach ann skb. Is e seo bufair socaid, structar dàta bunaiteach anns a bheil a h-uile fiosrachadh a tha ri fhaighinn mu phacaid.
  5. Gus an obraich an gnìomh, bidh feum agad air dà structar agus grunn chaochladairean, a’ gabhail a-steach dà neach-aithris.
      struct iphdr *iph;
      struct icmphdr *icmph;
    
      unsigned char *user_data;
      unsigned char *tail;
      unsigned char *i;
      int j = 0;
  6. Faodaidh sinn tòiseachadh le loidsig. Gus am bi am modal ag obair, chan eil feum air pacaidean a bharrachd air ICMP Echo, agus mar sin bidh sinn a’ parsadh a’ bhufair a’ cleachdadh gnìomhan togte agus a’ tilgeil a-mach a h-uile pacaid neo-ICMP agus neo-Echo. Tilleadh NF_ACCEPT a’ ciallachadh gabhail ris a’ phacaid, ach faodaidh tu cuideachd pacaidean a leigeil seachad le bhith a’ tilleadh 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;
      }

    Cha do rinn mi deuchainn air dè a thachras gun a bhith a’ sgrùdadh na cinn IP. Tha an t-eòlas as lugha a th’ agam air C ag innse dhomh, às aonais sgrùdaidhean a bharrachd, gu bheil rudeigin uamhasach gu bhith a’ tachairt. Bidh mi toilichte ma chuireas tu às do seo mi!

  7. A-nis gu bheil am pasgan den dearbh sheòrsa a dh’ fheumas tu, faodaidh tu an dàta a thoirt a-mach. Às aonais gnìomh togte, feumaidh tu an toiseach puing fhaighinn gu toiseach an eallach pàighidh. Tha seo air a dhèanamh ann an aon àite, feumaidh tu am puing a thoirt gu toiseach bann-cinn ICMP agus gluais e gu meud a’ chinn seo. Bidh a h-uile dad a’ cleachdadh structar icmph: user_data = (unsigned char *)((unsigned char *)icmph + (sizeof(icmph)));
    Feumaidh deireadh a’ chinn a bhith co-ionnan ri deireadh an eallach pàighidh a-steach skb, mar sin bidh sinn ga fhaighinn le bhith a’ cleachdadh dhòighean niùclasach bhon structar fhreagarrach: tail = skb_tail_pointer(skb);.

    Slige niuclasach thairis air ICMP

    Chaidh an dealbh a ghoid bho seo, faodaidh tu barrachd a leughadh mun bhufair socaid.

  8. Aon uair ‘s gu bheil comharran agad mu thoiseach is deireadh, faodaidh tu an dàta a chopaigeadh gu sreang cmd_string, thoir sùil air airson làthaireachd ro-leasachan run: agus, an dàrna cuid tilg air falbh am pasgan ma tha e a dhìth, no ath-sgrìobh an loidhne a-rithist, a’ toirt air falbh an ro-leasachan seo.
  9. Sin agad e, a-nis faodaidh tu fios a chuir gu neach-làimhseachaidh eile: schedule_work(&my_work);. Leis nach bi e comasach paramadair a chuir gu leithid de ghairm, feumaidh an loidhne leis an àithne a bhith cruinneil. schedule_work() cuiridh e an gnìomh co-cheangailte ris an structar a chaidh seachad ann an ciudha coitcheann clàr-ama na h-obrach agus crìochnaich e, a’ leigeil leat gun a bhith a’ feitheamh gus an tèid an àithne a chrìochnachadh. Tha seo riatanach oir feumaidh an dubhan a bhith gu math luath. Rud eile, is e do roghainn nach tòisich dad no gum faigh thu clisgeadh kernel. Tha dàil coltach ri bàs!
  10. Sin agad e, faodaidh tu gabhail ris a’ phacaid le tilleadh co-fhreagarrach.

A 'gairm prògram ann an userspace

Is e an gnìomh seo an rud as so-thuigsinn. Chaidh an t-ainm a thoirt seachad ann an DECLARE_WORK(), chan eil an seòrsa agus argamaidean ris an deach gabhail inntinneach. Gabhaidh sinn an loidhne leis an àithne agus bheir sinn seachad e gu tur don t-slige. Leig leis dèiligeadh ri parsadh, a 'lorg binaries agus a h-uile càil eile.

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. Suidhich na h-argamaidean gu sreath de shreathan argv[]. Gabhaidh mi ris gu bheil fios aig a h-uile duine gu bheil prògraman air an cur an gnìomh san dòigh seo, agus chan ann mar loidhne leantainneach le beàrnan.
  2. Suidhich caochladairean àrainneachd. Cha do chuir mi a-steach ach PATH le seata as lugha de shlighean, an dòchas gun robh iad uile air an cur còmhla mar-thà /bin с /usr/bin и /sbin с /usr/sbin. Is ann ainneamh a bhios slighean eile cudromach ann an cleachdadh.
  3. Dèan, dèanamaid e! Gnìomh kernel call_usermodehelper() a’ gabhail ri inntrigeadh. slighe chun na binary, sreath de argamaidean, raon de chaochladairean àrainneachd. An seo tha mi cuideachd a 'gabhail ris gu bheil a h-uile duine a' tuigsinn brìgh a bhith a 'dol seachad air an t-slighe chun an fhaidhle so-ghnìomhaichte mar argamaid air leth, ach faodaidh tu faighneachd. Tha an argamaid mu dheireadh a’ sònrachadh am bu chòir feitheamh gus am bi am pròiseas deiseil (UMH_WAIT_PROC), tòiseachadh pròiseas (UMH_WAIT_EXEC) no na fuirich idir (UMH_NO_WAIT). A bheil beagan a bharrachd ann UMH_KILLABLE, cha tug mi sùil air.

Tionndadh

Tha co-chruinneachadh mhodalan kernel air a dhèanamh tron ​​​​fhrèam dèanamh kernel. Glaodh make taobh a-staigh eòlaire sònraichte ceangailte ris an dreach kernel (air a mhìneachadh an seo: KERNELDIR:=/lib/modules/$(shell uname -r)/build), agus tha suidheachadh a’ mhodail air a chuir chun chaochladair M anns na h-argamaidean. Bidh an icmpshell.ko agus targaidean glan a’ cleachdadh am frèam seo gu tur. ANNS obj-m a’ comharrachadh am faidhle nì a thèid a thionndadh gu modal. Syntax a tha ag ath-dhèanamh main.o в icmpshell.o (icmpshell-objs = main.o) chan eil e a’ coimhead glè loidsigeach dhomh, ach mar sin biodh e.

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

Bidh sinn a’ cruinneachadh: make. A' luchdachadh: insmod icmpshell.ko. Air a dhèanamh, faodaidh tu sgrùdadh a dhèanamh: sudo ./send.py 45.11.26.232 "date > /tmp/test". Ma tha faidhle air an inneal agad /tmp/test agus tha an ceann-latha air an deach an t-iarrtas a chuir a-steach ann, a tha a 'ciallachadh gun do rinn thu a h-uile càil ceart agus rinn mi a h-uile càil ceart.

co-dhùnadh

Bha a’ chiad eòlas agam le leasachadh niuclasach tòrr na b’ fhasa na bha mi an dùil. Fiù ‘s às aonais eòlas a’ leasachadh ann an C, le fòcas air molaidhean cruinneachaidh agus toraidhean Google, bha e comasach dhomh modal obrach a sgrìobhadh agus a bhith a ’faireachdainn mar neach-tarraing kernel, agus aig an aon àm mar sgriobt kiddie. A bharrachd air an sin, chaidh mi gu sianal Kernel Newbies, far an deach innse dhomh a chleachdadh schedule_work() an àite a bhith a’ gairm call_usermodehelper() taobh a-staigh an dubhan fhèin agus chuir e nàire air, gu ceart fo amharas gun robh sgam ann. Chosg ceud loidhne de chòd dhomh mu sheachdain de leasachadh anns an ùine shaor agam. Eòlas soirbheachail a sgrios mo bheul-aithris pearsanta mu cho iom-fhillteachd leasachadh siostam.

Ma dh’ aontaicheas cuideigin ri lèirmheas còd a dhèanamh air Github, bidh mi taingeil. Tha mi gu math cinnteach gun do rinn mi tòrr mhearachdan gòrach, gu sònraichte nuair a bha mi ag obair le sreangan.

Slige niuclasach thairis air ICMP

Source: www.habr.com

Cuir beachd ann