# 網路安全(network security)
[TOC]
## 定義
### <a href = "https://www.ieee.org/">IEEE</a> (Institute of Electrical and Electronics Engineers) 的 paper
一種廣泛的模式,利用不同技術與設備去設定一系列的規則,以確保資料的機密性(Condfidentiality)、完整性(Integrity)、可存取性(Accessibility)。
- Condfidentiality
- 確保資料不能被未授權的攻擊者存取。
- ex. 你的情書不能被其他人想看就看
- Integrity
- 確保資料沒有被攻擊者竄改
- ex. 你的情書不能被改成是喜歡別人
- Accessibility
- 資料是否可以被正常存取
- ex. 你的情書不能因為被別人撕掉就沒辦法正常看
### 抽象
- 對大眾來說,較常見的有網路安全問題的例子有以下
- 帳號被盜用
- 隱私檔案被竊取
- 最近遇到的例子
- 成大工資管的書審上傳系統
- 
## 常見攻擊手法
### 暴力破解(Brute-force attack)
窮舉出所有可能的帳號密碼的字元組合,以找出正確的帳密,通常會利用大量的計算資源以加速計算過程。
通常會用字典檔來更有效率地破解(字典攻擊)
- 字典檔
- 包含一些常見的密碼組合,也可以利用工具(ex. crunch)針對特定的系統製作特定的字典檔
- 常見的字典檔
- rockyou.txt
- kali linux 內建提供,一間做社交軟體的 rockyou 公司因 SQL 漏洞而被駭入而外流的真實用戶的密碼檔
- kali linux:駭客常用的 linux,內含許多攻擊的工具
- 從此密碼檔發現最受使用者青睞的五大懶人密碼依序是 123456, 12345, 12345689, password, iloveyou。統計之後發現,有近 50% 的使用者選用名字、字典中的單字或鍵盤上鄰近的字母作為密碼。
- https://www.ithome.com.tw/node/59281
- https://github.com/brannondorsey/naive-hashcat/releases/download/data/rockyou.txt
- 實作:使用 Metasploit
- Metasploit
- https://www.metasploit.com
- 一個開源的框架,提供多種工具以用來尋找系統漏洞、滲透測試
- 安裝
- `curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall && chmod 755 msfinstall && ./msfinstall`
- 執行
- `msfconsole`
- ssh brute force
- 先來用 nmap 看看要攻擊的目標主機(192.168.67.185)的 ssh 開在哪一個 port
- nmap
- 可以掃描一台主機有哪些 port 是對外開放的
- 安裝
- `sudo apt install nmap`
- 預設掃描的 port : 1-1023
- 常用參數
- -p : 指定掃的 port
- 單個 : `nmap -p 80 192.168.1.1`
- 範圍 : `nmap -p 80-200 192.168.1.1`
- -A : 作業系統與各種服務的版本
- reference
- https://blog.gtwang.org/linux/nmap-command-examples-tutorials/
- 掃描結果
- 
- 可以知道 ssh 可能在其中一個 port
- 選擇 ssh brute force 要用的模組:`use auxiliary/scanner/ssh/ssh_login`
- 查看有哪些必要或非必要的參數要設定:`show options`
- `set stop_on_success true`
- `set verbose true`
- `set user_file /home/s109213059/ssh_burst/user.txt`
- `set pass_file /home/s109213059/ssh_burst/pwd.txt`
- `set rhosts 192.168.67.185`
- `set rport 21042`
- 設定完之後就可以攻擊:`exploit`
- 
### 零時差攻擊(Zero-Day Vulnerability)
利用系統未修補漏洞(vulnerability)的期間,針對漏洞進行攻擊(exploit),可能是因漏洞的補丁(patch)未發行,或是系統管理員沒有及時將系統更新到沒有漏洞的版本。
- 漏洞查詢
- CVE (Common Vulnerabilities and Exposures)
- 由美國非營利組織 MITRE 所屬的 National Cybersecurity FFRDC 所營運維護的資料庫,收集各種資安弱點及造成的漏洞並給予編號以便於搜尋
- 查詢漏洞的 CVE detail : https://www.cvedetails.com
- exploit-db
- 此資料庫中有許多漏洞的實際的攻擊腳本
- https://www.exploit-db.com
- 漏洞種類
- RCE (Remote code Execution)
- 攻擊者在遠端利用系統漏洞執行指令
- ex. 寫入一個 Web Shell 到網頁上
- 小實驗:https://www.exploit-db.com/exploits/50580
- XSS (Cross-Site-Scripting)
- reflected:受害人點擊 url,網頁直接執行 url get 的 query string
- storaged:將 js script 存到 serrver,每個 user 點開 site 就會執行
- 在前後端用套件過濾 user 的輸入
- ex. DOMPurify
- 避免用 innerHTML : 雖然 innerHTML 不會去執行內容的 <script> tag,但可用 button, img 等方式執行 script。但有時候要幫內容加 tag 還是要用 innerHTML
- sol : 用 textContent 過濾再放入使用者內容,再用 innerHTML 加上 html tag
- 實際範例的教學:https://xss-game.appspot.com/level1
- SQL injection
- user 輸入惡意 sql 指令
- 後端寫法:`'select * from users where uid =' + user_id + ' and password =' + user_pwd + ';' `
- user 輸入:`;drop table users;--`
- 直接把 users 這張 table 刪掉
- sol
- 後端執行 sql 時帶入參數用 placeholders
- 限制輸入格式
- regex
- 使用 ORM (Object Relational Mapping) 取代 raw sql
- ORM : 用框架定義好的物件去存取資料庫
- CSRF (Cross-Site Request Forgery)
- 利用社交工程,讓受害者點惡意網站,惡意網站裡面去抓受害者的 cookie,再發 request(可以用 ajax、axios 就不會跳轉,讓受害者無法發現) 到那個 cookie 對應的網站做一些有了受害者權限才能做的事

