Lucene search

K
talosTalos IntelligenceTALOS-2017-0317
HistorySep 13, 2017 - 12:00 a.m.

LibOFX Tag Parsing Code Execution Vulnerability

2017-09-1300:00:00
Talos Intelligence
www.talosintelligence.com
10

6.8 Medium

CVSS2

Attack Vector

NETWORK

Attack Complexity

MEDIUM

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:M/Au:N/C:P/I:P/A:P

8.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

REQUIRED

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

0.002 Low

EPSS

Percentile

55.3%

Summary

An exploitable buffer overflow vulnerability exists in the tag parsing functionality of LibOFX 0.9.11. A specially crafted OFX file can cause a write out of bounds resulting in a buffer overflow on the stack. An attacker can construct a malicious OFX file to trigger this vulnerability.

Tested Versions

LibOFX 0.9.11

Product URLs

<https://github.com/libofx/libofx&gt;

CVSSv3 Score

8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

CWE

CWE-120 - Buffer Copy without Checking Size of Input (β€˜Classic Buffer Overflow’)

Details

OFX is the Open Financial Exchange format used by financial institutions to share financial data with clients. GnuCash is an open source financial-accounting software that has the capability to import OFX records using libOFX, an open source implementation of OFX.

While parsing the tags of the given OFX record, libOFX attempts to strip any present OFX proprietary tags. After checking that the file begins with the correct OFX tag of &lt;OFX&gt;, the remaining tag is sent over to be sanitized by sanitize_proprietary_tags. In this function, the tag is copied into a local stack variable called tagname as long as the parser is still within the opening tag [0].

lib/ofx_preproc.cpp:75
const unsigned int READ_BUFFER_SIZE = 1024;

lib/ofx_preproc.cpp:417
string sanitize_proprietary_tags(string input_string)
{
unsigned int i;
size_t input_string_size;
bool strip = false;
bool tag_open = false;
int tag_open_idx = 0; //Are we within &lt; &gt; ?
bool closing_tag_open = false; //Are we within &lt;/ &gt; ?
int orig_tag_open_idx = 0;
bool proprietary_tag = false; //Are we within a proprietary element?
bool proprietary_closing_tag = false;
int crop_end_idx = 0;
char buffer[READ_BUFFER_SIZE] = "";
char tagname[READ_BUFFER_SIZE] = "";
int tagname_idx = 0;
char close_tagname[READ_BUFFER_SIZE] = "";


for (i = 0; i &lt; input_string_size; i++)

    if (input_string.c_str()[i] == '&lt;')
    {
    tag_open = true;
    tag_open_idx = i;
    if (proprietary_tag == true && input_string.c_str()[i+1] == '/')
    {
        ...
    }
    else if (proprietary_tag == true)
    {
        //It is the start of a new tag, following a proprietary tag
        crop_end_idx = i - 1;
        strip = true;
    }
    }
    else if (input_string.c_str()[i] == '&gt;')
    {
        ...
    }
    else if (tag_open == true && closing_tag_open == false)
    {
    if (input_string.c_str()[i] == '.')
    {
        if (proprietary_tag != true)
        {
        orig_tag_open_idx = tag_open_idx;
        proprietary_tag = true;
        }
    }
    tagname[tagname_idx] = input_string.c_str()[i]; [0]
    tagname_idx++;

Because the loop occurs over the size of the input_string, if the input_string is larger than READ_BUFFER_SIZE, then the stack variable is overflown and can potentially lead to code execution.

Crash Information

==6542==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffffbb4260 at pc 0x7fab9d30ccc1 bp 0x7fffffbb39b0 sp 0x7fffffbb39a8
WRITE of size 1 at 0x7fffffbb4260 thread T0
	#0 0x7fab9d30ccc0  (/home/vagrant/fuzzing/libofx-asan/libofx-0.9.11/lib/.libs/libofx.so.7+0x30cc0)
	#1 0x7fab9d30aba0  (/home/vagrant/fuzzing/libofx-asan/libofx-0.9.11/lib/.libs/libofx.so.7+0x2eba0)
	#2 0x7fab9d3057cb  (/home/vagrant/fuzzing/libofx-asan/libofx-0.9.11/lib/.libs/libofx.so.7+0x297cb)
	#3 0x4f8ba2  (/home/vagrant/fuzzing/libofx-asan/libofx-0.9.11/ofxdump/.libs/lt-ofxdump+0x4f8ba2)
	#4 0x7fab9c06982f  (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
	#5 0x419618  (/home/vagrant/fuzzing/libofx-asan/libofx-0.9.11/ofxdump/.libs/lt-ofxdump+0x419618)

Address 0x7fffffbb4260 is located in stack of thread T0 at offset 2208 in frame
	#0 0x7fab9d30c38f  (/home/vagrant/fuzzing/libofx-asan/libofx-0.9.11/lib/.libs/libofx.so.7+0x3038f)

This frame has 9 object(s):
	[32, 1056) 'buffer'
	[1184, 2208) 'tagname' &lt;== Memory access at offset 2208 overflows this variable
	[2336, 3360) 'close_tagname'
	[3488, 3520) ''
	[3552, 3584) ''
	[3616, 3617) ''
	[3632, 3664) ''
	[3696, 3728) ''
	[3760, 3761) ''
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
	(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/home/vagrant/fuzzing/libofx-asan/libofx-
    0.9.11/lib/.libs/libofx.so.7+0x30cc0)
Shadow bytes around the buggy address:
0x10007ff6e7f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007ff6e800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007ff6e810: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007ff6e820: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007ff6e830: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=&gt;0x10007ff6e840: 00 00 00 00 00 00 00 00 00 00 00 00[f2]f2 f2 f2
0x10007ff6e850: f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 00 00 00 00
0x10007ff6e860: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007ff6e870: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007ff6e880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10007ff6e890: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable:           00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone:       fa
Heap right redzone:      fb
Freed heap region:       fd
Stack left redzone:      f1
Stack mid redzone:       f2
Stack right redzone:     f3
Stack partial redzone:   f4
Stack after return:      f5
Stack use after scope:   f8
Global redzone:          f9
Global init order:       f6
Poisoned by user:        f7
Container overflow:      fc
Array cookie:            ac
Intra object redzone:    bb
ASan internal:           fe
Left alloca redzone:     ca
Right alloca redzone:    cb
==6542==ABORTING

Timeline

2017-04-14 - Vendor Disclosure
2017-09-13 - Public Release

6.8 Medium

CVSS2

Attack Vector

NETWORK

Attack Complexity

MEDIUM

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:M/Au:N/C:P/I:P/A:P

8.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

REQUIRED

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

0.002 Low

EPSS

Percentile

55.3%