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.

stephan 2023-07-15 13:57 trunk
Commit a065940a74345b27001215d66efcd16722fc2f5d838fe2255d82fe3892730940
2 files changed +25 -2 +1
+25 -2
--- src/cgi.c
+++ src/cgi.c
@@ -749,10 +749,11 @@
749749
const char *zName; /* Parameter or cookie name */
750750
const char *zValue; /* Value of the query parameter or cookie */
751751
int seq; /* Order of insertion */
752752
char isQP; /* True for query parameters */
753753
char cTag; /* Tag on query parameters */
754
+ char isFetched; /* 1 if the var is requested via P/PD() */
754755
} *aParamQP; /* An array of all parameters and cookies */
755756
756757
/*
757758
** Add another query parameter or cookie to the parameter set.
758759
** zName is the name of the query parameter or cookie and zValue
@@ -776,10 +777,11 @@
776777
fprintf(stderr, "# cgi: %s = [%s]\n", zName, zValue);
777778
}
778779
aParamQP[nUsedQP].seq = seqQP++;
779780
aParamQP[nUsedQP].isQP = isQP;
780781
aParamQP[nUsedQP].cTag = 0;
782
+ aParamQP[nUsedQP].isFetched = 0;
781783
nUsedQP++;
782784
sortQP = 1;
783785
}
784786
785787
/*
@@ -1503,10 +1505,11 @@
15031505
while( lo<=hi ){
15041506
mid = (lo+hi)/2;
15051507
c = fossil_strcmp(aParamQP[mid].zName, zName);
15061508
if( c==0 ){
15071509
CGIDEBUG(("mem-match [%s] = [%s]\n", zName, aParamQP[mid].zValue));
1510
+ aParamQP[mid].isFetched = 1;
15081511
return aParamQP[mid].zValue;
15091512
}else if( c>0 ){
15101513
hi = mid-1;
15111514
}else{
15121515
lo = mid+1;
@@ -1542,11 +1545,11 @@
15421545
@ <p>This page was generated because Fossil believes it has
15431546
@ detected an SQL injection attack. If you believe you are seeing
15441547
@ this in error, contact the developers on the Fossil-SCM Forum. Type
15451548
@ "fossil-scm forum" into any search engine to locate the Fossil-SCM Forum.
15461549
style_finish_page();
1547
- cgi_set_status(404,"Robot Attack Detected");
1550
+ cgi_set_status(418,"Robot Attack Detected");
15481551
cgi_reply();
15491552
exit(0);
15501553
}
15511554
15521555
/*
@@ -1770,11 +1773,11 @@
17701773
switch( eDest ){
17711774
case 0: {
17721775
cgi_printf("%h = %h <br>\n", zName, aParamQP[i].zValue);
17731776
break;
17741777
}
1775
- case 1: {
1778
+ case 1: {
17761779
fossil_trace("%s = %s\n", zName, aParamQP[i].zValue);
17771780
break;
17781781
}
17791782
case 2: {
17801783
cgi_debug("%s = %s\n", zName, aParamQP[i].zValue);
@@ -2704,5 +2707,25 @@
27042707
const char *zAgent = P("HTTP_USER_AGENT");
27052708
if( zAgent==0 ) return 0;
27062709
if( sqlite3_strglob("*iPad*", zAgent)==0 ) return 0;
27072710
return sqlite3_strlike("%mobile%", zAgent, 0)==0;
27082711
}
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
+}
27092732
--- 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 @@
641641
@ No such object: %h(zName)
642642
style_finish_page();
643643
return;
644644
}
645645
zRe = P("regex");
646
+ verify_all_options_cgi();
646647
if( zRe ) re_compile(&pRe, zRe, 0);
647648
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
648649
zParent = db_text(0,
649650
"SELECT uuid FROM plink, blob"
650651
" WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim",
651652
--- 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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button