Fossil SCM
Add verify_all_options_cgi(), which works similarly to verify_all_options() but only fails if it finds CGI GET/POST arguments which (A) have not been fetched via P(), PD(), or similar, and (B) fail cgi_value_spider_check(). Currently only applied on the /ci page.
Commit
a065940a74345b27001215d66efcd16722fc2f5d838fe2255d82fe3892730940
Parent
e88211628b529e0…
2 files changed
+25
-2
+1
+25
-2
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -749,10 +749,11 @@ | ||
| 749 | 749 | const char *zName; /* Parameter or cookie name */ |
| 750 | 750 | const char *zValue; /* Value of the query parameter or cookie */ |
| 751 | 751 | int seq; /* Order of insertion */ |
| 752 | 752 | char isQP; /* True for query parameters */ |
| 753 | 753 | char cTag; /* Tag on query parameters */ |
| 754 | + char isFetched; /* 1 if the var is requested via P/PD() */ | |
| 754 | 755 | } *aParamQP; /* An array of all parameters and cookies */ |
| 755 | 756 | |
| 756 | 757 | /* |
| 757 | 758 | ** Add another query parameter or cookie to the parameter set. |
| 758 | 759 | ** zName is the name of the query parameter or cookie and zValue |
| @@ -776,10 +777,11 @@ | ||
| 776 | 777 | fprintf(stderr, "# cgi: %s = [%s]\n", zName, zValue); |
| 777 | 778 | } |
| 778 | 779 | aParamQP[nUsedQP].seq = seqQP++; |
| 779 | 780 | aParamQP[nUsedQP].isQP = isQP; |
| 780 | 781 | aParamQP[nUsedQP].cTag = 0; |
| 782 | + aParamQP[nUsedQP].isFetched = 0; | |
| 781 | 783 | nUsedQP++; |
| 782 | 784 | sortQP = 1; |
| 783 | 785 | } |
| 784 | 786 | |
| 785 | 787 | /* |
| @@ -1503,10 +1505,11 @@ | ||
| 1503 | 1505 | while( lo<=hi ){ |
| 1504 | 1506 | mid = (lo+hi)/2; |
| 1505 | 1507 | c = fossil_strcmp(aParamQP[mid].zName, zName); |
| 1506 | 1508 | if( c==0 ){ |
| 1507 | 1509 | CGIDEBUG(("mem-match [%s] = [%s]\n", zName, aParamQP[mid].zValue)); |
| 1510 | + aParamQP[mid].isFetched = 1; | |
| 1508 | 1511 | return aParamQP[mid].zValue; |
| 1509 | 1512 | }else if( c>0 ){ |
| 1510 | 1513 | hi = mid-1; |
| 1511 | 1514 | }else{ |
| 1512 | 1515 | lo = mid+1; |
| @@ -1542,11 +1545,11 @@ | ||
| 1542 | 1545 | @ <p>This page was generated because Fossil believes it has |
| 1543 | 1546 | @ detected an SQL injection attack. If you believe you are seeing |
| 1544 | 1547 | @ this in error, contact the developers on the Fossil-SCM Forum. Type |
| 1545 | 1548 | @ "fossil-scm forum" into any search engine to locate the Fossil-SCM Forum. |
| 1546 | 1549 | style_finish_page(); |
| 1547 | - cgi_set_status(404,"Robot Attack Detected"); | |
| 1550 | + cgi_set_status(418,"Robot Attack Detected"); | |
| 1548 | 1551 | cgi_reply(); |
| 1549 | 1552 | exit(0); |
| 1550 | 1553 | } |
| 1551 | 1554 | |
| 1552 | 1555 | /* |
| @@ -1770,11 +1773,11 @@ | ||
| 1770 | 1773 | switch( eDest ){ |
| 1771 | 1774 | case 0: { |
| 1772 | 1775 | cgi_printf("%h = %h <br>\n", zName, aParamQP[i].zValue); |
| 1773 | 1776 | break; |
| 1774 | 1777 | } |
| 1775 | - case 1: { | |
| 1778 | + case 1: { | |
| 1776 | 1779 | fossil_trace("%s = %s\n", zName, aParamQP[i].zValue); |
| 1777 | 1780 | break; |
| 1778 | 1781 | } |
| 1779 | 1782 | case 2: { |
| 1780 | 1783 | cgi_debug("%s = %s\n", zName, aParamQP[i].zValue); |
| @@ -2704,5 +2707,25 @@ | ||
| 2704 | 2707 | const char *zAgent = P("HTTP_USER_AGENT"); |
| 2705 | 2708 | if( zAgent==0 ) return 0; |
| 2706 | 2709 | if( sqlite3_strglob("*iPad*", zAgent)==0 ) return 0; |
| 2707 | 2710 | return sqlite3_strlike("%mobile%", zAgent, 0)==0; |
| 2708 | 2711 | } |
| 2712 | + | |
| 2713 | +/* | |
| 2714 | +** If the CGI environment contains any parameters which were not | |
| 2715 | +** fetched via P(), PD(), or equivalent, its value is passed to | |
| 2716 | +** cgi_value_spider_check(), fatally failing if the value looks to be | |
| 2717 | +** malicious. The intent is to block attempts at attacks which post | |
| 2718 | +** apparent SQL injection attempts using arbitrary query parameter | |
| 2719 | +** names. | |
| 2720 | +*/ | |
| 2721 | +void verify_all_options_cgi(void){ | |
| 2722 | + struct QParam * pParam; | |
| 2723 | + int i; | |
| 2724 | + for(i = 0; i < nUsedQP; ++i){ | |
| 2725 | + pParam = &aParamQP[i]; | |
| 2726 | + if(0 == pParam->isFetched | |
| 2727 | + && fossil_islower(pParam->zName[0])){ | |
| 2728 | + cgi_value_spider_check(pParam->zValue); | |
| 2729 | + } | |
| 2730 | + } | |
| 2731 | +} | |
| 2709 | 2732 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -749,10 +749,11 @@ | |
| 749 | const char *zName; /* Parameter or cookie name */ |
| 750 | const char *zValue; /* Value of the query parameter or cookie */ |
| 751 | int seq; /* Order of insertion */ |
| 752 | char isQP; /* True for query parameters */ |
| 753 | char cTag; /* Tag on query parameters */ |
| 754 | } *aParamQP; /* An array of all parameters and cookies */ |
| 755 | |
| 756 | /* |
| 757 | ** Add another query parameter or cookie to the parameter set. |
| 758 | ** zName is the name of the query parameter or cookie and zValue |
| @@ -776,10 +777,11 @@ | |
| 776 | fprintf(stderr, "# cgi: %s = [%s]\n", zName, zValue); |
| 777 | } |
| 778 | aParamQP[nUsedQP].seq = seqQP++; |
| 779 | aParamQP[nUsedQP].isQP = isQP; |
| 780 | aParamQP[nUsedQP].cTag = 0; |
| 781 | nUsedQP++; |
| 782 | sortQP = 1; |
| 783 | } |
| 784 | |
| 785 | /* |
| @@ -1503,10 +1505,11 @@ | |
| 1503 | while( lo<=hi ){ |
| 1504 | mid = (lo+hi)/2; |
| 1505 | c = fossil_strcmp(aParamQP[mid].zName, zName); |
| 1506 | if( c==0 ){ |
| 1507 | CGIDEBUG(("mem-match [%s] = [%s]\n", zName, aParamQP[mid].zValue)); |
| 1508 | return aParamQP[mid].zValue; |
| 1509 | }else if( c>0 ){ |
| 1510 | hi = mid-1; |
| 1511 | }else{ |
| 1512 | lo = mid+1; |
| @@ -1542,11 +1545,11 @@ | |
| 1542 | @ <p>This page was generated because Fossil believes it has |
| 1543 | @ detected an SQL injection attack. If you believe you are seeing |
| 1544 | @ this in error, contact the developers on the Fossil-SCM Forum. Type |
| 1545 | @ "fossil-scm forum" into any search engine to locate the Fossil-SCM Forum. |
| 1546 | style_finish_page(); |
| 1547 | cgi_set_status(404,"Robot Attack Detected"); |
| 1548 | cgi_reply(); |
| 1549 | exit(0); |
| 1550 | } |
| 1551 | |
| 1552 | /* |
| @@ -1770,11 +1773,11 @@ | |
| 1770 | switch( eDest ){ |
| 1771 | case 0: { |
| 1772 | cgi_printf("%h = %h <br>\n", zName, aParamQP[i].zValue); |
| 1773 | break; |
| 1774 | } |
| 1775 | case 1: { |
| 1776 | fossil_trace("%s = %s\n", zName, aParamQP[i].zValue); |
| 1777 | break; |
| 1778 | } |
| 1779 | case 2: { |
| 1780 | cgi_debug("%s = %s\n", zName, aParamQP[i].zValue); |
| @@ -2704,5 +2707,25 @@ | |
| 2704 | const char *zAgent = P("HTTP_USER_AGENT"); |
| 2705 | if( zAgent==0 ) return 0; |
| 2706 | if( sqlite3_strglob("*iPad*", zAgent)==0 ) return 0; |
| 2707 | return sqlite3_strlike("%mobile%", zAgent, 0)==0; |
| 2708 | } |
| 2709 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -749,10 +749,11 @@ | |
| 749 | const char *zName; /* Parameter or cookie name */ |
| 750 | const char *zValue; /* Value of the query parameter or cookie */ |
| 751 | int seq; /* Order of insertion */ |
| 752 | char isQP; /* True for query parameters */ |
| 753 | char cTag; /* Tag on query parameters */ |
| 754 | char isFetched; /* 1 if the var is requested via P/PD() */ |
| 755 | } *aParamQP; /* An array of all parameters and cookies */ |
| 756 | |
| 757 | /* |
| 758 | ** Add another query parameter or cookie to the parameter set. |
| 759 | ** zName is the name of the query parameter or cookie and zValue |
| @@ -776,10 +777,11 @@ | |
| 777 | fprintf(stderr, "# cgi: %s = [%s]\n", zName, zValue); |
| 778 | } |
| 779 | aParamQP[nUsedQP].seq = seqQP++; |
| 780 | aParamQP[nUsedQP].isQP = isQP; |
| 781 | aParamQP[nUsedQP].cTag = 0; |
| 782 | aParamQP[nUsedQP].isFetched = 0; |
| 783 | nUsedQP++; |
| 784 | sortQP = 1; |
| 785 | } |
| 786 | |
| 787 | /* |
| @@ -1503,10 +1505,11 @@ | |
| 1505 | while( lo<=hi ){ |
| 1506 | mid = (lo+hi)/2; |
| 1507 | c = fossil_strcmp(aParamQP[mid].zName, zName); |
| 1508 | if( c==0 ){ |
| 1509 | CGIDEBUG(("mem-match [%s] = [%s]\n", zName, aParamQP[mid].zValue)); |
| 1510 | aParamQP[mid].isFetched = 1; |
| 1511 | return aParamQP[mid].zValue; |
| 1512 | }else if( c>0 ){ |
| 1513 | hi = mid-1; |
| 1514 | }else{ |
| 1515 | lo = mid+1; |
| @@ -1542,11 +1545,11 @@ | |
| 1545 | @ <p>This page was generated because Fossil believes it has |
| 1546 | @ detected an SQL injection attack. If you believe you are seeing |
| 1547 | @ this in error, contact the developers on the Fossil-SCM Forum. Type |
| 1548 | @ "fossil-scm forum" into any search engine to locate the Fossil-SCM Forum. |
| 1549 | style_finish_page(); |
| 1550 | cgi_set_status(418,"Robot Attack Detected"); |
| 1551 | cgi_reply(); |
| 1552 | exit(0); |
| 1553 | } |
| 1554 | |
| 1555 | /* |
| @@ -1770,11 +1773,11 @@ | |
| 1773 | switch( eDest ){ |
| 1774 | case 0: { |
| 1775 | cgi_printf("%h = %h <br>\n", zName, aParamQP[i].zValue); |
| 1776 | break; |
| 1777 | } |
| 1778 | case 1: { |
| 1779 | fossil_trace("%s = %s\n", zName, aParamQP[i].zValue); |
| 1780 | break; |
| 1781 | } |
| 1782 | case 2: { |
| 1783 | cgi_debug("%s = %s\n", zName, aParamQP[i].zValue); |
| @@ -2704,5 +2707,25 @@ | |
| 2707 | const char *zAgent = P("HTTP_USER_AGENT"); |
| 2708 | if( zAgent==0 ) return 0; |
| 2709 | if( sqlite3_strglob("*iPad*", zAgent)==0 ) return 0; |
| 2710 | return sqlite3_strlike("%mobile%", zAgent, 0)==0; |
| 2711 | } |
| 2712 | |
| 2713 | /* |
| 2714 | ** If the CGI environment contains any parameters which were not |
| 2715 | ** fetched via P(), PD(), or equivalent, its value is passed to |
| 2716 | ** cgi_value_spider_check(), fatally failing if the value looks to be |
| 2717 | ** malicious. The intent is to block attempts at attacks which post |
| 2718 | ** apparent SQL injection attempts using arbitrary query parameter |
| 2719 | ** names. |
| 2720 | */ |
| 2721 | void verify_all_options_cgi(void){ |
| 2722 | struct QParam * pParam; |
| 2723 | int i; |
| 2724 | for(i = 0; i < nUsedQP; ++i){ |
| 2725 | pParam = &aParamQP[i]; |
| 2726 | if(0 == pParam->isFetched |
| 2727 | && fossil_islower(pParam->zName[0])){ |
| 2728 | cgi_value_spider_check(pParam->zValue); |
| 2729 | } |
| 2730 | } |
| 2731 | } |
| 2732 |
+1
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -641,10 +641,11 @@ | ||
| 641 | 641 | @ No such object: %h(zName) |
| 642 | 642 | style_finish_page(); |
| 643 | 643 | return; |
| 644 | 644 | } |
| 645 | 645 | zRe = P("regex"); |
| 646 | + verify_all_options_cgi(); | |
| 646 | 647 | if( zRe ) re_compile(&pRe, zRe, 0); |
| 647 | 648 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 648 | 649 | zParent = db_text(0, |
| 649 | 650 | "SELECT uuid FROM plink, blob" |
| 650 | 651 | " WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim", |
| 651 | 652 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -641,10 +641,11 @@ | |
| 641 | @ No such object: %h(zName) |
| 642 | style_finish_page(); |
| 643 | return; |
| 644 | } |
| 645 | zRe = P("regex"); |
| 646 | if( zRe ) re_compile(&pRe, zRe, 0); |
| 647 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 648 | zParent = db_text(0, |
| 649 | "SELECT uuid FROM plink, blob" |
| 650 | " WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim", |
| 651 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -641,10 +641,11 @@ | |
| 641 | @ No such object: %h(zName) |
| 642 | style_finish_page(); |
| 643 | return; |
| 644 | } |
| 645 | zRe = P("regex"); |
| 646 | verify_all_options_cgi(); |
| 647 | if( zRe ) re_compile(&pRe, zRe, 0); |
| 648 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 649 | zParent = db_text(0, |
| 650 | "SELECT uuid FROM plink, blob" |
| 651 | " WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim", |
| 652 |