டிஎல்; DR: நான் ஒரு கர்னல் தொகுதியை எழுதுகிறேன், அது ICMP பேலோடில் இருந்து கட்டளைகளைப் படித்து, உங்கள் SSH செயலிழந்தாலும் அவற்றை சர்வரில் செயல்படுத்தும். மிகவும் பொறுமையற்றவர்களுக்கு, அனைத்து குறியீடுகளும் -மகிழ்ச்சியா.
எச்சரிக்கை! அனுபவம் வாய்ந்த சி புரோகிராமர்கள் இரத்தக் கண்ணீரில் வெடிக்கும் அபாயம்! சொற்களில் கூட நான் தவறாக இருக்கலாம், ஆனால் எந்த விமர்சனமும் வரவேற்கத்தக்கது. சி நிரலாக்கத்தைப் பற்றி மிகவும் தோராயமான யோசனை உள்ளவர்களுக்காகவும், லினக்ஸின் உட்புறங்களைப் பார்க்க விரும்புபவர்களுக்காகவும் இந்த இடுகை உள்ளது.
எனது முதல் கருத்துக்களில் கட்டுரை சில "வழக்கமான" நெறிமுறைகளை, குறிப்பாக HTTPS, ICMP மற்றும் DNS போன்றவற்றைப் பிரதிபலிக்கக்கூடிய SoftEther VPN ஐக் குறிப்பிட்டுள்ளது. நான் HTTP(S) பற்றி நன்கு அறிந்திருப்பதால், ICMP மற்றும் DNS மூலம் நான் சுரங்கப்பாதையை கற்றுக் கொள்ள வேண்டியிருந்ததால், அவர்களில் முதன்மையானவர்கள் மட்டுமே வேலை செய்வதை என்னால் கற்பனை செய்து பார்க்க முடிகிறது.
ஆம், 2020ல் ICMP பாக்கெட்டுகளில் தன்னிச்சையான பேலோடைச் செருகலாம் என்பதை அறிந்தேன். ஆனால் எப்பொழுதும் விட தாமதம்! மேலும் இதைப் பற்றி ஏதாவது செய்ய முடியும் என்பதால், அதைச் செய்ய வேண்டும். எனது அன்றாட வாழ்க்கையில் நான் SSH வழியாக கட்டளை வரியை அடிக்கடி பயன்படுத்துவதால், ICMP ஷெல் பற்றிய யோசனை முதலில் என் மனதில் வந்தது. மேலும் ஒரு முழுமையான புல்ஷீல்ட் பிங்கோவை அசெம்பிள் செய்வதற்காக, எனக்கு தோராயமாக மட்டுமே இருக்கும் மொழியில் லினக்ஸ் தொகுதியாக எழுத முடிவு செய்தேன். அத்தகைய ஷெல் செயல்முறைகளின் பட்டியலில் காணப்படாது, நீங்கள் அதை கர்னலில் ஏற்றலாம் மற்றும் அது கோப்பு முறைமையில் இருக்காது, கேட்கும் துறைமுகங்களின் பட்டியலில் சந்தேகத்திற்குரிய எதையும் நீங்கள் காண மாட்டீர்கள். அதன் திறன்களைப் பொறுத்தவரை, இது ஒரு முழு நீள ரூட்கிட் ஆகும், ஆனால் SSH வழியாக உள்நுழைந்து குறைந்தபட்சம் இயக்குவதற்கு ஏற்ற சராசரி அதிகமாக இருக்கும் போது, இதை மேம்படுத்தி, கடைசி முயற்சியாக இதைப் பயன்படுத்துவேன் என்று நம்புகிறேன். echo i > /proc/sysrq-triggerமறுதொடக்கம் செய்யாமல் அணுகலை மீட்டெடுக்க.
நாங்கள் ஒரு டெக்ஸ்ட் எடிட்டர், பைதான் மற்றும் சி, கூகிள் மற்றும் அடிப்படை நிரலாக்க திறன்களை எடுத்துக்கொள்கிறோம் மெய்நிகர் எல்லாம் உடைந்தால் (விரும்பினால் - உள்ளூர் விர்ச்சுவல்பாக்ஸ்/கேவிஎம்/முதலியன) கத்தியின் கீழ் வைப்பதை நீங்கள் பொருட்படுத்தவில்லை, போகலாம்!
வாடிக்கையாளர் பகுதி
கிளையன்ட் பகுதிக்கு நான் சுமார் 80 வரிகளுடன் ஒரு ஸ்கிரிப்டை எழுத வேண்டும் என்று எனக்குத் தோன்றியது, ஆனால் எனக்காக அதைச் செய்த அன்பானவர்கள் இருந்தனர். அனைத்து வேலை. குறியீடு எதிர்பாராத விதமாக எளிமையானதாக மாறியது, 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()
ஸ்கிரிப்ட் இரண்டு வாதங்களை எடுக்கும், ஒரு முகவரி மற்றும் ஒரு பேலோட். அனுப்புவதற்கு முன், பேலோடுக்கு முன்னால் ஒரு விசை இருக்கும் run:, சீரற்ற பேலோடுகளைக் கொண்ட தொகுப்புகளை விலக்க இது தேவைப்படும்.
தொகுப்புகளை உருவாக்க கர்னலுக்கு சிறப்புரிமைகள் தேவை, எனவே ஸ்கிரிப்டை சூப்பர் யூசராக இயக்க வேண்டும். செயல்படுத்துவதற்கான அனுமதிகளை வழங்கவும் மற்றும் ஸ்கேபியை நிறுவவும் மறக்காதீர்கள். டெபியனில் ஒரு தொகுப்பு உள்ளது python3-scapy. இப்போது அது எவ்வாறு செயல்படுகிறது என்பதை நீங்கள் சரிபார்க்கலாம்.
கட்டளையை இயக்குதல் மற்றும் வெளியிடுதல் 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!
மோப்பம் பிடித்தல் இப்படித்தான் தெரிகிறது 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)
டெபியன் மெய்நிகர் கணினியில் உருவாக்க உங்களுக்கு குறைந்தபட்சம் தேவைப்படும் make и linux-headers-amd64, மீதமுள்ளவை சார்பு வடிவில் வரும். கட்டுரையில் முழு குறியீட்டையும் நான் வழங்கமாட்டேன்; நீங்கள் அதை Github இல் குளோன் செய்யலாம்.
ஹூக் அமைப்பு
தொடங்குவதற்கு, தொகுதியை ஏற்றுவதற்கும் அதை இறக்குவதற்கும் இரண்டு செயல்பாடுகள் தேவை. இறக்குவதற்கான செயல்பாடு தேவையில்லை, ஆனால் பின்னர் rmmod அது வேலை செய்யாது; அணைக்கப்படும் போது மட்டுமே தொகுதி இறக்கப்படும்.
மாட்யூலையும் நெட்ஃபில்டரையும் கையாள இரண்டு தலைப்பு கோப்புகள் இழுக்கப்படுகின்றன.
அனைத்து செயல்பாடுகளும் ஒரு நெட்ஃபில்டர் மூலம் செல்கின்றன, நீங்கள் அதில் கொக்கிகளை அமைக்கலாம். இதைச் செய்ய, கொக்கி கட்டமைக்கப்படும் கட்டமைப்பை நீங்கள் அறிவிக்க வேண்டும். மிக முக்கியமான விஷயம், ஒரு கொக்கியாக செயல்படுத்தப்படும் செயல்பாட்டைக் குறிப்பிடுவது: nfho.hook = icmp_cmd_executor; நான் பிறகு விழாவிற்கு வருகிறேன்.
பின்னர் நான் தொகுப்பிற்கான செயலாக்க நேரத்தை அமைத்தேன்: NF_INET_PRE_ROUTING கர்னலில் முதலில் தோன்றும் போது தொகுப்பை செயல்படுத்த குறிப்பிடுகிறது. உபயோகிக்கலாம் NF_INET_POST_ROUTING கர்னலில் இருந்து வெளியேறும் போது பாக்கெட்டை செயலாக்க.
நான் வடிகட்டியை IPv4 க்கு அமைத்துள்ளேன்: nfho.pf = PF_INET;.
எனது கொக்கிக்கு நான் அதிக முன்னுரிமை கொடுக்கிறேன்: nfho.priority = NF_IP_PRI_FIRST;
நான் தரவு கட்டமைப்பை உண்மையான கொக்கியாக பதிவு செய்கிறேன்: nf_register_net_hook(&init_net, &nfho);
இறுதி செயல்பாடு கொக்கியை நீக்குகிறது.
கம்பைலர் புகார் செய்யாதபடி உரிமம் தெளிவாகக் குறிப்பிடப்பட்டுள்ளது.
செயல்பாடுகளை module_init() и module_exit() தொகுதியை துவக்க மற்றும் நிறுத்த மற்ற செயல்பாடுகளை அமைக்கவும்.
பேலோடை மீட்டெடுக்கிறது
இப்போது நாம் பேலோடைப் பிரித்தெடுக்க வேண்டும், இது மிகவும் கடினமான பணியாக மாறியது. கர்னலில் பேலோடுகளுடன் வேலை செய்வதற்கான உள்ளமைக்கப்பட்ட செயல்பாடுகள் இல்லை; உயர்நிலை நெறிமுறைகளின் தலைப்புகளை மட்டுமே நீங்கள் அலச முடியும்.
IP மற்றும் ICMP தலைப்புகளைக் கையாள, கூடுதல் தலைப்புக் கோப்புகளைச் சேர்க்க வேண்டியிருந்தது.
நான் அதிகபட்ச வரி நீளத்தை அமைத்தேன்: #define MAX_CMD_LEN 1976. ஏன் இது சரியாக? ஏனெனில் தொகுத்தவர் அதைப் பற்றி புகார் கூறுகிறார்! ஸ்டாக் மற்றும் குவியலை நான் புரிந்து கொள்ள வேண்டும் என்று அவர்கள் ஏற்கனவே என்னிடம் பரிந்துரைத்துள்ளனர், ஒருநாள் நான் நிச்சயமாக இதைச் செய்வேன், மேலும் குறியீட்டை சரிசெய்வேன். கட்டளையைக் கொண்டிருக்கும் வரியை உடனடியாக அமைத்தேன்: char cmd_string[MAX_CMD_LEN];. இது அனைத்து செயல்பாடுகளிலும் காணப்பட வேண்டும்; இதைப் பற்றி நான் பத்தி 9 இல் விரிவாகப் பேசுவேன்.
இப்போது நாம் துவக்க வேண்டும் (struct work_struct my_work;) கட்டமைப்பு மற்றும் அதை மற்றொரு செயல்பாட்டுடன் இணைக்கவும் (DECLARE_WORK(my_work, work_handler);) இது ஏன் அவசியம் என்பதையும் ஒன்பதாவது பத்தியில் பேசுவேன்.
இப்போது நான் ஒரு செயல்பாட்டை அறிவிக்கிறேன், அது ஒரு கொக்கியாக இருக்கும். வகை மற்றும் ஏற்றுக்கொள்ளப்பட்ட வாதங்கள் நெட்ஃபில்டரால் கட்டளையிடப்படுகின்றன, நாங்கள் ஆர்வமாக உள்ளோம் skb. இது ஒரு சாக்கெட் இடையகமாகும், இது ஒரு பாக்கெட் பற்றிய அனைத்து தகவல்களையும் கொண்ட ஒரு அடிப்படை தரவு கட்டமைப்பாகும்.
செயல்பாடு வேலை செய்ய, உங்களுக்கு இரண்டு கட்டமைப்புகள் மற்றும் பல மாறிகள் தேவைப்படும், இதில் இரண்டு மறு செய்கைகள் அடங்கும்.
நாம் தர்க்கத்துடன் ஆரம்பிக்கலாம். தொகுதி வேலை செய்ய, ICMP எக்கோவைத் தவிர வேறு பாக்கெட்டுகள் தேவையில்லை, எனவே உள்ளமைக்கப்பட்ட செயல்பாடுகளைப் பயன்படுத்தி இடையகத்தை அலசுவோம் மற்றும் அனைத்து ICMP மற்றும் எக்கோ அல்லாத பாக்கெட்டுகளையும் வெளியேற்றுவோம். திரும்பு NF_ACCEPT தொகுப்பை ஏற்றுக்கொள்வதைக் குறிக்கிறது, ஆனால் நீங்கள் திரும்பப் பெறுவதன் மூலம் தொகுப்புகளை கைவிடலாம் NF_DROP.
IP தலைப்புகளைச் சரிபார்க்காமல் என்ன நடக்கும் என்பதை நான் சோதிக்கவில்லை. C பற்றிய எனது குறைந்தபட்ச அறிவு, கூடுதல் சோதனைகள் இல்லாமல், பயங்கரமான ஒன்று நிகழும் என்று கூறுகிறது. நீங்கள் என்னை இதிலிருந்து விலக்கினால் நான் மகிழ்ச்சியடைவேன்!
இப்போது தொகுப்பு உங்களுக்குத் தேவையான சரியான வகையைச் சேர்ந்தது, நீங்கள் தரவைப் பிரித்தெடுக்கலாம். உள்ளமைக்கப்பட்ட செயல்பாடு இல்லாமல், நீங்கள் முதலில் பேலோடின் தொடக்கத்திற்கு ஒரு சுட்டியைப் பெற வேண்டும். இது ஒரே இடத்தில் செய்யப்படுகிறது, நீங்கள் ICMP தலைப்பின் தொடக்கத்திற்கு சுட்டியை எடுத்து இந்த தலைப்பின் அளவிற்கு நகர்த்த வேண்டும். எல்லாம் கட்டமைப்பைப் பயன்படுத்துகிறது icmph: user_data = (unsigned char *)((unsigned char *)icmph + (sizeof(icmph)));
தலைப்பின் முடிவு, பேலோடின் முடிவுடன் பொருந்த வேண்டும் skb, எனவே அணுசக்தி வழிமுறைகளைப் பயன்படுத்தி தொடர்புடைய கட்டமைப்பிலிருந்து அதைப் பெறுகிறோம்: tail = skb_tail_pointer(skb);.
படம் திருடப்பட்டது இங்கிருந்து, சாக்கெட் பஃபர் பற்றி மேலும் படிக்கலாம்.
தொடக்கம் மற்றும் முடிவுக்கான சுட்டிகளை நீங்கள் பெற்றவுடன், நீங்கள் தரவை ஒரு சரத்தில் நகலெடுக்கலாம் cmd_string, முன்னொட்டு உள்ளதா என சரிபார்க்கவும் run: மற்றும், தொகுப்பைக் காணவில்லை என்றால் அதை நிராகரிக்கவும் அல்லது வரியை மீண்டும் எழுதவும், இந்த முன்னொட்டை நீக்கவும்.
அவ்வளவுதான், இப்போது நீங்கள் மற்றொரு கையாளுபவரை அழைக்கலாம்: schedule_work(&my_work);. அத்தகைய அழைப்புக்கு ஒரு அளவுருவை அனுப்ப முடியாது என்பதால், கட்டளையுடன் கூடிய வரி உலகளாவியதாக இருக்க வேண்டும். schedule_work() அனுப்பப்பட்ட கட்டமைப்புடன் தொடர்புடைய செயல்பாட்டை பணி திட்டமிடுபவரின் பொது வரிசையில் வைத்து முடிக்கவும், கட்டளை முடிவடையும் வரை காத்திருக்க வேண்டாம். கொக்கி மிக வேகமாக இருக்க வேண்டும் என்பதால் இது அவசியம். இல்லையெனில், எதுவும் தொடங்காது அல்லது நீங்கள் கர்னல் பீதியைப் பெறுவீர்கள் என்பது உங்கள் விருப்பம். தாமதம் மரணம் போன்றது!
அவ்வளவுதான், அதற்கான வருவாயுடன் தொகுப்பை ஏற்கலாம்.
பயனர்வெளியில் ஒரு நிரலை அழைக்கிறது
இந்த செயல்பாடு மிகவும் புரிந்துகொள்ளக்கூடியது. அதன் பெயர் கொடுக்கப்பட்டது DECLARE_WORK(), வகை மற்றும் ஏற்றுக்கொள்ளப்பட்ட வாதங்கள் சுவாரஸ்யமானவை அல்ல. நாங்கள் கட்டளையுடன் வரியை எடுத்து அதை முழுமையாக ஷெல்லுக்கு அனுப்புகிறோம். பாகுபடுத்துதல், பைனரிகளைத் தேடுதல் மற்றும் எல்லாவற்றையும் அவர் சமாளிக்கட்டும்.
சரங்களின் வரிசைக்கு வாதங்களை அமைக்கவும் argv[]. நிரல்கள் உண்மையில் இந்த வழியில் செயல்படுத்தப்படுகின்றன என்பது அனைவருக்கும் தெரியும் என்று நான் கருதுகிறேன், இடைவெளிகளுடன் தொடர்ச்சியான வரியாக அல்ல.
சூழல் மாறிகளை அமைக்கவும். குறைந்தபட்ச பாதைகள் கொண்ட PATH ஐ மட்டும் செருகினேன், அவை அனைத்தும் ஏற்கனவே ஒருங்கிணைக்கப்பட்டுள்ளன என்ற நம்பிக்கையில் /bin с /usr/bin и /sbin с /usr/sbin. மற்ற பாதைகள் நடைமுறையில் அரிதாகவே முக்கியம்.
முடிந்தது, செய்வோம்! கர்னல் செயல்பாடு call_usermodehelper() நுழைவு ஏற்கிறது. பைனரிக்கான பாதை, வாதங்களின் வரிசை, சூழல் மாறிகளின் வரிசை. இயங்கக்கூடிய கோப்புக்கான பாதையை ஒரு தனி வாதமாக கடந்து செல்வதன் அர்த்தத்தை அனைவரும் புரிந்துகொள்கிறார்கள் என்று இங்கு நான் கருதுகிறேன், ஆனால் நீங்கள் கேட்கலாம். செயல்முறை முடிவடையும் வரை காத்திருக்க வேண்டுமா என்பதை கடைசி வாதம் குறிப்பிடுகிறது (UMH_WAIT_PROC), செயல்முறை தொடக்கம் (UMH_WAIT_EXEC) அல்லது காத்திருக்க வேண்டாம் (UMH_NO_WAIT) இன்னும் சில இருக்கிறதா UMH_KILLABLE, நான் அதைப் பார்க்கவில்லை.
சட்டசபை
கர்னல் தொகுதிகளின் அசெம்பிளி கர்னல் மேக்-ஃப்ரேம்வொர்க் மூலம் செய்யப்படுகிறது. அழைக்கப்பட்டது make கர்னல் பதிப்புடன் இணைக்கப்பட்ட ஒரு சிறப்பு அடைவின் உள்ளே (இங்கே வரையறுக்கப்பட்டுள்ளது: KERNELDIR:=/lib/modules/$(shell uname -r)/build), மற்றும் தொகுதியின் இடம் மாறிக்கு அனுப்பப்படுகிறது M வாதங்களில். icmpshell.ko மற்றும் சுத்தமான இலக்குகள் இந்த கட்டமைப்பை முழுமையாகப் பயன்படுத்துகின்றன. IN obj-m தொகுதியாக மாற்றப்படும் பொருள் கோப்பைக் குறிக்கிறது. ரீமேக் செய்யும் தொடரியல் main.o в icmpshell.o (icmpshell-objs = main.o) எனக்கு மிகவும் தர்க்கரீதியாகத் தெரியவில்லை, ஆனால் அது அப்படியே இருக்கும்.
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
நாங்கள் சேகரிக்கிறோம்: make. ஏற்றுகிறது: insmod icmpshell.ko. முடிந்தது, நீங்கள் சரிபார்க்கலாம்: sudo ./send.py 45.11.26.232 "date > /tmp/test". உங்கள் கணினியில் கோப்பு இருந்தால் /tmp/test கோரிக்கை அனுப்பப்பட்ட தேதி அதில் உள்ளது, அதாவது நீங்கள் எல்லாவற்றையும் சரியாகச் செய்தீர்கள், நான் எல்லாவற்றையும் சரியாகச் செய்தேன்.
முடிவுக்கு
அணுசக்தி வளர்ச்சியில் எனது முதல் அனுபவம் நான் எதிர்பார்த்ததை விட மிகவும் எளிதாக இருந்தது. C இல் வளர்ந்த அனுபவம் இல்லாவிட்டாலும், கம்பைலர் குறிப்புகள் மற்றும் கூகிள் முடிவுகளில் கவனம் செலுத்தி, நான் ஒரு வேலை செய்யும் தொகுதியை எழுத முடிந்தது மற்றும் ஒரு கர்னல் ஹேக்கராக உணர முடிந்தது, அதே நேரத்தில் ஒரு ஸ்கிரிப்ட் கிடி. கூடுதலாக, நான் Kernel Newbies சேனலுக்குச் சென்றேன், அங்கு அவர்கள் என்னைப் பயன்படுத்தச் சொன்னார்கள் schedule_work() அழைப்பதற்கு பதிலாக call_usermodehelper() கொக்கி உள்ளே மற்றும் அவரை அவமானப்படுத்தியது, சரியாக ஒரு மோசடி சந்தேகம். எனது ஓய்வு நேரத்தில் ஒரு வார வளர்ச்சிக்கு நூறு வரிகள் குறியீடு செலவாகிறது. சிஸ்டம் மேம்பாட்டின் பெரும் சிக்கலானது பற்றிய எனது தனிப்பட்ட கட்டுக்கதையை அழித்த ஒரு வெற்றிகரமான அனுபவம்.
கிதுப்பில் குறியீடு மதிப்பாய்வு செய்ய யாராவது ஒப்புக்கொண்டால், நான் நன்றியுள்ளவனாக இருப்பேன். நான் மிகவும் முட்டாள்தனமான தவறுகளை செய்திருக்கிறேன், குறிப்பாக சரங்களுடன் பணிபுரியும் போது.