[WebSec] Level 17

https://websec.fr/level17/index.php


Information Gathering

Như thường lệ, bước đầu tiên chúng ta ngó xem qua phần giao diện, có chỗ input và button Submit.

Nó yêu cầu mình đoán flag, nên thử nhập đại gì đó, và xem response trả về thế nào. Không có gì đáng chú ý hơn link tới source code.

Challenge cho sẵn luôn source code, chúng qua và để ý đến 2 phần code PHP.

1
2
3
4
5
6
7
8
9
10
11
12
<?php
include "flag.php";

function sleep_rand() { /* I wish php5 had random_int() */
$range = 100000;
$bytes = (int) (log($range, 2) / 8) + 1;
do { /* Side effect: more random cpu cycles wasted ;) */
$rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
} while ($rnd >= $range);
usleep($rnd);
}
?>

Đoạn code trên chỉ là hàm để delay trong quá trình thực thi chương trình. Khi nào gọi lại hàm sleep_rand() thì đoạn xử lí đó sẽ delay.

Thời gian delay lâu hay mau phụ thuộc vào hàm random ở dòng 8. Hàm openssl_random_pseudo_bytes() sẽ tạo ra random string pseudo_bytes từ param $bytes ở dạng binary.

Sau đó hàm bin2hex() sẽ convert binary sang dạng hex. Tiếp theo hàm hexdec() sẽ convert hex sang dạng decemal.

Đại khái là hàm trên cũng không ảnh hương tới challenge nhiều, vì hàm usleep() sẽ delay chương trình với param là micro second. Ví dụ usleep(2000000) thì sẽ delay 2s.


Tiếp đến source code còn lại:

1
2
3
4
5
6
<?php
if (! strcasecmp ($_POST['flag'], $flag))
echo '<div class="alert alert-success">Here is your flag: <mark>' . $flag . '</mark>.</div>';
else
echo '<div class="alert alert-danger">Invalid flag, sorry.</div>';
?>

Quan sát thấy thì đoạn code phía trên sẽ so sánh giá trị của flag khi input từ user vào và giá trị $flag đã assign trong chương trình.

Nhưng để so sánh thì dùng hàm strcasecmp(), điều đáng nói hơn ở đây là dấu chấm thang ở phía trước hàm.

Hàm strcasecmp($str1, $str2) sẽ nhận vào 2 string để so sánh. Kết quả trả về là:

  • > 0: Nếu như $str1 > $str2.
  • < 0: Nếu như $str1 < $str2.
  • = 0: Nếu như $str1 = $str2.

Dấu chấm thang ở phía trước có nghĩa là $str1$str2 bằng nhau.

1
2
if (! strcasecmp ($_POST['flag'], $flag))
if (strcasecpm($_POST['flag'], $flag) == 0)

Hai dòng code trên là tương tự nhau về mặt chức năng và bản chất.

  • So sánh == thì sẽ so sánh giá trị, nếu không cùng kiểu dữ liệu thì sẽ ép về cùng kiểu dữ liệu.
  • So sánh === thì sẽ so sánh cả giá trị và kiểu dữ liệu cùng lúc.

Khi so sánh == thì lại để ý tới lỗi Type Jugling và tham khảo hai hình bên dưới.

Loose

Strict
`


Exploit

Khi mà so sánh trong hàm strcasecpm() sẽ cho ra kết quả là False. Tiếp theo False so với 0 thì sẽ là True.

Debug compare

Từ đó, sẽ tìm ra được flag.

Payload: flag[]=1

Kết quả:

KetQua

References

  1. https://techgeekgalaxy.com/php-equality-comparisons/#:~:text=or%20security%20exploits.-,Strict%20Comparison%20(%3D%3D%3D),types%20then%20false%20is%20returned

  2. https://danuxx.blogspot.com/2013/03/unauthorized-access-bypassing-php-strcmp.html


[WebSec] Level 17
https://dovankha.github.io/2022/07/24/lv17/
Author
Khado
Posted on
July 24, 2022
Licensed under