Skip to main content
Loading...
Szukaj
Logowanie
Dane logowania.
Nie masz konta? Załóż je tutaj.
Zarejestruj się
Zarejestruj się
Masz konto? Zaloguj się tutaj.

Czy jedno zdjęcie na WhatsAppie może przejąć Twojego iPhone’a?

Czy jedno zdjęcie na WhatsAppie może przejąć Twojego iPhone’a?

Na papierze to “tylko” kolejny błąd typu out-of-bounds write w parserze obrazków. W praktyce – zero‑click, realne exploity w kampaniach szpiegowskich, wejście na iPhone’a przez samo odebranie zdjęcia w WhatsAppie, bez jednego tappa w ekran. To ten moment, kiedy wszyscy, którzy latami powtarzali „przecież to tylko obrazek”, muszą zaktualizować światopogląd.

Apple załatało CVE-2025-43300 20 sierpnia 2025 r., wprowadzając out‑of‑band patch na wszystkie główne systemy – iOS, iPadOS, macOS, tvOS. WhatsApp dorzucił swój fix kilka dni później, przyznając wprost, że jego podatność do łańcucha ataku dokładana była właśnie z tym bugiem w ImageIO. Najciekawsze? Sedno problemu to rozjazd między metadanymi TIFF/DNG a wewnętrznym strumieniem JPEG lossless – rzecz, którą większość devów zbyłaby wzruszeniem ramion.

Jeśli zajmujesz się ofensywką, detections albo hardeningiem urządzeń Apple w organizacji, ten case jest idealnym przykładem, jak bardzo “mały” błąd w głębokim, nudnym kawałku stacku (RawCamera, DNG, JPEG SOF3…) przekłada się na realne ryzyko biznesowe. W tym tekście nie robimy laurki Apple – rozbieramy ImageIO, pokazujemy, co dokładnie poszło nie tak, jak wyglądał patch i co z tego wynika dla Ciebie jako blue/red teamu.


DNG, JPEG lossless i dlaczego metadane naprawdę Cię obchodzą

CVE-2025-43300 siedzi w ImageIO – systemowym frameworku Apple, który ogarnia czytanie, zapisywanie, dekodowanie i metadane obrazów w iOS/macOS/iPadOS. To nie jest jakaś „biblioteka od zdjęć w jednej aplikacji”. To fundament, którego używa Photos, Safari, Messages, AirDrop, WhatsApp i cała reszta, wszędzie tam, gdzie system musi ruszyć obrazek.

Konkretny pacjent to RawCamera.bundle i klasa CDNGLosslessJpegUnpacker, która zajmuje się przetwarzaniem DNG – formatu Adobe opartego na TIFF/EP, wykorzystywanego m.in. do zdjęć RAW. DNG może trzymać dane skompresowane JPEG‑iem lossless (SOF3), a decoder korzysta przy tym z dwóch źródeł prawdy: tagów TIFF (np. SamplesPerPixel, BitsPerSample, RowsPerStrip/TileWidth/TileLength) oraz wewnętrznego strumienia JPEG, gdzie w markerze SOF3 deklarowana jest m.in. liczba komponentów (NumComponents).

I tu jest pies pogrzebany: jedna część kodu ufa TIFF‑owi (“SamplesPerPixel = 2, więc dwa kanały na piksel”), inna ufa strumieniowi JPEG (“NumComponents = 1, mamy jeden komponent”) i przy odpowiednio złośliwej kombinacji te dwa światy rozjeżdżają się jak źle skonfigurowane routing tables. Bufor alokowany jest według jednego zestawu założeń, pętle zapisujące dane iterują według innego – efekt końcowy to out‑of‑bounds write w trakcie dekompresji jednostek obrazu.


Jak dokładnie wyglądał bug: od SamplesPerPixel do OOB write

Quarkslab i niezależni badacze ładnie rozpisali call‑tree, ale sedno da się sprowadzić do jednego zdania: jeśli w DNG ustawisz SamplesPerPixel = 2, a w JPEG SOF3 NumComponents = 1, to kod w ImageIO zaczyna żyć w schizofrenii i pisze poza przydzieloną pamięcią.

W skrócie wygląda to tak:

