Using sanitize_text_field ( WordPress method to clean input field ) to clean a file path . Don’t do it.

What the hell is sanitize_text_field?

It is a method responsible for sanitizing strings input from user or database.

The documentation and many posts and articles recommend its use in input fields to protect against attacks.

But no silver bullet exists! You can see more in the documentation.

But sanitize what?

Protect from what?

It doesn’t protect against everything. Last week we posted about a real world case exploring rename() method.

Real case exploring rename() PHP method.

In this case the developer tried protecting your input data with sanitize_text_field to clean your field.

If he tried protect against XSS he was half right. In next post we will show a bypass to explore XSS.

But it is a subject for another day.

The sanitize_text_field promises to sanitize almost everything but doesn’t promise to sanitize values used to do path traversal( Attack that explores navigation in folders to do something ), like ../ to rollback folders.

We will use a real example to explain.

rename('' . SP_CDM_UPLOADS_DIR . ''.$r[$i]['uid'].'/'.$r[$i]['file'].'', '' . SP_CDM_UPLOADS_DIR . '' . sanitize_text_field($_POST['uid']) . '/'.$r[$i]['file'].'');

Value us is ‘../../../’.

$_POST['uid'] = '../../../';
sanitize_text_field($_POST['uid'])

We will look at the code in core of WordPress about this.

https://core.trac.wordpress.org/browser/tags/5.2/src/wp-includes/formatting.php#L5112

First check if exist string ‘<‘ in my request like this.

if( strpos( $filtered, '<') !== false ) {
...
wp_pre_kses_less_than
...
wp_strip_all_tags
...
}

Doesn’t have, so we jump some validations.

Second validation, remove break lines;

if ( !$keep_newlines ) {
$filtered = preg_replace( ‘/[\r\n\t ]+/’, ‘ ‘, $filtered );
}

We don’t have break lines in field.

Remove strips octets, using preg_replace:

while( preg_match( '/%[a-f0-9]{2}/i', $filtered, $match) ) {
$filtered= str_replace( $match[0], '', $filtered);
$found= true;
}

Ok, in the ‘../../../’ don’t have octets.

In short, nothing in sanitize_text_field stops path transversal attack.

http://www.target.com/?foo=../../../wp-config.php

<?php

$file = sanitize_text_field( $_GET['foo'] );

// Result is ../../../wp-config.php

So, how we can fix this specific problem?

Use realpath() of php:

<?php

$file = realpath( $_GET['foo'] );
// Result is wp-config.php

For each problem a solution. Always check. No silver bullet solution exists.

In next post we will show how we can break sanitize_text_field in text field exploring XSS.

See ya. =)

Leave a Reply

Your email address will not be published. Required fields are marked *