-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathupload.php
More file actions
66 lines (53 loc) · 2.28 KB
/
upload.php
File metadata and controls
66 lines (53 loc) · 2.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?php
require_once rtrim( $_SERVER['DOCUMENT_ROOT'], '/' ) . '/wp-load.php';
header( 'Content-Type: application/json' );
$response = (object) [ 'response' => 'Error' ];
// Only allow uploads from administrators.
if ( ! current_user_can( 'manage_options' ) ) {
status_header( 403 );
echo json_encode( $response );
exit;
}
// CSRF protection: require a valid REST nonce (sent by the client as the
// X-WP-Nonce header, or a _wpnonce field as a fallback).
$nonce = $_SERVER['HTTP_X_WP_NONCE'] ?? ( $_REQUEST['_wpnonce'] ?? '' );
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
status_header( 403 );
echo json_encode( $response );
exit;
}
if ( empty( $_FILES['file']['name'] ) ) {
echo json_encode( $response );
exit;
}
// Disable PHP warning in order to produce a consistent response.
error_reporting( E_ERROR | E_PARSE );
// Normalize the filename and reject executable / dangerous file types — the
// deploy directory is web-accessible, so an uploaded .php file would be RCE.
$filename = sanitize_file_name( $_FILES['file']['name'] );
$extension = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
$blocked = [ 'php', 'php3', 'php4', 'php5', 'php7', 'phps', 'phtml', 'pht', 'phar', 'cgi', 'pl', 'asp', 'aspx', 'jsp', 'jspx', 'htaccess', 'shtml' ];
if ( $extension === '' || in_array( $extension, $blocked, true ) ) {
$response->response = 'Invalid file type';
echo json_encode( $response );
exit;
}
$upload_dir = wp_upload_dir();
$deploy_path = "{$upload_dir['basedir']}/deploy/";
$deploy_path_url = "{$upload_dir['baseurl']}/deploy/";
// Create the directory if needed, and drop a guard that disables PHP execution
// within it as defense-in-depth against any file that slips past the allowlist.
if ( ! file_exists( $deploy_path ) ) {
mkdir( $deploy_path, 0755, true );
}
$htaccess = "{$deploy_path}.htaccess";
if ( ! file_exists( $htaccess ) ) {
file_put_contents( $htaccess, "php_flag engine off\n<FilesMatch \"\\.(php|php3|php4|php5|php7|phps|phtml|pht|phar)$\">\n\tRequire all denied\n</FilesMatch>\n" );
}
$upload_file = "{$deploy_path}{$filename}";
$upload_file_url = "{$deploy_path_url}{$filename}";
if ( move_uploaded_file( $_FILES['file']['tmp_name'], $upload_file ) ) {
$response->response = 'Success';
$response->url = $upload_file_url;
}
echo json_encode( $response );