• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • BIND8安全漏洞分析

    發表于:2007-07-02來源:作者:點擊數: 標簽:
    對BIND幾個 缺陷 的分析 綜述 現在隨著Internet的日益普及,而Internet非常依賴于域名服務(DNS)。在RFC845中對域名服務作了如下定義:一個迭代的分布式 數據庫 系統,它為Internet操作提供了基本的信息,例如:域名--IP地址的相互轉換,郵件處理信息。BIND

    對BIND幾個缺陷的分析
    綜述 
        現在隨著Internet的日益普及,而Internet非常依賴于域名服務(DNS)。在RFC845中對域名服務作了如下定義:一個迭代的分布式數據庫系統,它為Internet操作提供了基本的信息,例如:域名<-->IP地址的相互轉換,郵件處理信息。BIND(Berkeley Inetnet Name Domain,伯克利Internet域名是一種使用最廣的域名系統。它有安全缺陷對Internet無疑于是一場災難。
    2001年月29日,Network Associates of California發表了一個報告,指出了BIND最近出現的四個安全缺陷。其中有兩個是關于緩沖區溢出,可以使攻擊者關閉DNS或者獲得root權限,一個叫做"TSIG bug",影響BIND8,另一個是叫“complain bug"的緩沖區溢出缺陷,影響BIND4。其余兩個一個叫做"infoleak",影響BIND4和BIND8,另一個叫做"complain bug"格式化字符串缺陷,只影響BIND4。本文將著重講述infoleak和TSIG bug。其中,infoleak bug不能直接用來進行攻擊,但是它可以泄露棧的信息,甚至使攻擊者得到BIND運行時的內存布局,為使用TSIG進行攻擊創造了便利。這恐怕也是最近兩個蠕蟲:lion和adore都使用BIND的漏洞進行傳播的主要原因之一。

    細節
    1.infoleak
        infoleak bug是由Claudio Musmarra發現的,最早在CERT安全建議CA-2001-02對這個BUG進行了報道。它使攻擊者能夠直接得到named程序棧禎的信息,從而直接計算出進行單字節緩沖區溢出所需要的信息,大大增加了攻擊的成功率。
    程序執行時,在棧中保存了程序運行的內部變量和函數的局部變量,以及函數調用的返回地址等信息。infoleak bug可以使攻擊者直接讀出在棧中的這些信息,甚至程序運行時的內存布局。通過向運行有這個缺陷的BIND版本的DNS服務器發送一個特制的查詢包,就可以達成上述目的。
        所謂特制的查詢包就是向一個合法的很大的IQUERY(反向查詢)查詢包。向一個運行BIND的DNS服務器發出一個合法的IQUERY請求,DNS服務器把應答記錄放在這個查詢包之后返回。應答包括一個域名、類型(type)、類別(class)和ttl(包的生存時間)。在構造這個反向查詢包時,只要使域名對named程序的dn_skipname()函數是合法的就可以了。把這個反向查詢包的數據長度設置為一個和很大的數值,就會是應答記錄超出緩沖區的邊界。named程序的req_iquery()函數會發現這個反向查詢包非法,并且返回一個指示錯誤的字符串。不幸的是,它在檢查是否有錯誤時,不管反向查詢包的數據區有多長,首先把指向包尾的指針cp向后推,這樣很可能使cp指針超出了緩沖區的邊界。從req_iquery()函數返回后,ns_req()函數就會發出大小是cp-msg(指向緩沖區的頭)個字節含有錯誤信息的應答包。如果這個應答包已經超出了緩沖區的大小,就會包含named程序當前棧禎的信息如ebp等等,然后攻擊者就可以使用TSIG安全缺陷進行單字節緩沖區溢出攻擊了。
        因為相對于TSIG安全缺陷關于infoleak的分析資料較少,所以我將以bind-8.2為例對infoleak進行分析。BIND在查詢包小于512個字節時,使用UDP/53端口接受數據(更詳細的信息請參考TSIG部分),具體接受數據的函數就是datagram_read(),以下是datagram_read()函數的相關源代碼
    static void
    datagram_read(evContext lev, void *uap, int fd, int evmask) {
    interface *ifp = uap;
    struct sockaddr_in from;
    int from_len = sizeof from;
    int n, nudp;
    union {
    HEADER h; /* Force alignment of @#buf@#. */
    u_char buf[PACKETSZ+1];
    } u;<--這就是named函數存放小于512個字節的查詢包的緩沖區,后面對于查詢的處理操作都是針對于這個緩沖區的,也就是說,datagram_read是使用傳址方式把查詢包傳遞給以后的處理函數*/
    ..................
    dispatch_message(u.buf, n, PACKETSZ, NULL, from, fd, ifp);
    if (++nudp < nudptrans)
    goto more;
    }

    這時,棧的布局如下:
    ------------------
    |參數 |
    | |
    | |
    ------------------
    | |
    | 返回地址 |
    ------------------
    |ebp |
    ------------------
    |各個局部變量 |
    -----------------
    |u.buff[513] |
    -----------------
    |u.buff[512] |
    -----------------
    | ..... |
    -----------------
    |u.buff[0] |<----緩沖區
    -----------------
    接著,dispatch_message函數調用ns_req()函數:
    void
    ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp,
    struct sockaddr_in from, int dfd)
    {
    HEADER *hp = (HEADER *) msg;
    u_char *cp, *eom;/*<---cp指向請求包的數據區*/
    /*cp = msg + HFIXEDSZ*/
    /*eom指向請求包的尾*/
    /*eom = msg + msglen*/
    ................

    if (error == NOERROR) {
    switch (hp->opcode) {
    case ns_o_query:
    action = req_query(hp, &cp, eom, qsp,
    &buflen, &msglen,
    msg, dfd, from, in_tsig);
    break;

    case ns_o_iquery:
    action = req_iquery(hp, &cp, eom, &buflen, msg, from);
    break;
    /*反向請求包由req_iquery函數處理*/

    此時,棧如圖所示:
    ------------------
    |參數 |
    | |
    | |
    ------------------
    | |
    | 返回地址 |
    ------------------
    |ebp |
    ------------------
    |各個局部變量 |
    -----------------<----eom
    |u.buff[513] |
    -----------------
    |u.buff[512] |
    -----------------
    | ..... |
    -----------------
    |u.buff[12] |
    -----------------<----cp
    | ..... |
    -----------------
    |u.buff[0] |
    -----------------<---msg
    下面是req_iquery()函數:
    static enum req_action
    req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp,
    u_char *msg, struct sockaddr_in from)
    {
    int dlen, alen, n, type, class, count;
    char dnbuf[MAXDNAME], anbuf[PACKETSZ], *data, *fname;

    nameserIncr(from.sin_addr, nssRcvdIQ);

    if (ntohs(hp->ancount) != 1
    @# @#ntohs(hp->qdcount) != 0
    @# @#ntohs(hp->nscount) != 0
    @# @#ntohs(hp->arcount) != 0) {
    ns_debug(ns_log_default, 1,
    "FORMERR IQuery header counts wrong");
    hp->qdcount = htons(0);
    hp->ancount = htons(0);
    hp->nscount = htons(0);
    hp->arcount = htons(0);
    hp->rcode = FORMERR;
    return (Finish);
    }/*構造包時,使其能夠通過這些檢查*/
    /*
    * Skip domain name, get class, and type.
    */
    if ((n = dn_skipname(*cpp, eom)) < 0) {
    ns_debug(ns_log_default, 1,
    "FORMERR IQuery packet name problem");
    hp->rcode = FORMERR;
    return (Finish);
    }
    /*dn_skipname函數接著調用ns_name_skip函數*/
    *cpp += n;
    /*使攻擊程序構造的包數據區很大*/
    假設這時,棧如圖所示:

    ------------------
    |參數 |
    | |
    | |
    ------------------
    | |
    | 返回地址 |
    ------------------
    |ebp |
    ------------------
    |各個局部變量 |
    -----------------<----eom
    |u.buff[512] |
    -----------------
    |u.buff[511] |
    -----------------
    | ..... |
    -----------------
    |u.buff[446] |
    -----------------<----cp
    | ... |
    -----------------
    |u.buff[12] |
    -----------------
    | ..... |
    -----------------
    |u.buff[0] |
    -----------------<---msg
    /*但是符合*cpp+3*INT16SZ+INT32SZ<=eom*/
    if (*cpp + 3 * INT16SZ + INT32SZ > eom) {
    ns_debug(ns_log_default, 1,
    "FORMERR IQuery message too short");
    hp->rcode = FORMERR;
    return (Finish);
    }
    /*named處理type,class*/
    GETSHORT(type, *cpp);
    GETSHORT(class, *cpp);
    *cpp += INT32SZ; /* ttl */
    GETSHORT(dlen, *cpp);
    /*cpp已經接近緩沖區的邊界了*/
    此時,棧如圖所示:

    ------------------
    |參數 |
    | |
    | |
    ------------------
    | |
    | 返回地址 |
    ------------------
    |ebp |
    ------------------
    |各個局部變量 |
    -----------------<----eom
    |u.buff[512] |
    -----------------
    |u.buff[511] |
    -----------------
    | .... |
    -----------------
    |u.buff[458]=255|
    -----------------<---cp
    |u.buff[457]=0 |
    -----------------
    |u.buff[456]=255|<--假設dlen為255
    -----------------
    | ..... |
    -----------------
    |u.buff[446] |
    -----------------
    | ... |
    -----------------
    |u.buff[12] |
    -----------------
    | ..... |
    -----------------
    |u.buff[0] |
    -----------------<---msg
    *cpp += dlen;
    /*攻擊程序發出的反向查詢包的dlen為一個很大的值*/
    /*此時,再向后推dlen個字節*/
    /*哈,越界了*/
    if (*cpp != eom) {
    ns_debug(ns_log_default, 1,
    "FORMERR IQuery message length off");
    hp->rcode = FORMERR;
    return (Finish);
    }

        接下來,就是由ns_req()將cp-msg個字節發送給攻擊程序。攻擊者就可以得到named棧的信息,為下一步的單字節緩沖區攻擊作好準備。

    2.TSIG bug
        DNS域名服務器使用TISG(tranaction signature)來進行驗證通訊。TSIG BUG因此而得名。在最近出現的四個BIND BUG中,TSIG BUG危害是最為嚴重的。一個TSIG是一個高層的DNS資源記錄,在請求或者應答中是分別計算的,用完后丟棄,不能重復使用,也不應該保存在高速緩存中。TSIG是一個復雜的安全機制。它必須在消息的最后。如果在資源記錄(RR)中有幾個TSIG,或者位置不正確,BIND就會丟棄這個包并且送回一個錯誤信息。TSIG有幾個驗證機制,阻止了攻擊者從網絡上截取含有TSIG的包使用。
        TSIG BUG影響的BIND版本有:8.2(any service pack),8.2.1,8.2.2(packs1-7),和所有的8.2.3beta版本。
        當BIND接到一個請求,它會根據接受請求使用的傳輸機制,把請求放在?;蛘叨阎?。如果DNS請求小于512個字節,它就使用UDP/53接受請求的數據,并將其放在棧區中;如果DNS請求大于512個字節,它就使用TCP/53接受請求的數據,并把請求數據放在堆中。
        當請求小于或者等于512個字節時,由datagram_read()函數把請求放到棧中的一個513個字節緩沖區中,即u.buff;當收到一個TCP請求時,就由stream_getlen()函數把請求數據讀到一個64K的緩沖區中,這個緩沖區叫做sp->s_buff,是在堆中為每個套接字分配的。其中,有一個很有意思的特征,無論是使用TCP傳輸協議還是UDP傳輸協議,BIND都是只在緩沖區中對數據進行操作,然后做出相應的響應。
        BIND使用兩個變量來跟蹤緩沖區的使用情況:msglen保存緩沖區中現有數據的字節數;bufflen保存緩沖區沒有使用的字節數。
        當接到一個DNS消息,msglen被初始化為從網絡上接到的數據的長度。對于UDP來說,就是由recvfrom()系統調用返回的數;而TCP消息的msglen是由客戶端給出的。buflen被設置為讀取消息的緩沖區的大小,UDP是512,TCP是64K。
        通常情況下,在處理一個DNS查詢時,BIND回在查詢的后面加上應答、驗證以及其它的記錄信息。接著,BIND就會修改這個DNS查詢的頭來顯示上面所做的修改,將其送出。在處理過程中,msglen將會反映構造應答信息的緩沖區使用情況,而buflen將跟蹤緩沖區空閑區域的情況。在整個處理過程中,BIND都假設buflen+msglen等于緩沖區的長度。
        根據消息頭的設置,BIND會區分請求還是應答,分別對其進行處理。如果接到一個請求,它就區分這個請求是查詢(query)、反向查詢(iquery)、update還是notification。從BIND8.2開始,在處理請求數據之前,BIND首先要檢驗有沒有TSIG,這個功能是由ns_find_tsig()來完成的,同時這個函數還會對TSIG的合法性進行基本的驗證。如果有一個正確的TSIG而沒有準確的security key,BIND就發出一個錯誤信號,并跳過正常的處理操作。此時,msglen和buflen也保留為其初始值,而不是被設置為其工作值。
        因為有一個正確的TSIG但沒有準確的security key,BIND就進行錯誤處理。在產生錯誤信息時,BIND會重新起用緩沖區并且在這個有問題請求之后加上一個TSIG。此時,BIND假定msglen+buflen等于緩沖區的大小,當然在通常情況下,這時對的,但是只是在通常情況下-:(,在一些特殊的情況下msglen+buflen幾乎可以達到緩沖區大小的兩倍。接下來,BIND就調用ns_sign()函數在查詢之后加上一個TSIG,可能已經超出了緩沖區的范圍。
        下面是BIND處理請求的大體過程的示意圖:(本來是應該使用HTML格式的,但----是我一直對制作頁面缺乏興趣,所以只要如此了,不過我會抓緊學一學的-:) )
    ----------------
    |收到DNS請求 |
    ----------------
    | |
    | |
    / /
    -------------- ---------------
    |UDP請求由 | |TCP請求由 |
    |datagram_read| |stream_getlen |
    |放到 | |放到 |
    -------------- ---------------
    | |
    | |
    / /
    ------------ -----------------
    |棧 | |堆heap |
    |u.buff[513]| | sp->s_buff |
    | | | |
    ------------ ------------------
    跟蹤變量:msglen---數據長度
    buflen---未使用緩沖區的長度

    圖2.1
    |----------------------------------------------------------------|
    | 接到一個DNS請求 |
    | msglen設置為從網絡上接受的數據的長度 |buflen被初始化為緩沖區的長度|
    | UDP:recvfrom() |UDP:513 bytes |
    | TCP:由客戶端給出 |TCP:64K bytes |
    |-----------------------------------------------------------------|
    判斷請求是:
    query
    iquery
    update
    notification

    檢查是否有TSIG
    并檢驗其合法性
    ----------------------------------------------------------------------
    通常情況下, 異常情況下,
    TSIG和security key合法 正確的TSIG,而security key非法

    處理請求 發出錯誤信號:
    BIND跳過正常對請求的處理
    進行錯誤處理

    在查詢信息之后 msglen和buflen保留為其原來的值
    加上驗證及其它
    記錄

    修改查詢包的頭 重用緩沖區產生錯誤信息

    msglen等于數據的長度 假設nsglen+buflen等于原來緩沖區的長度
    buflen空閑緩沖區的長度
    假設原來緩沖區的長度等于
    msglen+buflen

    發出應答 加上TSIG,溢出
    ------------------------------------------------------------------
        例如,A公司的DNS使用的是BIND8.2.2-Patch5。一名攻擊者通過端口掃描知道了相關的信息,接著攻擊者向這臺域名服務器發出了一個請求,而這個請求包有一個TSIG而security key非法。A公司的DNS收到這個請求進行處理,它發現一個TSIG但是沒有合法的security key就發出了錯誤信號,而此時msglen和buflen都被鎖定,不能在處理錯誤時準確反映緩沖區的情況。datagram_read()或者stream_getlen()函數返回之前,BIND在請求包之后加上了新的TSIG,就超出了緩沖區。

    總結
        針對這個BUG可以使用單字節緩沖區溢出和堆溢出exploit。由于這兩個BUG和系統設置無關,所以應該趕快升級BIND系統。有一些途徑可以用來對named進行保護:
    1).不以root運行named;
    2).使用chroot保護文件系統。
    此外還可以使用其它一些方式保護自己的系統。

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>