- ref : https://dotblogs.com.tw/joysdw12/2013/09/16/asp-net-cross-site-request-forgery
- ex. 某個網站的 form 用 get
- https://example.com/delete?id=3
- 防範方法
- 一般使用者
- 不要點奇怪的網站
- 盡量不要保持登入,登入完就登出(清除 cookie)
- server 端
- server 端 check request referer,若不是相同來源就 drop 掉 request
- 
- cors
- 限定 request 的 origin 需是授權的
- 只在 browser 有用,因是 browser 去做判斷是否符合 policy,所以用 postman 之類的直接發送 request 就沒用
- simple request
- method = get, post, head
- 不合 policy,browser 會送出 request 但不把 response data 給 js(但還是會在 server 端執行,所以只用 cors 不夠,還要搭配上面的才安全)
- preflight request
- 觸發條件
- 
- https://vii120.coderbridge.io/2020/11/16/preflight-request/
- method = put, delete
- browser 會先問 server request 是否符合 policy, 符合才送
- 所以會有 2 個 request
- 
- csrf token
- 每個 form 每次新的頁面都會有一組 token,後端會先驗證此 token 是否一致
### 社交工程(Social Engineering)
- 利用人性弱點,應用簡單的溝通和欺騙技倆
- ex.
- 給我帳號密碼,我幫你儲值
- 恭喜你中獎了,點擊這個網站來領獎
- 防範方式
- 多查證,不要輕易地給別人帳號密碼
- 不要亂點網站、檔案
## 得到資源後的用途
當未授權的攻擊者可以隨意存取資料或主機,可以有許多用途
### 勒索
使用對稱式加密加密資料後勒索受害人,須支付一定贖金才能將資料解密
- 預防方式
- 重要資料要備份於其他網路下的裝置
### 挖擴
在受害者的 Server 上植入挖擴軟體,以利用 Server 的資源挖擴賺錢
分享系上主機被植入挖礦病毒:Multios.Coinminer.Miner
- 如何發現
- 系網載入的速度過慢,以及 Server 執行指令速度也很慢
- 利用 `top` 看到某個 process 的 cpu 使用率很高
- 看一下連線狀況(包含開放的連線和<b>對外</b>的連線):`sudo nestat -anpt`
- 
- 持續挖擴(因到某個荷蘭知名的挖擴 ip 的 443 port)
- 查看挖礦的惡意程式 process
- `cd /proc/{pid}` : 查看 process 內容
- `sudo ls -l exe` : 查看執行檔真正位置
- 
- 如何解決
- 利用 `ps` 發現被 temp 執行 3 隻 program
- 
- 
- 
- 都先砍掉 `sudo kill -9 {pid}`
- hacker 使用 temp 這個 user
- 
- 檔案皆為隱藏檔 `.`,要 `ls -a`
- 且被植入後門金鑰
- 
- 先砍掉
- crontab 也有執行惡意腳本排程
```=
5 6 * * 0 /home/temp/.configrc5/a/upd>/dev/null 2>&1
@reboot /home/temp/.configrc5/a/upd>/dev/null 2>&1
5 8 * * 0 /home/temp/.configrc5/b/sync>/dev/null 2>&1
@reboot /home/temp/.configrc5/b/sync>/dev/null 2>&1
0 0 */3 * * /tmp/.X291-unix/.rsync/c/aptitude>/dev/null 2>&1
```
- 先砍掉 : `sudo crontab -e -u temp`
- sol
- 這個病毒滿多人是因為 ssh 破解
- 更新 `temp` 使用者的密碼
- 設定 sshd 的 fail2ban
- 5 次就 ban ip
- ref
- https://askubuntu.com/questions/1224927/cpu-100-with-kswapd0-process-although-no-swap-is-needed
### Mail Server 跳板機
利用受害者的主機和網路資源,大量發送包含惡意網站的連結或是其他垃圾內容的信件。也會造成受害的 Server 的 domain 被列為黑名單,導致正常發送的信件無法正常被接收,以及造成 Server 上的其他正常服務可能無法正常存取
又來分享系上主機遇到的事情:
- 如何發現
- 系網因為 Server 都把資源用在大量寄送郵件而直接無法正常存取,系辦姐姐狂 call(所以我後來自己寫了監控腳本)
- `sudo netstat -anpt` : 有奇怪的 port 有大量流量一直到奇怪的 ip 的 25 port(SMTP)
- 如何解決
- 暫時方法
- `sudo ps aux | grep program_name` : 找到送 mail 的惡意 process,然後 `kill` 掉。
- 但是有其他的 process 監控,所以會馬上自己重建起來繼續送 mail
- 因為資源幾乎全用在傳送大量郵件,導致連下正常指令都須跑很久,所以先用防火牆 drop 掉一些往特定網段的流量
- 根本方法
- 依據 process 找出漏洞
### 網站植入惡意連結
藉由在正常的網站中植入惡意網站的連結,或是會導向惡意網站
分享系網(使用 Wordpress)遇到的事情:
- 如何發現
- 計中通報

