Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | If compiled with -DFOSSIL_PENTEST and if "<BUG>" appears anywhere in HTML output, or if "BUG" appears anywhere in SQL, then a panic is generated. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | pentest |
| Files: | files | file ages | folders |
| SHA3-256: |
9ceb5ff8696589e2dd2747753ee4dc8e |
| User & Date: | drh 2025-03-28 17:15:00.645 |
Context
|
2025-03-28
| ||
| 17:15 | If compiled with -DFOSSIL_PENTEST and if "<BUG>" appears anywhere in HTML output, or if "BUG" appears anywhere in SQL, then a panic is generated. Leaf check-in: 9ceb5ff869 user: drh tags: pentest | |
| 16:47 | Document parameters 'from' and 'to' for /reports. check-in: a584f75ff8 user: danield tags: trunk | |
Changes
Changes to src/cache.c.
| ︙ | ︙ | |||
93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
*/
static sqlite3_stmt *cacheStmt(sqlite3 *db, const char *zSql){
sqlite3_stmt *pStmt = 0;
int rc;
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
if( rc ){
sqlite3_finalize(pStmt);
pStmt = 0;
}
return pStmt;
}
/*
| > | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
*/
static sqlite3_stmt *cacheStmt(sqlite3 *db, const char *zSql){
sqlite3_stmt *pStmt = 0;
int rc;
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
if( rc ){
db_pentest(zSql);
sqlite3_finalize(pStmt);
pStmt = 0;
}
return pStmt;
}
/*
|
| ︙ | ︙ |
Changes to src/cgi.c.
| ︙ | ︙ | |||
474 475 476 477 478 479 480 481 482 483 484 485 486 487 |
**
** The reply consists of a response header (an HTTP or CGI response header)
** followed by the concatenation of the content header and content body.
*/
void cgi_reply(void){
Blob hdr = BLOB_INITIALIZER;
int total_size;
if( iReplyStatus<=0 ){
iReplyStatus = 200;
zReplyStatus = "OK";
}
if( g.fullHttpReply ){
if( rangeEnd>0
| > > > | 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 |
**
** The reply consists of a response header (an HTTP or CGI response header)
** followed by the concatenation of the content header and content body.
*/
void cgi_reply(void){
Blob hdr = BLOB_INITIALIZER;
int total_size;
#ifdef FOSSIL_PENTEST
int bHtml; /* True if the output is HTML */
#endif
if( iReplyStatus<=0 ){
iReplyStatus = 200;
zReplyStatus = "OK";
}
if( g.fullHttpReply ){
if( rangeEnd>0
|
| ︙ | ︙ | |||
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 |
total_size = rangeEnd - rangeStart;
}
blob_appendf(&hdr, "Content-Length: %d\r\n", total_size);
}else{
total_size = 0;
}
blob_appendf(&hdr, "\r\n");
cgi_fwrite(blob_buffer(&hdr), blob_size(&hdr));
blob_reset(&hdr);
if( total_size>0
&& iReplyStatus!=304
&& fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
){
int i, size;
for(i=0; i<2; i++){
size = blob_size(&cgiContent[i]);
if( size<=rangeStart ){
rangeStart -= size;
}else{
int n = size - rangeStart;
if( n>total_size ){
n = total_size;
| > > > > > > > > > > > > | 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 |
total_size = rangeEnd - rangeStart;
}
blob_appendf(&hdr, "Content-Length: %d\r\n", total_size);
}else{
total_size = 0;
}
blob_appendf(&hdr, "\r\n");
#ifdef FOSSIL_PENTEST
bHtml = strstr(blob_str(&hdr), "text/html")!=0;
if( strstr(blob_str(&hdr), "<BUG>")!=0 ){
fossil_panic("Cross-site scripting vulnerability!");
abort();
}
#endif
cgi_fwrite(blob_buffer(&hdr), blob_size(&hdr));
blob_reset(&hdr);
if( total_size>0
&& iReplyStatus!=304
&& fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
){
int i, size;
for(i=0; i<2; i++){
#ifdef FOSSIL_PENTEST
if( bHtml && strstr(blob_str(&cgiContent[i]), "<BUG>")!=0 ){
fossil_panic("Cross-site scripting vulnerability!\n");
}
#endif
size = blob_size(&cgiContent[i]);
if( size<=rangeStart ){
rangeStart -= size;
}else{
int n = size - rangeStart;
if( n>total_size ){
n = total_size;
|
| ︙ | ︙ |
Changes to src/db.c.
| ︙ | ︙ | |||
669 670 671 672 673 674 675 676 677 678 679 680 681 682 |
/*
** Set the Blob to which DML statement text should be appended. Set it
** to zero to stop appending DML statement text.
*/
void db_append_dml_to_blob(Blob *pBlob){
db.pDmlLog = pBlob;
}
/*
** Pause or unpause the DML log
*/
void db_pause_dml_log(void){ db.pauseDmlLog++; }
void db_unpause_dml_log(void){ db.pauseDmlLog--; }
| > > > > > > > > > > > > > > > > > | 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 |
/*
** Set the Blob to which DML statement text should be appended. Set it
** to zero to stop appending DML statement text.
*/
void db_append_dml_to_blob(Blob *pBlob){
db.pDmlLog = pBlob;
}
/*
** This routine is a no-op on most builds. But if Fossil is built using
** the FOSSIL_PENTEST compile-time option, and if the argument to this routine
** contains the text "BUG", then that indicates a potential SQL injection
** vulnerability. A panic is generated to bring this to the tester's
** attention.
*/
void db_pentest(const char *zSql){
#ifndef FOSSIL_PENTEST
(void)zSql;
#else
if( strstr(zSql,"BUG")!=0 ){
fossil_panic("SQL Injection vulnerability!");
}
#endif
}
/*
** Pause or unpause the DML log
*/
void db_pause_dml_log(void){ db.pauseDmlLog++; }
void db_unpause_dml_log(void){ db.pauseDmlLog--; }
|
| ︙ | ︙ | |||
696 697 698 699 700 701 702 703 704 705 706 707 708 709 |
zSql = blob_str(&pStmt->sql);
db.nPrepare++;
db_append_dml(zSql);
if( flags & DB_PREPARE_PERSISTENT ){
prepFlags = SQLITE_PREPARE_PERSISTENT;
}
rc = sqlite3_prepare_v3(g.db, zSql, -1, prepFlags, &pStmt->pStmt, &zExtra);
if( rc!=0 && (flags & DB_PREPARE_IGNORE_ERROR)==0 ){
db_err("%s\n%s", sqlite3_errmsg(g.db), zSql);
}else if( zExtra && !fossil_all_whitespace(zExtra) ){
db_err("surplus text follows SQL: \"%s\"", zExtra);
}
pStmt->pNext = db.pAllStmt;
pStmt->pPrev = 0;
| > | 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 |
zSql = blob_str(&pStmt->sql);
db.nPrepare++;
db_append_dml(zSql);
if( flags & DB_PREPARE_PERSISTENT ){
prepFlags = SQLITE_PREPARE_PERSISTENT;
}
rc = sqlite3_prepare_v3(g.db, zSql, -1, prepFlags, &pStmt->pStmt, &zExtra);
if( rc!=0 ) db_pentest(zSql);
if( rc!=0 && (flags & DB_PREPARE_IGNORE_ERROR)==0 ){
db_err("%s\n%s", sqlite3_errmsg(g.db), zSql);
}else if( zExtra && !fossil_all_whitespace(zExtra) ){
db_err("surplus text follows SQL: \"%s\"", zExtra);
}
pStmt->pNext = db.pAllStmt;
pStmt->pPrev = 0;
|
| ︙ | ︙ | |||
758 759 760 761 762 763 764 765 766 767 768 769 770 771 |
char *zSql;
pStmt->sql = *pSql;
blob_init(pSql, 0, 0);
zSql = blob_sql_text(&pStmt->sql);
db.nPrepare++;
rc = sqlite3_prepare_v3(g.db, zSql, -1, 0, &pStmt->pStmt, 0);
if( rc!=0 ){
db_err("%s\n%s", sqlite3_errmsg(g.db), zSql);
}
pStmt->pNext = pStmt->pPrev = 0;
pStmt->nStep = 0;
pStmt->rc = rc;
return rc;
}
| > | 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 |
char *zSql;
pStmt->sql = *pSql;
blob_init(pSql, 0, 0);
zSql = blob_sql_text(&pStmt->sql);
db.nPrepare++;
rc = sqlite3_prepare_v3(g.db, zSql, -1, 0, &pStmt->pStmt, 0);
if( rc!=0 ){
db_pentest(zSql);
db_err("%s\n%s", sqlite3_errmsg(g.db), zSql);
}
pStmt->pNext = pStmt->pPrev = 0;
pStmt->nStep = 0;
pStmt->rc = rc;
return rc;
}
|
| ︙ | ︙ | |||
1044 1045 1046 1047 1048 1049 1050 |
va_start(ap, zSql);
blob_vappendf(&sql, zSql, ap);
va_end(ap);
z = blob_str(&sql);
while( rc==SQLITE_OK && z[0] ){
pStmt = 0;
rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd);
| | > > > | 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 |
va_start(ap, zSql);
blob_vappendf(&sql, zSql, ap);
va_end(ap);
z = blob_str(&sql);
while( rc==SQLITE_OK && z[0] ){
pStmt = 0;
rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd);
if( rc!=SQLITE_OK ){
db_pentest(z);
break;
}
if( pStmt ){
int nRow = 0;
db.nPrepare++;
while( sqlite3_step(pStmt)==SQLITE_ROW ){
int i, n;
if( nRow++ > 0 ) fossil_print("\n");
n = sqlite3_column_count(pStmt);
|
| ︙ | ︙ | |||
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 |
int rc = SQLITE_OK;
sqlite3_stmt *pStmt;
const char *zEnd;
while( rc==SQLITE_OK && z[0] ){
pStmt = 0;
rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd);
if( rc ){
db_err("%s: {%s}", sqlite3_errmsg(g.db), z);
}else if( pStmt ){
db.nPrepare++;
db_append_dml(sqlite3_sql(pStmt));
while( sqlite3_step(pStmt)==SQLITE_ROW ){}
rc = sqlite3_finalize(pStmt);
if( rc ) db_err("%s: {%.*s}", sqlite3_errmsg(g.db), (int)(zEnd-z), z);
| > | 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 |
int rc = SQLITE_OK;
sqlite3_stmt *pStmt;
const char *zEnd;
while( rc==SQLITE_OK && z[0] ){
pStmt = 0;
rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd);
if( rc ){
db_pentest(z);
db_err("%s: {%s}", sqlite3_errmsg(g.db), z);
}else if( pStmt ){
db.nPrepare++;
db_append_dml(sqlite3_sql(pStmt));
while( sqlite3_step(pStmt)==SQLITE_ROW ){}
rc = sqlite3_finalize(pStmt);
if( rc ) db_err("%s: {%.*s}", sqlite3_errmsg(g.db), (int)(zEnd-z), z);
|
| ︙ | ︙ |
Changes to src/login.c.
| ︙ | ︙ | |||
1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 |
" AND octet_length(pw)>0"
" AND cexpire>julianday('now')"
" AND constant_time_cmp(cookie,%Q)=0",
zLogin, zHash
);
pStmt = 0;
rc = sqlite3_prepare_v2(pOther, zSQL, -1, &pStmt, 0);
if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
db_unprotect(PROTECT_USER);
db_multi_exec(
"UPDATE user SET cookie=%Q, cexpire=%.17g"
" WHERE login=%Q",
zHash,
sqlite3_column_double(pStmt, 0), zLogin
| > | 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 |
" AND octet_length(pw)>0"
" AND cexpire>julianday('now')"
" AND constant_time_cmp(cookie,%Q)=0",
zLogin, zHash
);
pStmt = 0;
rc = sqlite3_prepare_v2(pOther, zSQL, -1, &pStmt, 0);
if( rc!=SQLITE_OK ) db_pentest(zSQL);
if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
db_unprotect(PROTECT_USER);
db_multi_exec(
"UPDATE user SET cookie=%Q, cexpire=%.17g"
" WHERE login=%Q",
zHash,
sqlite3_column_double(pStmt, 0), zLogin
|
| ︙ | ︙ |
Changes to src/report.c.
| ︙ | ︙ | |||
320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
}
}
/* Compile the statement and check for illegal accesses or syntax errors. */
report_restrict_sql(&zErr);
rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, &zTail);
if( rc!=SQLITE_OK ){
zErr = mprintf("Syntax error: %s", sqlite3_errmsg(g.db));
}
if( !sqlite3_stmt_readonly(pStmt) ){
zErr = mprintf("SQL must not modify the database");
}
if( pStmt ){
sqlite3_finalize(pStmt);
| > | 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
}
}
/* Compile the statement and check for illegal accesses or syntax errors. */
report_restrict_sql(&zErr);
rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, &zTail);
if( rc!=SQLITE_OK ){
db_pentest(zSql);
zErr = mprintf("Syntax error: %s", sqlite3_errmsg(g.db));
}
if( !sqlite3_stmt_readonly(pStmt) ){
zErr = mprintf("SQL must not modify the database");
}
if( pStmt ){
sqlite3_finalize(pStmt);
|
| ︙ | ︙ | |||
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 |
int i; /* Loop counter */
int nVar; /* Number of parameters */
pStmt = 0;
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
assert( rc==SQLITE_OK || pStmt==0 );
if( rc!=SQLITE_OK ){
return rc;
}
if( !pStmt ){
/* this happens for a comment or white-space */
return SQLITE_OK;
}
if( !sqlite3_stmt_readonly(pStmt) ){
| > | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 |
int i; /* Loop counter */
int nVar; /* Number of parameters */
pStmt = 0;
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
assert( rc==SQLITE_OK || pStmt==0 );
if( rc!=SQLITE_OK ){
db_pentest(zSql);
return rc;
}
if( !pStmt ){
/* this happens for a comment or white-space */
return SQLITE_OK;
}
if( !sqlite3_stmt_readonly(pStmt) ){
|
| ︙ | ︙ |
Changes to src/th_main.c.
| ︙ | ︙ | |||
1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 |
zErr = 0;
report_restrict_sql(&zErr);
g.dbIgnoreErrors++;
rc = sqlite3_prepare_v2(g.db, argv[1], argl[1], &pStmt, &zTail);
g.dbIgnoreErrors--;
report_unrestrict_sql();
if( rc!=0 || zErr!=0 ){
if( noComplain ) return TH_OK;
Th_ErrorMessage(interp, "SQL error: ",
zErr ? zErr : sqlite3_errmsg(g.db), -1);
return TH_ERROR;
}
n = (int)(zTail - zSql);
zSql += n;
| > | 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 |
zErr = 0;
report_restrict_sql(&zErr);
g.dbIgnoreErrors++;
rc = sqlite3_prepare_v2(g.db, argv[1], argl[1], &pStmt, &zTail);
g.dbIgnoreErrors--;
report_unrestrict_sql();
if( rc!=0 || zErr!=0 ){
db_pentest(argv[1]);
if( noComplain ) return TH_OK;
Th_ErrorMessage(interp, "SQL error: ",
zErr ? zErr : sqlite3_errmsg(g.db), -1);
return TH_ERROR;
}
n = (int)(zTail - zSql);
zSql += n;
|
| ︙ | ︙ |