├── assets ├── 006 │ └── x86-registers.png ├── 004 │ ├── google-url-encode.png │ └── http.py └── 001 │ └── rainbow-table.svg ├── README.md ├── 002-201607-3.資訊安全與CIA.md ├── 000-201607-1.不要儲存明文密碼.md ├── 001-201607-2.Hash.md ├── 003-201607-4.HTTP.md ├── 004-201608-5.HTTP-II.md ├── 005-SQL-Injection.md └── 006-逆向工程簡介.md /assets/006/x86-registers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Inndy/fresh-foods/HEAD/assets/006/x86-registers.png -------------------------------------------------------------------------------- /assets/004/google-url-encode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Inndy/fresh-foods/HEAD/assets/004/google-url-encode.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fresh-Foods -- 每週一點小知識 2 | 3 | ## 內容授權方式 4 | 5 | 本期刊內容若無特別註明,則以 [creative commons BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/tw/) 授權發布 6 | -------------------------------------------------------------------------------- /002-201607-3.資訊安全與CIA.md: -------------------------------------------------------------------------------- 1 | # 資訊安全與 CIA 2 | 3 | Author: Inndy < inndy [dot] tw [at] gmail [dot] com > 4 | 5 | Date: 2016/07/24 6 | 7 | ## 什麼是資訊安全? 8 | 9 | 以最簡單的定義來說,就是保護電子化資料與系統(除了 Word 文件、照片、資料庫之外,程式碼、作業系統、乃至於電子門禁都包含在內),不會被授權人員以外的任何人讀取、操作、破壞、干擾等。 10 | 11 | ## 資訊安全三要素 - CIA 12 | 13 | 通常在資訊安全的課程裡面,第一個談的主題就是CIA三要素,分別是: 14 | 15 | - 機密性 (Confidentiality) 16 | - 完整性 (Integrity) 17 | - 可用性 (Availability) 18 | 19 | 這三個性質可以用來評估你的系統是否足夠安全,如果經過各種方向的考量,上面三者都能夠被滿足的話,就可以說你的系統是安全的 20 | 21 | ### 機密性 22 | 23 | 是否能夠正確限制資料的存取權限,不讓未被授權的使用者讀取到資料內容。 24 | 25 | 如:Facebook 發文限制只能讓好友看、公司產品的原始碼只有負責那項產品的工程師能夠拿到、任何人都不該能夠讀取某個使用者的密碼、Cache Service (Redis, Memcached) 不要裸奔在外網讓任何人可以存取到 26 | 27 | ### 完整性 28 | 29 | 資料在傳輸、儲存的過程中,不會被未經授權的使用者破壞或是竄改,可以建立一個偵測機制,如果傳輸過程中完整性遭到破壞就重新傳送 30 | 31 | 如:不會因為 Data Center 被炸掉就造成資料全數遺失(可能需要異地備援)、把影片上傳到 YouTube 的過程中,沒有人可以竄改你上傳的影片、傳送資料的時候使用 HMAC 或是數位簽章的方式確定真的是從你信任的單位傳送的,並且沒有經過他人修改 32 | 33 | ### 可用性 34 | 35 | 確保服務不會中斷 36 | 37 | 如:建立附載平衡機制抵禦 DDoS,讓網站不會因為簡單的 DDoS 就被打掛、入侵系統後刪除所有資料會造成服務中斷,破壞掉可用性 38 | 39 | ## 案例分析 40 | 41 | 接下來我們分析幾個場景,看看他們分別破壞了哪幾個要素?(以下案例均屬虛構,如有雷同,那就雷同) 42 | 43 | ### Case 1 44 | 45 | > 花花協助友人架設某知名 2D 角色扮演遊戲的私人伺服器,結果遭到同業發起 **DDoS 攻擊**,癱瘓遊戲伺服器,並且在網站上發現漏洞,**侵入主機並且下載了所有玩家的個人資料**,發送黑函 46 | 47 | DDoS 攻擊造成服務中斷,這打破了可用性,玩家的個人資料遭受到未授權的讀取,因此打破了機密性 48 | 49 | ### Case 2 50 | 51 | > 霹靂艾倫是一個強大的駭客,有一天他在上網的時候發現,有人在他自己的網站上面放了以下聲明:「這個網站由霹靂艾倫與椪柑守護,請不要輕易攻擊」,霹靂艾倫覺得有人冒用他的身份覺得不太開心,所以找了網站的漏洞,入侵那個網站,**把那段聲明拿掉並且放了一隻可愛的小羊 ASCII Art 與一段文字**提醒管理員不可以冒用別人的名義 52 | 53 | 霹靂艾倫雖然入侵了網站但是沒有進行惡意破壞的行為,網站的服務依然正常,也沒有敏感資料被偷走,不過網站的內容遭到修改,因此打破了完整性 54 | 55 | ### Case 3 56 | 57 | > 墨瘋心情不好的時候,喜歡在網路上亂逛,有時會不小心發現 webshell 又猜到密碼,有時候會找到 SQL injection 的漏洞,但是用 sqlmap 的時候常常會不小心加上 `--dump-all` 的參數,就不小心把整個網站的資料庫都搬回家了 58 | 59 | 以這個例子來說,建議大家在測試漏洞的時候點到為止就好,如果把資料讀取出來很有可能會犯法,不小心把整個網站的資料庫搬回家的部分,因為讀取了不該能夠抓到的資料,所以違反了機密性 60 | 61 | ## 下週預告 62 | 63 | - (NULL) 64 | 65 | --- 66 | 67 | 這篇文章以 [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/tw/) 授權釋出 68 | -------------------------------------------------------------------------------- /000-201607-1.不要儲存明文密碼.md: -------------------------------------------------------------------------------- 1 | # 不要儲存明文密碼 2 | 3 | Author: Inndy < inndy [dot] tw [at] gmail [dot] com > 4 | 5 | Date: 2016/07/07 6 | 7 | ## 什麼是明文? 8 | 9 | 首先我們先來談談,什麼是明文(plain text)。 10 | 11 | 明文就是沒有經過任何處理,任何人都能簡單解讀的原始資料,相對於明文的概念:密文(ciphertext)、暗語,就是經過加密或者轉換成暗號文字、資料內容。 12 | 13 | ## 為什麼不該儲存明文密碼 14 | 15 | 當你儲存的資料可以被任何人,或者未被授權的人讀取時,以明文儲存的密碼可以被輕易地取出,冒用你的身份。舉個例子:你把 Facebook 密碼寫在辦公室桌上,那麼就有人可以從你的桌上抄走密碼,盜用你的 Facebook 帳號。換個場景,如果你的網站系統有漏洞,黑客把你整個資料庫或者存有密碼的檔案下載回去了,就可以馬上登入你的帳號,毀了整個網站,或者關閉整個系統。 16 | 17 | 在另一個層面來看,不儲存明文密碼同時也是在保護你的網站使用者,大部分的使用者在很多地方使用相同的密碼,只要有一個網站的資料庫外洩,通常就代表使用者的 E-mail 和密碼同時外洩,那就有可能被用來登入其他的網站服務。 18 | 19 | ## 什麼是雜湊(Hash) 20 | 21 | 雜湊是以一個不可逆的過程,計算資料的摘要特徵值。 22 | 23 | 例如:將輸入的資料,每個 Unicode 加總,最後對 100 求餘數 24 | 25 | ``` python 26 | def H(data): 27 | s = 0 28 | for ch in data: 29 | s += ord(ch) 30 | return s % 100 31 | ``` 32 | 33 | `H` 稱作雜湊函數(hash function),並且可以算出 `I love Python` 的雜湊值為:`17` 34 | 35 | 再舉個例子: 36 | 37 | ``` python 38 | def H2(data): 39 | s = 12345 40 | for ch in data: 41 | s = (s * 123 + ord(ch)) % 1000 42 | return s 43 | ``` 44 | 45 | 這時候可以算出 `H2('I love Python')` 的雜湊值是 `322` 46 | 47 | ## 雜湊的特性 48 | 49 | 資料經過雜湊之後會具有一個特性:**相同的資料必然具有相同的雜湊值**,但是不同的資料也有可能產生一樣的雜湊值,不同資料產生相同雜湊值的狀況稱之為碰撞(hash collision),如: 50 | 51 | 剛剛提過的 `H2` 雜湊函數,輸入值 `I love Python` 和 `ccccccccccccccccccccccccccccccccccccccccccccccc` 都具有相同的雜湊值: `322`,`yyyyyyyyyyyyyyyyyyyyyyyyy` 和 `password` 具有相同的雜湊值: `716` 52 | 53 | ## 常見的雜湊函數 54 | 55 | - CRC (最常見的版本為 CRC32) 56 | - MD5 ([已被認為不安全](http://www.infosec.sdu.edu.cn/2person_wangxiaoyun.htm)) 57 | - SHA1 ([已被認為不安全](http://www.infosec.sdu.edu.cn/2person_wangxiaoyun.htm)) 58 | - SHA256 / SHA512 59 | - RIPEMD 60 | - Luhn algorithm (信用卡卡號用這個演算法檢查卡號正確性,臺灣身分證也採用了類似的演算法) 61 | 62 | 想知道更多的雜湊演算法,可以參考:[Wikipeida: List of hash functions](https://en.wikipedia.org/wiki/List_of_hash_functions) 63 | 64 | ## 所以應該如何儲存密碼 65 | 66 | 密碼應該先經過高強度雜湊(strong hash)的處理再儲存。 67 | 68 | 如果要驗證使用者的身份,則將使用者登入時輸入的密碼經由相同的雜湊函數運算,如果雜湊值相同,我們就認為密碼正確。 69 | 70 | ## 那產生碰撞的時候怎麼辦? 71 | 72 | 提高雜湊值的資料容量(長度),就可以減少碰撞的機率。 73 | 74 | ## 我該用哪種雜湊函數? 75 | 76 | 儲存密碼時,應該選用雜湊過程較為複雜的雜湊函數,如:[`bcrypt`](https://en.wikipedia.org/wiki/Bcrypt), [`pbkdf2`](https://en.wikipedia.org/wiki/PBKDF2), [`scrypt`](https://en.wikipedia.org/wiki/Scrypt) ... 等雜湊函數就是專門為了儲存密碼設計的。 77 | 78 | ## 保護自己 79 | 80 | 你沒辦法信任每個網站都是安全的,也沒辦法確定每個網站的營運者都有良心不會偷看你的密碼,更無法保證駭客不會入侵 Facebook,所以每個網站都應該要使用不同的密碼,至少至少,E-mail, Facebook, 通訊軟體 ... 等,這些比較重要(被盜用會發生嚴重的事情)的服務,密碼不能夠重複使用。 81 | 82 | ## 同場加映 83 | 84 | [我的密碼沒加密](http://plainpass.com/) 85 | 86 | ## 下週預告 87 | 88 | - 雜湊的其他用途 89 | - 資料完整性驗證 90 | - 針對雜湊密碼的攻擊與防禦 91 | - 加密、編碼、雜湊的差異 92 | 93 | --- 94 | 95 | 這篇文章以 [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/tw/) 授權釋出 96 | -------------------------------------------------------------------------------- /001-201607-2.Hash.md: -------------------------------------------------------------------------------- 1 | # Hash 2 | 3 | Author: Inndy < inndy [dot] tw [at] gmail [dot] com > 4 | 5 | Date: 2016/07/18 6 | 7 | ## 雜湊的其他用途 8 | 9 | 除了上一週所提到的儲存密碼,雜湊還有其他非常多的作用,如: 10 | 11 | - 幫資料分類(data sharding、hash set) 12 | - 如果 hash function 只是很簡單地把輸入資料除以十,那你就可以把資料分成十堆,分別存在不同的地方 13 | - 檢查資料完整性(下載檔案時,常會附上 sha1 / sha256 hash) 14 | - 萬一你下載了作業系統的安裝程式,結果安裝到一半告訴你說安裝檔不完整,沒辦法安裝,夠囧吧? 15 | - 保護資料不被竄改(HMAC) 16 | - 如果你需要把敏感資料存在第三方手上,你需要確保持有你資料的人不會惡意篡改你的資料 17 | - Block Chain 18 | - BitCoin 相關的技術 19 | - 尋找重複的檔案 20 | - 想像一下你有一萬個10MB檔案,其中這些資料彼此都具有超過95%的相同內容,大概有幾千個檔案內容是完全一樣的,一個一個抓出來倆倆比較需要花多少時間? 21 | 22 | ## 資料完整性驗證 23 | 24 | 如果是透過不穩定的傳輸媒介交換資料,可能會因為雜訊而造成資料的內容毀損或者傳輸了不正確的內容,這時候你可以附上資料的 hash,讓接收端有能力檢查出資料傳輸有誤,甚至具有一定的自我更正能力。 25 | 26 | 另一種資料完整性的保證,是為了保護資料不被第三人竄改,例如在 A 銀行轉賬,但是網路不通所以 A 銀行給了你一張書面證明,叫你拿去 B 銀行完成轉帳動作,那麼 A, B 銀行要如何確保你不會擅自修改書面證明上的東西? 27 | 28 | ## Hash-based Message Authentication Code (HMAC) 29 | 30 | 另一個場景,現在的網路服務常常會有會員登入機制,在網頁上的做法常常會在你的 [Cookie](https://zh.wikipedia.org/wiki/Cookie) 中記錄你的身份、會員權限之類的資料,但是 Cookie 可以輕易的修改,要如何確保網站的使用者不會修改自己的 Cookie 偽裝成另一個會員甚至是管理員?至於解決方案之一就是使用 HMAC,對於其他的方法我們之後再談。 31 | 32 | 概念上來講,HMAC 就是把 data 和一組暗號(secret)一起拿去做 hash,如果有人篡改了資料內容,但是不知道 secret,就會發現 HMAC 和資料不符合,進而防止資料被竄改。 33 | 34 | 對於 HMAC 的實作細節可以參考 [Wikipedia](https://en.wikipedia.org/wiki/Hash-based_message_authentication_code) 35 | 36 | 37 | ## 針對雜湊密碼的攻擊與防禦 38 | 39 | 如果我們儲存的是單次 `md5` 或是 `sha1` hash 過後的密碼,那麼可以進行字典檔攻擊以及彩虹表攻擊甚至是暴力破解。 40 | 41 | ### 字典檔攻擊 42 | 43 | 準備一串文字組合出可能的密碼,例如:日期、姓名、常用單字、動物... 之類的單字,組合成字典,並且用字典的內容組合出可能的密碼,如:`dog1234`, `cake19920214` ...之類的,逐一猜測,大部分的人設定密碼的習慣會容易被猜中 44 | 45 | ### 查表法以及彩虹表攻擊 46 | 47 | 針對單一的 hash 方式,可以產生 table,即:`000` 一直到 `ZZZZZZZZZZZZ` 的 hash 結果,想要知道某個 hash 對應的原文,只要使用查表的方式就可以很有效率的還原出原文,像是單層 `md5` 之類的就有很多網站可以查詢,而目前的 `md5` 解密網站服務都是採用這種方式進行 48 | 49 | 由於建表查詢的方式非常浪費空間,因此有人提出了 rainbow table 的概念,先有一個起始點,算出 hash 後,傳入一個 reduction function 進行運算,得到下一個明文,重複這個過程,會使得整個 table 變小很多。 50 | 51 | [![Rainbow Table](assets/001/rainbow-table.svg)](https://wikimedia.org/api/rest_v1/media/math/render/svg/609e4ea6eac3f25b5982f3c9c6ccdaead642540d) 52 | 53 | ### 如何防禦 54 | 55 | 最簡單的方法叫做 **加鹽** (salt) ,即對於每次 hash 都產生一組亂數資料,與密碼放在一起 hash,如此一來假設密碼至少 12 位,加上 16 位的 hash,你需要產生 28 位長度的彩虹表才能夠還原出一定程度的資料 56 | 57 | 有效的防禦,就是讓攻擊者的成本變高,所以可以採用 strong hash,讓運算時間變長,如果計算一次 hash 需要 0.3 秒,計算出所有八位英數大小寫組合的密碼 hash 就需要 700 萬年的時間(假設你只用一個 CPU 和一台電腦的狀況下),就算你用一百台電腦同時進行運算,也需要至少 7 萬年的時間才能夠完成整個彩虹表,如此一來就能夠讓攻擊成本過高,讓壞人打消念頭 58 | 59 | 因此,對於密碼的儲存應該採用: 60 | 61 | 1. strong hash 62 | 2. 加鹽 63 | 64 | 兩種保護措施,很幸運的,現代密碼 hash 函式庫都幫你做完以上兩件事情,選用 `scrypt`, `bcrypt`, `pbkdf2` 之類的密碼專用 hash 就可以保護好你的會員囉! 65 | 66 | ## 針對雜湊的攻擊 67 | 68 | 最著名的問題應該是 [Length Extension Attack](https://en.wikipedia.org/wiki/Length_extension_attack),這個問題主要是在說,當你知道部分資料以及他的 hash,可以在資料最後面新增任意資料,並且計算出新的 hash 值,這個問題在 `crc32`, `md5`, `sha1`, `sha256` ... 等 hash 上面都存在。 69 | 70 | ``` 71 | hash([xxxxx] [data you know]) == 0x12345678 72 | hash([xxxxx] [data you know] [something brand new]) == extense([something brand new], 0x12345678) == 0x56781234 73 | ``` 74 | 75 | ## 加密、編碼、雜湊的差異 76 | 77 | - 加密(encrypt)後的內容(ciphertext)可以解密,還原出明文(plaintext),過程中需要秘鑰(key)來保護明文 78 | - 編碼(encode)是指採用不同的方式來表示資料,常見的編碼方式如:base64,對於有經驗的程式設計師或是駭客來說,看一眼馬上就能夠辨識出來編碼方式,並且實作方式基本上是每個人都知道該怎麼進行轉換,解碼後就可以還原出原始資料,過程中沒有秘鑰的存在 79 | - 雜湊(hash)是把資料濃縮,計算出雜湊值(hash value),基本上沒有辦法還原出明文,因為有可能存在多個資料可以算出同一個 hash 的狀況 80 | 81 | ## 下週預告 82 | 83 | - 什麼是資訊安全三要素(CIA) 84 | 85 | --- 86 | 87 | 這篇文章以 [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/tw/) 授權釋出 88 | -------------------------------------------------------------------------------- /003-201607-4.HTTP.md: -------------------------------------------------------------------------------- 1 | # HTTP 2 | 3 | Author: Inndy < inndy [dot] tw [at] gmail [dot] com > 4 | 5 | Date: 2016/07/31 6 | 7 | ## 前言 8 | 9 | 在閱讀這篇文章之前,你最好具有一點 socket 的知識,以及一點點的網站後端經驗(PHP, Django, Rails, Express.js)。 10 | 11 | HTTP (HyperText Transfer Protocol,請注意,`HTTP 協定`是一個錯誤的說法,後面的協定跟 P 都是指 Protocol),是一個你每天都在用的東西,就算不打開瀏覽器,現代 App 的設計大多都是基於 HTTP 和伺服器溝通的,包含了 Facebook, LINE, Plurk, Twitter, Google, Instagram, Slack...都是。大家都想要學習如何寫網站,但是你是否曾經想要了解,一個網站從頭到腳是如何運作的呢? 12 | 13 | ## 介紹 14 | 15 | HTTP 最早起緣於 [CERN](https://home.cern/) 內部的一個實驗性 project,原本想要建立一個在網路內資料交換的媒介,後來在 1989 年由 Tim Berners-Lee 寫了[地球上第一個瀏覽器](http://info.cern.ch/NextBrowser.html),~~自此開啟了大 WWW 時代~~。 16 | 17 | 最早的 WWW 並不像現在的網站具備有這麼多的功能,登入系統、酷炫的互動特效通通不存在,更不用提可以在網頁上看影片之類的事情,當初只是一個資料檢索的媒介(HTTP/0.9),到後來發展出 HTTP/1.0 ,開始可以傳送表單資料(留言板、會員登入、論壇...這種需要傳送資料的功能),不過這時候還沒有很好的標準化,一直到大約2007年左右,HTTP/1.1 規格制定完成,成為了大家現在用量最大的版本,並且已經有大量的標準化文件(RFC)可以參考,並且從這時候開始支援多種 HTTP 動詞(如:`DELETE`, `PUT`, `PATCH`...)。 18 | 19 | 從前幾年 Google 提出的 SPDY 標準,演化出了 HTTP/2 標準,現代主流的網頁伺服器(Apache, Nginx, IIS)與主流瀏覽器(Chrome, Firefox, Opera, IE11, Edge...)都已經支援了,對於 HTTP 標頭改採 binary 格式,並且具有多工 (Multiplexing) 以及主動推送的功能,能夠讓效率有所提升。 20 | 21 | ## HTTP 長什麼樣子? 22 | 23 | 讓我們來看一個最簡潔的例子,請注意,每個請求(request)最後面會多一個換行作為標頭(header)的截止標示 24 | 25 | ``` 26 | GET / HTTP/1.1 27 | Host: google.com 28 | 29 | 30 | ``` 31 | 32 | 若以 C-Style string 的表示方式: 33 | 34 | ``` c 35 | "GET / HTTP/1.1\r\nHost: google.com\r\n\r\n" 36 | ``` 37 | 38 | 如果把這些內容,透過 [netcat](https://en.wikipedia.org/wiki/Netcat) 傳送到 google.com 的 80 port,就會收到回應(response) 39 | 40 | ``` 41 | $ echo -e "GET / HTTP/1.1\r\nHost: google.com\r\n\r\n" | nc google.com 80 42 | HTTP/1.1 302 Found 43 | Cache-Control: private 44 | Content-Type: text/html; charset=UTF-8 45 | Location: http://www.google.com.tw/?gfe_rd=cr&ei=7BaeV77FLs6B0ASl-aiQAw 46 | Content-Length: 262 47 | Date: Sun, 31 Jul 2016 15:19:08 GMT 48 | 49 | 50 | 302 Moved 51 |

