TL; DR: Qed nikteb modulu tal-kernel li se jaqra kmandi mit-tagħbija ICMP u jesegwixxihom fuq is-server anki jekk l-SSH tiegħek jiġġarraf. Għall-aktar paċenzja, il-kodiċi kollu huwa GitHub.
Attenzjoni! Programmaturi C b'esperjenza jirriskjaw li jinfaqgħu f'tiċrit tad-demm! Jista’ jkun li anke nkun żbaljat fit-terminoloġija, imma kull kritika hija milqugħa. Il-kariga hija maħsuba għal dawk li għandhom idea approssimattiva tal-ipprogrammar C u jridu jħarsu lejn il-ġewwieni tal-Linux.
Fil-kummenti għall-ewwel tiegħi artikolu semma SoftEther VPN, li jistgħu jimitaw xi protokolli "regolari", b'mod partikolari HTTPS, ICMP u anke DNS. Nista' nimmaġina li l-ewwel wieħed minnhom jaħdem biss, peress li jien familjari ħafna mal-HTTP(S), u kelli nitgħallem il-mini fuq ICMP u DNS.
Iva, fl-2020 tgħallimt li tista' ddaħħal tagħbija arbitrarja f'pakketti ICMP. Imma aħjar tard milli qatt! U peress li xi ħaġa tista 'ssir dwar dan, allura jeħtieġ li jsir. Peress li fil-ħajja ta 'kuljum tiegħi ħafna drabi nuża l-linja tal-kmand, inkluż permezz ta' SSH, l-ewwel ġiet f'moħħi l-idea ta 'qoxra ICMP. U sabiex niġbor tombla bullshield kompluta, iddeċidejt li nikteb bħala modulu Linux f'lingwa li għandi biss idea approssimattiva tagħha. Qoxra bħal din mhux se tkun viżibbli fil-lista ta 'proċessi, tista' tagħbijaha fil-qalba u mhux se tkun fuq is-sistema tal-fajls, ma tara xejn suspettuż fil-lista ta 'portijiet tas-smigħ. F'termini tal-kapaċitajiet tiegħu, dan huwa rootkit sħiħ, iżda nittama li ntejbuh u nużah bħala qoxra ta 'l-aħħar għażla meta l-Medja tat-Tagħbija tkun għolja wisq biex tidħol permezz ta' SSH u tesegwixxi mill-inqas echo i > /proc/sysrq-triggerbiex tirrestawra l-aċċess mingħajr rebooting.
Nieħdu editur tat-test, ħiliet bażiċi ta 'programmar f'Python u C, Google u virtwali li ma tiddejjaqx tpoġġi taħt is-sikkina jekk kollox jinkiser (mhux obbligatorju - VirtualBox/KVM/eċċ lokali) u ejja!
In-naħa tal-klijent
Deherli li għall-parti tal-klijent ikolli nikteb script b'madwar 80 linja, imma kien hemm nies ġentili li għamluh għalija ix-xogħol kollu. Il-kodiċi rriżulta li kien sempliċi b'mod mhux mistenni, li jidħol f'10 linji sinifikanti:
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()
L-iskrittura tieħu żewġ argumenti, indirizz u payload. Qabel ma tintbagħat, it-tagħbija hija preċeduta minn ċavetta run:, ikollna bżonnha biex neskludu pakketti b'tagħbija bl-addoċċ.
Il-qalba teħtieġ privileġġi biex tfassal pakketti, għalhekk l-iskript ikollu jitmexxa bħala superuser. Tinsiex li tagħti permessi ta 'eżekuzzjoni u tinstalla scapy innifsu. Debian għandu pakkett imsejjaħ python3-scapy. Issa tista 'tiċċekkja kif jaħdem kollox.
Tmexxi u toħroġ il-kmand 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!
Dan huwa kif jidher fil-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)
Biex tibni f'magna virtwali Debian ser ikollok bżonn mill-inqas make и linux-headers-amd64, il-bqija se jiġu fil-forma ta 'dipendenzi. Mhux se nipprovdi l-kodiċi kollu fl-artiklu; tista’ tikklonah fuq Github.
Setup tal-ganċ
Biex tibda, neħtieġu żewġ funzjonijiet sabiex tagħbija l-modulu u biex inħottu. Il-funzjoni għall-ħatt mhix meħtieġa, iżda mbagħad rmmod mhux se jaħdem; il-modulu jinħatt biss meta jintefa.
Żewġ fajls header jinġibdu biex jimmanipulaw il-modulu innifsu u n-netfilter.
L-operazzjonijiet kollha jgħaddu minn netfilter, tista 'tissettja ganċijiet fiha. Biex tagħmel dan, trid tiddikjara l-istruttura li fiha se jkun ikkonfigurat il-ganċ. L-iktar ħaġa importanti hija li tispeċifika l-funzjoni li se tiġi esegwita bħala ganċ: nfho.hook = icmp_cmd_executor; Ser nasal għall-funzjoni nnifisha aktar tard.
Imbagħad issettja l-ħin tal-ipproċessar għall-pakkett: NF_INET_PRE_ROUTING jispeċifika li jipproċessa l-pakkett meta jidher għall-ewwel darba fil-qalba. Jista 'jintuża NF_INET_POST_ROUTING biex tipproċessa l-pakkett hekk kif joħroġ mill-qalba.
Issettja l-filtru għal IPv4: nfho.pf = PF_INET;.
Nagħti lill-ganċ tiegħi l-ogħla prijorità: nfho.priority = NF_IP_PRI_FIRST;
U nirreġistra l-istruttura tad-dejta bħala l-ganċ attwali: nf_register_net_hook(&init_net, &nfho);
Il-funzjoni finali tneħħi l-ganċ.
Il-liċenzja hija indikata b'mod ċar sabiex il-kompilatur ma jilmentax.
Funzjonijiet module_init() и module_exit() issettja funzjonijiet oħra biex jinizjalizza u jtemm il-modulu.
L-irkupru tat-tagħbija
Issa għandna bżonn niġbdu t-tagħbija, dan irriżulta li kien l-aktar kompitu diffiċli. Il-kernel m'għandux funzjonijiet integrati biex jaħdem ma 'payloads; tista' tparsa biss headers ta' protokolli ta' livell ogħla.
Kelli ninkludi fajls header addizzjonali, din id-darba biex timmanipula headers IP u ICMP.
Issettja t-tul massimu tal-linja: #define MAX_CMD_LEN 1976. Għaliex eżattament dan? Għax il-kompilatur jilmenta dwarha! Diġà ssuġġerewli li għandi bżonn nifhem il-munzell u l-munzell, xi darba żgur nagħmel dan u forsi anke nikkoreġi l-kodiċi. Immedjatament nissettja l-linja li se jkun fiha l-kmand: char cmd_string[MAX_CMD_LEN];. Għandu jkun viżibbli fil-funzjonijiet kollha; se nitkellem dwar dan f'aktar dettall fil-paragrafu 9.
Issa għandna bżonn inizjalizzaw (struct work_struct my_work;) struttura u qabbadha ma' funzjoni oħra (DECLARE_WORK(my_work, work_handler);). Se nitkellem ukoll dwar għaliex dan huwa meħtieġ fid-disa' paragrafu.
Issa niddikjara funzjoni, li se tkun ganċ. It-tip u l-argumenti aċċettati huma ddettati mill-netfilter, aħna interessati biss fihom skb. Din hija socket buffer, struttura ta' data fundamentali li fiha l-informazzjoni kollha disponibbli dwar pakkett.
Biex il-funzjoni taħdem, ser ikollok bżonn żewġ strutturi u diversi varjabbli, inklużi żewġ iteraturi.
Nistgħu nibdew bil-loġika. Biex il-modulu jaħdem, ma huma meħtieġa l-ebda pakketti għajr ICMP Echo, għalhekk aħna naqsbu l-buffer billi tuża funzjonijiet integrati u nefgħu l-pakketti kollha mhux ICMP u mhux Echo. Ritorn NF_ACCEPT tfisser l-aċċettazzjoni tal-pakkett, iżda tista 'wkoll twaqqa' pakketti billi tirritorna NF_DROP.
Ma ttestjajtx x'se jiġri mingħajr ma niċċekkja l-headers tal-IP. L-għarfien minimu tiegħi ta 'C jgħidli li mingħajr kontrolli addizzjonali, xi ħaġa terribbli hija marbuta li sseħħ. Inkun ferħan jekk tiddisswadini minn dan!
Issa li l-pakkett huwa tat-tip eżatt li għandek bżonn, tista 'tiġbed id-dejta. Mingħajr funzjoni integrata, l-ewwel trid tikseb pointer għall-bidu tat-tagħbija. Dan isir f'post wieħed, għandek bżonn tieħu l-pointer għall-bidu tal-header ICMP u tmexxih għad-daqs ta 'din l-intestatura. Kollox juża struttura icmph: user_data = (unsigned char *)((unsigned char *)icmph + (sizeof(icmph)));
It-tarf tal-header għandu jaqbel mat-tarf tal-payload in skb, għalhekk niksbuha billi tuża mezzi nukleari mill-istruttura korrispondenti: tail = skb_tail_pointer(skb);.
L-istampa nsterqet għalhekk, tista 'taqra aktar dwar il-buffer tas-sokit.
Ladarba jkollok indikaturi għall-bidu u t-tmiem, tista 'tikkopja d-dejta f'sekwenza cmd_string, iċċekkjah għall-preżenza ta 'prefiss run: u, jew armi l-pakkett jekk ikun nieqes, jew erġa' ikteb il-linja, billi tneħħi dan il-prefiss.
Dak hu, issa tista' ċċempel handler ieħor: schedule_work(&my_work);. Peress li mhux se jkun possibbli li jgħaddi parametru għal sejħa bħal din, il-linja bil-kmand għandha tkun globali. schedule_work() se tpoġġi l-funzjoni assoċjata ma 'l-istruttura mgħoddija fil-kju ġenerali ta' l-iskedar tal-kompitu u kompluta, li jippermettilek li ma tistennax il-kmand biex jitlesta. Dan huwa meħtieġ minħabba li l-ganċ għandu jkun mgħaġġel ħafna. Inkella, l-għażla tiegħek hija li xejn ma jibda jew ikollok paniku tal-qalba. Id-dewmien huwa bħall-mewt!
Dak hu, tista 'taċċetta l-pakkett b'ritorn korrispondenti.
Sejħa ta' programm fl-ispazju tal-utent
Din il-funzjoni hija l-aktar li tinftiehem. Isimha ingħata fi DECLARE_WORK(), it-tip u l-argumenti aċċettati mhumiex interessanti. Nieħdu l-linja bil-kmand u ngħadduha kompletament lill-qoxra. Ħallih jittratta l-parsing, it-tiftix għal binarji u kull ħaġa oħra.
Issettja l-argumenti għal firxa ta 'kordi argv[]. Ser nassumi li kulħadd jaf li l-programmi huma attwalment eżegwiti b'dan il-mod, u mhux bħala linja kontinwa bi spazji.
Issettja varjabbli ambjentali. Daħħal PATH biss b'sett minimu ta 'mogħdijiet, bit-tama li kienu kollha diġà kkombinati /bin с /usr/bin и /sbin с /usr/sbin. Mogħdijiet oħra rari huma importanti fil-prattika.
Lest, ejja nagħmluha! Funzjoni tal-kernel call_usermodehelper() jaċċetta d-dħul. mogħdija għall-binarju, firxa ta 'argumenti, firxa ta' varjabbli ambjentali. Hawnhekk nassumi wkoll li kulħadd jifhem it-tifsira li tgħaddi t-triq għall-fajl eżekutibbli bħala argument separat, imma tista 'titlob. L-aħħar argument jispeċifika jekk għandux jistenna li jitlesta l-proċess (UMH_WAIT_PROC), bidu tal-proċess (UMH_WAIT_EXEC) jew ma tistenna xejn (UMH_NO_WAIT). Hemm xi ftit aktar UMH_KILLABLE, ma ħaristx fiha.
Assemblea
L-assemblaġġ tal-moduli tal-qalba jitwettaq permezz tal-qafas tal-għamla tal-qalba. Imsejjaħ make ġewwa direttorju speċjali marbut mal-verżjoni tal-kernel (definit hawn: KERNELDIR:=/lib/modules/$(shell uname -r)/build), u l-post tal-modulu jiġi mgħoddi lill-varjabbli M fl-argumenti. L-icmpshell.ko u l-miri nodfa jużaw dan il-qafas għal kollox. IN obj-m jindika l-fajl tal-oġġett li se jiġi kkonvertit f'modulu. Sintassi li tirrefaka main.o в icmpshell.o (icmpshell-objs = main.o) ma tantx tidher loġika għalija, imma hekk ikun.
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
Aħna niġbru: make. Tagħbija: insmod icmpshell.ko. Lest, tista' tiċċekkja: sudo ./send.py 45.11.26.232 "date > /tmp/test". Jekk għandek fajl fuq il-magna tiegħek /tmp/test u fiha d-data li fiha ntbagħtet it-talba, li jfisser li inti għamilt kollox sew u jien għamilt kollox tajjeb.
Konklużjoni
L-ewwel esperjenza tiegħi bl-iżvilupp nukleari kienet ħafna aktar faċli milli stennejt. Anke mingħajr esperjenza ta 'żvilupp f'Ċ, li niffoka fuq ħjiel tal-kompilatur u riżultati ta' Google, stajt nikteb modulu ta 'ħidma u nħossni bħal hacker tal-kernel, u fl-istess ħin kiddie tal-iskript. Barra minn hekk, mort fil-kanal Kernel Newbies, fejn qaluli biex nuża schedule_work() minflok iċempel call_usermodehelper() ġewwa l-ganċ innifsu u shamed lilu, bir-raġun jissuspetta scam. Mitt linja ta’ kodiċi jiswieli madwar ġimgħa ta’ żvilupp fil-ħin liberu tiegħi. Esperjenza ta’ suċċess li qerdet il-leġġenda personali tiegħi dwar il-kumplessità kbira tal-iżvilupp tas-sistema.
Jekk xi ħadd jaqbel li jagħmel reviżjoni tal-kodiċi fuq Github, inkun grat. Jien pjuttost ċert li għamilt ħafna żbalji stupidi, speċjalment meta naħdem mal-kordi.