diff --git a/lib/parsers.c b/lib/parsers.c index d5e00916..2720b154 100644 --- a/lib/parsers.c +++ b/lib/parsers.c @@ -334,11 +334,20 @@ int lws_parse(struct lws *wsi, unsigned char c) if (ah->nfrag >= ARRAY_SIZE(ah->frags)) goto excessive; /* start next fragment after the & */ + wsi->u.hdr.post_literal_equal = 0; ah->frags[ah->nfrag].offset = ah->pos; ah->frags[ah->nfrag].len = 0; ah->frags[ah->nfrag].nfrag = 0; goto swallow; } + /* uriencoded = in the name part, disallow */ + if (c == '=' && enc && !wsi->u.hdr.post_literal_equal) + c = '_'; + + /* after the real =, we don't care how many = */ + if (c == '=' && !enc) + wsi->u.hdr.post_literal_equal = 1; + /* + to space */ if (c == '+' && !enc) c = ' '; @@ -413,6 +422,7 @@ int lws_parse(struct lws *wsi, unsigned char c) ah->frags[ah->nfrag].len = 0; ah->frags[ah->nfrag].nfrag = 0; + wsi->u.hdr.post_literal_equal = 0; ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] = ah->nfrag; wsi->u.hdr.ups = URIPS_IDLE; goto swallow; diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 390018ae..62a3646d 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -810,6 +810,7 @@ struct _lws_header_related { enum uri_path_states ups; enum uri_esc_states ues; char esc_stash; + char post_literal_equal; }; struct _lws_websocket_related { diff --git a/test-server/attack.sh b/test-server/attack.sh index 5db93da9..688ce5cf 100755 --- a/test-server/attack.sh +++ b/test-server/attack.sh @@ -90,6 +90,12 @@ echo -e "GET /cgi-bin/settings.js?key1=value1 HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SE check 1 "key1=value1" check +echo +echo "---- ? processing (/test?key1%3d2=value1)" +rm -f /tmp/lwscap +echo -e "GET /test?key1%3d2=value1 HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap +check 1 "key1_2=value1" +check echo echo "---- ? processing (%2f%2e%2e%2f%2e./test.html?arg=1)"