– RawCamera alokuje bufor uncompressed o rozmiarze width * height * SamplesPerPixel (czyli bazuje na TIFF, który mówi: na piksel mamy 2 próbki).– W pętli po wysokości (height) dekompresuje wiersz po wierszu, korzystając z tablic Huffmana zdefiniowanych w markerach DHT i parametrów z SOF3 (tam NumComponents = 1).– Pierwszy piksel w wierszu jest przetwarzany w pętli po komponentach – ale komponent jest jeden, więc wszystko się jeszcze spina.– Dalej wchodzi w gałąź kodu, która jest napisana z założeniem „mamy co najmniej 2 komponenty na piksel” – i to jest krytyczny moment.

Zamiast ograniczać się do NumComponents, wewnętrzna pętla “przeskakiwania” po pikselach używa mnożnika width * 2 (czyli zakodowane na sztywno „2 komponenty”), a funkcja decompress() zwraca ilość danych odpowiadającą SamplesPerPixel, czyli dwóm 16‑bitowym próbką na piksel. W efekcie:

– limiter pętli opiera się na NumComponents = 1,– ale ilość danych zapisywanych na wyjściu jest wyliczana jak dla SamplesPerPixel = 2 i 16 bitów na próbkę (2 bajty na kanał).

To oznacza, że dla każdego wiersza dekoder wypycha do bufora mniej więcej dwa razy więcej danych, niż pierwotnie założył przy alokacji – klasyczny out‑of‑bounds write (CWE‑787), tylko zakopany głęboko w ścieżce dekodowania JPEG lossless w DNG.

Co gorsza, ta ścieżka nie jest egzotycznym edge‑casem. Kod obsługuje tzw. “Lossless DNG Tile Unpacker Queue” – kolejkę, która dzieli obraz na kafelki (tiles) i równolegle je rozpakowuje, wstawiając w odpowiednie miejsca w buforze wyjściowym. Jeśli któryś z kafelków zostanie zasilony takim złośliwym układem SamplesPerPixel/NumComponents, nadpisanie pamięci może dotknąć nie tylko samego bufora pikseli, ale także struktury zarządzające kolejką lub inne obiekty w tym samym regionie pamięci, co już otwiera drogę do RCE.


Dwa bajty patcha, duże kłopoty dla ofensywy

Najbardziej smakowite w tym case’ie jest to, jak niewielki diff wprowadziło Apple, żeby wybić z ręki tę klasę bugów. Quarkslab, Hackyboiz i inni badacze przejrzeli diff RawCamera między iOS 18.6.1 a 18.6.2 / odpowiadającymi buildami macOS – wyszło, że istotnie zmienionych jest tak naprawdę kilka funkcji, z czego dwie są kluczowe: odpowiedzialne za dekodowanie JPEG lossless oraz ścieżka renderowania pixel bufferów.

Po pierwsze, Apple przesiadło się z “gołego” pipeline’u CGImage + CFData na pipeline CMPhoto + CVPixelBuffer w części odpowiedzialnej za obsługę niektórych formatów. Stary kod sprawdzał mniej więcej: czy CFDataGetLength(data) == 4 * width * height – zakładając 4 bajty na piksel, ignorując padding w wierszach (BytesPerRow) i różne formaty bufora. Nowa wersja bierze CVPixelBuffer, wywołuje CVPixelBufferGetBytesPerRow i CVPixelBufferGetDataSize, a potem porównuje DataSize z wyliczoną wewnętrznie wartością „expected”, uwzględniającą stride i format. Jeśli coś się nie zgadza, leci RawCameraException zamiast spokojnego przejścia dalej.

Po drugie, w samej logicznej ścieżce dekompresji Apple dorzuciło klasyczny „bezpiecznik”: przed każdym zapisem do bufora sprawdzana jest faktyczna granica – dodatkowe wywołania pomocniczych funkcji, które rezerwują bufor i raportują jego rozmiar, a warunek typu „jeżeli pointer przekroczył koniec, rzuć wyjątek”. W praktyce to sprowadza się do dodania jednego dodatkowego porównania na pointerze i skoku do handlera wyjątku – dokładnie tych „dwóch bajtów”, o których mówili badacze, choć oczywiście całościowo patch jest odrobinę większy.

