XCTF:Web – I-got-id-200 (Perl语言与linux命令)

Perl语法及特性学习和web CGI接口编程,linux命令以及管道操作

初窥题目

打开网站有三个指向网页

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第1张图片

第一个网页是个pl页面,而且可以发现url处,不是我们常见的php语言,jsp,asp语言。而是.pl后缀,查了一下是perl语言。

Perl一种脚本语言,也是胶水语言,拥有巨大的第三方库CPAN,可以用来做web编程,而且对于文件操作方便快捷。

 

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第2张图片

第二个网页是个表单,看题目有一个CGI,查询一下。

CGI通用网关接口,它是一段程序,运行在服务器上如:HTTP服务器,提供同客户端HTML页面的接口。通俗来说就是可以支持前后台交互的接口

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第3张图片

测试一下,没有什么发现

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第4张图片

打开第三个file页面,是一个文件上传页面,可能会有文件上传漏洞,上传试试

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第5张图片

文件内容会直接回显出来

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第6张图片

查一下perl语言利用CGI模块是如何实现文件上传的

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第7张图片

这里需要学习perl的语法知识

https://www.runoob.com/perl/perl-intro.html

https://qntm.org/perl_cn

尝试构造后台源代码

首先进行服务器配置使其能够支持Perl的CGI接口,我这里使用的是Tomcat

配置方法:修改Tomcat/conf下的web.xml和context.xml

