Итоги и разбор заданий онлайн-тура NeoQUEST-2014

342d1280ad1f68444d5576b9386da85c.jpg Настала пора подвести итоги онлайн-тура NeoQUEST-2014, в том числе: — разобрать все 7 заданий квеста (на каждый день недели!); — поведать о победителях и их наградах; — рассказать, что ждет участников и гостей мероприятия в очном туре NeoQUEST-2014, который пройдет 3 июля в Санкт-Петербурге в Политехническом Университете.О победителях «Золото», «серебро» и «бронзу» онлайн-тура получили AV1ct0r, n0n3me и Dor1s соответственно. Борьба за первое место была очень жаркой, на протяжении трех дней лидер непрерывно менялся — AV1ct0r и n0n3me вырывали друг у друга первое место, и разница между ними составляла всего пару-тройку очков. Но затем AV1ct0r прошел задание про «фальшивый цитрус» и укрепил свое лидерство, оторвавшись на 113 баллов! Мы не можем не отметить волю n0n3me к победе и его несомненный талант (второе по сложности задание квеста он прошел первым). «Бронзовый» призер Dor1s ненамного отстал от второго места, зато реализовал большой отрыв от следующих участников.Поздравляем победителей, их ждут главные призы и очный тур, победа в котором принесет победителю поездку на одну из международных хакерских конференций! AV1ct0r и n0n3m4 награждаются смарт-часами от Samsung и Sony (а вот еще интересный обзор на Хабре) соответственно, а Dor1s получает почти трехкилограммового робота, тоже отнюдь не глупого! Кстати, всех прошедших хотя бы одно задание NeoQUEST-2014 также ждет небольшой приз. Поскольку стандартные идеи памятных сувениров (чашки, блокноты, флешки, ручки, шоколадки и прочее) уже исчерпали себя, наш сувенир крайне удивит участников, но большинство, скорее всего, рано или поздно им воспользуются! Мы связываемся со всеми призерами. Уважаемые участники, проверяйте почту на наличие писем от info@neoquest.ru!

Разбор заданий NeoQUEST-2014 состоял из 7 заданий из различных областей кибербезопасности:1) «Моя твоя не понимать» — reverse engineering приложения на C#;2) «Hasta la vista» — reverse engineering Android-приложения;3) «TimeShift2. Revenge» — временная атака на RSA;4) «Отмороженный компьютер» — получение видеопамяти виртуальной машины из дампа оперативной памяти;5) «Обнаружено неизвестное дымящееся устройство» — анализ дампа синхронизации по USB Android-телефона с компьютером;6) «Игродром» — использование port knocking для игры в Pac-Man;7) «В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!» — задание на reverse engineering, знание технологий обхода DEP и ASLR, основ криптографии и умения эксплуатировать бинарные уязвимости.Задания «Обнаружено неизвестное дымящееся устройство», «Игродром», «В чащах юга жил бы цитрус?» будут детально рассмотрены в майском номере журнала «Хакер». К тому же, наши участники написали достаточное количество writeup’ов, в которых можно почитать, как они прошли то или иное задание. Здесь writeup от AV1ct0r’а, тут — от n0n3m4 и там — от Dor1s.

1 — Моя твоя не понимать В основе задания лежала технология, позволяющая встраивать приложения, написанные на C#, в Интернет-сайты. Возможно это только в том случае, если сайт написан на asp.NET. Правда, и тут есть определенные ограничения. Только Internet Explorer сможет отобразить графическую оболочку апплета, остальные браузеры могут лишь использовать экспортируемые им функции.Участник квеста из всех исходных данных получал только IP-адрес сайта, при переходе по которому загружалась такая вот страница: 356b89e5c1d294f34a4f612f5e231997.jpg

На странице выводился адрес пользователя, зашедшего на сайт, и еще непонятные иероглифы. Адрес, подсвеченный белым цветом, намекает, что сайту небезразлична локация, из которой пользователь на него заходит.Если ввести выводимые сайтом иероглифы в сервис translate.google.ru, получится вот что:

80409abbbba7e9239d3e08d202f8b32b.jpg

