CVE-2017-1000257- : Out of bounds read in libcurl's IMAP FETCH response parser

I've fuzzed libcurl with great success (CVE-2017-1000101 and CVE-2017-7407) in the past, so I thought I'd try my hand at finding another bug and it didn't take very long. Note: I compiled curl with the following flags: -g -O1 -fsanitize=address,undefined but you can play around with these to suit your needs.

==32295==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60c0000000b3 at pc 0x000000432e75 bp 0x7ffd8b226960 sp 0x7ffd8b226108
READ of size 108 at 0x60c0000000b3 thread T0
#0 0x432e74 in __interceptor_strlen (/root/fuzz/curl_fuzzer+0x432e74)
#1 0x5e1bab in Curl_client_write /root/curl/lib/sendf.c:632:11
#2 0x6eb2a3 in imap_state_fetch_resp /root/curl/lib/imap.c:1129:16
#3 0x6eb2a3 in imap_statemach_act /root/curl/lib/imap.c:1299
#4 0x6e6c2d in imap_multi_statemach /root/curl/lib/imap.c:1342:12
#5 0x6e6f06 in imap_doing /root/curl/lib/imap.c:1645:21
#6 0x538e66 in multi_runsingle /root/curl/lib/multi.c:1755:16
#7 0x52dbde in curl_multi_perform /root/curl/lib/multi.c:2160:14
#8 0x4f93e2 in fuzz_handle_transfer(fuzz_data*) /root/curl-fuzzer/curl_fuzzer.cc:705:5
#9 0x4f21e5 in LLVMFuzzerTestOneInput /root/curl-fuzzer/curl_fuzzer.cc:89:3
#10 0x7c550d in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /root/./Fuzzer/FuzzerLoop.cpp:495:13
#11 0x7b9322 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /root/./Fuzzer/FuzzerDriver.cpp:273:6
#12 0x7bde2a in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /root/./Fuzzer/FuzzerDriver.cpp:690:9
#13 0x7b8ff0 in main /root/./Fuzzer/FuzzerMain.cpp:20:10
#14 0x7f79b5e8bb44 in __libc_start_main /build/glibc-6V9RKT/glibc-2.19/csu/libc-start.c:287
#15 0x4200eb in _start (/root/fuzz/curl_fuzzer+0x4200eb)

0x60c0000000b3 is located 0 bytes to the right of 115-byte region [0x60c000000040,0x60c0000000b3)
allocated by thread T0 here:
#0 0x4c3153 in malloc (/root/fuzz/curl_fuzzer+0x4c3153)
#1 0x50778e in curl_domalloc /root/curl/lib/memdebug.c:175:9
#2 0x71a797 in Curl_pp_readresp /root/curl/lib/pingpong.c:433:21
#3 0x6e82b7 in imap_statemach_act /root/curl/lib/imap.c:1257:14
#4 0x6e6c2d in imap_multi_statemach /root/curl/lib/imap.c:1342:12
#5 0x6e6f06 in imap_doing /root/curl/lib/imap.c:1645:21
#6 0x538e66 in multi_runsingle /root/curl/lib/multi.c:1755:16
#7 0x52dbde in curl_multi_perform /root/curl/lib/multi.c:2160:14
#8 0x4f93e2 in fuzz_handle_transfer(fuzz_data*) /root/curl-fuzzer/curl_fuzzer.cc:705:5
#9 0x4f21e5 in LLVMFuzzerTestOneInput /root/curl-fuzzer/curl_fuzzer.cc:89:3
#10 0x7c550d in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /root/./Fuzzer/FuzzerLoop.cpp:495:13
#11 0x7b9322 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /root/./Fuzzer/FuzzerDriver.cpp:273:6
#12 0x7bde2a in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /root/./Fuzzer/FuzzerDriver.cpp:690:9
#13 0x7b8ff0 in main /root/./Fuzzer/FuzzerMain.cpp:20:10
#14 0x7f79b5e8bb44 in __libc_start_main /build/glibc-6V9RKT/glibc-2.19/csu/libc-start.c:287

SUMMARY: AddressSanitizer: heap-buffer-overflow (/root/fuzz/curl_fuzzer+0x432e74) in __interceptor_strlen

Neat. When we analyze the testcase that triggered the crash, we see that this is happening:

TLVHeader(type='CURLOPT_URL' (1), length=32, data='imap://127.0.0.1:9003/800/;UID=1')
TLVHeader(type='Server banner (sent on connection)' (2), length=29, data='* OK IMAP4rev1 Service Ready\n')
TLVHeader(type='Server response 1' (17), length=11, data='A001 IMAP4\n')
TLVHeader(type='Server response 2' (18), length=51, data='* 800 EXISTS\nA002 OK [READ-WRITE] SELECT completed\n')
TLVHeader(type='Server response 3' (19), length=127, data='* 1 FETCH (BODY[TET]X3{ 0}\r\nFrom: me@somewhere\r\nTo: fake@nowhere\r\n\r\nbody\r\n\r\n--\r\n  yours sincerely\r\n)\r\nA003 OK FETCH completed\r\n')

The bad code is in imap_state_fetch_resp when parsing

* 1 FETCH (BODY[TET]X3{ 0}\r\nFrom: me@somewhere\r\nTo: fake@nowhere\r\n\r\nbody\r\n\r\n--\r\n yours sincerely\r\n)\r\nA003 OK FETCH completed\r\n

It parses the value in {} as "0" and uses that as 'size', which is the size of the data that's coming up. Further down, 'chunk' is set to 'size', which is still 0. Calling 'Curl_client_write' with a length of 0 causes it to call 'strlen' on the buffer that's passed to it. This buffer is not null terminated in memory:

0x60c000000048: "From: me@somewhere\r\nTo: fake@nowhere\r\n\r\nbody\r\n\r\n--\r\n  yours sincerely\r\n)\r\nA003 OK FETCH completed\r\n\276\276\276\276\276\276\276\276"

Pretty nice find if I do say so myself. Thanks to the Curl security team for their prompt response, patch and release. Thanks to my Patreon supporters for helping fund the research. As always, if you like the work I'm doing, you can show your support through Patreon, PayPal, Square Cash or via Bitcoin: 1LcCefcdue8XTMj3zXjkXgCJk6S71kAtah. Thank you!

Please see the Curl Security Advisory if you don't understand anything I said here.

Geeknik Labs

Also on this blog

SHARE:  Email · Facebook · Google · Twitter · Tumblr · Kindle
SUBSCRIBE:  Receive an email on new posts from Geeknik Labs

Comments


  • Notify me upon new comments

☺ Got it