CVE-2017-7407: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: The ourWriteOut function in tool_writeout.c in curl 7.53.1 might allow physically proximate attackers to obtain sensitive information from process memory in opportunistic circumstances by reading a workstation screen during use of a --write-out argument ending in a '%' character, which leads to a heap-based buffer over-read.
CWE description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
CVSS v3 base score: 2.4
Published: 2017-04-03T20:59Z
Repository: https://github.com/curl/curl
Language: Other
Files changed: src/tool_writeout.c, tests/data/Makefile.inc, tests/data/test1440, tests/data/test1441
Commit date: 2017-03-12 08:28:31 +0100
Commit message: tool_writeout: fixed a buffer read overrun on --write-out

If a % ended the statement, the string's trailing NUL would be skipped
and memory past the end of the buffer would be accessed and potentially
displayed as part of the --write-out output. Added tests 1440 and 1441
to check for this kind of condition.

Reported-by: Brian Carpenter

Diff: diff --git a/src/tool_writeout.c b/src/tool_writeout.c
index 2fb77742a..7843182f2 100644
--- a/src/tool_writeout.c
+++ b/src/tool_writeout.c
@@ -111,11 +111,11 @@ void ourWriteOut(CURL *curl, struct OutStruct *outs, const char *writeinfo)
   char *stringp = NULL;
   long longinfo;
   double doubleinfo;
 
   while(ptr && *ptr) {
-    if('%' == *ptr) {
+    if('%' == *ptr && ptr[1]) {
       if('%' == ptr[1]) {
         /* an escaped %-letter */
         fputc('%', stream);
         ptr += 2;
       }
diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
index 7742bcfec..a6a06b81f 100644
--- a/tests/data/Makefile.inc
+++ b/tests/data/Makefile.inc
@@ -151,11 +151,11 @@ test1396 test1397 test1398 \
 test1400 test1401 test1402 test1403 test1404 test1405 test1406 test1407 \
 test1408 test1409 test1410 test1411 test1412 test1413 test1414 test1415 \
 test1416 test1417 test1418 test1419 test1420 test1421 test1422 test1423 \
 test1424 \
 test1428 test1429 test1430 test1431 test1432 test1433 test1434 test1435 \
-test1436 test1437 test1438 test1439 \
+test1436 test1437 test1438 test1439 test1440 test1441 \
 \
 test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
 test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \
 test1516 test1517 \
 \
diff --git a/tests/data/test1440 b/tests/data/test1440
new file mode 100644
index 000000000..7ed0c4d5f
--- /dev/null
+++ b/tests/data/test1440
@@ -0,0 +1,31 @@
+<testcase>
+<info>
+<keywords>
+--write-out
+</keywords>
+</info>
+# Server-side
+<reply>
+</reply>
+
+# Client-side
+<client>
+<server>
+file
+</server>
+
+<name>
+Check --write-out with trailing %{
+</name>
+<command>
+file://localhost/%PWD/log/ --write-out '%{'
+</command>
+</client>
+
+# Verify data
+<verify>
+<stdout nonewline="yes">
+%{
+</stdout>
+</verify>
+</testcase>
diff --git a/tests/data/test1441 b/tests/data/test1441
new file mode 100644
index 000000000..6e253a690
--- /dev/null
+++ b/tests/data/test1441
@@ -0,0 +1,31 @@
+<testcase>
+<info>
+<keywords>
+--write-out
+</keywords>
+</info>
+# Server-side
+<reply>
+</reply>
+
+# Client-side
+<client>
+<server>
+file
+</server>
+
+<name>
+Check --write-out with trailing %
+</name>
+<command>
+file://localhost/%PWD/log/ --write-out '%'
+</command>
+</client>
+
+# Verify data
+<verify>
+<stdout nonewline="yes">
+%
+</stdout>
+</verify>
+</testcase>

Vulnerable code:     if('%' == *ptr) {
test1436 test1437 test1438 test1439 \
Fixed code:     if('%' == *ptr && ptr[1]) {
test1436 test1437 test1438 test1439 test1440 test1441 \
<testcase>
<info>
<keywords>
--write-out
</keywords>
</info>
# Server-side
<reply>
</reply>

# Client-side
<client>
<server>
file
</server>

<name>
Check --write-out with trailing %{
</name>
<command>
file://localhost/%PWD/log/ --write-out '%{'
</command>
</client>

# Verify data
<verify>
<stdout nonewline="yes">
%{
</stdout>
</verify>
</testcase>
<testcase>
<info>
<keywords>
--write-out
</keywords>
</info>
# Server-side
<reply>
</reply>

# Client-side
<client>
<server>
file
</server>

<name>
Check --write-out with trailing %
</name>
<command>
file://localhost/%PWD/log/ --write-out '%'
</command>
</client>

# Verify data
<verify>
<stdout nonewline="yes">
%
</stdout>
</verify>
</testcase>