Сервис автоматически определил язык как вьетнамский, это должно натолкнуть участника квеста на мысль о том, что стоит попробовать посетить сайт через вьетнамский прокси-сервер. Списки прокси-серверов есть в свободном доступе на многих сайтах, например, тут.Использование вьетнамского прокси-сервера приводит к желаемому результату. Участнику отображается другая версия сайта с заданием:

8860e39ef90b8061a8424f18b598de7c.jpg

Пользователю выводится форма для ввода данных, но что туда нужно ввести? Вот в чем вопрос. Для этого нужно покопаться в исходном коде страницы, тогда обнаруживается такой любопытный кусочек:

548bd1ec286d239ee76a5eef6d981449.jpg

В исходнике страницы в явном виде указан путь к C#-апплету. Но, как уже говорилось выше, он не отображается ни в каких браузерах кроме Internet Explorer. Вот так выглядит сайт в IE при использовании прокси-сервера:

22cb45af711686e15f367fb17462e18a.jpg

Однако на ход выполнение задания отображение графической части апплета не влияет. Кнопки в его интерфейсе не несут никакой полезной нагрузки.Дальнейшая задача участника — изучение исходного кода апплета. Приложения, написанные на языке C# достаточно легко декомпилируются. Например, можно использовать приложение .NET Reflector. Получаем исходный код апплета:

2a250519f60a374285c887c1dd3d651f.jpg

В декомпилированном приложении несложно найти класс с говорящим названием KeyStore. В нем хранится ключ, который необходимо ввести в форму на сайте.К слову, функция проверки ключа реализована так же в апплете. Средствами asp.NET она вызывается и проверяет вводимую информацию на правильность. Этот функционал работает в любом браузере. Задание пройдено!

2 — Hasta la vista В задании участники получали некий файл MyGreenManController.zip, при открытии которого становилось понятно, что это не что иное, как приложение для Android (да, собственно, и название файла подсказывало): bc15c704b127f5486488961cddf34a3e.jpg

Участникам нужно было пореверсить этот файл. Для этого требовалось знать, что представляет собой приложение для операционной системы Android. Это ни что иное, как архив, упакованный zip-ом и имеющий расширение ».apk». В данном архиве содержатся ресурсы приложения, файл AndroidManifest.xml, который определяет права приложения, его имя и т.д., и файл classes.dex. Последний является байт-кодом программы, скомпилированной для виртуальной машины Dalvik, использующейся в Android. Получить из него исходный код на java просто так не получится, однако можно получить набор команд для виртуальной машины — dalvik opcodes. Данный способ не особо пригоден для анализа приложений, поскольку существует другой, более простой и удобный, который заключается в преобразовании dex-файла в jar, который можно декомпилировать и получить вполне читаемый код на java.

Для проведения описанных выше действий потребуется архиватором извлечь из apk-файла файл classes.dex. Далее при помощи утилиты dex2jar перевести его в jar-файл, а затем открыть его в программе jd-gui.Реверсинг сводится к получению файла classes.dex, с использованием утилиты Apk Manager или простого архиватора. Затем, при помощи утилиты dex2jar, получаем файл classes.dex.dex2jar.jar, который очень удобно изучать при помощи программы jd-gui.Входной точкой является класс Code:

public class Code extends Activity { public static String aA = »;

public void onCreate (Bundle paramBundle) { super.onCreate (paramBundle); setContentView (2130837504); TextView localTextView = (TextView)findViewById (2130968577); ((Button)findViewById (2130968578)).setOnClickListener (new View.OnClickListener (localTextView) { public void onClick (View paramView) { Code.aA = Code.this.getApplicationContext ().getFilesDir ().getAbsolutePath (); String str = new AA ().a (this.val$aaa.getText ().toString (), Code.aA); if (str == null) Toast.makeText (Code.this.getApplicationContext (), «Error», 0).show (); do return; while (! str.equals («Correct command»)); Toast.makeText (Code.this.getApplicationContext (), «Correct command», 0).show (); A localA = new A (); try { localA.a ((TelephonyManager)Code.this.getSystemService («phone»)); return; } catch (Exception localException) { localException.printStackTrace (); } } }); } } Что делает класс Code? При нажатии на кнопку в переменную aA записывается путь до данного приложения (и да, однотипные названия методов и классов были сделаны исключительно с целью немного запутать участников квеста):