- 而且後來發現除了系網以外,其他網站(ex. 系學會網站)也被植入
- 所以我後來有寫一隻腳本檢查有沒有惡意的檔案,因為 Wordpress 中大多是在 `wp-content/uploads` 內被植入
- 如何解決
- 查看 wordpress 使用的套件之中是否有套件的版本在 CVE 當中是有嚴重漏洞的(ex. RCE)
- 都找不到有漏洞的套件,也不太確定是由 Server 中哪個網站的漏洞所造成,所以先將惡意檔案移除後,用 container 將各個網站隔離開來
- 將各個網站隔離開來後,發現只有系網仍會被植入,且在 wordpress 中新安裝的防火牆顯示有被來自奇怪 ip 登入帳號的狀況
- 最後我將 wordpress 設定限制登入失敗的次數,到現在都是正常的
## 攻擊防範方式
### 限制存取
就像上面提到,若沒有限制存取失敗的次數,攻擊者可以藉由暴力破解來找到真正的帳號密碼。且有些服務是不能讓未授權的人存取。
- fail2ban
通過監視系統日誌中的活動以辨識不符合規則的行為,並且將不合規則的 ip 和對應的處理方式寫入防火牆
- 安裝:`sudo apt install fail2ban`
- 啟動:`sudo systemctl start fail2ban`
- 預設保護 sshd
- 開機啟動 : `sudo systemctl enable fail2ban`
- 設定檔 :
- 預設路徑 : `/etc/fail2ban/jail.conf`
- 先複製設定檔成 `jail.local`,因為如果更新 fail2ban,`jail.conf` 的內容會被更新,而且 `jail.local` 會覆蓋 `jail.conf`,所以以後的設定檔就直接去改 `jail.local` 就可以:
- `sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local`
- [DEFAULT] 是所有服務共用的設定,如果是針對特定的服務如 [sshd],若有重疊的部分會直接覆蓋 [DEFAULT] 的。但若要啟用特定服務,要把 enabled = true。
- ex. sshd
```conf=
[DEFAULT]
ignoreip = 127.0.0.1/8 999.999.999.0/24 888.888.888.0/24
[sshd]
enabled = true
port = ssh # 如果 ssh 開在別的 port 這邊要改成改的 port
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
findtime = 600
bantime = 1200
```
- 限制設定 :
- ex. 預設 : 在 10 分鐘內(findtime) 登入失敗次數超過 5 次(maxretry),就 ban 10 分鐘(bantime)

- 沒寫單位是秒,分鐘是 m,小時是 h,天是 d
- 白名單 : 有多個就用空白隔開
```config=
ignoreip = 192.168.56.1 192.168.56.2
```

