# patching matching CBJS ## Giới thiệu: đây là 1 giải bên CBJS với luật chơi ta sẽ được cung cấp 1 source liên quan đến các lỗi SQLI,Path Traversal,SSRF sau đó mỗi team sẽ dùng bản patch được cấp của các thầy để vá cái lỗi đó (mục tiêu là bypath và getflag) **Note:Trong write up có 1 vài ảnh mình có nói chuyện với thầy mục đích là để hiểu thêm về idea của bài và mình chỉ hỏi sau khi mình giải xong** ### SQL Injection phần SQLi tất cả các team đều sài chung 1 patch ![image](https://hackmd.io/_uploads/rJkmaIrBgg.png) đây là bản vá ![image](https://hackmd.io/_uploads/ryw_p8HSxx.png) Untrusted data nằm ở parameter ==name== đây là dạng SQL ở phần ==insert statement== đề filter đi 1 vài hàm, mình khai thác bằng cách dùng hàm ==extractvalue== cụ thể idea là như này nếu ta chú ý thì hàm ==str_replace== sẽ xóa đi cả kí tự ==/*== và ==*/== vậy thì điều gì xảy ra nếu ta khai thác chính phần này để bypass filter vì theo đoạn code hàm patch sẽ sử lý xong mới gọi đến phần ==query== mình bypass filter ==select== bằng cách ==SEL/**/ECT== câu lệnh khai thác của mình sẽ có dạng như này ==1' AND extractvalue(1, concat(0x7e, (SELECT Jutsu FROM ninja_db.scroll LIMIT 0,1))) AND '1'='1== phần này khá là dễ nên là về table và column thì ta chỉ việc dùng select để lấy ra mình sẽ không đi sâu phần này có 1 team họ đã patch bằng cách khác đó là filter đi chữ ==jutsu== ![image](https://hackmd.io/_uploads/HJ9MkPBSxl.png) nhưng vấn đề là hàm ==strpos== này không hề mạnh nếu là dùng ==regex== thì được nên ta chỉ cần thay chữ ==jutsu== thành ==Jutsu== hẹ hẹ ### Path Traversal ![image](https://hackmd.io/_uploads/Hy5_1vHBll.png) cách mình giải phần này khá là funny =)) vì có phần này có 1 team họ dùng bản patch khác những team còn lại nên là mình khai thác từ team đó có 2 bản vá cho phần này ![image](https://hackmd.io/_uploads/BydTkvrBge.png) bản vá này khá khó nên tạm gác lại bản vá đó mình sẽ dùng bản vá của team mà mình khai thác được ![image](https://hackmd.io/_uploads/S1-blwHrge.png) với bản vá số ==7== chỉ filter ./ nhằm tránh việc attacker truyền ../ vào phần patch nhưng vấn đề đây là path traversal khai thác từ serialize nên ta hoàn toàn bypass được ![image](https://hackmd.io/_uploads/Hy5_1vHBll.png) oke tạm gác việc bypass đi ta sẽ nói về idea của việc khai thác path traversal trước để trigger path traversal ta sẽ ép kiểu dữ liệu bằng cách gọi đến hàm ==__toString()== payload khai thác sẽ có dạng như này ``` <?php class Scroll { public $secret; public function __toString() { $path = 'C:/Users/Dell/Desktop/exploit' . $this->secret; echo " read: $path\n"; return file_get_contents($path); } } // object chứa đường dẫn $a = new Scroll(); $a->secret = '/flag.txt'; // object chứa object $b = new Scroll(); $b->secret = $a; $unseal = serialize($b); unserialize($unseal); $result = 'Secret: ' . $b->secret; echo $result . "\n"; ``` Cụ thể, ta chú ý phần == $b->secret ==. Biến $b->secret là một object, và trong đoạn code trước đó, nó đã được gán với object $a, vốn là một instance của class Scroll. Khi thực hiện unserialize(), PHP khôi phục lại object $b, trong đó thuộc tính secret chính là object $a ở phần $result = 'Secret: ' . $b->secret; PHP buộc phải ép $b->secret về kiểu chuỗi để thực hiện phép nối chuỗi (.). Vì $b->secret là một object, PHP sẽ tự động gọi phương thức __toString() của class Scroll. → Từ đó, __toString() được thực thi và payload được trigger. ![image](https://hackmd.io/_uploads/r1cdCvrBgl.png) oke vậy thì ta sẽ dùng idea này để cat phần flag nhưng vấn đề như mình đã nói từ đầu là filter ./ thì không thể path traversal ở phần này được dẫn đến ta sẽ không thể khai thác path traversal bằng cách truyền vào ==$secret== tuy nhiên như đã đề cập nếu là path traversal thì không đây là php serialize nên ta hoàn toàn có thể tạo payload bypass mình tham khảo từ https://github.com/ambionics/phpggc ![image](https://hackmd.io/_uploads/HJzEyuSBle.png) ![image](https://hackmd.io/_uploads/BJBuJuBSeg.png) thật ra bản chỉ cần quan tâm mỗi mỗi phẩn ==Armor Strings== là đủ thay vì dùng s ta có thể sử dụng S bằng cách thay thế payload thành định dạng hex mình để dòng dưới vì đó là cách mình bypass ở phần patch matching 1 lúc filter đi ==O:6== ![image](https://hackmd.io/_uploads/Sy0zlOrSel.png) oke vì phần này không dùng đến nên mình không muốn đi sâu lắm quay lại phần ==Armor Strings== ta sẽ khai thác như mình đề cập bằng cách thay đổi payload thành định dạng ==hex== dùng đoạn code này để tạo ra payload theo dạng ==Armor Strings== ``` <?php function armor_encode($input) { $output = ''; for ($i = 0; $i < strlen($input); $i++) { $output .= sprintf('\\%02x', ord($input[$i])); } return $output; } $secret = 'secret'; $fileread = "../../../../../etc/passwd"; echo "\n" . armor_encode($fileread); echo "\n" . armor_encode($secret); echo "\n" . strlen(($fileread)); // Output: 30 echo "\n" . strlen(($secret)); ?> ``` một vài lưu ý khi khác thác cách này ==Armor Strings== chỉ thay đổi payload bạn qua định dạng hex nhưng không thay đổi đi phần ==length== ví dụ ta có chữ secret là length bằng 6 thì dù có convert qua hex dạng ==\73\65\63\72\65\74== vẫn sẽ là length bằng 6 oke payload chúng ta sẽ có dạng như này ==O:006:"Scroll":1:{S:6:"\73\65\63\72\65\74";O:006:"Scroll":1:{S:6:"\73\65\63\72\65\74";S:30:"\2e\2f\2e\2e\2f\2e\2e\2f\2e\2e\2f\46\4c\41\47\5f\50\41\54\48\5f\54\52\41\56\45\52\53\41\4c";}}== và theo idea này thay vì đọc flag như bth mình đã đọc đoạn code của ==rungtuthan.php== ![image](https://hackmd.io/_uploads/SJPiM_BBle.png) ==Secret: <?php include('./validations/7.php'); ?>== oke vậy là bản vá sẽ ở phần validations/<numberpatch>.php nên mình edit lại payload và đọc bản vá thứ 10 để tìm class ẩn =)) ![image](https://hackmd.io/_uploads/SyvNQdBBlg.png) đây rồi nó tên là ==System== mình đã đi trao đổi với thầy thì thầy bảo là phần này chỉ có thể giải bằng cách ==bruteforce class== nên là cũng có thể nói nếu thay bằng tên class khác như ==dk2== thì chắc là no solve nếu như các team đều sai bản patch 10 giờ biết được class gì rồi ta chỉ cần tạo payload nhằm load class ==System== là get flag phần patch 10 thì quằn ở phần regex mà như thầy nói là không thể bypass nếu đi theo idea trên được ![image](https://hackmd.io/_uploads/BydTkvrBge.png) ![image](https://hackmd.io/_uploads/SyUXHdBBee.png) biết được flag rồi thì mình chỉ cần tạo 1 payload đơn giản và bypass Regex trên thì khá easy vì nó chỉ check ==O:== nên mình tạo array bắt đầu từ ==a== là bypass được cụ thể payload như sau ==a:1:{i:0;O:6:"System":0:{}}== ![image](https://hackmd.io/_uploads/BkojHOrHgg.png) ### SSRF đánh giá đây là phần dễ nhất trong các chall phần filter cũng rất nhẹ có 1 team họ patch hơi kì lạ tí hẹ hẹ mình gọi thẳng localhost lấy luôn flag nên thôi mình đi vào các team đúng patch filter localhost ![image](https://hackmd.io/_uploads/r1TmLOrrel.png) ![image](https://hackmd.io/_uploads/ryTOI_rHgg.png) idea thì như này ![image](https://hackmd.io/_uploads/HkLBDuBBgg.png) ngoài ra bạn có thể thử payload này http://fbi.com/flag.php cụ thể này dns resolve thôi vì có 1 ông nào đó đã mua tên miền fbi.com nên khi gọi đến nó tự gọi local =)) ![image](https://hackmd.io/_uploads/ryi0POBBgx.png) Vậy có cách nào nếu như không phải do team nào đó patch sai và không đọc được path traversal tất nhiên là có vì này có 2 team lận có 1 team patch SSRF gọi thẳng local ta có thể sử dụng thay vì get flag thì get luôn file chúng ta cần đọc ví dụ patch 10 chẳng hạn ==?input=https://team<đã che>-chunin-45ff7393.cyberjutsu-lab.tech/dautruong.php?input=file:///var/www/html/validations/10.php== hehe happy hacking