Skip to content

Commit 6f5fc34

Browse files
davidpandersonroot
authored andcommitted
web: fix various XSS vulnerabilities
Most of these involve putting user text in error messages. Use htmlspecialchars() for this. filenames: require POSIX portable names
1 parent 1a8200e commit 6f5fc34

File tree

6 files changed

+51
-23
lines changed

6 files changed

+51
-23
lines changed

html/inc/util_basic.inc

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,12 +185,34 @@ function dtime() {
185185
return microtime(true);
186186
}
187187

188+
// security vulnerabilities and user-supplied strings:
189+
// sources:
190+
// GET and POST arguments
191+
// including XML documents passed as args to RPC handlers
192+
// cookies
193+
//
194+
// when used as SQL query args:
195+
// use BoincDb::escape_string() to prevent SQL injection
196+
// when shown as HTML output
197+
// (e.g. 'not found' error pages, user names, forum posts)
198+
// use htmlspecialchars() to prevent XSS
199+
// when used as file or dir name
200+
// use is_valid_filename()
201+
188202
// is $x a valid file (or dir) name?
203+
// we want to avoid
204+
// FS traversal, e.g. "../../foo" or "/usr/lib/..."
205+
// shell command injection, e.g. "foo; rm*"
206+
// XSS stuff
207+
// let's be conservative and allow only 'POSIX fully portable filenames',
208+
// which can have only A-Z a-z 0-9 . - _
209+
// In some cases filenames are used on volunteer hosts,
210+
// whose OSs may have such restrictions.
189211
//
190212
function is_valid_filename($x) {
191-
if (htmlspecialchars($x) != $x) return false;
192-
if (strstr($x, '/')) return false;
193-
return true;
213+
if (strlen($x)>255) return false;
214+
// \w means A-Za-z0-9_
215+
return preg_match('/^[\w\-.]+$/', $x);
194216
}
195217

196218
?>