- filter
- 路徑 : /etc/fail2ban/filter.d
- 用途 : 用來過濾哪一些是此服務失敗的條件(failregex),fail2ban 預設會有各種服務(ex. ssh、nginx)的 filter 檔
- ex. ssh 的過濾條件
- 
- 
- filter 檔的 regex 語法
- 基本語法
- ^ : 比對字串的開始位置
- $ : 比對字串的結束位置
- ? : 問號前的字元可以出現 0 次或一次。
- ex. colou?r = colour、color
- 教學 :
- https://docs.python.org/3/library/re.html
- https://www.cyut.edu.tw/~ckhung/b/re/
- http://it-life.puckwang.com/2016/03/regular-expression.html
- action
- 用途 : 用來決定超過 maxretry 後要採取的行為,預設是只有封鎖 ip
- 寄信 :
- 兩種不同寄信內容
- action_mw : 封鎖後寄信通知
- action_mwl : 信還會含有whois資訊
- 更改 action : `sudo vi /etc/fail2ban/jail.local`
- 
- 更改寄達信箱 : `sudo vi /etc/fail2ban/jail.local`
- 
- 結果
- 
- 查看 fail2ban 管理的項目
`sudo fail2ban-client status`
ex. 目前有 ssh 被管理

- 查看被管理的項目的狀況(包括哪些 ip 被鎖)
- `sudo fail2ban-client status sshd`