Z perspektywy ofensywnej to jest ciekawy sygnał: Apple nie wprowadza tu żadnej kosmicznej nowej technologii, tylko przenosi dekodowanie na api, które z natury wymusza świadomość rozmiaru bufora (CVPixelBuffer) i dokręca klasyczne bounds‑checking. To oznacza, że w 2026 r. polowanie na podobne bugi w ImageIO czy innych krytycznych frameworkach będzie wymagało szukania bardziej subtelnych bugów logicznych, a nie prostych matematycznych wpadek w pętlach.


Zero‑click łańcuch: jak z obrazka w WhatsAppie zrobić pełne przejęcie

Sama podatność w ImageIO to tylko połowa historii. Druga połowa siedzi w kliencie, który umożliwia dociągnięcie i automatyczne przetworzenie obrazka bez interakcji użytkownika. W tym przypadku w łańcuch wchodził WhatsApp – jego własna luka pozwalała na wymuszenie pobrania zasobu z dowolnego URL‑a i odpalenie jego przetwarzania, a ImageIO robiło resztę.

Schemat na poziomie taktycznym wygląda mniej więcej tak:

– Tzw. delivery/initial access: atakujący wysyła do ofiary specjalnie przygotowaną wiadomość w WhatsAppie; klient automatycznie pobiera obraz DNG (albo plik przetworzony do DNG w trakcie pipeline’u) z kontrolowanego przez atakującego serwera.– Exploitation: przy przetwarzaniu obrazka (np. generowanie miniatury, analiza metadanych, przygotowanie do wyświetlenia w UI) WhatsApp woła systemowy ImageIO, który odpala dekodowanie DNG → wchodzi w podatną ścieżkę Lossless DNG Tile Unpacker Queue, odpala out‑of‑bounds write.– Post‑exploitation: jeśli dopiszesz do tego łańcucha odpowiedni ROP/JavaScriptCore/IOKit czy cokolwiek jeszcze potrzebne do pełnego sandbox escape i persistence, kończysz z typowym spyware‑owym scenariuszem – przejęcie komunikatorów, mikrofonu, aparatu, backupów itd.

To jest typowy zero‑click z gatunku „nie musisz zrobić absolutnie nic złego jako użytkownik, wystarczy być na liście celów”. Amnesty i inni sygnalizowali, że kampanie wykorzystujące CVE‑2025‑43300 były ukierunkowane na konkretne osoby, a nie randomowe masowe skanowanie internetu. Dla zespołów bezpieczeństwa to nie jest klasyczny problem „usera, który kliknął w phishing”, tylko czysta gra w klasie APT/spyware.


Co z tego wynika dla SOC, IR i devów?

Dla SOC‑u i IR‑u pierwsza, bardzo przyziemna konsekwencja: zero‑click na poziomie ImageIO jest z definicji słabo widoczny w klasycznych telemetrycznych śladach użytkownika. Nie ma URL‑i klikanych w Safari, nie ma dziwnych tapów, nie ma „otwarł PDF z maila”. Jest normalny traffic do CDN‑ów WhatsAppa i systemowy proces przetwarzający obrazki. Jeśli nie masz dobrej widoczności na poziomie MDM/EDR dla iOS z logami crashy, exceptionów z RawCamera/ImageIO czy zachowań WhatsAppa, jesteś w zasadzie ślepy.

Po drugie, i to powinni sobie wziąć do serca zarówno devowie, jak i ci, którzy klepią secure coding guidelines: ten bug to książkowy przykład, dlaczego „podwójne źródło prawdy” o strukturze danych (tu: metadane TIFF vs. wewnętrzny strumień JPEG) musi mieć twardą walidację spójności. Jeżeli jedna warstwa ufa SamplesPerPixel, a druga NumComponents i nikt nie robi cross‑checka, to prędzej czy później wpadniesz w taką minę.

Z bardzo praktycznych rzeczy, które możesz zrobić już teraz:

– W procesach IR potraktuj CVE‑2025‑43300 jako trigger do retro‑analizy crashy i logów na flotach iOS/macOS w okresie sprzed patcha (18.6.2 / odpowiadające wersje macOS). Szukaj nietypowych błędów RawCameraException, crashy w ImageIO/RawCamera w kontekście komunikatorów.– Jeśli jesteś po stronie MDM/EDR – loguj i koreluj wywołania do ImageIO oraz nietypowe błędy podczas przetwarzania obrazów z komunikatorów i aplikacji „wysokiego ryzyka” (WhatsApp, iMessage, Signal, inne). To nie jest piękne ani proste na iOS, ale ignorowanie tego wektoru to proszenie się o kłopoty.– Jeśli tworzysz aplikacje korzystające z ImageIO lub własne parsowanie obrazów, po prostu przestań zakładać, że metadane mówią prawdę. Krzyżowo waliduj wartości takie jak SamplesPerPixel, BitsPerSample, NumComponents, RowsPerStrip/TileLength, a bufor alokuj na podstawie najbardziej konserwatywnych założeń, a nie najsympatyczniejszych dla wydajności.