html/user/get_output.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ function return_error($str) {
3333
function get_output_file($instance_name, $file_num, $auth_str) {
3434
$result = BoincResult::lookup_name(BoincDb::escape_string($instance_name));
3535
if (!$result) {
36-
return_error("no job instance $instance_name");
36+
return_error("no job instance ".htmlspecialchars($instance_name));
3737
}
3838
$workunit = BoincWorkunit::lookup_id($result->workunitid);
3939
if (!$workunit) {
@@ -124,7 +124,7 @@ function get_wu_output_file($wu_name, $file_num, $auth_str) {
124124
$wu_name = BoincDb::escape_string($wu_name);
125125
$wu = BoincWorkunit::lookup("name='$wu_name'");
126126
if (!$wu) {
127-
return_error("no workunit $wu_name");
127+
return_error("no workunit ".htmlspecialchars($wu_name));
128128
}
129129
$batch = BoincBatch::lookup_id($wu->batch);
130130
if (!$batch) {
@@ -140,15 +140,15 @@ function get_wu_output_file($wu_name, $file_num, $auth_str) {
140140
$fanout = parse_config(get_config(), "<uldl_dir_fanout>");
141141
$upload_dir = parse_config(get_config(), "<upload_dir>");
142142
if (!$wu->canonical_resultid) {
143-
return_error("no canonical result for wu $wu->name");
143+
return_error("no canonical result for wu ".htmlspecialchars($wu->name));
144144
}
145145
$result = BoincResult::lookup_id($wu->canonical_resultid);
146146
$names = get_outfile_names($result);
147147
$path = dir_hier_path($names[$file_num], $upload_dir, $fanout);
148148
if (file_exists($path)) {
149149
do_download($path);
150150
} else {
151-
return_error("no such file: $path");
151+
return_error("no such file: ".htmlspecialchars($path));
152152
}
153153
}
154154

@@ -179,7 +179,7 @@ function get_wu_output_files($wu_id, $auth_str) {
179179
$upload_dir = parse_config(get_config(), "<upload_dir>");
180180

181181
if (!$wu->canonical_resultid) {
182-
return_error("no canonical result for wu $wu->name");
182+
return_error("no canonical result for wu ".htmlspecialchars($wu->name));
183183
}
184184
$result = BoincResult::lookup_id($wu->canonical_resultid);
185185
$names = get_outfile_names($result);

html/user/job_file.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
1818

1919
// Web RPCs for managing input files for remote job submission
20+
// These support systems where users - possibly lots of them -
21+
// process jobs without logging on to the BOINC server.
2022
//
2123
// Issues:
2224
//
@@ -111,6 +113,9 @@ function query_files($r) {
111113
}
112114
$i = 0;
113115
foreach($phys_names as $fname) {
116+
if (!is_valid_filename($fname)) {
117+
xml_error(-1, 'bad filename');
118+
}
114119
$path = dir_hier_path($fname, project_dir() . "/download", $fanout);
115120

116121
// if the job_file record is there,
@@ -192,11 +197,18 @@ function upload_files($r) {
192197

193198
$phys_names = array();
194199
foreach ($r->phys_name as $cs) {
195-
$phys_names[] = (string)$cs;
200+
$fname = (string)$cs;
201+
if (!is_valid_filename($fname)) {
202+
xml_error(-1, 'bad filename');
203+
}
204+
$phys_names[] = $fname;
196205
}
197206

198207
foreach ($_FILES as $f) {
199208
$name = $f['name'];
209+
if (!is_valid_filename($fname)) {
210+
xml_error(-1, 'bad FILES filename');
211+
}
200212
$tmp_name = $f['tmp_name'];
201213

202214
if ($f['error'] != UPLOAD_ERR_OK) {

html/user/openid_login.php

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
// You should have received a copy of the GNU Lesser General Public License
1717
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
1818

19+
NOT FINISHED. DON'T USE
20+
1921
require 'openid.php';
2022
include_once("../inc/boinc_db.inc");
2123
include_once("../inc/util.inc");
@@ -25,16 +27,13 @@
2527
function show_error($str) {
2628
page_head("Can't create account");
2729
echo "$str<br>\n";
28-
echo BoincDb::error();
29-
echo "<p>Click your browser's <b>Back</b> button to try again.\n<p>\n";
3030
page_tail();
3131
exit();
3232
}
3333

3434
try {
3535
$openid = new LightOpenID;
3636
echo "<pre>";
37-
print_r($openid); exit;
3837
if(!$openid->mode) {
3938
if(isset($_POST['openid_identifier'])) {
4039
$openid->identity = $_POST['openid_identifier'];
@@ -52,7 +51,6 @@ function show_error($str) {
5251
echo 'User has canceled authentication!';
5352
} else {
5453
echo 'User ' . ($openid->validate() ? $openid->identity . ' has ' : 'has not ') . 'logged in.';
55-
//print_r($openid->getAttributes());
5654
// Create the user in the DB
5755
$data = $openid->getAttributes();
5856
$email_addr = $data['contact/email'];
@@ -67,7 +65,6 @@ function show_error($str) {
6765
error_page("Account creation is disabled");
6866
}
6967

70-
7168
// see whether the new account should be pre-enrolled in a team,
7269
// and initialized with its founder's project prefs
7370
//
@@ -93,10 +90,7 @@ function show_error($str) {
9390
// if (!preg_match(INVITE_CODES, $invite_code)) {
9491
// show_error(tra("The invitation code you gave is not valid."));
9592
// }
96-
//}
97-
98-
print_r($data);
99-
exit();
93+
//}
10094

10195
$new_name = $data['namePerson/friendly'];
10296
if (!is_valid_user_name($new_name, $reason)) {

html/user/prefs_edit.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
$action = sanitize_tags(get_str("action", true));
2727
$subset = sanitize_tags(get_str("subset"));
2828
$venue = sanitize_tags(get_str("venue", true));
29-
$columns = get_str("cols", true);
29+
$columns = get_int("cols", true);
3030
$c = $columns?"&cols=$columns":"";
3131
check_subset($subset);
3232
if ($action) {

html/user/submit_rpc_handler.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ function get_wu($name) {
3636
$wu = BoincWorkunit::lookup("name='$name'");
3737
if (!$wu) {
3838
log_write("no job named $name was found");
39-
xml_error(-1, "no job named $name was found");
39+
xml_error(-1, "job not found: ".htmlspecialchars($name));
4040
}
4141
return $wu;
4242
}
@@ -46,7 +46,7 @@ function get_submit_app($name) {
4646
$app = BoincApp::lookup("name='$name'");
4747
if (!$app) {
4848
log_write("no app named $name was found");
49-
xml_error(-1, "no app named $name was found");
49+
xml_error(-1, "app not found: ".htmlspecialchars($name));
5050
}
5151
return $app;
5252
}
@@ -105,7 +105,7 @@ function read_input_template($app, $r) {
105105
$x = simplexml_load_file($path);
106106
if (!$x) {
107107
log_write("couldn't parse input template file $path");
108-
xml_error(-1, "couldn't parse input template file $path");
108+
xml_error(-1, "couldn't parse input template file ".htmlspecialchars($path));
109109
}
110110
return $x;
111111
} else {
@@ -1068,7 +1068,7 @@ function ping($r) {
10681068
$r = simplexml_load_string($req);
10691069
if (!$r) {
10701070
log_write("----- RPC request: can't parse request message: $req");
1071-
xml_error(-1, "can't parse request message: $req");
1071+
xml_error(-1, "can't parse request message: ".htmlspecialchars($req));
10721072
}
10731073

10741074
log_write("----- Handling RPC; command ".$r->getName());

0 commit comments

Comments
 (0)