I did this
When varfunc() in src/var.c processes a chained variable-expansion that places trim after any function that can emit leading whitespace, the trim handler advances the working pointer c past the leading whitespace characters in-place.
A shared cleanup block that follows every function iteration then calls curlx_free(c) on that shifted, interior pointer instead of on the original allocation base.
c is updated here:
|
if(FUNCMATCH(f, FUNC_TRIM, FUNC_TRIM_LEN)) { |
|
size_t len = clen; |
|
f += FUNC_TRIM_LEN; |
|
if(clen) { |
|
/* skip leading white space, including CRLF */ |
|
while(ISSPACE(*c)) { |
|
c++; |
|
len--; |
|
} |
|
while(len && ISSPACE(c[len - 1])) |
|
len--; |
|
} |
|
/* put it in the output */ |
|
curlx_dyn_reset(out); |
|
if(curlx_dyn_addn(out, c, len)) { |
|
err = PARAM_NO_MEM; |
|
break; |
|
} |
|
} |
and freed here:
This bug can easily trigger ASAN using 64dec and trim as belows.
64dec causes the buffer allocation, and whitespaces in the decoded data triggers trim to update c
$ ./curl --variable VAR=IA== --expand-url 'http://localhost:9999/{{VAR:64dec:trim}}'
=================================================================
==3844293==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x503000020111 in thread T0
#0 0x77b04e6fc4d8 in free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:52
#1 0x77b04e3752f7 in curl_dbg_free /home/eunsookim/repo/curl/curl-latest/lib/memdebug.c:385
#2 0x5f4a82aef203 in varfunc /home/eunsookim/repo/curl/curl-latest/src/var.c:189
#3 0x5f4a82aefbbb in varexpand /home/eunsookim/repo/curl/curl-latest/src/var.c:298
#4 0x5f4a82abeb00 in getparameter /home/eunsookim/repo/curl/curl-latest/src/tool_getparam.c:3022
#5 0x5f4a82abf6be in parse_args /home/eunsookim/repo/curl/curl-latest/src/tool_getparam.c:3154
#6 0x5f4a82ad4826 in operate /home/eunsookim/repo/curl/curl-latest/src/tool_operate.c:2421
#7 0x5f4a82ac55c5 in main /home/eunsookim/repo/curl/curl-latest/src/tool_main.c:189
#8 0x77b04d82a1c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
#9 0x77b04d82a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
#10 0x5f4a82a8f5e4 in _start (/home/eunsookim/repo/curl/curl-latest/bld-asan/src/curl+0xad5e4) (BuildId: 4f63030c99f8e089db65531fce2cdee9bef8685b)
0x503000020111 is located 1 bytes inside of 18-byte region [0x503000020110,0x503000020122)
allocated by thread T0 here:
#0 0x77b04e6fd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x77b04e374dce in curl_dbg_malloc /home/eunsookim/repo/curl/curl-latest/lib/memdebug.c:224
#2 0x5f4a82af604a in curlx_memdup0 /home/eunsookim/repo/curl/curl-latest/lib/curlx/strdup.c:87
#3 0x5f4a82aef23d in varfunc /home/eunsookim/repo/curl/curl-latest/src/var.c:192
#4 0x5f4a82aefbbb in varexpand /home/eunsookim/repo/curl/curl-latest/src/var.c:298
#5 0x5f4a82abeb00 in getparameter /home/eunsookim/repo/curl/curl-latest/src/tool_getparam.c:3022
#6 0x5f4a82abf6be in parse_args /home/eunsookim/repo/curl/curl-latest/src/tool_getparam.c:3154
#7 0x5f4a82ad4826 in operate /home/eunsookim/repo/curl/curl-latest/src/tool_operate.c:2421
#8 0x5f4a82ac55c5 in main /home/eunsookim/repo/curl/curl-latest/src/tool_main.c:189
#9 0x77b04d82a1c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
#10 0x77b04d82a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 8e9fd827446c24067541ac5390e6f527fb5947bb)
#11 0x5f4a82a8f5e4 in _start (/home/eunsookim/repo/curl/curl-latest/bld-asan/src/curl+0xad5e4) (BuildId: 4f63030c99f8e089db65531fce2cdee9bef8685b)
SUMMARY: AddressSanitizer: bad-free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:52 in free
==3844293==ABORTING
As it can be only triggered in local with specific options and is hard to exploit, I'm reporting this as a bug rather than a security issue.
I expected the following
curlx_free should free the original base of the allocated buffer c.
curl/libcurl version
curl 8.21.0-DEV (Linux)
operating system
Linux 6.6.87.2
The initial discovery was made by AI (MDASH).
The analysis, exploitation, and this report have been reviewed and verified by human experts.
Reporting on behalf of Autonomous Code Security (ACS) team at Microsoft.
I did this
When
varfunc()insrc/var.cprocesses a chained variable-expansion that placestrimafter any function that can emit leading whitespace, thetrimhandler advances the working pointercpast the leading whitespace characters in-place.A shared cleanup block that follows every function iteration then calls
curlx_free(c)on that shifted, interior pointer instead of on the original allocation base.cis updated here:curl/src/var.c
Lines 94 to 112 in 7c34365
and freed here:
curl/src/var.c
Lines 188 to 189 in 7c34365
This bug can easily trigger ASAN using
64decandtrimas belows.64deccauses the buffer allocation, and whitespaces in the decoded data triggerstrimto updatecAs it can be only triggered in local with specific options and is hard to exploit, I'm reporting this as a bug rather than a security issue.
I expected the following
curlx_freeshould free the original base of the allocated bufferc.curl/libcurl version
curl 8.21.0-DEV (Linux)
operating system
Linux 6.6.87.2
The initial discovery was made by AI (MDASH).
The analysis, exploitation, and this report have been reviewed and verified by human experts.
Reporting on behalf of Autonomous Code Security (ACS) team at Microsoft.