【作者投稿】奇葩webshell技巧

前段时间看XDCTF的一道web题,发现了一种很奇特的构造webshell的方法。

Base64一句话木马


题目的大概意思就是允许包含,但限制了使用的字符,仅允许使用'acgtACGT'这8个字符。

emmm,就像我第一次看到一样,感觉这根本不能构造webshell嘛,这要能弄出来,我直播吃……冰激凌。

不废话了,原理如下:

先大致讲一下,任何由 {A-Z|a-z|0-9|+|/} 组合的字符串(如果不够4的倍数可以用'='补全),如果长度为4的倍数,则都可以作为base64解码的材料,而在base64decode的时候,会产生原字符串包含字符集以外的字符,举个例子:

字符串aaaa进行base64解码:

结果为i��,有一部分为乱码,不过不要紧,因为至少产生了一个额外的、可以被利用的字符i

如果是md5那样的哈希编码,多一位字母,编码后的整个字符串就完全不一样了,但是base64不一样。

base64编码是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。三个字节有24个比特,对应于4个Base64单元,即3个字节可表示4个可打印字符。也就是说3个字节进行base64编码之后是4个字节。四个字节解码后为三个字节。

因此base64有一个特性,就是以四位为一个单位,多个单位组合起来,进行多次解密,得到的结果和组合的顺序相同。再举一个例子:

abcABC123的编码结果为YWJjQUJDMTIz,我们把加密后的字符串四个为一组拆开YWJj(abc)、QUJD(ABC)、MTIz(123),组合为MTIzYWJjQUJD

123abcABC的顺序反过来了。

base64还有一个特性,就是会自动抛弃不符合要求的字符,如果要进行解密的base64字符串包括有不合法的字符,也就是不在集合 {A-Z|a-z|0-9|+|/} 里,同时也不是末尾的等号的字符。会被自动抛弃,又一个例子:

PS:注意py版本为2.7

aaaa的解密结果为i��

iiii的解密结果为�(�

如果我们把aaaa的解密结果重复四遍,再进行解密

结果和iiii的解密结果是一样的

从以上两个例子能Get到什么猥琐的技巧呢?

三个背景知识:

① 编码和解码不是唯一对应,就是说字母a可能通过不同的,其它字符的组合进行base64解码解出来。(组合种类远多于base64的合法字符种类)

② 被解码的字符,以四位为一个单位,多个单位组合起来,进行多次解密,得到的结果和组合的顺序相同。

③ 我们的一句话<?php @eval($_POST[a]);?>,可以通过解密另一个字符串,我们假设为字符串一号获得,而字符串一号可以通过解密字符串二号获得,并且这种序列不是唯一的。我们有可能找到仅仅由acgtACGT这8个字符组合起来的一串字符,这串字符在经过n次解密后的结果为我们的一句话木马。当然,在这个过程中,要保证四位一组,否则会乱序。

然后附上王一航大佬的Python脚本:

https://gist.github.com/WangYihang/a49c663237e68822dd4816e99534ca72)

我加入了很多的注解,然后我们来一步一步地,从主函数开始分析:

首先输出了base64_chars,这是在之前的 base64_chars = string.letters + string.digits + "+/" 中定义好的。base64除了‘=’以外可能会用到的字符串。然后tables = enmu_tables(set(chars))将可以使用的8个字符带入了enmu_tables()函数。

我们跟进enmu_tables()函数,它将我们可以使用的8个字符带入enmu_table()函数,四位为一组进行组合,然后进行base64解码,生成了一个list,这个list的key值为所有acgtACGT组合能够生成的合法数字(再带两个注定要被遗弃的非法数字),value值为生成这个合法数字的‘acgtACGT’四位字符组合。

还记得之前提到的一个栗子吗?

aaaa解码生成了i��,那么在第一次生成时,list的key值为i,value值为‘aaaa’

经过所有的组合之后

我们拿到了26个字符,而这二十六个字符能重新组成的四位字符串为四的26次方~

循环上一步步骤,我们拿到了57个

再循环一次

我们拿到了64个,已经是全部的base64合法字符了

这时,我们手中有三个表,分别是一层一层地一位key(伴随着两个注定要被扔掉的垃圾字符)对应四位value。这时,我们可以把一句话密码中的字符分隔开,挨个去最后一个表(64个key)中寻找由第二次循环生成的57个字符组成的4位字符串。找到之后,再去第二个表中,将目前的这些字符,用第一次循环得到的26位字符串的4位组合替换掉,然后再去第一个表中,找到用最初始的8位字符组成的四位字符串替换;

总共替换了3次,又因为在把一句话进行输入的时候额外进行了一次base64encode,所以最后的payload为:

include(php://filter/convert.base64-decode/resource=php://filter/convert.base64-decode/resource=php://filter/convert.base64-decode/resource=php://filter/convert.base64-decode/resource= 【我们的acgtACGT组合】);

生成的payload,储存在了名字为'acgtACGT'的文件中,长得是这个样子:

特别长,我就不贴出来了

那个脚本中还要注意的一点为:

其中,如果长度不是4的倍数,会根据base64编码原理默认用等号补齐,凑够长度为4的倍数。

原文发布于微信公众号 - 信安之路(xazlsec)

原文发表时间:2017-10-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序猿

Linux sed 命令的使用

首先,就昨晚的发的消息道歉,虽然整蛊大家了,但是我还是挺开心的。 sed是一种流编辑器,配合正则表达式使用,sed处理文件之时,把当前处理的文保存...

39310
来自专栏用户2442861的专栏

《Effective Modern C++》读书笔记

Note:为避免各种侵权问题,本文并没有复制原书任意文字(代码除外,作者已经声明代码可以被使用)。需要原书完整中文翻译的读者请等待官方译本的发布。

3822
来自专栏C语言及其他语言

C语言第一个简单实例

在信息化、智能化的世界里,可能很早很早 我们就听过许多IT类的名词,C语言也在其中,我们侃侃而谈,到底C程序是什么样子?让我们先看简单的一个例子: #inclu...

3446
来自专栏Java Web

《编写高质量代码》学习笔记(2)

写着写着发现简书提醒我文章接近字数极限,建议我换一篇写了。 ---- 建议52:推荐使用String直接量赋值 一般对象都是通过new关键字生成的,但是Str...

3644
来自专栏Coco的专栏

高性能Javascript--高效的数据访问

972
来自专栏编程

Python原创0基础入门一看几张图就学会了

Python最近势头很猛,由于他在人工智能方面的出色表现,已经成为现在热门的编程语音之一,为了大家方便学习,而不是浪费时间去看入门教程,萌掌用图片的方式画出了你...

2168
来自专栏orientlu

C 链表 - linux 如何实现

链表是基本数据结构, 一开始学习数据结构时, 我一般这么定义, 对应实现从头或尾插入的处理函数,

1493
来自专栏代码世界

Python之面向对象四

面向对象进阶 一、关于面向对象的两个内置函数 isinstance   判断类与对象的关系    isinstance(obj,cls)检查obj是否是类 cl...

37713
来自专栏小樱的经验随笔

Uva 11729 Commando War (简单贪心)

Uva 11729  Commando War (简单贪心) There is a war and it doesn't look very promising...

2666
来自专栏JMCui

MongoDB系列六(聚合).

 一、概念     使用聚合框架可以对集合中的文档进行变换和组合。基本上,可以用多个构件创建一个管道(pipeline),用于对一连串的文档进行处理。这些构件包...

6825

扫码关注云+社区