From 6f42910987f4e99f9ec3bfd6fd27ff222665b4a8 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Mon, 11 Nov 2013 06:14:52 +0800 Subject: [PATCH] uri santitation fixes deal with single dot update attack.sh Signed-off-by: Andy Green --- lib/parsers.c | 14 ++++++-- test-server/attack.sh | 83 +++++++++++++++++++++++++++++++++++++++++++++-- test-server/test-server.c | 6 ++-- 3 files changed, 97 insertions(+), 6 deletions(-) diff --git a/lib/parsers.c b/lib/parsers.c index f6d7120..bfda32d 100644 --- a/lib/parsers.c +++ b/lib/parsers.c @@ -250,7 +250,7 @@ int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) } wsi->u.hdr.esc_stash = c; wsi->u.hdr.ues = URIES_SEEN_PERCENT_H1; - break; + goto swallow; case URIES_SEEN_PERCENT_H1: if (char_to_hex(c) < 0) { @@ -265,12 +265,14 @@ int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) } c = (char_to_hex(wsi->u.hdr.esc_stash) << 4) | char_to_hex(c); + wsi->u.hdr.ues = URIES_IDLE; break; } /* * special URI processing... - * convert /.. or /... etc to / + * convert /.. or /... or /../ etc to / + * convert /./ to / * convert // or /// etc to / * leave /.dir or whatever alone */ @@ -298,6 +300,11 @@ int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT_DOT; goto swallow; } + /* change /./ to / */ + if (c == '/') { + wsi->u.hdr.ups = URIPS_SEEN_SLASH; + goto swallow; + } /* it was like /.dir ... regurgitate the . */ wsi->u.hdr.ups = URIPS_IDLE; issue_char(wsi, '.'); @@ -307,6 +314,9 @@ int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) /* swallow prior .. chars and any subsequent . */ if (c == '.') goto swallow; + /* last issued was /, so another / == // */ + if (c == '/') + goto swallow; else /* last we issued was / so SEEN_SLASH */ wsi->u.hdr.ups = URIPS_SEEN_SLASH; break; diff --git a/test-server/attack.sh b/test-server/attack.sh index dae2c2a..84328ac 100755 --- a/test-server/attack.sh +++ b/test-server/attack.sh @@ -125,6 +125,29 @@ echo -e "GET blah HTTP/1.1\x0d\x0a\x0d\x0aILLEGAL-PAYLOAD....................... "......................................................................................................................." \ | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check +size=`stat /tmp/lwscap | grep Size: | tr -s ' ' | cut -d' ' -f3` +if [ $size -ne 0 ] ; then + echo "FAIL: got something back when should have hung up" + cat /tmp/lwscap + exit 1 +fi + +echo +echo "---- directory attack 1 (/../../../../etc/passwd should be /etc/passswd)" +rm -f /tmp/lwscap +echo -e "GET /../../../../etc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap +check +size=`stat /tmp/lwscap | grep Size: | tr -s ' ' | cut -d' ' -f3` +if [ $size -ne 0 ] ; then + echo "FAIL: got something back when should have hung up" + exit 1 +fi + +echo +echo "---- directory attack 2 (/../ should be /)" +rm -f /tmp/lwscap +echo -e "GET /../ HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap +check diff /tmp/lwscap /usr/share/libwebsockets-test-server/test.html > /dev/null if [ $? -ne 0 ] ; then echo "FAIL: got something other than test.html back" @@ -132,9 +155,9 @@ if [ $? -ne 0 ] ; then fi echo -echo "---- directory attack" +echo "---- directory attack 3 (/./ should be /)" rm -f /tmp/lwscap -echo -e "GET ../../../../etc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap +echo -e "GET /./ HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check diff /tmp/lwscap /usr/share/libwebsockets-test-server/test.html > /dev/null if [ $? -ne 0 ] ; then @@ -143,6 +166,62 @@ if [ $? -ne 0 ] ; then fi echo +echo "---- directory attack 4 (/blah/.. should be /blah/)" +rm -f /tmp/lwscap +echo -e "GET /blah/.. HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap +check +size=`stat /tmp/lwscap | grep Size: | tr -s ' ' | cut -d' ' -f3` +if [ $size -ne 0 ] ; then + echo "FAIL: got something back when should have hung up" + exit 1 +fi + +echo +echo "---- directory attack 5 (/blah/../ should be /blah/)" +rm -f /tmp/lwscap +echo -e "GET /blah/../ HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap +check +size=`stat /tmp/lwscap | grep Size: | tr -s ' ' | cut -d' ' -f3` +if [ $size -ne 0 ] ; then + echo "FAIL: got something back when should have hung up" + exit 1 +fi + +echo +echo "---- directory attack 6 (/blah/../. should be /blah/)" +rm -f /tmp/lwscap +echo -e "GET /blah/../. HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap +check +size=`stat /tmp/lwscap | grep Size: | tr -s ' ' | cut -d' ' -f3` +if [ $size -ne 0 ] ; then + echo "FAIL: got something back when should have hung up" + exit 1 +fi + +echo +echo "---- directory attack 7 (/%2e%2e%2f../../../etc/passwd should be /etc/passswd)" +rm -f /tmp/lwscap +echo -e "GET /%2e%2e%2f../../../etc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap +check +size=`stat /tmp/lwscap | grep Size: | tr -s ' ' | cut -d' ' -f3` +if [ $size -ne 0 ] ; then + echo "FAIL: got something back when should have hung up" + exit 1 +fi + +echo +echo "---- directory attack 7 (%2f%2e%2e%2f%2e./.%2e/.%2e%2fetc/passwd should be /etc/passswd)" +rm -f /tmp/lwscap +echo -e "GET %2f%2e%2e%2f%2e./.%2e/.%2e%2fetc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap +check +size=`stat /tmp/lwscap | grep Size: | tr -s ' ' | cut -d' ' -f3` +if [ $size -ne 0 ] ; then + echo "FAIL: got something back when should have hung up" + exit 1 +fi + + +echo echo "--- survived" kill -2 $CPID diff --git a/test-server/test-server.c b/test-server/test-server.c index 2c01f53..35150de 100644 --- a/test-server/test-server.c +++ b/test-server/test-server.c @@ -210,9 +210,11 @@ static int callback_http(struct libwebsocket_context *context, /* if not, send a file the easy way */ strcpy(buf, resource_path); - if (strcmp(in, "/")) + if (strcmp(in, "/")) { + if (*((const char *)in) != '/') + strcat(buf, "/"); strncat(buf, in, sizeof(buf) - strlen(resource_path)); - else /* default file to serve */ + } else /* default file to serve */ strcat(buf, "/test.html"); buf[sizeof(buf) - 1] = '\0'; mimetype = get_mimetype(buf); -- 2.7.4