non cai hand
Introduction
EHCTF
Category: Web
Write-up date: 03/03/2025
Question: PHP so suck :(
Point: 269 (nice)
Source code analysis
Vì đề bài không cho quá nhiều thông tin nên chúng ta sẽ lược qua phần phân tích đề bài và chú trọng dến source code. Thông qua source code ta có thể thấy phần so sánh của php được sử dụng là == (Loose Comparison). Vì php là một ngôn ngữ không yêu cầu về kiểu dữ liệu nên một số trường hợp so sánh sẽ tạo ra một lỗi không mong muốn. Lỗi này trong php được gọi là PHP Type Juggling
Dưới đay là bảng so sánh Loose comparison (Điều kiện để sảy ra Type Juggling)

Exploit
Đề bài yêu cầu chúng ta cung cấp 5 param gồm param từ một đến 5
$param1 = $_GET['param1'];
$param2 = $_GET['param2'];
$param3 = $_GET['param3'];
$param4 = $_GET['param4'];
$param5 = $_GET['param5'];
Chúng ta sẽ chia nhỏ thành từng so sánh một cho dễ theo dõi
Checkpoint 1
Nếu param1 != md5($param1) thì trả về giá trị là Try harder
Ở param 1 này, mình sẽ
dùng "Magic Hash", hay còn gọi là
những hash đặc biệt. Những hash này sau khi qua hàm md5() sẽ có giá trị hex là 0e... . Khi đem đi so sánh những string
đặc biệt có ký tự 0e ở đầu, php sẽ coi những sâu đấy là scientific notation và coi chúng là float. Khi đó hai float gần
sấp sỉ nhau so sánh sẽ bằng nhau
Payload 1: param1=0e1137126905 hoặc param1=0e215962017
Checkpoint 2
if (!($param2 !== $param3 && hash('md5', $SALT . $param2) == hash('md5', $SALT . $param3))) {
die('Try more harder!');
}
Đoạn này thì mình không hẳn là dùng bug của type juggling lắm mà mình dùng một unexpected behaviour khác. Khi mà một string concat (.) với một array thì giá trị trả về sẽ là string đó với Array, ví dụ như:
Khi concat như trên, hàm sẽ báo lỗi là Warning: Array to string conversion và trả giá trị aArray. Như vậy chỉ cần
hai array khác nhau thì điều kiện trên sẽ đúng.
Payload 2: param2[]=1 và param3[]=2
Checkpoint 3
if (!(strstr($param4, 'fromehcwithlove') && strlen($param4) == 30)) {
die('Try much more harder!');
}
Checkpoint này đơn giản hơn các checkpoin trên, ở đây chỉ cần đọc hiểu code và làm theo. Param4 cần chứa fromehcwithlove và param4 = 30 ký tự
Payload3: param4=fromehcwithlovefromehcwithlove
Checkpoint 4
Lợi dụng việc strcmp và một số hàm khác khi so sánh với null sẽ trả về int(0) hay false ta có thể điền param là một array rỗng với không phần tử nào và strcmp() sẽ trả về giá trị là 0 và từ đó in ra cho chúng ta flag.
Ở đay có thể thấy $param4 được so sánh với flag qua hàm strcmp() Hàm sẽ trả về giá trị > 0 nếu string1 > string2 và 0 nếu hai string giống nhau. Chúng ta muốn ở đây là một giá trị > 0 nếu string
Payload 3: param5[]=
Sau khi hoàn thành đủ 5 param, chúng ta nhận được giá trị trả về là
Here is your flag: EHCTF{Ju57_aN_3Asy_cHA1LENgE_RlgHt?_3df83c149031}
FLAG: EHCTF{SomeTIme5_EvERy7h1Ng_I5_EA5Y_7Han_y0u_ThlNK_:V_44380a08ef95}