Fossil SCM
Fix the SSH sync protocol to avoid "ssh" command-line option injection attacks such as those fixed in Git 2.14.1 and Mercurial 4.2.3.
Commit
1f63db591c77108cd722fd9ededaabf65e238f21d82b42ffbc19f0eb4f5eed3d
Parent
b130b64cb47003c…
1 file changed
+15
-2
+15
-2
| --- src/http_transport.c | ||
| +++ src/http_transport.c | ||
| @@ -73,10 +73,23 @@ | ||
| 73 | 73 | if( resetFlag ){ |
| 74 | 74 | transport.nSent = 0; |
| 75 | 75 | transport.nRcvd = 0; |
| 76 | 76 | } |
| 77 | 77 | } |
| 78 | + | |
| 79 | +/* | |
| 80 | +** Remove leading "-" characters from the input string. | |
| 81 | +** | |
| 82 | +** This prevents attacks that try to trick a victim into using | |
| 83 | +** a ssh:// URI with a carefully crafted hostname of other | |
| 84 | +** parameter that ends up being interpreted as a command-line | |
| 85 | +** option by "ssh". | |
| 86 | +*/ | |
| 87 | +static const char *stripLeadingMinus(const char *z){ | |
| 88 | + while( z[0]=='-' ) z++; | |
| 89 | + return z; | |
| 90 | +} | |
| 78 | 91 | |
| 79 | 92 | /* |
| 80 | 93 | ** Default SSH command |
| 81 | 94 | */ |
| 82 | 95 | #ifdef _WIN32 |
| @@ -116,17 +129,17 @@ | ||
| 116 | 129 | }else{ |
| 117 | 130 | zHost = mprintf("%s", pUrlData->name); |
| 118 | 131 | } |
| 119 | 132 | n = blob_size(&zCmd); |
| 120 | 133 | blob_append(&zCmd, " ", 1); |
| 121 | - shell_escape(&zCmd, zHost); | |
| 134 | + shell_escape(&zCmd, stripLeadingMinus(zHost)); | |
| 122 | 135 | blob_append(&zCmd, " ", 1); |
| 123 | 136 | shell_escape(&zCmd, mprintf("%s", pUrlData->fossil)); |
| 124 | 137 | blob_append(&zCmd, " test-http", 10); |
| 125 | 138 | if( pUrlData->path && pUrlData->path[0] ){ |
| 126 | 139 | blob_append(&zCmd, " ", 1); |
| 127 | - shell_escape(&zCmd, mprintf("%s", pUrlData->path)); | |
| 140 | + shell_escape(&zCmd, mprintf("%s", stripLeadingMinus(pUrlData->path))); | |
| 128 | 141 | } |
| 129 | 142 | if( g.fSshTrace ){ |
| 130 | 143 | fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */ |
| 131 | 144 | } |
| 132 | 145 | free(zHost); |
| 133 | 146 |
| --- src/http_transport.c | |
| +++ src/http_transport.c | |
| @@ -73,10 +73,23 @@ | |
| 73 | if( resetFlag ){ |
| 74 | transport.nSent = 0; |
| 75 | transport.nRcvd = 0; |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | /* |
| 80 | ** Default SSH command |
| 81 | */ |
| 82 | #ifdef _WIN32 |
| @@ -116,17 +129,17 @@ | |
| 116 | }else{ |
| 117 | zHost = mprintf("%s", pUrlData->name); |
| 118 | } |
| 119 | n = blob_size(&zCmd); |
| 120 | blob_append(&zCmd, " ", 1); |
| 121 | shell_escape(&zCmd, zHost); |
| 122 | blob_append(&zCmd, " ", 1); |
| 123 | shell_escape(&zCmd, mprintf("%s", pUrlData->fossil)); |
| 124 | blob_append(&zCmd, " test-http", 10); |
| 125 | if( pUrlData->path && pUrlData->path[0] ){ |
| 126 | blob_append(&zCmd, " ", 1); |
| 127 | shell_escape(&zCmd, mprintf("%s", pUrlData->path)); |
| 128 | } |
| 129 | if( g.fSshTrace ){ |
| 130 | fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */ |
| 131 | } |
| 132 | free(zHost); |
| 133 |
| --- src/http_transport.c | |
| +++ src/http_transport.c | |
| @@ -73,10 +73,23 @@ | |
| 73 | if( resetFlag ){ |
| 74 | transport.nSent = 0; |
| 75 | transport.nRcvd = 0; |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | /* |
| 80 | ** Remove leading "-" characters from the input string. |
| 81 | ** |
| 82 | ** This prevents attacks that try to trick a victim into using |
| 83 | ** a ssh:// URI with a carefully crafted hostname of other |
| 84 | ** parameter that ends up being interpreted as a command-line |
| 85 | ** option by "ssh". |
| 86 | */ |
| 87 | static const char *stripLeadingMinus(const char *z){ |
| 88 | while( z[0]=='-' ) z++; |
| 89 | return z; |
| 90 | } |
| 91 | |
| 92 | /* |
| 93 | ** Default SSH command |
| 94 | */ |
| 95 | #ifdef _WIN32 |
| @@ -116,17 +129,17 @@ | |
| 129 | }else{ |
| 130 | zHost = mprintf("%s", pUrlData->name); |
| 131 | } |
| 132 | n = blob_size(&zCmd); |
| 133 | blob_append(&zCmd, " ", 1); |
| 134 | shell_escape(&zCmd, stripLeadingMinus(zHost)); |
| 135 | blob_append(&zCmd, " ", 1); |
| 136 | shell_escape(&zCmd, mprintf("%s", pUrlData->fossil)); |
| 137 | blob_append(&zCmd, " test-http", 10); |
| 138 | if( pUrlData->path && pUrlData->path[0] ){ |
| 139 | blob_append(&zCmd, " ", 1); |
| 140 | shell_escape(&zCmd, mprintf("%s", stripLeadingMinus(pUrlData->path))); |
| 141 | } |
| 142 | if( g.fSshTrace ){ |
| 143 | fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */ |
| 144 | } |
| 145 | free(zHost); |
| 146 |