Code.aA = Code.this.getApplicationContext ().getFilesDir ().getAbsolutePath (); Затем в переменную str записывается результат выполнения метода a из класса AA.Метод a прост до невозможности:

public String a (String paramString1, String paramString2) { if (! paramString1.equals («download_image»)) return null; aa («http://10.0.31.111/index.php», «neoquest_2014», paramString2 + File.separator + «neoquest_2014»); return «Correct command»; } В случае если в текстовое поле введена команда, отличная от «download_image» возвращается null, иначе вызывается метод aa со следующими параметрами:

aa («http://hastalavistababy.ru/index.php», «neoquest_2014», paramString2 + File.separator + «neoquest_2014»); Метод aa формирует строку вида:

«cmd=1&time=xxx&command_name=download_image&path=neoquest_2014» А затем вызывает метод getExampleInFile, который сохраняет ответ от сервера в файл:

getExampleInFile («http://hastalavistababy.ru/index.php», cmd=1&time=xxx&command_name=download_image&path=neoquest_2014, /data/data/com.example.NeoQUEST2014/files/neoquest_2014); В результате в папке files нашего приложения окажется файл, загруженный с сервера. Ввиду того, что достать этот файл на телефоне можно только с правами root, следует воспользоваться утилитой wget и скачать файл следующей командой:

wget.exe http://hastalavistababy.ru/index.php? cmd=1&time=xxx&command_name=download_image&path=neoquest_2014 Что же это за странный файл? На этот вопрос ответит класс Code. После скачивания файла вызывается метод a класса A c параметром TelephonyManager:

A localA = new A (); try{ localA.a ((TelephonyManager)Code.this.getSystemService («phone»)); return; } Метод a делает следующее:

public String a (TelephonyManager paramTelephonyManager) throws Exception { StringBuffer localStringBuffer = new StringBuffer (); localStringBuffer.append (paramTelephonyManager.getDeviceId ()); if (! paramTelephonyManager.getDeviceId ().equals (»352276054393855»)); do { return null; localStringBuffer.append (paramTelephonyManager.getSimOperator ()); } while (! paramTelephonyManager.getSimOperator ().equals (»25001»)); localStringBuffer.append (aaaa («neoquest_2014»)); String str = aaaa (localStringBuffer.toString ()); localStringBuffer.setLength (0); localStringBuffer.append (str); aa (localStringBuffer.toString ().substring (0, 16).getBytes ()); return «Success»; } Для начала он берет ID телефона и проверяет его на соответствие строке »352276054393855», а ID оператора связи проверяет на соответствие строке »25001» и добавляет эти строки в переменную localStringBuffer:

if (! paramTelephonyManager.getDeviceId ().equals (»352276054393855»)); do { return null; localStringBuffer.append (paramTelephonyManager.getSimOperator ()); } while (! paramTelephonyManager.getSimOperator ().equals (»25001»)); Затем в переменную localStringBuffer добавляется строка «neoquest_2014»:

localStringBuffer.append (aaaa («neoquest_2014»)); Затем вызывается метод aaaa с параметром — сформированной строкой. Данный метод считает хэш по алгоритму MD5:

String str = aaaa (localStringBuffer.toString ()); Далее вызывается метод aa c параметром — первые 16 байт полученного хэша:

aa (localStringBuffer.toString ().substring (0, 16).getBytes ()); Метод aa осуществляет расшифрование загруженного файла neoquest_2014 с ключом, состоящим из первых 16-ти байт того самого хэша, а результат записывает в файл neoquest_2014_original:

public static void aa (byte[] paramArrayOfByte) throws Exception { SecretKeySpec localSecretKeySpec = new SecretKeySpec (paramArrayOfByte, «AES»); byte[] arrayOfByte1 = IOUtils.toByteArray (new FileInputStream (Code.aA + File.separator + «neoquest_2014»)); Cipher localCipher = Cipher.getInstance («AES/ECB/PKCS5Padding»); localCipher.init (1, localSecretKeySpec); localCipher.init (2, localSecretKeySpec); byte[] arrayOfByte2 = localCipher.doFinal (arrayOfByte1); FileOutputStream localFileOutputStream = new FileOutputStream (Code.aA + File.separator + «neoquest_2014_original»); localFileOutputStream.write (arrayOfByte2); localFileOutputStream.close (); } Таким образом, участникам нужно было скачать файл на компьютер (или с телефона, для любителей извращений), а затем восстановить ключ и расшифровать загруженный файл.

3 — TimeShift 2. Revenge Задание с очного тура NeoQUEST-2013, тогда его никто не смог пройти. Мы его доработали для онлайн-тура, и в этот раз многие с ним справились.Из легенды имеем два IP-адреса с портом (213.170.102.196:4001, 213.170.102.197:4002) и ключ B4365F2.Установив соединение с первым сервером и отправив произвольные данные (например, программой netcat), получаем ответ: ilya@debian:~$ netcat 213.170.102.196 4001 hi ЖїAlert! Expected client hello message. Format: 1 byte type NEOSSL_HANDSHAKE 0×16 2 byte version NEOSSL1_VERSION 0×01 3–4 bytes length (excluding header) 5 byte data NEOSSL_CLIENT_HELLO 0×01 ---DEBUG INFO--- Ubuntu Release 10.04 (lucid) Kernel Linux 2.6.32–21-generic Memory 1001.9 MiB Processor Intel® Core i3 CPU Processing time 1471 cycles Processing threads — 1 thread Public-key cryptography algorithm — RSA (with Montgomery multiplication) Symmetric-key cryptography algorithm — AES-128 (zero IV) ------ Хост отвечает сообщением об ошибке в котором содержится формат ожидаемого сообщения и отладочная информация. Сервер ожидает получить сообщение client hello: {0×16, 0×01, 0×00, 0×01, 0×01}. Из 5-ти байт 4 входит в заголовок сообщения, один (NEOSSL_CLIENT_HELLO) в данные.Проверим второй сервер.

ilya@debian:~$ netcat 213.170.102.197 4002 hi

뤲t! Expected server hello message. Format: 1 byte type NEOSSL_HANDSHAKE 0×16 2 byte version NEOSSL1_VERSION 0×01 3–4 bytes length (excluding header) 5 byte data NEOSSL_SERVER_HELLO 0×02 6 byte data RSA_WITH_AES_128_CBC 0×01 7-n bytes data Certificate ---DEBUG INFO--- Ubuntu Release 10.04 (lucid) Kernel Linux 2.6.32–21-generic Memory 1001.9 MiB Processor Intel® Core i3 CPU Processing time 1531 cycles Processing threads — 1 thread Public-key cryptography algorithm — RSA (with Montgomery multiplication) Symmetric-key cryptography algorithm — AES-128 (zero IV) ------ Второй хост отвечает сообщением client hello и ожидает сообщение server hello, содержащее сертификат сервера. Таким образом, первый хост выполняет роль сервера, второй — клиента. Пересылая их сообщения друг другу и анализируя сообщения об ошибках, можно понять протокол общения.1. Клиент посылает NEOSSL_CLIENT_HELLO сообщение.2. Сервер отвечает сообщением NEOSSL_SERVER_HELLO, содержащим параметры защищенного соединения (RSA_WITH_AES_128_CBC) и сертификат.3. Клиент отправляет NEOSSL_KEY_EXCHANGE сообщение, содержащее зашифрованный открытым ключом сервера сессионный ключ AES-128.4. Сервер отвечает NEOSSL_FINISHED.5. Клиент отправляет зашифрованные данные.Зашифрованные данные также отправляются с заголовком и имеют следующий формат:

1 byte type NEOSSL_DATA 0×17 2 byte version NEOSSL1_VERSION 0×01 3–4 bytes length (excluding header) 5-n bytes data Поскольку в схеме отсутствует аутентификация клиента, можно попробовать отправлять сообщения серверу, однако, без знания протокола дальнейшего общения, это не принесет никаких результатов.Нужно получить данные, которые клиент посылает серверу на 5-м шаге. Можно попытаться сгенерировать сертификат и с его помощью установить соединение с клиентом. Однако клиент проверяет получаемый сертификат и не принимает сгенерированный. Про шифрование AES-ом практически ничего не известно (ключ каждый раз разный, сообщение, вероятно, тоже может меняться и его содержание неизвестно). Значит, надо взламывать RSA.

Необходимо получить закрытый ключ сервера. Имеется сертификат сервера (содержащий открытый ключ) и доступ к шифратору (на шаге 3 клиент посылает данные, которые сервер расшифровывает и интерпретирует как сессионный ключ).

Среди атак на RSA есть интересный класс атак, связанный с реализацией шифрования. Наиболее интересна нам атака по времени выполнения, потому как в отладочной информации находится время, которое сервер затратил на расшифровку сообщения (а еще — название задания намекает!). Еще про шифрование известно то, что оно использует умножение Монтгомери для увеличения скорости шифрования.Для вскрытия секретного ключа можно воспользоваться атакой, описанной в статье Harshman Singh «Timing Attacks on software implementation of RSA». Атака позволяет вычислить один из множителей модуля n. Вскрытие множителя выполняется побитово, начиная со старших бит. Для вскрытия шифратору отправляются запросы, сформированные из текущего известного значения модуля и вычисляется разница времени в случае если выбран бит 0 или 1. Если разница большая — устанавливается нулевой бит, иначе «один». Первые три бита множителя при этом нужно угадать. После вскрытия множителя легко вычислить закрытый ключ сервера.

Далее, установив соединение с клиентом, попробуем расшифровать сессионный ключ и сообщение, зашифрованное шифром AES. В отладочной информации сказано, что используется нулевой инициализирующий вектор AES. Вот полученное от клиента сообщение:

To obtain the access to the missile control system send a message: «XXXXXXX: Connect». XXXXXXX — ID В качестве ID нужно использовать значение из задания — B4365F2. Необходимо зашифровать строку «B4365F2: Connect» с использованием сессионного ключа и отправить её клиенту. Расшифровав очередной его ответ, получаем хэш — f9e8ceee19e980bd68e3193d6d0de2d3, это и есть наш ключ. Задание пройдено!

4 — Отмороженный компьютер Это задание было посвящено анализу данных дампа оперативной памяти, который был выдан участникам в виде файла размером в 1GB. Дамп был получен путем простого копирования файла vmem от запущенной и настроенной заранее виртуальной машины. Особенностью задания заключалась в том, что внутри одной виртуальной машины VMware, от которой и предоставлялся дамп, была создана и запущена другая виртуальная машина под управлением Oracle Virtual Box. Схема задания выглядела вот так: 0a30805512a063b581cdd0f6bee0d842.jpg

Обе виртуальные машины были под управлением одинаковых версий Windows 7, поэтому в дампе памяти присутствовало одновременно две операционные системы, страницы памяти которых были сильно разбросаны по дампу. Участникам NeoQUEST требовалось найти в дампе ключ. Наличие двух виртуальных машин и определение их типов выяснялось достаточно легко, путем анализа всех текстовых строк, находящихся в памяти. Интересно отметить, что при использовании CMAT на выданном участникам дампе программа отказывалась нормально работать, в то время как Volatility Framework успешно справлялся со своей работой и находил сразу две операционные системы.Победитель AV1ct0r для решения этого задания использовал именно Volatility Framework, про что он подробно написал в своем блоге. Еще одной особенностью задания NeoQUEST было то, что ключ, который нужно было найти участникам, был только в виде графического изображения в видеопамяти виртуальной машины Virtual Box. Поэтому для решения необходимо было восстановить видеопамять этой виртуалки. Для решения существует два пути, поскольку оперативная память и видеопамять виртуальной машины Virtual Box замаплена одновременно и в физическую память виртуальной машины VMware, и в виртуальную память процесса Virtual Box с эмуляторами (как ни странно, VirtualBox.exe).

babf1f96f9367475d539183004c02882.jpg

AV1ct0r решил задание с использованием дампа памяти процесса VirtualBox.exe, выделив в нем по виртуальному адресу, найденному в логах, видеопамять и сделав из нее картинку. Получение дампа процесса осуществлялось им так же, при помощи Volatility Framework. Вот алгоритм решения задания с получением видеопамяти виртуальной машины Virtual Box и формированием из нее картинки, с использованием маппинга видеопамяти в физическую память виртуальной машины VMware.

2b685ef39cba62fb852dbb999e47aced.jpg

Шаг 1. Получаем все читаемые строки из дампа памяти виртуальной машины VMware при помощи утилиты strings.exe. Файл со строками получается внушительным: 196 MB.Шаг 2. Узнаем, что запущена виртуальная машина Virtual Box и получаем кусок лога от ее запуска с более подробной и необходимой нам информацией:

:2013122720131228: komsomol@file:///C:/Users/komsomol/VirtualBox%20VMs/KP-2/Logs/VBox.log 00:00:02.305000 00:00:02.305001 [/DBGF/] (level 1) 00:00:02.305002 Path = «C:\Users\komsomol\VirtualBox VMs\KP-2/debug/; C:\Users\komsomol\VirtualBox VMs\KP-2/; C:\Users\komsomol/» (cb=103) 00:00:02.897225 HWACCM: TPR shadow physaddr = 000000003dd5f000 00:00:02.897227 HWACCM: VCPU0: MSR bitmap physaddr = 000000003dd67000 00:00:02.897229 HWACCM: VCPU0: VMCS physaddr = 000000003dd65000 00:00:02.897653 CPUMSetGuestCpuIdFeature: Enabled sysenter/exit 00:00:02.897655 HWACCM: 32-bit guests supported. 00:00:02.897656 HWACCM: VMX enabled! 00:00:02.897656 HWACCM: Enabled nested paging 00:00:02.897658 HWACCM: EPT root page = 000000003dd8b000 Из лога мы узнаем, что включена аппаратная виртуализация и что включена аппаратная поддержка таблиц страниц nested paging. Последнее означает, что Virtual Box настраивает таблицы EPT (Extended Page Tables), которые используются затем процессором для преобразования физических адресов виртуальной машины в физические адреса хостовой машины. В нашем случае, физические адреса виртуальной машины Virtual Box в смещения в файле дампа памяти. Чтобы узнать побольше про формат EPT (и про то, что он соответствует PML4), нужно почитать мануал процессора.Адрес корневой таблицы виден в логе и он равен 3dd8b000. Как и любые таблицы трансляций в них используются исключительно физические адреса, которые соответствуют абсолютным смещениям в файле дампа, поэтому осталось проичтать видеопамять, которая также расположена в физическом адресном пространстве виртуальной машины Virtual Box и маппится при помощи EPT.Эмуляторы устройства VGA (видеоадаптера) используют хостовую оперативную память для имитации видеопамяти для виртуальной машины, а для выполнения непосредственного рисования картинки на экран просто копируют обладсть оперативной памяти в хостовую видеопамять периодически — в точности как работает классический алгоритм двойной буферизации, использующийся во многих графических движках.Шаг 3. Узнаем физический адрес видеопамяти для виртуальной машины Virtual Box.В дампе его нет, поэтому, чтобы его узнать, достаточно запустить Virtual Box у себя на компьютере и посмотреть во вкладке ресурсов видеоадаптера значение (кстати, размер оперативной памяти в дампе есть):

00:00:02.305353 VRamSize = 0×0000000001000000 (16 777 216, 16 MB) Шаг 4. Определяем формат и размер видеоизображения. В видеопамяти графические данные хранятся в определенном формате, который схож с обычным BMP форматом: последовательно байты RGBXRGBX…на каждый пиксель по 3 или 4 байта. Разрешение экрана и битность узнаем из лога:

00:01:14.565973 Display: handleDisplayResize (): uScreenId = 0, pvVRAM=065c0000 w=800 h=600 bpp=32 cbLine=0xC80, flags=0×1 Шаг 5. Теперь нужно написать программу, которая прочитает из дампа только видеопамять. Для этого программа должна разбирать таблицы страниц в заданном диапазоне (начиная с физического адреса 0xE0000000 длиной размер картинки 800×600*4). Основная часть кода программы выглядит так:

DWORD TranslateGPA2HPA (DWORD gpa) { vmxGuestPysicalAddress addr; addr.Value = gpa;

vmxEPTP eptp; eptp.Value = EPT_base; DWORD64 pml4_base = (eptp.PML4ShiftedAddr << 12); vmxEptPML4Entry pml4_ent; pml4_ent.Value = DumpRead64(pml4_base + 8 * addr.eptPML4EntryOffset); DWORD64 pdpt_base = (pml4_ent.eptPDPTShiftedAddr << 12); vmxEptPDPTEntry pdpt_ent; pdpt_ent.Value = DumpRead64(pdpt_base + 8 * addr.eptPDPTEntryOffset);

DWORD64 pd_base = (pdpt_ent.eptrfPDShiftedAddr << 12); vmxEptPDEntry pd_ent; pd_ent.Value = DumpRead64(pd_base + 8 * addr.eptPDEntryOffset);

DWORD64 pt_base = (pd_ent.eptrfPTShiftedAddr << 12); vmxEptPTEntry pt_ent; pt_ent.Value = DumpRead64(pt_base + 8 * addr.eptPTEntryOffset);

return (pt_ent.Shifted4KPageAddr << 12) | addr.eptByteOffset; } void ReadPage(void *data, DWORD gpa) { DWORD offset = TranslateGPA2HPA(gpa & (~0xFFF)); fseek(g_fdump, offset, SEEK_SET); fread(data, 4096, 1, g_fdump); } HBITMAP ReadVideoMemory( DWORD width, DWORD height, DWORD bpp ) { DWORD size = ((width * height * (bpp / 8) / 4096) + 1) * 4096; char *bmp = (char *)malloc(size);

for (int i = 0; i < size; i+=4096) { ReadPage(bmp + i, 0xE0000000 + i); }

return CreateBitmap (width, height, 1, 32, bmp); } Объявление структур можно найти в документации к процессору. Функцию CreateBitmap можно найти в Интернете.После компиляции и запуска программы получается такая картинка:

65b6cc1165c94ce6b677a98280983ef8.jpg

Ключ найден! В результате задание можно решить и без использования CMAT и Volatility Framework, используя знания об устройстве видеопамяти и технологии виртуализации.

5 — Обнаружено неизвестное дымящееся устройство По легенде, участникам надо было, разобравшись, что же за непонятное устройство они «синхронизировали с ноутбуком», получить ключ из файла неизвестного формата.AV1ct0r в своем writeup’е определил, что этот файл — ни что иное, как дамп USB-трафика Android-устройства, и совершенно правильно отметил, что удобнее всего с ним работать в HEX-редакторе, а не в Wireshark.Поанализировав дамп, находим имена людей, телефонные номера и SMS-сообщения. Помня, что важная информация может храниться в SMS, ищем подсказку и находим: e9b56f8919a3493f965b84a780839a16.jpg

Информация о датах рождения хранилась в записной книжке, она начиналась с VCARD, там обнаружились 4 претендентки на роль жены. Оставался открытым вопрос:, а что должен открывать этот пароль? Повнимательнее просмотрев дамп, обнаруживаем файл с названием look_at_this.7z. Гуглим сигнатуру 7z файлов:

37 7A BC AF 27 1C Дальше остается всего-то ничего — вытащить архив из дампа и перебрать 4 полученные ранее даты рождения. Внутри архива лежит файл win.txt с флагом key. Задание пройдено!

6 — Игродром В этом задании от участников требовалось поиграть в старый добрый Pac-Man, но особым образом, реализуя своеобразный port knocking.Первоначально — надо было догадаться, что сервер принимает запросы только с тегом. Методом проб и ошибок, используя подсказки от сервера, приходящие с порта 1898, участник, наконец, должен получить такое приветственное сообщение: