Методи перехоплення httphttps трафіку

Наскільки я знаю, зараз в ходу досить відома і проста схема перехоплень трафіку в браузерах (для модифікації і збору інформації). Схема хоч і популярна, але націлена виключно на певні версії браузерів.

Методи перехоплення httphttps трафіку

Так, наприклад, для IE використовується схема з перехопленням функцій wininet. Тут, до речі, теж існує як мінімум дві версії логіки - перехоплення, що синхронізує InternetReadFile (Ex), і православний перехоплення коллбека InternetStatusCallback і всіх допоміжних функцій.

Другий підхід, безумовно, архітектурно більш вдалий, так як всі операції всередині ИЕ відбуваються також асинхронно і немає лага. Тобто, після установки перехоплень, wininet так і залишається асинхронним, як і був задуманий розробниками microsoft. З точки зору коду, такий підхід куди більш складний, ніж перший (в часності застосовується в zeus і його клонах, начебто цитаделі та іншого шлаку).

Що стосується інших браузерів - тут все не так прозоро. Для хрому і фраєр фокса використовується перехоплення функцій NSS (Network Security Services), а конекретнее - функцій PR_ReadPR_Write.

У Фаєр Фокса вони експортуються nspr4.dllnss3.dll (ДЛЛ залежить від версії), в хромі покажчики на функції беруться з таблиці, яку найчастіше шукають сигнатурної. В Opera взагалі незрозуміло що і як, так як реверс геморойно, движок зараз постійно змінюється і смакоти начебто PDB ніхто від неї не дає. Хоча можна припустити, що Opera Next, побудована на Chromium, теж може бути скомпрометованість так само, як і хром (пошуком функцій nss3). У підсумку, маємо стабільний перехоплення, мабуть, тільки в ІЕ (на час читання статті допустимо що код, написаний для цих цілей, не креш віслюк і працює стабільно).

Сигнатурний метод апріорі не можна вважати стабільним, так як ці два поняття несумісні. Завтра вийде нова версія браузера, де по-іншому написаний код, доданий метод в клас, щось кудись переміщено і сигнатура виявиться збита. Тим більше хром, який, можливо, вcкоре відмовиться від NSS. Фаєр фокс останнім часом теж активно взявся за апгрейд старого коду, що видно неозброєним оком з чейджлога. Від функцій перевірки та валідації сертифікатів засобами nss вже відмовилися, замінивши цю частину новеньким mozilla :: pkix (багато хто вже вихоплюють ништяки, заганяючи кодес деактивації функцій валідації). Втім, можливо, перспектива змальована мною, занадто песимістична і поточні коди будуть працювати ще 200 років.

Складність всіх перерахованих методів бачиться мені в своїй неуніверсальності, необхідності моніторити оновлення браузерів, гори перехоплень, до яких готові різні захисту на кшталт трастер рапорту, необхідності підтримувати кілька гілок коду, що виконує одну "просту" мета - втручання в призначений для користувача сслхттп трафік.

Ось тільки, як мені здається, хук на коннект недвозначного говорить "про що, то такому". Більш беспалевно було б хукнуть NtDeviceIoControlFile. У хук моніторити, якщо IoControlCode буде IOCTL_AFD_CONNECT, то безжально патчить InputBuffer. У ньому буде структура AFD_CONNECT_INFO і в ній все що потрібно знатьізменять для успішного перенаправлення з'єднання. Деталі реалізації залишимо на совісті експериментаторів.

Варто тільки відзначити що структури для NT5 і NT6 + різні. Але в цій точці можна відловлювати будь-яким спробам конекту процесу, в якому ми знаходимося.

З коннектом розібралися. Куди його направити? Очевидним здається відповідь "на локалхост". На локалхосте ми піднімемо хттп сервер для розрулювання запитів і відповідей браузера. хттп від хттпс відливається тільки шаром SSL, в іншому, зрозуміло все однаковий. хттп і в Африці хттп. Цей момент може відлякати своєю нетривіальністю реалізації, але насправді, ми ж про теорію, хехе.

Все інше справа техніки. Ми може як модифікувати запит (підміна ПОСТ даних), так і відповідь, збираючи під тимчасовий буффер відповідь, на що цікавить нас запит. Все ніби прозоро, все просто. До речі, відмінний хттп парсер є в libevent. Його юзает в своїх цілях NGINX, він компактний, налагоджений і стабільний.

Припустимо, все це у нас реалізовано. Починаючи з цього моменту, здійснити перехоплення трафіку в хттп не буде складно. Єдиною "складною" завданням тут буде тільки парсинг нерегулярного контентта, начебто чанкед енкодинг і гзіпа. Але в ідеалі все це на совісті хттп парсеру і підключеної zlib. Цей шлях більш технічно складний, ніж той що використовується в Зевса при парсінгу відповідей - запитів в ФФ, але більш стабільний і правильний, так як браузер продовжує спілкуватися з хттп сервером і ми не змушуємо його отримувати сурогатний відповідь і не змушуємо браузер відключати гзіп, втручаючись в його хедери в реалтайм.

Цей підхід також дає можливість використовувати всі переваги хттп, такі як пайпеллінг, вебсокет, стиск, прозорий контроль використання хттп проксі.

HTTPS. Ось тут починаються деякі складності. Але все можна вирішити. Розглянемо докладніше. Навряд чи варто відволікатися на те, як працює SSL, чому необхідно мати валідний сертифікат і чому у нас не вийде втрутитися в роботу браузера, якщо сертифікату не буде. Але у нас немає валидного сертифіката для будь-якого домену, тому можна вчинити по-різному.

Підхід перший. патчінга перевірки сертифікатів. Метод дібільний, успішно заре- рекомендували свою непріменяемость. Суть зводиться до того, щоб створювати коннект браузер локалхост з самоподпісанного сертіфткатом, але ставлячи перехоплення всередині CryptoAPI і всередині браузерів (найчастіше це неекспортіруемие функції внутрішніх перевірок браузера), створювати видимість того, що сертіфкат нормальний. До того ж тут вилазить маса побічних ефектів:

1 - всі сайти раптово починають юзати один і той же сертифікат. Тобто якщо зайти в гугл, там там сертіфкат виданий "super co ltd". Якщо зайти на майкрософт, то і там все той же "super co ltd".

Нормальна людина відразу запідозрить недобре. А цільова аудиторія у нас, природно, не ідіоти.

2 - Нестабільність методу, так як фукнции перевірки сертифікатів розробники браузерів (ИЕ виняток) не поспішають позначати як експортовані. Звідси купа геморою, на кшталт того, що самі Функ змінюються, їх сигнатурку змінюються, кількість параметрів може змінюватись (нормальне явище у випадку з хромом)

Як зробити так, щоб усім було добре? Очевидно, потрібно або не чіпати сертіфкати, або робити так, щоб ніхто не бачив різниці між справжнім і фальшивкою. Нам потрібно генерувати сертифікат на льоту для кожного домена, повністю дублюючи всі записи цього сертифіката в новому, фейковий сертіфкате. Тобто схема така:

1 - ловимо коннект браузера на віддалений сервер

2 - редирект на локалхост, запускаючи там попутно новий інстанси TCP сервера, копія якого прив'язана до хосту, куди спочатку йшов браузер

3 - В інстанси сервера чекаємо конекту браузера. Як тільки браузер пріконнектілся, ми не починаємо SSL сесію, а йдемо на той хост, куди йшов браузер спочатку. Шлях це буде гугл.

4 - Після ініціалізації SSL з'єднання з гуглом, отримуємо від нього сертіфкат, Парс все поля з нього.

5 - створюємо свій сертіфкат, на основі всього того, що вдалося видерти з цього Церта. Для замилювання очей вистачить полів CN, E, OU, etc. базові поля х509

6 - перетворимо наш інстанси TCP сервера в SSL сервер, починаючи handsnake з тільки що згенерованого сертіфката.

У підсумку, ми маємо динамічну генерацію Церта для кожного домена. Результат генерації можна зберігати в локальних кешах, звичайно. Таким чином ми можемо зробити так, щоб сертіфкати були такі, які потрібно (за складом). Щоб браузер не лаявся на те, що Церта самопальний, потрібно зробити так, щоб він не був самопальним 🙂

Тобто, нам потрібно для початку згенерувати якийсь початковий Церта, якому дати право підписувати сертіфкати (CertStrToName, CertCreateSelfSignCertificate), виставивши відповідні прапори при створенні сертифіката:

Потім додати його в сторадж довірених віндовий Церта (CertAddCertificateContextT oStore). Потім зв'язати його з генерованим приватним ключем (CryptGenKey / CryptAcq uireCertificatePrivateKey). Усе!

Тепер аглорітм розширюється тим, що для домену ми генерітся сертіфкат і підписуємо його нашим рутом.

Браузер алгоритм показує що cерт справжній, все працює як треба, трафік перехоплюється. Більш того, можна не генерувати сертіфкат заново, а просто переподпісать той, що йде від того ж гугла.

Браузер побачить Церта, почне розкручувати ланцюжок видачі, наткнеться на наш траст, який числиться видавцем сертіфкатов, переконається що сертіфкат валідний. Профіт.

Що виходить в сухому залишку?

1 - Один перехоплення, в повністю документованої і нікуди не дівається Функе в ntdll.

2 - Незалежність від платформи браузера (3264) і особливостей реалізації його механізмів перевірки Церта та іншого гівна:

3 - робота на всіх ос максимально безболісно;

4 - плная невидимість роботи для користувача (все працює швидко, хоча і залежить від хттп парсеру), все сертіфкати залишаються такими, якими вони повинні бути.

Дякую за увагу!