# OSWE (WEB-300: Advanced Web Attacks and Exploitation) 考試紀錄 (2023/11) ## 學習過程 - 基本上OWASP TOP 10 裡面的都有涵蓋到 - 可以學會幾項程式語言DEBUG的SOURCE CODE的方法,像是 JAVA、csharp、node js 等平台 - PT實務上好像比較少有機會 CODE REVIEW - 課程整體而言算是蠻有趣的,第6、11、12、13章節在工作上有遇到類似的案例所以特別有興趣 - 想想這種考題對 CTF 是打 WEB 的非常友善,還提供 SOURCE CODE - 基本上學習完這些遠遠還不夠,只能說算是一個起點,WEB的世界變化的太快,只能不斷的去適應新的框架和打法 - 考題算是難度適中,但課程裡面我覺得最難的應該還是和 JavaScript Prototype 相關的 - 工作關係 LAB 時間不足,所以只好再延後一個月 Q_Q - 考試時間盡量選和自己作息接近的時間,比較不會太累 ## OSWE 考試紀錄 - 選了早上8點考試,提前15分鐘 (共計 47小時 45分), 用 OSID 跟一組 MD5 hash 值登入監考系統 - 監考是用瀏覽器桌面分享功能,每個螢幕都要 - 半個小時在身份驗證,環境檢查 - 因為我是用 Windows 所以他會要檢查你的process,會跑一組 powershell 並回傳結果 - 上面的驗證都通過後,就會收到官方寄來的郵件,會有考試 vpn 及 vpn 密碼 - 中間休息和考官說要休息,回來的時候也和考官說,基本上和其他Offsec 考試相同 - 第一天 第一題 上午 取得 AuthBypass,晚上取得 RCE 休息8小時睡覺 - 第二天 第二題 上午 取得 AuthBypass,下午取得 RCE,晚上開始寫報告,晚上12點提前結束考試-睡覺 - 第三天 整理報告,中午報告交出 ## 考試環境 - 考試共有五台機器 - Kali 可用來編寫 PoC,但我沒有用,比較習慣在自己機器上做 - 兩台 debugger 提供帳密 - 兩台和 debugger 一樣的機器並提供 source code 模擬 ## 考試回憶 - 要把考試情境描述看完,可以讓你 Code Review 比較有目標,也比較省時 - 課程中的 LAB 算是部分和考題重疊,LAB 一定要做完 - 需要熟練使用binary search 及 多執行續,幫助你在遇到SQL injection 時可以減少執行時間,在VPN 的狀態下差很多。 - 考試前最好要準備你要一鍵SHELL 的框架和function,可以減省不少時間 - 一個好的考試範本筆記也很重要,這次是使用 https://github.com/ret2src/OSCP-Exam-Report-Template-Markdown#docker 有一些東西需要調整 如果你有遇到無法正常產出報告就需要額外在 DOCKER 安裝 xetex 並指定 xetex ,指令 `sudo apt install texlive-xetex` - burp 一定要安裝 [Copy As Python-Requests](https://portswigger.net/bappstore/b324647b6efa4b6a8f346389730df160),不用在自己手刻 request - 熟練 python requests ,session 盡量重複使用、requests.post 的 file 、data 會用到 ## 需要特別注意的-考試禁止事項 - 不能用AI,自動化工具,醒醒吧你! - 題目檔案不能用任何方式下載到你自己的機器 - [exam-restrictions](https://help.offsec.com/hc/en-us/articles/360046869951#exam-restrictions) ## 報告部分截圖 - 基本上寫好的 markdown OSCP-Exam-Report-Template-Markdown#docker 都會自動把格式調整好輸出成PDF - 封面 ![image](https://hackmd.io/_uploads/BkO7hxHE6.png) - 大鋼 ![image](https://hackmd.io/_uploads/BJdshgSE6.png) - 內容 ![image](https://hackmd.io/_uploads/H1TITeS4T.png) ## 考試時使用的一鍵SHELL python 骨架 - 個人是參考了 https://github.com/gh0x0st/OSWE-crawling-through-the-webs/tree/main - 要 debug 看 burp 時確實蠻方便,而且可以標示清楚成功或失敗 ```python import os import argparse import threading from http.server import BaseHTTPRequestHandler,HTTPServer class message (): def __init__ (self): self.red = '\033[91m' self.green = '\033[92m' self.white = '\033[37m' self.yellow = '\033[93m' self.bold = '\033[1m' self.end = '\033[0m' def info (self, message): print(f"[{self.white}*{self.end}] {message}") def warning (self, message): print(f"[{self.yellow}!{self.end}] {message}") def error (self, message): print(f"[{self.red}x{self.end}] {message}") def success (self, message): print(f"[{self.green}✓{self.end}] {self.bold}{message}{self.end}") def run_nc(port): output.info("run nc shell") os.system("/usr/bin/nc -lvvp {}".format(port)) def start_web_server(host,port): class webHandler(BaseHTTPRequestHandler): def do_GET(self): # Get Http if self.path == '/test.js': try: with open('test.js', 'rb') as file: content = file.read() self.send_response(200) #application/javascript; charset=utf-8 self.send_header('Content-type', 'application/javascript; charset=utf-8') self.end_headers() self.wfile.write(content) output.success("XSS Trigger") except FileNotFoundError: self.send_error(404, 'File not found') elif self.path == '/test.txt': try: with open('test.txt', 'rb') as file: content = file.read() self.send_response(200) self.send_header('Content-type', 'text/plain') self.end_headers() self.wfile.write(content) except FileNotFoundError: self.send_error(404, 'File not found') elif self.path.startswith('/test?name='): try: global admin_key admin_key = self.path.split("=")[1] if admin_key: output.success("Get admin Key:" + admin_key) except Exception as e: output.error("Error while fetching admin key: " + str(e)) else: self.send_error(404, 'File not found') httpd = HTTPServer((host, int(port)), webHandler) threading.Thread(target=httpd.serve_forever).start() def writefile(attackerip,httpport): files = f"""""".format(attackerip,httpport) with open("files","w+") as f: f.write(files) def main(): global output output = message() parser = argparse.ArgumentParser() parser.add_argument('-t', '--target', help='Target ip address or hostname', required=True) parser.add_argument('-aip', '--attackerip', help='Listening IP address for reverse shell', required=True) parser.add_argument('-hport', '--httpport', help='Listening port for http', required=True) parser.add_argument('-aport', '--attackerport', help='Listening port for reverse shell', required=True) parser.add_argument('-d', '--debug', help='Instruct our web requests to use our defined proxy', action='store_true', required=False) args = parser.parse_args() global anserip anserip = args.target global proxy_list proxy_list = None if args.debug: for k,v in sorted(vars(args).items()): if k == 'debug': proxy_list = {'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080'} output.warning(f"Debugging Mode: {v}") else: output.info(f"{k}: {v}") if __name__ == '__main__': main() ``` ## 過惹 ![image alt](https://api.accredible.com/v1/frontend/credential_website_embed_image/certificate/86894872) ## 參考連結 - https://blog.stevenyu.tw/2022/11/27/%E5%A6%82%E6%9E%9C%E6%88%91%E8%AA%AA-oswe-%E5%BE%88%E5%A5%BD%E8%80%83%E6%9C%83%E4%B8%8D%E6%9C%83%E6%9C%89%E4%BA%BA%E6%83%B3%E6%89%93%E6%88%91/ - https://medium.com/%E4%BD%95%E5%93%81%E7%B7%AF-hoping-way/vulnhub-securecode-1-bb7a91b58426 - https://portswigger.net/web-security - https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html