Wreszcie – aspekt biznesowy. To nie jest bug klasy „userowi źle się wyświetli ikonka”. To jest luka, która wprost przekłada się na: ryzyko wycieku komunikacji zarządu, podsłuchów narzędzi zarządzania kryzysowego, kompromitacji urządzeń, które ze względu na politykę BYOD/COPE są używane jednocześnie prywatnie i służbowo. Jeśli Twoja organizacja zakłada, że „iPhone’y są w miarę bezpieczne same z siebie”, to CVE‑2025‑43300 jest kolejnym argumentem, że bez procesu patchowania, wymuszania wersji i kontroli aplikacji to jest czyste życzeniowe myślenie.


Gdzie jest granica zaufania do platformy?

Ta historia ma bardzo prostą puentę. Jeśli framework od obrazków w systemie klasy iOS potrafi popełnić tak trywialny błąd jak pomylenie SamplesPerPixel z NumComponents i nieprzeliczenie limitu pętli, to nie ma żadnego powodu, żebyś traktował „systemowe” jako z definicji „bezpieczne”.

Z punktu widzenia red‑teamów i exploit devów to jest żyzna gleba: parsowanie złożonych formatów, głębokie frameworki, stare założenia projektowe i minimalne testy w branchach, które „przecież i tak prawie nikt nie używa”. Z punktu widzenia blue‑teamu – sygnał, że bez twardych wymogów aktualizacji (policy dla iOS 18.6.2+), ograniczania komunikatorów, które mają historię takich łańcuchów, i realnej obserwowalności na endpointach, grasz w ruletkę.

Jeżeli po lekturze tej historii jedyne, co zrobisz, to dopiszesz dwa zdania w polityce „zalecamy aktualizację urządzeń”, to znaczy, że kompletnie nie zrozumiałeś stawki. Traktuj CVE‑2025‑43300 jako modelowy case: przeanalizuj go z zespołem, zmapuj, które Twoje procesy by go wyłapały, a które kompletnie przegapiły. A potem popraw te ostatnie – zanim następny „niewinny obrazek” zrobi Ci RCE w najważniejszym telefonie w firmie.


Bibliografia:

– Quarkslab: Reverse engineering of Apple's iOS 0-click CVE-2025-43300https://blog.quarkslab.com/patch-analysis-of-Apple-iOS-CVE-2025-43300.html– Hackyboiz: iOS/macOS DNG Image Processing Memory Corruption (CVE-2025-43300)https://hackyboiz.github.io/2025/10/23/clalxk/imageIO_en/– Cryptika: Analysis of Apple's ImageIO Zero-Day Vulnerabilityhttps://www.cryptika.com/analysis-of-apples-imageio-zero-day-vulnerability-attacker-context-and-historical-ios-zero-click-similarities/– Fidelis Security: CVE-2025-43300 Zero-Day: ImageIO Exploit Alerthttps://fidelissecurity.com/vulnerabilities/cve-2025-43300/– Wiz: CVE-2025-43300 Impact, Exploitability, and Mitigation Stepshttps://www.wiz.io/vulnerability-database/cve/cve-2025-43300– Malwarebytes: WhatsApp fixes vulnerability used in zero-click attackshttps://www.malwarebytes.com/blog/news/2025/09/whatsapp-fixes-vulnerability-used-in-zero-click-attacks– The Hacker News: WhatsApp Patches Zero-Click Exploit Targeting iOS and macOS Usershttps://thehackernews.com/2025/09/whatsapp-issues-emergency-update-for.html– PKF: Understanding Apple's ImageIO Framework CVE-2025-43300https://pkfthailand.asia/cve-2025-43300-vulnerability-understanding-apples-imageio-framework/

Sprawdź się!

Powiązane materiały

Zapisz się do newslettera

Bądź na bieżąco z najnowszymi informacjami na temat
cyberbezpieczeństwa