302 Moved

52 | The document has moved 53 | here. 54 | 55 | ``` 56 | 57 | 上面這些內容就是一個 http response 的樣子,基本上分成兩個部分:標頭(header)與內文(body),中間由兩個換行分隔(`"\r\n\r\n"` 或是 `"\n\n"`) 58 | 59 | 整個 response 的第一行可以拆成三個部分:版本、狀態碼、狀態敘述 60 | 61 | `HTTP/1.1`, `302`, `Found` 62 | 63 | 狀態碼相關資料可以在 [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) 上面找到,相信大家一定都知道 `404 Not Found` 或是 `500 Internal Server Error`,因為他們最常在網站出錯的時候看到,至於沒有任何問題,正常返回網頁內容的狀態碼會是 `200 OK`,至於這裡的 `302 Found` 則是告訴瀏覽器,要跳轉到下一個網址去,基本上[縮網址服務](https://en.wikipedia.org/wiki/URL_shortening)大多都是透過這種方式帶你的瀏覽器到真正的目標的。 64 | 65 | 對於狀態碼我們就不多敘述,如果有興趣的話可以自己去看看 MDN 的資料。 66 | 67 | ## HTTP 動詞 68 | 69 | HTTP verb,用以區分不同意圖的 request,像是在剛剛的範例中我們使用了 `GET` 這個 HTTP verb,通常是用於單純的下載、請求資料,如果是登入或是留言板之類的地方會使用 `POST` 這個動詞比較多。 70 | 71 | 在 [`RESTful API design`](https://ihower.tw/blog/archives/1542) 中,會用到其他的 HTTP verb,如:`PATCH`, `DELETE`, `PUT` 等。 72 | 73 | 另外還有兩個特殊的 HTTP verb:`TRACE`, `HEAD` 74 | 75 | ### 常見 HTTP verb 說明 76 | 77 | | HTTP verb | 說明 | 78 | | --------- | --- | 79 | | GET | 下載或取得資料 | 80 | | POST | 最常見的表單 (web form) 資料傳輸會使用的方式 / RESTful API 創造新的資源 | 81 | | PUT | RESTful API 更新一個資源 | 82 | | PATCH | RESTful API 更新一個資源部分的資料時 | 83 | | DELETE | RESTful API ~~你猜猜看啊~~ 刪除一個資源 | 84 | | TRACE | Apache web server 除錯用途,他會把你送出去的 HTTP header 當作 body 回傳給你 | 85 | | HEAD | 要求伺服器只需回應 HTTP header,不要 body | 86 | 87 | ## 下集預告 88 | 89 | - HTTP POST 範例 90 | - URL Encode 91 | - 常見的 HTTP header 解釋 92 | - RESTful API 93 | - 自己用 Python 寫一個 HTTP client 94 | 95 | --- 96 | 97 | 這篇文章以 [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/tw/) 授權釋出 98 | -------------------------------------------------------------------------------- /004-201608-5.HTTP-II.md: -------------------------------------------------------------------------------- 1 | # HTTP (續) 2 | 3 | Author: Inndy < inndy [dot] tw [at] gmail [dot] com > 4 | 5 | Date: 2016/08/07 6 | 7 | ## URL Encode 8 | 9 | ![URL Encode Sample](assets/004/google-url-encode.png) 10 | 11 | 不知道大家是否曾經注意過,使用 Google 搜尋的時候會在網址列上面看到你輸入的關鍵字,但是跟我們輸入的資料好像有點差異? 12 | 13 | 這是因為如果你輸入的資料不在 ASCII 定義的範圍內,甚至是包含了換行 `"\r\n"`,那可能會導致 HTTP request 整個壞掉,所以必須要經過某種編碼處理,讓那些怪怪的字元轉換成 ASCII 範圍內的表示方式。 14 | 15 | 轉換規則大概是這樣: 16 | 17 | 1. 如果是英文、數字、以及部分的符號(`"-_.~"` 之類的)不轉換 18 | 2. 其餘的資料以 UTF-8 (也可以是其他 text encoding,但是現在 UTF-8 是主流)編碼後,每個 byte 如果不再 (1) 的白名單上,則換成 `%FF`(其中 FF 的部分為該 byte 轉成十六進位,且補零至兩位) 19 | 20 | 並且在實作上有個特例,瀏覽器會把空白字元轉成 `"+"` ,但是也可以根據第二規則把空白(ASCII = 32, 0x20) 換成 `"%20"` 21 | 22 | ## 參數的傳遞 23 | 24 | 在 HTTP 中,有三個地方可以塞資料傳給伺服器,分別是: 25 | 26 | 1. GET 參數(網址後面以 `"?"` 分隔,問號之後的資料都是 GET 參數) 27 | 2. Request body (POST body) 28 | 3. Header(通常自定義的 Header 都會以 `X-` 開頭) 29 | 30 | 以剛剛的例子來說,Google 搜尋會把關鍵字放在 GET 參數的 `q` 裡面,例如:[`https://www.google.com/search?q=url+encode`](https://www.google.com/search?q=url+encode) 31 | 32 | ## HTTP Post 範例 33 | 34 | 這是一個從 Firefox 瀏覽器發出的 HTTP Post 範例: 35 | 36 | ``` 37 | POST /data HTTP/1.1 38 | Host: 127.0.0.1:9999 39 | User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:47.0) Gecko/20100101 Firefox/47.0 40 | Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 41 | Accept-Language: en-US,en;q=0.5 42 | Accept-Encoding: gzip, deflate 43 | DNT: 1 44 | Connection: keep-alive 45 | Content-Type: application/x-www-form-urlencoded 46 | Content-Length: 80 47 | 48 | A=%E6%B8%AC%E8%A9%A6&B=Hello&C=%5E____%5E%21%21...%20%26____%26%20..%20%23___%23 49 | ``` 50 | 51 | 其中的重點大概有這幾個: 52 | 53 | ``` 54 | POST /data HTTP/1.1 55 | ``` 56 | 57 | 首先 `POST` 是 HTTP method (verb),表示我們要使用 HTTP request body 傳送資料,目標的路徑是 `/data`。 58 | 59 | ``` 60 | Content-Type: application/x-www-form-urlencoded 61 | Content-Length: 80 62 | ``` 63 | 64 | `Content-Type: application/x-www-form-urlencoded` 表示 request body 的格式是 `key=value&key2=value2` 的格式,並且經過 url encode 轉換處理,`Content-Length: 80` 表示在 `"\r\n\r\n"` 的分隔之後的 request body 有 80 bytes。 65 | 66 | ``` 67 | A=%E6%B8%AC%E8%A9%A6&B=Hello&C=%5E____%5E%21%21...%20%26____%26%20..%20%23___%23 68 | ``` 69 | 70 | 經過解碼後可以得到內容是: 71 | 72 | ``` 73 | A: 測試 74 | B: Hello 75 | C: ^____^!!... &____& .. #___# 76 | ``` 77 | 78 | ## 常見的 HTTP Header 79 | 80 | ### `Connection: Keep-alive` 81 | 82 | request 放這個 header 表示告訴伺服器請重複使用同一個 tcp connection,節省 tcp handshake 的時間,如果 server 也支援重複利用 tcp connection 的話,也會在 response 中回應同樣的 header,相對的是 `Connection: close`,如果其中任何一方送出了這個 header,表示他不支援重複使用 tcp connection,對方就只能關掉連線 83 | 84 | ### `User-Agent` 85 | 86 | 內容包含了瀏覽器類型、版本、作業系統等資訊,可以從這裡看出來你用的瀏覽器是什麼,是哪個版本,用什麼作業系統、作業系統的版本 87 | 88 | ### `Host` 89 | 90 | 現在的 http server 幾乎都支援,在同一台機器同一個 IP 上放多個網站,並且根據連線時用的 domain name 給出不同的內容 91 | 92 | 舉例來說,`facebook.com` / `fb.com` 兩個 domain 可能會在同一台機器上(`66.220.146.36`): 93 | 94 | ``` 95 | inndy ~$ nslookup fb.com 96 | Server: 8.8.8.8 97 | Address: 8.8.8.8#53 98 | 99 | Non-authoritative answer: 100 | Name: fb.com 101 | Address: 66.220.146.36 102 | 103 | inndy ~$ nslookup facebook.com 104 | Server: 8.8.8.8 105 | Address: 8.8.8.8#53 106 | 107 | Non-authoritative answer: 108 | Name: facebook.com 109 | Address: 66.220.146.36 110 | ``` 111 | 112 | ### `Referer` 113 | 114 | 這個 header 可能會包含在 HTTP request 裡面,內容是「來源網頁的網址」,例如你在 Google 首頁點了 Gmail 的連結,那麼 gmail.com 的 HTTP request 中就會包含 `Referer: https://www.google.com` 115 | 116 | ### `Content-Type` 117 | 118 | 表示 request body / response body 中的內容是什麼格式,例如普通的網頁會在 response header 中放 `Content-Type: text/html`,png 圖片會是: `Content-Type: image/png`,這種格式表示方式叫做 [`MIME type`](https://en.wikipedia.org/wiki/Media_type) 119 | 120 | ### `Location` 121 | 122 | 這個 header 會出現在 HTTP response 中,表示要進行轉址,`Location` 的內容是要跳轉到的網址 123 | 124 | ## 用 Python 寫一個 HTTP client 125 | 126 | [Source Code](assets/004/http.py) 127 | 128 | ## 附錄:Web Architecture 129 | 130 | 這是我之前講課用的簡報,簡單介紹了一個網站從 front-end 到 back-end 的結構:[Web Architecture](https://speakerdeck.com/inndy/web-architecture) 131 | 132 | ## /dev/null 133 | 134 | 我真的沒有遲交喔,Las Vegas 現在的時間是 8/7 早上十點 XDDDD 135 | 136 | ## 下集預告 137 | 138 | (nil) 139 | 140 | --- 141 | 142 | 這篇文章以 [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/tw/) 授權釋出 143 | -------------------------------------------------------------------------------- /005-SQL-Injection.md: -------------------------------------------------------------------------------- 1 | # SQL Injection 2 | 3 | Author: Inndy < inndy [dot] tw [at] gmail [dot] com > 4 | 5 | Date: 2016/08/04 6 | 7 | ## 開始之前 8 | 9 | 現代的網站提供了各式各樣精彩的服務,並且大多數的網站都需要在伺服器上面保存一些資料,這些資料除了圖片、影片、壓縮檔...之類的附件素材之外,諸如使用者資訊、文章內容、交易資料...等,通常會放在資料庫內保存,今天要介紹的是針對資料庫的攻擊。 10 | 11 | **以下內容僅供學習研究用途,請勿用於非法入侵。** 12 | 13 | ## SQL 是什麼? 14 | 15 | Structured Query Language,一種用來跟關聯式資料庫(relational database)溝通的語言,可以在資料庫裡面查詢、新增、修改、刪除資料,也可以對資料庫進行管理。 16 | 17 | 如果我想要查詢使用者的資料,我可能會對資料庫下以下的 SQL: 18 | 19 | ```sql 20 | SELECT * FROM `users`; 21 | ``` 22 | 23 | 使用大寫是寫 SQL 時的一個慣例,屬於 SQL 保留字的部分採用大寫,其餘開發者自行命名的部分通常採用小寫。這個 SQL 會告訴資料庫,我想要讀取 `users` 這個資料表的內容,並且把所有的東西都讀出來給我。 24 | 25 | 讀到這裡,如果你還看不懂下面的東西,你可以先參考這些東西去補充一些相關知識。 26 | 27 | ## Injection? 28 | 29 | 當你看到 Injection 這個字的時候,就表示某個使用者在某個地方操作時,輸入的資料未經過檢查就被放進了某些地方執行,而使用者可以用某種方式「結束資料表示區段」,例如 Python 使用單引號或者雙引號表示一個字串,如果你輸入的使用者名稱會經由註冊程式,被寫入一個 Python script 檔案然後執行,當你輸入 `Inndy` 時,會產生以下內容: 30 | 31 | ```python 32 | from time import time 33 | 34 | with open("users-list.html", "a") as f: 35 | f.write("Name: Inndy\n") 36 | f.write("Register time: " + str(time()) + "\n") 37 | ``` 38 | 39 | 那麼如果我輸入了:`" + open("../super-secret.txt").read() + "`,最後註冊程式就會執行: 40 | 41 | ```python 42 | from time import time 43 | 44 | with open("users-list.html", "a") as f: 45 | f.write("Name: " + open("../super-secret.txt").read() + "\n") 46 | f.write("Register time: " + str(time()) + "\n") 47 | ``` 48 | 49 | 接著你就可以在使用者列表上的網頁上看到 `super-secret.txt` 的內容了 50 | 51 | ## SQL Injection 是什麼? 52 | 53 | 現今網站以 PHP + MySQL 為大宗,所以以下舉例就是這個組合。 54 | 55 | 資料表 `users`: 56 | 57 | - id -> int, auto_increment 58 | - name -> varchar(255), not null 59 | - password -> char(40), not null 60 | - 不良示範,密碼請使用更強的雜湊演算法,[詳情請見這裡](000-201607-1.不要儲存明文密碼.md) 61 | - is_admin -> int 62 | 63 | 考慮以下程式碼: 64 | 65 | ```php 66 | 0) 71 | return $user[0]; 72 | else 73 | return false; 74 | } 75 | 76 | $user = login($_POST['user'], $_POST['pass']); 77 | if ($user !== false) { 78 | echo "登入成功:" . $user['name']; 79 | if ($user['is_admin']) { 80 | echo "\n你是網站管理員"; 81 | } 82 | } else { 83 | echo "登入失敗!"; 84 | } 85 | ``` 86 | 87 | 如果我們想要在不知道帳號密碼的狀況下登入這個系統,那麼我們可以輸入 `name` = `' or 1 = 1 --` 而密碼隨意,那麼 SQL 語句組合後就會變成 88 | 89 | ```sql 90 | SELECT * FROM `users` WHERE `name` = '' or 1 = 1 --' AND `password` = SHA1('123123123') 91 | ``` 92 | 93 | 你可以看到第一個單引號結束了這個字串,而 `--` 是 MySQL 的註解,接著這個 SQL 語句就變成了無論如何都會成立的檢查。 94 | 95 | 到這裡,你應該知道了要如何利用 SQL Injection 繞過檢查,對於真實環境的攻擊(或黑箱安全測試),你要猜測網站內的 SQL 語句是怎麼寫的,注入點在什麼地方,可能用的是雙引號字串,或者數字的欄位根本沒有用引號,有可能有括號,也有可能有多個括號,猜到了才有辦法進行攻擊。 96 | 97 | 總結一下攻擊步驟: 98 | 99 | 1. 猜 SQL 語句結構 100 | 2. 關閉字串並且補上括號結尾 101 | 3. DO EVERYTHING YOU WANT 102 | 4. 用註解使後面的 SQL 語句失去作用(不一定需要) 103 | 104 | ## 其他的攻擊方式 105 | 106 | 剛剛我示範了如何繞過登入檢查,現在我們來講講其他攻擊方式,讓你可以從資料庫的其他地方撈出資料。 107 | 108 | ### UNION Based 109 | 110 | 如果是 `SELECT` 語句的狀況下,可以用 `UNION SELECT` 的方式,偽造結果或者是讀取其他資料表的內容。 111 | 112 | 如: `' UNION SELECT 1, 'QQ', '', 1 --` 這組攻擊可以讓你登入,並且使用者名稱是 `QQ`,並且具有管理員權限。當然你也可以讀取別的資料表。 113 | 114 | ### Error Message Based 115 | 116 | 有些天真的開發者把資料庫回傳的錯誤訊息給直接印出來了,正確的做法是把任何的錯誤訊息給寫入檔案或是資料庫記錄下來,印出來給使用者會發生不好的事。MySQL 可以利用錯誤訊息把資料給帶出來。 117 | 118 | [這裡有個例子](https://www.notsosecure.com/mysql-exploitation-with-error-messages/) 119 | 120 | ### Boolean Based 121 | 122 | 沒有錯誤訊息,但是可以判斷 SQL 語句執行成功或否(例如:無法登入、顯示操作失敗的訊息)的狀況下,可以一次洩漏一個 bit 的資料,對於數字可以做 binary search,對於文字資料可以一次洩漏一個 bit 慢慢拼出來。 123 | 124 | ### Time Based 125 | 126 | 連錯誤訊息都沒有,無從判斷 SQL 成功與否,那麼可以做的事情是[旁道攻擊](https://en.wikipedia.org/wiki/Side-channel_attack),網站通常會等待 SQL 執行完成後才繼續,所以我們可以讓 SQL 執行久一點的方式來洩漏資料,接下來的攻擊方式就跟 Boolean Based 一樣。 127 | 128 | 邏輯大概如下: 129 | 130 | ```python 131 | if bits(data)[0] == 1: 132 | delay(10) 133 | else: 134 | return 135 | ``` 136 | 137 | 如果發現這個 HTTP 請求過了很久才返回,那就表示被延遲了,藉此讀取資料。 138 | 139 | ## 自動化攻擊 140 | 141 | - [sqlmap](http://sqlmap.org/) 142 | - [sqlninja](http://sqlninja.sourceforge.net/) 143 | 144 | ## 小試身手 145 | 146 | 有興趣的讀者可以在 [https://github.com/Inndy/super-simple-vulnerable-guestbook](https://github.com/Inndy/super-simple-vulnerable-guestbook) 下載到具有 SQL Injection 漏洞的留言板系統進行測試。 147 | 148 | ## 解決方式 149 | 150 | 1. 使用 ORM,如:[LazyRecord](https://github.com/corneltek/LazyRecord), [Illuminate Database](https://github.com/illuminate/database) (Laravel 的 Eloquent 獨立版本),或是考慮挑一個 PHP Framework 使用內建的 ORM 如 [Laravel](https://laravel.com/) 151 | 2. [mysqli prepared statement](http://php.net/manual/en/mysqli.quickstart.prepared-statements.php) 152 | 3. [PDO with parameter binding](http://php.net/manual/en/pdostatement.bindparam.php) 153 | 4. [mysqli::real\_escape\_string](http://php.net/manual/en/mysqli.real-escape-string.php) 154 | - 不推薦這個方法,需要正確設定文字編碼才有效 155 | - [real\_escape\_string 被繞過的例子](http://stackoverflow.com/questions/5741187/sql-injection-that-gets-around-mysql-real-escape-string) 156 | 5. 先使用[正規表達式](https://zh.wikipedia.org/wiki/正規表達式)檢查資料 157 | - 不推薦這個方法,你寫的正規表達式可能有漏網之魚 158 | 159 | 不論你使用以上任何一種解決方式,切記:自己用字串拼接或是 `sprintf` 組合 SQL 語句,就有可能被攻擊 160 | 161 | ## 下集預告 162 | 163 | (nil) 164 | 165 | --- 166 | 167 | 這篇文章以 [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/tw/) 授權釋出 168 | -------------------------------------------------------------------------------- /assets/004/http.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import warnings 3 | import functools 4 | import socket 5 | import ssl 6 | import urllib.parse 7 | 8 | __version__ = '0.0.1' 9 | 10 | """ 11 | Inndy's simple HTTP client 12 | 13 | A demo for writing a http client. 14 | 15 | [!] This program requires Python/3.5 or higher to run 16 | [!] This client DOES NOT perform a certificate checking, it's vulnerable to 17 | MITM attack, DO NOT USE THIS IN REAL WORLD. 18 | """ 19 | 20 | class SecurityWarning(UserWarning): 21 | pass 22 | 23 | class HTTPResponse(object): 24 | def __init__(self, status_code, headers, content): 25 | self.status_code = status_code 26 | self.headers = headers 27 | self.content = content 28 | 29 | @property 30 | def body(self): 31 | return self.content 32 | 33 | def __repr__(self): 34 | return '' % self.status_code 35 | 36 | def tcp_connect(host, port, use_ssl=False): 37 | soc = socket.socket() 38 | soc.connect((host, port)) 39 | if use_ssl: 40 | warnings.warn('This https client is vulnerable to man-in-the-middle ' + 41 | 'attack because of the lack of certificate checking', 42 | SecurityWarning) 43 | soc = ssl.wrap_socket(soc) 44 | return soc 45 | 46 | def read_all(soc): 47 | data = b'' 48 | while True: 49 | tmp = soc.recv(1000000) 50 | if not tmp: break 51 | data += tmp 52 | return data 53 | 54 | def request(method, url, body=None, headers={}): 55 | # determine protocol (use SSL or not) 56 | if url.startswith('http://'): 57 | ssl = False 58 | url = url[len('http://'):] 59 | elif url.startswith('https://'): 60 | ssl = True 61 | url = url[len('https://'):] 62 | else: 63 | ssl = False 64 | 65 | # determine host and port 66 | if '/' in url: 67 | host, url = url.split('/', 1) 68 | url = '/' + url 69 | else: 70 | host, url = url, '/' 71 | 72 | if ':' in host: 73 | host, port = host.split(':', 1) 74 | port = int(port, 10) 75 | else: # default port is 80 for plain http, 443 for https 76 | host, port = host, 80 if not ssl else 443 77 | 78 | if body and (type(body) is dict or hasattr(body, '__iter__')): 79 | body = urllib.parse.urlencode(body) 80 | 81 | final_header = { 82 | 'Host': '%s:%d' % (host, port) if port != 80 else host, 83 | 'User-Agent': 'inndy/%s' % __version__, 84 | 'Content-Length': len(body) if body else None, 85 | 'Connection': 'close' 86 | } 87 | 88 | final_header.update(headers) 89 | 90 | header = ''.join( 91 | '%s: %s\r\n' % (key, value) 92 | for key, value in final_header.items() 93 | if value 94 | ) 95 | 96 | request_line = '%s %s HTTP/1.1\r\n' % (method, url) 97 | 98 | soc = tcp_connect(host, port, ssl) 99 | soc.sendall(request_line.encode()) 100 | soc.sendall(header.encode()) 101 | soc.sendall(b'\r\n') # end of headers 102 | 103 | if body: 104 | soc.sendall(body if type(body) is bytes else body.encode()) 105 | 106 | response = soc.recv(1000000) 107 | while b'\r\n\r\n' not in response: 108 | data = soc.recv(1000000) 109 | if not data: break 110 | response += data 111 | 112 | print(response) 113 | 114 | status_line, response = response.split(b'\r\n', 1) 115 | response_header, body = response.split(b'\r\n\r\n', 1) 116 | 117 | http_ver, status_code, status_text = status_line.decode().split(maxsplit=2) 118 | status_code = int(status_code, 10) 119 | 120 | response_header = { 121 | key.decode(): value.decode() 122 | for key, value in ( 123 | i.split(b': ', 1) 124 | for i in response_header.split(b'\r\n') 125 | ) 126 | } 127 | 128 | if 'TRANSFER-ENCODING' in ( h.upper() for h in response_header ): 129 | warnings.warn('Transfer-Encoding detected, response body may be wired') 130 | return HTTPResponse(status_code, response_header, body) 131 | 132 | body_length = int(response_header.get('Content-Length', '0'), 10) 133 | if not body_length: 134 | warnings.warn('Can not find `Content-Length` in response headers') 135 | body += read_all(soc) 136 | return HTTPResponse(status_code, response_header, body) 137 | 138 | while len(body) < body_length: 139 | body += soc.recv(1000000) 140 | 141 | return HTTPResponse(status_code, response_header, body[:body_length]) 142 | 143 | get = functools.partial(request, 'GET') 144 | post = functools.partial(request, 'POST') 145 | put = functools.partial(request, 'PUT') 146 | patch = functools.partial(request, 'PATCH') 147 | delete = functools.partial(request, 'DELETE') 148 | 149 | if __name__ == '__main__': 150 | def test(response): 151 | print(response) 152 | print(response.headers) 153 | print(response.content) 154 | 155 | test(get('http://codepad.org')) 156 | test(get('https://google.com/')) 157 | try: 158 | test(post('http://localhost:8000/index.php?a=b', 159 | {'Hello': 'World', '測試': '!@#$'})) 160 | except: 161 | pass 162 | -------------------------------------------------------------------------------- /006-逆向工程簡介.md: -------------------------------------------------------------------------------- 1 | # Intro to RE 2 | 3 | Author: Inndy < inndy [dot] tw [at] gmail [dot] com > 4 | 5 | Date: 2016/08/21 6 | 7 | ## 什麼是逆向工程 8 | 9 | 廣義上的逆向工程 (reverse engineerning) 是指,將一個物品拆解,了解內部構造和運作原理,並且還原出製造方法。但是在這裡,我們談的是電腦軟體的逆向工程,簡單一句話來解釋就是:從 App, exe, elf 回到原始碼的過程。 10 | 11 | 我們知道程式碼經過編譯器的一連串處理後會被轉換成機器語言,包裝成可執行檔,接下來就可以經由作業系統載入,把機器碼放進 CPU 執行起來。逆向工程做的事情是,將機器碼進行反組譯,轉換成人類可讀的組合語言,經過整理後理解這個程式做的事情。 12 | 13 | 除此之外,有些框架、技術會把程式碼轉換成其他的IR(Intermediate Representation,中間碼),IR 在經過直譯器(Interpreter)執行或是即時編譯技術(JIT, Just In Time compilation)在執行時期轉換成機器碼執行,對於這種技術也有逆向工程的存在。 14 | 15 | ## 逆向工程的目的 16 | 17 | - 病毒分析 18 | - 除錯 19 | - 漏洞研究 20 | - 程式安全檢測 21 | - 遊戲外掛 22 | - 軟體驗證破解 23 | - 軟體漏洞攻擊 24 | 25 | ## 警告 26 | 27 | 以下內容含有大量程式碼,如果是看到程式碼容易感到頭暈目眩嘔吐的體質,請自行斟酌是否繼續觀看。 28 | 29 | 建議有 C 語言基礎,了解指標後會比較容易看懂,如果有學過計算機組織更好。(日後會寫一篇指標的介紹) 30 | 31 | ## 組合語言概觀 32 | 33 | 在這裡以最普遍的 x86 CPU(說不定是 ARM 處理器,但是你大概不會想在手機上進行接下來的操作) 來做說明: 34 | 35 | ### 暫存器 36 | 37 | 暫存器可以視為 CPU 內部幾個固定的變數 38 | 39 | | 名稱 | 用途 | 40 | | ---- | ------------------ | 41 | | EAX | function 返回值 | 42 | | EBX | - | 43 | | ECX | - | 44 | | EDX | - | 45 | | ESI | - | 46 | | EDI | - | 47 | | ESP | Stack Pointer | 48 | | EBP | Stack Base Pointer | 49 | | EIP | Program Counter | 50 | 51 | 以上 x86 CPU 的暫存器儲存的內容都是 32 bits (4 bytes) 整數,並且四個通用暫存器(`EAX`, `EBX`, `ECX`, `EDX`)存在有幾個子暫存器,見下圖解釋: 52 | 53 | ![http://www.cs.virginia.edu/~evans/cs216/guides/x86-registers.png](assets/006/x86-registers.png) 54 | 55 | (source: [http://www.cs.virginia.edu/~evans/cs216/guides/x86-registers.png](http://www.cs.virginia.edu/~evans/cs216/guides/x86-registers.png)) 56 | 57 | 假設 `EAX` 暫存器的值是 `0x12345678` 則: 58 | 59 | | 暫存器 | 數值 | 60 | | -------- | ------------ | 61 | | EAX | `0x12345678` | 62 | | AX | `0x5678` | 63 | | AH | `0x56` | 64 | | AL | `0x78` | 65 | 66 | 另外 EIP 的功能是指向現在正在執行的指令。 67 | 68 | ### Hello World 69 | 70 | 程式碼如下: 71 | 72 | ```c 73 | #include 74 | 75 | int main() 76 | { 77 | puts("Hello, World"); 78 | } 79 | ``` 80 | 81 | 使用 llvm 3.8 進行編譯: 82 | 83 | ```sh 84 | clang helloworld.c -m32 -O3 -o helloworld 85 | ``` 86 | 87 | 使用 `objdump` 觀察結果 88 | 89 | ```sh 90 | objdump -d -M intel helloworld 91 | ``` 92 | 93 | 部分輸出擷取,main function 內容如下: 94 | 95 | ```asm 96 | 08048410
: 97 | 8048410: 83 ec 0c sub esp,0xc 98 | 8048413: c7 04 24 b0 84 04 08 mov DWORD PTR [esp],0x80484b0 "Hell, World" 99 | 804841a: e8 c1 fe ff ff call 80482e0 100 | 804841f: 31 c0 xor eax,eax 101 | 8048421: 83 c4 0c add esp,0xc 102 | 8048424: c3 ret 103 | ``` 104 | 105 | 可以看到最左邊的部分是程式執行後,指令所在的記憶體位址,中間的一堆十六進位 byte 則是這個指令對應的機器碼,右邊則是反組譯後的結果。 106 | 107 | ### 常見的指令 108 | 109 | - `add A, B` 110 | - `A += B` 111 | - A 可以是:記憶體(`[eax+8]`, `[0x0804789a]`)、暫存器 (`edx`) 112 | - B 可以是:記憶體、暫存器、常數值 113 | - A, B 不能同時是記憶體 114 | - `sub`, `xor` 類推 115 | - `mov A, B` 116 | - A, B 兩個參數的規則同上 117 | - `A = B` 118 | - `push val` 119 | - val 可以是:記憶體、暫存器、常數值 120 | - `pop target` 121 | - target 可以是:記憶體、暫存器 122 | - `call function ` 123 | - 可以理解為: 124 | 1. `push ` (return address 就是 call 指令的下一個指令所在的位址) 125 | 2. `jmp function` 126 | - 用於呼叫 function 127 | - `ret` 128 | - 簡單解釋:`pop eip` 或是 `add esp, 4; jmp [esp-4]` 129 | - 從 function call 返回 130 | - `jmp addr` 131 | - addr 可以是:記憶體、暫存器、常數值 132 | - 無條件跳躍到該位址 133 | 134 | ### Stack 的運作 135 | 136 | x86 的 stack 會從高位往低位長,例如:Linux 的 stack 預設會放在 `0xffffe000` 這個記憶體位址,經過一連串的 push 操作之後,會變得越來越接近 `0`,並且 `esp` 會指向 stack 的最後一個數值 137 | 138 | ```asm 139 | push 0xaabbccdd 140 | // 此時 *(int*)esp == 0xaabbccdd 141 | pop eax 142 | // 此時 eax == 0xaabbccdd 143 | ``` 144 | 145 | ### Function Call 的運作 146 | 147 | 當你呼叫了一個 function 之後,你會需要 return 到原本的地方往下執行,這時候我們會利用 stack 的特性來做這件事情,當要 call function 的時候就把 return address 給 push 到 stack 上,return 的時候就從 stack 上讀 retrun address。 148 | 149 | 參數的傳遞,也會透過 stack 進行,舉例來說: 150 | 151 | ```c 152 | printf("Number: %d\n", 100); 153 | ``` 154 | 155 | 會被轉換成: 156 | 157 | ```asm 158 | push 100 159 | push str_format ; "Number: %d\n" 160 | call printf 161 | add esp, 8 ; 清掉 stack 上的參數 162 | ``` 163 | 164 | 讓我們來讀個簡單的例子 165 | 166 | ```c 167 | int zero(int v) 168 | { 169 | return v - 1; 170 | } 171 | 172 | int main(int argc, const char *argv[]) 173 | { 174 | return zero(argc); 175 | } 176 | ``` 177 | 178 | ```asm 179 | 080483db : 180 | 80483db: 55 push ebp 181 | 80483dc: 89 e5 mov ebp,esp 182 | 80483de: 8b 45 08 mov eax,DWORD PTR [ebp+0x8] ; arg1 183 | 80483e1: 83 e8 01 sub eax,0x1 ; return arg1 - 1 184 | 80483e4: 5d pop ebp 185 | 80483e5: c3 ret 186 | 187 | 080483e6
: 188 | 80483e6: 55 push ebp 189 | 80483e7: 89 e5 mov ebp,esp 190 | 80483e9: ff 75 08 push DWORD PTR [ebp+0x8] ; arg1 = argc 191 | 80483ec: e8 ea ff ff ff call 80483db ; zero(argc) 192 | ; eax is return value from and also return value for main 193 | 80483f1: 83 c4 04 add esp,0x4 ; 丟掉 arg1 194 | 80483f4: c9 leave 195 | 80483f5: c3 ret 196 | ``` 197 | 198 | ## 下集預告 199 | 200 | - 流程控制 201 | - 迴圈 202 | - Stack Frame 203 | - 數學運算 204 | 205 | --- 206 | 207 | 這篇文章以 [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/tw/) 授權釋出 208 | -------------------------------------------------------------------------------- /assets/001/rainbow-table.svg: -------------------------------------------------------------------------------- 1 | 2 | {\displaystyle {\color {Red}{\mathtt {aaaaaa}}}\,{\xrightarrow[{\;H\;}]{}}\,{\mathtt {281DAF40}}\,{\xrightarrow[{\;R\;}]{}}\,{\mathtt {sgfnyd}}\,{\xrightarrow[{\;H\;}]{}}\,{\mathtt {920ECF10}}\,{\xrightarrow[{\;R\;}]{}}\,{\color {Violet}{\mathtt {kiebgt}}}} 3 | 32 | 180 | --------------------------------------------------------------------------------