- 可以去 /var/log/auth.log 看被登入的狀況(成功和失敗都會記錄)
- 查看被鎖的 ip 和時間(起始到結束) : `sudo fail2ban-client get sshd banip --with-time`
- 手動解鎖 ip :
- 單一 : `sudo fail2ban-client set sshd unbanip x.x.x.x`
- 全部 : `sudo fail2ban-client set sshd unbanip --all`
- 手動增加要封鎖的 ip :
- `sudo fail2ban-client set sshd banip a.a.a.a x.x.x.x`
- 手動調整白名單 :
- 新增 : `sudo fail2ban-client set sshd addignoreip x.x.x.x`
- 刪除 : `sudo fail2ban-client set sshd delignoreip x.x.x.x`
- reference
- [fail2ban-基本設定及安裝筆記 - 鴉哥手札](https://web.archive.org/web/20211231192318/https://crowsnest1217.com/%e5%ad%b8%e7%bf%92%e8%88%87%e5%88%86%e4%ba%ab/fail2ban-setting.html)
- https://newtoypia.blogspot.com/2016/04/fail2ban.html
- https://net.nthu.edu.tw/2009/security:fail2ban
- portSentry
- 介紹
- 因為攻擊者可以用 nmap 之類的軟體掃主機的 port,會暴露主機的一些資訊,ex. 某些 port 可以被掃出來是哪些服務、主機的資訊(ex. os)
所以要對主機是否被掃描做監控,就可以利用這個工具。
- 安裝
- `sudo apt install portsentry`
- 啟動
- `sudo systemctl start portsentry`
- `sudo portsentry -atcp`
- -a : 會檢查主機是否有正在用要檢查的 port,若有就不要監聽該 port
- 設定檔
- path : `/etc/portsentry/portsentry.conf`
- 針對 tcp、udp 的掃描進行動作。
- 
- 0 : 不要限制掃描
- 1 : 限制掃描(通常是用這個)
- 2 : 用自己寫的腳本對掃描進行處置
- 要監聽的 port
- 有在用的 port 不要監聽。ex. 22 80 443
- 基本上用下面這個推薦的就夠了,因為掃描通常是掃描一個範圍,而不是特定 port
- 
- 對於攻擊者如何處理
- 直接用防火牆把該 ip 的封包都 drop掉

- 結果
- 受害者
- 
- 把攻擊 ip 加入 /etc/hosts.deny
- 
- 結果
- 受害者
- 
- 攻擊者
- 
- ignore 檔
- path : `/etc/portsentry/portsentry.ignore.static`
- 因為 `/etc/portsentry/portsentry.ignore` 會因 restart 而刷新,然後會依 static 檔建一個新的
- 新增白名單 ip
- 
- log
- path
- `/var/lib/portsentry/`
- portsentry.blocked.tcp
- 現在 block 的紀錄(會因 restart 而刷新)
- 
- portsentry.blocked.udp
- 現在 block 的紀錄(會因 restart 而刷新)
- portsentry.history
- 過去到目前 block 的紀錄
- 
- refernence
- https://hackmd.io/@ncnu-opensource/B17djyQs8#PortSentry
- ssh
因為 ssh 非常常被使用,所以攻擊非常普遍,因此需要對 ssh 重點防護,畢竟若被攻擊者成功用 ssh login,即使該 user 沒有 root 權限,仍有非常大的機會對 Server 造成嚴重的危害(例如使用 Server 資源挖礦、利用其他方式提升 user 的權限)。
- 更改 ssh port
- 理由
- 預設的 22 port 容易被駭客用暴力破解一直攻擊,雖然有些還是會逐 port 找,但相對較安全
- ex. 一個有對外 ip 的主機開個幾個小時
- ssh port 在 22,基本上都是中國的 ip

- ssh port 在其他 port

- 更改方式
- 決定要換的 port
- 因為有些掃描主機的工具(ex. nmap)預設是掃描 1~1023 比較常用的 port,所以推薦改成 1024~65535。
- 先找找看要換的 port 是不是有在用了
- ex. 要換用 21042 : `sudo netstat -tupln | grep 21042`
- 改成要換的 port
- `sudo vi /etc/ssh/sshd_config`
- OpenSSH server 預設啟動會去讀 `/etc/ssh/sshd_config` 的參數
- 
- 開防火牆 port,我是用 ufw
- 如果還沒開 : `sudo ufw enable`
- 記得加一些會用的 port,ex. 443, 80
- 看一下 : `sudo ufw status`
- 加入新的 ssh 的 port : `sudo ufw allow 21042/tcp`
- `sudo ufw reload`
- `sudo service sshd restart`
- reference
- https://www.cyberciti.biz/faq/howto-change-ssh-port-on-linux-or-unix-server/
- https://xenby.com/b/258-%E6%95%99%E5%AD%B8-ufw-%E9%98%B2%E7%81%AB%E7%89%86%E8%A8%AD%E5%AE%9A%E8%BB%9F%E9%AB%94%E6%93%8D%E4%BD%9C%E6%8C%87%E5%8D%97
- 限制 ssh 登入 ip(黑/白名單)
- 一般規則
- 語法
- sshd(其他服務也可):(ip/netmask)
- /etc/hosts.allow : 可通過的 ip
```config=
sshd:163.22.32.0/255.255.255.0 163.22.17.179
```
- /etc/hosts.deny : 要擋掉的 ip
```config=
sshd:ALL
```
- 另一種寫法,都寫在一起
- `sudo vi /etc/hosts.allow`
- 語法
- sshd:(ip/netmask):(allow||deny)
- ex.
- 
- reference
- https://hackmd.io/@ncnu-opensource/B17djyQs8#%E7%99%BC%E7%8F%BE%E5%95%8F%E9%A1%8C%E5%88%86%E6%9E%90-log-
- ssh 取消密碼登入,只能用金鑰
- 理由
- 開著 port 讓別人連總是有風險
- 在本地產生 ssh 金鑰 : `ssh-keygen -t rsa`
- 私鑰(自己留) : `.ssh/id_rsa`
- 公鑰(給別人) : `.ssh/id_rsa.pub`
- 伺服器端加入本地的公鑰 :
- 複製本地的公鑰 : `sudo vi ~/.ssh/id_rsa.pub`
- 貼到伺服器端 :`sudo vi ~/.ssh/authorized_keys`
- 拒絕用密碼登入
- `sudo vi /etc/ssh/sshd_config`
- `PasswordAuthentication no`
- 
- `sudo service ssh restart`
- 結果
- 
- reference
- https://hackmd.io/@ncnu-opensource/book/https%3A%2F%2Fhackmd.io%2F7kiV5QwqT3y7L46EZF8DQQ#%E4%BD%BF%E7%94%A8%E6%86%91%E8%AD%89%E4%BE%86%E9%81%A0%E7%AB%AF%E9%80%A3%E7%B7%9A
### 檢查是否存在惡意程式
藉由即時檢查 Server 中是否有惡意程式、rootkit 在執行,可以降低惡意程式所帶來的損害
- rootkit : 藉由機器上某些服務的漏洞來取得 root 權限的程式,可能藉由改某些程式(ex. `ps`)來隱藏自己
- 如何隱藏
- 如果取得 root 權限,可以藉由載入惡意模組(可以過濾掉特定 pid),重新編譯核心,然後再呼叫惡意模組,輸入要過濾掉的 pid
- reference
- https://github.com/DanielNiv/Process-Hiding-Rootkit
- 若中了的解決方法 : 因 rootkit 善於隱藏,所以最好備份後重灌系統
- rkhunter
- 找 rootkit 方式
- 利用檔案獨有的指紋資料(md5 編碼),rkhunter 一開始會有各種服務的原始的指紋資料,只要檔案有被更動,就會和原本的編碼不一樣。
- md5 : 雜湊,相同內容會得到同一組編碼,不相同內容很大機率不會得到同組編碼
- 
- reference
- https://ithelp.ithome.com.tw/articles/10193762
- 檢查重要二進位檔案的權限 :
- 因為系統實際在執行的是編譯後的二進位檔案,這些通常會是 755 的權限,不能被其他人更改。但 rootkit 為了要方便控制系統,所以可能直接改這些二進位的檔案的權限成 777
- 檢查隱藏檔案(.xxx)
- 
- 檢查有沒有被奇怪的程式占用的 port
- 檢查有沒有特定惡意程式的檔名或目錄
- 安裝
- `sudo apt install rkhunter`
- 執行
- `sudo rkhunter`
- 常用參數
- `--checkall (-c)` : 全系統全部項目都檢測
- `-cronjob` : 用 crontab 自動跑
- ex. 每天 8 點 30 分執行一次
- `30 8 * * * rkhunter --checkall --cronjob`
- `--report-warnings-only` : 只報出有問題的,正常的不顯示
- `--skip-keypress` : 自動執行,不用一部分檢查完再按 enter 才能檢查下一部分
- `--versioncheck` : 用最新版的 rkhunter
- reference
- https://linux.vbird.org/linux_server/others/0420rkhunter.php#whatisrk
### 防火牆
管理主機的網路流量,包含:過濾掉不符合規則的封包、轉送封包到指定的主機
#### iptables
- 介紹
- Linux 上常見的防火牆套件
- 架構
- 由 table、chain、rule 組成
- table 裡有不同 chain,chain 裡有不同 rule,每條 rule 都有一個 target
- table
總共有 5 種 table
- filter : 預設使用的表,用於過濾封包(常用)
- nat : 用於 IP 或 port 轉換(常用)
- mangle : 用於修改封包內容(ex : 改封包 header)
- raw : 用於停止追蹤封包
- security : 用於設定 SELinux 對單個封包或整個連線的處理
- chain
總共有 5 種 chain,不同 chain 代表封包抵達 Server 後的不同時間點
* PREROUTING : 進行路由前 (封包決定要往哪邊走之前)
* INPUT : 要進入主機的封包(封包的目的地 ip 是本地的 Server)
* FORWARD : 轉送的封包
* OUTPUT : 從主機送出的封包
* POSTROUTING : 進行路由後 (封包決定要往哪邊走之後)

- filter
- 過濾封包
- chain : input, output, forward(封包不會進到本機,會馬上被轉送出去)
- nat (network address translation)
- 來源與目的之 IP 或 port 的轉換
- chain : output, prerouting, postrouting

* 外網 IP 的位址數量不夠用 -> 使用內網 IP
* 外網 IP 無法連線內網 IP (找不到) -> NAT 來轉換
* 主要的 NAT 種類有 SNAT、DNAT、MASQUERADE
- SNAT
> Source NAT
> 在路由後(POSTROUTING)將來源 IP 從內網 IP 位址修改為 NAT 主機的外網 IP 位址
##### 情境 : 內網主機(192.168.1.100)要連線到外網(域名 tw.yahoo.com)

1. 來源 192.168.1.100 傳遞封包給NAT主機
2. NAT 發現目的地不是內網,透過路由轉到外網網卡
3. 因為內網和外網不能互通,所以在 POSTROUTING 透過 NAT 把來源 IP 從內網 IP 換成外網 IP ,另外 conntrack 會在 NAT translation table 把這兩個(內網主機和 NAT)來源 IP、port 的對應關係記錄起來,之後回應封包傳回來時就能知道要傳給內網的哪台主機
##### 情境 : 外網(域名tw.yahoo.com)回傳封包給內網主機(192.168.1.100)

4. 來源外網傳遞封包給 NAT 主機
5. NAT 主機收到外網的回應封包後,會分析封包的序號,並比對前面存到 NAT translation table 的資料,就會發現這個封包是內網主機(192.168.1.100)之前傳送出去的,就會透過 PREROUTING 把目的 IP 從外網 IP 改成內網主機的 IP 192.168.1.100
6. 封包會傳送到 192.168.1.2 這個內網網卡,然後再傳送到目的地192.168.1.100 的內網主機(完成連線!)
- MASQUERADE
> 動態 SNAT
* SNAT 是靜態的,必須在 rule 手動設定外網 IP
* 如果網卡的外網 IP 變動,SNAT 就需要手動去修改(很麻煩)
* MASQUERADE 會自己去找對應網卡的 IP 位址,它的外網 IP 是多少來當作 SNAT 的來源 IP
- 缺點是因每次傳送封包都需去找網卡對應的 IP,故速度較慢
- DNAT
> Destination NAT
> 在路由前(PREROUTING)將來自外網訪問的目的 IP 位址從外網 IP 位址修改為內網主機的IP位址,就能讓外網連線到內網的主機
##### 情境 : 外網主機(61.xx.xx.xx)發送請求給 NAT 主機的80 port (對應到內網主機(192.168.1.210) 的 80 port 上的 WWW 服務)

1. 外部主機要連到WWW服務,需要先連到NAT主機上
2. NAT 主機已經有設定要分析 80 port 的封包,所以當它接收到封包後,會用 PREROUTING 將目的 IP 從外網 IP 改成內網 IP,也就變成連線到 192.168.1.210 的 80 port,同時紀錄封包資訊
3. 封包會傳送到 192.168.1.2 這個內網網卡,然後再傳送到目的地192.168.1.210 的 80 port (連線到 WWW 服務!)
4. 之後在回傳封包給外網主機時,會比對前面儲存的封包資訊,把來源 IP 從內網 IP 換成外網 IP,就可以傳送回去了
- 封包在抵達本機後經過的流程
- 
- rule
* 若符合該 rule 就會執行相應的行為,有順序性

> 若符合排在前面的 rule ,就會去執行相應的 action ,通常不會再往下去執行(類似 if , else if)
- 查看 rule
```
sudo ipatables [-t table] -L [-nv --line-numbers]
```
* `-t` : 選擇 table,預設是 filter
* `-L` : 列出 rule
* `-n` : 不把 IP 位址解析成域名,所以速度較快
* `-v` : 列出更多資訊
* `--line-numbers` : 顯示編號

* target : 進行的動作
* prot : 針對的封包使用的協定
* opt : 額外選項說明
* source : 針對的來源 IP
* destination : 針對的目的 IP
- 新增 rule
```
sudo iptables [-t table] [-A or -I] <INPUT, OUTPUT,FORWARD...>\
-j <ACCEPT, DROP, REJECT> [-i -o -p -s -d...]
```
* `-t` : 選擇 table,後面接 table 名稱
* 新增
* `-A` : append,規則加在最後面,後面接 chain 名稱
* `-I` : insert,規則加在最前面,後面接 chain 名稱
* target
* `-j` : jump target,後面接 target
- target
* ACCEPT : 允許
* REJECT : 拒絕,會告知發送者封包被拒絕
* DROP : 丟掉,發送者不會知道
* SNAT : 修改封包來源 IP
* DNAT : 修改封包目的 IP
* MASQUERADE : 動態 SNAT
* LOG : 紀錄連線到 log
* 網卡
* `-i` : in interface,封包從哪個網卡進來
* `-o` : out interface,封包從哪個網卡出去
* IP位址
* `-s` : source address,封包來源IP位址
* `-d` : destination address,封包目的IP位址
* `!` : 可用在 -s 和 -d 之後,表示非該 IP
* 協定
* `-p` : protocol,當封包使用什麼協定(tcp、udp、ICMP...)
* port:當 `-p` 要指定 tcp 或 udp 時才可以使用
* `--sport` : source port,封包來源 port
* `--dport` : destination port,封包目標 port
* 模組
* `-m` : 呼叫系統模組提供其他功能
- ex: conntrack 模組
* 此模組會記錄連線資訊,所以我們可以依此針對不同種類的連線狀態設定不同規則
* NEW : 新建立的連線
* ESTABLISHED : 已建立的連線(雙向都得到回應)
* RELATED : 新的連線,但與已建立的連線相關
- ex. ftp 21 port 先建立連線,20 port 傳送資料
* INVALID : 無法辨認或惡意的連線
* UNTRACKED : 在 raw 表已被關閉追蹤
- policy
* 封包預設處理方式,如果 chain 都沒有符合的 rule 就會執行 policy 的 rule
- 更改 policy
```
sudo iptables [-t table] -P <INPUT, OUTPUT, FORWARD...> <ACCEPT, DROP, ...>
```
* `-t` : 選擇 table
* `-P` : policy , 後面接 [chain] [target]
* 把 filter table 的 INPUT policy 更改為 DROP


* 範例 1:

* iptables 在 http server 主機上,對外網卡是 eth1
* 讓 Good user 可以連線到 http server
```
sudo iptables -A INPUT -i eth1 -s 192.168.0.101 -j ACCEPT
```
* 讓 Bad user 無法連線到 http server
```
sudo iptables -A INPUT -i eth1 -s 192.168.0.102 -j DROP
```
- 範例 2:
自己的 Server 一直幫特定網段(163.22.17.0, netmask = 255.255.255.0)的 Server 挖礦,所以想要先丟棄到該網段的封包
`sudo iptables -I OUTPUT -d 163.22.17.0/24 -j DROP`
- 範例 3:
將連線到 NAT 主機 80 port 的封包的目的地,改成內網主機中 Web Server 的 8080 port
`sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to {Web Server IP}:8080`
- 刪除 rule
* `-D` : Delete,刪除 chain 裡對應編號的 rule
```
sudo iptables [-t table] -D <INPUT,OUTPUT,FORWAED...> <rule 編號>
```
* `-F` : Flush,清除 chain 裡全部的 rule
```
sudo iptables [-t table] -F <INPUT,OUTPUT,FORWARD...>
```
- 儲存 iptables 設定
* iptables 的設定關機就會消失,不會自動保存和載入
* 把設定 save 到檔案裡再 restore 回去
* `iptables-save` 可以輸出 iptables 目前的設定
* `iptables-save > iptables.conf` 把輸出的結果寫入 iptables.conf
* `iptables-restore < iptables.conf` 把 iptables.conf 的內容載入到 iptables
- DMZ
> Demilitarized Zone (非軍事區)
>將內網中要開放的伺服器與沒有要開放的主機分隔開來
>讓外網有限制地存取內網資源
>當 DMZ 被攻擊時,不開放的內網主機是安全的

* 要讓內外網都可以存取服務的主機放在 DMZ,而不對外開放的主機放在 LAN
* 外網、內網可以直接連線到 DMZ,但 DMZ 不能直接連線內網
* 所以當 DMZ 被攻擊時,因為 DMZ 不能直接連線到 LAN ,所以 LAN 還會是安全的
- 練習:firewall 主機的 iptables 設定
共有 firewall、DMZ、LAN 的三台主機
- 外網進來的封包
* 可以連 DMZ
* 將外網連到 Firewall 80 port 的封包,轉送到 Web Server 80 port
```=1
sudo iptables -t nat -A PREROUTING \
-i {外網網卡} -p tcp --dport 80 \
-j DNAT --to {Web Server IP}:80
```
* 同意該封包轉送
```=1
sudo iptables -A FORWARD \
-i {外網網卡} -d {Web Server IP} \
-p tcp --dport 80 -j ACCEPT
```
* 不能連 LAN
* 後面統一設定
- DMZ 發出的封包
* 可以連外網
```=1
sudo iptables -I FORWARD -i {DMZ 網卡} -o {外網網卡} -j ACCEPT
sudo iptables -t nat -I POSTROUTING -o {外網網卡} -j MASQUERADE
```
* 不能連 LAN
* 後面統一設定
- LAN 發出的封包
* 可以連外網
```bash=1
sudo iptables -I FORWARD -i {LAN 網卡} -o {外網網卡} -j ACCEPT
# 出去的封包做 MASQUERADE 在前面已經設過,所以這裡就不用再設定
```
* 可以連 DMZ
* 不限制只能連到 80 port,也允許 ssh 進去等其他功能
```=1
sudo iptables -I FORWARD -i {LAN 網卡} -o {DMZ 網卡} -j ACCEPT
```
- 其他
* 允許轉送已建立或相關的連線
```bash=1
sudo iptables -I FORWARD \
-m conntrack --ctstate "ESTABLISHED,RELATED" \
-j ACCEPT
```
* 拒絕其他進來 Firewall 主機的連線
```=1
sudo iptables -A INPUT -j DROP
```
* 拒絕轉送其他連線
* 要用 `-A` 加在最後面,不然所有轉送的封包都會被 DROP 掉
```=1
sudo iptables -A FORWARD -j DROP
```
- ref
- https://hackmd.io/@ncnu-opensource/book/https%3A%2F%2Fhackmd.io%2FGEFEQU2GQTq36U5Bs6xVfw#iptables
#### ufw
- 介紹
- Uncomplicated Firewall (簡化版 iptables)
- 相比 iptables 在操作上更直覺、簡單,因 ufw 會再幫我們設定 iptables 的規則
- 安裝
- `sudo apt install ufw`
* 查看狀態 : `sudo ufw status`
* 詳細狀態 : `sudo ufw status verbose`
* 啟用 ufw : `sudo ufw enable`
* 關閉 ufw : `sudo ufw disable`
* 重設 ufw : `sudo ufw reset`
- 查看規則
* 顯示目前規則&顯示規則編號(有順序性) : `sudo ufw status numbered`
- 刪除規則
* 刪除第 3 條規則 : `sudo ufw delete 3`
- 預設規則
* 預設允許 : `sudo ufw default allow`
* 預設拒絕 : `sudo ufw default deny`
- 新增規則
* 允許 ssh port : `sudo ufw allow ssh`
* 拒絕 22 port : `sudo ufw deny 22`
* 允許 TCP 6000~6007 port : `sudo ufw allow 6000:6007/tcp`
* 允許 192.168.11.10 的所有連線 : `sudo ufw allow from 192.168.11.10`
* 拒絕 192.168.11.1 ~ 192.168.11.255 的所有連線 : `sudo ufw deny from 192.168.11.0/24`
* 拒絕某 IP 連到某 port : `sudo ufw deny from 192.168.11.7 to any port 22`
- reference
* https://noob.tw/ufw/
* https://zh.wikipedia.org/zh-tw/Uncomplicated_Firewall