Web.xml,打开cgi servlet部分和mapping部分的注释,Tomcat默认是在WEB-INF/cgi这个目录里寻找文件并解析(paramname与parameterValue规定的),并且mapping配置的过滤原则是:/cgi-bin/*都会被perl的cgi解释(url-pattern规定的)。可以看情况自己修改。

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第8张图片

打开context.xml,把改成 ,如果要应用容器提供的一些servele 或者是filter的话,就必须设置为true

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第9张图片

重启服务器

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第10张图片

在Tomcat8/webapps目录下新建工程test目录,新建WEB-INF/cgi存放所有的pl文件。

根据我们开启的规则,当输入http://127.0.0.1/test/cgi-bin/xxx.pl时,服务器会去test项目下的WEB-INF/cgi目录下寻找xxx.pl并执行。

在../webapps/test/WEB-INF/cgi下新建test.pl文件,写入(语法需要仔细看)

笔误(warnings 而不是warning。。。)

注意:Content-type:text/html后面必须跟两个换行\n\n

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第11张图片

保存后授予执行权限,chmod 555 test.pl

用perl执行一下perl test.pl

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第12张图片

解释成功,在打开网址运行一下url:127.0.0.1/test/cgi-bin/test.pl

测试成功,Tomcat的perl环境搭建完成

接下来开始构造file.pl源代码

  • 首先要加载CGI模块
use CGI;
  • 创建CGI的句柄,来访问相关函数。相当于初始化。Cgi函数功能简介http://www.freeoa.net/development/perl/perl-cgi-fun-intro_2195.html
my $cgi = new CGI;
  • 文件上传函数upload()

upload() 函数是用于处理文件上传的标准函数,参数为在构造表单时 看一下网页源代码可以看到,表单里name 参数的值为 “ file ” , 所以文件上传的过程应该是这样的 :

if ( $cgi->upload("file") ) { ... }

 

  • 获取参数

在 Perl CGI 标准函数中 , param() 函数用于获取传入的参数,根据接受变量的类型,可能是个标量,也可能返回一个数组,代码应该是

my $file = $ cgi->param(‘file’);
  • 读取文件

Perl 使用一种叫做文件句柄类型的变量来操作文件,从文件读取或者写入数据都需要使用到文件句柄 .

文件句柄( file handle )是一个I/O连接的名称 , Perl 中提供了三种文件句柄 : STDIN , STDOUT , STDERR , 分别代表标准输入,标准输出,标准错误输出

这里就要使用到 Perl 中的尖括号运算符( <> )了 , 它有如下的用途

  1. 如果尖括号中间是文件句柄, 尖括号运算符允许读取文件句柄
  2. 如果尖括号中间是搜索模式, 尖括号运算符能返回与该模式相匹配的的文件列表 ,这被称为一个 glob , 比如 <*.bat>
  3. 如果尖括号内没有任何内容, 那么它可以读取命令行上所有的文件内容, 如果没有文件名, 则可以读取标准输出

所以要进行下一步文件操作,必须要读取到文件句柄,也就是$file

  • 输出文件内容

前面读取到了文件句柄 , 那么如何输出文件的内容呢 ?这里要用到 Perl 中的特殊变量 $_

$_ 是默认参数的意思,指的是在不指定的情况下,程序处理的上一个变量 .

比如打开一个文本文件,读取每一行,在没有指定参数的情况下, $_ 指向从文件中读取的每一行 .

因此,若想要读取某个文件的所有内容,可以写一个循环,逐行读取文件的内容

while ( <$file> ) { print "$_"; }

源代码

至此我们可以简单写出后端源码的主要逻辑功能了!

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第13张图片

完整模拟源码

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第14张图片

运行试验一下

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第15张图片

正常输出上传文件的内容

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第16张图片

漏洞分析

这里大佬告诉我们要利用@ARGV这个全局变量

首先要了解Perl中的ARGV全局特殊文件句柄

ARGV:遍历数组变量@ARGV中所有文件名的特殊文件句柄

@ARGV:是个全局数组特殊变量,传给脚本的命令行参数列表

Perl 会将 perl 命令行参数列表放入到数组 @ARGV 中,而默认情况下,这些命令行参数是 Perl 的数据输入源,也就是 说Perl 会以依次将他们当作文件进行读取。这里可以参考C语言的argv{}数组,但不同的是,Perl语言的@ARGV中的第一个变量就是参数,而不是文件名。

Param() 函数会返回一个列表,但只有第一个文件会被放到变量中。

这里我们尝试在原来的数据包中新增一个文件上传项,并且删除filename参数,观察返回内容,为了方便测试,写了一个demo,加入了输出$file的语句

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第17张图片

原上传内容和返回结果,print $file 变量的值就是 filename的值

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第18张图片

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第19张图片

增加新的上传项,并删除filename,重大漏洞来了

删除filename后, $file的值(也就是文件名)变为了上传的内容,而输出的文件内容为空

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第20张图片

通俗理解就是,新加入的文件内容替换了filename参数,传给了$file变量,句柄中打开文件内容为空。。。

那如果我们利用@ARGV,将$file替换为@ARGV,其句柄就是,就是命令行的参数呀,如果给的参数是文件名,就可以输出第一个文件名的所有内容。

构造试试:test.pl就是把文件上传语句中的$file替换为@ARGV

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第21张图片

通过打印信息可以直观看到,ARGV文件句柄将@ARGV中的数组存放的每一个命令行参数作为文件名,然后输出文件内容(如果文件不存在则输出为空)。

这里我们利用以上信息构造,加入新的文件列表,删除filename,文件内容写入ARGV

那么后端执行,就会把$file的值换为ARGV,也就成了上述test.pl的内容,会把从命令行里读取到的参数,当作文件路径找到并输出。

那么如何传入命令行参数呢?其实直接在url给出参数就相当于命令行传参

那么,通过ARGV和url的参数就可以达到读取服务器上任意文件的目的

例如读取/etc/passwd

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第22张图片

但这里需要给出文件的绝对路径才可以输出,对于flag,我们得不到路径该怎么办呢?

Linux中,一切皆文件!既然能输出文件,那就能执行命令!!

构造远程执行代码

/bin/bash%20-c%20ls$IFS/| 

列出跟目录下所有文件并通过管道返回至浏览器,

这里空格需要用url编码转义,否则不符合http头部格式,不能随便加空格的。。。。。

Tips:

  • Linux中,/bin/bash 是bash解释器,这句话当作文件名时,首先会去寻找/bin/bash并且输出,那就是执行了解释器的功能,。
  • bash -c 的语法是,后面跟的第一个参数会当作命令来被bash解析,第二,第三个参数被认为是bash的参数,而不是第一个参数(命令)的参数

举个例子:

bash -c ls /

会执行ls命令,列出当前目录,/会被当做bash的参数,没有意义,会找不到。。。

如果我们想要列出根目录需要 “ls /”时,需要加入$IFS

IFS是linux的特殊变量,默认值是space空格, $是取变量值,$IFS就代表空格

bash -c ls$IFS/ 

就可以执行“ls /“的命令了

若只有 /bin/bash%20-c%20ls$IFS/ 命令会发现没有返回信息

 

因为,/etc/passwd本身就是文件,后端代码找到并输出返回在html标签中

而/bin/bash 一旦被访问输出,就是bash运行环境,整个语句的输出结果在shell的缓冲区里,也就是后台服务器才能看到,并不会输出到html标签中。在linux里我们只需要管道操作就可以指定结果的存放位置了。

Tips:Perl open()函数会默认打开一个管道!

这里利用Perl open()函数打开的管道,进行劫持,通过“|“操作符,把内容引入open()函数已经打开的管道中,就可以输出到html标签中啦!

(所以我们之前构造的file.pl源码也是不完善的,没有open()函数去打开管道,那就不能回显出bash执行结果,需要重新构造文件读取方式,利用open函数就可以返回/bin/bash执行结果)

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第23张图片

回到题目:构造payload列出根目录,发现flag文件

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第24张图片

 

使用 /bin/bash%20-c%20cat$IFS/flag| 输出flag内容 

XCTF:Web – I-got-id-200 (Perl语言与linux命令)_第25张图片

参考链接:https://www.guildhab.top/?p=867

你可能感兴趣的:(ctf)