├── 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 | [](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 | 
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 | 
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 |
--------------------------------------------------------------------------------